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:
@@ -461,7 +461,7 @@ export function Workspace() {
|
||||
}
|
||||
};
|
||||
|
||||
// Mirrors `ccam lanes pipeline <template> <id>`: same PATCH, same
|
||||
// Mirrors `agenthub lanes pipeline <template> <id>`: same PATCH, same
|
||||
// stage-mismatch warning when the current declared stage matches no node
|
||||
// in the newly chosen template.
|
||||
const handlePipelineChange = async (id: number, pipeline: string) => {
|
||||
@@ -470,7 +470,7 @@ export function Workspace() {
|
||||
const { lane } = await api.lanes.update(id, { pipeline });
|
||||
await refreshLanes();
|
||||
// `stage` defaults to the DB sentinel "idle" until a driving session ever
|
||||
// calls `ccam stage` — that's the normal state for most lanes and never
|
||||
// calls `agenthub stage` — that's the normal state for most lanes and never
|
||||
// matches a real pipeline node, so it isn't a mismatch worth surfacing.
|
||||
if (lane.stage !== "idle" && !lane.pipeline_nodes.some((n) => n.state === "current")) {
|
||||
setLaneActionError(
|
||||
@@ -558,7 +558,7 @@ export function Workspace() {
|
||||
))}
|
||||
{!lanes.length && (
|
||||
<p className="text-sm text-fg-muted">
|
||||
{tLanes("emptyState")} <code>ccam lanes add --cwd $(pwd)</code>
|
||||
{tLanes("emptyState")} <code>agenthub lanes add --cwd $(pwd)</code>
|
||||
</p>
|
||||
)}
|
||||
</div>
|
||||
@@ -636,7 +636,7 @@ export function Workspace() {
|
||||
))}
|
||||
</select>
|
||||
{/* `stage` defaults to the DB sentinel "idle" until the driving
|
||||
session ever calls `ccam stage` — that string collides with
|
||||
session ever calls `agenthub stage` — that string collides with
|
||||
`status`'s own "idle"/"running" vocabulary, so a lane that is
|
||||
actively running but has never declared a stage read as if it
|
||||
were sitting idle. Show a distinct label instead of the raw
|
||||
|
||||
@@ -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