Files
nntrivi2001 17d56d0e01 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).
2026-09-07 12:09:15 +07:00

73 lines
2.9 KiB
JavaScript

/**
* @file Tests for server/lib/lane-gc.js's capOversizedLogs — pure fs, safe to
* test directly. reapOrphanMcp shells out to pgrep/ps against real OS
* processes; no automated test for that here (same reasoning routes with no
* HTTP test harness already use in this repo) — verified via manual smoke
* check per the F3c design spec.
* @author Nguyễn Ngọc Trí Vĩ <vinnt@smartgift.vn>
*/
const { describe, it, after } = require("node:test");
const assert = require("node:assert/strict");
const fs = require("node:fs");
const os = require("node:os");
const path = require("node:path");
// LANES_ROOT is read once at require time (from worktree.js) — set it before
// the first require, then use it as a fixed root every test writes under.
const SUITE_ROOT = fs.mkdtempSync(path.join(os.tmpdir(), "agenthub-gc-"));
process.env.LANES_ROOT = SUITE_ROOT;
const laneGc = require("../lib/lane-gc");
after(() => fs.rmSync(SUITE_ROOT, { recursive: true, force: true }));
function writeLog(laneSlot, name, sizeBytes, fill = "x") {
const dir = path.join(SUITE_ROOT, ".state", `lane${laneSlot}`, "logs");
fs.mkdirSync(dir, { recursive: true });
const filePath = path.join(dir, name);
fs.writeFileSync(filePath, fill.repeat(sizeBytes));
return filePath;
}
describe("capOversizedLogs", () => {
it("leaves a log under the 10MB cap untouched", () => {
const filePath = writeLog(1, "boot.log", 1024);
const before = laneGc.capOversizedLogs();
assert.deepEqual(
before.filter((c) => c.path === filePath),
[]
);
assert.equal(fs.statSync(filePath).size, 1024);
});
it("caps a log over 10MB to its last 2MB, in place", () => {
const dir = path.join(SUITE_ROOT, ".state", "lane2", "logs");
fs.mkdirSync(dir, { recursive: true });
const filePath = path.join(dir, "e2e.log");
const fd = fs.openSync(filePath, "w");
// Distinguishable content: 9MB of 'a', then a 2MB tail of 'b's we can
// assert survived, sized to land over the 10MB cap.
fs.writeSync(fd, "a".repeat(9 * 1024 * 1024));
fs.writeSync(fd, "b".repeat(2 * 1024 * 1024));
fs.closeSync(fd);
const result = laneGc.capOversizedLogs();
const entry = result.find((c) => c.path === filePath);
assert.ok(entry, "expected e2e.log to be reported as capped");
assert.equal(entry.sizeBefore, 11 * 1024 * 1024);
const capped = fs.readFileSync(filePath, "utf8");
assert.equal(capped.length, 2 * 1024 * 1024);
assert.ok(capped.split("").every((ch) => ch === "b"));
});
it("--dry-run reports what would be capped without touching the file", () => {
const filePath = writeLog(3, "boot.log", 11 * 1024 * 1024);
const result = laneGc.capOversizedLogs({ dryRun: true });
const entry = result.find((c) => c.path === filePath);
assert.ok(entry, "expected boot.log to be reported as would-be-capped");
assert.equal(fs.statSync(filePath).size, 11 * 1024 * 1024);
});
});