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.
This commit is contained in:
2026-07-29 17:07:45 +07:00
commit 57dc91585d
783 changed files with 221743 additions and 0 deletions
+100
View File
@@ -0,0 +1,100 @@
#!/usr/bin/env node
/**
* @file Pre-build guard.
*
* Ensures the desktop bundle has everything it needs before TypeScript
* compiles. Specifically:
* 1. The root repo's node_modules exists (Express + friends).
* 2. The client has been built (client/dist exists). In production mode the
* Express server serves the SPA from client/dist; if it's missing the
* DMG would ship a 404-only dashboard.
* 3. Asset PNGs exist (or we leave a clear warning — icons can be
* regenerated via scripts/build-icons.sh).
* 4. The desktop-local better-sqlite3 native binary matches this machine's
* CPU architecture. A prior `electron-builder --mac --x64/--arm64` build
* rebuilds it for the target arch; left mismatched it breaks `desktop:dev`
* and `desktop:test` with ERR_DLOPEN_FAILED. We rebuild it if so.
* @author Nguyễn Ngọc Trí Vĩ <vinnt@smartgift.vn>
*/
const fs = require("node:fs");
const path = require("node:path");
const { spawnSync } = require("node:child_process");
const { hasBetterSqliteBinary, printNativeDepHelp } = require("./preflight");
const desktopRoot = path.resolve(__dirname, "..");
const repoRoot = path.resolve(__dirname, "..", "..");
const clientDist = path.join(repoRoot, "client", "dist");
const rootNodeModules = path.join(repoRoot, "node_modules");
const assets = path.join(desktopRoot, "assets");
function run(cmd, args, opts = {}) {
// On Windows `npm`/`npx` are `.cmd` shims that `spawnSync` can only launch
// through a shell; without this it fails with ENOENT. POSIX is unaffected.
const result = spawnSync(cmd, args, {
stdio: "inherit",
shell: process.platform === "win32",
...opts,
});
if (result.status !== 0) {
throw new Error(`${cmd} ${args.join(" ")} failed with exit ${result.status}`);
}
}
if (!fs.existsSync(rootNodeModules)) {
console.log("[prebuild] installing root dependencies…");
run("npm", ["ci"], { cwd: repoRoot });
}
if (!fs.existsSync(clientDist) || !fs.existsSync(path.join(clientDist, "index.html"))) {
console.log("[prebuild] building client (client/dist missing)…");
run("npm", ["ci"], { cwd: path.join(repoRoot, "client") });
run("npm", ["run", "build"], { cwd: repoRoot });
}
const trayIcon = path.join(assets, "tray-icon-Template.png");
if (!fs.existsSync(trayIcon)) {
console.warn(
"[prebuild] WARN: tray-icon-Template.png missing. Run `npm run build:icons` to regenerate from assets/icon.svg."
);
}
// Heal a better-sqlite3 native binary left built for the wrong CPU arch by a
// prior `electron-builder --mac --x64/--arm64` run. Without this, `desktop:dev`
// and `desktop:test` fail to load the module (ERR_DLOPEN_FAILED) until the
// contributor manually re-runs `npm run desktop:install`.
if (process.platform === "darwin") {
const bsNode = path.join(
desktopRoot,
"node_modules",
"better-sqlite3",
"build",
"Release",
"better_sqlite3.node"
);
if (fs.existsSync(bsNode)) {
const desc = spawnSync("file", ["-b", bsNode], { encoding: "utf8" }).stdout || "";
// A universal binary works on both arches; only act on a clear mismatch.
const universal = /universal/i.test(desc);
const wrongArch =
!universal &&
((process.arch === "arm64" && !/arm64/.test(desc)) ||
(process.arch === "x64" && !/x86_64/.test(desc)));
if (wrongArch) {
console.log(
"[prebuild] better-sqlite3 is built for the wrong CPU arch (a prior DMG build left it that way) — rebuilding for this machine…"
);
run("npx", ["electron-builder", "install-app-deps"], { cwd: desktopRoot });
}
}
}
// The embedded server `require`s better-sqlite3 at boot; without its native
// binary the desktop app dies with a fatal dialog after compiling cleanly.
// Catch it here (a build-time, copy-pasteable failure) rather than at runtime.
if (!hasBetterSqliteBinary()) {
printNativeDepHelp("The desktop-local better-sqlite3 native binary is missing.");
process.exit(1);
}
console.log("[prebuild] ok");