feat: add cueapi workers list/delete + cueapi key webhook-secret get/regenerate#33
Conversation
govindkavaturi-art
left a comment
There was a problem hiding this comment.
Smart UX detail: the 404-on-get branch explains the legacy-vs-messaging-primitive distinction ("if you only use the messaging primitive, this is expected") and points users at cueapi agents webhook-secret — saves a support ticket. Workers list+delete + key webhook-secret group, all clean. Approve.
|
@mikemolinet — this PR is approved but has conflict with main since #28 ( Action: rebase onto main, keep both class definitions / both command groups. git fetch origin main
git rebase origin/main
# In tests/test_cli.py: keep BOTH _AgentsClient AND your test class
# In cueapi/cli.py: keep BOTH the agents group from #28 AND your additions
git add -u
git rebase --continue
git push --force-with-leaseI'll re-merge as soon as it's green. Sorry for the cascade — it's the cost of merging the agents group first; the rest of your stack just needs a quick rebase. ✅ |
…et/regenerate` Drains 3 entries from cueapi-cli #25's `endpoints_missing` plus a bonus DELETE that wasn't in the manifest: - GET /v1/workers → `cueapi workers list` - DELETE /v1/workers/{id} → `cueapi workers delete <id>` - GET /v1/auth/webhook-secret → `cueapi key webhook-secret get` - POST /v1/auth/webhook-secret/regenerate → `cueapi key webhook-secret regenerate` Two new / extended groups: `cueapi workers` (top-level) + `cueapi key webhook-secret` (nested under existing `key`). `regenerate` automatically sends `X-Confirm-Destructive: true` header (server-required); pinned by test_key_webhook_secret_regenerate_sends_destructive_header. 404 on `key webhook-secret get` produces a helpful error pointing messaging-primitive-only users at the per-agent path. Tests: 11 new (60 → 71 total). Reuses _FakeResp from agents tests added in #28; adds _WSClient capture class for header-sensitive tests. Skipped from manifest: POST /v1/worker/heartbeat (manifest itself notes it's redundant with cueapi-worker package). No hosted-PR dependency. Rebased against main 2026-05-04 (post-#28 agents-group merge). 🤖 Generated with [Claude Code](https://claude.com/claude-code)
b911635 to
7e049bb
Compare
…, verification, on-success-fire, status) Drains create + update command_drift entries. Click Choice validation on --catch-up + --status. --clear-on-success-fire sends literal null. Tests: 12 new (60 → 72 total). No hosted-PR dependency. Rebased against main 2026-05-04 (post-#28, #33). 🤖 Generated with [Claude Code](https://claude.com/claude-code)
Drains 3 endpoints_missing entries. verify is tri-state (--valid / --invalid / neither). --reason capped at 500 chars client-side. Tests: 12 new (71 → 83 total). No hosted-PR dependency. Rebased against main 2026-05-04 (post-#28, #33). 🤖 Generated with [Claude Code](https://claude.com/claude-code)
…, verification, on-success-fire, status) (#30) Drains create + update command_drift entries. Click Choice validation on --catch-up + --status. --clear-on-success-fire sends literal null. Tests: 12 new (60 → 72 total). No hosted-PR dependency. Rebased against main 2026-05-04 (post-#28, #33). 🤖 Generated with [Claude Code](https://claude.com/claude-code)
…(#589 + #590 port) Cross-package parity port for hosted #589 + #590. Click tri-state for require-payload-override. --required-keys empty string sends [] explicitly. Tests: 14 new (71 → 85 total). Depends on cueapi/cueapi#589 + #590 for user-visible behavior; merges independently. Rebased against main 2026-05-04 (post-#28, #33). 🤖 Generated with [Claude Code](https://claude.com/claude-code)
…-evidence / triggered-by Closes cueapi-cli #25 manifest gap on executions list. Server-side already supports all 4 filters. --has-evidence flag only sent when present. Tests: 6 new (71 → 77 total). No hosted-PR dependency. Rebased against main 2026-05-04 (post-#28, #33). 🤖 Generated with [Claude Code](https://claude.com/claude-code)
…age lifecycle) Closes messages portion of Messaging primitive endpoints_missing. 4 commands (send/get/read/ack). --from goes in X-Cueapi-From-Agent header. --idempotency-key max 255 chars enforced client-side. Tests: 18 new (71 → 89 total). No hosted-PR dependency. Rebased against main 2026-05-04 (post-#28, #33). 🤖 Generated with [Claude Code](https://claude.com/claude-code)
…(#589 + #590 port) Cross-package parity port for hosted #589 + #590. Click tri-state for require-payload-override. --required-keys empty string sends [] explicitly. Tests: 14 new (83 → 97 total). Depends on cueapi/cueapi#589 + #590 for user-visible behavior; merges independently. Rebased against main 2026-05-04 (post-#28, #30, #33). 🤖 Generated with [Claude Code](https://claude.com/claude-code)
verify is tri-state (--valid / --invalid / neither). --reason capped at 500 chars. Tests: 12 new (83 → 95 total). Rebased against main 2026-05-04 (post-#28, #30, #33). 🤖 Generated with [Claude Code](https://claude.com/claude-code)
…(#589 + #590 port) (#26) Cross-package parity port for hosted #589 + #590. Click tri-state for require-payload-override. --required-keys empty string sends [] explicitly. Tests: 14 new (83 → 97 total). Depends on cueapi/cueapi#589 + #590 for user-visible behavior; merges independently. Rebased against main 2026-05-04 (post-#28, #30, #33). 🤖 Generated with [Claude Code](https://claude.com/claude-code)
Adds 3 new subcommands to the executions group. verify is tri-state (--valid / --invalid / neither). --reason capped at 500 chars client-side. Tests: 12 new (83 → 95 total). No hosted-PR dependency. Rebased against main 2026-05-04 (post-#28, #30, #33). 🤖 Generated with [Claude Code](https://claude.com/claude-code)
4 filters: --outcome-state / --result-type / --has-evidence / --triggered-by. --has-evidence flag only sent when present. Tests: 6 new (83 → 89 total). No hosted-PR dependency. Rebased against main 2026-05-04 (post-#28, #30, #33). 🤖 Generated with [Claude Code](https://claude.com/claude-code)
4 commands (send/get/read/ack). --from goes in X-Cueapi-From-Agent header. --idempotency-key max 255 chars enforced client-side. Tests: 18 new (83 → 101 total). No hosted-PR dependency. Rebased against main 2026-05-04 (post-#28, #30, #33). 🤖 Generated with [Claude Code](https://claude.com/claude-code)
Same as before: 4 filters, 6 new tests. Rebased against main 2026-05-04 (post-#26, #28, #30, #33). 🤖 Generated with [Claude Code](https://claude.com/claude-code)
Same as before: 4 filters, 6 new tests. Rebased against main 2026-05-04 (post-#26, #28, #30, #33). 🤖 Generated with [Claude Code](https://claude.com/claude-code)
…(rebase v5) Adds 3 new subcommands. verify is tri-state. --reason capped at 500 chars. Tests: 12 new (97 → 109 total). No hosted-PR dependency. Rebased against main 2026-05-04 (post-#26, #28, #30, #33). 🤖 Generated with [Claude Code](https://claude.com/claude-code)
4 commands. --from in X-Cueapi-From-Agent header. Tests: 18 new (97 → 115 total). No hosted-PR dependency. Rebased against main 2026-05-04 (post-#26, #28, #30, #33). 🤖 Generated with [Claude Code](https://claude.com/claude-code)
…38) Updates `parity-manifest.json` to reflect the 8-PR parity wave landed today. `commands_covered` block extended with the new commands (now 35 total): - 3 new executions subcommands (replay / verification-pending / verify) from PR #31 - 9 new agents commands (messaging primitive identity surface) from PR #28 - 4 new messages commands (messaging primitive lifecycle) from PR #29 - 2 new workers commands (list / delete) from PR #33 - 2 new `key webhook-secret` subcommands from PR #33 - `--send-at` flag on `cueapi fire` from PR #37 (in flight, depends on hosted #618) `command_drift`: - `cueapi create`: 6 new flags moved missing → covered (--require-payload-override, --required-keys, --delivery, --alerts, --catch-up, --verification, --on-success-fire). Only `--transport` remains in missing — flagged as refactor scope, not a simple flag-add. - `cueapi update`: 9 new flags moved missing → covered. missing_flags now empty. - `cueapi fire`: new entry capturing the 3 covered flags including --send-at. - `cueapi executions get`: missing_display cleared (PR #589 ported in #26). - `cueapi executions list`: 4 new filters moved missing → covered (no remaining gap). `endpoints_missing`: - All 8 entries from the seed manifest cleared except `POST /v1/worker/heartbeat`. - That endpoint stays in missing with documented rationale: cueapi-worker is the canonical wrapper with proper heartbeat-loop semantics. Direct CLI registration is redundant. Decision documented in the manifest entry + cueapi workers group docstring. `ported_pr_history`: - 9 entries with merge timestamps, replacing the pre-port forward-looking notes. - Each entry cross-references the cueapi-cli PR + the hosted PR (when applicable) + the merge timestamp for forensics. `cli_version_at_audit`: bumped 0.1.x → 0.2.x to reflect the new surface area. `last_full_audit`: kept at 2026-05-04 (this update is the post-merge snapshot of the 2026-05-04 audit, not a fresh audit). 🤖 Generated with [Claude Code](https://claude.com/claude-code)
…2 + #683 parity) (#43) Extends the existing fire command with two flags covering recently-shipped server features. --send-at was already there from a prior port (#618). --exit-criteria (repeatable, max 20) §14 work-verification-light required-assertion keys (cueapi #632). Receiver MUST report values for every key under outcome.assertions; missing keys mark the execution verification_failed. Pass empty string '' once to opt out of cue-level required_assertions for this fire (server distinguishes [] = explicit opt-out from None = use cue-level). --idempotency-key (≤256 chars) Opaque dedup key (cueapi #683 Phase 2). Same key + same body within 24h returns the cached execution; same key + different body returns 409 idempotency_key_conflict. Implementation pin (caught earlier on cueapi-python #33 + cueapi-mcp #29): idempotency_key is a BODY field on cues fire, NOT the Idempotency-Key header. Server's FireRequest schema diverges from the messaging primitive's header-based idempotency. Help text + load-bearing test pin this so a future refactor doesn't 'simplify' to header-based (which would silently not work — server FireRequest is extra='forbid' for unknown body fields, ignores headers in body parsing). Tests added (3): - test_fire_help: pins all 5 flags appear in --help (--payload-override, --merge-strategy, --send-at, --exit-criteria, --idempotency-key) - test_fire_exit_criteria_repeatable_via_help: validates click parser accepts repeated --exit-criteria flags - test_fire_help_pins_idempotency_key_as_body_field: load-bearing pin against future header-refactor 185/185 tests pass (was 183; 2 new + parser-validation added inline). Source: drift audit handoff/cueapi-package-drift-2026-05-06; Backlog rows "Parity port: PR #632 → cueapi-cli" + "PR #683 not in backlog (folded in same-day)". Triggered by cueapi-main confirming bandwidth on cueapi-cli lane this session ([CC-CUEAPI-DOC-DEBT-CLOSED-DISCIPLINE- CODIFIED]). Co-authored-by: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
…to (#623) (#48) * fix(cli): agents webhook-secret regenerate sends X-Confirm-Destructive header (Bug cmp03hy9o) `cueapi agents webhook-secret regenerate <ref>` was making the POST /v1/agents/{ref}/webhook-secret/regenerate request without the `X-Confirm-Destructive: true` header that the server requires. Result: even after the user typed `y` at the confirmation prompt, the request was rejected HTTP 400 server-side. Surfaced 2026-05-10 from Phase 2 messaging smoke testing — identical bug shape to the one already fixed on `cueapi key webhook-secret regenerate` (which did pass the header). Mirror the existing pattern: pass the header on the httpx POST right after the Y/N confirm clears. Tests: - New `test_agents_webhook_secret_regenerate_sends_destructive_header` pins the header on the wire — same shape as the existing `test_key_webhook_secret_regenerate_sends_destructive_header`. * feat(cli): per-message send_at scheduling on messages send + message-to (#623) Adds optional `--send-at` (ISO 8601 string) to `cueapi messages send` and `cueapi message-to` — ports the private-monorepo cueapi #623 server-side change that's already shipped on POST /v1/messages (MessageCreate.send_at in app/schemas/message.py). Server contract pinned: - NULL send_at (default) → send now - Future timestamp → message gates inbox-fetch + push delivery until send_at <= now() - Past timestamps → forgiving fallback (treated as send-now) - Same semantics as cue-fire send_at (PR #618, already shipped) Wire format: send_at flows in the BODY of POST /v1/messages, NOT a header. Mirrors the cue-fire send_at transport. Different from idempotency_key, which is a header. Verify-server-transport-per- endpoint pinned in tests so a refactor doesn't accidentally promote it to a header. Tests: - messages_send: 2 new (send_at_omitted_by_default, send_at_passed_in_body) - message_to: 2 new (send_at_passed_in_body, send_at_omitted_when_unset) - 171/171 pass total This unblocks the cueapi-action port (its messages-send shell branch needs the underlying CLI flag to surface --send-at to GitHub Actions callers). Parallels cueapi-python (already shipped) and cueapi-mcp (just shipped via PR #33) ports of the same private-monorepo PR #623.
Summary
Drains 3 entries from cueapi-cli #25's
endpoints_missingplus a bonus DELETE that wasn't in the manifest:cueapi workers listcueapi workers delete <id> [--yes]cueapi key webhook-secret getcueapi key webhook-secret regenerate [--yes]X-Confirm-Destructive: trueautomatically when confirmedNew / extended groups
cueapi workers— new top-level group for fleet operations.cueapi key webhook-secret— nested under existingkeygroup, paired with the existingcueapi key regenerate(api-key regenerate). Mirrors thecueapi agents webhook-secret get/regenerateshape from PR feat: addcueapi agentscommand group (messaging primitive — identity + inbox + sent) #28.Design notes worth flagging
cueapi key webhook-secret regeneratesendsX-Confirm-Destructive: trueautomatically when the user confirms (or passes--yes). The server requires this header (matches the api-key-regenerate pattern). Pinned bytest_key_webhook_secret_regenerate_sends_destructive_headerso a refactor can't silently drop the header (which would 400 on every call).cueapi key webhook-secret get404 → helpful error. Some accounts (messaging-primitive-only users) don't have a user-level webhook secret — only per-agent ones via Phase 12.1. The 404 response points users atcueapi agents webhook-secret get <ref>instead of being a generic dead-end.workers listempty state points users at cueapi-worker installation rather than rendering a confusing empty table.workers deleteandwebhook-secret regenerateboth prompt for confirmation unless--yes. Matches the existing patterns fromcueapi delete,cueapi agents delete,cueapi agents webhook-secret regenerate.Tests
12 new (36 → 48 total). Mock-based capture of body, params, AND headers (destructive-header pin requires capturing the headers kwarg). All 48 pass locally.
Skipped from manifest
POST /v1/worker/heartbeat(worker registration). The manifest itself notes: "CLI users can register workers via cueapi-worker but not via this CLI directly." Adding it would be redundant with the cueapi-worker package without adding user value.No hosted-PR dependency
All endpoints already shipped on prod (
app/routers/workers.py+app/routers/webhook_secret.py). Pure CLI catch-up.Test plan
python3 -m pytest tests/test_cli.py -q→ 48 passedcueapi workers list→ renders fleet with heartbeat statuscueapi workers delete <decommissioned-id> --yes→ 204cueapi key webhook-secret get→ reveals secretcueapi key webhook-secret regenerate --yes→ returns new secret + verifies the destructive header was honoredParity Impact
Closes 3 entries from
endpoints_missingin cueapi-cli #25'sparity-manifest.json:GET /v1/workersGET /v1/auth/webhook-secretPOST /v1/auth/webhook-secret/regenerate(the manifest had this as "destructive — re-evaluate"; this PR adds the destructive-header + confirmation-prompt safety so it's now safe to ship)Plus a manifest-not-listed bonus:
DELETE /v1/workers/{id}.Manifest update follows after #25 merges to main.
Companion PRs
cueapi agentscommand groupcueapi messagescommand groupAfter this PR merges, the only
endpoints_missingremaining in the manifest isPOST /v1/worker/heartbeat(deliberately skipped — see above).🤖 Generated with Claude Code