@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
|
@@ -8,6 +8,7 @@ import { join } from "node:path";
|
|
|
8
8
|
import { tmpdir } from "node:os";
|
|
9
9
|
|
|
10
10
|
import {
|
|
11
|
+
CONTEXT_MODE_GUIDANCE_BY_UNIT,
|
|
11
12
|
composeContractedUnitContext,
|
|
12
13
|
composeContextModeInstructions,
|
|
13
14
|
composeInlinedContext,
|
|
@@ -141,9 +142,13 @@ test("Context Mode composer: nested output is compact single sentence", () => {
|
|
|
141
142
|
assert.ok(!out.startsWith("## Context Mode"));
|
|
142
143
|
assert.match(out, /^Context Mode \(verification lane\): /);
|
|
143
144
|
assert.strictEqual(out.split(/\n/).length, 1);
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
assert.
|
|
145
|
+
// Nested guidance is embedded into tester subagent prompts — it must instruct the tester
|
|
146
|
+
// to run verification and call gsd_save_gate_result, NOT to dispatch further subagents.
|
|
147
|
+
assert.doesNotMatch(out, /`subagent`/, "tester prompts must not be told to dispatch subagents");
|
|
148
|
+
assert.match(out, /`gsd_save_gate_result`/);
|
|
149
|
+
assert.doesNotMatch(out, /`gsd_exec`/);
|
|
150
|
+
assert.doesNotMatch(out, /`gsd_exec_search`/);
|
|
151
|
+
assert.doesNotMatch(out, /`gsd_resume`/);
|
|
147
152
|
assert.ok(out.length < 240, `nested guidance should stay compact, got ${out.length} chars`);
|
|
148
153
|
});
|
|
149
154
|
|
|
@@ -158,6 +163,53 @@ const laneLabelByMode: Record<string, string> = {
|
|
|
158
163
|
triage: "triage",
|
|
159
164
|
};
|
|
160
165
|
|
|
166
|
+
const contextModeGuidanceOverrideExpectedTools: Record<string, readonly string[]> = {
|
|
167
|
+
"discuss-milestone": [
|
|
168
|
+
"ask_user_questions",
|
|
169
|
+
"gsd_summary_save",
|
|
170
|
+
"gsd_decision_save",
|
|
171
|
+
"gsd_requirement_save",
|
|
172
|
+
"gsd_requirement_update",
|
|
173
|
+
"gsd_plan_milestone",
|
|
174
|
+
"gsd_milestone_generate_id",
|
|
175
|
+
],
|
|
176
|
+
"discuss-project": [
|
|
177
|
+
"ask_user_questions",
|
|
178
|
+
"gsd_summary_save",
|
|
179
|
+
"gsd_decision_save",
|
|
180
|
+
"gsd_requirement_save",
|
|
181
|
+
],
|
|
182
|
+
"discuss-requirements": [
|
|
183
|
+
"ask_user_questions",
|
|
184
|
+
"gsd_requirement_save",
|
|
185
|
+
"gsd_summary_save",
|
|
186
|
+
],
|
|
187
|
+
"discuss-slice": [
|
|
188
|
+
"ask_user_questions",
|
|
189
|
+
"gsd_summary_save",
|
|
190
|
+
"gsd_decision_save",
|
|
191
|
+
],
|
|
192
|
+
"replan-slice": [
|
|
193
|
+
"gsd_replan_slice",
|
|
194
|
+
"gsd_decision_save",
|
|
195
|
+
],
|
|
196
|
+
"reassess-roadmap": [
|
|
197
|
+
"gsd_milestone_status",
|
|
198
|
+
"gsd_reassess_roadmap",
|
|
199
|
+
],
|
|
200
|
+
"run-uat": [
|
|
201
|
+
"gsd_uat_exec",
|
|
202
|
+
"gsd_resume",
|
|
203
|
+
],
|
|
204
|
+
// research-project uses scout subagents that write .gsd/research/ files directly;
|
|
205
|
+
// the parent dispatches Task calls and verifies file outputs — no GSD save tools.
|
|
206
|
+
"research-project": [],
|
|
207
|
+
"gate-evaluate": [
|
|
208
|
+
"subagent",
|
|
209
|
+
"gsd_save_gate_result",
|
|
210
|
+
],
|
|
211
|
+
};
|
|
212
|
+
|
|
161
213
|
test("Context Mode composer: every known eligible unit renders its configured lane and required tools", () => {
|
|
162
214
|
for (const unitType of KNOWN_UNIT_TYPES) {
|
|
163
215
|
const manifest = UNIT_MANIFESTS[unitType];
|
|
@@ -170,18 +222,65 @@ test("Context Mode composer: every known eligible unit renders its configured la
|
|
|
170
222
|
assert.ok(out.startsWith("## Context Mode"), `${unitType} should render standalone Context Mode heading`);
|
|
171
223
|
assert.match(out, new RegExp(`Lane: \\*\\*${laneLabelByMode[manifest.contextMode]} lane\\*\\*\\.`, "i"));
|
|
172
224
|
const forbidden = getUnitToolSurfaceContract(unitType)?.forbiddenGsdTools ?? {};
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
//
|
|
176
|
-
//
|
|
177
|
-
assert.doesNotMatch(out, /`gsd_exec`/, `${unitType}
|
|
225
|
+
const overrideExpectedTools = contextModeGuidanceOverrideExpectedTools[unitType];
|
|
226
|
+
if ("gsd_exec" in forbidden || overrideExpectedTools) {
|
|
227
|
+
// Unit overrides are the contract-specific exception to lane defaults.
|
|
228
|
+
// Steering to the lane default here can produce unavailable-tool loops.
|
|
229
|
+
assert.doesNotMatch(out, /`gsd_exec`/, `${unitType} guidance must not steer to gsd_exec`);
|
|
178
230
|
assert.doesNotMatch(out, /`gsd_exec_search`/, `${unitType} guidance must not steer to gsd_exec_search`);
|
|
179
|
-
|
|
231
|
+
for (const toolName of overrideExpectedTools ?? []) {
|
|
232
|
+
assert.match(out, new RegExp(`\`${toolName}\``), `${unitType} guidance should mention ${toolName}`);
|
|
233
|
+
}
|
|
180
234
|
} else {
|
|
181
235
|
assert.match(out, /`gsd_exec`/, `${unitType} should mention gsd_exec`);
|
|
182
236
|
assert.match(out, /`gsd_exec_search`/, `${unitType} should mention gsd_exec_search`);
|
|
183
237
|
}
|
|
184
|
-
|
|
238
|
+
if (!overrideExpectedTools || overrideExpectedTools.includes("gsd_resume")) {
|
|
239
|
+
assert.match(out, /`gsd_resume`/, `${unitType} should mention gsd_resume`);
|
|
240
|
+
} else {
|
|
241
|
+
assert.doesNotMatch(out, /`gsd_resume`/, `${unitType} guidance must not steer to gsd_resume`);
|
|
242
|
+
}
|
|
243
|
+
}
|
|
244
|
+
});
|
|
245
|
+
|
|
246
|
+
test("Context Mode composer: discuss interview overrides stay within unit contracts", () => {
|
|
247
|
+
const discussUnits = [
|
|
248
|
+
"discuss-milestone",
|
|
249
|
+
"discuss-project",
|
|
250
|
+
"discuss-requirements",
|
|
251
|
+
"discuss-slice",
|
|
252
|
+
];
|
|
253
|
+
|
|
254
|
+
for (const unitType of discussUnits) {
|
|
255
|
+
const guidance = CONTEXT_MODE_GUIDANCE_BY_UNIT[unitType];
|
|
256
|
+
assert.ok(guidance, `${unitType} should have a Context Mode override`);
|
|
257
|
+
assert.doesNotMatch(guidance, /`gsd_exec`/, `${unitType} guidance must not mention gsd_exec`);
|
|
258
|
+
assert.doesNotMatch(guidance, /`gsd_exec_search`/, `${unitType} guidance must not mention gsd_exec_search`);
|
|
259
|
+
assert.doesNotMatch(guidance, /`gsd_resume`/, `${unitType} guidance must not mention gsd_resume`);
|
|
260
|
+
|
|
261
|
+
const expectedTools = contextModeGuidanceOverrideExpectedTools[unitType] ?? [];
|
|
262
|
+
assert.ok(expectedTools.length > 0, `${unitType} should declare expected override tools`);
|
|
263
|
+
const contract = getUnitToolSurfaceContract(unitType);
|
|
264
|
+
assert.ok(contract, `${unitType} should have a tool contract`);
|
|
265
|
+
const contractTools = new Set([
|
|
266
|
+
...contract.allowedGsdTools,
|
|
267
|
+
...contract.requiredWorkflowTools,
|
|
268
|
+
]);
|
|
269
|
+
|
|
270
|
+
for (const toolName of expectedTools) {
|
|
271
|
+
assert.match(guidance, new RegExp(`\`${toolName}\``), `${unitType} guidance should mention ${toolName}`);
|
|
272
|
+
assert.ok(contractTools.has(toolName as UnitGsdToolName), `${unitType} contract should allow ${toolName}`);
|
|
273
|
+
const scope = shouldBlockAutoUnitToolCall(unitType, toolName);
|
|
274
|
+
assert.equal(scope.block, false, `${unitType} should not hard-block ${toolName}: ${scope.reason ?? ""}`);
|
|
275
|
+
}
|
|
276
|
+
|
|
277
|
+
const out = composeContextModeInstructions(unitType, { enabled: true, renderMode: "standalone" });
|
|
278
|
+
if (out) {
|
|
279
|
+
assert.match(out, /interview lane/i);
|
|
280
|
+
assert.doesNotMatch(out, /`gsd_exec`/);
|
|
281
|
+
assert.doesNotMatch(out, /`gsd_exec_search`/);
|
|
282
|
+
assert.doesNotMatch(out, /`gsd_resume`/);
|
|
283
|
+
}
|
|
185
284
|
}
|
|
186
285
|
});
|
|
187
286
|
|
|
@@ -195,8 +294,67 @@ test("Context Mode composer: run-uat guidance steers to gsd_uat_exec in both ren
|
|
|
195
294
|
assert.doesNotMatch(standalone, /`gsd_exec`/);
|
|
196
295
|
});
|
|
197
296
|
|
|
198
|
-
test("Context Mode composer:
|
|
199
|
-
const
|
|
297
|
+
test("Context Mode composer: research-project guidance steers to scout orchestration", () => {
|
|
298
|
+
for (const renderMode of ["nested", "standalone"] as const) {
|
|
299
|
+
const out = composeContextModeInstructions("research-project", { enabled: true, renderMode });
|
|
300
|
+
assert.match(out, /research lane/i);
|
|
301
|
+
assert.match(out, /scout subagents/i);
|
|
302
|
+
assert.match(out, /\.gsd\/research\//);
|
|
303
|
+
assert.match(out, /STACK\.md/);
|
|
304
|
+
assert.match(out, /PITFALLS\.md/);
|
|
305
|
+
assert.doesNotMatch(out, /`gsd_summary_save`/);
|
|
306
|
+
assert.doesNotMatch(out, /`gsd_decision_save`/);
|
|
307
|
+
assert.doesNotMatch(out, /`gsd_exec`/);
|
|
308
|
+
assert.doesNotMatch(out, /`gsd_exec_search`/);
|
|
309
|
+
assert.doesNotMatch(out, /`gsd_resume`/);
|
|
310
|
+
}
|
|
311
|
+
|
|
312
|
+
const contract = getUnitToolSurfaceContract("research-project");
|
|
313
|
+
assert.deepEqual(contract?.allowedGsdTools, []);
|
|
314
|
+
assert.deepEqual(contract?.requiredWorkflowTools, []);
|
|
315
|
+
for (const toolName of ["gsd_summary_save", "gsd_decision_save"]) {
|
|
316
|
+
const scope = shouldBlockAutoUnitToolCall("research-project", toolName);
|
|
317
|
+
assert.equal(scope.block, true, `research-project should not allow ${toolName}`);
|
|
318
|
+
}
|
|
319
|
+
});
|
|
320
|
+
|
|
321
|
+
test("Context Mode composer: narrow planning guidance steers only to contracted tools", () => {
|
|
322
|
+
const cases = [
|
|
323
|
+
{
|
|
324
|
+
unitType: "replan-slice",
|
|
325
|
+
expectedTools: ["gsd_replan_slice", "gsd_decision_save"],
|
|
326
|
+
},
|
|
327
|
+
{
|
|
328
|
+
unitType: "reassess-roadmap",
|
|
329
|
+
expectedTools: ["gsd_milestone_status", "gsd_reassess_roadmap"],
|
|
330
|
+
},
|
|
331
|
+
];
|
|
332
|
+
const disallowedTools = ["gsd_exec", "gsd_exec_search", "gsd_resume"];
|
|
333
|
+
|
|
334
|
+
for (const { unitType, expectedTools } of cases) {
|
|
335
|
+
for (const renderMode of ["nested", "standalone"] as const) {
|
|
336
|
+
const out = composeContextModeInstructions(unitType, { enabled: true, renderMode });
|
|
337
|
+
assert.match(out, /planning lane/i, `${unitType} should still render planning lane guidance`);
|
|
338
|
+
for (const toolName of expectedTools) {
|
|
339
|
+
assert.ok(out.includes(`\`${toolName}\``), `${unitType} guidance should mention ${toolName}`);
|
|
340
|
+
}
|
|
341
|
+
for (const toolName of disallowedTools) {
|
|
342
|
+
assert.ok(!out.includes(`\`${toolName}\``), `${unitType} guidance must not mention ${toolName}`);
|
|
343
|
+
}
|
|
344
|
+
}
|
|
345
|
+
}
|
|
346
|
+
});
|
|
347
|
+
|
|
348
|
+
test("Context Mode composer: lane guidance tools pass unit contracts", () => {
|
|
349
|
+
const affectedUnits = [
|
|
350
|
+
"research-milestone",
|
|
351
|
+
"research-slice",
|
|
352
|
+
"plan-slice",
|
|
353
|
+
"refine-slice",
|
|
354
|
+
"complete-slice",
|
|
355
|
+
"validate-milestone",
|
|
356
|
+
"complete-milestone",
|
|
357
|
+
];
|
|
200
358
|
const contextModeTools: UnitGsdToolName[] = ["gsd_exec", "gsd_exec_search", "gsd_resume"];
|
|
201
359
|
const readOnlyOrientationTools: UnitGsdToolName[] = ["gsd_milestone_status", ...contextModeTools];
|
|
202
360
|
|
|
@@ -207,7 +365,10 @@ test("Context Mode composer: slice planning and research guidance tools pass uni
|
|
|
207
365
|
for (const toolName of contextModeTools) {
|
|
208
366
|
assert.ok(out.includes(`\`${toolName}\``), `${unitType} guidance should mention ${toolName}`);
|
|
209
367
|
}
|
|
210
|
-
|
|
368
|
+
const expectedContractTools = unitType === "research-milestone"
|
|
369
|
+
? contextModeTools
|
|
370
|
+
: readOnlyOrientationTools;
|
|
371
|
+
for (const toolName of expectedContractTools) {
|
|
211
372
|
assert.ok(allowed.has(toolName), `${unitType} contract should allow ${toolName}`);
|
|
212
373
|
const scope = shouldBlockAutoUnitToolCall(unitType, toolName);
|
|
213
374
|
assert.equal(scope.block, false, `${unitType} should not hard-block ${toolName}: ${scope.reason ?? ""}`);
|
|
@@ -357,13 +518,31 @@ test("#4782 phase 2: buildReassessRoadmapPrompt emits composer-shaped context wi
|
|
|
357
518
|
assert.ok(!prompt.includes("Slice Context (from discussion)"));
|
|
358
519
|
});
|
|
359
520
|
|
|
360
|
-
test("execute-task prompt
|
|
521
|
+
test("execute-task prompt omits on-demand slice research when the artifact is absent", async (t) => {
|
|
522
|
+
const base = makeFixtureBase();
|
|
523
|
+
t.after(() => cleanup(base));
|
|
524
|
+
invalidateAllCaches();
|
|
525
|
+
|
|
526
|
+
seed(base, "M001");
|
|
527
|
+
writeArtifacts(base);
|
|
528
|
+
|
|
529
|
+
const prompt = await buildExecuteTaskPrompt("M001", "S01", "First", "T01", "Task", base);
|
|
530
|
+
|
|
531
|
+
assert.doesNotMatch(prompt, /## On-demand Context/);
|
|
532
|
+
assert.doesNotMatch(prompt, /\.gsd\/milestones\/M001\/slices\/S01\/S01-RESEARCH\.md/);
|
|
533
|
+
});
|
|
534
|
+
|
|
535
|
+
test("execute-task prompt surfaces on-demand slice research when the artifact exists", async (t) => {
|
|
361
536
|
const base = makeFixtureBase();
|
|
362
537
|
t.after(() => cleanup(base));
|
|
363
538
|
invalidateAllCaches();
|
|
364
539
|
|
|
365
540
|
seed(base, "M001");
|
|
366
541
|
writeArtifacts(base);
|
|
542
|
+
writeFileSync(
|
|
543
|
+
join(base, ".gsd", "milestones", "M001", "slices", "S01", "S01-RESEARCH.md"),
|
|
544
|
+
"# S01 Research\n",
|
|
545
|
+
);
|
|
367
546
|
|
|
368
547
|
const prompt = await buildExecuteTaskPrompt("M001", "S01", "First", "T01", "Task", base);
|
|
369
548
|
|
|
@@ -127,6 +127,31 @@ test("formatUnmergedMilestoneBlockMessage includes files, branch, and dirty over
|
|
|
127
127
|
}
|
|
128
128
|
});
|
|
129
129
|
|
|
130
|
+
test("findUnmergedCompletedMilestones reports dirty overlap without content fingerprints", async () => {
|
|
131
|
+
const base = makeTempRepo("gsd-unmerged-guard-");
|
|
132
|
+
try {
|
|
133
|
+
const relPath = "build/output.bin";
|
|
134
|
+
const absPath = join(base, relPath);
|
|
135
|
+
mkdirSync(dirname(absPath), { recursive: true });
|
|
136
|
+
writeFileSync(absPath, "main artifact\n");
|
|
137
|
+
git(base, "add", relPath);
|
|
138
|
+
git(base, "commit", "-m", "test: track build output fixture");
|
|
139
|
+
|
|
140
|
+
seedMilestone(base, "M012");
|
|
141
|
+
commitBranchFile(base, "milestone/M012", relPath, "milestone artifact\n");
|
|
142
|
+
writeFileSync(absPath, "dirty root artifact\n");
|
|
143
|
+
|
|
144
|
+
const [blocker] = await findUnmergedCompletedMilestones(base);
|
|
145
|
+
assert.ok(blocker);
|
|
146
|
+
assert.deepEqual(blocker.files, [relPath]);
|
|
147
|
+
assert.deepEqual(blocker.dirtyOverlap, [{ path: relPath, status: "M" }]);
|
|
148
|
+
assert.equal(Object.hasOwn(blocker.dirtyOverlap[0], "fingerprint"), false);
|
|
149
|
+
} finally {
|
|
150
|
+
closeDatabase();
|
|
151
|
+
cleanup(base);
|
|
152
|
+
}
|
|
153
|
+
});
|
|
154
|
+
|
|
130
155
|
test("isUnmergedMilestoneAllowedCommand permits inspection and explicit recovery commands", () => {
|
|
131
156
|
assert.equal(isUnmergedMilestoneAllowedCommand(""), false);
|
|
132
157
|
assert.equal(isUnmergedMilestoneAllowedCommand("auto"), false);
|
|
@@ -3,13 +3,28 @@
|
|
|
3
3
|
|
|
4
4
|
import test from "node:test";
|
|
5
5
|
import assert from "node:assert/strict";
|
|
6
|
+
import { createRequire } from "node:module";
|
|
7
|
+
import { mkdirSync } from "node:fs";
|
|
8
|
+
import { join } from "node:path";
|
|
9
|
+
|
|
10
|
+
const _require = createRequire(import.meta.url);
|
|
6
11
|
|
|
7
12
|
import {
|
|
8
13
|
formatValidationBlockedMessage,
|
|
14
|
+
getValidationBlockMessageForBase,
|
|
9
15
|
isValidationBlockAllowedCommand,
|
|
10
16
|
isValidationBlockedState,
|
|
11
17
|
} from "../validation-block-guard.ts";
|
|
18
|
+
import {
|
|
19
|
+
_getAdapter,
|
|
20
|
+
closeDatabase,
|
|
21
|
+
insertMilestone,
|
|
22
|
+
insertSlice,
|
|
23
|
+
openDatabase,
|
|
24
|
+
} from "../gsd-db.ts";
|
|
25
|
+
import { invalidateStateCache } from "../state.ts";
|
|
12
26
|
import type { GSDState } from "../types.ts";
|
|
27
|
+
import { cleanup, makeTempDir } from "./test-utils.ts";
|
|
13
28
|
|
|
14
29
|
function blockedState(): GSDState {
|
|
15
30
|
return {
|
|
@@ -38,6 +53,24 @@ function blockedState(): GSDState {
|
|
|
38
53
|
};
|
|
39
54
|
}
|
|
40
55
|
|
|
56
|
+
function makeBase(): string {
|
|
57
|
+
const base = makeTempDir("gsd-validation-block-");
|
|
58
|
+
mkdirSync(join(base, ".gsd"), { recursive: true });
|
|
59
|
+
return base;
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
function openRawSqliteForTest(dbPath: string): { exec(sql: string): void; close(): void } {
|
|
63
|
+
try {
|
|
64
|
+
const mod = _require("node:sqlite") as { DatabaseSync: new (path: string) => { exec(sql: string): void; close(): void } };
|
|
65
|
+
return new mod.DatabaseSync(dbPath);
|
|
66
|
+
} catch {
|
|
67
|
+
type SqliteCtor = new (path: string) => { exec(sql: string): void; close(): void };
|
|
68
|
+
const mod = _require("better-sqlite3") as SqliteCtor | { default: SqliteCtor };
|
|
69
|
+
const DatabaseCtor: SqliteCtor = typeof mod === "function" ? mod : mod.default;
|
|
70
|
+
return new DatabaseCtor(dbPath);
|
|
71
|
+
}
|
|
72
|
+
}
|
|
73
|
+
|
|
41
74
|
test("validation block detection only matches validation blockers", () => {
|
|
42
75
|
assert.equal(isValidationBlockedState(blockedState()), true);
|
|
43
76
|
assert.equal(isValidationBlockedState({
|
|
@@ -194,3 +227,49 @@ test("validation block message can guide remediation through dispatch reassess",
|
|
|
194
227
|
assert.match(message, /\/gsd dispatch reassess/);
|
|
195
228
|
assert.doesNotMatch(message, /gsd_reassess_roadmap/);
|
|
196
229
|
});
|
|
230
|
+
|
|
231
|
+
test("validation block guard refreshes from disk and sees external validation blocks", async () => {
|
|
232
|
+
const base = makeBase();
|
|
233
|
+
const dbPath = join(base, ".gsd", "gsd.db");
|
|
234
|
+
const validationPath = join(base, ".gsd", "milestones", "M001", "M001-VALIDATION.md");
|
|
235
|
+
try {
|
|
236
|
+
openDatabase(dbPath);
|
|
237
|
+
insertMilestone({ id: "M001", title: "Active Milestone", status: "active" });
|
|
238
|
+
insertSlice({
|
|
239
|
+
id: "S01",
|
|
240
|
+
milestoneId: "M001",
|
|
241
|
+
title: "Done Slice",
|
|
242
|
+
status: "complete",
|
|
243
|
+
risk: "low",
|
|
244
|
+
depends: [],
|
|
245
|
+
});
|
|
246
|
+
invalidateStateCache();
|
|
247
|
+
|
|
248
|
+
const adapterBefore = _getAdapter();
|
|
249
|
+
assert.ok(adapterBefore);
|
|
250
|
+
|
|
251
|
+
const externalDb = openRawSqliteForTest(dbPath);
|
|
252
|
+
try {
|
|
253
|
+
externalDb.exec(`
|
|
254
|
+
INSERT OR REPLACE INTO assessments (path, milestone_id, slice_id, task_id, status, scope, full_content, created_at)
|
|
255
|
+
VALUES (
|
|
256
|
+
'${validationPath.replace(/'/g, "''")}',
|
|
257
|
+
'M001', NULL, NULL, 'needs-attention', 'milestone-validation',
|
|
258
|
+
'---\nverdict: needs-attention\n---', datetime('now')
|
|
259
|
+
)
|
|
260
|
+
`);
|
|
261
|
+
} finally {
|
|
262
|
+
externalDb.close();
|
|
263
|
+
}
|
|
264
|
+
|
|
265
|
+
const message = await getValidationBlockMessageForBase(base, "next");
|
|
266
|
+
|
|
267
|
+
assert.ok(message);
|
|
268
|
+
assert.match(message, /cannot run because the active milestone is blocked by validation/);
|
|
269
|
+
assert.notEqual(_getAdapter(), adapterBefore, "guard must refresh stale database handle");
|
|
270
|
+
} finally {
|
|
271
|
+
closeDatabase();
|
|
272
|
+
invalidateStateCache();
|
|
273
|
+
cleanup(base);
|
|
274
|
+
}
|
|
275
|
+
});
|
|
@@ -11,6 +11,8 @@ import {
|
|
|
11
11
|
verificationRetryKey,
|
|
12
12
|
VERIFICATION_RETRY_MAX_DELAY_MS,
|
|
13
13
|
} from "../auto/verification-retry-policy.ts";
|
|
14
|
+
import { formatFailureContext, formatFailureSignature } from "../verification-gate.ts";
|
|
15
|
+
import type { VerificationResult } from "../types.ts";
|
|
14
16
|
|
|
15
17
|
test("verificationRetryDelayMs uses exponential backoff with cap", () => {
|
|
16
18
|
assert.deepEqual(verificationRetryDelayMs(1, () => 0.5), {
|
|
@@ -31,9 +33,22 @@ test("verificationRetryDelayMs uses exponential backoff with cap", () => {
|
|
|
31
33
|
});
|
|
32
34
|
});
|
|
33
35
|
|
|
34
|
-
test("decideVerificationRetry pauses on
|
|
36
|
+
test("decideVerificationRetry pauses on repeated failure context across attempts", () => {
|
|
35
37
|
const failureContext = "lint failed\n";
|
|
36
|
-
const
|
|
38
|
+
const firstDecision = decideVerificationRetry({
|
|
39
|
+
unitType: "execute-task",
|
|
40
|
+
retryInfo: {
|
|
41
|
+
unitId: "M001/S01/T01",
|
|
42
|
+
failureContext,
|
|
43
|
+
attempt: 1,
|
|
44
|
+
},
|
|
45
|
+
previousFailureHash: undefined,
|
|
46
|
+
random: () => 0.5,
|
|
47
|
+
});
|
|
48
|
+
|
|
49
|
+
assert.equal(firstDecision.action, "delay");
|
|
50
|
+
assert.equal(firstDecision.failureHash, hashVerificationFailureContext(failureContext));
|
|
51
|
+
|
|
37
52
|
const decision = decideVerificationRetry({
|
|
38
53
|
unitType: "execute-task",
|
|
39
54
|
retryInfo: {
|
|
@@ -41,7 +56,7 @@ test("decideVerificationRetry pauses on duplicate failure context", () => {
|
|
|
41
56
|
failureContext,
|
|
42
57
|
attempt: 2,
|
|
43
58
|
},
|
|
44
|
-
previousFailureHash: failureHash,
|
|
59
|
+
previousFailureHash: firstDecision.failureHash,
|
|
45
60
|
random: () => 0.5,
|
|
46
61
|
});
|
|
47
62
|
|
|
@@ -49,7 +64,7 @@ test("decideVerificationRetry pauses on duplicate failure context", () => {
|
|
|
49
64
|
action: "pause",
|
|
50
65
|
reason: "duplicate-failure-context",
|
|
51
66
|
key: verificationRetryKey("execute-task", "M001/S01/T01"),
|
|
52
|
-
failureHash,
|
|
67
|
+
failureHash: firstDecision.failureHash,
|
|
53
68
|
});
|
|
54
69
|
});
|
|
55
70
|
|
|
@@ -71,6 +86,56 @@ test("decideVerificationRetry delays changed failure context", () => {
|
|
|
71
86
|
assert.equal(decision.baseDelayMs, 4_000);
|
|
72
87
|
});
|
|
73
88
|
|
|
89
|
+
test("decideVerificationRetry pauses duplicate host-check failures with volatile stderr", () => {
|
|
90
|
+
const makeResult = (stderr: string): VerificationResult => ({
|
|
91
|
+
passed: false,
|
|
92
|
+
discoverySource: "package-json",
|
|
93
|
+
timestamp: Date.now(),
|
|
94
|
+
checks: [
|
|
95
|
+
{
|
|
96
|
+
command: "npm test",
|
|
97
|
+
exitCode: 1,
|
|
98
|
+
stdout: "",
|
|
99
|
+
stderr,
|
|
100
|
+
durationMs: 100,
|
|
101
|
+
},
|
|
102
|
+
],
|
|
103
|
+
});
|
|
104
|
+
const first = makeResult("failed after 120ms in /tmp/gsd-a worker pid 101");
|
|
105
|
+
const second = makeResult("failed after 133ms in /tmp/gsd-b worker pid 202");
|
|
106
|
+
const firstContext = formatFailureContext(first);
|
|
107
|
+
const secondContext = formatFailureContext(second);
|
|
108
|
+
|
|
109
|
+
assert.notEqual(
|
|
110
|
+
hashVerificationFailureContext(firstContext),
|
|
111
|
+
hashVerificationFailureContext(secondContext),
|
|
112
|
+
);
|
|
113
|
+
|
|
114
|
+
const signature = formatFailureSignature(first);
|
|
115
|
+
assert.equal(signature, "npm test#1");
|
|
116
|
+
assert.equal(formatFailureSignature(second), signature);
|
|
117
|
+
|
|
118
|
+
const failureHash = hashVerificationFailureContext(signature);
|
|
119
|
+
const decision = decideVerificationRetry({
|
|
120
|
+
unitType: "execute-task",
|
|
121
|
+
retryInfo: {
|
|
122
|
+
unitId: "M001/S01/T01",
|
|
123
|
+
failureContext: secondContext,
|
|
124
|
+
signature: formatFailureSignature(second),
|
|
125
|
+
attempt: 2,
|
|
126
|
+
},
|
|
127
|
+
previousFailureHash: failureHash,
|
|
128
|
+
random: () => 0.5,
|
|
129
|
+
});
|
|
130
|
+
|
|
131
|
+
assert.deepEqual(decision, {
|
|
132
|
+
action: "pause",
|
|
133
|
+
reason: "duplicate-failure-context",
|
|
134
|
+
key: verificationRetryKey("execute-task", "M001/S01/T01"),
|
|
135
|
+
failureHash,
|
|
136
|
+
});
|
|
137
|
+
});
|
|
138
|
+
|
|
74
139
|
test("decideVerificationRetry pauses when retry context is missing", () => {
|
|
75
140
|
assert.deepEqual(
|
|
76
141
|
decideVerificationRetry({
|
|
@@ -292,3 +292,69 @@ test("#852: discuss-milestone fails when CONTEXT is in neither worktree nor proj
|
|
|
292
292
|
rmSync(projectRoot, { recursive: true, force: true });
|
|
293
293
|
}
|
|
294
294
|
});
|
|
295
|
+
|
|
296
|
+
// ---------------------------------------------------------------------------
|
|
297
|
+
// #870: discuss-milestone verify-fail when the unit runs IN the worktree.
|
|
298
|
+
//
|
|
299
|
+
// The #852 tests above all pass `projectRoot` as the base. But the real call
|
|
300
|
+
// site (auto-post-unit.ts:1726) passes `s.currentUnit.workspaceRoot ?? s.basePath`
|
|
301
|
+
// — i.e. the WORKTREE path when the unit executed in a worktree. In the
|
|
302
|
+
// canonical layout (`<root>/.gsd-worktrees/<MID>/`) resolveCanonicalMilestoneRoot
|
|
303
|
+
// round-trips the worktree path back to itself, so `artifactBase === base` and
|
|
304
|
+
// the worktree→project-root fallback (guarded by `artifactBase !== base`) is
|
|
305
|
+
// skipped. CONTEXT is written to the project root, not projected into the
|
|
306
|
+
// worktree, so verification finds nothing → "existsSync false" → re-dispatch
|
|
307
|
+
// 3× → stuck-loop stop. These tests pin the real call site.
|
|
308
|
+
// ---------------------------------------------------------------------------
|
|
309
|
+
|
|
310
|
+
test("#870: discuss-milestone falls back to project root when base IS the canonical-layout worktree", () => {
|
|
311
|
+
closeDatabase();
|
|
312
|
+
const projectRoot = mkdtempSync(join(tmpdir(), "gsd-canonical-wt-"));
|
|
313
|
+
try {
|
|
314
|
+
// CONTEXT lives ONLY at the project root (flat-phase layout).
|
|
315
|
+
const phaseDir = join(projectRoot, ".gsd", "phases", "15-m015");
|
|
316
|
+
mkdirSync(phaseDir, { recursive: true });
|
|
317
|
+
writeFileSync(join(phaseDir, "15-CONTEXT.md"), "# M015 context\n");
|
|
318
|
+
|
|
319
|
+
// Canonical-layout worktree: <root>/.gsd-worktrees/<MID>/. Registered
|
|
320
|
+
// with git (.git file) so resolveCanonicalMilestoneRoot treats it as the
|
|
321
|
+
// canonical milestone root — but it has NO phases/ projection.
|
|
322
|
+
const wtRoot = join(projectRoot, ".gsd-worktrees", "M015");
|
|
323
|
+
mkdirSync(join(wtRoot, ".gsd", "milestones", "M015"), { recursive: true });
|
|
324
|
+
writeFileSync(join(wtRoot, ".gsd", "milestones", "M015", "M015-META.json"), '{"branch":"milestone/M015"}');
|
|
325
|
+
writeFileSync(join(wtRoot, ".git"), "gitdir: /fake/path");
|
|
326
|
+
|
|
327
|
+
// Real call site: base = worktree path (workspaceRoot).
|
|
328
|
+
assert.equal(
|
|
329
|
+
verifyExpectedArtifact("discuss-milestone", "M015", wtRoot),
|
|
330
|
+
true,
|
|
331
|
+
"must fall back to project root when base is the canonical-layout worktree",
|
|
332
|
+
);
|
|
333
|
+
} finally {
|
|
334
|
+
closeDatabase();
|
|
335
|
+
rmSync(projectRoot, { recursive: true, force: true });
|
|
336
|
+
}
|
|
337
|
+
});
|
|
338
|
+
|
|
339
|
+
test("#870: discuss-milestone also falls back when base is the legacy-layout worktree", () => {
|
|
340
|
+
closeDatabase();
|
|
341
|
+
const projectRoot = mkdtempSync(join(tmpdir(), "gsd-legacy-wt-"));
|
|
342
|
+
try {
|
|
343
|
+
const phaseDir = join(projectRoot, ".gsd", "phases", "15-m015");
|
|
344
|
+
mkdirSync(phaseDir, { recursive: true });
|
|
345
|
+
writeFileSync(join(phaseDir, "15-CONTEXT.md"), "# M015 context\n");
|
|
346
|
+
|
|
347
|
+
const wtRoot = join(projectRoot, ".gsd", "worktrees", "M015");
|
|
348
|
+
mkdirSync(join(wtRoot, ".gsd", "milestones", "M015"), { recursive: true });
|
|
349
|
+
writeFileSync(join(wtRoot, ".git"), "gitdir: /fake/path");
|
|
350
|
+
|
|
351
|
+
assert.equal(
|
|
352
|
+
verifyExpectedArtifact("discuss-milestone", "M015", wtRoot),
|
|
353
|
+
true,
|
|
354
|
+
"must fall back to project root when base is the legacy-layout worktree",
|
|
355
|
+
);
|
|
356
|
+
} finally {
|
|
357
|
+
closeDatabase();
|
|
358
|
+
rmSync(projectRoot, { recursive: true, force: true });
|
|
359
|
+
}
|
|
360
|
+
});
|
|
@@ -380,6 +380,60 @@ test('workflow-manifest: bootstrapFromManifest preserves target_repositories', (
|
|
|
380
380
|
}
|
|
381
381
|
});
|
|
382
382
|
|
|
383
|
+
test('workflow-manifest: bootstrapFromManifest does not truncate projections when artifact content is empty', () => {
|
|
384
|
+
const base = tempDir();
|
|
385
|
+
openDatabase(tempDbPath(base));
|
|
386
|
+
try {
|
|
387
|
+
insertMilestone({ id: 'M001', title: 'Projection Milestone' });
|
|
388
|
+
insertArtifact({
|
|
389
|
+
path: '.gsd/milestones/M001/M001-PLAN.md',
|
|
390
|
+
artifact_type: 'PLAN',
|
|
391
|
+
milestone_id: 'M001',
|
|
392
|
+
slice_id: null,
|
|
393
|
+
task_id: null,
|
|
394
|
+
full_content: '# Manifest Plan',
|
|
395
|
+
});
|
|
396
|
+
insertArtifact({
|
|
397
|
+
path: '.gsd/milestones/M001/M001-VALIDATION.md',
|
|
398
|
+
artifact_type: 'VALIDATION',
|
|
399
|
+
milestone_id: 'M001',
|
|
400
|
+
slice_id: null,
|
|
401
|
+
task_id: null,
|
|
402
|
+
full_content: '# Manifest Validation',
|
|
403
|
+
});
|
|
404
|
+
writeManifest(base);
|
|
405
|
+
|
|
406
|
+
const planPath = path.join(base, '.gsd', 'milestones', 'M001', 'M001-PLAN.md');
|
|
407
|
+
const validationPath = path.join(base, '.gsd', 'milestones', 'M001', 'M001-VALIDATION.md');
|
|
408
|
+
fs.mkdirSync(path.dirname(planPath), { recursive: true });
|
|
409
|
+
fs.writeFileSync(planPath, '# Existing Plan\n\nKeep this.');
|
|
410
|
+
fs.writeFileSync(validationPath, '# Existing Validation\n\nKeep this.');
|
|
411
|
+
|
|
412
|
+
const manifestPath = path.join(base, '.gsd', 'state-manifest.json');
|
|
413
|
+
const manifest = JSON.parse(fs.readFileSync(manifestPath, 'utf8')) as Record<string, unknown>;
|
|
414
|
+
const artifacts = manifest['artifacts'] as Array<Record<string, unknown>>;
|
|
415
|
+
const emptyArtifact = artifacts.find((r) => r['path'] === '.gsd/milestones/M001/M001-PLAN.md');
|
|
416
|
+
const absentArtifact = artifacts.find((r) => r['path'] === '.gsd/milestones/M001/M001-VALIDATION.md');
|
|
417
|
+
assert.ok(emptyArtifact !== undefined);
|
|
418
|
+
assert.ok(absentArtifact !== undefined);
|
|
419
|
+
emptyArtifact['full_content'] = '';
|
|
420
|
+
delete absentArtifact['full_content'];
|
|
421
|
+
fs.writeFileSync(manifestPath, JSON.stringify(manifest, null, 2));
|
|
422
|
+
closeDatabase();
|
|
423
|
+
|
|
424
|
+
const newDbPath = path.join(base, 'new.db');
|
|
425
|
+
openDatabase(newDbPath);
|
|
426
|
+
const restored = bootstrapFromManifest(base);
|
|
427
|
+
assert.strictEqual(restored, true);
|
|
428
|
+
|
|
429
|
+
assert.strictEqual(fs.readFileSync(planPath, 'utf-8'), '# Existing Plan\n\nKeep this.');
|
|
430
|
+
assert.strictEqual(fs.readFileSync(validationPath, 'utf-8'), '# Existing Validation\n\nKeep this.');
|
|
431
|
+
} finally {
|
|
432
|
+
closeDatabase();
|
|
433
|
+
cleanupDir(base);
|
|
434
|
+
}
|
|
435
|
+
});
|
|
436
|
+
|
|
383
437
|
test('workflow-manifest: bootstrapFromManifest preserves optional rows from old manifests', () => {
|
|
384
438
|
const base = tempDir();
|
|
385
439
|
openDatabase(tempDbPath(base));
|