@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
|
@@ -3,7 +3,7 @@
|
|
|
3
3
|
import { describe, test } from 'node:test';
|
|
4
4
|
import assert from 'node:assert/strict';
|
|
5
5
|
import { mkdtempSync, mkdirSync, writeFileSync, rmSync, existsSync, symlinkSync, readFileSync, chmodSync } from "node:fs";
|
|
6
|
-
import { join, dirname } from "node:path";
|
|
6
|
+
import { join, dirname, delimiter } from "node:path";
|
|
7
7
|
import { tmpdir } from "node:os";
|
|
8
8
|
import { execFileSync, execSync } from "node:child_process";
|
|
9
9
|
|
|
@@ -23,6 +23,7 @@ import {
|
|
|
23
23
|
type PreMergeCheckResult,
|
|
24
24
|
type TaskCommitContext,
|
|
25
25
|
} from "../../git-service.ts";
|
|
26
|
+
import { GIT_NO_PROMPT_ENV } from "../../git-constants.ts";
|
|
26
27
|
import { nativeAddAllWithExclusions, nativeHasChanges, _resetHasChangesCache } from "../../native-git-bridge.ts";
|
|
27
28
|
function run(command: string, cwd: string): string {
|
|
28
29
|
return execSync(command, { cwd, stdio: ["ignore", "pipe", "pipe"], encoding: "utf-8" }).trim();
|
|
@@ -293,12 +294,13 @@ describe('git-service', async () => {
|
|
|
293
294
|
|
|
294
295
|
assert.deepStrictEqual(
|
|
295
296
|
RUNTIME_EXCLUSION_PATHS.length,
|
|
296
|
-
|
|
297
|
-
"exactly
|
|
297
|
+
18,
|
|
298
|
+
"exactly 18 runtime exclusion paths"
|
|
298
299
|
);
|
|
299
300
|
|
|
300
301
|
const expectedPaths = [
|
|
301
302
|
".gsd-worktrees/",
|
|
303
|
+
".gsd-backups/**",
|
|
302
304
|
".gsd/activity/",
|
|
303
305
|
".gsd/audit/",
|
|
304
306
|
".gsd/forensics/",
|
|
@@ -405,6 +407,49 @@ describe('git-service', async () => {
|
|
|
405
407
|
}).trim();
|
|
406
408
|
}
|
|
407
409
|
|
|
410
|
+
function findGitExecutable(): string {
|
|
411
|
+
const command = process.platform === "win32" ? "where git" : "command -v git";
|
|
412
|
+
const output = execSync(command, { encoding: "utf-8" });
|
|
413
|
+
const found = output.split(/\r?\n/).map(line => line.trim()).find(Boolean);
|
|
414
|
+
assert.ok(found, "git executable is available");
|
|
415
|
+
return found;
|
|
416
|
+
}
|
|
417
|
+
|
|
418
|
+
function installGitRmCachedCounterShim(shimDir: string): void {
|
|
419
|
+
const shimScript = join(shimDir, "git-shim.cjs");
|
|
420
|
+
writeFileSync(shimScript, `
|
|
421
|
+
const { appendFileSync } = require("node:fs");
|
|
422
|
+
const { spawnSync } = require("node:child_process");
|
|
423
|
+
|
|
424
|
+
const args = process.argv.slice(2);
|
|
425
|
+
if (args[0] === "rm" && args[1] === "--cached") {
|
|
426
|
+
appendFileSync(process.env.GSD_GIT_SHIM_LOG, args.join("\\0") + "\\n");
|
|
427
|
+
}
|
|
428
|
+
|
|
429
|
+
const result = spawnSync(process.env.GSD_REAL_GIT || "git", args, {
|
|
430
|
+
stdio: "inherit",
|
|
431
|
+
env: process.env,
|
|
432
|
+
});
|
|
433
|
+
if (result.error) {
|
|
434
|
+
console.error(result.error.message);
|
|
435
|
+
process.exit(1);
|
|
436
|
+
}
|
|
437
|
+
process.exit(result.status ?? 0);
|
|
438
|
+
`.trimStart(), "utf-8");
|
|
439
|
+
|
|
440
|
+
const posixShim = join(shimDir, "git");
|
|
441
|
+
const quotedScript = `'${shimScript.replace(/'/g, "'\\''")}'`;
|
|
442
|
+
writeFileSync(posixShim, `#!/bin/sh\nexec node ${quotedScript} "$@"\n`, "utf-8");
|
|
443
|
+
chmodSync(posixShim, 0o755);
|
|
444
|
+
|
|
445
|
+
writeFileSync(join(shimDir, "git.cmd"), "@echo off\r\nnode \"%~dp0git-shim.cjs\" %*\r\n", "utf-8");
|
|
446
|
+
}
|
|
447
|
+
|
|
448
|
+
function countRmCachedInvocations(logFile: string): number {
|
|
449
|
+
if (!existsSync(logFile)) return 0;
|
|
450
|
+
return readFileSync(logFile, "utf-8").split(/\r?\n/).filter(Boolean).length;
|
|
451
|
+
}
|
|
452
|
+
|
|
408
453
|
// ─── GitServiceImpl: smart staging ─────────────────────────────────────
|
|
409
454
|
|
|
410
455
|
test('GitServiceImpl: smart staging', () => {
|
|
@@ -447,6 +492,80 @@ describe('git-service', async () => {
|
|
|
447
492
|
rmSync(repo, { recursive: true, force: true });
|
|
448
493
|
});
|
|
449
494
|
|
|
495
|
+
test('GitServiceImpl: runtime cleanup runs once per repo across service instances', () => {
|
|
496
|
+
const repo = initTempRepo();
|
|
497
|
+
const shimDir = mkdtempSync(join(tmpdir(), "gsd-git-rm-shim-"));
|
|
498
|
+
const logFile = join(shimDir, "git-rm-cached.log");
|
|
499
|
+
const originalPath = process.env.PATH;
|
|
500
|
+
const originalRealGit = process.env.GSD_REAL_GIT;
|
|
501
|
+
const originalShimLog = process.env.GSD_GIT_SHIM_LOG;
|
|
502
|
+
const originalSafePath = GIT_NO_PROMPT_ENV.PATH;
|
|
503
|
+
const originalSafeRealGit = GIT_NO_PROMPT_ENV.GSD_REAL_GIT;
|
|
504
|
+
const originalSafeShimLog = GIT_NO_PROMPT_ENV.GSD_GIT_SHIM_LOG;
|
|
505
|
+
|
|
506
|
+
try {
|
|
507
|
+
installGitRmCachedCounterShim(shimDir);
|
|
508
|
+
const realGit = findGitExecutable();
|
|
509
|
+
process.env.GSD_REAL_GIT = realGit;
|
|
510
|
+
process.env.GSD_GIT_SHIM_LOG = logFile;
|
|
511
|
+
process.env.PATH = `${shimDir}${delimiter}${originalPath ?? ""}`;
|
|
512
|
+
GIT_NO_PROMPT_ENV.GSD_REAL_GIT = realGit;
|
|
513
|
+
GIT_NO_PROMPT_ENV.GSD_GIT_SHIM_LOG = logFile;
|
|
514
|
+
GIT_NO_PROMPT_ENV.PATH = process.env.PATH;
|
|
515
|
+
|
|
516
|
+
createFile(repo, "src/first.ts", "first");
|
|
517
|
+
const first = new GitServiceImpl(repo).commit({ message: "test: first cleanup pass" });
|
|
518
|
+
assert.deepStrictEqual(first, "test: first cleanup pass", "first commit succeeds");
|
|
519
|
+
assert.deepStrictEqual(
|
|
520
|
+
countRmCachedInvocations(logFile),
|
|
521
|
+
RUNTIME_EXCLUSION_PATHS.length,
|
|
522
|
+
"first service instance checks each runtime exclusion once",
|
|
523
|
+
);
|
|
524
|
+
|
|
525
|
+
createFile(repo, "src/second.ts", "second");
|
|
526
|
+
const second = new GitServiceImpl(repo).commit({ message: "test: second cleanup pass" });
|
|
527
|
+
assert.deepStrictEqual(second, "test: second cleanup pass", "second commit succeeds");
|
|
528
|
+
assert.deepStrictEqual(
|
|
529
|
+
countRmCachedInvocations(logFile),
|
|
530
|
+
RUNTIME_EXCLUSION_PATHS.length,
|
|
531
|
+
"fresh service instance for the same repo does not rerun runtime cleanup",
|
|
532
|
+
);
|
|
533
|
+
} finally {
|
|
534
|
+
if (originalPath === undefined) {
|
|
535
|
+
delete process.env.PATH;
|
|
536
|
+
} else {
|
|
537
|
+
process.env.PATH = originalPath;
|
|
538
|
+
}
|
|
539
|
+
if (originalRealGit === undefined) {
|
|
540
|
+
delete process.env.GSD_REAL_GIT;
|
|
541
|
+
} else {
|
|
542
|
+
process.env.GSD_REAL_GIT = originalRealGit;
|
|
543
|
+
}
|
|
544
|
+
if (originalShimLog === undefined) {
|
|
545
|
+
delete process.env.GSD_GIT_SHIM_LOG;
|
|
546
|
+
} else {
|
|
547
|
+
process.env.GSD_GIT_SHIM_LOG = originalShimLog;
|
|
548
|
+
}
|
|
549
|
+
if (originalSafePath === undefined) {
|
|
550
|
+
delete GIT_NO_PROMPT_ENV.PATH;
|
|
551
|
+
} else {
|
|
552
|
+
GIT_NO_PROMPT_ENV.PATH = originalSafePath;
|
|
553
|
+
}
|
|
554
|
+
if (originalSafeRealGit === undefined) {
|
|
555
|
+
delete GIT_NO_PROMPT_ENV.GSD_REAL_GIT;
|
|
556
|
+
} else {
|
|
557
|
+
GIT_NO_PROMPT_ENV.GSD_REAL_GIT = originalSafeRealGit;
|
|
558
|
+
}
|
|
559
|
+
if (originalSafeShimLog === undefined) {
|
|
560
|
+
delete GIT_NO_PROMPT_ENV.GSD_GIT_SHIM_LOG;
|
|
561
|
+
} else {
|
|
562
|
+
GIT_NO_PROMPT_ENV.GSD_GIT_SHIM_LOG = originalSafeShimLog;
|
|
563
|
+
}
|
|
564
|
+
rmSync(repo, { recursive: true, force: true });
|
|
565
|
+
rmSync(shimDir, { recursive: true, force: true });
|
|
566
|
+
}
|
|
567
|
+
});
|
|
568
|
+
|
|
450
569
|
test('GitServiceImpl: task autoCommit skips keyFiles inside submodules', () => {
|
|
451
570
|
const repo = initTempRepo();
|
|
452
571
|
const subSrc = mkdtempSync(join(tmpdir(), "gsd-git-submodule-src-"));
|
|
@@ -1505,11 +1624,13 @@ describe('git-service', async () => {
|
|
|
1505
1624
|
// Create and track runtime files (simulates pre-.gitignore state)
|
|
1506
1625
|
mkdirSync(join(repo, ".gsd", "activity"), { recursive: true });
|
|
1507
1626
|
mkdirSync(join(repo, ".gsd", "runtime"), { recursive: true });
|
|
1627
|
+
mkdirSync(join(repo, ".gsd-backups", "migrate-old"), { recursive: true });
|
|
1508
1628
|
writeFileSync(join(repo, ".gsd", "completed-units.json"), '["u1"]');
|
|
1509
1629
|
writeFileSync(join(repo, ".gsd", "metrics.json"), '{}');
|
|
1510
1630
|
writeFileSync(join(repo, ".gsd", "STATE.md"), "# State");
|
|
1511
1631
|
writeFileSync(join(repo, ".gsd", "activity", "log.jsonl"), "{}");
|
|
1512
1632
|
writeFileSync(join(repo, ".gsd", "runtime", "data.json"), "{}");
|
|
1633
|
+
writeFileSync(join(repo, ".gsd-backups", "migrate-old", "marker.txt"), "backup");
|
|
1513
1634
|
writeFileSync(join(repo, "src.ts"), "code");
|
|
1514
1635
|
runGit(repo, ["add", "-A"]);
|
|
1515
1636
|
runGit(repo, ["commit", "-m", "init"]);
|
|
@@ -1518,6 +1639,8 @@ describe('git-service', async () => {
|
|
|
1518
1639
|
const trackedBefore = run("git ls-files .gsd/", repo);
|
|
1519
1640
|
assert.ok(trackedBefore.includes("completed-units.json"), "untrack: precondition — completed-units tracked");
|
|
1520
1641
|
assert.ok(trackedBefore.includes("metrics.json"), "untrack: precondition — metrics tracked");
|
|
1642
|
+
const backupTrackedBefore = run("git ls-files .gsd-backups/", repo);
|
|
1643
|
+
assert.ok(backupTrackedBefore.includes("marker.txt"), "untrack: precondition — migration backup tracked");
|
|
1521
1644
|
|
|
1522
1645
|
// Run untrackRuntimeFiles
|
|
1523
1646
|
untrackRuntimeFiles(repo);
|
|
@@ -1525,6 +1648,8 @@ describe('git-service', async () => {
|
|
|
1525
1648
|
// Runtime files should be removed from the index
|
|
1526
1649
|
const trackedAfter = run("git ls-files .gsd/", repo);
|
|
1527
1650
|
assert.deepStrictEqual(trackedAfter, "", "untrack: all runtime files removed from index");
|
|
1651
|
+
const backupTrackedAfter = run("git ls-files .gsd-backups/", repo);
|
|
1652
|
+
assert.deepStrictEqual(backupTrackedAfter, "", "untrack: migration backups removed from index");
|
|
1528
1653
|
|
|
1529
1654
|
// Non-runtime files remain tracked
|
|
1530
1655
|
const srcTracked = run("git ls-files src.ts", repo);
|
|
@@ -1535,6 +1660,8 @@ describe('git-service', async () => {
|
|
|
1535
1660
|
"untrack: completed-units.json still on disk");
|
|
1536
1661
|
assert.ok(existsSync(join(repo, ".gsd", "metrics.json")),
|
|
1537
1662
|
"untrack: metrics.json still on disk");
|
|
1663
|
+
assert.ok(existsSync(join(repo, ".gsd-backups", "migrate-old", "marker.txt")),
|
|
1664
|
+
"untrack: migration backup still on disk");
|
|
1538
1665
|
|
|
1539
1666
|
// Idempotent — running again doesn't error
|
|
1540
1667
|
untrackRuntimeFiles(repo);
|
package/src/resources/extensions/gsd/tests/integration/queue-active-milestone-context-budget.test.ts
ADDED
|
@@ -0,0 +1,93 @@
|
|
|
1
|
+
import { describe, test } from "node:test";
|
|
2
|
+
import assert from "node:assert/strict";
|
|
3
|
+
import { mkdtempSync, mkdirSync, rmSync, writeFileSync } from "node:fs";
|
|
4
|
+
import { join } from "node:path";
|
|
5
|
+
import { tmpdir } from "node:os";
|
|
6
|
+
|
|
7
|
+
import { buildExistingMilestonesContext } from "../../guided-flow-queue.ts";
|
|
8
|
+
import type { GSDState, MilestoneRegistryEntry } from "../../types.ts";
|
|
9
|
+
|
|
10
|
+
const LARGE_BODY = "A".repeat(150_000);
|
|
11
|
+
const LARGE_DRAFT = "D".repeat(150_000);
|
|
12
|
+
const LARGE_ROADMAP = "R".repeat(150_000);
|
|
13
|
+
|
|
14
|
+
function makeState(registry: MilestoneRegistryEntry[]): GSDState {
|
|
15
|
+
return {
|
|
16
|
+
activeMilestone: registry.find(m => m.status === "active") ?? null,
|
|
17
|
+
activeSlice: null,
|
|
18
|
+
activeTask: null,
|
|
19
|
+
phase: "executing",
|
|
20
|
+
recentDecisions: [],
|
|
21
|
+
blockers: [],
|
|
22
|
+
nextAction: "",
|
|
23
|
+
registry,
|
|
24
|
+
};
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
function writeMilestoneArtifact(base: string, mid: string, suffix: string, content: string): void {
|
|
28
|
+
mkdirSync(join(base, ".gsd", "milestones", mid), { recursive: true });
|
|
29
|
+
writeFileSync(join(base, ".gsd", "milestones", mid, `${mid}-${suffix}.md`), content);
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
describe("queue active/pending milestone context budget", () => {
|
|
33
|
+
test("summarizes active and pending artifacts with source paths and bounded excerpts", async () => {
|
|
34
|
+
const tmpBase = mkdtempSync(join(tmpdir(), "gsd-queue-active-budget-"));
|
|
35
|
+
try {
|
|
36
|
+
writeMilestoneArtifact(tmpBase, "M001", "CONTEXT", `# Active context\n\n${LARGE_BODY}\nEND_ACTIVE_CONTEXT`);
|
|
37
|
+
writeMilestoneArtifact(tmpBase, "M001", "ROADMAP", `# Active roadmap\n\n${LARGE_ROADMAP}\nEND_ACTIVE_ROADMAP`);
|
|
38
|
+
writeMilestoneArtifact(tmpBase, "M002", "CONTEXT-DRAFT", `# Pending draft\n\n${LARGE_DRAFT}\nEND_PENDING_DRAFT`);
|
|
39
|
+
writeMilestoneArtifact(tmpBase, "M002", "ROADMAP", `# Pending roadmap\n\n${LARGE_ROADMAP}\nEND_PENDING_ROADMAP`);
|
|
40
|
+
|
|
41
|
+
const registry: MilestoneRegistryEntry[] = [
|
|
42
|
+
{ id: "M001", title: "Active milestone", status: "active" },
|
|
43
|
+
{ id: "M002", title: "Pending milestone", status: "pending" },
|
|
44
|
+
];
|
|
45
|
+
|
|
46
|
+
const context = await buildExistingMilestonesContext(tmpBase, ["M001", "M002"], makeState(registry));
|
|
47
|
+
|
|
48
|
+
assert.match(context, /Source: `.gsd\/milestones\/M001\/M001-CONTEXT.md`/);
|
|
49
|
+
assert.match(context, /Source: `.gsd\/milestones\/M001\/M001-ROADMAP.md`/);
|
|
50
|
+
assert.match(context, /Source: `.gsd\/milestones\/M002\/M002-CONTEXT-DRAFT.md`/);
|
|
51
|
+
assert.match(context, /Source: `.gsd\/milestones\/M002\/M002-ROADMAP.md`/);
|
|
52
|
+
assert.match(context, /Read `.gsd\/milestones\/M001\/M001-CONTEXT.md` for full content/);
|
|
53
|
+
assert.equal(context.includes("END_ACTIVE_CONTEXT"), false);
|
|
54
|
+
assert.equal(context.includes("END_ACTIVE_ROADMAP"), false);
|
|
55
|
+
assert.equal(context.includes("END_PENDING_DRAFT"), false);
|
|
56
|
+
assert.equal(context.includes("END_PENDING_ROADMAP"), false);
|
|
57
|
+
} finally {
|
|
58
|
+
rmSync(tmpBase, { recursive: true, force: true });
|
|
59
|
+
}
|
|
60
|
+
});
|
|
61
|
+
|
|
62
|
+
test("caps the total existing milestones context", async () => {
|
|
63
|
+
const tmpBase = mkdtempSync(join(tmpdir(), "gsd-queue-total-budget-"));
|
|
64
|
+
try {
|
|
65
|
+
const registry: MilestoneRegistryEntry[] = [];
|
|
66
|
+
const milestoneIds: string[] = [];
|
|
67
|
+
for (let i = 1; i <= 5; i++) {
|
|
68
|
+
const mid = `M${String(i).padStart(3, "0")}`;
|
|
69
|
+
milestoneIds.push(mid);
|
|
70
|
+
registry.push({ id: mid, title: `Pending milestone ${i}`, status: "pending" });
|
|
71
|
+
writeMilestoneArtifact(tmpBase, mid, "CONTEXT", `# ${mid} context\n\n${LARGE_BODY}\nEND_${mid}_CONTEXT`);
|
|
72
|
+
writeMilestoneArtifact(tmpBase, mid, "ROADMAP", `# ${mid} roadmap\n\n${LARGE_ROADMAP}\nEND_${mid}_ROADMAP`);
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
const context = await buildExistingMilestonesContext(tmpBase, milestoneIds, makeState(registry));
|
|
76
|
+
|
|
77
|
+
assert.ok(
|
|
78
|
+
context.length <= 120_000,
|
|
79
|
+
`expected total context to stay within budget, got ${context.length} chars`,
|
|
80
|
+
);
|
|
81
|
+
assert.match(context, /Existing milestones context truncated/);
|
|
82
|
+
for (let i = 1; i <= 5; i++) {
|
|
83
|
+
const mid = `M${String(i).padStart(3, "0")}`;
|
|
84
|
+
assert.match(context, new RegExp(`### ${mid}: Pending milestone ${i}`));
|
|
85
|
+
assert.match(context, new RegExp(`Source: \`.gsd/milestones/${mid}/${mid}-CONTEXT.md\``));
|
|
86
|
+
assert.match(context, new RegExp(`Source: \`.gsd/milestones/${mid}/${mid}-ROADMAP.md\``));
|
|
87
|
+
}
|
|
88
|
+
assert.equal(context.includes("END_M005_ROADMAP"), false);
|
|
89
|
+
} finally {
|
|
90
|
+
rmSync(tmpBase, { recursive: true, force: true });
|
|
91
|
+
}
|
|
92
|
+
});
|
|
93
|
+
});
|
|
@@ -16,6 +16,7 @@ import { execSync } from "node:child_process";
|
|
|
16
16
|
|
|
17
17
|
import { captureIntegrationBranch, getCurrentBranch } from "../../worktree.ts";
|
|
18
18
|
import { readIntegrationBranch, QUICK_BRANCH_RE } from "../../git-service.ts";
|
|
19
|
+
import { disableDebug, enableDebug, getDebugCounters } from "../../debug-logger.ts";
|
|
19
20
|
|
|
20
21
|
function run(command: string, cwd: string): string {
|
|
21
22
|
return execSync(command, { cwd, stdio: ["ignore", "pipe", "pipe"], encoding: "utf-8" }).trim();
|
|
@@ -205,16 +206,25 @@ test('cleanupQuickBranch: recovers from disk state (cross-session)', async () =>
|
|
|
205
206
|
test('cleanupQuickBranch: no-op without pending state', async () => {
|
|
206
207
|
const repo = createTestRepo();
|
|
207
208
|
const origCwd = process.cwd();
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
const result = cleanupQuickBranch();
|
|
212
|
-
|
|
213
|
-
assert.ok(!result, "returns false when no pending state");
|
|
214
|
-
assert.deepStrictEqual(getCurrentBranch(repo), "main", "stays on main");
|
|
209
|
+
try {
|
|
210
|
+
process.chdir(repo);
|
|
211
|
+
enableDebug(repo);
|
|
215
212
|
|
|
216
|
-
|
|
217
|
-
|
|
213
|
+
const { cleanupQuickBranch } = await import("../../quick.ts");
|
|
214
|
+
const result = cleanupQuickBranch();
|
|
215
|
+
const firstGitInvocations = getDebugCounters().gitInvocations;
|
|
216
|
+
const secondResult = cleanupQuickBranch();
|
|
217
|
+
|
|
218
|
+
assert.ok(!result, "returns false when no pending state");
|
|
219
|
+
assert.ok(!secondResult, "still returns false when no pending state");
|
|
220
|
+
assert.deepStrictEqual(getDebugCounters().gitInvocations, firstGitInvocations,
|
|
221
|
+
"cached no-state cleanup does not re-run git branch inference");
|
|
222
|
+
assert.deepStrictEqual(getCurrentBranch(repo), "main", "stays on main");
|
|
223
|
+
} finally {
|
|
224
|
+
disableDebug();
|
|
225
|
+
process.chdir(origCwd);
|
|
226
|
+
rmSync(repo, { recursive: true, force: true });
|
|
227
|
+
}
|
|
218
228
|
});
|
|
219
229
|
|
|
220
230
|
test('cleanupQuickBranch: infers return state from current gsd/quick branch', async () => {
|
|
@@ -240,6 +250,43 @@ test('cleanupQuickBranch: infers return state from current gsd/quick branch', as
|
|
|
240
250
|
}
|
|
241
251
|
});
|
|
242
252
|
|
|
253
|
+
// ═══════════════════════════════════════════════════════════════════════
|
|
254
|
+
// cleanupQuickBranch: stale miss invalidated after mid-session branch switch
|
|
255
|
+
// ═══════════════════════════════════════════════════════════════════════
|
|
256
|
+
test('cleanupQuickBranch: clears stale miss when branch switches to gsd/quick mid-session', async () => {
|
|
257
|
+
const repo = createTestRepo();
|
|
258
|
+
const origCwd = process.cwd();
|
|
259
|
+
try {
|
|
260
|
+
// Create a quick branch with real product work (so inference finds a diff)
|
|
261
|
+
run("git checkout -b gsd/quick/3-stale-miss", repo);
|
|
262
|
+
writeFileSync(join(repo, "stale.txt"), "stale miss test\n");
|
|
263
|
+
run("git add stale.txt", repo);
|
|
264
|
+
run('git commit -m "test: stale miss"', repo);
|
|
265
|
+
// Return to main so the first cleanupQuickBranch call records a miss
|
|
266
|
+
run("git checkout main", repo);
|
|
267
|
+
|
|
268
|
+
process.chdir(repo);
|
|
269
|
+
const { cleanupQuickBranch } = await import("../../quick.ts");
|
|
270
|
+
|
|
271
|
+
// First call: on main with no disk state → miss recorded (keyed to "main")
|
|
272
|
+
const result1 = cleanupQuickBranch();
|
|
273
|
+
assert.ok(!result1, "first call (on main) returns false — miss recorded");
|
|
274
|
+
|
|
275
|
+
// Simulate mid-session external branch switch to the stranded quick branch
|
|
276
|
+
run("git checkout gsd/quick/3-stale-miss", repo);
|
|
277
|
+
|
|
278
|
+
// Second call: branch changed from the recorded miss, so cache is invalidated
|
|
279
|
+
// and inferQuickReturnFromBranch runs — cleanup must succeed
|
|
280
|
+
const result2 = cleanupQuickBranch();
|
|
281
|
+
assert.ok(result2, "second call returns true after mid-session switch to quick branch");
|
|
282
|
+
assert.deepStrictEqual(getCurrentBranch(repo), "main",
|
|
283
|
+
"cleanup merged back to main after stale-miss invalidation");
|
|
284
|
+
} finally {
|
|
285
|
+
process.chdir(origCwd);
|
|
286
|
+
rmSync(repo, { recursive: true, force: true });
|
|
287
|
+
}
|
|
288
|
+
});
|
|
289
|
+
|
|
243
290
|
// ═══════════════════════════════════════════════════════════════════════
|
|
244
291
|
// End-to-end: quick branch does NOT contaminate integration branch
|
|
245
292
|
// ═══════════════════════════════════════════════════════════════════════
|
|
@@ -19,6 +19,7 @@ import { tmpdir } from "node:os";
|
|
|
19
19
|
|
|
20
20
|
import {
|
|
21
21
|
saveJsonFile,
|
|
22
|
+
saveJsonFileCompact,
|
|
22
23
|
loadJsonFile,
|
|
23
24
|
writeJsonFileAtomic,
|
|
24
25
|
} from "../json-persistence.ts";
|
|
@@ -56,6 +57,37 @@ test("saveJsonFile creates file with valid JSON content", () => {
|
|
|
56
57
|
}
|
|
57
58
|
});
|
|
58
59
|
|
|
60
|
+
test("saveJsonFile keeps pretty-printed output for human-readable state", () => {
|
|
61
|
+
const dir = makeTempDir();
|
|
62
|
+
const filePath = join(dir, "pretty.json");
|
|
63
|
+
|
|
64
|
+
try {
|
|
65
|
+
const data = { foo: "bar", nested: { count: 42 } };
|
|
66
|
+
saveJsonFile(filePath, data);
|
|
67
|
+
|
|
68
|
+
const content = readFileSync(filePath, "utf-8");
|
|
69
|
+
assert.equal(content, JSON.stringify(data, null, 2) + "\n");
|
|
70
|
+
} finally {
|
|
71
|
+
cleanup(dir);
|
|
72
|
+
}
|
|
73
|
+
});
|
|
74
|
+
|
|
75
|
+
test("saveJsonFileCompact writes valid compact JSON content", () => {
|
|
76
|
+
const dir = makeTempDir();
|
|
77
|
+
const filePath = join(dir, "compact.json");
|
|
78
|
+
|
|
79
|
+
try {
|
|
80
|
+
const data = { foo: "bar", nested: { count: 42 } };
|
|
81
|
+
saveJsonFileCompact(filePath, data);
|
|
82
|
+
|
|
83
|
+
const content = readFileSync(filePath, "utf-8");
|
|
84
|
+
assert.equal(content, JSON.stringify(data) + "\n");
|
|
85
|
+
assert.deepEqual(JSON.parse(content), data);
|
|
86
|
+
} finally {
|
|
87
|
+
cleanup(dir);
|
|
88
|
+
}
|
|
89
|
+
});
|
|
90
|
+
|
|
59
91
|
test("saveJsonFile does not leave .tmp files on success", () => {
|
|
60
92
|
const dir = makeTempDir();
|
|
61
93
|
const filePath = join(dir, "clean.json");
|
|
@@ -72,6 +104,21 @@ test("saveJsonFile does not leave .tmp files on success", () => {
|
|
|
72
104
|
}
|
|
73
105
|
});
|
|
74
106
|
|
|
107
|
+
test("saveJsonFileCompact does not leave .tmp files on success", () => {
|
|
108
|
+
const dir = makeTempDir();
|
|
109
|
+
const filePath = join(dir, "compact-clean.json");
|
|
110
|
+
|
|
111
|
+
try {
|
|
112
|
+
saveJsonFileCompact(filePath, { test: true });
|
|
113
|
+
|
|
114
|
+
const files = readdirSync(dir);
|
|
115
|
+
const tmpFiles = files.filter(f => f.includes(".tmp"));
|
|
116
|
+
assert.equal(tmpFiles.length, 0, `Unexpected .tmp files: ${tmpFiles.join(", ")}`);
|
|
117
|
+
} finally {
|
|
118
|
+
cleanup(dir);
|
|
119
|
+
}
|
|
120
|
+
});
|
|
121
|
+
|
|
75
122
|
test("saveJsonFile creates parent directories", () => {
|
|
76
123
|
const dir = makeTempDir();
|
|
77
124
|
const filePath = join(dir, "deep", "nested", "data.json");
|
|
@@ -161,6 +161,41 @@ test("backfill is idempotent — second run on the same file is a no-op", () =>
|
|
|
161
161
|
}
|
|
162
162
|
});
|
|
163
163
|
|
|
164
|
+
test("backfill skips a knowledge row whose memory insert throws and continues later rows", () => {
|
|
165
|
+
const base = makeTmpBase();
|
|
166
|
+
try {
|
|
167
|
+
writeKnowledgeMd(base, FIXTURE);
|
|
168
|
+
|
|
169
|
+
const adapter = _getAdapter();
|
|
170
|
+
assert.ok(adapter);
|
|
171
|
+
adapter.exec(`
|
|
172
|
+
CREATE TRIGGER fail_p002_memory_insert
|
|
173
|
+
BEFORE INSERT ON memories
|
|
174
|
+
WHEN json_extract(NEW.structured_fields, '$.sourceKnowledgeId') = 'P002'
|
|
175
|
+
BEGIN
|
|
176
|
+
SELECT RAISE(ABORT, 'poison knowledge P002');
|
|
177
|
+
END
|
|
178
|
+
`);
|
|
179
|
+
|
|
180
|
+
const written = backfillKnowledgeToMemories(base);
|
|
181
|
+
assert.equal(written, 2, "one poisoned row should not abort the batch");
|
|
182
|
+
|
|
183
|
+
const rows = adapter
|
|
184
|
+
.prepare(
|
|
185
|
+
"SELECT structured_fields FROM memories WHERE structured_fields LIKE '%\"sourceKnowledgeId\":\"%' ORDER BY seq",
|
|
186
|
+
)
|
|
187
|
+
.all() as Array<{ structured_fields: string }>;
|
|
188
|
+
|
|
189
|
+
assert.deepEqual(
|
|
190
|
+
rows.map((row) => JSON.parse(row.structured_fields).sourceKnowledgeId),
|
|
191
|
+
["P001", "L001"],
|
|
192
|
+
"rows after the poisoned knowledge entry should still be migrated",
|
|
193
|
+
);
|
|
194
|
+
} finally {
|
|
195
|
+
cleanup(base);
|
|
196
|
+
}
|
|
197
|
+
});
|
|
198
|
+
|
|
164
199
|
test("backfill returns 0 when KNOWLEDGE.md is absent", () => {
|
|
165
200
|
const base = makeTmpBase();
|
|
166
201
|
try {
|
|
@@ -136,8 +136,10 @@ test("#896 startup maintenance skips repeated sentinel work in one session", asy
|
|
|
136
136
|
closeDatabase();
|
|
137
137
|
assert.equal(isDbAvailable(), false);
|
|
138
138
|
|
|
139
|
+
let sessionId = "session-one";
|
|
139
140
|
const ctx = {
|
|
140
141
|
projectRoot: base,
|
|
142
|
+
sessionManager: { getSessionId: () => sessionId },
|
|
141
143
|
ui: { notify: () => undefined },
|
|
142
144
|
} as unknown as ExtensionContext;
|
|
143
145
|
|
|
@@ -190,6 +192,18 @@ test("#896 startup maintenance skips repeated sentinel work in one session", asy
|
|
|
190
192
|
.prepare("SELECT COUNT(*) AS count FROM memories WHERE structured_fields LIKE '%\"sourceKnowledgeId\":\"P002\"%'")
|
|
191
193
|
.get() as { count: number };
|
|
192
194
|
assert.equal(secondPass.count, 0, "second startup in same session should not re-run KNOWLEDGE.md sentinel backfill");
|
|
195
|
+
|
|
196
|
+
sessionId = "session-two";
|
|
197
|
+
await buildBeforeAgentStartResult(
|
|
198
|
+
{ prompt: "Inspect project knowledge in a new session", systemPrompt: "base system prompt" },
|
|
199
|
+
ctx,
|
|
200
|
+
);
|
|
201
|
+
await _flushDeferredContextMaintenanceForTest(base);
|
|
202
|
+
|
|
203
|
+
const nextSessionPass = adapter
|
|
204
|
+
.prepare("SELECT COUNT(*) AS count FROM memories WHERE structured_fields LIKE '%\"sourceKnowledgeId\":\"P002\"%'")
|
|
205
|
+
.get() as { count: number };
|
|
206
|
+
assert.equal(nextSessionPass.count, 1, "startup maintenance should run once for a later session");
|
|
193
207
|
});
|
|
194
208
|
|
|
195
209
|
test("#896 later turns reopen the project DB after startup maintenance is complete", async (t) => {
|
|
@@ -16,6 +16,7 @@ import {
|
|
|
16
16
|
openDatabase,
|
|
17
17
|
closeDatabase,
|
|
18
18
|
insertDecision,
|
|
19
|
+
_getAdapter,
|
|
19
20
|
} from "../gsd-db.ts";
|
|
20
21
|
import { createMemory } from "../memory-store.ts";
|
|
21
22
|
import {
|
|
@@ -271,6 +272,83 @@ test("scanConsolidationGaps combines decisions and KNOWLEDGE.md gaps in summary"
|
|
|
271
272
|
}
|
|
272
273
|
});
|
|
273
274
|
|
|
275
|
+
test("scanConsolidationGaps collects memory source markers with one memories scan", () => {
|
|
276
|
+
const base = makeTmpBase();
|
|
277
|
+
try {
|
|
278
|
+
insertDecision({
|
|
279
|
+
id: "D001",
|
|
280
|
+
when_context: "2026-01-01",
|
|
281
|
+
scope: "M001",
|
|
282
|
+
decision: "Unmigrated decision",
|
|
283
|
+
choice: "A",
|
|
284
|
+
rationale: "x",
|
|
285
|
+
revisable: "yes",
|
|
286
|
+
made_by: "agent",
|
|
287
|
+
superseded_by: null,
|
|
288
|
+
});
|
|
289
|
+
insertDecision({
|
|
290
|
+
id: "D002",
|
|
291
|
+
when_context: "2026-01-02",
|
|
292
|
+
scope: "M001",
|
|
293
|
+
decision: "Migrated decision",
|
|
294
|
+
choice: "B",
|
|
295
|
+
rationale: "y",
|
|
296
|
+
revisable: "yes",
|
|
297
|
+
made_by: "agent",
|
|
298
|
+
superseded_by: null,
|
|
299
|
+
});
|
|
300
|
+
createMemory({
|
|
301
|
+
category: "architecture",
|
|
302
|
+
content: "Migrated decision Chose: B. Rationale: y.",
|
|
303
|
+
scope: "M001",
|
|
304
|
+
structuredFields: { sourceDecisionId: "D002" },
|
|
305
|
+
});
|
|
306
|
+
createMemory({
|
|
307
|
+
category: "pattern",
|
|
308
|
+
content: "Migrated knowledge pattern",
|
|
309
|
+
scope: "project",
|
|
310
|
+
structuredFields: { sourceKnowledgeId: "P001" },
|
|
311
|
+
});
|
|
312
|
+
writeKnowledgeMd(
|
|
313
|
+
base,
|
|
314
|
+
`## Patterns
|
|
315
|
+
|
|
316
|
+
| # | Pattern | Where | Notes |
|
|
317
|
+
|---|---------|-------|-------|
|
|
318
|
+
| P001 | Migrated knowledge pattern | scanner | covered |
|
|
319
|
+
| P002 | Unmigrated knowledge pattern | scanner | gap |
|
|
320
|
+
`,
|
|
321
|
+
);
|
|
322
|
+
|
|
323
|
+
const adapter = _getAdapter();
|
|
324
|
+
assert.ok(adapter);
|
|
325
|
+
const originalPrepare = adapter.prepare.bind(adapter);
|
|
326
|
+
const memorySql: string[] = [];
|
|
327
|
+
adapter.prepare = (sql: string) => {
|
|
328
|
+
if (sql.includes("FROM memories")) memorySql.push(sql);
|
|
329
|
+
return originalPrepare(sql);
|
|
330
|
+
};
|
|
331
|
+
|
|
332
|
+
const report = scanConsolidationGaps(base);
|
|
333
|
+
assert.equal(report.decisions.migrated, 1);
|
|
334
|
+
assert.equal(report.decisions.unmigrated, 1);
|
|
335
|
+
assert.equal(report.knowledge.migrated, 1);
|
|
336
|
+
assert.equal(report.knowledge.unmigrated, 1);
|
|
337
|
+
assert.equal(
|
|
338
|
+
memorySql.filter((sql) => sql.includes("SELECT structured_fields FROM memories")).length,
|
|
339
|
+
1,
|
|
340
|
+
"source marker detection should read memories once",
|
|
341
|
+
);
|
|
342
|
+
assert.equal(
|
|
343
|
+
memorySql.some((sql) => sql.includes("LIKE :pattern")),
|
|
344
|
+
false,
|
|
345
|
+
"scanner must not reintroduce per-row LIKE marker probes",
|
|
346
|
+
);
|
|
347
|
+
} finally {
|
|
348
|
+
cleanup(base);
|
|
349
|
+
}
|
|
350
|
+
});
|
|
351
|
+
|
|
274
352
|
// ─── reportConsolidationGaps ───────────────────────────────────────────────
|
|
275
353
|
|
|
276
354
|
test("reportConsolidationGaps emits a notification + warning when gaps exist", () => {
|
|
@@ -9,7 +9,15 @@ import { tmpdir } from "node:os";
|
|
|
9
9
|
import { execFileSync } from "node:child_process";
|
|
10
10
|
|
|
11
11
|
import { mergeMilestoneToMain } from "../auto-worktree.ts";
|
|
12
|
-
import {
|
|
12
|
+
import { checkCloseoutConsistencyGate } from "../closeout-consistency-gate.ts";
|
|
13
|
+
import {
|
|
14
|
+
closeDatabase,
|
|
15
|
+
insertAssessment,
|
|
16
|
+
insertMilestone,
|
|
17
|
+
insertSlice,
|
|
18
|
+
insertTask,
|
|
19
|
+
openDatabase,
|
|
20
|
+
} from "../gsd-db.ts";
|
|
13
21
|
|
|
14
22
|
function git(args: string[], cwd: string): string {
|
|
15
23
|
return execFileSync("git", args, {
|
|
@@ -61,3 +69,25 @@ test("mergeMilestoneToMain blocks when project DB closeout is still open", () =>
|
|
|
61
69
|
if (existsSync(repo)) rmSync(repo, { recursive: true, force: true });
|
|
62
70
|
}
|
|
63
71
|
});
|
|
72
|
+
|
|
73
|
+
test("closeout consistency treats deferred slices as inactive", () => {
|
|
74
|
+
try {
|
|
75
|
+
assert.equal(openDatabase(":memory:"), true);
|
|
76
|
+
insertMilestone({ id: "M001", title: "Milestone One", status: "complete" });
|
|
77
|
+
insertSlice({ milestoneId: "M001", id: "S01", title: "Done", status: "complete" });
|
|
78
|
+
insertTask({ milestoneId: "M001", sliceId: "S01", id: "T01", title: "Done", status: "complete" });
|
|
79
|
+
insertSlice({ milestoneId: "M001", id: "S02", title: "Deferred", status: "deferred" });
|
|
80
|
+
insertTask({ milestoneId: "M001", sliceId: "S02", id: "T02", title: "Deferred", status: "pending" });
|
|
81
|
+
insertAssessment({
|
|
82
|
+
path: "milestones/M001/M001-VALIDATION.md",
|
|
83
|
+
milestoneId: "M001",
|
|
84
|
+
status: "pass",
|
|
85
|
+
scope: "milestone-validation",
|
|
86
|
+
fullContent: "verdict: pass",
|
|
87
|
+
});
|
|
88
|
+
|
|
89
|
+
assert.deepEqual(checkCloseoutConsistencyGate("M001"), { ok: true });
|
|
90
|
+
} finally {
|
|
91
|
+
closeDatabase();
|
|
92
|
+
}
|
|
93
|
+
});
|
|
@@ -112,6 +112,12 @@ describe("pruneMetricsLedger: invalidates scoped ledger cache", () => {
|
|
|
112
112
|
// 3. Prune to keepCount=2 — should evict 3 old units from disk AND clear scopedLedgers.
|
|
113
113
|
const removed = pruneMetricsLedger(tmpDir, 2);
|
|
114
114
|
assert.equal(removed, 3, "pruneMetricsLedger should report 3 removed units");
|
|
115
|
+
const prunedRaw = readFileSync(metricsPath(tmpDir), "utf-8");
|
|
116
|
+
assert.equal(
|
|
117
|
+
prunedRaw,
|
|
118
|
+
JSON.stringify(JSON.parse(prunedRaw)) + "\n",
|
|
119
|
+
"pruneMetricsLedger should persist compact metrics.json",
|
|
120
|
+
);
|
|
115
121
|
|
|
116
122
|
// 4. Snapshot a new unit via scope. This exercises the lazy-reload path
|
|
117
123
|
// (scopedLedgers was cleared by prune) and writes the result to disk.
|