Add basecamp boost update
What
basecamp boost update <boost-id|url> <content> (and boosts update) changes the content of a boost you gave. It calls the SDK's BoostsService.Update (PUT /boosts/{id}).
- Content is a short note, 16 characters max, counted in characters not bytes.
boost createandboost updateshare one helper (checkBoostLength), and the check runs before any request is made. - Blank content is refused locally ("Boost content required").
-as the content reads it from stdin, ascreatedoes.- A boost ID or a boost URL is accepted (
.../boosts/789, parsed the wayshowanddeleteparse it). The route is flat, so no project or item is needed; the boost ID is the whole address. - Only the boost's creator can update it. Anyone else, admins included, gets the server's 403, which comes back through the usual error mapping (404 and 422 too).
- Output matches
create: the updated boost, a summary (Updated boost #N to <content>), and breadcrumbs to show and delete it. - Catalog entry,
.surface,API-COVERAGE.mdboosts row (6 to 7 operations), and a live smoke test.skills/basecamp/SKILL.mddocuments no boost commands, so it is unchanged. The basecamp-connect skill is untouched.
SDK dependency
Needs UpdateBoost from basecamp-sdk #1016 (head 32567741, which contains #1015). Until that releases, the bottom DO NOT MERGE commits point the replace at a local SDK worktree. Drop them and run make bump-sdk once it ships. This PR is stacked on #914.
Compatibility check (final SDK vs the provisional CLI stack)
With the replace pointed at the #1016 SDK, make check (what bin/ci runs) at the replace commit alone (#913/#914 code, nothing of this PR) exits 0: fmt, vet, lint, lint-actions, go unit tests (-tags dev ./...), BATS e2e, sync-skills, naming, surface, skill drift, bare groups, lint lockstep, smoke coverage, eval checks, race shards, tidy. Only the SDK provenance check skips, as expected with a replace active. The final SDK broke nothing in #913/#914.
Tests
New tests in internal/commands/boost_test.go (all red against the old boost.go, green now): sends new content and summary, boosts alias, URL form, stdin, over 16 refused before any request, exactly 16 accepted, 16 emoji accepted (characters, not bytes), empty and blank refused before any request, bad ID refused before any request, 403/404/422 mapping.
make check on the PR head also exits 0.
Live check
Against production, on the R2-D2 Ping line (bucket 49282878, line 10420899410), as the logged-in profile (R2-D2), self-cleaning: boost create with 👀, boost update to ✅ done, boost show confirmed ✅ done, an over-cap update was refused locally, a stdin update (-) worked, then boost delete. The line's one pre-existing boost was untouched.
Summary by cubic
Adds basecamp boost update <boost-id|url> <content> (and boosts update) to change the content of a boost you gave, via the SDK's UpdateBoost (PUT /boosts/{id}).
- Content follows the same 16-character cap as
boost create, checked before any request through one shared helper; blank content is refused locally, and-reads content from stdin. - Accepts a boost ID or URL, but the URL must be on a trusted Basecamp host, name exactly one boost, and belong to the configured account — anything else is refused before a request is sent.
- Only the boost's creator can update it; the server's 403, 404, and 422 errors map through the usual error handling.
- Output matches
create: the updated boost, a summary, and breadcrumbs to show and delete it. - Updates the catalog entry,
.surface,API-COVERAGE.md(boosts row 6 to 7), and adds a live smoke test.
Dependencies
Depends on the SDK's UpdateBoost (basecamp-sdk#1016); the bottom DO NOT MERGE commits point the replace at a local SDK worktree. Drop them and run make bump-sdk once the SDK ships.