gsd-pi 2.81.0-dev.72a81bdf3 → 2.82.0-dev.20138ae42
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 +50 -31
- package/dist/resources/.managed-resources-content-hash +1 -1
- package/dist/resources/GSD-WORKFLOW.md +10 -1
- package/dist/resources/extensions/browser-tools/tools/screenshot.js +1 -0
- package/dist/resources/extensions/browser-tools/tools/zoom.js +1 -0
- package/dist/resources/extensions/claude-code-cli/partial-builder.js +2 -1
- package/dist/resources/extensions/cmux/index.js +5 -0
- package/dist/resources/extensions/gsd/auto/infra-errors.js +9 -3
- package/dist/resources/extensions/gsd/auto/loop.js +5 -5
- package/dist/resources/extensions/gsd/auto/orchestrator.js +124 -6
- package/dist/resources/extensions/gsd/auto/phases.js +30 -1
- package/dist/resources/extensions/gsd/auto/workflow-memory-pressure.js +12 -0
- package/dist/resources/extensions/gsd/auto-dashboard.js +66 -1
- package/dist/resources/extensions/gsd/auto-dispatch.js +13 -6
- package/dist/resources/extensions/gsd/auto-model-selection.js +2 -0
- package/dist/resources/extensions/gsd/auto-post-unit.js +233 -127
- package/dist/resources/extensions/gsd/auto-prompts.js +13 -5
- package/dist/resources/extensions/gsd/auto-recovery.js +31 -1
- package/dist/resources/extensions/gsd/auto-start.js +85 -12
- package/dist/resources/extensions/gsd/auto-verification.js +28 -22
- package/dist/resources/extensions/gsd/auto-worktree.js +111 -1
- package/dist/resources/extensions/gsd/auto.js +158 -55
- package/dist/resources/extensions/gsd/bootstrap/agent-end-recovery.js +25 -6
- package/dist/resources/extensions/gsd/bootstrap/db-tools.js +9 -8
- package/dist/resources/extensions/gsd/bootstrap/register-hooks.js +9 -2
- package/dist/resources/extensions/gsd/bootstrap/subagent-input.js +21 -9
- package/dist/resources/extensions/gsd/bootstrap/system-context.js +55 -12
- package/dist/resources/extensions/gsd/bootstrap/write-gate.js +16 -2
- package/dist/resources/extensions/gsd/clean-root-preflight.js +170 -8
- package/dist/resources/extensions/gsd/commands/catalog.js +4 -1
- package/dist/resources/extensions/gsd/commands/handlers/core.js +38 -1
- package/dist/resources/extensions/gsd/commands-bootstrap.js +5 -0
- package/dist/resources/extensions/gsd/commands-handlers.js +15 -2
- package/dist/resources/extensions/gsd/context-store.js +112 -0
- package/dist/resources/extensions/gsd/crash-recovery.js +31 -5
- package/dist/resources/extensions/gsd/db/unit-dispatches.js +3 -2
- package/dist/resources/extensions/gsd/db-writer.js +150 -84
- package/dist/resources/extensions/gsd/dispatch-guard.js +2 -2
- package/dist/resources/extensions/gsd/docs/preferences-reference.md +1 -1
- package/dist/resources/extensions/gsd/doctor-git-checks.js +41 -6
- package/dist/resources/extensions/gsd/doctor-runtime-checks.js +28 -11
- package/dist/resources/extensions/gsd/doctor.js +2 -28
- package/dist/resources/extensions/gsd/export-html.js +27 -425
- package/dist/resources/extensions/gsd/git-service.js +39 -1
- package/dist/resources/extensions/gsd/gsd-db.js +1 -0
- package/dist/resources/extensions/gsd/guided-flow.js +93 -111
- package/dist/resources/extensions/gsd/guided-unit-context.js +23 -0
- package/dist/resources/extensions/gsd/knowledge-backfill.js +144 -0
- package/dist/resources/extensions/gsd/knowledge-capture.js +136 -0
- package/dist/resources/extensions/gsd/knowledge-parser.js +154 -0
- package/dist/resources/extensions/gsd/knowledge-projection.js +210 -0
- package/dist/resources/extensions/gsd/markdown-renderer.js +6 -1
- package/dist/resources/extensions/gsd/md-importer.js +1 -1
- package/dist/resources/extensions/gsd/memory-backfill.js +73 -17
- package/dist/resources/extensions/gsd/memory-consolidation-scanner.js +222 -0
- package/dist/resources/extensions/gsd/migrate/command.js +5 -0
- package/dist/resources/extensions/gsd/migrate/parsers.js +10 -0
- package/dist/resources/extensions/gsd/migrate/preview.js +9 -0
- package/dist/resources/extensions/gsd/migrate/transformer.js +51 -4
- package/dist/resources/extensions/gsd/migrate/writer.js +11 -1
- package/dist/resources/extensions/gsd/migration-auto-check.js +12 -17
- package/dist/resources/extensions/gsd/milestone-actions.js +11 -4
- package/dist/resources/extensions/gsd/native-git-bridge.js +48 -12
- package/dist/resources/extensions/gsd/pending-auto-start.js +52 -0
- package/dist/resources/extensions/gsd/post-execution-checks.js +73 -2
- package/dist/resources/extensions/gsd/pre-execution-checks.js +28 -1
- package/dist/resources/extensions/gsd/prompt-loader.js +1 -1
- package/dist/resources/extensions/gsd/prompts/complete-milestone.md +1 -1
- package/dist/resources/extensions/gsd/prompts/complete-slice.md +1 -1
- package/dist/resources/extensions/gsd/prompts/discuss-headless.md +8 -8
- package/dist/resources/extensions/gsd/prompts/discuss.md +9 -9
- package/dist/resources/extensions/gsd/prompts/guided-discuss-project.md +4 -4
- package/dist/resources/extensions/gsd/prompts/guided-discuss-requirements.md +3 -3
- package/dist/resources/extensions/gsd/prompts/plan-slice.md +4 -4
- package/dist/resources/extensions/gsd/prompts/queue.md +4 -4
- package/dist/resources/extensions/gsd/prompts/refine-slice.md +2 -2
- package/dist/resources/extensions/gsd/prompts/rewrite-docs.md +1 -1
- package/dist/resources/extensions/gsd/prompts/system.md +2 -2
- package/dist/resources/extensions/gsd/provider-switch-observer.js +146 -0
- package/dist/resources/extensions/gsd/smart-entry-routing.js +36 -0
- package/dist/resources/extensions/gsd/state-reconciliation/drift/merge-state.js +6 -1
- package/dist/resources/extensions/gsd/state-reconciliation/drift/project-md.js +9 -14
- package/dist/resources/extensions/gsd/state-reconciliation/drift/roadmap.js +19 -24
- package/dist/resources/extensions/gsd/status-guards.js +4 -0
- package/dist/resources/extensions/gsd/templates/knowledge.md +2 -2
- package/dist/resources/extensions/gsd/templates/plan.md +8 -5
- package/dist/resources/extensions/gsd/templates/task-plan.md +4 -2
- package/dist/resources/extensions/gsd/tools/complete-milestone.js +6 -8
- package/dist/resources/extensions/gsd/tools/complete-slice.js +6 -8
- package/dist/resources/extensions/gsd/tools/plan-milestone.js +7 -1
- package/dist/resources/extensions/gsd/tools/plan-slice.js +89 -14
- package/dist/resources/extensions/gsd/tools/workflow-tool-executors.js +119 -0
- package/dist/resources/extensions/gsd/unit-context-manifest.js +32 -10
- package/dist/resources/extensions/gsd/validation.js +23 -1
- package/dist/resources/extensions/gsd/verification-gate.js +68 -7
- package/dist/resources/extensions/gsd/verification-verdict.js +26 -0
- package/dist/resources/extensions/gsd/workflow-projections.js +6 -8
- package/dist/resources/extensions/gsd/worktree-lifecycle.js +54 -10
- package/dist/resources/extensions/shared/html-shell.js +388 -0
- package/dist/resources/extensions/subagent/index.js +448 -78
- package/dist/resources/extensions/subagent/launch.js +77 -0
- package/dist/resources/extensions/subagent/run-store.js +148 -0
- package/dist/resources/extensions/visual-brief/artifact-policy.js +29 -0
- package/dist/resources/extensions/visual-brief/extension-manifest.json +8 -0
- package/dist/resources/extensions/visual-brief/index.js +5 -0
- package/dist/resources/extensions/visual-brief/page-contract.js +124 -0
- package/dist/resources/extensions/visual-brief/prompts.js +140 -0
- 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 +3 -3
- 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.js +2 -2
- package/dist/web/standalone/.next/server/app/_not-found/page.js.nft.json +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 +4 -7
- package/dist/web/standalone/.next/server/app/_not-found.segments/_full.segment.rsc +4 -7
- 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 +4 -5
- 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 +2 -5
- package/dist/web/standalone/.next/server/app/api/git/route.js +1 -1
- package/dist/web/standalone/.next/server/app/index.html +1 -1
- package/dist/web/standalone/.next/server/app/index.rsc +4 -7
- package/dist/web/standalone/.next/server/app/index.segments/__PAGE__.segment.rsc +1 -1
- package/dist/web/standalone/.next/server/app/index.segments/_full.segment.rsc +4 -7
- 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 +4 -5
- package/dist/web/standalone/.next/server/app/index.segments/_tree.segment.rsc +2 -5
- package/dist/web/standalone/.next/server/app/page.js +2 -2
- package/dist/web/standalone/.next/server/app/page.js.nft.json +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/chunks/4266.js +2 -0
- 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/next-font-manifest.js +1 -1
- package/dist/web/standalone/.next/server/next-font-manifest.json +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/2973.33f26573894b6153.js +2 -0
- package/dist/web/standalone/.next/static/chunks/{8359.e059d86b255fce1c.js → 8359.7eb3bb8f8ecf4c01.js} +2 -2
- package/dist/web/standalone/.next/static/chunks/app/layout-8c10ec293ae0f1d5.js +1 -0
- package/dist/web/standalone/.next/static/chunks/{webpack-de742b64187e13fe.js → webpack-9a4db269f9ed63ad.js} +1 -1
- package/dist/web/standalone/.next/static/css/746ee28c929d1880.css +1 -0
- package/package.json +6 -5
- package/packages/contracts/dist/rpc.test.js +7 -0
- package/packages/contracts/dist/rpc.test.js.map +1 -1
- package/packages/contracts/dist/workflow.d.ts +21 -0
- package/packages/contracts/dist/workflow.d.ts.map +1 -1
- package/packages/contracts/dist/workflow.js +24 -0
- package/packages/contracts/dist/workflow.js.map +1 -1
- package/packages/contracts/src/rpc.test.ts +8 -0
- package/packages/contracts/src/workflow.ts +24 -0
- package/packages/daemon/package.json +2 -2
- package/packages/mcp-server/README.md +14 -3
- package/packages/mcp-server/dist/workflow-tools.d.ts +0 -3
- package/packages/mcp-server/dist/workflow-tools.d.ts.map +1 -1
- package/packages/mcp-server/dist/workflow-tools.js +80 -0
- package/packages/mcp-server/dist/workflow-tools.js.map +1 -1
- package/packages/mcp-server/package.json +2 -2
- package/packages/mcp-server/src/workflow-tools-parity.test.ts +244 -0
- package/packages/mcp-server/src/workflow-tools.test.ts +23 -1
- package/packages/mcp-server/src/workflow-tools.ts +168 -0
- package/packages/mcp-server/tsconfig.tsbuildinfo +1 -1
- package/packages/native/package.json +1 -1
- package/packages/native/tsconfig.json +2 -1
- package/packages/native/tsconfig.tsbuildinfo +1 -1
- package/packages/pi-agent-core/package.json +1 -1
- package/packages/pi-agent-core/tsconfig.tsbuildinfo +1 -1
- package/packages/pi-ai/dist/index.d.ts +2 -2
- package/packages/pi-ai/dist/index.d.ts.map +1 -1
- package/packages/pi-ai/dist/index.js +1 -1
- package/packages/pi-ai/dist/index.js.map +1 -1
- package/packages/pi-ai/dist/providers/openai-codex-responses.d.ts.map +1 -1
- package/packages/pi-ai/dist/providers/openai-codex-responses.js +82 -1
- package/packages/pi-ai/dist/providers/openai-codex-responses.js.map +1 -1
- package/packages/pi-ai/dist/providers/openai-codex-responses.test.d.ts +2 -0
- package/packages/pi-ai/dist/providers/openai-codex-responses.test.d.ts.map +1 -0
- package/packages/pi-ai/dist/providers/openai-codex-responses.test.js +52 -0
- package/packages/pi-ai/dist/providers/openai-codex-responses.test.js.map +1 -0
- package/packages/pi-ai/dist/providers/simple-options.d.ts +2 -4
- package/packages/pi-ai/dist/providers/simple-options.d.ts.map +1 -1
- package/packages/pi-ai/dist/providers/simple-options.js +5 -6
- package/packages/pi-ai/dist/providers/simple-options.js.map +1 -1
- package/packages/pi-ai/dist/providers/simple-options.test.d.ts +2 -0
- package/packages/pi-ai/dist/providers/simple-options.test.d.ts.map +1 -0
- package/packages/pi-ai/dist/providers/simple-options.test.js +50 -0
- package/packages/pi-ai/dist/providers/simple-options.test.js.map +1 -0
- package/packages/pi-ai/dist/providers/transform-messages.d.ts +11 -0
- package/packages/pi-ai/dist/providers/transform-messages.d.ts.map +1 -1
- package/packages/pi-ai/dist/providers/transform-messages.js +20 -0
- package/packages/pi-ai/dist/providers/transform-messages.js.map +1 -1
- package/packages/pi-ai/package.json +1 -1
- package/packages/pi-ai/src/index.ts +7 -2
- package/packages/pi-ai/src/providers/openai-codex-responses.test.ts +63 -0
- package/packages/pi-ai/src/providers/openai-codex-responses.ts +91 -1
- package/packages/pi-ai/src/providers/simple-options.test.ts +60 -0
- package/packages/pi-ai/src/providers/simple-options.ts +5 -6
- package/packages/pi-ai/src/providers/transform-messages.ts +24 -0
- package/packages/pi-ai/tsconfig.tsbuildinfo +1 -1
- package/packages/pi-coding-agent/dist/core/agent-session-thinking-level.test.d.ts +2 -0
- package/packages/pi-coding-agent/dist/core/agent-session-thinking-level.test.d.ts.map +1 -0
- package/packages/pi-coding-agent/dist/core/agent-session-thinking-level.test.js +66 -0
- package/packages/pi-coding-agent/dist/core/agent-session-thinking-level.test.js.map +1 -0
- package/packages/pi-coding-agent/dist/core/agent-session.js +1 -1
- package/packages/pi-coding-agent/dist/core/agent-session.js.map +1 -1
- package/packages/pi-coding-agent/dist/core/system-prompt.js +4 -4
- package/packages/pi-coding-agent/dist/core/system-prompt.js.map +1 -1
- package/packages/pi-coding-agent/dist/modes/interactive/components/footer.d.ts.map +1 -1
- package/packages/pi-coding-agent/dist/modes/interactive/components/footer.js +24 -6
- package/packages/pi-coding-agent/dist/modes/interactive/components/footer.js.map +1 -1
- package/packages/pi-coding-agent/dist/tests/system-prompt-file-safety.test.d.ts +2 -0
- package/packages/pi-coding-agent/dist/tests/system-prompt-file-safety.test.d.ts.map +1 -0
- package/packages/pi-coding-agent/dist/tests/system-prompt-file-safety.test.js +17 -0
- package/packages/pi-coding-agent/dist/tests/system-prompt-file-safety.test.js.map +1 -0
- package/packages/pi-coding-agent/package.json +1 -1
- package/packages/pi-coding-agent/src/core/agent-session-thinking-level.test.ts +79 -0
- package/packages/pi-coding-agent/src/core/agent-session.ts +1 -1
- package/packages/pi-coding-agent/src/core/system-prompt.ts +4 -4
- package/packages/pi-coding-agent/src/modes/interactive/components/footer.ts +23 -7
- package/packages/pi-coding-agent/src/tests/system-prompt-file-safety.test.ts +22 -0
- package/packages/pi-coding-agent/tsconfig.tsbuildinfo +1 -1
- package/packages/pi-tui/dist/tui.d.ts.map +1 -1
- package/packages/pi-tui/dist/tui.js +5 -0
- package/packages/pi-tui/dist/tui.js.map +1 -1
- package/packages/pi-tui/package.json +1 -1
- package/packages/pi-tui/src/tui.ts +6 -0
- package/packages/pi-tui/tsconfig.tsbuildinfo +1 -1
- package/packages/rpc-client/package.json +1 -1
- package/packages/rpc-client/tsconfig.tsbuildinfo +1 -1
- package/pkg/package.json +1 -1
- package/src/resources/GSD-WORKFLOW.md +10 -1
- package/src/resources/extensions/browser-tools/tools/screenshot.ts +1 -0
- package/src/resources/extensions/browser-tools/tools/zoom.ts +1 -0
- package/src/resources/extensions/claude-code-cli/partial-builder.ts +2 -1
- package/src/resources/extensions/claude-code-cli/tests/partial-builder.test.ts +19 -2
- package/src/resources/extensions/cmux/index.ts +6 -0
- package/src/resources/extensions/gsd/auto/contracts.ts +59 -16
- package/src/resources/extensions/gsd/auto/infra-errors.ts +9 -3
- package/src/resources/extensions/gsd/auto/loop.ts +8 -5
- package/src/resources/extensions/gsd/auto/orchestrator.ts +129 -6
- package/src/resources/extensions/gsd/auto/phases.ts +36 -1
- package/src/resources/extensions/gsd/auto/workflow-memory-pressure.ts +13 -0
- package/src/resources/extensions/gsd/auto-dashboard.ts +72 -1
- package/src/resources/extensions/gsd/auto-dispatch.ts +14 -6
- package/src/resources/extensions/gsd/auto-model-selection.ts +2 -1
- package/src/resources/extensions/gsd/auto-post-unit.ts +266 -139
- package/src/resources/extensions/gsd/auto-prompts.ts +13 -5
- package/src/resources/extensions/gsd/auto-recovery.ts +29 -0
- package/src/resources/extensions/gsd/auto-start.ts +92 -9
- package/src/resources/extensions/gsd/auto-verification.ts +36 -34
- package/src/resources/extensions/gsd/auto-worktree.ts +119 -1
- package/src/resources/extensions/gsd/auto.ts +167 -53
- package/src/resources/extensions/gsd/bootstrap/agent-end-recovery.ts +33 -6
- package/src/resources/extensions/gsd/bootstrap/db-tools.ts +9 -8
- package/src/resources/extensions/gsd/bootstrap/register-hooks.ts +10 -2
- package/src/resources/extensions/gsd/bootstrap/subagent-input.ts +19 -7
- package/src/resources/extensions/gsd/bootstrap/system-context.ts +58 -15
- package/src/resources/extensions/gsd/bootstrap/write-gate.ts +19 -3
- package/src/resources/extensions/gsd/clean-root-preflight.ts +174 -8
- package/src/resources/extensions/gsd/commands/catalog.ts +4 -1
- package/src/resources/extensions/gsd/commands/handlers/core.ts +41 -1
- package/src/resources/extensions/gsd/commands-bootstrap.ts +10 -0
- package/src/resources/extensions/gsd/commands-handlers.ts +19 -2
- package/src/resources/extensions/gsd/context-store.ts +120 -1
- package/src/resources/extensions/gsd/crash-recovery.ts +30 -4
- package/src/resources/extensions/gsd/db/unit-dispatches.ts +4 -3
- package/src/resources/extensions/gsd/db-writer.ts +167 -84
- package/src/resources/extensions/gsd/dispatch-guard.ts +2 -2
- package/src/resources/extensions/gsd/docs/preferences-reference.md +1 -1
- package/src/resources/extensions/gsd/doctor-git-checks.ts +44 -6
- package/src/resources/extensions/gsd/doctor-runtime-checks.ts +25 -13
- package/src/resources/extensions/gsd/doctor-types.ts +2 -0
- package/src/resources/extensions/gsd/doctor.ts +2 -27
- package/src/resources/extensions/gsd/export-html.ts +27 -427
- package/src/resources/extensions/gsd/git-service.ts +45 -1
- package/src/resources/extensions/gsd/gsd-db.ts +3 -0
- package/src/resources/extensions/gsd/guided-flow.ts +126 -128
- package/src/resources/extensions/gsd/guided-unit-context.ts +30 -0
- package/src/resources/extensions/gsd/knowledge-backfill.ts +164 -0
- package/src/resources/extensions/gsd/knowledge-capture.ts +160 -0
- package/src/resources/extensions/gsd/knowledge-parser.ts +174 -0
- package/src/resources/extensions/gsd/knowledge-projection.ts +241 -0
- package/src/resources/extensions/gsd/markdown-renderer.ts +6 -1
- package/src/resources/extensions/gsd/md-importer.ts +1 -1
- package/src/resources/extensions/gsd/memory-backfill.ts +89 -17
- package/src/resources/extensions/gsd/memory-consolidation-scanner.ts +277 -0
- package/src/resources/extensions/gsd/migrate/command.ts +5 -0
- package/src/resources/extensions/gsd/migrate/parsers.ts +11 -0
- package/src/resources/extensions/gsd/migrate/preview.ts +10 -0
- package/src/resources/extensions/gsd/migrate/transformer.ts +58 -4
- package/src/resources/extensions/gsd/migrate/writer.ts +14 -1
- package/src/resources/extensions/gsd/migration-auto-check.ts +15 -23
- package/src/resources/extensions/gsd/milestone-actions.ts +10 -4
- package/src/resources/extensions/gsd/native-git-bridge.ts +54 -12
- package/src/resources/extensions/gsd/pending-auto-start.ts +79 -0
- package/src/resources/extensions/gsd/post-execution-checks.ts +87 -2
- package/src/resources/extensions/gsd/pre-execution-checks.ts +32 -1
- package/src/resources/extensions/gsd/prompt-loader.ts +1 -1
- package/src/resources/extensions/gsd/prompts/complete-milestone.md +1 -1
- package/src/resources/extensions/gsd/prompts/complete-slice.md +1 -1
- package/src/resources/extensions/gsd/prompts/discuss-headless.md +8 -8
- package/src/resources/extensions/gsd/prompts/discuss.md +9 -9
- package/src/resources/extensions/gsd/prompts/guided-discuss-project.md +4 -4
- package/src/resources/extensions/gsd/prompts/guided-discuss-requirements.md +3 -3
- package/src/resources/extensions/gsd/prompts/plan-slice.md +4 -4
- package/src/resources/extensions/gsd/prompts/queue.md +4 -4
- package/src/resources/extensions/gsd/prompts/refine-slice.md +2 -2
- package/src/resources/extensions/gsd/prompts/rewrite-docs.md +1 -1
- package/src/resources/extensions/gsd/prompts/system.md +2 -2
- package/src/resources/extensions/gsd/provider-switch-observer.ts +185 -0
- package/src/resources/extensions/gsd/smart-entry-routing.ts +77 -0
- package/src/resources/extensions/gsd/state-reconciliation/drift/merge-state.ts +8 -1
- package/src/resources/extensions/gsd/state-reconciliation/drift/project-md.ts +12 -15
- package/src/resources/extensions/gsd/state-reconciliation/drift/roadmap.ts +17 -25
- package/src/resources/extensions/gsd/status-guards.ts +5 -0
- package/src/resources/extensions/gsd/templates/knowledge.md +2 -2
- package/src/resources/extensions/gsd/templates/plan.md +8 -5
- package/src/resources/extensions/gsd/templates/task-plan.md +4 -2
- package/src/resources/extensions/gsd/tests/auto-dashboard.test.ts +71 -0
- package/src/resources/extensions/gsd/tests/auto-deterministic-error-classification-4973.test.ts +116 -0
- package/src/resources/extensions/gsd/tests/auto-loop.test.ts +129 -0
- package/src/resources/extensions/gsd/tests/auto-orchestrator.test.ts +487 -4
- package/src/resources/extensions/gsd/tests/auto-paused-ui-cleanup.test.ts +12 -11
- package/src/resources/extensions/gsd/tests/auto-phases-lifecycle.test.ts +53 -2
- package/src/resources/extensions/gsd/tests/auto-post-unit-step-message.test.ts +12 -1
- package/src/resources/extensions/gsd/tests/auto-recovery.test.ts +15 -1
- package/src/resources/extensions/gsd/tests/auto-runtime-state.test.ts +4 -4
- package/src/resources/extensions/gsd/tests/auto-start-orphan-bootstrap.test.ts +1 -0
- package/src/resources/extensions/gsd/tests/auto-worktree-registry.test.ts +69 -1
- package/src/resources/extensions/gsd/tests/brief-command.test.ts +89 -0
- package/src/resources/extensions/gsd/tests/browser-tools-compatibility-declarations.test.ts +62 -0
- package/src/resources/extensions/gsd/tests/clean-root-preflight.test.ts +107 -2
- package/src/resources/extensions/gsd/tests/clear-stale-autostart.test.ts +11 -2
- package/src/resources/extensions/gsd/tests/closeout-git-deferral.test.ts +16 -0
- package/src/resources/extensions/gsd/tests/complete-milestone.test.ts +4 -1
- package/src/resources/extensions/gsd/tests/complete-slice.test.ts +5 -9
- package/src/resources/extensions/gsd/tests/complete-task.test.ts +3 -1
- package/src/resources/extensions/gsd/tests/context-store-decisions-from-memories.test.ts +312 -0
- package/src/resources/extensions/gsd/tests/crash-recovery-via-db.test.ts +43 -2
- package/src/resources/extensions/gsd/tests/db-authority-regression.test.ts +208 -0
- package/src/resources/extensions/gsd/tests/db-writer.test.ts +13 -8
- package/src/resources/extensions/gsd/tests/decisions-projection-from-memories.test.ts +453 -0
- package/src/resources/extensions/gsd/tests/decisions-stop-table-writes.test.ts +348 -0
- package/src/resources/extensions/gsd/tests/deep-project-auto-loop.test.ts +59 -2
- package/src/resources/extensions/gsd/tests/dispatch-complete-milestone-guard.test.ts +39 -0
- package/src/resources/extensions/gsd/tests/dispatch-guard.test.ts +27 -0
- package/src/resources/extensions/gsd/tests/evidence-cross-ref.test.ts +38 -0
- package/src/resources/extensions/gsd/tests/export-html-enhancements.test.ts +8 -0
- package/src/resources/extensions/gsd/tests/freeform-decisions.test.ts +8 -4
- package/src/resources/extensions/gsd/tests/gsd-tools.test.ts +11 -7
- package/src/resources/extensions/gsd/tests/guided-discuss-project-prompt-rendering.test.ts +2 -0
- package/src/resources/extensions/gsd/tests/guided-dispatch-root.test.ts +106 -0
- package/src/resources/extensions/gsd/tests/guided-flow-session-isolation.test.ts +59 -11
- package/src/resources/extensions/gsd/tests/guided-flow.test.ts +21 -0
- package/src/resources/extensions/gsd/tests/guided-tool-contract.test.ts +65 -0
- package/src/resources/extensions/gsd/tests/headless-milestone-parity.test.ts +7 -7
- package/src/resources/extensions/gsd/tests/hook-model-resolution.test.ts +5 -0
- package/src/resources/extensions/gsd/tests/infra-error.test.ts +2 -2
- package/src/resources/extensions/gsd/tests/infra-errors-cooldown.test.ts +9 -0
- package/src/resources/extensions/gsd/tests/integration/doctor-git.test.ts +44 -0
- package/src/resources/extensions/gsd/tests/integration/doctor-runtime.test.ts +20 -0
- package/src/resources/extensions/gsd/tests/integration/git-service.test.ts +103 -1
- package/src/resources/extensions/gsd/tests/integration/integration-lifecycle.test.ts +13 -5
- package/src/resources/extensions/gsd/tests/integration/migrate-command.test.ts +48 -3
- package/src/resources/extensions/gsd/tests/integration/state-machine-runtime-failures.test.ts +6 -1
- package/src/resources/extensions/gsd/tests/knowledge-backfill-projection.test.ts +323 -0
- package/src/resources/extensions/gsd/tests/knowledge-capture.test.ts +242 -0
- package/src/resources/extensions/gsd/tests/knowledge.test.ts +47 -2
- package/src/resources/extensions/gsd/tests/load-knowledge-block-rules-only.test.ts +209 -0
- package/src/resources/extensions/gsd/tests/memory-consolidation-scanner.test.ts +316 -0
- package/src/resources/extensions/gsd/tests/migrate-transformer.test.ts +5 -1
- package/src/resources/extensions/gsd/tests/migrate-validator-parsers.test.ts +24 -1
- package/src/resources/extensions/gsd/tests/migrate-writer-integration.test.ts +6 -1
- package/src/resources/extensions/gsd/tests/migration-auto-check.test.ts +26 -18
- package/src/resources/extensions/gsd/tests/native-git-bridge-exec-fallback.test.ts +63 -2
- package/src/resources/extensions/gsd/tests/orphaned-worktree-audit.test.ts +121 -1
- package/src/resources/extensions/gsd/tests/park-db-sync.test.ts +55 -1
- package/src/resources/extensions/gsd/tests/pending-autostart-scope.test.ts +29 -5
- package/src/resources/extensions/gsd/tests/plan-milestone-sketch-render.test.ts +157 -0
- package/src/resources/extensions/gsd/tests/plan-milestone.test.ts +26 -0
- package/src/resources/extensions/gsd/tests/plan-slice-prompt.test.ts +2 -0
- package/src/resources/extensions/gsd/tests/plan-slice.test.ts +225 -1
- package/src/resources/extensions/gsd/tests/plan-task.test.ts +17 -0
- package/src/resources/extensions/gsd/tests/post-exec-retry-bypass.test.ts +79 -1
- package/src/resources/extensions/gsd/tests/post-execution-checks.test.ts +86 -0
- package/src/resources/extensions/gsd/tests/post-unit-git-failure.test.ts +1 -1
- package/src/resources/extensions/gsd/tests/pre-execution-checks.test.ts +53 -0
- package/src/resources/extensions/gsd/tests/prompt-contracts.test.ts +8 -0
- package/src/resources/extensions/gsd/tests/prompt-loader.test.ts +23 -0
- package/src/resources/extensions/gsd/tests/provider-errors.test.ts +20 -1
- package/src/resources/extensions/gsd/tests/provider-switch-observer.test.ts +252 -0
- package/src/resources/extensions/gsd/tests/remediation-completion-guard.test.ts +46 -2
- package/src/resources/extensions/gsd/tests/session-start-footer.test.ts +16 -4
- package/src/resources/extensions/gsd/tests/session-switch-abort-misclassification.test.ts +10 -0
- package/src/resources/extensions/gsd/tests/smart-entry-routing.test.ts +113 -0
- package/src/resources/extensions/gsd/tests/start-auto-detached.test.ts +53 -2
- package/src/resources/extensions/gsd/tests/state-corruption-2945.test.ts +6 -0
- package/src/resources/extensions/gsd/tests/state-reconciliation-drift.test.ts +119 -23
- package/src/resources/extensions/gsd/tests/stuck-state-via-db.test.ts +64 -1
- package/src/resources/extensions/gsd/tests/summary-render-parity.test.ts +7 -3
- package/src/resources/extensions/gsd/tests/unit-context-manifest.test.ts +86 -7
- package/src/resources/extensions/gsd/tests/verification-gate.test.ts +110 -1
- package/src/resources/extensions/gsd/tests/verification-verdict.test.ts +78 -0
- package/src/resources/extensions/gsd/tests/workflow-mcp.test.ts +1 -1
- package/src/resources/extensions/gsd/tests/workflow-memory-pressure.test.ts +21 -1
- package/src/resources/extensions/gsd/tests/workflow-tool-executors.test.ts +1 -1
- package/src/resources/extensions/gsd/tests/worktree-git-pathspec.test.ts +39 -0
- package/src/resources/extensions/gsd/tests/worktree-journal-events.test.ts +64 -12
- package/src/resources/extensions/gsd/tests/worktree-lifecycle.test.ts +25 -0
- package/src/resources/extensions/gsd/tests/write-gate-planning-unit.test.ts +54 -0
- package/src/resources/extensions/gsd/tools/complete-milestone.ts +8 -10
- package/src/resources/extensions/gsd/tools/complete-slice.ts +6 -8
- package/src/resources/extensions/gsd/tools/plan-milestone.ts +5 -1
- package/src/resources/extensions/gsd/tools/plan-slice.ts +98 -12
- package/src/resources/extensions/gsd/tools/workflow-tool-executors.ts +135 -0
- package/src/resources/extensions/gsd/types.ts +1 -1
- package/src/resources/extensions/gsd/unit-context-manifest.ts +47 -11
- package/src/resources/extensions/gsd/validation.ts +23 -1
- package/src/resources/extensions/gsd/verification-gate.ts +78 -6
- package/src/resources/extensions/gsd/verification-verdict.ts +47 -0
- package/src/resources/extensions/gsd/workflow-logger.ts +4 -0
- package/src/resources/extensions/gsd/workflow-projections.ts +6 -8
- package/src/resources/extensions/gsd/worktree-lifecycle.ts +61 -10
- package/src/resources/extensions/shared/html-shell.ts +412 -0
- package/src/resources/extensions/subagent/index.ts +567 -103
- package/src/resources/extensions/subagent/launch.ts +131 -0
- package/src/resources/extensions/subagent/run-store.ts +218 -0
- package/src/resources/extensions/subagent/tests/launch.test.ts +115 -0
- package/src/resources/extensions/subagent/tests/run-store.test.ts +111 -0
- package/src/resources/extensions/visual-brief/artifact-policy.ts +41 -0
- package/src/resources/extensions/visual-brief/extension-manifest.json +8 -0
- package/src/resources/extensions/visual-brief/index.ts +8 -0
- package/src/resources/extensions/visual-brief/page-contract.ts +136 -0
- package/src/resources/extensions/visual-brief/prompts.ts +183 -0
- package/src/resources/extensions/visual-brief/tests/visual-brief.test.ts +212 -0
- package/dist/web/standalone/.next/server/chunks/5822.js +0 -2
- package/dist/web/standalone/.next/static/chunks/2556.0527fea66e123b7f.js +0 -1
- package/dist/web/standalone/.next/static/chunks/app/layout-a16c7a7ecdf0c2cf.js +0 -1
- package/dist/web/standalone/.next/static/css/54ec2745c1da488b.css +0 -1
- package/dist/web/standalone/.next/static/css/de70bee13400563f.css +0 -1
- package/dist/web/standalone/.next/static/media/4cf2300e9c8272f7-s.p.woff2 +0 -0
- package/dist/web/standalone/.next/static/media/747892c23ea88013-s.woff2 +0 -0
- package/dist/web/standalone/.next/static/media/8d697b304b401681-s.woff2 +0 -0
- package/dist/web/standalone/.next/static/media/93f479601ee12b01-s.p.woff2 +0 -0
- package/dist/web/standalone/.next/static/media/9610d9e46709d722-s.woff2 +0 -0
- package/dist/web/standalone/.next/static/media/ba015fad6dcf6784-s.woff2 +0 -0
- /package/dist/web/standalone/.next/static/{rIkMv4YSNlfSeqmGqWVns → xRy4LqKSNKdT7y6ATYyEl}/_buildManifest.js +0 -0
- /package/dist/web/standalone/.next/static/{rIkMv4YSNlfSeqmGqWVns → xRy4LqKSNKdT7y6ATYyEl}/_ssgManifest.js +0 -0
|
@@ -62,7 +62,11 @@ async function runSuccessfulFinalize(s: AutoSession) {
|
|
|
62
62
|
);
|
|
63
63
|
}
|
|
64
64
|
|
|
65
|
-
async function runFinalizeWithDeps(
|
|
65
|
+
async function runFinalizeWithDeps(
|
|
66
|
+
s: AutoSession,
|
|
67
|
+
depsOverrides: Record<string, unknown>,
|
|
68
|
+
ctxOverride?: Record<string, unknown>,
|
|
69
|
+
) {
|
|
66
70
|
const unit = s.currentUnit;
|
|
67
71
|
assert.ok(unit, "test setup must provide currentUnit");
|
|
68
72
|
|
|
@@ -86,7 +90,7 @@ async function runFinalizeWithDeps(s: AutoSession, depsOverrides: Record<string,
|
|
|
86
90
|
|
|
87
91
|
return runFinalize(
|
|
88
92
|
{
|
|
89
|
-
ctx: { ui: { notify() {} } },
|
|
93
|
+
ctx: ctxOverride ?? { ui: { notify() {} } },
|
|
90
94
|
pi: {},
|
|
91
95
|
s,
|
|
92
96
|
deps,
|
|
@@ -223,3 +227,50 @@ test("runFinalize merges a verified complete-milestone immediately and only once
|
|
|
223
227
|
assert.equal(lifecycleMergeCalls, 1);
|
|
224
228
|
assert.equal(resolverMergeCalls, 0);
|
|
225
229
|
});
|
|
230
|
+
|
|
231
|
+
test("runFinalize does not render next-phase handoff for complete-milestone", async (t) => {
|
|
232
|
+
const base = mkdtempSync(join(tmpdir(), "gsd-finalize-complete-handoff-"));
|
|
233
|
+
t.after(() => {
|
|
234
|
+
rmSync(base, { recursive: true, force: true });
|
|
235
|
+
});
|
|
236
|
+
|
|
237
|
+
const s = new AutoSession();
|
|
238
|
+
const widgetCalls: Array<[string, unknown]> = [];
|
|
239
|
+
s.basePath = base;
|
|
240
|
+
s.originalBasePath = base;
|
|
241
|
+
s.currentMilestoneId = "M001";
|
|
242
|
+
s.currentUnit = {
|
|
243
|
+
type: "complete-milestone",
|
|
244
|
+
id: "M001",
|
|
245
|
+
startedAt: Date.now(),
|
|
246
|
+
};
|
|
247
|
+
|
|
248
|
+
const result = await runFinalizeWithDeps(
|
|
249
|
+
s,
|
|
250
|
+
{
|
|
251
|
+
preflightCleanRoot: () => ({ stashPushed: false }),
|
|
252
|
+
postflightPopStash: () => ({ needsManualRecovery: false }),
|
|
253
|
+
lifecycle: {
|
|
254
|
+
exitMilestone() {
|
|
255
|
+
return { ok: true, merged: true, codeFilesChanged: false };
|
|
256
|
+
},
|
|
257
|
+
},
|
|
258
|
+
},
|
|
259
|
+
{
|
|
260
|
+
hasUI: true,
|
|
261
|
+
ui: {
|
|
262
|
+
notify() {},
|
|
263
|
+
setWidget(key: string, value: unknown) {
|
|
264
|
+
widgetCalls.push([key, value]);
|
|
265
|
+
},
|
|
266
|
+
},
|
|
267
|
+
},
|
|
268
|
+
);
|
|
269
|
+
|
|
270
|
+
assert.equal(result.action, "next");
|
|
271
|
+
assert.equal(
|
|
272
|
+
widgetCalls.some(([key]) => key === "gsd-outcome"),
|
|
273
|
+
false,
|
|
274
|
+
"complete-milestone finalize should leave terminal completion UI to stopAuto",
|
|
275
|
+
);
|
|
276
|
+
});
|
|
@@ -3,7 +3,11 @@
|
|
|
3
3
|
import test from "node:test";
|
|
4
4
|
import assert from "node:assert/strict";
|
|
5
5
|
|
|
6
|
-
import {
|
|
6
|
+
import {
|
|
7
|
+
buildStepCompleteMessage,
|
|
8
|
+
shouldReturnStepWizardAfterUnit,
|
|
9
|
+
STEP_COMPLETE_FALLBACK_MESSAGE,
|
|
10
|
+
} from "../auto-post-unit.ts";
|
|
7
11
|
import type { GSDState } from "../types.ts";
|
|
8
12
|
|
|
9
13
|
function makeState(overrides: Partial<GSDState>): GSDState {
|
|
@@ -51,3 +55,10 @@ test("STEP_COMPLETE_FALLBACK_MESSAGE: used when deriveState throws, still points
|
|
|
51
55
|
assert.match(STEP_COMPLETE_FALLBACK_MESSAGE, /\/clear/);
|
|
52
56
|
assert.match(STEP_COMPLETE_FALLBACK_MESSAGE, /\/gsd/);
|
|
53
57
|
});
|
|
58
|
+
|
|
59
|
+
test("shouldReturnStepWizardAfterUnit: terminal milestone completion continues to merge-back path", () => {
|
|
60
|
+
assert.equal(shouldReturnStepWizardAfterUnit("complete-milestone", "complete"), false);
|
|
61
|
+
assert.equal(shouldReturnStepWizardAfterUnit("complete-milestone", null), false);
|
|
62
|
+
assert.equal(shouldReturnStepWizardAfterUnit("execute-task", "complete"), false);
|
|
63
|
+
assert.equal(shouldReturnStepWizardAfterUnit("execute-task", "executing"), true);
|
|
64
|
+
});
|
|
@@ -5,7 +5,7 @@ import { join } from "node:path";
|
|
|
5
5
|
import { tmpdir } from "node:os";
|
|
6
6
|
import { randomUUID } from "node:crypto";
|
|
7
7
|
|
|
8
|
-
import { verifyExpectedArtifact, hasImplementationArtifacts, resolveExpectedArtifactPath, diagnoseExpectedArtifact, buildLoopRemediationSteps, writeBlockerPlaceholder, refreshRecoveryDbForArtifact } from "../auto-recovery.ts";
|
|
8
|
+
import { verifyExpectedArtifact, hasImplementationArtifacts, resolveExpectedArtifactPath, diagnoseExpectedArtifact, diagnoseWorktreeIntegrityFailure, buildLoopRemediationSteps, writeBlockerPlaceholder, refreshRecoveryDbForArtifact } from "../auto-recovery.ts";
|
|
9
9
|
import { resolveMilestoneFile } from "../paths.ts";
|
|
10
10
|
import { openDatabase, closeDatabase, insertMilestone, insertSlice, insertGateRow, insertTask, getMilestoneCommitAttributionShas } from "../gsd-db.ts";
|
|
11
11
|
import { clearParseCache } from "../files.ts";
|
|
@@ -141,6 +141,20 @@ test("resolveExpectedArtifactPath returns null for unknown type", () => {
|
|
|
141
141
|
}
|
|
142
142
|
});
|
|
143
143
|
|
|
144
|
+
test("diagnoseWorktreeIntegrityFailure reports missing GSD worktree paths only", () => {
|
|
145
|
+
const missingWorktreePath = join(tmpdir(), `gsd-test-${randomUUID()}`, ".gsd", "worktrees", "M001-S01");
|
|
146
|
+
assert.equal(
|
|
147
|
+
diagnoseWorktreeIntegrityFailure(join(tmpdir(), `gsd-test-${randomUUID()}`)),
|
|
148
|
+
null,
|
|
149
|
+
"non-GSD paths should keep falling through to artifact recovery",
|
|
150
|
+
);
|
|
151
|
+
assert.equal(
|
|
152
|
+
diagnoseWorktreeIntegrityFailure(missingWorktreePath),
|
|
153
|
+
`Worktree integrity failure: ${missingWorktreePath} does not exist. Repair or recreate the worktree before retrying.`,
|
|
154
|
+
"missing GSD worktree paths should fail terminally before artifact retry",
|
|
155
|
+
);
|
|
156
|
+
});
|
|
157
|
+
|
|
144
158
|
test("resolveExpectedArtifactPath returns correct path for all milestone-level types", () => {
|
|
145
159
|
const base = makeTmpBase();
|
|
146
160
|
try {
|
|
@@ -12,10 +12,10 @@ test("getAutoRuntimeSnapshot includes orchestration phase when available", () =>
|
|
|
12
12
|
autoSession.active = true;
|
|
13
13
|
autoSession.basePath = "/tmp/project";
|
|
14
14
|
autoSession.orchestration = {
|
|
15
|
-
async start() { return { kind: "
|
|
16
|
-
async advance() { return { kind: "
|
|
17
|
-
async resume() { return { kind: "
|
|
18
|
-
async stop() { return { kind: "stopped" as const }; },
|
|
15
|
+
async start() { return { kind: "stopped" as const, reason: "test" }; },
|
|
16
|
+
async advance() { return { kind: "stopped" as const, reason: "test" }; },
|
|
17
|
+
async resume() { return { kind: "stopped" as const, reason: "test" }; },
|
|
18
|
+
async stop() { return { kind: "stopped" as const, reason: "test" }; },
|
|
19
19
|
getStatus() {
|
|
20
20
|
return { phase: "running" as const, transitionCount: 3, lastTransitionAt: 123 };
|
|
21
21
|
},
|
|
@@ -98,6 +98,7 @@ test("bootstrap aborts before starting next milestone when completed orphan merg
|
|
|
98
98
|
{
|
|
99
99
|
shouldUseWorktreeIsolation: () => true,
|
|
100
100
|
registerSigtermHandler: () => {},
|
|
101
|
+
registerAutoWorkerForSession: () => {},
|
|
101
102
|
lockBase: () => base,
|
|
102
103
|
buildLifecycle: () => ({
|
|
103
104
|
adoptSessionRoot: (sessionBase: string, originalBase?: string) => {
|
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
|
|
3
3
|
import { describe, test, beforeEach } from "node:test";
|
|
4
4
|
import assert from "node:assert/strict";
|
|
5
|
-
import { mkdtempSync, mkdirSync, writeFileSync, rmSync, realpathSync } from "node:fs";
|
|
5
|
+
import { existsSync, mkdtempSync, mkdirSync, writeFileSync, rmSync, realpathSync } from "node:fs";
|
|
6
6
|
import { join } from "node:path";
|
|
7
7
|
import { tmpdir } from "node:os";
|
|
8
8
|
import { execFileSync } from "node:child_process";
|
|
@@ -13,6 +13,7 @@ import {
|
|
|
13
13
|
_resetAutoWorktreeOriginalBaseForTests,
|
|
14
14
|
createAutoWorktree,
|
|
15
15
|
enterAutoWorktree,
|
|
16
|
+
mergeMilestoneToMain,
|
|
16
17
|
teardownAutoWorktree,
|
|
17
18
|
} from "../auto-worktree.ts";
|
|
18
19
|
|
|
@@ -173,4 +174,71 @@ describe("auto-worktree workspace registry", () => {
|
|
|
173
174
|
teardownAutoWorktree(dir2, "M020");
|
|
174
175
|
try { process.chdir(savedCwd); } catch { /* ignore */ }
|
|
175
176
|
});
|
|
177
|
+
|
|
178
|
+
test("mergeMilestoneToMain cleans up when milestone branch was already regular-merged", (t) => {
|
|
179
|
+
const tempDir = createTempRepo(t);
|
|
180
|
+
const msDir = join(tempDir, ".gsd", "milestones", "M003");
|
|
181
|
+
mkdirSync(msDir, { recursive: true });
|
|
182
|
+
writeFileSync(join(msDir, "CONTEXT.md"), "# M003 Context\n");
|
|
183
|
+
git(["add", "."], tempDir);
|
|
184
|
+
git(["commit", "-m", "add milestone"], tempDir);
|
|
185
|
+
|
|
186
|
+
createAutoWorktree(tempDir, "M003");
|
|
187
|
+
const wtDir = join(tempDir, ".gsd", "worktrees", "M003");
|
|
188
|
+
writeFileSync(join(wtDir, "feature.txt"), "implemented\n");
|
|
189
|
+
git(["add", "feature.txt"], wtDir);
|
|
190
|
+
git(["commit", "-m", "feat: implement M003"], wtDir);
|
|
191
|
+
|
|
192
|
+
process.chdir(tempDir);
|
|
193
|
+
git(["merge", "--no-ff", "milestone/M003", "-m", "merge M003"], tempDir);
|
|
194
|
+
|
|
195
|
+
process.chdir(wtDir);
|
|
196
|
+
const result = mergeMilestoneToMain(tempDir, "M003", "# M003\n- [x] **S01: Done**\n");
|
|
197
|
+
|
|
198
|
+
assert.equal(result.codeFilesChanged, true);
|
|
199
|
+
assert.equal(result.pushed, false);
|
|
200
|
+
assert.equal(result.prCreated, false);
|
|
201
|
+
assert.equal(existsSync(wtDir), false, "worktree directory is removed");
|
|
202
|
+
assert.throws(
|
|
203
|
+
() => git(["rev-parse", "--verify", "milestone/M003"], tempDir),
|
|
204
|
+
/Command failed/,
|
|
205
|
+
"already-merged milestone branch is deleted",
|
|
206
|
+
);
|
|
207
|
+
try { process.chdir(savedCwd); } catch { /* ignore */ }
|
|
208
|
+
});
|
|
209
|
+
|
|
210
|
+
test("mergeMilestoneToMain cleans up already-merged milestone after main advances", (t) => {
|
|
211
|
+
const tempDir = createTempRepo(t);
|
|
212
|
+
const msDir = join(tempDir, ".gsd", "milestones", "M004");
|
|
213
|
+
mkdirSync(msDir, { recursive: true });
|
|
214
|
+
writeFileSync(join(msDir, "CONTEXT.md"), "# M004 Context\n");
|
|
215
|
+
git(["add", "."], tempDir);
|
|
216
|
+
git(["commit", "-m", "add milestone"], tempDir);
|
|
217
|
+
|
|
218
|
+
createAutoWorktree(tempDir, "M004");
|
|
219
|
+
const wtDir = join(tempDir, ".gsd", "worktrees", "M004");
|
|
220
|
+
writeFileSync(join(wtDir, "feature.txt"), "implemented\n");
|
|
221
|
+
git(["add", "feature.txt"], wtDir);
|
|
222
|
+
git(["commit", "-m", "feat: implement M004"], wtDir);
|
|
223
|
+
|
|
224
|
+
process.chdir(tempDir);
|
|
225
|
+
git(["merge", "--no-ff", "milestone/M004", "-m", "merge M004"], tempDir);
|
|
226
|
+
writeFileSync(join(tempDir, "hotfix.txt"), "later main work\n");
|
|
227
|
+
git(["add", "hotfix.txt"], tempDir);
|
|
228
|
+
git(["commit", "-m", "fix: advance main"], tempDir);
|
|
229
|
+
|
|
230
|
+
process.chdir(wtDir);
|
|
231
|
+
const result = mergeMilestoneToMain(tempDir, "M004", "# M004\n- [x] **S01: Done**\n");
|
|
232
|
+
|
|
233
|
+
assert.equal(result.codeFilesChanged, true);
|
|
234
|
+
assert.equal(result.pushed, false);
|
|
235
|
+
assert.equal(result.prCreated, false);
|
|
236
|
+
assert.equal(existsSync(wtDir), false, "worktree directory is removed");
|
|
237
|
+
assert.throws(
|
|
238
|
+
() => git(["rev-parse", "--verify", "milestone/M004"], tempDir),
|
|
239
|
+
/Command failed/,
|
|
240
|
+
"already-merged milestone branch is deleted",
|
|
241
|
+
);
|
|
242
|
+
try { process.chdir(savedCwd); } catch { /* ignore */ }
|
|
243
|
+
});
|
|
176
244
|
});
|
|
@@ -0,0 +1,89 @@
|
|
|
1
|
+
// GSD-2 + /gsd brief command behavior tests
|
|
2
|
+
|
|
3
|
+
import test from "node:test";
|
|
4
|
+
import assert from "node:assert/strict";
|
|
5
|
+
|
|
6
|
+
import { GSD_COMMAND_DESCRIPTION, getGsdArgumentCompletions } from "../commands/catalog.ts";
|
|
7
|
+
import { handleCoreCommand, showHelp } from "../commands/handlers/core.ts";
|
|
8
|
+
import { VISUAL_BRIEF_USAGE } from "../../visual-brief/prompts.ts";
|
|
9
|
+
|
|
10
|
+
function createMockCtx() {
|
|
11
|
+
const notifications: { message: string; level: string }[] = [];
|
|
12
|
+
return {
|
|
13
|
+
notifications,
|
|
14
|
+
ui: {
|
|
15
|
+
notify(message: string, level: string) {
|
|
16
|
+
notifications.push({ message, level });
|
|
17
|
+
},
|
|
18
|
+
custom: async () => undefined,
|
|
19
|
+
},
|
|
20
|
+
};
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
function createMockPi() {
|
|
24
|
+
const sentMessages: string[] = [];
|
|
25
|
+
return {
|
|
26
|
+
sentMessages,
|
|
27
|
+
sendUserMessage(content: string) {
|
|
28
|
+
sentMessages.push(content);
|
|
29
|
+
},
|
|
30
|
+
};
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
test("/gsd brief appears in the command description and top-level completions", () => {
|
|
34
|
+
assert.match(GSD_COMMAND_DESCRIPTION, /brief/);
|
|
35
|
+
|
|
36
|
+
const completions = getGsdArgumentCompletions("br");
|
|
37
|
+
const entry = completions.find((completion) => completion.value === "brief");
|
|
38
|
+
|
|
39
|
+
assert.ok(entry, "brief should appear in top-level completions");
|
|
40
|
+
assert.match(entry.description, /visual HTML brief/i);
|
|
41
|
+
});
|
|
42
|
+
|
|
43
|
+
test("/gsd brief exposes Visual Brief mode completions", () => {
|
|
44
|
+
const completions = getGsdArgumentCompletions("brief d");
|
|
45
|
+
|
|
46
|
+
assert.ok(
|
|
47
|
+
completions.some((completion) => completion.value === "brief diagram"),
|
|
48
|
+
"diagram should be suggested as a /gsd brief mode",
|
|
49
|
+
);
|
|
50
|
+
assert.ok(
|
|
51
|
+
getGsdArgumentCompletions("brief ").some((completion) => completion.value === "brief diff"),
|
|
52
|
+
"diff should be suggested after /gsd brief",
|
|
53
|
+
);
|
|
54
|
+
});
|
|
55
|
+
|
|
56
|
+
test("/gsd brief sends a Visual Brief prompt for valid args", async () => {
|
|
57
|
+
const ctx = createMockCtx();
|
|
58
|
+
const pi = createMockPi();
|
|
59
|
+
|
|
60
|
+
const handled = await handleCoreCommand("brief diagram extension loading lifecycle", ctx as any, pi as any);
|
|
61
|
+
|
|
62
|
+
assert.equal(handled, true);
|
|
63
|
+
assert.equal(ctx.notifications.length, 0);
|
|
64
|
+
assert.equal(pi.sentMessages.length, 1);
|
|
65
|
+
assert.match(pi.sentMessages[0], /Mode: diagram/);
|
|
66
|
+
assert.match(pi.sentMessages[0], /Subject: extension loading lifecycle/);
|
|
67
|
+
assert.match(pi.sentMessages[0], /Output directory:/);
|
|
68
|
+
});
|
|
69
|
+
|
|
70
|
+
test("/gsd brief reports usage for empty args instead of sending a prompt", async () => {
|
|
71
|
+
const ctx = createMockCtx();
|
|
72
|
+
const pi = createMockPi();
|
|
73
|
+
|
|
74
|
+
const handled = await handleCoreCommand("brief", ctx as any, pi as any);
|
|
75
|
+
|
|
76
|
+
assert.equal(handled, true);
|
|
77
|
+
assert.equal(pi.sentMessages.length, 0);
|
|
78
|
+
assert.deepEqual(ctx.notifications, [{ message: VISUAL_BRIEF_USAGE, level: "info" }]);
|
|
79
|
+
});
|
|
80
|
+
|
|
81
|
+
test("/gsd help full lists brief separately from visualize", () => {
|
|
82
|
+
const ctx = createMockCtx();
|
|
83
|
+
|
|
84
|
+
showHelp(ctx as any, "full");
|
|
85
|
+
|
|
86
|
+
const help = ctx.notifications.at(0)?.message ?? "";
|
|
87
|
+
assert.match(help, /\/gsd visualize\s+Interactive 10-tab TUI/);
|
|
88
|
+
assert.match(help, /\/gsd brief <mode>\s+Generate a visual HTML brief/);
|
|
89
|
+
});
|
|
@@ -0,0 +1,62 @@
|
|
|
1
|
+
// GSD-2 — ADR-005 Phase 2: Verify browser tool compatibility declarations.
|
|
2
|
+
//
|
|
3
|
+
// Locks in the declarations that always-image-producing browser tools
|
|
4
|
+
// (browser_screenshot, browser_zoom_region) carry `producesImages: true` so
|
|
5
|
+
// the model-router filters them out on providers without imageToolResults
|
|
6
|
+
// (OpenAI completions/responses, Azure, Mistral, Ollama). Conditional-image
|
|
7
|
+
// browser tools (navigation, forms, refs, intent, interaction) must NOT
|
|
8
|
+
// declare producesImages — they only attach error screenshots and filtering
|
|
9
|
+
// them would lose the whole tool surface for OpenAI users.
|
|
10
|
+
|
|
11
|
+
import test from "node:test";
|
|
12
|
+
import assert from "node:assert/strict";
|
|
13
|
+
|
|
14
|
+
import type { ExtensionAPI } from "@gsd/pi-coding-agent";
|
|
15
|
+
|
|
16
|
+
import { registerScreenshotTools } from "../../browser-tools/tools/screenshot.ts";
|
|
17
|
+
import { registerZoomTools } from "../../browser-tools/tools/zoom.ts";
|
|
18
|
+
|
|
19
|
+
interface CapturedToolDef {
|
|
20
|
+
name: string;
|
|
21
|
+
compatibility?: { producesImages?: boolean; schemaFeatures?: string[] };
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
function makeCapturingPi(): { pi: ExtensionAPI; tools: CapturedToolDef[] } {
|
|
25
|
+
const tools: CapturedToolDef[] = [];
|
|
26
|
+
const pi = {
|
|
27
|
+
registerTool(def: CapturedToolDef): void {
|
|
28
|
+
tools.push({ name: def.name, compatibility: def.compatibility });
|
|
29
|
+
},
|
|
30
|
+
} as unknown as ExtensionAPI;
|
|
31
|
+
return { pi, tools };
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
// Browser tool registration functions accept a `deps` object. None of the
|
|
35
|
+
// declarations under test reach for these deps at registration time — they
|
|
36
|
+
// only run inside execute(), which we never invoke. A bare object satisfies
|
|
37
|
+
// the type signature.
|
|
38
|
+
const stubDeps = {} as Parameters<typeof registerScreenshotTools>[1];
|
|
39
|
+
|
|
40
|
+
test("browser_screenshot declares producesImages: true", () => {
|
|
41
|
+
const { pi, tools } = makeCapturingPi();
|
|
42
|
+
registerScreenshotTools(pi, stubDeps);
|
|
43
|
+
const screenshot = tools.find((t) => t.name === "browser_screenshot");
|
|
44
|
+
assert.ok(screenshot, "browser_screenshot should be registered");
|
|
45
|
+
assert.equal(
|
|
46
|
+
screenshot.compatibility?.producesImages,
|
|
47
|
+
true,
|
|
48
|
+
"browser_screenshot must declare producesImages so it is filtered on providers without imageToolResults",
|
|
49
|
+
);
|
|
50
|
+
});
|
|
51
|
+
|
|
52
|
+
test("browser_zoom_region declares producesImages: true", () => {
|
|
53
|
+
const { pi, tools } = makeCapturingPi();
|
|
54
|
+
registerZoomTools(pi, stubDeps);
|
|
55
|
+
const zoom = tools.find((t) => t.name === "browser_zoom_region");
|
|
56
|
+
assert.ok(zoom, "browser_zoom_region should be registered");
|
|
57
|
+
assert.equal(
|
|
58
|
+
zoom.compatibility?.producesImages,
|
|
59
|
+
true,
|
|
60
|
+
"browser_zoom_region must declare producesImages so it is filtered on providers without imageToolResults",
|
|
61
|
+
);
|
|
62
|
+
});
|
|
@@ -8,7 +8,7 @@
|
|
|
8
8
|
|
|
9
9
|
import test from "node:test";
|
|
10
10
|
import assert from "node:assert/strict";
|
|
11
|
-
import { mkdtempSync, mkdirSync, writeFileSync, rmSync, readFileSync, realpathSync } from "node:fs";
|
|
11
|
+
import { existsSync, mkdtempSync, mkdirSync, writeFileSync, rmSync, readFileSync, realpathSync } from "node:fs";
|
|
12
12
|
import { join } from "node:path";
|
|
13
13
|
import { tmpdir } from "node:os";
|
|
14
14
|
import { execSync } from "node:child_process";
|
|
@@ -208,8 +208,8 @@ test("postflightPopStash conflict warning names the exact stash ref", () => {
|
|
|
208
208
|
assert.match(postflight.message, /failed after merge of milestone M005C/);
|
|
209
209
|
|
|
210
210
|
const warning = notifications.find((n) => n.level === "warning")?.msg ?? "";
|
|
211
|
-
assert.match(warning, /git stash pop stash@\{\d+\}/);
|
|
212
211
|
assert.match(warning, /git stash apply stash@\{\d+\}/);
|
|
212
|
+
assert.match(warning, /git stash drop stash@\{\d+\}/);
|
|
213
213
|
} finally {
|
|
214
214
|
try { rmSync(repo, { recursive: true, force: true, maxRetries: 3, retryDelay: 100 }); } catch { /* ignore */ }
|
|
215
215
|
}
|
|
@@ -279,3 +279,108 @@ test("postflightPopStash falls back to milestone marker prefix when exact marker
|
|
|
279
279
|
try { rmSync(repo, { recursive: true, force: true, maxRetries: 3, retryDelay: 100 }); } catch { /* ignore */ }
|
|
280
280
|
}
|
|
281
281
|
});
|
|
282
|
+
|
|
283
|
+
test("postflightPopStash preserves stash when untracked collision differs from merged file", () => {
|
|
284
|
+
const repo = createTempRepo();
|
|
285
|
+
try {
|
|
286
|
+
writeFileSync(join(repo, "tests.txt"), "local preflight test\n");
|
|
287
|
+
const preflight = preflightCleanRoot(repo, "M009", () => {});
|
|
288
|
+
assert.equal(preflight.stashPushed, true, "preflight must stash untracked file");
|
|
289
|
+
|
|
290
|
+
writeFileSync(join(repo, "tests.txt"), "merged milestone test\n");
|
|
291
|
+
run("git add tests.txt", repo);
|
|
292
|
+
run('git commit -m "feat: add merged test"', repo);
|
|
293
|
+
|
|
294
|
+
const notifications: Array<{ msg: string; level: string }> = [];
|
|
295
|
+
const postflight = postflightPopStash(repo, "M009", preflight.stashMarker, (msg, level) => {
|
|
296
|
+
notifications.push({ msg, level });
|
|
297
|
+
});
|
|
298
|
+
|
|
299
|
+
assert.equal(postflight.needsManualRecovery, false, "different already-present untracked files must not stop auto-mode");
|
|
300
|
+
assert.equal(postflight.resolution, "already-present-preserved");
|
|
301
|
+
assert.deepEqual(postflight.collidedPaths, ["tests.txt"]);
|
|
302
|
+
assert.equal(readFileSync(join(repo, "tests.txt"), "utf-8"), "merged milestone test\n");
|
|
303
|
+
assert.equal(run("git status --porcelain", repo), "", "merged file must stay clean");
|
|
304
|
+
|
|
305
|
+
const stashList = run("git stash list", repo);
|
|
306
|
+
assert.ok(preflight.stashMarker && stashList.includes(preflight.stashMarker), "stash backup must be preserved");
|
|
307
|
+
assert.ok(
|
|
308
|
+
notifications.some((n) => n.level === "warning" && n.msg.includes("preserving")),
|
|
309
|
+
"user must be warned that the stash was preserved as backup",
|
|
310
|
+
);
|
|
311
|
+
} finally {
|
|
312
|
+
try { rmSync(repo, { recursive: true, force: true, maxRetries: 3, retryDelay: 100 }); } catch { /* ignore */ }
|
|
313
|
+
}
|
|
314
|
+
});
|
|
315
|
+
|
|
316
|
+
test("postflightPopStash drops stash when untracked collision is identical to merged file", () => {
|
|
317
|
+
const repo = createTempRepo();
|
|
318
|
+
try {
|
|
319
|
+
writeFileSync(join(repo, "tests.txt"), "same test content\n");
|
|
320
|
+
const preflight = preflightCleanRoot(repo, "M010", () => {});
|
|
321
|
+
assert.equal(preflight.stashPushed, true, "preflight must stash untracked file");
|
|
322
|
+
|
|
323
|
+
writeFileSync(join(repo, "tests.txt"), "same test content\n");
|
|
324
|
+
run("git add tests.txt", repo);
|
|
325
|
+
run('git commit -m "feat: add same test"', repo);
|
|
326
|
+
|
|
327
|
+
const postflight = postflightPopStash(repo, "M010", preflight.stashMarker, () => {});
|
|
328
|
+
|
|
329
|
+
assert.equal(postflight.needsManualRecovery, false, "identical already-present files must not stop auto-mode");
|
|
330
|
+
assert.equal(postflight.resolution, "already-present-dropped");
|
|
331
|
+
assert.equal(readFileSync(join(repo, "tests.txt"), "utf-8"), "same test content\n");
|
|
332
|
+
|
|
333
|
+
const stashList = run("git stash list", repo);
|
|
334
|
+
assert.ok(!stashList.includes(preflight.stashMarker ?? ""), "identical stash must be dropped");
|
|
335
|
+
} finally {
|
|
336
|
+
try { rmSync(repo, { recursive: true, force: true, maxRetries: 3, retryDelay: 100 }); } catch { /* ignore */ }
|
|
337
|
+
}
|
|
338
|
+
});
|
|
339
|
+
|
|
340
|
+
test("postflightPopStash requires manual recovery for mixed tracked changes and untracked collision", () => {
|
|
341
|
+
const repo = createTempRepo();
|
|
342
|
+
try {
|
|
343
|
+
writeFileSync(join(repo, "README.md"), "# local tracked work\n");
|
|
344
|
+
writeFileSync(join(repo, "tests.txt"), "local untracked work\n");
|
|
345
|
+
const preflight = preflightCleanRoot(repo, "M011", () => {});
|
|
346
|
+
assert.equal(preflight.stashPushed, true, "preflight must stash mixed changes");
|
|
347
|
+
|
|
348
|
+
writeFileSync(join(repo, "tests.txt"), "merged milestone test\n");
|
|
349
|
+
run("git add tests.txt", repo);
|
|
350
|
+
run('git commit -m "feat: add merged test"', repo);
|
|
351
|
+
|
|
352
|
+
const postflight = postflightPopStash(repo, "M011", preflight.stashMarker, () => {});
|
|
353
|
+
|
|
354
|
+
assert.equal(postflight.needsManualRecovery, true, "tracked stash payload must still require manual recovery");
|
|
355
|
+
assert.equal(postflight.resolution, "manual-recovery");
|
|
356
|
+
const stashList = run("git stash list", repo);
|
|
357
|
+
assert.ok(preflight.stashMarker && stashList.includes(preflight.stashMarker), "mixed stash must be preserved");
|
|
358
|
+
} finally {
|
|
359
|
+
try { rmSync(repo, { recursive: true, force: true, maxRetries: 3, retryDelay: 100 }); } catch { /* ignore */ }
|
|
360
|
+
}
|
|
361
|
+
});
|
|
362
|
+
|
|
363
|
+
test("postflightPopStash requires manual recovery when an untracked stash path is missing after collision", () => {
|
|
364
|
+
const repo = createTempRepo();
|
|
365
|
+
try {
|
|
366
|
+
writeFileSync(join(repo, "tests.txt"), "local untracked work\n");
|
|
367
|
+
writeFileSync(join(repo, "other-tests.txt"), "other local untracked work\n");
|
|
368
|
+
const preflight = preflightCleanRoot(repo, "M012", () => {});
|
|
369
|
+
assert.equal(preflight.stashPushed, true, "preflight must stash untracked files");
|
|
370
|
+
|
|
371
|
+
writeFileSync(join(repo, "tests.txt"), "merged milestone test\n");
|
|
372
|
+
run("git add tests.txt", repo);
|
|
373
|
+
run('git commit -m "feat: add one merged test"', repo);
|
|
374
|
+
|
|
375
|
+
const postflight = postflightPopStash(repo, "M012", preflight.stashMarker, () => {});
|
|
376
|
+
|
|
377
|
+
assert.equal(postflight.needsManualRecovery, true, "partial untracked restores must still require manual recovery");
|
|
378
|
+
assert.equal(postflight.resolution, "manual-recovery");
|
|
379
|
+
assert.equal(existsSync(join(repo, "other-tests.txt")), true, "git may partially restore the non-colliding path");
|
|
380
|
+
assert.match(run("git status --porcelain", repo), /\?\? other-tests\.txt/, "partial restore must leave manual recovery visible");
|
|
381
|
+
const stashList = run("git stash list", repo);
|
|
382
|
+
assert.ok(preflight.stashMarker && stashList.includes(preflight.stashMarker), "stash must remain for manual recovery");
|
|
383
|
+
} finally {
|
|
384
|
+
try { rmSync(repo, { recursive: true, force: true, maxRetries: 3, retryDelay: 100 }); } catch { /* ignore */ }
|
|
385
|
+
}
|
|
386
|
+
});
|
|
@@ -17,6 +17,15 @@ import {
|
|
|
17
17
|
setPendingAutoStart,
|
|
18
18
|
} from "../guided-flow.ts";
|
|
19
19
|
|
|
20
|
+
function pendingInput(basePath: string, milestoneId: string) {
|
|
21
|
+
return {
|
|
22
|
+
basePath,
|
|
23
|
+
milestoneId,
|
|
24
|
+
ctx: { ui: { notify: () => undefined } } as any,
|
|
25
|
+
pi: { sendMessage: () => undefined } as any,
|
|
26
|
+
};
|
|
27
|
+
}
|
|
28
|
+
|
|
20
29
|
afterEach(() => {
|
|
21
30
|
clearPendingAutoStart();
|
|
22
31
|
});
|
|
@@ -28,7 +37,7 @@ describe("clear stale pending auto-start (#3667)", () => {
|
|
|
28
37
|
mkdirSync(join(base, ".gsd"), { recursive: true });
|
|
29
38
|
const before = Date.now();
|
|
30
39
|
|
|
31
|
-
setPendingAutoStart(base,
|
|
40
|
+
setPendingAutoStart(base, pendingInput(base, "M001"));
|
|
32
41
|
|
|
33
42
|
const entry = _getPendingAutoStart(base);
|
|
34
43
|
assert.ok(entry);
|
|
@@ -41,7 +50,7 @@ describe("clear stale pending auto-start (#3667)", () => {
|
|
|
41
50
|
t.after(() => rmSync(base, { recursive: true, force: true }));
|
|
42
51
|
mkdirSync(join(base, ".gsd"), { recursive: true });
|
|
43
52
|
|
|
44
|
-
setPendingAutoStart(base, {
|
|
53
|
+
setPendingAutoStart(base, { ...pendingInput(base, "M001"), createdAt: 123 });
|
|
45
54
|
|
|
46
55
|
assert.equal(_getPendingAutoStart(base)?.createdAt, 123);
|
|
47
56
|
});
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
// Project/App: GSD-2
|
|
2
|
+
// File Purpose: Tests closeout git action deferral policy for auto-mode units.
|
|
3
|
+
|
|
4
|
+
import test from "node:test";
|
|
5
|
+
import assert from "node:assert/strict";
|
|
6
|
+
|
|
7
|
+
import { shouldDeferCloseoutGitAction } from "../auto-post-unit.ts";
|
|
8
|
+
|
|
9
|
+
test("execute-task defers closeout git action until verification passes", () => {
|
|
10
|
+
assert.equal(shouldDeferCloseoutGitAction("execute-task"), true);
|
|
11
|
+
});
|
|
12
|
+
|
|
13
|
+
test("non execute-task units keep pre-verification closeout git action", () => {
|
|
14
|
+
assert.equal(shouldDeferCloseoutGitAction("plan-slice"), false);
|
|
15
|
+
assert.equal(shouldDeferCloseoutGitAction("complete-slice"), false);
|
|
16
|
+
});
|
|
@@ -645,7 +645,7 @@ describe("complete-milestone", () => {
|
|
|
645
645
|
assert.strictEqual(sanitized.triggerReason, undefined);
|
|
646
646
|
});
|
|
647
647
|
|
|
648
|
-
test("rendered SUMMARY.md uses
|
|
648
|
+
test("rendered SUMMARY.md uses empty frontmatter lists for empty key fields", async () => {
|
|
649
649
|
const { handleCompleteMilestone } = await import("../tools/complete-milestone.ts");
|
|
650
650
|
const base = createFixtureBase();
|
|
651
651
|
const mid = "M001";
|
|
@@ -678,6 +678,9 @@ describe("complete-milestone", () => {
|
|
|
678
678
|
assert.match(summary, /## Success Criteria Results\n\nNot provided\./);
|
|
679
679
|
assert.match(summary, /## Definition of Done Results\n\nNot provided\./);
|
|
680
680
|
assert.match(summary, /## Requirement Outcomes\n\nNot provided\./);
|
|
681
|
+
assert.match(summary, /key_decisions:\s*\[\]/);
|
|
682
|
+
assert.match(summary, /key_files:\s*\[\]/);
|
|
683
|
+
assert.doesNotMatch(summary, /key_(?:decisions|files):\n - \(none\)/);
|
|
681
684
|
assert.match(summary, /## Deviations\n\nNone\./);
|
|
682
685
|
assert.match(summary, /## Follow-ups\n\nNone\./);
|
|
683
686
|
} finally {
|
|
@@ -408,10 +408,10 @@ console.log('\n=== complete-slice: handler with missing roadmap ===');
|
|
|
408
408
|
}
|
|
409
409
|
|
|
410
410
|
// ═══════════════════════════════════════════════════════════════════════════
|
|
411
|
-
// complete-slice:
|
|
411
|
+
// complete-slice: PROJECT refresh uses DB-backed artifact tool.
|
|
412
412
|
// ═══════════════════════════════════════════════════════════════════════════
|
|
413
413
|
|
|
414
|
-
console.log('\n=== complete-slice:
|
|
414
|
+
console.log('\n=== complete-slice: PROJECT refresh uses gsd_summary_save ===');
|
|
415
415
|
{
|
|
416
416
|
const promptPath = path.join(
|
|
417
417
|
path.dirname(new URL(import.meta.url).pathname),
|
|
@@ -419,13 +419,9 @@ console.log('\n=== complete-slice: step 13 specifies write tool for PROJECT.md (
|
|
|
419
419
|
);
|
|
420
420
|
const prompt = fs.readFileSync(promptPath, 'utf-8');
|
|
421
421
|
|
|
422
|
-
|
|
423
|
-
|
|
424
|
-
|
|
425
|
-
const mentionsWriteTool =
|
|
426
|
-
/PROJECT\.md.*\bwrite\b/i.test(prompt) ||
|
|
427
|
-
/\bwrite\b.*PROJECT\.md/i.test(prompt);
|
|
428
|
-
assertTrue(mentionsWriteTool, 'step 13 must name the `write` tool when updating PROJECT.md');
|
|
422
|
+
assertTrue(prompt.includes('gsd_summary_save'), 'PROJECT refresh must use gsd_summary_save');
|
|
423
|
+
assertTrue(prompt.includes('artifact_type: "PROJECT"'), 'PROJECT refresh must use artifact_type PROJECT');
|
|
424
|
+
assertTrue(!/with a full `write`/i.test(prompt), 'prompt must not instruct direct PROJECT.md writes');
|
|
429
425
|
}
|
|
430
426
|
|
|
431
427
|
// ═══════════════════════════════════════════════════════════════════════════
|
|
@@ -491,7 +491,9 @@ console.log('\n=== complete-task: minimal params (no keyFiles, keyDecisions, ver
|
|
|
491
491
|
assertTrue(fs.existsSync(result.summaryPath), 'summary file should be written with minimal params');
|
|
492
492
|
const summaryContent = fs.readFileSync(result.summaryPath, 'utf-8');
|
|
493
493
|
assertMatch(summaryContent, /blocker_discovered:\s*false/, 'blocker_discovered should default to false');
|
|
494
|
-
assertMatch(summaryContent,
|
|
494
|
+
assertMatch(summaryContent, /key_files:\s*\[\]/, 'key_files should render as an empty frontmatter list');
|
|
495
|
+
assertMatch(summaryContent, /key_decisions:\s*\[\]/, 'key_decisions should render as an empty frontmatter list');
|
|
496
|
+
assertTrue(!summaryContent.includes(' - (none)'), 'empty frontmatter lists should not render (none) as a list item');
|
|
495
497
|
}
|
|
496
498
|
|
|
497
499
|
cleanupDir(basePath);
|