@opengsd/gsd-pi 1.3.0-dev.65546769 → 1.3.0-dev.965d1788
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +1 -1
- package/dist/resources/.managed-resources-content-hash +1 -1
- package/dist/resources/extensions/claude-code-cli/stream-adapter.js +11 -2
- package/dist/resources/extensions/google-cli/stream-adapter.js +82 -15
- package/dist/resources/extensions/gsd/artifact-verification.js +427 -0
- package/dist/resources/extensions/gsd/auto/orchestrator.js +12 -3
- package/dist/resources/extensions/gsd/auto/session.js +3 -0
- package/dist/resources/extensions/gsd/auto/verification-retry-policy.js +1 -1
- package/dist/resources/extensions/gsd/auto-artifact-paths.js +28 -1
- package/dist/resources/extensions/gsd/auto-dispatch.js +20 -19
- package/dist/resources/extensions/gsd/auto-post-unit.js +1 -1
- package/dist/resources/extensions/gsd/auto-prompts.js +26 -11
- package/dist/resources/extensions/gsd/auto-recovery.js +6 -507
- package/dist/resources/extensions/gsd/auto-runtime-state.js +4 -5
- package/dist/resources/extensions/gsd/auto-timeout-recovery.js +3 -3
- package/dist/resources/extensions/gsd/auto-verification.js +5 -2
- package/dist/resources/extensions/gsd/bootstrap/agent-end-recovery.js +103 -13
- package/dist/resources/extensions/gsd/bootstrap/core-session-tools.js +38 -0
- package/dist/resources/extensions/gsd/bootstrap/db-tools.js +6 -1
- package/dist/resources/extensions/gsd/bootstrap/exec-tools.js +2 -0
- package/dist/resources/extensions/gsd/bootstrap/register-hooks.js +16 -19
- package/dist/resources/extensions/gsd/bootstrap/system-context.js +46 -19
- package/dist/resources/extensions/gsd/bootstrap/tool-call-loop-guard.js +68 -10
- package/dist/resources/extensions/gsd/bootstrap/write-gate.js +1 -1
- package/dist/resources/extensions/gsd/closeout-consistency-gate.js +3 -1
- package/dist/resources/extensions/gsd/commands-context.js +19 -1
- package/dist/resources/extensions/gsd/commands-prefs-wizard.js +16 -10
- package/dist/resources/extensions/gsd/commands-worktree.js +12 -10
- package/dist/resources/extensions/gsd/dashboard-overlay.js +32 -3
- package/dist/resources/extensions/gsd/db/queries.js +60 -0
- package/dist/resources/extensions/gsd/db-workspace.js +55 -3
- package/dist/resources/extensions/gsd/doctor-providers.js +92 -8
- package/dist/resources/extensions/gsd/doctor-runtime-checks.js +3 -0
- package/dist/resources/extensions/gsd/exec-sandbox.js +45 -9
- package/dist/resources/extensions/gsd/flat-phase-migration.js +45 -0
- package/dist/resources/extensions/gsd/forensics.js +2 -32
- package/dist/resources/extensions/gsd/git-service.js +5 -4
- package/dist/resources/extensions/gsd/gitignore.js +3 -0
- package/dist/resources/extensions/gsd/guided-flow-queue.js +66 -5
- package/dist/resources/extensions/gsd/health-widget.js +55 -29
- package/dist/resources/extensions/gsd/json-persistence.js +20 -0
- package/dist/resources/extensions/gsd/knowledge-backfill.js +18 -11
- package/dist/resources/extensions/gsd/layout-policy.js +3 -1
- package/dist/resources/extensions/gsd/markdown-renderer.js +8 -9
- package/dist/resources/extensions/gsd/memory-backfill.js +28 -21
- package/dist/resources/extensions/gsd/memory-consolidation-scanner.js +44 -21
- package/dist/resources/extensions/gsd/metrics.js +4 -4
- package/dist/resources/extensions/gsd/migration-auto-check.js +22 -0
- package/dist/resources/extensions/gsd/milestone-ids.js +32 -2
- package/dist/resources/extensions/gsd/milestone-implementation-evidence.js +26 -20
- package/dist/resources/extensions/gsd/orphan-stash-audit.js +92 -16
- package/dist/resources/extensions/gsd/prompts/code-review.md +6 -4
- package/dist/resources/extensions/gsd/prompts/plan-slice.md +1 -1
- package/dist/resources/extensions/gsd/quick.js +45 -2
- package/dist/resources/extensions/gsd/safety/file-change-validator.js +5 -2
- package/dist/resources/extensions/gsd/session-forensics.js +11 -1
- package/dist/resources/extensions/gsd/skills/gsd-headless/references/commands.md +1 -1
- package/dist/resources/extensions/gsd/state/derive/cache.js +28 -0
- package/dist/resources/extensions/gsd/state/derive/db-open.js +39 -0
- package/dist/resources/extensions/gsd/state/derive/from-db.js +452 -0
- package/dist/resources/extensions/gsd/state/derive/index.js +75 -0
- package/dist/resources/extensions/gsd/state/derive/interrupted-work.js +21 -0
- package/dist/resources/extensions/gsd/state-reconciliation/drift/stale-render.js +45 -2
- package/dist/resources/extensions/gsd/state-reconciliation/index.js +48 -23
- package/dist/resources/extensions/gsd/state-reconciliation/registry.js +32 -28
- package/dist/resources/extensions/gsd/state.js +12 -611
- package/dist/resources/extensions/gsd/tools/complete-milestone.js +4 -2
- package/dist/resources/extensions/gsd/tools/complete-slice.js +2 -2
- package/dist/resources/extensions/gsd/tools/complete-task.js +43 -14
- package/dist/resources/extensions/gsd/tools/exec-tool.js +7 -2
- package/dist/resources/extensions/gsd/undo.js +43 -6
- package/dist/resources/extensions/gsd/unit-context-composer.js +23 -7
- package/dist/resources/extensions/gsd/unit-registry.js +32 -4
- package/dist/resources/extensions/gsd/unmerged-milestone-guard.js +33 -3
- package/dist/resources/extensions/gsd/validation-block-guard.js +9 -4
- package/dist/resources/extensions/gsd/verification-gate.js +7 -0
- package/dist/resources/extensions/gsd/workflow-manifest.js +4 -1
- package/dist/resources/extensions/gsd/workflow-projections.js +19 -14
- package/dist/resources/extensions/gsd/workspace-git-preflight.js +30 -1
- package/dist/resources/extensions/gsd/worktree-manager.js +44 -2
- package/dist/tsconfig.extensions.tsbuildinfo +1 -1
- package/dist/web/standalone/.next/BUILD_ID +1 -1
- package/dist/web/standalone/.next/app-path-routes-manifest.json +12 -12
- package/dist/web/standalone/.next/build-manifest.json +3 -3
- package/dist/web/standalone/.next/prerender-manifest.json +3 -3
- package/dist/web/standalone/.next/react-loadable-manifest.json +9 -9
- package/dist/web/standalone/.next/server/app/_global-error/page_client-reference-manifest.js +1 -1
- package/dist/web/standalone/.next/server/app/_global-error.html +1 -1
- package/dist/web/standalone/.next/server/app/_global-error.rsc +1 -1
- package/dist/web/standalone/.next/server/app/_global-error.segments/_full.segment.rsc +1 -1
- package/dist/web/standalone/.next/server/app/_global-error.segments/_global-error/__PAGE__.segment.rsc +1 -1
- package/dist/web/standalone/.next/server/app/_global-error.segments/_global-error.segment.rsc +1 -1
- package/dist/web/standalone/.next/server/app/_global-error.segments/_head.segment.rsc +1 -1
- package/dist/web/standalone/.next/server/app/_global-error.segments/_index.segment.rsc +1 -1
- package/dist/web/standalone/.next/server/app/_global-error.segments/_tree.segment.rsc +1 -1
- package/dist/web/standalone/.next/server/app/_not-found/page_client-reference-manifest.js +1 -1
- package/dist/web/standalone/.next/server/app/_not-found.html +1 -1
- package/dist/web/standalone/.next/server/app/_not-found.rsc +1 -1
- package/dist/web/standalone/.next/server/app/_not-found.segments/_full.segment.rsc +1 -1
- package/dist/web/standalone/.next/server/app/_not-found.segments/_head.segment.rsc +1 -1
- package/dist/web/standalone/.next/server/app/_not-found.segments/_index.segment.rsc +1 -1
- package/dist/web/standalone/.next/server/app/_not-found.segments/_not-found/__PAGE__.segment.rsc +1 -1
- package/dist/web/standalone/.next/server/app/_not-found.segments/_not-found.segment.rsc +1 -1
- package/dist/web/standalone/.next/server/app/_not-found.segments/_tree.segment.rsc +1 -1
- package/dist/web/standalone/.next/server/app/api/visualizer/route.js +1 -1
- package/dist/web/standalone/.next/server/app/index.html +1 -1
- package/dist/web/standalone/.next/server/app/index.rsc +2 -2
- package/dist/web/standalone/.next/server/app/index.segments/__PAGE__.segment.rsc +2 -2
- package/dist/web/standalone/.next/server/app/index.segments/_full.segment.rsc +2 -2
- package/dist/web/standalone/.next/server/app/index.segments/_head.segment.rsc +1 -1
- package/dist/web/standalone/.next/server/app/index.segments/_index.segment.rsc +1 -1
- package/dist/web/standalone/.next/server/app/index.segments/_tree.segment.rsc +1 -1
- package/dist/web/standalone/.next/server/app/page_client-reference-manifest.js +1 -1
- package/dist/web/standalone/.next/server/app-paths-manifest.json +12 -12
- package/dist/web/standalone/.next/server/middleware-build-manifest.js +1 -1
- package/dist/web/standalone/.next/server/middleware-react-loadable-manifest.js +1 -1
- package/dist/web/standalone/.next/server/pages/404.html +1 -1
- package/dist/web/standalone/.next/server/pages/500.html +1 -1
- package/dist/web/standalone/.next/server/server-reference-manifest.json +1 -1
- package/dist/web/standalone/.next/static/chunks/{2659.b7b129ee6a769448.js → 2659.58e950899a9bb82f.js} +1 -1
- package/dist/web/standalone/.next/static/chunks/2772.a7c1fcc69a4685ef.js +1 -0
- package/dist/web/standalone/.next/static/chunks/{3616.3c60753b8ffcbd2e.js → 3616.61a2af74bb8833c8.js} +1 -1
- package/dist/web/standalone/.next/static/chunks/{4283.8e446784528ed9dc.js → 4283.d0d9e0a955e441cb.js} +1 -1
- package/dist/web/standalone/.next/static/chunks/{5826.a46ecdd1cfe8dabc.js → 5826.5421d66c72b9f34e.js} +1 -1
- package/dist/web/standalone/.next/static/chunks/{8785.481aa5869991b760.js → 8785.e29b3134cab1d153.js} +1 -1
- package/dist/web/standalone/.next/static/chunks/8937.640dc9c2aaa1dfad.js +10 -0
- package/dist/web/standalone/.next/static/chunks/app/{page-6644fc6ee8ca1247.js → page-72a856634ad14c10.js} +1 -1
- package/dist/web/standalone/.next/static/chunks/webpack-9c401904f87ded16.js +1 -0
- package/dist/web/standalone/node_modules/node-pty/build/Makefile +1 -1
- package/package.json +1 -1
- package/packages/cloud-mcp-gateway/package.json +2 -2
- package/packages/contracts/dist/workflow.d.ts +1 -0
- package/packages/contracts/dist/workflow.d.ts.map +1 -1
- package/packages/contracts/dist/workflow.js +2 -0
- package/packages/contracts/dist/workflow.js.map +1 -1
- package/packages/contracts/package.json +1 -1
- package/packages/daemon/package.json +4 -4
- package/packages/gsd-agent-core/dist/agent-session.d.ts +1 -0
- package/packages/gsd-agent-core/dist/agent-session.d.ts.map +1 -1
- package/packages/gsd-agent-core/dist/agent-session.js +3 -0
- package/packages/gsd-agent-core/dist/agent-session.js.map +1 -1
- package/packages/gsd-agent-core/dist/extension-ui-snapshot.d.ts +41 -0
- package/packages/gsd-agent-core/dist/extension-ui-snapshot.d.ts.map +1 -0
- package/packages/gsd-agent-core/dist/extension-ui-snapshot.js +62 -0
- package/packages/gsd-agent-core/dist/extension-ui-snapshot.js.map +1 -0
- package/packages/gsd-agent-core/dist/index.d.ts +2 -0
- package/packages/gsd-agent-core/dist/index.d.ts.map +1 -1
- package/packages/gsd-agent-core/dist/index.js +2 -0
- package/packages/gsd-agent-core/dist/index.js.map +1 -1
- package/packages/gsd-agent-core/dist/session/agent-session-events.js +1 -1
- package/packages/gsd-agent-core/dist/session/agent-session-events.js.map +1 -1
- package/packages/gsd-agent-core/dist/session/agent-session-host.d.ts +1 -0
- package/packages/gsd-agent-core/dist/session/agent-session-host.d.ts.map +1 -1
- package/packages/gsd-agent-core/dist/session/agent-session-host.js.map +1 -1
- package/packages/gsd-agent-core/dist/session/agent-session-prompt.d.ts +5 -0
- package/packages/gsd-agent-core/dist/session/agent-session-prompt.d.ts.map +1 -1
- package/packages/gsd-agent-core/dist/session/agent-session-prompt.js +60 -3
- package/packages/gsd-agent-core/dist/session/agent-session-prompt.js.map +1 -1
- package/packages/gsd-agent-core/dist/transcript-store.d.ts +58 -0
- package/packages/gsd-agent-core/dist/transcript-store.d.ts.map +1 -0
- package/packages/gsd-agent-core/dist/transcript-store.js +132 -0
- package/packages/gsd-agent-core/dist/transcript-store.js.map +1 -0
- package/packages/gsd-agent-core/package.json +5 -5
- package/packages/gsd-agent-modes/dist/modes/interactive/components/tool-execution.d.ts +2 -0
- package/packages/gsd-agent-modes/dist/modes/interactive/components/tool-execution.d.ts.map +1 -1
- package/packages/gsd-agent-modes/dist/modes/interactive/components/tool-execution.js +25 -11
- package/packages/gsd-agent-modes/dist/modes/interactive/components/tool-execution.js.map +1 -1
- package/packages/gsd-agent-modes/dist/modes/interactive/controllers/chat-controller-latency.d.ts +4 -0
- package/packages/gsd-agent-modes/dist/modes/interactive/controllers/chat-controller-latency.d.ts.map +1 -0
- package/packages/gsd-agent-modes/dist/modes/interactive/controllers/chat-controller-latency.js +7 -0
- package/packages/gsd-agent-modes/dist/modes/interactive/controllers/chat-controller-latency.js.map +1 -0
- package/packages/gsd-agent-modes/dist/modes/interactive/controllers/chat-controller.d.ts +3 -24
- package/packages/gsd-agent-modes/dist/modes/interactive/controllers/chat-controller.d.ts.map +1 -1
- package/packages/gsd-agent-modes/dist/modes/interactive/controllers/chat-controller.js +26 -829
- package/packages/gsd-agent-modes/dist/modes/interactive/controllers/chat-controller.js.map +1 -1
- package/packages/gsd-agent-modes/dist/modes/interactive/controllers/chat-handoff-filter.d.ts +58 -0
- package/packages/gsd-agent-modes/dist/modes/interactive/controllers/chat-handoff-filter.d.ts.map +1 -0
- package/packages/gsd-agent-modes/dist/modes/interactive/controllers/chat-handoff-filter.js +312 -0
- package/packages/gsd-agent-modes/dist/modes/interactive/controllers/chat-handoff-filter.js.map +1 -0
- package/packages/gsd-agent-modes/dist/modes/interactive/controllers/chat-pinned-zone.d.ts +31 -0
- package/packages/gsd-agent-modes/dist/modes/interactive/controllers/chat-pinned-zone.d.ts.map +1 -0
- package/packages/gsd-agent-modes/dist/modes/interactive/controllers/chat-pinned-zone.js +130 -0
- package/packages/gsd-agent-modes/dist/modes/interactive/controllers/chat-pinned-zone.js.map +1 -0
- package/packages/gsd-agent-modes/dist/modes/interactive/controllers/chat-segment-walker.d.ts +15 -0
- package/packages/gsd-agent-modes/dist/modes/interactive/controllers/chat-segment-walker.d.ts.map +1 -0
- package/packages/gsd-agent-modes/dist/modes/interactive/controllers/chat-segment-walker.js +258 -0
- package/packages/gsd-agent-modes/dist/modes/interactive/controllers/chat-segment-walker.js.map +1 -0
- package/packages/gsd-agent-modes/dist/modes/interactive/controllers/chat-tool-rollup.d.ts +13 -0
- package/packages/gsd-agent-modes/dist/modes/interactive/controllers/chat-tool-rollup.d.ts.map +1 -0
- package/packages/gsd-agent-modes/dist/modes/interactive/controllers/chat-tool-rollup.js +118 -0
- package/packages/gsd-agent-modes/dist/modes/interactive/controllers/chat-tool-rollup.js.map +1 -0
- package/packages/gsd-agent-modes/dist/modes/interactive/interactive-mode-state.d.ts +9 -0
- package/packages/gsd-agent-modes/dist/modes/interactive/interactive-mode-state.d.ts.map +1 -1
- package/packages/gsd-agent-modes/dist/modes/interactive/interactive-mode-state.js +1 -1
- package/packages/gsd-agent-modes/dist/modes/interactive/interactive-mode-state.js.map +1 -1
- package/packages/gsd-agent-modes/dist/modes/interactive/interactive-mode-ui-state.d.ts +54 -0
- package/packages/gsd-agent-modes/dist/modes/interactive/interactive-mode-ui-state.d.ts.map +1 -0
- package/packages/gsd-agent-modes/dist/modes/interactive/interactive-mode-ui-state.js +20 -0
- package/packages/gsd-agent-modes/dist/modes/interactive/interactive-mode-ui-state.js.map +1 -0
- package/packages/gsd-agent-modes/dist/modes/interactive/interactive-mode.d.ts +4 -1
- package/packages/gsd-agent-modes/dist/modes/interactive/interactive-mode.d.ts.map +1 -1
- package/packages/gsd-agent-modes/dist/modes/interactive/interactive-mode.js +9 -0
- package/packages/gsd-agent-modes/dist/modes/interactive/interactive-mode.js.map +1 -1
- package/packages/gsd-agent-modes/dist/modes/interactive/streaming-render-state.d.ts +56 -0
- package/packages/gsd-agent-modes/dist/modes/interactive/streaming-render-state.d.ts.map +1 -0
- package/packages/gsd-agent-modes/dist/modes/interactive/streaming-render-state.js +44 -0
- package/packages/gsd-agent-modes/dist/modes/interactive/streaming-render-state.js.map +1 -0
- package/packages/gsd-agent-modes/dist/modes/interactive/tui-transcript-tracker.d.ts +5 -0
- package/packages/gsd-agent-modes/dist/modes/interactive/tui-transcript-tracker.d.ts.map +1 -0
- package/packages/gsd-agent-modes/dist/modes/interactive/tui-transcript-tracker.js +77 -0
- package/packages/gsd-agent-modes/dist/modes/interactive/tui-transcript-tracker.js.map +1 -0
- package/packages/gsd-agent-modes/dist/modes/rpc/rpc-mode.d.ts.map +1 -1
- package/packages/gsd-agent-modes/dist/modes/rpc/rpc-mode.js +18 -0
- package/packages/gsd-agent-modes/dist/modes/rpc/rpc-mode.js.map +1 -1
- package/packages/gsd-agent-modes/package.json +7 -7
- package/packages/mcp-server/README.md +1 -1
- package/packages/mcp-server/dist/server.d.ts +1 -1
- package/packages/mcp-server/dist/server.d.ts.map +1 -1
- package/packages/mcp-server/dist/server.js +3 -3
- package/packages/mcp-server/dist/server.js.map +1 -1
- package/packages/mcp-server/dist/workflow-tools.d.ts +13 -1
- package/packages/mcp-server/dist/workflow-tools.d.ts.map +1 -1
- package/packages/mcp-server/dist/workflow-tools.js +34 -20
- package/packages/mcp-server/dist/workflow-tools.js.map +1 -1
- package/packages/mcp-server/package.json +4 -4
- package/packages/native/package.json +1 -1
- package/packages/pi-agent-core/package.json +1 -1
- package/packages/pi-ai/package.json +1 -1
- package/packages/pi-coding-agent/README.md +3 -2
- package/packages/pi-coding-agent/dist/core/session-manager-context.d.ts +9 -0
- package/packages/pi-coding-agent/dist/core/session-manager-context.d.ts.map +1 -0
- package/packages/pi-coding-agent/dist/core/session-manager-context.js +94 -0
- package/packages/pi-coding-agent/dist/core/session-manager-context.js.map +1 -0
- package/packages/pi-coding-agent/dist/core/session-manager-list.d.ts +8 -0
- package/packages/pi-coding-agent/dist/core/session-manager-list.d.ts.map +1 -0
- package/packages/pi-coding-agent/dist/core/session-manager-list.js +244 -0
- package/packages/pi-coding-agent/dist/core/session-manager-list.js.map +1 -0
- package/packages/pi-coding-agent/dist/core/session-manager-migration.d.ts +12 -0
- package/packages/pi-coding-agent/dist/core/session-manager-migration.d.ts.map +1 -0
- package/packages/pi-coding-agent/dist/core/session-manager-migration.js +84 -0
- package/packages/pi-coding-agent/dist/core/session-manager-migration.js.map +1 -0
- package/packages/pi-coding-agent/dist/core/session-manager-types.d.ts +135 -0
- package/packages/pi-coding-agent/dist/core/session-manager-types.d.ts.map +1 -0
- package/packages/pi-coding-agent/dist/core/session-manager-types.js +2 -0
- package/packages/pi-coding-agent/dist/core/session-manager-types.js.map +1 -0
- package/packages/pi-coding-agent/dist/core/session-manager.d.ts +6 -154
- package/packages/pi-coding-agent/dist/core/session-manager.d.ts.map +1 -1
- package/packages/pi-coding-agent/dist/core/session-manager.js +22 -459
- package/packages/pi-coding-agent/dist/core/session-manager.js.map +1 -1
- package/packages/pi-coding-agent/dist/theme/theme-schema.d.ts +75 -75
- package/packages/pi-coding-agent/dist/theme/theme-schema.d.ts.map +1 -1
- package/packages/pi-coding-agent/dist/theme/theme-schema.js +1 -1
- package/packages/pi-coding-agent/dist/theme/theme-schema.js.map +1 -1
- package/packages/pi-coding-agent/dist/theme/theme.d.ts.map +1 -1
- package/packages/pi-coding-agent/dist/theme/theme.js +11 -7
- package/packages/pi-coding-agent/dist/theme/theme.js.map +1 -1
- package/packages/pi-coding-agent/package.json +7 -7
- package/packages/pi-tui/package.json +2 -2
- package/packages/rpc-client/package.json +2 -2
- package/pkg/dist/theme/theme-schema.d.ts +75 -75
- package/pkg/dist/theme/theme-schema.d.ts.map +1 -1
- package/pkg/dist/theme/theme-schema.js +1 -1
- package/pkg/dist/theme/theme-schema.js.map +1 -1
- package/pkg/dist/theme/theme.d.ts.map +1 -1
- package/pkg/dist/theme/theme.js +11 -7
- package/pkg/dist/theme/theme.js.map +1 -1
- package/pkg/package.json +1 -1
- package/src/resources/extensions/claude-code-cli/stream-adapter.ts +20 -2
- package/src/resources/extensions/claude-code-cli/tests/stream-adapter.test.ts +80 -0
- package/src/resources/extensions/google-cli/stream-adapter.ts +106 -19
- package/src/resources/extensions/gsd/artifact-verification.ts +464 -0
- package/src/resources/extensions/gsd/auto/orchestrator.ts +25 -11
- package/src/resources/extensions/gsd/auto/session.ts +6 -0
- package/src/resources/extensions/gsd/auto/verification-retry-policy.ts +3 -1
- package/src/resources/extensions/gsd/auto-artifact-paths.ts +47 -1
- package/src/resources/extensions/gsd/auto-dispatch.ts +21 -23
- package/src/resources/extensions/gsd/auto-post-unit.ts +1 -1
- package/src/resources/extensions/gsd/auto-prompts.ts +38 -12
- package/src/resources/extensions/gsd/auto-recovery.ts +10 -508
- package/src/resources/extensions/gsd/auto-runtime-state.ts +4 -5
- package/src/resources/extensions/gsd/auto-timeout-recovery.ts +3 -2
- package/src/resources/extensions/gsd/auto-verification.ts +5 -1
- package/src/resources/extensions/gsd/bootstrap/agent-end-recovery.ts +125 -12
- package/src/resources/extensions/gsd/bootstrap/core-session-tools.ts +43 -0
- package/src/resources/extensions/gsd/bootstrap/db-tools.ts +6 -1
- package/src/resources/extensions/gsd/bootstrap/exec-tools.ts +2 -0
- package/src/resources/extensions/gsd/bootstrap/register-hooks.ts +20 -19
- package/src/resources/extensions/gsd/bootstrap/system-context.ts +52 -18
- package/src/resources/extensions/gsd/bootstrap/tool-call-loop-guard.ts +74 -10
- package/src/resources/extensions/gsd/bootstrap/write-gate.ts +1 -1
- package/src/resources/extensions/gsd/closeout-consistency-gate.ts +2 -1
- package/src/resources/extensions/gsd/commands-context.ts +18 -1
- package/src/resources/extensions/gsd/commands-prefs-wizard.ts +14 -9
- package/src/resources/extensions/gsd/commands-worktree.ts +12 -10
- package/src/resources/extensions/gsd/dashboard-overlay.ts +32 -3
- package/src/resources/extensions/gsd/db/queries.ts +79 -0
- package/src/resources/extensions/gsd/db-workspace.ts +61 -3
- package/src/resources/extensions/gsd/doctor-providers.ts +103 -9
- package/src/resources/extensions/gsd/doctor-runtime-checks.ts +3 -0
- package/src/resources/extensions/gsd/exec-sandbox.ts +49 -9
- package/src/resources/extensions/gsd/flat-phase-migration.ts +44 -0
- package/src/resources/extensions/gsd/forensics.ts +2 -33
- package/src/resources/extensions/gsd/git-service.ts +6 -5
- package/src/resources/extensions/gsd/gitignore.ts +3 -0
- package/src/resources/extensions/gsd/guided-flow-queue.ts +89 -4
- package/src/resources/extensions/gsd/health-widget.ts +69 -32
- package/src/resources/extensions/gsd/json-persistence.ts +20 -0
- package/src/resources/extensions/gsd/knowledge-backfill.ts +16 -10
- package/src/resources/extensions/gsd/layout-policy.ts +2 -1
- package/src/resources/extensions/gsd/markdown-renderer.ts +8 -11
- package/src/resources/extensions/gsd/memory-backfill.ts +26 -20
- package/src/resources/extensions/gsd/memory-consolidation-scanner.ts +51 -19
- package/src/resources/extensions/gsd/metrics.ts +4 -4
- package/src/resources/extensions/gsd/migration-auto-check.ts +23 -0
- package/src/resources/extensions/gsd/milestone-ids.ts +31 -2
- package/src/resources/extensions/gsd/milestone-implementation-evidence.ts +35 -21
- package/src/resources/extensions/gsd/orphan-stash-audit.ts +108 -20
- package/src/resources/extensions/gsd/prompts/code-review.md +6 -4
- package/src/resources/extensions/gsd/prompts/plan-slice.md +1 -1
- package/src/resources/extensions/gsd/quick.ts +43 -2
- package/src/resources/extensions/gsd/safety/file-change-validator.ts +8 -2
- package/src/resources/extensions/gsd/session-forensics.ts +11 -1
- package/src/resources/extensions/gsd/skills/gsd-headless/references/commands.md +1 -1
- package/src/resources/extensions/gsd/state/derive/cache.ts +46 -0
- package/src/resources/extensions/gsd/state/derive/db-open.ts +45 -0
- package/src/resources/extensions/gsd/state/derive/from-db.ts +561 -0
- package/src/resources/extensions/gsd/state/derive/index.ts +104 -0
- package/src/resources/extensions/gsd/state/derive/interrupted-work.ts +31 -0
- package/src/resources/extensions/gsd/state-reconciliation/drift/stale-render.ts +81 -7
- package/src/resources/extensions/gsd/state-reconciliation/index.ts +50 -24
- package/src/resources/extensions/gsd/state-reconciliation/registry.ts +43 -28
- package/src/resources/extensions/gsd/state.ts +32 -732
- package/src/resources/extensions/gsd/tests/artifact-retry-cap.test.ts +4 -3
- package/src/resources/extensions/gsd/tests/auto-artifact-paths.test.ts +98 -1
- package/src/resources/extensions/gsd/tests/auto-recovery.test.ts +111 -1
- package/src/resources/extensions/gsd/tests/commands-context.test.ts +26 -0
- package/src/resources/extensions/gsd/tests/commands-gsd-core.test.ts +1 -0
- package/src/resources/extensions/gsd/tests/commands-worktree-clean.test.ts +80 -0
- package/src/resources/extensions/gsd/tests/complete-milestone.test.ts +28 -0
- package/src/resources/extensions/gsd/tests/complete-slice-reopen-handoff.test.ts +69 -0
- package/src/resources/extensions/gsd/tests/complete-slice.test.ts +11 -0
- package/src/resources/extensions/gsd/tests/complete-task-rollback-evidence.test.ts +48 -8
- package/src/resources/extensions/gsd/tests/complete-task.test.ts +75 -0
- package/src/resources/extensions/gsd/tests/dashboard-overlay.test.ts +55 -2
- package/src/resources/extensions/gsd/tests/decisions-projection-from-memories.test.ts +51 -0
- package/src/resources/extensions/gsd/tests/dispatch-rule-coverage.test.ts +26 -1
- package/src/resources/extensions/gsd/tests/doctor-forensics-db-open-regression.test.ts +70 -2
- package/src/resources/extensions/gsd/tests/doctor-providers.test.ts +107 -0
- package/src/resources/extensions/gsd/tests/exec-graceful-kill.test.ts +38 -0
- package/src/resources/extensions/gsd/tests/exec-tool.test.ts +45 -1
- package/src/resources/extensions/gsd/tests/file-change-validator.test.ts +40 -0
- package/src/resources/extensions/gsd/tests/flat-phase-migration.test.ts +37 -2
- package/src/resources/extensions/gsd/tests/forensics-error-filter.test.ts +88 -0
- package/src/resources/extensions/gsd/tests/gitignore-bg-shell-runtime.test.ts +4 -0
- package/src/resources/extensions/gsd/tests/guided-discuss-milestone-prompt-rendering.test.ts +42 -0
- package/src/resources/extensions/gsd/tests/health-widget.test.ts +268 -3
- package/src/resources/extensions/gsd/tests/integration/git-service.test.ts +130 -3
- package/src/resources/extensions/gsd/tests/integration/queue-active-milestone-context-budget.test.ts +93 -0
- package/src/resources/extensions/gsd/tests/integration/quick-branch-lifecycle.test.ts +56 -9
- package/src/resources/extensions/gsd/tests/json-persistence-atomic.test.ts +47 -0
- package/src/resources/extensions/gsd/tests/knowledge-backfill-projection.test.ts +35 -0
- package/src/resources/extensions/gsd/tests/knowledge-cold-start.test.ts +14 -0
- package/src/resources/extensions/gsd/tests/memory-consolidation-scanner.test.ts +78 -0
- package/src/resources/extensions/gsd/tests/merge-closeout-consistency-gate.test.ts +31 -1
- package/src/resources/extensions/gsd/tests/metrics-prune-cache-invalidation.test.ts +6 -0
- package/src/resources/extensions/gsd/tests/metrics.test.ts +1 -0
- package/src/resources/extensions/gsd/tests/migration-auto-check.test.ts +70 -0
- package/src/resources/extensions/gsd/tests/orchestrator-logs.test.ts +43 -1
- package/src/resources/extensions/gsd/tests/orphan-stash-audit.test.ts +91 -7
- package/src/resources/extensions/gsd/tests/parallel-research-dispatch.test.ts +26 -0
- package/src/resources/extensions/gsd/tests/parsers-legacy-importers.test.ts +2 -1
- package/src/resources/extensions/gsd/tests/pipeline-variant-dispatch.test.ts +1 -1
- package/src/resources/extensions/gsd/tests/plan-slice-prompt.test.ts +10 -0
- package/src/resources/extensions/gsd/tests/prefs-wizard-coverage.test.ts +54 -1
- package/src/resources/extensions/gsd/tests/progressive-planning.test.ts +50 -14
- package/src/resources/extensions/gsd/tests/provider-errors.test.ts +195 -1
- package/src/resources/extensions/gsd/tests/read-uat-gate-verdict.test.ts +185 -0
- package/src/resources/extensions/gsd/tests/register-hooks-depth-verification.test.ts +87 -0
- package/src/resources/extensions/gsd/tests/runtime-invariant-modules.test.ts +7 -0
- package/src/resources/extensions/gsd/tests/stalled-tool-recovery.test.ts +56 -0
- package/src/resources/extensions/gsd/tests/state-reconciliation-drift.test.ts +191 -0
- package/src/resources/extensions/gsd/tests/tool-call-loop-guard.test.ts +151 -0
- package/src/resources/extensions/gsd/tests/tool-param-optionality.test.ts +26 -0
- package/src/resources/extensions/gsd/tests/undo.test.ts +74 -0
- package/src/resources/extensions/gsd/tests/unit-context-composer.test.ts +193 -14
- package/src/resources/extensions/gsd/tests/unmerged-milestone-guard.test.ts +25 -0
- package/src/resources/extensions/gsd/tests/validation-block-guard.test.ts +79 -0
- package/src/resources/extensions/gsd/tests/verification-retry-policy.test.ts +69 -4
- package/src/resources/extensions/gsd/tests/verify-artifact-tightened.test.ts +66 -0
- package/src/resources/extensions/gsd/tests/workflow-manifest.test.ts +54 -0
- package/src/resources/extensions/gsd/tests/workspace-git-preflight.test.ts +151 -2
- package/src/resources/extensions/gsd/tests/worktree-manager.test.ts +39 -0
- package/src/resources/extensions/gsd/tools/complete-milestone.ts +3 -2
- package/src/resources/extensions/gsd/tools/complete-slice.ts +2 -2
- package/src/resources/extensions/gsd/tools/complete-task.ts +53 -15
- package/src/resources/extensions/gsd/tools/exec-tool.ts +7 -3
- package/src/resources/extensions/gsd/undo.ts +47 -6
- package/src/resources/extensions/gsd/unit-context-composer.ts +33 -7
- package/src/resources/extensions/gsd/unit-registry.ts +32 -4
- package/src/resources/extensions/gsd/unmerged-milestone-guard.ts +41 -5
- package/src/resources/extensions/gsd/validation-block-guard.ts +13 -7
- package/src/resources/extensions/gsd/verification-gate.ts +8 -0
- package/src/resources/extensions/gsd/workflow-manifest.ts +4 -1
- package/src/resources/extensions/gsd/workflow-projections.ts +20 -14
- package/src/resources/extensions/gsd/workspace-git-preflight.ts +31 -0
- package/src/resources/extensions/gsd/worktree-manager.ts +41 -1
- package/dist/web/standalone/.next/static/chunks/2772.bfa657f49f955239.js +0 -1
- package/dist/web/standalone/.next/static/chunks/796.e0bdc932325d7e03.js +0 -10
- package/dist/web/standalone/.next/static/chunks/webpack-f46ea08200a0227e.js +0 -1
- /package/dist/web/standalone/.next/static/{BTKtGFF1Y-hvVJEGhBRo9 → -ji77QJck2IKIwrGza1Bs}/_buildManifest.js +0 -0
- /package/dist/web/standalone/.next/static/{BTKtGFF1Y-hvVJEGhBRo9 → -ji77QJck2IKIwrGza1Bs}/_ssgManifest.js +0 -0
|
@@ -47,8 +47,9 @@ export function dbPath(basePath: string): string {
|
|
|
47
47
|
* Used by the renderer to derive the phase number from the DB's milestone_id.
|
|
48
48
|
*/
|
|
49
49
|
export function milestoneIdToPhaseNum(milestoneId: string): number {
|
|
50
|
-
// No $ anchor: accepts bare (M012)
|
|
50
|
+
// No $ anchor: accepts bare (M012), team-suffixed (M012-abc123), and legacy numeric IDs.
|
|
51
51
|
const m = milestoneId.match(/^M0*(\d+)/i);
|
|
52
|
+
if (!m && /^\d+$/.test(milestoneId)) return Number.parseInt(milestoneId, 10);
|
|
52
53
|
return m ? Number.parseInt(m[1]!, 10) : 1;
|
|
53
54
|
}
|
|
54
55
|
|
|
@@ -25,6 +25,7 @@ import {
|
|
|
25
25
|
insertArtifact,
|
|
26
26
|
deleteArtifactByPath,
|
|
27
27
|
getGateResults,
|
|
28
|
+
isDbAvailable,
|
|
28
29
|
} from "./gsd-db.js";
|
|
29
30
|
import type { MilestoneRow, ArtifactRow } from "./db-milestone-artifact-rows.js";
|
|
30
31
|
import type { SliceRow, TaskRow } from "./db-task-slice-rows.js";
|
|
@@ -631,16 +632,8 @@ export async function renderRoadmapCheckboxes(
|
|
|
631
632
|
basePath: string,
|
|
632
633
|
milestoneId: string,
|
|
633
634
|
): Promise<boolean> {
|
|
634
|
-
const
|
|
635
|
-
|
|
636
|
-
process.stderr.write(
|
|
637
|
-
`markdown-renderer: no slices found for milestone ${milestoneId}\n`,
|
|
638
|
-
);
|
|
639
|
-
return false;
|
|
640
|
-
}
|
|
641
|
-
|
|
642
|
-
await renderRoadmapFromDb(basePath, milestoneId);
|
|
643
|
-
return true;
|
|
635
|
+
const rendered = await renderRoadmapFromDb(basePath, milestoneId);
|
|
636
|
+
return !("skipped" in rendered);
|
|
644
637
|
}
|
|
645
638
|
|
|
646
639
|
/**
|
|
@@ -737,7 +730,8 @@ function isAutoRecoveryPlaceholderPlan(content: string): boolean {
|
|
|
737
730
|
* projection (the 4S/0T-vs-5S/13T drift class). The artifacts table is an
|
|
738
731
|
* output sink, never a render input.
|
|
739
732
|
*
|
|
740
|
-
* @returns true if the plan was written, false
|
|
733
|
+
* @returns true if the plan was written, false when the DB slice has no tasks
|
|
734
|
+
* @throws when the DB connection is unavailable or the render write fails
|
|
741
735
|
*/
|
|
742
736
|
export async function renderPlanCheckboxes(
|
|
743
737
|
basePath: string,
|
|
@@ -747,6 +741,9 @@ export async function renderPlanCheckboxes(
|
|
|
747
741
|
): Promise<boolean> {
|
|
748
742
|
const tasks = getSliceTasks(milestoneId, sliceId);
|
|
749
743
|
if (tasks.length === 0) {
|
|
744
|
+
if (!isDbAvailable()) {
|
|
745
|
+
throw new Error(`database unavailable while rendering plan checkboxes for ${milestoneId}/${sliceId}`);
|
|
746
|
+
}
|
|
750
747
|
process.stderr.write(
|
|
751
748
|
`markdown-renderer: no tasks found for ${milestoneId}/${sliceId}\n`,
|
|
752
749
|
);
|
|
@@ -49,8 +49,8 @@ type DecisionContentFields = Pick<DecisionRow, "decision" | "choice" | "rational
|
|
|
49
49
|
* decision is checked individually; only decisions whose id is already
|
|
50
50
|
* present in the memory store are skipped. A user-authored memory with
|
|
51
51
|
* their own `sourceDecisionId` does NOT abort the backfill.
|
|
52
|
-
* - Best-effort: never throws.
|
|
53
|
-
* backfill cannot block
|
|
52
|
+
* - Best-effort: never throws. Failed memory inserts are logged and skipped;
|
|
53
|
+
* setup/read failures log and return 0 so backfill cannot block startup.
|
|
54
54
|
* - Full migration (ADR-013 Stage 2a): both active and superseded rows are
|
|
55
55
|
* migrated. `structured_fields.superseded_by` preserves the supersedes
|
|
56
56
|
* chain so the DECISIONS.md projection regen can source from memories
|
|
@@ -146,24 +146,30 @@ export function backfillDecisionsToMemories(): number {
|
|
|
146
146
|
}
|
|
147
147
|
|
|
148
148
|
const content = synthesizeDecisionMemoryContent(row);
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
149
|
+
try {
|
|
150
|
+
const id = createMemory({
|
|
151
|
+
category: "architecture",
|
|
152
|
+
content,
|
|
153
|
+
scope: row.scope || "project",
|
|
154
|
+
confidence: 0.85,
|
|
155
|
+
structuredFields: {
|
|
156
|
+
sourceDecisionId: row.id,
|
|
157
|
+
when_context: row.when_context,
|
|
158
|
+
scope: row.scope,
|
|
159
|
+
decision: row.decision,
|
|
160
|
+
choice: row.choice,
|
|
161
|
+
rationale: row.rationale,
|
|
162
|
+
made_by: row.made_by,
|
|
163
|
+
revisable: row.revisable,
|
|
164
|
+
superseded_by: row.superseded_by,
|
|
165
|
+
},
|
|
166
|
+
});
|
|
167
|
+
if (id) written += 1;
|
|
168
|
+
} catch (rowErr) {
|
|
169
|
+
const message = rowErr instanceof Error ? rowErr.message : String(rowErr);
|
|
170
|
+
logWarning("memory-backfill", `decisions->memories backfill skipped ${row.id}: ${message}`);
|
|
171
|
+
continue;
|
|
172
|
+
}
|
|
167
173
|
}
|
|
168
174
|
|
|
169
175
|
if (healed > 0) {
|
|
@@ -142,23 +142,53 @@ function getActiveDecisions(): DecisionRow[] {
|
|
|
142
142
|
}
|
|
143
143
|
|
|
144
144
|
/**
|
|
145
|
-
*
|
|
146
|
-
*
|
|
147
|
-
*
|
|
148
|
-
* backfill's idempotency check.
|
|
145
|
+
* Source IDs already present in memory `structured_fields`. Collected with one
|
|
146
|
+
* pass over the memories table so the scanner does not perform a non-indexable
|
|
147
|
+
* LIKE probe for every decision and KNOWLEDGE.md row.
|
|
149
148
|
*/
|
|
150
|
-
|
|
151
|
-
|
|
149
|
+
interface MemorySourceMarkers {
|
|
150
|
+
decisionIds: Set<string>;
|
|
151
|
+
knowledgeIds: Set<string>;
|
|
152
|
+
}
|
|
153
|
+
|
|
154
|
+
function emptyMemorySourceMarkers(): MemorySourceMarkers {
|
|
155
|
+
return { decisionIds: new Set(), knowledgeIds: new Set() };
|
|
156
|
+
}
|
|
157
|
+
|
|
158
|
+
function getMemorySourceMarkers(): MemorySourceMarkers {
|
|
159
|
+
const markers = emptyMemorySourceMarkers();
|
|
160
|
+
if (!isDbAvailable()) return markers;
|
|
152
161
|
const adapter = _getAdapter();
|
|
153
|
-
if (!adapter) return
|
|
162
|
+
if (!adapter) return markers;
|
|
163
|
+
try {
|
|
164
|
+
const rows = adapter
|
|
165
|
+
.prepare("SELECT structured_fields FROM memories WHERE structured_fields IS NOT NULL")
|
|
166
|
+
.all() as Array<Record<string, unknown>>;
|
|
167
|
+
for (const row of rows) {
|
|
168
|
+
collectMemorySourceMarker(markers, row["structured_fields"]);
|
|
169
|
+
}
|
|
170
|
+
} catch {
|
|
171
|
+
return markers;
|
|
172
|
+
}
|
|
173
|
+
return markers;
|
|
174
|
+
}
|
|
175
|
+
|
|
176
|
+
function collectMemorySourceMarker(markers: MemorySourceMarkers, raw: unknown): void {
|
|
177
|
+
if (typeof raw !== "string" || raw.length === 0) return;
|
|
154
178
|
try {
|
|
155
|
-
const
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
179
|
+
const parsed = JSON.parse(raw);
|
|
180
|
+
if (!parsed || typeof parsed !== "object" || Array.isArray(parsed)) return;
|
|
181
|
+
const fields = parsed as Record<string, unknown>;
|
|
182
|
+
const decisionId = fields["sourceDecisionId"];
|
|
183
|
+
if (typeof decisionId === "string" && decisionId.length > 0) {
|
|
184
|
+
markers.decisionIds.add(decisionId);
|
|
185
|
+
}
|
|
186
|
+
const knowledgeId = fields["sourceKnowledgeId"];
|
|
187
|
+
if (typeof knowledgeId === "string" && knowledgeId.length > 0) {
|
|
188
|
+
markers.knowledgeIds.add(knowledgeId);
|
|
189
|
+
}
|
|
160
190
|
} catch {
|
|
161
|
-
return
|
|
191
|
+
return;
|
|
162
192
|
}
|
|
163
193
|
}
|
|
164
194
|
|
|
@@ -174,10 +204,14 @@ const SAMPLE_LIMIT = 5;
|
|
|
174
204
|
export function scanConsolidationGaps(basePath: string): ConsolidationGapReport {
|
|
175
205
|
// ── Decisions ────────────────────────────────────────────────────────
|
|
176
206
|
const decisions = getActiveDecisions();
|
|
207
|
+
const knowledgeRows = parseKnowledgeRows(knowledgeMdContent(basePath));
|
|
208
|
+
const memorySourceMarkers = decisions.length > 0 || knowledgeRows.length > 0
|
|
209
|
+
? getMemorySourceMarkers()
|
|
210
|
+
: emptyMemorySourceMarkers();
|
|
177
211
|
const decisionSamples: DecisionsSurfaceReport["samples"] = [];
|
|
178
212
|
let decisionMigrated = 0;
|
|
179
213
|
for (const decision of decisions) {
|
|
180
|
-
if (
|
|
214
|
+
if (memorySourceMarkers.decisionIds.has(decision.id)) {
|
|
181
215
|
decisionMigrated += 1;
|
|
182
216
|
continue;
|
|
183
217
|
}
|
|
@@ -190,16 +224,14 @@ export function scanConsolidationGaps(basePath: string): ConsolidationGapReport
|
|
|
190
224
|
}
|
|
191
225
|
|
|
192
226
|
// ── KNOWLEDGE.md ─────────────────────────────────────────────────────
|
|
193
|
-
const knowledgeRows = parseKnowledgeRows(knowledgeMdContent(basePath));
|
|
194
227
|
const knowledgeByTable = { rules: 0, patterns: 0, lessons: 0 };
|
|
195
228
|
const knowledgeSamples: KnowledgeSurfaceReport["samples"] = [];
|
|
196
229
|
let knowledgeMigrated = 0;
|
|
197
230
|
for (const row of knowledgeRows) {
|
|
198
231
|
knowledgeByTable[row.table] += 1;
|
|
199
|
-
//
|
|
200
|
-
//
|
|
201
|
-
|
|
202
|
-
if (memoryHasSourceMarker("sourceKnowledgeId", row.id)) {
|
|
232
|
+
// KNOWLEDGE.md backfill writes `sourceKnowledgeId`; rows without that
|
|
233
|
+
// marker are still reported as consolidation gaps.
|
|
234
|
+
if (memorySourceMarkers.knowledgeIds.has(row.id)) {
|
|
203
235
|
knowledgeMigrated += 1;
|
|
204
236
|
continue;
|
|
205
237
|
}
|
|
@@ -19,7 +19,7 @@ import { openSync, closeSync, unlinkSync, statSync, writeFileSync } from "node:f
|
|
|
19
19
|
import type { ExtensionContext } from "@gsd/pi-coding-agent";
|
|
20
20
|
import { gsdRoot } from "./paths.js";
|
|
21
21
|
import { getAndClearSkills } from "./skill-telemetry.js";
|
|
22
|
-
import { loadJsonFile, loadJsonFileOrNull,
|
|
22
|
+
import { loadJsonFile, loadJsonFileOrNull, saveJsonFileCompact } from "./json-persistence.js";
|
|
23
23
|
import { parseUnitId } from "./unit-id.js";
|
|
24
24
|
import { buildAuditEnvelope, emitUokAuditEvent } from "./uok/audit.js";
|
|
25
25
|
import { isUnifiedAuditEnabled } from "./uok/audit-toggle.js";
|
|
@@ -873,7 +873,7 @@ export function pruneMetricsLedger(base: string, keepCount: number): number {
|
|
|
873
873
|
if (!disk || disk.units.length <= keepCount) return 0;
|
|
874
874
|
const removed = disk.units.length - keepCount;
|
|
875
875
|
disk.units = keepNewestUnits(disk.units, keepCount);
|
|
876
|
-
|
|
876
|
+
saveJsonFileCompact(metricsPath(base), disk);
|
|
877
877
|
// Keep the in-memory ledger in sync if it is loaded for this session.
|
|
878
878
|
if (ledger) {
|
|
879
879
|
ledger.units = keepNewestUnits(ledger.units, keepCount);
|
|
@@ -1041,7 +1041,7 @@ function saveLedger(base: string, data: MetricsLedger): void {
|
|
|
1041
1041
|
: dataUnits;
|
|
1042
1042
|
merged.sort(compareUnitsByTime);
|
|
1043
1043
|
data.units = keepNewestUnits(merged);
|
|
1044
|
-
|
|
1044
|
+
saveJsonFileCompact(path, data);
|
|
1045
1045
|
} finally {
|
|
1046
1046
|
releaseLock(lockPath);
|
|
1047
1047
|
}
|
|
@@ -1053,6 +1053,6 @@ function saveLedger(base: string, data: MetricsLedger): void {
|
|
|
1053
1053
|
// read-merge-write sequence without mutual exclusion.
|
|
1054
1054
|
logWarning("fs", "saveLedger: lock not acquired — falling back to direct write (no merge)");
|
|
1055
1055
|
data.units = keepNewestUnits(data.units);
|
|
1056
|
-
|
|
1056
|
+
saveJsonFileCompact(path, data);
|
|
1057
1057
|
}
|
|
1058
1058
|
}
|
|
@@ -90,6 +90,28 @@ function scanHasExtraIdentities(a: HierarchyScan, b: HierarchyScan): boolean {
|
|
|
90
90
|
);
|
|
91
91
|
}
|
|
92
92
|
|
|
93
|
+
function paddedMilestoneId(id: string): string | null {
|
|
94
|
+
return /^\d+$/.test(id) ? `M${id.padStart(3, "0")}` : null;
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
function replaceSetPrefix(values: Set<string>, from: string, to: string): void {
|
|
98
|
+
for (const value of [...values]) {
|
|
99
|
+
if (value !== from && !value.startsWith(`${from}/`)) continue;
|
|
100
|
+
values.delete(value);
|
|
101
|
+
values.add(`${to}${value.slice(from.length)}`);
|
|
102
|
+
}
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
function alignNumericMarkdownIdsWithDb(markdownScan: HierarchyScan, dbScan: HierarchyScan): void {
|
|
106
|
+
for (const dbId of dbScan.milestones) {
|
|
107
|
+
const paddedId = paddedMilestoneId(dbId);
|
|
108
|
+
if (!paddedId || dbScan.milestones.has(paddedId) || !markdownScan.milestones.has(paddedId)) continue;
|
|
109
|
+
replaceSetPrefix(markdownScan.milestones, paddedId, dbId);
|
|
110
|
+
replaceSetPrefix(markdownScan.slices, paddedId, dbId);
|
|
111
|
+
replaceSetPrefix(markdownScan.tasks, paddedId, dbId);
|
|
112
|
+
}
|
|
113
|
+
}
|
|
114
|
+
|
|
93
115
|
/**
|
|
94
116
|
* True when the DB holds any milestone/slice/task identity the markdown lacks —
|
|
95
117
|
* i.e. a `/gsd recover --confirm` (markdown → DB) would DELETE authoritative DB
|
|
@@ -185,6 +207,7 @@ export async function checkMarkdownHierarchyAgainstDb(
|
|
|
185
207
|
|
|
186
208
|
const dbScan = scanDbHierarchy();
|
|
187
209
|
const beforeDb = dbScan.counts;
|
|
210
|
+
alignNumericMarkdownIdsWithDb(markdownScan, dbScan);
|
|
188
211
|
|
|
189
212
|
// Discussion-phase scratch: a milestone dir with no ROADMAP and no DB row is
|
|
190
213
|
// a pre-registration discussion artifact (CONTEXT/CONTEXT-DRAFT only — the
|
|
@@ -141,7 +141,8 @@ export function clearReservedMilestoneIds(): void {
|
|
|
141
141
|
|
|
142
142
|
// ─── Discovery ──────────────────────────────────────────────────────────────
|
|
143
143
|
|
|
144
|
-
function scanMilestoneIdsFromDir(dir: string): string[] {
|
|
144
|
+
function scanMilestoneIdsFromDir(basePath: string, dir: string): string[] {
|
|
145
|
+
const legacyNumericIds = idsWithLegacyNumericDirs(basePath);
|
|
145
146
|
return readdirSync(dir, { withFileTypes: true })
|
|
146
147
|
.filter((d) => d.isDirectory())
|
|
147
148
|
.map((d) => {
|
|
@@ -149,6 +150,12 @@ function scanMilestoneIdsFromDir(dir: string): string[] {
|
|
|
149
150
|
if (MILESTONE_ID_RE.test(d.name)) {
|
|
150
151
|
return d.name;
|
|
151
152
|
}
|
|
153
|
+
// Legacy recovery/imports may contain bare numeric milestone directories
|
|
154
|
+
// (for example `milestones/15/15-ROADMAP.md`). The DB can preserve that
|
|
155
|
+
// id, and rebuild renders it, so drift scans must see it too.
|
|
156
|
+
if (/^\d+$/.test(d.name)) {
|
|
157
|
+
return d.name;
|
|
158
|
+
}
|
|
152
159
|
// Legacy layout: M001-abcdef-slug descriptor directories
|
|
153
160
|
const legacyMatch = d.name.match(/^(M\d{3}(?:-[a-z0-9]{6})?)-/);
|
|
154
161
|
if (legacyMatch) {
|
|
@@ -162,6 +169,10 @@ function scanMilestoneIdsFromDir(dir: string): string[] {
|
|
|
162
169
|
if (MILESTONE_ID_RE.test(fromSlug)) {
|
|
163
170
|
return fromSlug;
|
|
164
171
|
}
|
|
172
|
+
const numericId = String(phaseNum);
|
|
173
|
+
if (legacyNumericIds.has(numericId)) {
|
|
174
|
+
return numericId;
|
|
175
|
+
}
|
|
165
176
|
return `M${String(phaseNum).padStart(3, "0")}`;
|
|
166
177
|
}
|
|
167
178
|
return null;
|
|
@@ -169,6 +180,24 @@ function scanMilestoneIdsFromDir(dir: string): string[] {
|
|
|
169
180
|
.filter((id): id is string => id !== null);
|
|
170
181
|
}
|
|
171
182
|
|
|
183
|
+
function idsWithLegacyNumericDirs(basePath: string): Set<string> {
|
|
184
|
+
const legacyDir = join(gsdProjectionRoot(basePath), "milestones");
|
|
185
|
+
const ids = new Set<string>();
|
|
186
|
+
try {
|
|
187
|
+
for (const entry of readdirSync(legacyDir, { withFileTypes: true })) {
|
|
188
|
+
if (entry.isDirectory() && /^\d+$/.test(entry.name)) ids.add(entry.name);
|
|
189
|
+
}
|
|
190
|
+
} catch (err) {
|
|
191
|
+
// A missing legacy directory is the common, benign case (nothing to
|
|
192
|
+
// consult). Only surface a real failure when the directory exists but
|
|
193
|
+
// could not be read.
|
|
194
|
+
if (existsSync(legacyDir)) {
|
|
195
|
+
logWarning("engine", `idsWithLegacyNumericDirs: ${legacyDir} exists but readdirSync failed — ${getErrorMessage(err)}`);
|
|
196
|
+
}
|
|
197
|
+
}
|
|
198
|
+
return ids;
|
|
199
|
+
}
|
|
200
|
+
|
|
172
201
|
/** Scan the milestones directory and return IDs sorted by queue order (or numeric fallback). */
|
|
173
202
|
export function findMilestoneIds(basePath: string): string[] {
|
|
174
203
|
const root = gsdProjectionRoot(basePath);
|
|
@@ -181,7 +210,7 @@ export function findMilestoneIds(basePath: string): string[] {
|
|
|
181
210
|
const ids = new Set<string>();
|
|
182
211
|
for (const dir of dirs) {
|
|
183
212
|
try {
|
|
184
|
-
for (const id of scanMilestoneIdsFromDir(dir)) ids.add(id);
|
|
213
|
+
for (const id of scanMilestoneIdsFromDir(basePath, dir)) ids.add(id);
|
|
185
214
|
} catch (err) {
|
|
186
215
|
if (existsSync(dir)) {
|
|
187
216
|
logWarning("engine", `findMilestoneIds: ${dir} exists but readdirSync failed — ${getErrorMessage(err)}`);
|
|
@@ -19,6 +19,16 @@ import { resolveTasksDir } from "./paths.js";
|
|
|
19
19
|
|
|
20
20
|
/** Large enough for unbounded milestone-history git log scans in big repos. */
|
|
21
21
|
const GIT_LOG_MAX_BUFFER = 16 * 1024 * 1024;
|
|
22
|
+
const LOG_FIELD_SEPARATOR = "\x1f";
|
|
23
|
+
const LOG_RECORD_SEPARATOR = "\x1e";
|
|
24
|
+
|
|
25
|
+
type CommitRecord = {
|
|
26
|
+
hash: string;
|
|
27
|
+
parents: string;
|
|
28
|
+
committedAt: string;
|
|
29
|
+
message: string;
|
|
30
|
+
files: string[];
|
|
31
|
+
};
|
|
22
32
|
|
|
23
33
|
/**
|
|
24
34
|
* Check whether a milestone produced implementation artifacts (non-`.gsd/`
|
|
@@ -198,7 +208,7 @@ function getChangedFilesFromMilestoneTaggedCommits(
|
|
|
198
208
|
// Primary: path-scoped log against .gsd/milestones/<id>. Fast and unbounded
|
|
199
209
|
// by depth when .gsd/ is tracked in git.
|
|
200
210
|
const scoped = scanGsdTaggedCommits(basePath, milestoneId, [
|
|
201
|
-
"log", "--format=%H%x1f%B%
|
|
211
|
+
"log", "--full-diff", "--name-only", "--format=%x1e%H%x1f%B%x1f", "HEAD", "--", `.gsd/milestones/${milestoneId}`,
|
|
202
212
|
]);
|
|
203
213
|
if (!scoped.ok) return scoped;
|
|
204
214
|
if (scoped.matched && classifyImplementationFiles(scoped.files) === "present") return scoped;
|
|
@@ -213,7 +223,7 @@ function getChangedFilesFromMilestoneTaggedCommits(
|
|
|
213
223
|
// reintroducing the rolling-depth failure class removed in #4699 where
|
|
214
224
|
// milestone evidence aged out behind unrelated activity.
|
|
215
225
|
const unscoped = scanGsdTaggedCommits(basePath, milestoneId, [
|
|
216
|
-
"log", "--format=%H%x1f%B%
|
|
226
|
+
"log", "--name-only", "--format=%x1e%H%x1f%B%x1f", "HEAD",
|
|
217
227
|
]);
|
|
218
228
|
if (!unscoped.ok) return scoped.matched ? scoped : unscoped;
|
|
219
229
|
if (!unscoped.matched) return scoped;
|
|
@@ -299,8 +309,7 @@ function backfillChangedFilesFromUntaggedMilestoneCommits(
|
|
|
299
309
|
if (record.parents.trim().split(/\s+/).filter(Boolean).length > 1) continue;
|
|
300
310
|
if (commitMessageHasGsdTrailer(record.message)) continue;
|
|
301
311
|
|
|
302
|
-
const
|
|
303
|
-
const implementationFiles = commitFiles.map(normalizeRepoPath).filter(isImplementationPath);
|
|
312
|
+
const implementationFiles = record.files.map(normalizeRepoPath).filter(isImplementationPath);
|
|
304
313
|
if (implementationFiles.length === 0) continue;
|
|
305
314
|
if (!implementationFiles.some((file) => hintSet.has(file))) continue;
|
|
306
315
|
|
|
@@ -323,25 +332,30 @@ function backfillChangedFilesFromUntaggedMilestoneCommits(
|
|
|
323
332
|
}
|
|
324
333
|
}
|
|
325
334
|
|
|
326
|
-
function getCommitRecords(basePath: string):
|
|
327
|
-
const logOutput = execFileSync("git", ["log", "--format=%H%x1f%P%x1f%cI%x1f%B%
|
|
335
|
+
function getCommitRecords(basePath: string): CommitRecord[] {
|
|
336
|
+
const logOutput = execFileSync("git", ["log", "--name-only", "--format=%x1e%H%x1f%P%x1f%cI%x1f%B%x1f", "HEAD"], {
|
|
328
337
|
cwd: basePath,
|
|
329
338
|
stdio: ["ignore", "pipe", "pipe"],
|
|
330
339
|
encoding: "utf-8",
|
|
331
340
|
maxBuffer: GIT_LOG_MAX_BUFFER,
|
|
332
341
|
});
|
|
333
342
|
return logOutput
|
|
334
|
-
.split(
|
|
335
|
-
.map((record) => record.trim())
|
|
343
|
+
.split(LOG_RECORD_SEPARATOR)
|
|
336
344
|
.filter(Boolean)
|
|
337
345
|
.flatMap((record) => {
|
|
338
|
-
const parts = record.split(
|
|
339
|
-
if (parts.length <
|
|
340
|
-
const [hash, parents, committedAt
|
|
341
|
-
|
|
346
|
+
const parts = record.split(LOG_FIELD_SEPARATOR);
|
|
347
|
+
if (parts.length < 5) return [];
|
|
348
|
+
const [hash, parents, committedAt] = parts;
|
|
349
|
+
const files = parseNameOnlyFiles(parts.at(-1) ?? "");
|
|
350
|
+
const message = parts.slice(3, -1).join(LOG_FIELD_SEPARATOR);
|
|
351
|
+
return [{ hash: hash.trim(), parents: parents.trim(), committedAt: committedAt.trim(), message, files }];
|
|
342
352
|
});
|
|
343
353
|
}
|
|
344
354
|
|
|
355
|
+
function parseNameOnlyFiles(rawFiles: string): string[] {
|
|
356
|
+
return rawFiles.split(/\r?\n/).map((file) => file.trim()).filter(Boolean);
|
|
357
|
+
}
|
|
358
|
+
|
|
345
359
|
function isFullCommitSha(value: string): boolean {
|
|
346
360
|
return /^[0-9a-f]{40}$/i.test(value);
|
|
347
361
|
}
|
|
@@ -359,23 +373,23 @@ function scanGsdTaggedCommits(
|
|
|
359
373
|
maxBuffer: GIT_LOG_MAX_BUFFER,
|
|
360
374
|
});
|
|
361
375
|
const records = logOutput
|
|
362
|
-
.split(
|
|
363
|
-
.map((record) => record.trim())
|
|
376
|
+
.split(LOG_RECORD_SEPARATOR)
|
|
364
377
|
.filter(Boolean)
|
|
365
378
|
.flatMap((record) => {
|
|
366
|
-
const
|
|
367
|
-
if (
|
|
368
|
-
const hash =
|
|
369
|
-
|
|
370
|
-
|
|
379
|
+
const parts = record.split(LOG_FIELD_SEPARATOR);
|
|
380
|
+
if (parts.length < 3) return [];
|
|
381
|
+
const hash = parts[0].trim();
|
|
382
|
+
if (!hash) return [];
|
|
383
|
+
const files = parseNameOnlyFiles(parts.at(-1) ?? "");
|
|
384
|
+
const message = parts.slice(1, -1).join(LOG_FIELD_SEPARATOR);
|
|
385
|
+
return [{ message, files }];
|
|
371
386
|
});
|
|
372
387
|
|
|
373
388
|
const files = new Set<string>();
|
|
374
389
|
let matched = false;
|
|
375
|
-
for (const {
|
|
390
|
+
for (const { message, files: commitFiles } of records) {
|
|
376
391
|
if (!commitMessageHasGsdTrailer(message)) continue;
|
|
377
392
|
|
|
378
|
-
const commitFiles = getChangedFilesForCommit(basePath, hash);
|
|
379
393
|
if (!commitMatchesMilestone(basePath, message, milestoneId, commitFiles)) continue;
|
|
380
394
|
|
|
381
395
|
matched = true;
|
|
@@ -33,16 +33,87 @@ function _isAlreadyRestoredApplyError(err: unknown): boolean {
|
|
|
33
33
|
|
|
34
34
|
export { _isAlreadyRestoredApplyError };
|
|
35
35
|
|
|
36
|
+
function gitOutput(basePath: string, args: string[]): string {
|
|
37
|
+
return execFileSync("git", args, {
|
|
38
|
+
cwd: basePath,
|
|
39
|
+
stdio: ["ignore", "pipe", "pipe"],
|
|
40
|
+
encoding: "utf-8",
|
|
41
|
+
env: GIT_NO_PROMPT_ENV,
|
|
42
|
+
});
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
function listStashUntrackedPaths(basePath: string, stashRef: string): string[] | null {
|
|
46
|
+
try {
|
|
47
|
+
return gitOutput(basePath, ["ls-tree", "-r", "-z", "--name-only", `${stashRef}^3`]).split("\0").filter(Boolean);
|
|
48
|
+
} catch {
|
|
49
|
+
return null;
|
|
50
|
+
}
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
function listStashTrackedPaths(basePath: string, stashRef: string): string[] | null {
|
|
54
|
+
try {
|
|
55
|
+
return gitOutput(basePath, ["diff", "--name-only", "-z", `${stashRef}^1`, stashRef]).split("\0").filter(Boolean);
|
|
56
|
+
} catch {
|
|
57
|
+
return null;
|
|
58
|
+
}
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
interface PorcelainEntry {
|
|
62
|
+
code: string;
|
|
63
|
+
path: string;
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
function readWorkingTreeStatus(basePath: string): PorcelainEntry[] | null {
|
|
67
|
+
try {
|
|
68
|
+
return gitOutput(basePath, ["status", "--porcelain", "-z", "--untracked-files=all"])
|
|
69
|
+
.split("\0")
|
|
70
|
+
.filter(Boolean)
|
|
71
|
+
.map((entry) => ({ code: entry.slice(0, 2), path: entry.slice(3) }));
|
|
72
|
+
} catch {
|
|
73
|
+
return null;
|
|
74
|
+
}
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
function isAlreadyRestoredUntrackedStatus(basePath: string, stashRef: string, statusEntries: PorcelainEntry[]): boolean {
|
|
78
|
+
if (statusEntries.length === 0 || statusEntries.some((entry) => entry.code !== "??")) return false;
|
|
79
|
+
const stashTrackedPaths = listStashTrackedPaths(basePath, stashRef);
|
|
80
|
+
if (!stashTrackedPaths || stashTrackedPaths.length > 0) return false;
|
|
81
|
+
const stashUntrackedPaths = listStashUntrackedPaths(basePath, stashRef);
|
|
82
|
+
if (!stashUntrackedPaths || stashUntrackedPaths.length === 0) return false;
|
|
83
|
+
const stashUntrackedPathSet = new Set(stashUntrackedPaths);
|
|
84
|
+
const workingTreeUntrackedPathSet = new Set(statusEntries.map((entry) => entry.path));
|
|
85
|
+
// "Already restored" requires the working tree's untracked paths to match the
|
|
86
|
+
// stash's untracked paths exactly, in BOTH directions:
|
|
87
|
+
// 1. every current untracked path comes from the stash (no unexplained user
|
|
88
|
+
// work that an apply would clobber), AND
|
|
89
|
+
// 2. every stash untracked path is already present in the working tree.
|
|
90
|
+
// Without (2), a partial restore (where only some stash files were recovered)
|
|
91
|
+
// would be misread as fully restored: the audit would no-op without applying
|
|
92
|
+
// or warning, leaving the remaining pre-merge files missing.
|
|
93
|
+
return (
|
|
94
|
+
statusEntries.every((entry) => stashUntrackedPathSet.has(entry.path)) &&
|
|
95
|
+
stashUntrackedPaths.every((path) => workingTreeUntrackedPathSet.has(path))
|
|
96
|
+
);
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
function manualApplyWarning(stashRef: string, milestoneId: string, reason: string): string {
|
|
100
|
+
return (
|
|
101
|
+
`Pre-merge stash ${stashRef} for milestone ${milestoneId} not auto-applied: ${reason}; ` +
|
|
102
|
+
`run \`git stash apply ${stashRef}\` manually to restore your pre-merge changes.`
|
|
103
|
+
);
|
|
104
|
+
}
|
|
105
|
+
|
|
36
106
|
/**
|
|
37
107
|
* Audit `git stash list` for orphaned `gsd-preflight-stash:M00x:*` entries.
|
|
38
108
|
*
|
|
39
109
|
* The matching merge code in `phases.ts` previously skipped the postflight
|
|
40
110
|
* pop whenever `mergeAndExit` threw, leaking the user's pre-merge working
|
|
41
|
-
* tree into the stash list.
|
|
42
|
-
*
|
|
111
|
+
* tree into the stash list. Completed-milestone stashes are only auto-applied
|
|
112
|
+
* when the working tree is clean and the stash does not modify tracked files.
|
|
113
|
+
* Dirty trees and tracked-file stashes are left untouched with a manual
|
|
114
|
+
* recovery warning. When auto-apply is safe, `git stash apply` is invoked —
|
|
43
115
|
* NOT `pop`. The stash entry stays in the list so the user retains a backup
|
|
44
|
-
* if the apply produces unexpected merge results.
|
|
45
|
-
* startup runs.
|
|
116
|
+
* if the apply produces unexpected merge results.
|
|
46
117
|
*
|
|
47
118
|
* Failures are best-effort: a list error (no repo, git unavailable) returns
|
|
48
119
|
* an empty result. An apply error becomes a warning the user sees alongside
|
|
@@ -56,16 +127,7 @@ export function auditOrphanedPreflightStashes(
|
|
|
56
127
|
|
|
57
128
|
let listOutput: string;
|
|
58
129
|
try {
|
|
59
|
-
listOutput =
|
|
60
|
-
"git",
|
|
61
|
-
["stash", "list", "--format=%gd%x00%s"],
|
|
62
|
-
{
|
|
63
|
-
cwd: basePath,
|
|
64
|
-
stdio: ["ignore", "pipe", "pipe"],
|
|
65
|
-
encoding: "utf-8",
|
|
66
|
-
env: GIT_NO_PROMPT_ENV,
|
|
67
|
-
},
|
|
68
|
-
);
|
|
130
|
+
listOutput = gitOutput(basePath, ["stash", "list", "--format=%gd%x00%s"]);
|
|
69
131
|
} catch {
|
|
70
132
|
return result;
|
|
71
133
|
}
|
|
@@ -93,13 +155,39 @@ export function auditOrphanedPreflightStashes(
|
|
|
93
155
|
}
|
|
94
156
|
if (!complete) continue;
|
|
95
157
|
|
|
158
|
+
const statusEntries = readWorkingTreeStatus(basePath);
|
|
159
|
+
if (!statusEntries) {
|
|
160
|
+
result.warnings.push(
|
|
161
|
+
manualApplyWarning(ref, milestoneId, "could not verify working tree status"),
|
|
162
|
+
);
|
|
163
|
+
continue;
|
|
164
|
+
}
|
|
165
|
+
if (statusEntries.length > 0) {
|
|
166
|
+
if (isAlreadyRestoredUntrackedStatus(basePath, ref, statusEntries)) continue;
|
|
167
|
+
result.warnings.push(manualApplyWarning(ref, milestoneId, "working tree not clean"));
|
|
168
|
+
continue;
|
|
169
|
+
}
|
|
170
|
+
|
|
171
|
+
const trackedPaths = listStashTrackedPaths(basePath, ref);
|
|
172
|
+
if (trackedPaths === null) {
|
|
173
|
+
result.warnings.push(
|
|
174
|
+
manualApplyWarning(ref, milestoneId, "could not inspect tracked paths in stash"),
|
|
175
|
+
);
|
|
176
|
+
continue;
|
|
177
|
+
}
|
|
178
|
+
if (trackedPaths.length > 0) {
|
|
179
|
+
// A retained tracked-file stash has no durable marker showing whether a
|
|
180
|
+
// clean tree needs first recovery or would be re-mutated by an old backup.
|
|
181
|
+
const preview = trackedPaths.slice(0, 5).join(", ");
|
|
182
|
+
const suffix = trackedPaths.length > 5 ? `, and ${trackedPaths.length - 5} more` : "";
|
|
183
|
+
result.warnings.push(
|
|
184
|
+
manualApplyWarning(ref, milestoneId, `stash modifies tracked files (${preview}${suffix})`),
|
|
185
|
+
);
|
|
186
|
+
continue;
|
|
187
|
+
}
|
|
188
|
+
|
|
96
189
|
try {
|
|
97
|
-
|
|
98
|
-
cwd: basePath,
|
|
99
|
-
stdio: ["ignore", "pipe", "pipe"],
|
|
100
|
-
encoding: "utf-8",
|
|
101
|
-
env: GIT_NO_PROMPT_ENV,
|
|
102
|
-
});
|
|
190
|
+
gitOutput(basePath, ["stash", "apply", "--quiet", ref]);
|
|
103
191
|
result.applied.push({ milestoneId, stashRef: ref });
|
|
104
192
|
} catch (err) {
|
|
105
193
|
// Idempotent steady state: stash was already applied in a prior audit
|
|
@@ -16,18 +16,20 @@ You are running the GSD **code-review** workflow — review source files changed
|
|
|
16
16
|
|
|
17
17
|
1. **Determine the file set.** Use the explicit `--files` list if provided. Otherwise derive the changed source files from the active slice's recent commits / SUMMARY, or fall back to the git diff against the base branch. Exclude `.gsd/`, lockfiles, generated/vendored code, and docs unless `--files` names them.
|
|
18
18
|
|
|
19
|
-
2. **
|
|
19
|
+
2. **Gather diff-first context.** Run `git diff` for the file set (or the relevant commit range) and use that as the primary review evidence. Use `read` only when the diff is insufficient — new/untracked files, truncated hunks, or missing surrounding context needed for a finding. Do **not** read every changed file when the diff already covers the edits. If the Tool Call Loop Guard blocks a tool, stop calling tools for the rest of this turn and continue in text.
|
|
20
|
+
|
|
21
|
+
3. **Review at the requested depth:**
|
|
20
22
|
- **quick** — bugs, security, and correctness only.
|
|
21
23
|
- **standard** (default) — quick + maintainability, error handling, edge cases.
|
|
22
24
|
- **deep** — standard + performance, concurrency, API design, test coverage gaps.
|
|
23
25
|
|
|
24
26
|
Ground every finding in the actual code with file path + line reference. Categorize each by severity (critical / warning / nit) and type (bug, security, quality, performance).
|
|
25
27
|
|
|
26
|
-
|
|
28
|
+
4. **Write the review.** Produce `.gsd/reviews/{{reviewId}}-REVIEW.md` with the findings table and per-finding detail (location, issue, suggested fix).
|
|
27
29
|
|
|
28
|
-
|
|
30
|
+
5. **Present results.** Summarize counts by severity and list the critical findings first.
|
|
29
31
|
|
|
30
|
-
|
|
32
|
+
6. **Fix mode** (only when `--fix` is set): for each finding that is safely auto-fixable (deterministic, no behavior change beyond the fix), apply it. After each fix batch, run the project's tests. Commit atomically with the finding IDs referenced in the message. Do not auto-apply findings that are ambiguous or that change public behavior — surface those for a human decision instead.
|
|
31
33
|
|
|
32
34
|
## Success criteria
|
|
33
35
|
|