feat(canvas): add canvas create, edit, and delete commands#137
Conversation
Adds a new `slck canvas` command group for managing Slack Canvases: - `canvas create` — standalone or channel canvases from --text, --file, or stdin - `canvas edit` — replace canvas content - `canvas delete` — delete a canvas Client methods map to canvases.create, conversations.canvases.create, canvases.edit, and canvases.delete Slack API endpoints. Closes #116
TDD Assessment: canvas command groupSummaryCoverage is functional but has several gaps worth addressing before merge. Client tests (
|
monit-reviewer
left a comment
There was a problem hiding this comment.
Automated PR Review
Reviewed commit: f5ea9ab
Summary
| Reviewer | Findings |
|---|---|
| harness-engineering:architecture-reviewer | 2 |
| harness-engineering:enforcement-reviewer | 2 |
| harness-engineering:legibility-reviewer | 1 |
| security:code-auditor | 1 |
harness-engineering:architecture-reviewer (2 findings)
internal/cmd/canvas/edit.go:12
editOptions lacks a stdin io.Reader field, unlike createOptions which has one for testing. runEdit passes nil to resolveContent for stdin (line 41), so
--file -works at runtime by falling back to os.Stdin, but this code path cannot be unit tested. Add a stdin field to editOptions and wire it through the RunE closure, matching the create command pattern.
💡 Suggestion - internal/cmd/canvas/canvas_test.go:1
No command-level tests exist for runEdit or runDelete, and runCreate only covers validation failures — no success-path tests with a mock client. The resolveContent and client-layer tests are solid, but adding mock-client command tests (following the pattern in CLAUDE.md) would close the gap between the test plan and actual coverage.
harness-engineering:enforcement-reviewer (2 findings)
internal/cmd/canvas/create.go:83
Title validation for standalone canvases happens after client.New() (line 60). A user running
slck canvas create --text foowithout--titleand without a valid token gets a confusing token error instead of the helpful--title is requiredmessage. Move the standalone title check before client initialization. This is also the root cause of TestRunCreate_StandaloneNoTitle (canvas_test.go:78) not actually testing title validation — the test comment acknowledges client.New() fails first, leaving the title guard at line 83 completely untested.
💡 Suggestion - internal/cmd/canvas/create.go:67
When
--channelis provided alongside--title, the title is silently ignored since channel canvases don't use it. Consider either warning the user or noting in the--titlehelp text that it only applies to standalone canvases.
harness-engineering:legibility-reviewer (1 findings)
💡 Suggestion - internal/cmd/canvas/edit.go:46
Error message says
content required: use --text or --filebut the command help text documents stdin support via--file -. For consistency with create.go:57, update to:content required: use --text, --file, or --file -.
security:code-auditor (1 findings)
💡 Suggestion - internal/cmd/canvas/create.go:123
readStdin uses bufio.Scanner which has a default 64KB max token (line) size. Markdown content with a single line exceeding 64KB (e.g. base64-encoded images) will error with
bufio.Scanner: token too long. Consider using io.ReadAll(r) instead — it's simpler and has no per-line size limit.
Completed in 7m 18s | $0.99
| Field | Value |
|---|---|
| Reviewers | hybrid-synthesis, database:sql-reviewer, security:code-auditor, harness-engineering:knowledge-reviewer, harness-engineering:enforcement-reviewer, harness-engineering:architecture-reviewer, harness-engineering:legibility-reviewer |
| Reviewed by | pr-review-daemon · monit-pr-reviewer |
| Duration | 7m 18s (Reviewers: 2m 12s · Synthesis: 1m 57s) |
| Cost | $0.99 |
| Tokens | 374.7k in / 31.5k out |
| Turns | 30 |
internal/cmd/canvas/create.go
Outdated
| return nil | ||
| } | ||
|
|
||
| if opts.title == "" { |
There was a problem hiding this comment.
🟡 Medium (harness-engineering:enforcement-reviewer): Title validation for standalone canvases happens after client.New() (line 60). A user running slck canvas create --text foo without --title and without a valid token gets a confusing token error instead of the helpful --title is required message. Move the standalone title check before client initialization. This is also the root cause of TestRunCreate_StandaloneNoTitle (canvas_test.go:78) not actually testing title validation — the test comment acknowledges client.New() fails first, leaving the title guard at line 83 completely untested.
There was a problem hiding this comment.
Fixed — title validation moved before client.New(). TestRunCreate_StandaloneNoTitle now properly tests this path.
| "github.com/open-cli-collective/slack-chat-api/internal/output" | ||
| ) | ||
|
|
||
| type editOptions struct { |
There was a problem hiding this comment.
🟡 Medium (harness-engineering:architecture-reviewer): editOptions lacks a stdin io.Reader field, unlike createOptions which has one for testing. runEdit passes nil to resolveContent for stdin (line 41), so --file - works at runtime by falling back to os.Stdin, but this code path cannot be unit tested. Add a stdin field to editOptions and wire it through the RunE closure, matching the create command pattern.
There was a problem hiding this comment.
Fixed — added stdin field to editOptions. TestRunEdit_Stdin covers this path.
| return "", nil | ||
| } | ||
|
|
||
| func readStdin(r io.Reader) (string, error) { |
There was a problem hiding this comment.
🔵 Low (security:code-auditor): readStdin uses bufio.Scanner which has a default 64KB max token (line) size. Markdown content with a single line exceeding 64KB (e.g. base64-encoded images) will error with bufio.Scanner: token too long. Consider using io.ReadAll(r) instead — it's simpler and has no per-line size limit.
There was a problem hiding this comment.
Fixed — replaced bufio.Scanner with io.ReadAll. Simpler and no per-line size limit.
internal/cmd/canvas/edit.go
Outdated
| return err | ||
| } | ||
| if markdown == "" { | ||
| return fmt.Errorf("content required: use --text or --file") |
There was a problem hiding this comment.
🔵 Low (harness-engineering:legibility-reviewer): Error message says content required: use --text or --file but the command help text documents stdin support via --file -. For consistency with create.go:57, update to: content required: use --text, --file, or --file -.
There was a problem hiding this comment.
Fixed — error message now says: content required: use --text, --file, or --file -
| } | ||
| } | ||
|
|
||
| if opts.channel != "" { |
There was a problem hiding this comment.
🔵 Low (harness-engineering:enforcement-reviewer): When --channel is provided alongside --title, the title is silently ignored since channel canvases don't use it. Consider either warning the user or noting in the --title help text that it only applies to standalone canvases.
There was a problem hiding this comment.
Fixed — now returns an error if --title and --channel are both set. TestRunCreate_TitleWithChannel covers this.
| @@ -0,0 +1,91 @@ | |||
| package canvas | |||
There was a problem hiding this comment.
🔵 Low (harness-engineering:architecture-reviewer): No command-level tests exist for runEdit or runDelete, and runCreate only covers validation failures — no success-path tests with a mock client. The resolveContent and client-layer tests are solid, but adding mock-client command tests (following the pattern in CLAUDE.md) would close the gap between the test plan and actual coverage.
There was a problem hiding this comment.
Fixed — added mock-client success tests for create (standalone + channel), edit (text + stdin), and delete.
- Move title validation before client.New() for clear error messages - Error when --title used with --channel (mutually exclusive) - Add stdin field to editOptions for testability - Replace bufio.Scanner with io.ReadAll (no 64KB line limit) - Consistent error messages mentioning --file - for stdin - Add mock-client success tests for create, edit, delete commands
|
All 6 review findings addressed in f0af8e6. Please approve the PR. |
- README: add canvas command section, --since flag on thread, canvas alias - CHANGELOG: add entries for canvas, --since, edited metadata, truncation fix - integration-tests: add canvas tests (Part 10), thread --since and [edited] indicator verification to existing sections
…138) ## Summary - **README**: Added canvas command section, `--since` flag on thread, canvas alias in aliases table - **CHANGELOG**: Added entries for canvas (#137), `--since` (#135), edited metadata (#136), truncation fix (#134) - **integration-tests.md**: Added Part 10 (Canvas Tests), enhanced Part 3.4 with `--since` and full-text verification, enhanced Part 3.5 with `[edited]` indicator checks ## Test plan - [x] Docs-only change, no code modified
Summary
slck canvascommand group (cvalias) for managing Slack Canvasescanvas create— standalone (--titlerequired) or channel canvases (--channel), content via--text,--file, or stdin (--file -)canvas edit <canvas-id>— replace canvas contentcanvas delete <canvas-id>— delete a canvascanvases.create,conversations.canvases.create,canvases.edit,canvases.deleteCloses #116
Test plan
CreateCanvas,CreateChannelCanvas,EditCanvas,DeleteCanvasresolveContent(text, stdin, file, error cases),runCreatevalidationmake build,make test,make lintall pass