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:
@@ -11,13 +11,13 @@ const fs = require("node:fs");
|
||||
const { describe, it, after } = require("node:test");
|
||||
const assert = require("node:assert/strict");
|
||||
|
||||
const SUITE_ROOT = fs.mkdtempSync(path.join(os.tmpdir(), "ccam-detect-"));
|
||||
const SUITE_ROOT = fs.mkdtempSync(path.join(os.tmpdir(), "agenthub-detect-"));
|
||||
// Must be set before the first require of anything that transitively loads
|
||||
// server/lib/secrets.js (lane-detect.js does, for checkProfile) — SECRETS_PATH
|
||||
// is bound once at that module's first load, and without this a test run on a
|
||||
// machine with a real ~/.ccam/secrets.env would read that file instead of a
|
||||
// machine with a real ~/.agenthub/secrets.env would read that file instead of a
|
||||
// deterministic, isolated one.
|
||||
process.env.CCAM_SECRETS_PATH = path.join(SUITE_ROOT, "secrets.env");
|
||||
process.env.AGENTHUB_SECRETS_PATH = path.join(SUITE_ROOT, "secrets.env");
|
||||
process.env.DASHBOARD_DB_PATH = path.join(SUITE_ROOT, "dashboard.db");
|
||||
process.env.LANES_ROOT = path.join(SUITE_ROOT, "lanes");
|
||||
after(() => fs.rmSync(SUITE_ROOT, { recursive: true, force: true }));
|
||||
@@ -180,7 +180,7 @@ describe("scaffoldProfile", () => {
|
||||
|
||||
const result = detect.scaffoldProfile(repo, facts);
|
||||
|
||||
const profileDir = path.join(repo, ".ccam", "profile");
|
||||
const profileDir = path.join(repo, ".agenthub", "profile");
|
||||
const env = fs.readFileSync(path.join(profileDir, "profile.env"), "utf8");
|
||||
assert.match(env, /PORTS="app"/);
|
||||
assert.match(env, /PORT_BASE_app=3000/);
|
||||
@@ -209,7 +209,7 @@ describe("scaffoldProfile", () => {
|
||||
|
||||
const result = detect.scaffoldProfile(repo, facts);
|
||||
|
||||
const profileDir = path.join(repo, ".ccam", "profile");
|
||||
const profileDir = path.join(repo, ".agenthub", "profile");
|
||||
const env = fs.readFileSync(path.join(profileDir, "profile.env"), "utf8");
|
||||
assert.match(env, /DB_PREFIX=/);
|
||||
assert.match(env, /REDIS=1/);
|
||||
@@ -238,7 +238,10 @@ describe("scaffoldProfile", () => {
|
||||
env: null,
|
||||
};
|
||||
const result = detect.scaffoldProfile(repo, facts);
|
||||
const boot = fs.readFileSync(path.join(repo, ".ccam", "profile", "hooks", "boot.sh"), "utf8");
|
||||
const boot = fs.readFileSync(
|
||||
path.join(repo, ".agenthub", "profile", "hooks", "boot.sh"),
|
||||
"utf8"
|
||||
);
|
||||
assert.match(boot, /# TODO: no start\/dev script found/);
|
||||
assert.equal(result.todos.length, 1);
|
||||
});
|
||||
@@ -307,7 +310,7 @@ describe("checkProfile", () => {
|
||||
const repo = makeRepo();
|
||||
writePkg(repo, { start: "node index.js" });
|
||||
detect.scaffoldProfile(repo, detect.detectNode(repo));
|
||||
fs.rmSync(path.join(repo, ".ccam", "profile", "hooks", "health.sh"));
|
||||
fs.rmSync(path.join(repo, ".agenthub", "profile", "hooks", "health.sh"));
|
||||
const result = await detect.checkProfile(repo);
|
||||
assert.equal(result.ok, false);
|
||||
assert.ok(result.errors.some((e) => /health/.test(e)));
|
||||
@@ -319,7 +322,7 @@ describe("checkProfile", () => {
|
||||
writeCompose(repo, " postgres:\n image: postgres:16\n");
|
||||
detect.scaffoldProfile(repo, detect.detectNode(repo));
|
||||
// Remove the migrate/seed TODO lines so only the secrets warning is left to check.
|
||||
const hooksDir = path.join(repo, ".ccam", "profile", "hooks");
|
||||
const hooksDir = path.join(repo, ".agenthub", "profile", "hooks");
|
||||
fs.writeFileSync(path.join(hooksDir, "migrate.sh"), "#!/usr/bin/env bash\nexit 0\n");
|
||||
fs.writeFileSync(path.join(hooksDir, "seed.sh"), "#!/usr/bin/env bash\nexit 0\n");
|
||||
const result = await detect.checkProfile(repo);
|
||||
@@ -330,7 +333,7 @@ describe("checkProfile", () => {
|
||||
const repo = makeRepo();
|
||||
writePkg(repo, { start: "node index.js" });
|
||||
detect.scaffoldProfile(repo, detect.detectNode(repo));
|
||||
const hookPath = path.join(repo, ".ccam", "profile", "hooks", "health.sh");
|
||||
const hookPath = path.join(repo, ".agenthub", "profile", "hooks", "health.sh");
|
||||
fs.chmodSync(hookPath, 0o000);
|
||||
try {
|
||||
const result = await detect.checkProfile(repo);
|
||||
|
||||
Reference in New Issue
Block a user