Files
Claude-Code-Monitor/monitoring/scripts/start.js
T
nntrivi2001 57dc91585d feat: Claude Code Monitor — lanes, pipelines and a merged workspace
Internal SmartGift build of a Claude Code monitoring dashboard.

Lanes: a durable unit of parallel agent work, one per working directory,
tracked across session restarts. Managed lanes are git worktrees the
dashboard provisions and can reset or remove behind a three-check destroy
guard and a counted preflight; adopted lanes are directories you already
own and are never destroyable.

Pipelines: a lane moves through pipeline stages. A stage the agent declares
with evidence renders green; a stage inferred from the tool-event stream
renders dashed amber and never counts as done. Detection is forward-only
within a 30-minute window, and never writes the declared stage.

Workspace: one page at /run with a lane grid, the selected lane's pipeline,
and a full Claude console behind a disclosure.
2026-07-30 14:39:03 +07:00

155 lines
4.6 KiB
JavaScript

#!/usr/bin/env node
/**
* @file Starts the npm-managed Prometheus + Grafana stack (no Docker / no Brew).
* Downloads binaries on first run if monitoring:setup has not been run yet.
* @author Nguyễn Ngọc Trí Vĩ <vinnt@smartgift.vn>
*/
const fs = require("node:fs");
const { spawnSync } = require("node:child_process");
const path = require("node:path");
const {
PROMETHEUS_CONFIG,
PROMETHEUS_DATA,
GRAFANA_DATA,
RUNTIME_PROVISIONING,
prometheusBinary,
prometheusServerArgs,
PROMETHEUS_CONSOLES_URL,
grafanaBinary,
grafanaHome,
grafanaAdminEnv,
grafanaLoginLabel,
binariesReady,
} = require("./paths");
const {
readPid,
isRunning,
writePid,
writeGrafanaProvisioning,
spawnDetached,
spawnForeground,
waitForHttp,
killProcess,
PROMETHEUS_PID,
GRAFANA_PID,
PROMETHEUS_LOG,
GRAFANA_LOG,
} = require("./lib");
const detached = process.argv.includes("--detach") || process.argv.includes("-d");
const foreground = process.argv.includes("--foreground") || process.argv.includes("-f");
async function ensureBinaries() {
if (binariesReady()) return;
console.log("Monitoring binaries not found — running setup…");
const script = path.join(__dirname, "ensure-binaries.js");
const result = spawnSync(process.execPath, [script], { stdio: "inherit" });
if (result.status !== 0) process.exit(result.status || 1);
}
function assertNotRunning() {
for (const [file, label] of [
[PROMETHEUS_PID, "Prometheus"],
[GRAFANA_PID, "Grafana"],
]) {
const pid = readPid(file);
if (isRunning(pid)) {
console.error(`${label} is already running (pid ${pid}). Run: npm run monitoring:down`);
process.exit(1);
}
}
}
function startPrometheus() {
fs.mkdirSync(PROMETHEUS_DATA, { recursive: true });
const args = prometheusServerArgs(PROMETHEUS_CONFIG);
const binary = prometheusBinary();
if (detached || (!foreground && !process.stdout.isTTY)) {
const pid = spawnDetached(binary, args, {}, PROMETHEUS_LOG);
writePid(PROMETHEUS_PID, pid);
return pid;
}
return spawnForeground(binary, args, {});
}
function startGrafana() {
fs.mkdirSync(GRAFANA_DATA, { recursive: true });
writeGrafanaProvisioning();
const env = {
GF_PATHS_HOME: grafanaHome(),
GF_PATHS_DATA: GRAFANA_DATA,
GF_PATHS_PROVISIONING: RUNTIME_PROVISIONING,
...grafanaAdminEnv(),
};
const args = ["server", "--homepath", grafanaHome()];
const binary = grafanaBinary();
if (detached || (!foreground && !process.stdout.isTTY)) {
const pid = spawnDetached(binary, args, env, GRAFANA_LOG);
writePid(GRAFANA_PID, pid);
return pid;
}
return spawnForeground(binary, args, env);
}
async function main() {
await ensureBinaries();
assertNotRunning();
console.log("Starting CCAM monitoring stack…");
console.log(` Prometheus config: ${PROMETHEUS_CONFIG}`);
console.log(` Grafana home: ${grafanaHome()}`);
if (detached || (!foreground && !process.stdout.isTTY)) {
const promPid = startPrometheus();
const grafPid = startGrafana();
const promOk = await waitForHttp("http://127.0.0.1:9090/-/ready");
const grafOk = await waitForHttp("http://127.0.0.1:3000/api/health");
console.log("");
console.log(
`Prometheus http://localhost:9090 (pid ${promPid})${promOk ? "" : " [still starting]"}`
);
console.log(` CCAM console: ${PROMETHEUS_CONSOLES_URL}`);
console.log(
`Grafana http://localhost:3000 (pid ${grafPid}) ${grafanaLoginLabel()}${grafOk ? "" : " [still starting]"}`
);
console.log(
"CCAM dashboards auto-provisioned (Overview, Sessions & Agents, Tokens & Events, Platform Health)."
);
console.log("Stop with: npm run monitoring:down");
if (!promOk || !grafOk) {
console.log(`Logs: ${PROMETHEUS_LOG} ${GRAFANA_LOG}`);
}
return;
}
// Foreground: Prometheus in background, Grafana in foreground (Grafana owns the tty).
const promPid = spawnDetached(
prometheusBinary(),
prometheusServerArgs(PROMETHEUS_CONFIG),
{},
PROMETHEUS_LOG
);
writePid(PROMETHEUS_PID, promPid);
console.log(`Prometheus running at http://localhost:9090 (pid ${promPid})`);
console.log(` CCAM console: ${PROMETHEUS_CONSOLES_URL}`);
console.log(
`Grafana starting at http://localhost:3000 (${grafanaLoginLabel()}) — Ctrl+C stops both`
);
const graf = startGrafana();
const shutdown = () => {
killProcess(promPid);
process.exit(0);
};
process.on("SIGINT", shutdown);
process.on("SIGTERM", shutdown);
graf.on("exit", (code) => {
shutdown();
process.exit(code ?? 0);
});
}
main().catch((err) => {
console.error(`monitoring:start failed: ${err.message}`);
process.exit(1);
});