Add hey thread comment for private thread notes - #383
Conversation
There was a problem hiding this comment.
Pull request overview
Adds hey thread comment for private, non-mailed thread notes.
Changes:
- Adds and registers the comment command.
- Posts account-scoped plain-text notes through the SDK.
- Adds tests and updates documentation/snapshots.
Tip
If you aren't ready for review, convert to a draft PR.
Click "Convert to draft" or run gh pr ready --undo.
Click "Ready for review" or run gh pr ready to reengage.
Reviewed changes
Copilot reviewed 7 out of 7 changed files in this pull request and generated 3 comments.
Show a summary per file
| File | Description |
|---|---|
internal/cmd/thread_comment.go |
Implements the command. |
internal/cmd/thread_comment_test.go |
Tests requests, validation, and output. |
internal/cmd/topic.go |
Registers the subcommand. |
README.md |
Documents user-facing usage. |
skills/hey/SKILL.md |
Adds agent guidance. |
API-COVERAGE.md |
Records endpoint coverage. |
.surface |
Updates the CLI surface snapshot. |
💡 Add a code-review agent skill or configure MCP servers for context-aware, tailored reviews. Learn more in the docs.
| if _, err := rootSDK.PostForm(cmd.Context(), path, values); err != nil { | ||
| return apierr.FromSDK(err) | ||
| } |
There was a problem hiding this comment.
Not changing this yet, because it is the open question on this PR rather than a detail of it. What HEY answers a comment post with — a redirect to /imbox, a redirect to the thread, a 200 — is the endpoint's contract, and pinning Location: /imbox from the outside would make the command fail on a harmless change to HEY's own UI routing. The SDK already surfaces 4xx/5xx as errors, so a 2xx or a redirect is HEY accepting the form. Whether this command should post the form at all, or wait for a JSON endpoint and an SDK operation, is the decision this PR is parked on (see the API-COVERAGE thread); the success check will be shaped by that answer.
There was a problem hiding this comment.
1 issue found across 7 files
Prompt for AI agents (unresolved issues)
Check if these issues are valid — if so, understand the root cause of each and fix them. If appropriate, use sub-agents to investigate and fix each issue separately.
<file name="API-COVERAGE.md">
<violation number="1" location="API-COVERAGE.md:74">
P2: The new `/topics/{id}/comments` row posts through `Client.PostForm`, but both this file's header ("API interactions use the HEY SDK") and AGENTS.md ("All API interactions must go through the HEY SDK... add it to the SDK") require SDK-typed operations, and this is the only `PostForm` call in the repo. The cited precedent (Collections, Publications) is the opposite: those form endpoints were added to the SDK as `Collections().Create`/`Publications().Create`. Add a `Comments().Create` operation to hey-sdk/go instead of working around it, matching the repo's rule that missing operations go into the SDK (require operator sign-off) rather than here.</violation>
</file>
Reply with feedback, questions, or to request a fix.
Re-trigger cubic
| | `/entries/{id}/replies` | POST | SDK `Entries().CreateReply`, `Entries().CreateReplyDraft` | `hey reply <topic-id>`, `hey reply --draft`, `hey compose --thread-id [--draft]` | covered | | ||
| | `/topics/{id}.json` | GET | SDK `Topics().Get` | `hey forward <topic-id>`, `hey reply <topic-id>`, TUI `r` | covered | | ||
| | `/topics/{id}.json` | GET | SDK `Topics().Get` | `hey forward <topic-id>`, `hey reply <topic-id>`, `hey thread comment <topic-id>`, TUI `r` | covered | | ||
| | `/topics/{id}/comments` | POST | `Client.PostForm` (not generated — no OpenAPI operation) | `hey thread comment <topic-id>` | covered | |
There was a problem hiding this comment.
P2: The new /topics/{id}/comments row posts through Client.PostForm, but both this file's header ("API interactions use the HEY SDK") and AGENTS.md ("All API interactions must go through the HEY SDK... add it to the SDK") require SDK-typed operations, and this is the only PostForm call in the repo. The cited precedent (Collections, Publications) is the opposite: those form endpoints were added to the SDK as Collections().Create/Publications().Create. Add a Comments().Create operation to hey-sdk/go instead of working around it, matching the repo's rule that missing operations go into the SDK (require operator sign-off) rather than here.
Prompt for AI agents
Check if this issue is valid — if so, understand the root cause and fix it. At API-COVERAGE.md, line 74:
<comment>The new `/topics/{id}/comments` row posts through `Client.PostForm`, but both this file's header ("API interactions use the HEY SDK") and AGENTS.md ("All API interactions must go through the HEY SDK... add it to the SDK") require SDK-typed operations, and this is the only `PostForm` call in the repo. The cited precedent (Collections, Publications) is the opposite: those form endpoints were added to the SDK as `Collections().Create`/`Publications().Create`. Add a `Comments().Create` operation to hey-sdk/go instead of working around it, matching the repo's rule that missing operations go into the SDK (require operator sign-off) rather than here.</comment>
<file context>
@@ -70,7 +70,8 @@ which is what `Entries().ListDraftsPage` and `hey draft list --page` exist for.
| `/entries/{id}/replies` | POST | SDK `Entries().CreateReply`, `Entries().CreateReplyDraft` | `hey reply <topic-id>`, `hey reply --draft`, `hey compose --thread-id [--draft]` | covered |
-| `/topics/{id}.json` | GET | SDK `Topics().Get` | `hey forward <topic-id>`, `hey reply <topic-id>`, TUI `r` | covered |
+| `/topics/{id}.json` | GET | SDK `Topics().Get` | `hey forward <topic-id>`, `hey reply <topic-id>`, `hey thread comment <topic-id>`, TUI `r` | covered |
+| `/topics/{id}/comments` | POST | `Client.PostForm` (not generated — no OpenAPI operation) | `hey thread comment <topic-id>` | covered |
| `/entries/{id}/forwards/new.json` | GET | SDK `Entries().NewForward` | `hey forward <topic-id>` | covered |
| `/bulk_replies/new.json` | GET | SDK `BulkReplies().Draft` | `hey bulk-reply preview`, `hey bulk-reply send`, TUI `ctrl+b` | covered |
</file context>
There was a problem hiding this comment.
This is the right reading of the rule, and it is the decision this PR is waiting on: /topics/{id}/comments has no JSON endpoint in HEY today, so a typed Comments().Create in hey-sdk/go would be wrapping the same HTML form post the CLI does here. Whether to accept a form-built operation for thread comments (in the SDK, then here) or wait for HEY to expose comments as JSON first is an operator/API call that is pending alongside the same question for stage threads. Until it lands I have rebased the branch onto main and kept it green rather than moving the call between repos.
Posts an internal note via PostForm to /topics/{id}/comments, not a mailed reply.
…e Markdown exception Trimming only decides whether -m is blank; the text itself goes to HEY untouched, as the command documents. The parent command's listing now says it writes as well as reads, and the skill's Markdown-by-default sentence names thread comment as the one exception.
7773e64 to
d88a059
Compare
|
Rebased onto main at d88a059 (the README additions moved to Where this stands: HEY has no JSON endpoint for thread comments, so this command posts the same HTML form the web app does. Whether to accept a form-built operation for comments — in hey-sdk/go and then here — or wait for HEY to expose comments as JSON first is a pending API decision, and the PR waits on that rather than on anything in the diff. |
The gap
hey replymails a reply. There is no CLI for the other thing a thread holds: a private internal note. Those notes show up askind: "comment"inhey thread read, but you could only add them in the web app.The comments write is not in hey-sdk OpenAPI. Empty or wrong form fields can create a blank comment, so this has to post a specific field.
The change
hey thread comment <thread-id> -m "..."posts a private internal note, not a mailed reply.POST /topics/{topic_id}/comments?account_id={account_id}viaClient.PostForm(same redirect-capturing form path as collections, snippets, and publications)comment[content]=<plain text>— sent exactly as typed, not converted from Markdown302 Location: /imbox; the redirect is not followedTopics().Getso All Accounts still posts against the thread's mail accounthey thread readshows the note askind: "comment"--message/-mis required and cannot be blank.Tests
internal/cmd/thread_comment_test.gochecks the POST path and query, form field,Accept: */*,Content-Type: application/x-www-form-urlencoded, that Markdown-looking text is sent verbatim, that missing/empty-mand a bad thread ID make no request, and that/imboxis not followed.TMPDIR=/tmp/t GOWORK=off make checkis green. (Without the shortTMPDIR, three pre-existing TUI unix-socket tests fail to bind on this machine; they are unrelated to this change.)Summary by cubic
Adds
hey thread comment <thread-id> -m "..."so private internal thread notes can be posted from the CLI. Previously these notes could be read viahey thread readbut only created in the web app.New Features
/topics/{id}/commentsthroughPostFormsince the comments write is not in the SDK OpenAPI.-mflags.-m; treats the 302 to/imboxas success and does not follow it.Written for commit d88a059. Summary will update on new commits.