refactor!: rebrand CCAM to AgentHub
Clean break, no compatibility alias. Renames the product name, the CLI binary (`ccam` -> `agenthub`), the env var prefix (`CCAM_` -> `AGENTHUB_`), the Prometheus metric namespace (`ccam_*` -> `agenthub_*`), the tmux session prefix (`ccam-lane-<id>` -> `agenthub-lane-<id>`), the per-repo runtime profile directory (`.ccam/profile` -> `.agenthub/profile`), the lanes state root (`~/.claude/ccam-lanes` -> `~/.claude/agenthub-lanes`), the bundled plugins (`plugins/ccam*` -> `plugins/agenthub*`) and their slash commands (`/ccam-doctor` -> `/agenthub-doctor`, `/ccam:*` -> `/agenthub:*`). Because there is no alias, an existing install has to be updated by hand: rename its `.ccam/profile` directory and any `CCAM_*` variables, and reinstall the plugin under its new name. Two other name families are deliberately left alone here, since they are not just strings: the `Claude-Code-Monitor` repository/marketplace name, and the `agent-dashboard` npm package plus its `~/.claude/agent-dashboard` runtime directory, which holds the live database and needs a migration rather than a rename. Verified: server 1406/1406, client 459/459, `grep -i ccam` clean across tracked files, `openapi.yaml` regenerated (95 paths, unchanged count).
This commit is contained in:
@@ -26,10 +26,10 @@ Task 4: fix round 1/5 (3 addressed, 0 open — clear now gated on the pre-existi
|
||||
Task 4: complete (commits 76c6f26..3f7121d, review clean) — 780 server tests pass
|
||||
|
||||
Task 5: first attempt reported DONE_WITH_CONCERNS claiming the sandbox blocks loopback — WRONG, and nothing was committed (pre-commit test gate held). Real cause: the plan's own test harness used blocking spawnSync while the test HTTP server ran in the same process, so the event loop stalled and the CLI child's request was never served. Verified loopback works between processes (detached node server + curl + separate node fetch, all exit 0). Plan's code block corrected to async spawn.
|
||||
Task 5: review — spec PASS, 2 Important (ccam lanes add untested; temp DB leaked), 3 Minor.
|
||||
Task 5: review — spec PASS, 2 Important (agenthub lanes add untested; temp DB leaked), 3 Minor.
|
||||
Task 5: fix round 1/5 (2 addressed, 1 open — lanes-add test added, health poll replaced the 100ms sleep, DB cleanup added but not exception-safe; commits 19dd31b..3deb420)
|
||||
Task 5: fix round 2/5 (1 addressed, 0 open — after() teardown wrapped in try/finally; commit 35138b4; verified inline)
|
||||
Task 5: complete (commits 3f7121d..35138b4, review clean) — 783 server tests pass. `ccam lanes add` was an authorised addition so the CLI's empty-state hint names a command that exists.
|
||||
Task 5: complete (commits 3f7121d..35138b4, review clean) — 783 server tests pass. `agenthub lanes add` was an authorised addition so the CLI's empty-state hint names a command that exists.
|
||||
|
||||
Task 6: review — spec MET; security verified adversarially (cross-origin POST to /:id/start returns 403; prompt travels via stdin, model/effort/resumeSessionId are separate argv with no shell; /:id/stage not captured by /:id/:action; unknown action rejected before any lookup or mutation). 1 Important, 2 Minor.
|
||||
Task 6: fix round 1/5 (2 addressed, 0 open — message now consults getRun and returns 409 for a recorded-but-dead run instead of 500; unknown-action test asserts stage/status unchanged; new 409 test; commits f225fe8..b3f9e2f)
|
||||
@@ -42,12 +42,12 @@ Task 7: minor (deferred): the Lanes screen snapshot captures the empty state onl
|
||||
Task 7: minor (deferred): the card cannot send a prompt — driving a lane from the UI needs a prompt/message input; today `start` opens a promptless conversation run and `message` has no input field. Follow-up feature, not a defect.
|
||||
Task 7: complete (commits b3f9e2f..a05065d, review clean) — verified by controller: 279/279 client tests, `npm run build` clean
|
||||
|
||||
Task 8: review — every documented command/flag/env var/endpoint/state-rule fact-checked against the shipped code and correct, EXCEPT one Critical: docs advertised `ccam lanes add --pipeline <id>` which the CLI never parsed.
|
||||
Task 8: review — every documented command/flag/env var/endpoint/state-rule fact-checked against the shipped code and correct, EXCEPT one Critical: docs advertised `agenthub lanes add --pipeline <id>` which the CLI never parsed.
|
||||
Task 8: ruled — fix the CODE, not the docs: a pipeline template you cannot select from the CLI is a template nobody uses, and the server already accepted the field. Authorised a scoped code change inside the docs task.
|
||||
Task 8: fix round 1/5 (1 addressed, 0 open — --pipeline parsed and forwarded only when provided, usage string updated, two tests via a DASHBOARD_PIPELINES_DIR fixture with cleanup, docs parenthetical corrected; commits 6cca59c..3b196ef)
|
||||
Task 8: minor (deferred): README VN/CN/KO mirrors are now behind the English README; the repo's update-project-docs convention expects them synced.
|
||||
Task 8: complete (commits a05065d..3b196ef, review clean) — 790 server tests pass
|
||||
|
||||
Final whole-branch review (Opus): READY — no Critical/Important/Minor findings. Cross-cutting types, CLI-vs-server cwd resolution, WS payload branches, migration safety on an existing DB, the same-origin guard on the spawning routes, and both confirmation gates all verified. All 8 deferred/parked items triaged acceptable-to-defer, none load-bearing.
|
||||
Controller end-to-end smoke test (real server, real CLI, real hook POSTs) — lane created, `ccam stage plan --evidence` then `ccam stage review` reported: node states came back intake=passed-no-evidence, plan=done, implement/tests=passed-no-evidence, review=current, rest=pending; progress 57%; stage_seconds live; `ccam lanes` table and counters correct; a Notification hook bound the lane and a later hook from the newly-bound session cleared needs_action exactly as the amended contract specifies.
|
||||
Side effect found and REVERTED: starting the fork's server auto-configured Claude Code hooks in ~/.claude/settings.json (8 entries pointing at this fork). Removed surgically; the pre-existing `rtk hook claude` PreToolUse entry was left untouched. Polluted copy kept at /tmp/settings.before-ccam-cleanup.json.
|
||||
Controller end-to-end smoke test (real server, real CLI, real hook POSTs) — lane created, `agenthub stage plan --evidence` then `agenthub stage review` reported: node states came back intake=passed-no-evidence, plan=done, implement/tests=passed-no-evidence, review=current, rest=pending; progress 57%; stage_seconds live; `agenthub lanes` table and counters correct; a Notification hook bound the lane and a later hook from the newly-bound session cleared needs_action exactly as the amended contract specifies.
|
||||
Side effect found and REVERTED: starting the fork's server auto-configured Claude Code hooks in ~/.claude/settings.json (8 entries pointing at this fork). Removed surgically; the pre-existing `rtk hook claude` PreToolUse entry was left untouched. Polluted copy kept at /tmp/settings.before-agenthub-cleanup.json.
|
||||
|
||||
@@ -18,7 +18,7 @@ Task 3: complete (883 server tests)
|
||||
|
||||
Task 4 (B4): detected nodes render amber-dashed via a class that REPLACES the state-driven one, so even a hypothetical {detected:true, state:"done"} payload renders amber and never green — the safe direction. `auto:` chip only when the detection leads the declaration. tsc (not vitest) caught a missing field in an unrelated test fixture, which is why `npm run build` is in every client task's verification list.
|
||||
Task 4: complete (308 client tests)
|
||||
Task 5 (B5): `ccam lanes` gains a detected suffix using the same lead-comparison as the card, so terminal and browser never disagree; docs/LANES.md documents the signals, the field allowlist, the 120-char cap, the rules node by node, the deliberate blanks on intake/gate/done, forward-only + write-on-change, and the evidence boundary with its reason. The implementer flagged rather than papered over the fact that GET /api/lanes has NO OpenAPI path docs at all and no Lane schema — it added a standalone schema for the three fields instead of inventing either.
|
||||
Task 5 (B5): `agenthub lanes` gains a detected suffix using the same lead-comparison as the card, so terminal and browser never disagree; docs/LANES.md documents the signals, the field allowlist, the 120-char cap, the rules node by node, the deliberate blanks on intake/gate/done, forward-only + write-on-change, and the evidence boundary with its reason. The implementer flagged rather than papered over the fact that GET /api/lanes has NO OpenAPI path docs at all and no Lane schema — it added a standalone schema for the three fields instead of inventing either.
|
||||
Task 5: complete (885 server tests)
|
||||
|
||||
FINAL whole-branch review (Opus): READY WITH FIXES — 1 Critical, 5 Important, 7 Minor. The evidence boundary itself held: no lane state could be constructed in which a detection renders green or writes lanes.stage, proved by mutation and live probing rather than by reading, with per-event cost measured (1 µs for an ordinary Bash event, zero queries when nothing changes).
|
||||
|
||||
@@ -7,7 +7,7 @@ Task 1: review — spec MET (one accepted deviation: reset-in-place instead of d
|
||||
Task 1: fix round 1/5 (2 addressed, 0 open — ERESETBRANCH verifies the worktree really landed on the feature branch; ENOBASE verifies the base ref before ANY mutation, with a test proving the worktree and its dirty files are untouched on that path; commits 436adfa..03a6e63)
|
||||
Task 1: complete (commits 7195741..03a6e63, review clean) — 801 server tests pass, every commit through the pre-commit gate
|
||||
|
||||
Task 2: review — spec met on the surface, 2 Critical underneath. (a) the migration probed only `kind` while adding four columns, so a crash after the first ALTER left three columns permanently missing on a real install — the plan's own fault; (b) `kind` was validated in createLane only, so updateLane could silently corrupt the boundary that decides whether CCAM may delete a directory. Plus 3 Important (lock Map never pruned, two missing tests).
|
||||
Task 2: review — spec met on the surface, 2 Critical underneath. (a) the migration probed only `kind` while adding four columns, so a crash after the first ALTER left three columns permanently missing on a real install — the plan's own fault; (b) `kind` was validated in createLane only, so updateLane could silently corrupt the boundary that decides whether AgentHub may delete a directory. Plus 3 Important (lock Map never pruned, two missing tests).
|
||||
Task 2: fix round 1/5 (5 addressed, 0 open — per-column independent probes that self-heal a partial migration; shared validateKind() used by both create and update, rejecting before any write so a mixed patch cannot half-apply; lock entry deleted when its chain settles if still current; regression tests for update-kind, per-lane (not global) locking, and an old-schema database plus a simulated mid-migration crash; commits fdf4da4..6138944)
|
||||
Task 2: complete (commits 03a6e63..6138944, review clean) — 808 server tests pass
|
||||
|
||||
@@ -33,7 +33,7 @@ Task 5: complete (commits cf8ebbf..cac0d2a, review clean) — 834 server tests,
|
||||
|
||||
Task 6: written by Codex terra, whose process was killed by a wall-clock limit TWICE before it could run a single test or commit — the work survived staged. A Claude subagent then read the staged diff, verified it and committed it unchanged (00fc9fa). So the code reached review having never been run by its author; the reviewer was told that and given permission to run the CLI test file itself.
|
||||
Task 6: review — no Critical, no Important. Verified field-by-field that the CLI's LANE_PREFLIGHT_FIELDS matches the server's expectedFields exactly and that `expect` is built from the freshly fetched preflight (not client-guessed); `--yes` cannot be bypassed (returns with exit 1 before any POST is constructed); `--force` only ever unlocks the unpushed gate; the adopted-lane refusal is plain language and its test asserts the file's CONTENTS survive; no spawnSync, no bare sleeps, no vacuous tests. Reviewer independently ran the CLI suite: 10/10.
|
||||
Task 6: minor (deferred): `ccam help` shows `[--yes]` while the prose shows it unbracketed; no test covers the ESTALE 409 or the provisioning failed/timeout print paths; the destructive tests share a mutable `managedLane` across describe blocks.
|
||||
Task 6: minor (deferred): `agenthub help` shows `[--yes]` while the prose shows it unbracketed; no test covers the ESTALE 409 or the provisioning failed/timeout print paths; the destructive tests share a mutable `managedLane` across describe blocks.
|
||||
Task 6: complete (commits cac0d2a..00fc9fa, review clean) — 839 server tests
|
||||
|
||||
Task 7: Codex wrote the component work and was killed by a wall-clock limit a third time, leaving it uncommitted and missing both the modal tests and all the documentation; a Claude agent audited it, wrote those, and committed (2a58f5a).
|
||||
@@ -45,13 +45,13 @@ Task 7: complete (commits 00fc9fa..2a58f5a, 1 Critical carried into C8) — 287
|
||||
|
||||
Task 8 (added after Task 7's Critical): implemented by a Claude subagent. Root-cause fix rather than a patch — `blocked[]` had been conflating three kinds of thing, so it now carries only the action-preventing conditions (adopted, missing, unreadable) plus `unpushed-commits` (the one Force overrides), while purely informational facts (`no-remote`) moved to a new `warnings[]`. The modal needed no logic change at all: it was locked out purely because the server mislabelled `no-remote` as blocking. Also landed: status.* i18n keys for all four locales, real support for LANE_BASE_BRANCH and LANE_BRANCH_PREFIX (the spec had promised them, the code had hardcoded main and feat/), CLI tests for the ESTALE print path and for failed provisioning, and `--yes` presented as mandatory everywhere.
|
||||
Task 8: review — APPROVE, no Critical or Important. Reviewer enumerated every blocked[] combination the server can emit and confirmed the modal and the server now agree on all eight; ran the ESTALE test three times (12/12 each, ~300 ms) and confirmed it is structural rather than timing-based, since GET /preflight takes no lock while POST does; verified the env-var tests actually set the variables and observe their values rather than asserting a default that would pass anyway; fact-checked the docs against the code and found no inaccurate sentence.
|
||||
Task 8: minor (deferred, for final-review triage): `lanes.status` is not validated at the API layer — `POST /:id/stage` and `ccam stage --status <s>` accept an arbitrary string, so a rogue value would reproduce the raw-key badge bug this task fixed. The robust fix is a t() defaultValue in LaneCard rather than restricting what an agent may declare.
|
||||
Task 8: minor (deferred, for final-review triage): `lanes.status` is not validated at the API layer — `POST /:id/stage` and `agenthub stage --status <s>` accept an arbitrary string, so a rogue value would reproduce the raw-key badge bug this task fixed. The robust fix is a t() defaultValue in LaneCard rather than restricting what an agent may declare.
|
||||
Task 8: complete (commits 2a58f5a..3139de9, review clean) — 844 server tests, 292 client tests
|
||||
|
||||
FINAL whole-branch review (Opus): READY WITH FIXES — 2 Critical, 6 Important, 9 Minor. Safety core sound: every caller of resetWorktree/removeWorktree/purgeLaneSessions/deleteLane enumerated across server/, bin/, scripts/, mcp/ (the CLI goes over HTTP, so nothing outside the routes reaches the git layer), the guard sits INSIDE both destructive functions rather than only upstream, and the migration was verified against real SQLite including a simulated mid-migration crash.
|
||||
FINAL: the reviewer earned its verdict by mutation — it deleted `await assertDestroyable(lane)` from removeWorktree and all 844 tests stayed green, proving the remove-path guard was pinned by nothing. The same deletion in resetWorktree failed a test.
|
||||
FINAL: controller raised the reviewer's Important I3 to Critical — `cwd LIKE ? || '/%'` was unescaped and `_` is a LIKE wildcard, while every managed lane directory this branch creates is named `<repo>__<slug>`. A lane at /root/myrepo__feat-foo purged sessions belonging to /root/myrepoXXfeat-foo, and the preflight counted the victims too, so the confirmation was consistently wrong rather than detectably wrong. The old fixture (/tmp/wt-purge) had no underscore, so nothing could have caught it.
|
||||
Fix wave (one commit, 513235a, Opus): all 16 findings addressed, +997/-151 across 28 files, 844→857 server tests, 292→297 client tests. Deletion experiments run and reported for C2, C3, I1 and I2. The fixer also found a FOURTH instance of "the UI refusing what the server permits" in bin/ccam.js and disclosed it rather than fixing it silently.
|
||||
Fix wave (one commit, 513235a, Opus): all 16 findings addressed, +997/-151 across 28 files, 844→857 server tests, 292→297 client tests. Deletion experiments run and reported for C2, C3, I1 and I2. The fixer also found a FOURTH instance of "the UI refusing what the server permits" in bin/agenthub.js and disclosed it rather than fixing it silently.
|
||||
Fix-wave re-review (Opus): READY. Verified 857/857 itself, re-ran the C2 mutation in a throwaway copy, and built the four-way table (adopted/missing/unreadable/no-remote × reset/remove/purge × modal/server/CLI) — no square where the UI is stricter than the server, no third instance of the defect.
|
||||
FINAL: the re-reviewer found what neither the fix wave nor I had: a FOURTH refusal shape for C2 that git does NOT incidentally refuse — an adopted lane legitimately pointing at a worktree the user registered themselves. With the guard removed it destroyed the directory silently with no error at all. Check 1 is the sole protection for that case, so the guard was load-bearing well beyond the three shapes the tests cover.
|
||||
FINAL: it also disproved the fix wave's own reasoning on `unreadable` + `remove` by reproducing a corrupt-.git worktree: `git worktree remove --force` and even `--force --force` both refuse (code 128), so the promise written into `destructive.notice.unreadable` in all four locales and into two doc lines — that removal is forced and git's entry cleared — is FALSE for that shape. Decision to unblock stands (blocking recreates the defect class), but the copy over-promises.
|
||||
|
||||
@@ -147,12 +147,12 @@ produces zero diff against the currently committed file.
|
||||
previously the only two mutating lane routes without it.
|
||||
|
||||
Checked both callers before changing anything:
|
||||
- `bin/ccam.js`'s `post()` helper (backing `ccam lanes add` and `ccam stage`)
|
||||
- `bin/agenthub.js`'s `post()` helper (backing `agenthub lanes add` and `agenthub stage`)
|
||||
only ever sends a `Content-Type` header, never `Origin` or `Referer` — the
|
||||
guard passes any request with no Origin header through unconditionally
|
||||
(same rule already relied on by every other guarded lane route). Verified
|
||||
end to end by re-running `server/__tests__/lanes-cli.test.js` (13/13) after
|
||||
the change — both `ccam lanes add --repo` and the destructive-lifecycle
|
||||
the change — both `agenthub lanes add --repo` and the destructive-lifecycle
|
||||
CLI flows (which call `stage` indirectly via `clear`) still pass.
|
||||
- `grep -rn "api/lanes" mcp/ scripts/` — no hits. Nothing else calls these
|
||||
routes.
|
||||
@@ -191,7 +191,7 @@ changed).
|
||||
corrupt-`.git` case, so it was not inaccurate and editing it would have
|
||||
been unrequested scope.
|
||||
- Did not add a CLI-level test reproducing the corrupt-`.git` removal
|
||||
through `ccam lanes remove` — the brief asked for "a test proving (a)"
|
||||
through `agenthub lanes remove` — the brief asked for "a test proving (a)"
|
||||
which the new `worktree.test.js` case already does directly against
|
||||
`removeWorktree` (the same function the route and CLI both call); adding a
|
||||
second, slower end-to-end CLI version would duplicate coverage without
|
||||
|
||||
Reference in New Issue
Block a user