nntrivi2001 d2327408fb fix(lanes): mergeSync commits a fully rerere-auto-resolved merge instead of rethrowing (E2)
Root cause: the catch block only fell through to the auto-commit path when
`unmergedFiles().length && MERGE_HEAD exists` — but a merge rerere resolved
completely has ZERO unmerged files (git already staged the resolution), so
that guard was always false and the raw git error was rethrown instead.
Found via an audit against the Shipyard source this was ported from.

Fixed by checking MERGE_HEAD first (unconditionally — its absence means the
merge never started, a real failure), then branching on whether any files
are still unmerged. Added a real rerere fixture test (teach a resolution,
recreate the identical conflict, confirm mergeSync auto-commits) — the
existing test suite had no coverage for this path.
2026-08-05 14:39:02 +07:00

Claude Code Monitor

Internal SmartGift build. Local-first dashboard for Claude Code: hooks POST every tool call to an Express + SQLite server, a React UI updates over WebSocket, and lanes track parallel agent work through a pipeline.

Internal build — all rights reserved.

What it does

  • Sessions, agents, events. Everything Claude Code emits, recorded and searchable: tool calls, token usage, cost, subagent trees, transcripts.
  • Lanes. One lane per working directory, surviving session restarts. A lane moves through pipeline stages and the dashboard shows where it is.
  • Stage detection. The stage is inferred from the tool stream, so a session that never calls ccam stage still shows progress — rendered dashed amber and never as done, because an inference is not evidence.
  • Run Claude from the browser. Spawn a session in a lane's directory, stream its output, send follow-ups, resume any past session.
  • Analytics, alerts, Kanban and a workflow view, plus an MCP server and a CLI.

Requirements

Node >= 20 (engines in package.json). Node 24 is what the test suites are verified on — node 25 currently breaks 6 server tests through a better-sqlite3 ABI mismatch and 20 client tests through a global localStorage change.

Install and run

npm run setup          # root, client and vscode-extension dependencies
npm run build          # builds the client into client/dist
npm start              # serves the built client and the API on :4820

Open http://localhost:4820.

Development, with hot reload:

npm run dev            # server on :4820, Vite client on :5173

DASHBOARD_PORT overrides the port. postinstall writes the Claude Code hook entries that feed the dashboard.

The CLI

ccam is linked by npm run setup; otherwise call node bin/ccam.js.

ccam status            # is the dashboard up
ccam start             # start it in the background and wait for healthy
ccam sessions          # recent sessions
ccam lanes             # lanes with stage and progress
ccam stage <name>      # declare the current lane's stage
ccam tail              # live event feed

ccam --help lists the rest.

Lanes

A lane is a working directory the dashboard watches. Two kinds:

  • adopted — a directory you already had. The dashboard only reads it; it is never reset or deleted.
  • managed — a git worktree the dashboard created under LANES_ROOT. It owns the full lifecycle and may reset or remove it, behind a three-check destroy guard and a counted preflight the caller has to echo back.
ccam lanes add --cwd /path/to/repo --title "My feature"    # adopt
ccam lanes add --repo /path/to/repo --slug my-feature      # managed worktree

The declared stage comes from ccam stage. The inferred stage comes from tool events and expires after DETECTION_TTL_MS (default 5 minutes), so a lane can move backwards between work sessions. Detection never writes the declared stage, and an inferred node never renders as done.

A lane can also run its own application stack, isolated per lane, when its repository declares a profile at <repo>/.ccam/profile/ — a profile.env of declarations plus shell hooks the dashboard calls. Each lane gets a slot, and its ports and per-lane directories derive from it:

ccam lanes up          # boot the stack of the lane owning this directory
ccam lanes runtime     # slot, ports, service health
ccam lanes logs api    # tail a service log
ccam lanes down

Services are fully detached, so restarting the dashboard never stops a running lane. This is resource namespacing on the host, not a container: lanes run as the same user and share the network.

docs/LANES.md has the pipeline model, the destroy guard, the preflight contract, the Workspace page, GET /api/lanes/:id/git, and the full runtime/profile contract.

Tests

npm run test:server    # node:test
npm run test:client    # Vitest

Both must be green before a commit; the pre-commit hook runs them plus Prettier.

Layout

Path What
server/ Express API, SQLite schema, hook ingest, lane and worktree libraries
client/ React 18 + Vite + Tailwind dashboard
bin/ccam.js CLI
mcp/ MCP server exposing read-only dashboard tools
desktop/ Electron wrapper that embeds the server
docs/ Architecture, API, lanes, database, deployment
plugins/ Claude Code plugins shipped with the dashboard

Docs

S
Description
No description provided
Readme 72 MiB
Languages
JavaScript 52%
TypeScript 45.2%
HTML 1.3%
Shell 0.6%
CSS 0.4%
Other 0.4%