singularity-forge/src
Jeremy McSpadden ea2118d794 feat(cleanup): add ~/.gsd/projects/ orphan detection and pruning (#1686)
* fix(worktree): recurse into tasks/ when syncing slice artifacts back to project root (#1678)

syncWorktreeStateBack() only processed files directly in each slice
directory, silently skipping the tasks/ subdirectory. Task-level
summaries (T01-SUMMARY.md, T02-SUMMARY.md, etc.) were therefore never
copied from the worktree back to the project root before teardown,
causing data loss when the worktree was removed on milestone completion.

Fix: detect the tasks/ directory entry in the inner loop and recurse
into it, copying all .md files and appending them to the synced list.
Consistent with how syncStateToProjectRoot() already uses recursive
copy via safeCopyRecursive().

Adds regression test (case 8 in worktree-sync-milestones.test.ts)
covering slice-level and task-level summary sync.

* feat(cleanup): add ~/.gsd/projects/ orphan detection and pruning

Introduces a complete lifecycle management story for the external project
state directory (~/.gsd/projects/<hash>/). Previously these directories
accumulated indefinitely with no mechanism to identify or remove them
after a repo was deleted or moved.

Changes:

repo-identity.ts
- Write `repo-meta.json` into each external state dir on first open
  (and backfill on any subsequent open if the file is missing).
- Records: version, hash (dir name), gitRoot, remoteUrl, createdAt.
- Non-fatal: metadata write failure never blocks project setup.
- Export `readRepoMeta()` and `RepoMeta` interface for consumers.

doctor-types.ts
- Add `orphaned_project_state` to DoctorIssueCode.
- Add `GLOBAL_STATE_CODES` set — codes that must never be auto-fixed
  at fixLevel=task (post-task automated health checks must not delete
  project state directories).

doctor-checks.ts
- Add `checkGlobalHealth()` — scans ~/.gsd/projects/, reads repo-meta.json
  from each dir, reports info-severity issue for any whose gitRoot is gone.
- Auto-fixable with --fix; skipped entirely at fixLevel=task.

doctor.ts
- Import and call `checkGlobalHealth` after `checkRuntimeHealth`.
- Gate on `GLOBAL_STATE_CODES` in `shouldFix` at task fixLevel.

commands-maintenance.ts
- Add `handleCleanupProjects(args, ctx)` — interactive audit command.
- Categorises dirs as active / orphaned / unknown (no metadata yet).
- Without --fix: prints full report with per-dir gitRoot + remoteUrl.
- With --fix: deletes orphaned dirs, reports removed/failed counts.

commands/handlers/ops.ts
- Route `cleanup projects` and `cleanup projects --fix` to handler.

commands/catalog.ts
- Add `projects` and `projects --fix` to cleanup tab-completions.

* feat(cleanup): add metrics.json bloat detection and pruning

The metrics ledger has no TTL and grows by one entry per completed unit —
~1-2 KB/entry with no ceiling. On a busy project (50 units/day) this
reaches 4-9 MB in 90 days and continues growing indefinitely.

Changes:

metrics.ts
- Add pruneMetricsLedger(base, keepCount): trims oldest entries from the
  head of the units array, keeping the newest `keepCount`. Updates both
  the on-disk file and the in-memory ledger if a session is active.

doctor-types.ts
- Add "metrics_ledger_bloat" to DoctorIssueCode.

doctor-checks.ts (checkRuntimeHealth)
- Add metrics ledger bloat check after the existing integrity check.
- Threshold: 2000 units / fires as "warning".
- Fix: prune to newest 1500 entries via pruneMetricsLedger().
- Reports both the unit count and file size in MB in the issue message.

* fix cleanup project-state path and repo-meta refresh
2026-03-21 08:33:05 -06:00
..
resources feat(cleanup): add ~/.gsd/projects/ orphan detection and pruning (#1686) 2026-03-21 08:33:05 -06:00
tests feat(gsd): activate matching skills in dispatched prompts (#1630) 2026-03-20 13:20:06 -06:00
app-paths.ts feat: add GSD_HOME env var to override global ~/.gsd directory (#1566) 2026-03-20 08:29:01 -06:00
bundled-extension-paths.ts Fix packaging verification and path portability (#378) 2026-03-14 12:28:14 -06:00
bundled-resource-path.ts M001: The Minimal Machine — linear auto-loop, sole-authority state, sidecar queue, WorktreeResolver (#1419) 2026-03-19 14:56:00 -06:00
cli.ts feat: feat(ui): minimal GSD welcome screen on startup (#1584) 2026-03-20 08:11:06 -06:00
extension-discovery.ts fix: apply pi manifest opt-out to extension-discovery.ts (#1545) 2026-03-20 08:11:51 -06:00
extension-registry.ts feat: add GSD_HOME env var to override global ~/.gsd directory (#1566) 2026-03-20 08:29:01 -06:00
headless-answers.ts refactor(headless): remove duplicate jsonLine, use serializeJsonLine from pi-coding-agent (#1039) 2026-03-17 18:35:00 -06:00
headless-context.ts refactor(headless): split 772-line god file into events, UI, and context modules (#1047) 2026-03-17 18:36:20 -06:00
headless-events.ts refactor(headless): split 772-line god file into events, UI, and context modules (#1047) 2026-03-17 18:36:20 -06:00
headless-query.ts M001: The Minimal Machine — linear auto-loop, sole-authority state, sidecar queue, WorktreeResolver (#1419) 2026-03-19 14:56:00 -06:00
headless-ui.ts refactor(headless): split 772-line god file into events, UI, and context modules (#1047) 2026-03-17 18:36:20 -06:00
headless.ts fix: increase headless new-milestone timeout and limit investigation scope (#1230) 2026-03-18 13:54:34 -06:00
help-text.ts feat: add -w/--worktree CLI flag for isolated worktree sessions (#1247) 2026-03-18 14:57:25 -06:00
loader.ts feat: add extension manifest + registry for user-managed enable/disable (#1238) 2026-03-18 14:12:19 -06:00
logo.ts fix: abort squash-merge on conflict and stop auto-mode instead of looping (#merge-bug-fix) 2026-03-12 15:32:39 -06:00
mcp-server.ts feat: add VS Code extension scaffold and MCP server compiled module 2026-03-16 16:46:20 -05:00
models-resolver.ts refactor: remove unnecessary 'as any' casts, dead exports, and duplicate code (#786) 2026-03-16 21:47:04 -06:00
onboarding.ts feat: add anthropic-vertex provider for Claude on Vertex AI (#1533) 2026-03-19 23:14:13 -06:00
pi-migration.ts Merge pull request #151 from dbachelder/fix/pi-provider-reuse-and-extension-loading 2026-03-12 22:25:15 -06:00
remote-questions-config.ts feat: add GSD_HOME env var to override global ~/.gsd directory (#1566) 2026-03-20 08:29:01 -06:00
resource-loader.ts fix: prune stale env-utils.js from extensions root, preventing startup load error (#1655) 2026-03-20 15:43:06 -06:00
startup-timings.ts Improve startup performance with lazy extension loading (#1336) 2026-03-19 07:38:50 -06:00
tool-bootstrap.ts M001: The Minimal Machine — linear auto-loop, sole-authority state, sidecar queue, WorktreeResolver (#1419) 2026-03-19 14:56:00 -06:00
update-check.ts feat: add /gsd update slash command for in-session self-update (#964) 2026-03-17 16:13:02 -06:00
update-cmd.ts feat: add gsd update subcommand for self-update 2026-03-13 18:47:33 -03:00
welcome-screen.ts fix(splash): replace box corners with full-width bars for visual unity with auto-mode widget (#1654) 2026-03-20 15:42:18 -06:00
wizard.ts fix: Phase 1 quick wins — bug fixes, security hardening, and performance 2026-03-16 13:18:02 -05:00
worktree-cli.ts M001: The Minimal Machine — linear auto-loop, sole-authority state, sidecar queue, WorktreeResolver (#1419) 2026-03-19 14:56:00 -06:00
worktree-name-gen.ts feat: add -w/--worktree CLI flag for isolated worktree sessions (#1247) 2026-03-18 14:57:25 -06:00