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:
@@ -30,7 +30,7 @@ describe("pty-run", () => {
|
||||
tmux.__reset();
|
||||
});
|
||||
|
||||
it("spawnRun creates a new tmux session named ccam-lane-<id> when none exists", () => {
|
||||
it("spawnRun creates a new tmux session named agenthub-lane-<id> when none exists", () => {
|
||||
const calls = [];
|
||||
tmux.__setExecImpl((args) => {
|
||||
calls.push(args);
|
||||
@@ -42,14 +42,14 @@ describe("pty-run", () => {
|
||||
return "";
|
||||
});
|
||||
const handle = pty.spawnRun({ laneId: 42, cwd: "/tmp/repo", model: "opus" });
|
||||
assert.equal(handle.id, "ccam-lane-42");
|
||||
assert.equal(handle.id, "agenthub-lane-42");
|
||||
const newSessionCall = calls.find((c) => c[0] === "new-session");
|
||||
assert.ok(newSessionCall, "expected a new-session call");
|
||||
assert.deepEqual(newSessionCall.slice(0, 6), [
|
||||
"new-session",
|
||||
"-d",
|
||||
"-s",
|
||||
"ccam-lane-42",
|
||||
"agenthub-lane-42",
|
||||
"-c",
|
||||
"/tmp/repo",
|
||||
]);
|
||||
@@ -66,7 +66,7 @@ describe("pty-run", () => {
|
||||
return ""; // has-session succeeds → already running
|
||||
});
|
||||
const handle = pty.spawnRun({ laneId: 7, cwd: "/tmp/repo" });
|
||||
assert.equal(handle.id, "ccam-lane-7");
|
||||
assert.equal(handle.id, "agenthub-lane-7");
|
||||
assert.ok(!calls.some((c) => c[0] === "new-session"), "must not create a duplicate session");
|
||||
assert.ok(!calls.some((c) => c[0] === "send-keys"), "must not type over a live agent");
|
||||
});
|
||||
@@ -82,7 +82,7 @@ describe("pty-run", () => {
|
||||
assert.ok(!calls.some((c) => c[0] === "new-session"), "must not create a duplicate session");
|
||||
const literal = calls.find((c) => c[0] === "send-keys" && c[3] === "-l");
|
||||
assert.ok(literal, "expected a literal send-keys with the command line");
|
||||
assert.match(literal[4], /^CCAM_LANE_ID='8' 'claude' .*'--resume' 'abc12345'$/);
|
||||
assert.match(literal[4], /^AGENTHUB_LANE_ID='8' 'claude' .*'--resume' 'abc12345'$/);
|
||||
assert.ok(
|
||||
calls.some((c) => c[0] === "send-keys" && c[3] === "Enter"),
|
||||
"expected the command to be submitted"
|
||||
@@ -100,7 +100,7 @@ describe("pty-run", () => {
|
||||
assert.ok(literal.endsWith(`'don'\\''t; rm -rf /'`), literal);
|
||||
});
|
||||
|
||||
it("spawnRun puts CCAM_LANE_ID in the new session's environment", () => {
|
||||
it("spawnRun puts AGENTHUB_LANE_ID in the new session's environment", () => {
|
||||
let newSessionArgv = null;
|
||||
tmux.__setExecImpl((args) => {
|
||||
if (args[0] === "has-session") {
|
||||
@@ -114,12 +114,12 @@ describe("pty-run", () => {
|
||||
pty.spawnRun({ laneId: 33, cwd: "/tmp/repo", tool: "codex" });
|
||||
const at = newSessionArgv.indexOf("-e");
|
||||
assert.ok(at > -1, "expected a tmux -e environment flag");
|
||||
assert.equal(newSessionArgv[at + 1], "CCAM_LANE_ID=33");
|
||||
assert.equal(newSessionArgv[at + 1], "AGENTHUB_LANE_ID=33");
|
||||
// Must stay ahead of the `--` that starts the pane's own argv.
|
||||
assert.ok(at < newSessionArgv.indexOf("--"));
|
||||
});
|
||||
|
||||
it("spawnRun prefixes CCAM_LANE_ID when typing into an existing shell pane", () => {
|
||||
it("spawnRun prefixes AGENTHUB_LANE_ID when typing into an existing shell pane", () => {
|
||||
let literal = null;
|
||||
tmux.__setExecImpl((args) => {
|
||||
if (args[0] === "display-message") return "bash\n";
|
||||
@@ -129,7 +129,7 @@ describe("pty-run", () => {
|
||||
pty.spawnRun({ laneId: 12, cwd: "/tmp/repo", tool: "codex" });
|
||||
// An assignment prefix on the same line: tmux's -e only applies at session
|
||||
// creation, and a live shell takes its env from the command line.
|
||||
assert.match(literal, /^CCAM_LANE_ID='12' 'codex'/);
|
||||
assert.match(literal, /^AGENTHUB_LANE_ID='12' 'codex'/);
|
||||
});
|
||||
|
||||
it("spawnRun with resumeSessionId passes --resume in argv", () => {
|
||||
@@ -189,33 +189,33 @@ describe("pty-run", () => {
|
||||
calls.push(args);
|
||||
return "";
|
||||
});
|
||||
assert.equal(pty.killRun("ccam-lane-5"), true);
|
||||
assert.ok(calls.some((c) => c[0] === "kill-session" && c[2] === "ccam-lane-5"));
|
||||
assert.equal(pty.killRun("agenthub-lane-5"), true);
|
||||
assert.ok(calls.some((c) => c[0] === "kill-session" && c[2] === "agenthub-lane-5"));
|
||||
});
|
||||
|
||||
it("listRuns reflects live tmux-session state, not cached memory", () => {
|
||||
tmux.__setExecImpl((args) => {
|
||||
if (args[0] === "list-sessions") return "ccam-lane-1\nccam-lane-2\n";
|
||||
if (args[0] === "list-sessions") return "agenthub-lane-1\nagenthub-lane-2\n";
|
||||
return "";
|
||||
});
|
||||
const first = pty.listRuns();
|
||||
assert.deepEqual(first.map((r) => r.id).sort(), ["ccam-lane-1", "ccam-lane-2"]);
|
||||
assert.deepEqual(first.map((r) => r.id).sort(), ["agenthub-lane-1", "agenthub-lane-2"]);
|
||||
|
||||
// Session killed out-of-band (not through killRun) — next list() call
|
||||
// must self-correct, proving state is computed, not stored.
|
||||
tmux.__setExecImpl((args) => {
|
||||
if (args[0] === "list-sessions") return "ccam-lane-1\n";
|
||||
if (args[0] === "list-sessions") return "agenthub-lane-1\n";
|
||||
return "";
|
||||
});
|
||||
const second = pty.listRuns();
|
||||
assert.deepEqual(
|
||||
second.map((r) => r.id),
|
||||
["ccam-lane-1"]
|
||||
["agenthub-lane-1"]
|
||||
);
|
||||
});
|
||||
|
||||
it("laneIdFromRunId parses the numeric lane id back out", () => {
|
||||
assert.equal(pty.laneIdFromRunId("ccam-lane-42"), 42);
|
||||
assert.equal(pty.laneIdFromRunId("agenthub-lane-42"), 42);
|
||||
assert.equal(pty.laneIdFromRunId("not-a-run-id"), null);
|
||||
});
|
||||
|
||||
@@ -242,7 +242,7 @@ describe("pty-run", () => {
|
||||
initialPrompt: "the live prompt",
|
||||
});
|
||||
const retrieved = pty.getRun(handle.id);
|
||||
assert.equal(retrieved.id, "ccam-lane-99");
|
||||
assert.equal(retrieved.id, "agenthub-lane-99");
|
||||
assert.equal(retrieved.promptPreview, "the live prompt");
|
||||
assert.equal(retrieved.status, "running");
|
||||
});
|
||||
|
||||
Reference in New Issue
Block a user