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:
@@ -96,7 +96,7 @@ vi.mock("../../lib/api", async (importOriginal) => {
|
||||
return { available: false };
|
||||
}),
|
||||
// Same for the lane's own application stack: nothing here asserts on it,
|
||||
// so report the "no .ccam/profile" shape, which is the common case.
|
||||
// so report the "no .agenthub/profile" shape, which is the common case.
|
||||
runtime: vi.fn().mockImplementation(async (id: number) => {
|
||||
recordCall("GET", `/api/lanes/${id}/runtime`);
|
||||
return { available: false };
|
||||
@@ -692,7 +692,7 @@ describe("split terminal view", () => {
|
||||
|
||||
it("falls back to unselected when a persisted lane id no longer exists", async () => {
|
||||
localStorage.setItem(
|
||||
"ccam.workspace.splitView",
|
||||
"agenthub.workspace.splitView",
|
||||
JSON.stringify({ layout: 2, paneLaneIds: [9999, null] })
|
||||
);
|
||||
await renderWorkspace();
|
||||
|
||||
@@ -5086,7 +5086,7 @@ exports[`screen snapshots > Run 1`] = `
|
||||
No lanes yet. Create one from a working directory:
|
||||
|
||||
<code>
|
||||
ccam lanes add --cwd $(pwd)
|
||||
agenthub lanes add --cwd $(pwd)
|
||||
</code>
|
||||
</p>
|
||||
</div>
|
||||
@@ -10368,7 +10368,7 @@ exports[`screen snapshots > Workflows 1`] = `
|
||||
No lane has recorded a stage yet. Create one with
|
||||
|
||||
<code>
|
||||
ccam lanes add --cwd $(pwd)
|
||||
agenthub lanes add --cwd $(pwd)
|
||||
</code>
|
||||
</p>
|
||||
</div>
|
||||
|
||||
@@ -31,12 +31,12 @@ vi.mock("../../lib/api", async (importOriginal) => {
|
||||
// One installed plugin that actually contributes something, so the Claude Code
|
||||
// tab renders PluginCard's contribution chips instead of an empty list.
|
||||
const demoPlugin = {
|
||||
key: "ccam@sg",
|
||||
name: "ccam",
|
||||
key: "agenthub@sg",
|
||||
name: "agenthub",
|
||||
marketplace: "sg",
|
||||
scope: "user",
|
||||
version: "1.4.6",
|
||||
installPath: "/home/test/.claude/plugins/ccam",
|
||||
installPath: "/home/test/.claude/plugins/agenthub",
|
||||
installedAt: "2026-05-01T12:00:00.000Z",
|
||||
lastUpdated: "2026-06-01T09:30:00.000Z",
|
||||
gitCommitSha: "a1b2c3d",
|
||||
@@ -53,31 +53,31 @@ vi.mock("../../lib/api", async (importOriginal) => {
|
||||
{
|
||||
name: "ship-feature",
|
||||
description: "Implement a feature safely end-to-end.",
|
||||
file: "/home/test/.claude/plugins/ccam/skills/ship-feature/SKILL.md",
|
||||
file: "/home/test/.claude/plugins/agenthub/skills/ship-feature/SKILL.md",
|
||||
},
|
||||
{
|
||||
name: "file-headers",
|
||||
description: "Authorship header policy.",
|
||||
file: "/home/test/.claude/plugins/ccam/skills/file-headers/SKILL.md",
|
||||
file: "/home/test/.claude/plugins/agenthub/skills/file-headers/SKILL.md",
|
||||
},
|
||||
],
|
||||
agents: [
|
||||
{
|
||||
name: "qc-local",
|
||||
description: "Local browser QC.",
|
||||
file: "/home/test/.claude/plugins/ccam/agents/qc-local.md",
|
||||
file: "/home/test/.claude/plugins/agenthub/agents/qc-local.md",
|
||||
},
|
||||
],
|
||||
commands: [
|
||||
{
|
||||
name: "ccam-doctor",
|
||||
name: "agenthub-doctor",
|
||||
description: null,
|
||||
file: "/home/test/.claude/plugins/ccam/plugins/ccam/commands/ccam-doctor.md",
|
||||
file: "/home/test/.claude/plugins/agenthub/plugins/agenthub/commands/agenthub-doctor.md",
|
||||
},
|
||||
],
|
||||
outputStyles: [],
|
||||
},
|
||||
pluginJson: { name: "ccam", description: "The dashboard as a plugin.", version: "1.4.6" },
|
||||
pluginJson: { name: "agenthub", description: "The dashboard as a plugin.", version: "1.4.6" },
|
||||
},
|
||||
};
|
||||
|
||||
@@ -614,7 +614,7 @@ describe("plugin contribution chips", () => {
|
||||
it("expands a plugin's skills by name on click, and collapses again", async () => {
|
||||
await openPluginsTab();
|
||||
|
||||
const chip = screen.getByTestId("plugin-contrib-ccam@sg-skills");
|
||||
const chip = screen.getByTestId("plugin-contrib-agenthub@sg-skills");
|
||||
expect(chip).toHaveAttribute("aria-expanded", "false");
|
||||
expect(screen.queryByText("ship-feature")).toBeNull();
|
||||
|
||||
@@ -631,16 +631,16 @@ describe("plugin contribution chips", () => {
|
||||
it("shows only one surface at a time, and prefixes a command with its slash", async () => {
|
||||
await openPluginsTab();
|
||||
|
||||
fireEvent.click(screen.getByTestId("plugin-contrib-ccam@sg-skills"));
|
||||
fireEvent.click(screen.getByTestId("plugin-contrib-ccam@sg-commands"));
|
||||
fireEvent.click(screen.getByTestId("plugin-contrib-agenthub@sg-skills"));
|
||||
fireEvent.click(screen.getByTestId("plugin-contrib-agenthub@sg-commands"));
|
||||
|
||||
expect(screen.queryByText("ship-feature")).toBeNull();
|
||||
expect(screen.getByText("/ccam-doctor")).toBeInTheDocument();
|
||||
expect(screen.getByText("/agenthub-doctor")).toBeInTheDocument();
|
||||
});
|
||||
|
||||
it("leaves hooks as a plain chip - they have no per-item list to open", async () => {
|
||||
await openPluginsTab();
|
||||
|
||||
expect(screen.queryByTestId("plugin-contrib-ccam@sg-hooks")).toBeNull();
|
||||
expect(screen.queryByTestId("plugin-contrib-agenthub@sg-hooks")).toBeNull();
|
||||
});
|
||||
});
|
||||
|
||||
Reference in New Issue
Block a user