Commit Graph

27 Commits

Author SHA1 Message Date
nntrivi2001 56744b360d feat(run): add tmux-backed run lifecycle (spawn/kill/list computed from tmux state) 2026-08-12 09:38:25 +07:00
nntrivi2001 1dd18fe98c feat(run): add tmux command wrapper with an injectable exec seam 2026-08-12 09:34:18 +07:00
nntrivi2001 dfea1a99d6 fix(tests): scrub GIT_* env vars leaking from the pre-commit hook into git-fixture tests
server/lib/update-check.js's execGit() and two test helpers
(lanes-cli.test.js, update-check.test.js) shelled out to git with an
explicit `cwd` but no `env` override. A parent git hook process (this
repo's own .husky/pre-commit, which runs `npm run test:server`) sets
GIT_DIR/GIT_INDEX_FILE in its own environment; those leak to every
child process and take precedence over `cwd` for repo discovery, so
every git command these tests ran against their throwaway tmp repos
was silently redirected at the real repo running the hook instead —
reproduced firsthand as four foreign "init"/"fixture" commits
overwriting a worktree branch mid pre-commit run. Fixes it the same
way server/lib/worktree.js already documented and did for its own git
calls: strip the GIT_* vars before exec.
2026-08-12 09:24:03 +07:00
nntrivi2001 67edda77eb feat(lanes): make the pipeline map track a skill's real progress
A lane's pipeline map only ever moved when a skill remembered to call
`ccam stage`, and the ship-feature template shipped with no detection rules
at all — so a lane driven by Superpowers skills sat at whatever stage it
last declared, and the `gates` node was never declared by anything.

Detection (`detect` rules on each node) now covers the Superpowers skill
invocations and the `ccam`/`gh` commands the ship-feature-lane skill
actually runs. It stays a safety net, not the mechanism: forward-only,
never `done`, never overriding a declaration. Two rules were deliberately
left out — `git diff` on `review` (this repo's own tests record it pinning
a lane at `review` on a real session) and anything on `merged`/`done`.

Stage vocabulary grows to 50 names over the same 16 nodes, following
Shipyard's PHASES shape: sub-states like `migration-collision`,
`e2e-scoped` and `gate-blocked` say WHY a lane sits on a node without the
map growing a node per reason. Every alias has a source — the skill
declares it, `default.json` uses it, or Shipyard's PHASES lists it.

Two silent failures fixed along the way:

- `lane.stages` is keyed by the raw declared string, so a stage declared
  under an alias lost its `--evidence` and rendered amber instead of
  green. `stageRecords` resolves each key onto its node.
- `ccam stage <typo>` stored fine and then rendered nowhere. It now warns
  on stderr while still exiting 0.

`ccam lanes pipeline` closes the gap that made all of this invisible: a
lane could only be assigned a template at creation, and no screen in the
web UI offers the choice, so every lane added from "+ Add lane" was stuck
on `default`'s 8 nodes. An unknown template id is now refused rather than
silently falling back to `default` on read.

Also merges the repo's own `ship-feature` skill into the Superpowers
workflow: it delegates planning/TDD/review/verification instead of
restating them, and declares a stage at each phase.
2026-08-07 09:34:20 +07:00
nntrivi2001 78f6e1be8e feat(lanes): Add Lane repo/worktree mode toggle, manual branch, folder browse
- Repo mode adopts a directory as-is via /lanes/ensure (no worktree, no
  branch fields) - the right choice for a main repo you want stage
  detection on. Worktree mode (default) keeps the existing provisioning
  flow but now requires a manually-typed branch name instead of deriving
  one from the title.
- POST /lanes/worktree accepts an optional `branch`, validated via
  `git check-ref-format --branch`; omitting it preserves the CLI's
  existing auto-derived-branch behavior.
- New GET /lanes/browse lists a directory's immediate subdirectories,
  backing a small folder-browse modal on both path fields - browsers
  cannot expose an absolute path from a native picker, so this is
  server-backed instead, consistent with the tool's local-first model.
2026-08-06 16:03:49 +07:00
nntrivi2001 e7ef7bcef9 feat(lanes): extract skills-install lib, add POST /api/skills/install (F4) 2026-08-06 09:26:43 +07:00
nntrivi2001 5e620bd8ab feat(lanes): add ccam lanes gc — orphan MCP reap + log capping (E, F3c)
Ports the two pieces of Shipyard's lane-gc.sh that match CCAM's actual
architecture: kill Playwright MCP processes reparented to pid 1 (owning
session died), cap hook logs over 10MB back to their last 2MB in place.
Drops auto-removing stale worktrees by age (conflicts with the
never-automatic-destroy rule), state archiving, and scratch-debris
sweep (different storage architecture / files CCAM doesn't generate) —
see docs/superpowers/specs/2026-08-05-lane-gc-design.md.
2026-08-05 17:44:46 +07:00
nntrivi2001 8fc7a32490 feat(lanes): add isIntegrationEnabled toggle check (F3a) 2026-08-05 16:12:58 +07:00
nntrivi2001 2731b7c8ce feat(lanes): add lane-mcp sync core (F1) 2026-08-05 15:20:25 +07:00
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
nntrivi2001 4134b3d307 feat(lanes): add lane-agents install core (E3) 2026-08-05 12:37:40 +07:00
nntrivi2001 d12e9410e3 feat(lanes): add lane-sync core — check/merge/continue (E2) 2026-08-05 10:36:33 +07:00
nntrivi2001 a4246528fe feat(lanes): add MIGRATIONS_DIR + GENERATED_MERGE_PATHS profile declarations (E2) 2026-08-05 10:30:41 +07:00
nntrivi2001 31f984c750 feat(lanes): add --qc boot flag + QC_BOOT_ENV for deterministic QC stacks (E1) 2026-08-04 17:51:03 +07:00
nntrivi2001 e6942db7fe feat(lanes): add proof gallery core (list/file/delete/link) (C) 2026-08-04 15:55:04 +07:00
nntrivi2001 fcc7a8f2f3 fix(lanes): stop archive/activate from clobbering feature title and links
archiveActiveFeature was overwriting a feature's own title with the
LIVE lane's title on every clear/switch — a --title set on activation
silently disappeared. activateFeature restored stage/status/gate/CI/
stages/notes onto the live lane when switching back to a past feature,
but never links, so they vanished on reactivation. Both are fixed, with
a regression test for each (full activate/archive/reactivate round trip
for links).

Also fixes server/routes/lanes.js: the doc comment explaining GET
/:id/git's rationale had been left sitting above the newly-inserted
/:id/features routes instead of its own route.

docs/API.md's Lane features section described fields and behavior that
don't exist in the real routes (an "active" boolean, a POST response
containing "archivedPrevious", a "409 ESTALE" concurrency response) —
rewritten to match the actual request/response shapes exactly.
2026-08-04 15:17:14 +07:00
nntrivi2001 aa01d77ce6 feat(lanes): clearLane archives the active feature before resetting (B) 2026-08-04 14:23:01 +07:00
nntrivi2001 181e0f77ff feat(lanes): add per-feature state + archive core (lane_features) (B) 2026-08-04 14:16:48 +07:00
nntrivi2001 2312c53788 feat(locks): add cross-lane named locks (mkdir-atomic, staleness floor) (D) 2026-08-04 10:53:58 +07:00
nntrivi2001 9d145865dd feat(lanes): per-lane database, Redis, and .env isolation (A1+A2)
Gives each lane its own slot-derived runtime (ports, detached process
lifecycle, profile-driven hooks) and its own database/Redis logical
index/.env file, so two lanes running the same repo's stack at once no
longer share state. Machine-level DB/Redis credentials live at
~/.ccam/secrets.env (mode 0600, never returned by any route); a hook's
output is redacted of that password (raw and URL-encoded forms) before
it reaches a log file or the lane_hook_output websocket broadcast.
Wired into provision/up/reset/remove; reset accepts --keep-db to skip
the drop/recreate/migrate/reseed block entirely.
2026-08-04 10:03:40 +07:00
nntrivi2001 c3546f568a fix(lanes): add error handling for unreadable hook files in checkProfile 2026-08-04 09:36:58 +07:00
nntrivi2001 fa489016b4 feat(lanes): validate a scaffolded profile with checkProfile (A3) 2026-08-04 09:28:59 +07:00
nntrivi2001 9f9879cc3d feat(lanes): scaffold .ccam/profile/ from detected Node facts (A3) 2026-08-04 09:20:22 +07:00
nntrivi2001 c4b11799dc feat(lanes): detect docker-compose database/Redis and wire ENV_REWRITE (A3) 2026-08-04 09:13:20 +07:00
nntrivi2001 0ecc2eec24 feat(lanes): detect a Node.js project's layout and boot scripts (A3) 2026-08-04 09:06:45 +07:00
nntrivi2001 4905d63b97 fix(lanes): clear stale detection on real stage transitions, exclude scratch dirs from implement detect
setStage() left detected_stage/signal/at untouched across a real transition,
so a prior task's leftover inference (e.g. `tests` from earlier work) both
misrepresented a fresh task's progress and — because recordDetection is
forward-only — silently rejected every real detection behind it until the
old one aged past DETECTION_TTL_MS. A real stage change now clears the
detection columns; a same-stage heartbeat leaves a live detection alone.

Also excludes `.superpowers/` from the `implement` node's Write detect rule
- brainstorm-companion scratch files were being counted as implementation
work.

fix(client): disable Node's default --experimental-webstorage in tests

Node 25 enables --experimental-webstorage by default, which defines a
broken global `localStorage` (no backing file configured) ahead of jsdom's
own full polyfill. Every test touching real localStorage failed with
"localStorage.clear/getItem is not a function" — not flaky, not test-specific,
just this one Node default. NODE_OPTIONS=--no-experimental-webstorage on the
test scripts lets jsdom's polyfill take over as before.
2026-07-31 10:53:07 +07:00
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