gsd-pi 2.82.0-dev.725028083 → 2.82.0-dev.98ea09b1e
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 +4 -3
- package/dist/resources/.managed-resources-content-hash +1 -1
- package/dist/resources/GSD-WORKFLOW.md +10 -1
- 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 +8 -1
- package/dist/resources/extensions/gsd/auto/workflow-memory-pressure.js +12 -0
- 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 +2 -2
- 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 +4 -1
- package/dist/resources/extensions/gsd/bootstrap/db-tools.js +9 -8
- package/dist/resources/extensions/gsd/bootstrap/subagent-input.js +21 -9
- 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 +37 -0
- package/dist/resources/extensions/gsd/commands-bootstrap.js +5 -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/dispatch-guard.js +2 -2
- 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 +13 -6
- package/dist/resources/extensions/gsd/md-importer.js +1 -1
- 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/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/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/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 +14 -14
- 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 +14 -14
- 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 +4 -4
- 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/mcp-server/README.md +13 -4
- 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/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/tsconfig.json +2 -1
- package/packages/native/tsconfig.tsbuildinfo +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/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/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/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/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/src/tui.ts +6 -0
- package/packages/pi-tui/tsconfig.tsbuildinfo +1 -1
- package/packages/rpc-client/tsconfig.tsbuildinfo +1 -1
- package/src/resources/GSD-WORKFLOW.md +10 -1
- 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 +7 -1
- package/src/resources/extensions/gsd/auto/workflow-memory-pressure.ts +13 -0
- 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 +2 -2
- 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 +6 -1
- package/src/resources/extensions/gsd/bootstrap/db-tools.ts +9 -8
- package/src/resources/extensions/gsd/bootstrap/subagent-input.ts +19 -7
- 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 +40 -0
- package/src/resources/extensions/gsd/commands-bootstrap.ts +10 -0
- 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/dispatch-guard.ts +2 -2
- package/src/resources/extensions/gsd/doctor-runtime-checks.ts +25 -13
- 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 +14 -7
- package/src/resources/extensions/gsd/md-importer.ts +1 -1
- 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/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/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/plan.md +8 -5
- package/src/resources/extensions/gsd/templates/task-plan.md +4 -2
- 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 +54 -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-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/clean-root-preflight.test.ts +107 -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/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/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/guided-discuss-project-prompt-rendering.test.ts +2 -0
- package/src/resources/extensions/gsd/tests/guided-flow.test.ts +21 -0
- package/src/resources/extensions/gsd/tests/headless-milestone-parity.test.ts +6 -6
- 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-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/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/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/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-loader.test.ts +23 -0
- package/src/resources/extensions/gsd/tests/remediation-completion-guard.test.ts +46 -2
- package/src/resources/extensions/gsd/tests/session-switch-abort-misclassification.test.ts +10 -0
- package/src/resources/extensions/gsd/tests/start-auto-detached.test.ts +31 -1
- 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-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/{KDRTXR-22LPCsa80X9dey → euQ0CLP_v8V4e76Tu3odJ}/_buildManifest.js +0 -0
- /package/dist/web/standalone/.next/static/{KDRTXR-22LPCsa80X9dey → euQ0CLP_v8V4e76Tu3odJ}/_ssgManifest.js +0 -0
|
@@ -7,13 +7,17 @@ import {
|
|
|
7
7
|
ARTIFACT_KEYS,
|
|
8
8
|
KNOWN_UNIT_TYPES,
|
|
9
9
|
UNIT_MANIFESTS,
|
|
10
|
+
resolveSubagentPermissionContract,
|
|
10
11
|
resolveManifest,
|
|
11
12
|
type ArtifactKey,
|
|
12
13
|
type ContextModePolicy,
|
|
13
14
|
type SkillsPolicy,
|
|
14
15
|
type UnitContextManifest,
|
|
15
16
|
} from "../unit-context-manifest.ts";
|
|
16
|
-
import {
|
|
17
|
+
import {
|
|
18
|
+
ALLOWED_PLANNING_DISPATCH_AGENTS,
|
|
19
|
+
shouldBlockPlanningUnit,
|
|
20
|
+
} from "../bootstrap/write-gate.ts";
|
|
17
21
|
import {
|
|
18
22
|
getRequiredWorkflowToolsForAutoUnit,
|
|
19
23
|
getRequiredWorkflowToolsForGuidedUnit,
|
|
@@ -216,7 +220,7 @@ test("#4934: every manifest declares a tools policy", () => {
|
|
|
216
220
|
});
|
|
217
221
|
|
|
218
222
|
test("#4934: tools.mode is one of the declared policies", () => {
|
|
219
|
-
const validModes = new Set(["all", "read-only", "planning", "planning-dispatch", "docs"]);
|
|
223
|
+
const validModes = new Set(["all", "read-only", "planning", "planning-dispatch", "docs", "verification"]);
|
|
220
224
|
for (const [unitType, manifest] of Object.entries(UNIT_MANIFESTS)) {
|
|
221
225
|
const mode = (manifest as { tools: { mode: string } }).tools.mode;
|
|
222
226
|
assert.ok(
|
|
@@ -226,27 +230,84 @@ test("#4934: tools.mode is one of the declared policies", () => {
|
|
|
226
230
|
}
|
|
227
231
|
});
|
|
228
232
|
|
|
229
|
-
test('#4934: only
|
|
230
|
-
const allowedAllUnits = new Set(["execute-task", "reactive-execute"]);
|
|
233
|
+
test('#4934: only execution units and complete-milestone may use tools.mode "all"', () => {
|
|
234
|
+
const allowedAllUnits = new Set(["execute-task", "reactive-execute", "complete-milestone"]);
|
|
231
235
|
for (const [unitType, manifest] of Object.entries(UNIT_MANIFESTS)) {
|
|
232
236
|
const mode = (manifest as { tools: { mode: string } }).tools.mode;
|
|
233
237
|
if (mode === "all") {
|
|
234
238
|
assert.ok(
|
|
235
239
|
allowedAllUnits.has(unitType),
|
|
236
|
-
`manifest "${unitType}" declares tools.mode = "all" but is not
|
|
237
|
-
'Only execute-task
|
|
240
|
+
`manifest "${unitType}" declares tools.mode = "all" but is not explicitly allowed. ` +
|
|
241
|
+
'Only execute-task, reactive-execute, and complete-milestone should have full source write access; ' +
|
|
238
242
|
'planning/discuss/research units must use "planning" or "planning-dispatch" (or "docs" for rewrite-docs).',
|
|
239
243
|
);
|
|
240
244
|
}
|
|
241
245
|
}
|
|
242
246
|
});
|
|
243
247
|
|
|
248
|
+
test("#5453: complete-milestone uses all tools so bash verification is not planning-dispatch blocked", () => {
|
|
249
|
+
const manifest = UNIT_MANIFESTS["complete-milestone"];
|
|
250
|
+
|
|
251
|
+
assert.strictEqual(manifest.tools.mode, "all");
|
|
252
|
+
assert.deepEqual(resolveSubagentPermissionContract("complete-milestone"), {
|
|
253
|
+
allowed: true,
|
|
254
|
+
allowedSubagents: ["*"],
|
|
255
|
+
toolsMode: "all",
|
|
256
|
+
});
|
|
257
|
+
// Runtime gate-level regression: these verification commands were blocked
|
|
258
|
+
// under planning-dispatch in #5453; complete-milestone must bypass that gate.
|
|
259
|
+
for (const cmd of ["git diff --name-only HEAD~1", "git log -n1 --oneline"]) {
|
|
260
|
+
const result = shouldBlockPlanningUnit(
|
|
261
|
+
"bash",
|
|
262
|
+
cmd,
|
|
263
|
+
process.cwd(),
|
|
264
|
+
"complete-milestone",
|
|
265
|
+
manifest.tools,
|
|
266
|
+
);
|
|
267
|
+
assert.strictEqual(
|
|
268
|
+
result.block,
|
|
269
|
+
false,
|
|
270
|
+
`shouldBlockPlanningUnit must not block ${cmd} for complete-milestone: ${result.reason}`,
|
|
271
|
+
);
|
|
272
|
+
}
|
|
273
|
+
});
|
|
274
|
+
|
|
275
|
+
test("#5843: run-uat uses verification tools policy so build/test commands can run", () => {
|
|
276
|
+
const manifest = UNIT_MANIFESTS["run-uat"];
|
|
277
|
+
|
|
278
|
+
assert.strictEqual(manifest.tools.mode, "verification");
|
|
279
|
+
|
|
280
|
+
const buildResult = shouldBlockPlanningUnit(
|
|
281
|
+
"bash",
|
|
282
|
+
"npm run build 2>&1",
|
|
283
|
+
process.cwd(),
|
|
284
|
+
"run-uat",
|
|
285
|
+
manifest.tools,
|
|
286
|
+
);
|
|
287
|
+
assert.strictEqual(
|
|
288
|
+
buildResult.block,
|
|
289
|
+
false,
|
|
290
|
+
`run-uat must allow build verification commands: ${buildResult.reason}`,
|
|
291
|
+
);
|
|
292
|
+
|
|
293
|
+
const sourceWriteResult = shouldBlockPlanningUnit(
|
|
294
|
+
"edit",
|
|
295
|
+
"src/main.ts",
|
|
296
|
+
process.cwd(),
|
|
297
|
+
"run-uat",
|
|
298
|
+
manifest.tools,
|
|
299
|
+
);
|
|
300
|
+
assert.strictEqual(sourceWriteResult.block, true);
|
|
301
|
+
assert.match(sourceWriteResult.reason!, /tools-policy "verification"/);
|
|
302
|
+
});
|
|
303
|
+
|
|
244
304
|
test('planning-dispatch mode is reserved for slice-level decomposition and completion units', () => {
|
|
245
305
|
const allowedDispatchUnits = new Set([
|
|
246
306
|
"plan-slice",
|
|
307
|
+
"research-slice",
|
|
247
308
|
"refine-slice",
|
|
248
309
|
"complete-slice",
|
|
249
|
-
"
|
|
310
|
+
"gate-evaluate",
|
|
250
311
|
// Deep planning mode: research-project orchestrates 4 parallel research
|
|
251
312
|
// subagents (stack/features/architecture/pitfalls). Subagent dispatch is
|
|
252
313
|
// the unit's core mechanism — without it, the unit cannot do its job.
|
|
@@ -265,6 +326,24 @@ test('planning-dispatch mode is reserved for slice-level decomposition and compl
|
|
|
265
326
|
}
|
|
266
327
|
});
|
|
267
328
|
|
|
329
|
+
test('Unit Tool Contract exposes subagent dispatch permissions', () => {
|
|
330
|
+
assert.deepEqual(resolveSubagentPermissionContract("plan-slice"), {
|
|
331
|
+
allowed: true,
|
|
332
|
+
allowedSubagents: ["scout", "planner"],
|
|
333
|
+
toolsMode: "planning-dispatch",
|
|
334
|
+
});
|
|
335
|
+
assert.deepEqual(resolveSubagentPermissionContract("gate-evaluate"), {
|
|
336
|
+
allowed: true,
|
|
337
|
+
allowedSubagents: ["reviewer", "security", "tester"],
|
|
338
|
+
toolsMode: "planning-dispatch",
|
|
339
|
+
});
|
|
340
|
+
assert.deepEqual(resolveSubagentPermissionContract("discuss-milestone"), {
|
|
341
|
+
allowed: false,
|
|
342
|
+
allowedSubagents: [],
|
|
343
|
+
toolsMode: "planning",
|
|
344
|
+
});
|
|
345
|
+
});
|
|
346
|
+
|
|
268
347
|
test('planning-dispatch manifests declare non-empty allowedSubagents lists', () => {
|
|
269
348
|
for (const [unitType, manifest] of Object.entries(UNIT_MANIFESTS)) {
|
|
270
349
|
if (manifest.tools.mode !== "planning-dispatch") continue;
|
|
@@ -22,7 +22,7 @@ import { join, dirname } from "node:path";
|
|
|
22
22
|
import { tmpdir } from "node:os";
|
|
23
23
|
import { spawnSync } from "node:child_process";
|
|
24
24
|
import { fileURLToPath, pathToFileURL } from "node:url";
|
|
25
|
-
import { discoverCommands, runVerificationGate, formatFailureContext, captureRuntimeErrors, runDependencyAudit, isLikelyCommand } from "../verification-gate.ts";
|
|
25
|
+
import { discoverCommands, runVerificationGate, formatFailureContext, captureRuntimeErrors, runDependencyAudit, isLikelyCommand, validateVerificationCommand } from "../verification-gate.ts";
|
|
26
26
|
import type { CaptureRuntimeErrorsOptions, DependencyAuditOptions } from "../verification-gate.ts";
|
|
27
27
|
import { validatePreferences } from "../preferences.ts";
|
|
28
28
|
|
|
@@ -215,6 +215,102 @@ describe("verification-gate: discovery", () => {
|
|
|
215
215
|
assert.equal(result.source, "task-plan");
|
|
216
216
|
assert.deepStrictEqual(result.commands, ["npm run test"]);
|
|
217
217
|
});
|
|
218
|
+
|
|
219
|
+
test("taskPlanVerify rejects piped pytest command", () => {
|
|
220
|
+
const result = discoverCommands({
|
|
221
|
+
taskPlanVerify: "python3 -m pytest tests/ -q --tb=short 2>&1 | tail -5",
|
|
222
|
+
cwd: tmp,
|
|
223
|
+
});
|
|
224
|
+
assert.equal(result.source, "none");
|
|
225
|
+
assert.deepStrictEqual(result.commands, []);
|
|
226
|
+
});
|
|
227
|
+
|
|
228
|
+
test("Python project with tests discovers pytest when package.json is absent", () => {
|
|
229
|
+
mkdirSync(join(tmp, "tests"));
|
|
230
|
+
writeFileSync(join(tmp, "tests", "test_sample.py"), "def test_sample():\n assert True\n");
|
|
231
|
+
writeFileSync(
|
|
232
|
+
join(tmp, "pyproject.toml"),
|
|
233
|
+
`[project]
|
|
234
|
+
name = "sample"
|
|
235
|
+
|
|
236
|
+
[tool.pytest.ini_options]
|
|
237
|
+
pythonpath = ["."]
|
|
238
|
+
`,
|
|
239
|
+
);
|
|
240
|
+
|
|
241
|
+
const result = discoverCommands({ cwd: tmp });
|
|
242
|
+
|
|
243
|
+
assert.equal(result.source, "python-project");
|
|
244
|
+
assert.deepStrictEqual(result.commands, ["python3 -m pytest"]);
|
|
245
|
+
});
|
|
246
|
+
|
|
247
|
+
test("Python project with nested Python test file discovers pytest", () => {
|
|
248
|
+
mkdirSync(join(tmp, "tests", "unit"), { recursive: true });
|
|
249
|
+
writeFileSync(join(tmp, "tests", "unit", "sample_test.py"), "def test_sample():\n assert True\n");
|
|
250
|
+
|
|
251
|
+
const result = discoverCommands({ cwd: tmp });
|
|
252
|
+
|
|
253
|
+
assert.equal(result.source, "python-project");
|
|
254
|
+
assert.deepStrictEqual(result.commands, ["python3 -m pytest"]);
|
|
255
|
+
});
|
|
256
|
+
|
|
257
|
+
test("Python project with pytest.ini discovers pytest", () => {
|
|
258
|
+
writeFileSync(join(tmp, "pytest.ini"), "[pytest]\npythonpath = .\n");
|
|
259
|
+
|
|
260
|
+
const result = discoverCommands({ cwd: tmp });
|
|
261
|
+
|
|
262
|
+
assert.equal(result.source, "python-project");
|
|
263
|
+
assert.deepStrictEqual(result.commands, ["python3 -m pytest"]);
|
|
264
|
+
});
|
|
265
|
+
|
|
266
|
+
test("Python project with explicit pyproject pytest marker discovers pytest", () => {
|
|
267
|
+
writeFileSync(
|
|
268
|
+
join(tmp, "pyproject.toml"),
|
|
269
|
+
`[tool.pytest]
|
|
270
|
+
pythonpath = ["."]
|
|
271
|
+
`,
|
|
272
|
+
);
|
|
273
|
+
|
|
274
|
+
const result = discoverCommands({ cwd: tmp });
|
|
275
|
+
|
|
276
|
+
assert.equal(result.source, "python-project");
|
|
277
|
+
assert.deepStrictEqual(result.commands, ["python3 -m pytest"]);
|
|
278
|
+
});
|
|
279
|
+
|
|
280
|
+
test("Python project markers without pytest evidence do not discover pytest", () => {
|
|
281
|
+
mkdirSync(join(tmp, "tests"));
|
|
282
|
+
writeFileSync(join(tmp, "tests", "README.md"), "# tests\n");
|
|
283
|
+
writeFileSync(
|
|
284
|
+
join(tmp, "pyproject.toml"),
|
|
285
|
+
`[project]
|
|
286
|
+
name = "sample"
|
|
287
|
+
dependencies = ["pytest-cov"]
|
|
288
|
+
`,
|
|
289
|
+
);
|
|
290
|
+
|
|
291
|
+
const result = discoverCommands({ cwd: tmp });
|
|
292
|
+
|
|
293
|
+
assert.equal(result.source, "none");
|
|
294
|
+
assert.deepStrictEqual(result.commands, []);
|
|
295
|
+
});
|
|
296
|
+
|
|
297
|
+
test("Python project with setup.cfg alone does not discover pytest", () => {
|
|
298
|
+
writeFileSync(join(tmp, "setup.cfg"), "[tool:pytest]\npythonpath = .\n");
|
|
299
|
+
|
|
300
|
+
const result = discoverCommands({ cwd: tmp });
|
|
301
|
+
|
|
302
|
+
assert.equal(result.source, "none");
|
|
303
|
+
assert.deepStrictEqual(result.commands, []);
|
|
304
|
+
});
|
|
305
|
+
|
|
306
|
+
test("Python project with tox.ini alone does not discover pytest", () => {
|
|
307
|
+
writeFileSync(join(tmp, "tox.ini"), "[pytest]\npythonpath = .\n");
|
|
308
|
+
|
|
309
|
+
const result = discoverCommands({ cwd: tmp });
|
|
310
|
+
|
|
311
|
+
assert.equal(result.source, "none");
|
|
312
|
+
assert.deepStrictEqual(result.commands, []);
|
|
313
|
+
});
|
|
218
314
|
});
|
|
219
315
|
|
|
220
316
|
// ─── Execution Tests ─────────────────────────────────────────────────────────
|
|
@@ -445,6 +541,10 @@ test("isLikelyCommand: prose descriptions are rejected", () => {
|
|
|
445
541
|
assert.equal(isLikelyCommand("Build succeeds without errors or warnings"), false);
|
|
446
542
|
});
|
|
447
543
|
|
|
544
|
+
test("isLikelyCommand: non-ASCII prose descriptions are rejected", () => {
|
|
545
|
+
assert.equal(isLikelyCommand("所有 命令 输出 一行 JSONL go test ./... 通过"), false);
|
|
546
|
+
});
|
|
547
|
+
|
|
448
548
|
test("isLikelyCommand: empty or whitespace-only strings are rejected", () => {
|
|
449
549
|
assert.equal(isLikelyCommand(""), false);
|
|
450
550
|
assert.equal(isLikelyCommand(" "), false);
|
|
@@ -455,6 +555,15 @@ test("isLikelyCommand: short lowercase tokens without flags are accepted (could
|
|
|
455
555
|
assert.equal(isLikelyCommand("mycheck"), true);
|
|
456
556
|
});
|
|
457
557
|
|
|
558
|
+
test("validateVerificationCommand rejects shell control syntax", () => {
|
|
559
|
+
assert.deepEqual(validateVerificationCommand("python3 -m pytest tests/ -q --tb=short").ok, true);
|
|
560
|
+
const result = validateVerificationCommand("python3 -m pytest tests/ -q --tb=short 2>&1 | tail -5");
|
|
561
|
+
assert.equal(result.ok, false);
|
|
562
|
+
if (!result.ok) {
|
|
563
|
+
assert.match(result.reason, /shell control syntax/);
|
|
564
|
+
}
|
|
565
|
+
});
|
|
566
|
+
|
|
458
567
|
// ─── Additional Preference Validation Tests (T02) ──────────────────────────
|
|
459
568
|
|
|
460
569
|
test("verification-gate: verification_commands produces no unknown-key warnings", () => {
|
|
@@ -0,0 +1,78 @@
|
|
|
1
|
+
// Project/App: GSD-2
|
|
2
|
+
// File Purpose: Tests for host-owned auto-mode verification verdict policy.
|
|
3
|
+
|
|
4
|
+
import test from "node:test";
|
|
5
|
+
import assert from "node:assert/strict";
|
|
6
|
+
|
|
7
|
+
import { decideVerificationVerdict } from "../verification-verdict.ts";
|
|
8
|
+
import type { VerificationResult } from "../types.ts";
|
|
9
|
+
|
|
10
|
+
function makeResult(overrides: Partial<VerificationResult> = {}): VerificationResult {
|
|
11
|
+
return {
|
|
12
|
+
passed: true,
|
|
13
|
+
checks: [],
|
|
14
|
+
discoverySource: "none",
|
|
15
|
+
timestamp: 1,
|
|
16
|
+
...overrides,
|
|
17
|
+
};
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
test("execute-task fails closed when no host-owned checks are discovered", () => {
|
|
21
|
+
const verdict = decideVerificationVerdict("execute-task", makeResult());
|
|
22
|
+
|
|
23
|
+
assert.equal(verdict.passed, false);
|
|
24
|
+
assert.equal(verdict.reason, "no-host-checks");
|
|
25
|
+
assert.equal(verdict.retryable, false);
|
|
26
|
+
assert.match(verdict.failureContext, /No runnable host-owned verification command/);
|
|
27
|
+
});
|
|
28
|
+
|
|
29
|
+
test("non execute-task units preserve no-check pass semantics", () => {
|
|
30
|
+
const verdict = decideVerificationVerdict("plan-slice", makeResult());
|
|
31
|
+
|
|
32
|
+
assert.equal(verdict.passed, true);
|
|
33
|
+
assert.equal(verdict.reason, "passed");
|
|
34
|
+
});
|
|
35
|
+
|
|
36
|
+
test("execute-task command failure remains retryable verification failure", () => {
|
|
37
|
+
const verdict = decideVerificationVerdict(
|
|
38
|
+
"execute-task",
|
|
39
|
+
makeResult({
|
|
40
|
+
passed: false,
|
|
41
|
+
discoverySource: "package-json",
|
|
42
|
+
checks: [
|
|
43
|
+
{
|
|
44
|
+
command: "npm test",
|
|
45
|
+
exitCode: 1,
|
|
46
|
+
stdout: "",
|
|
47
|
+
stderr: "failed",
|
|
48
|
+
durationMs: 10,
|
|
49
|
+
},
|
|
50
|
+
],
|
|
51
|
+
}),
|
|
52
|
+
);
|
|
53
|
+
|
|
54
|
+
assert.equal(verdict.passed, false);
|
|
55
|
+
assert.equal(verdict.reason, "checks-failed");
|
|
56
|
+
assert.equal(verdict.retryable, true);
|
|
57
|
+
});
|
|
58
|
+
|
|
59
|
+
test("execute-task passes when a discovered host check succeeds", () => {
|
|
60
|
+
const verdict = decideVerificationVerdict(
|
|
61
|
+
"execute-task",
|
|
62
|
+
makeResult({
|
|
63
|
+
discoverySource: "preference",
|
|
64
|
+
checks: [
|
|
65
|
+
{
|
|
66
|
+
command: "npm test",
|
|
67
|
+
exitCode: 0,
|
|
68
|
+
stdout: "ok",
|
|
69
|
+
stderr: "",
|
|
70
|
+
durationMs: 10,
|
|
71
|
+
},
|
|
72
|
+
],
|
|
73
|
+
}),
|
|
74
|
+
);
|
|
75
|
+
|
|
76
|
+
assert.equal(verdict.passed, true);
|
|
77
|
+
assert.equal(verdict.reason, "passed");
|
|
78
|
+
});
|
|
@@ -375,7 +375,7 @@ test("workflow MCP launch config reaches mutation tools over stdio", async () =>
|
|
|
375
375
|
estimate: "10m",
|
|
376
376
|
files: ["src/resources/extensions/gsd/workflow-mcp.ts"],
|
|
377
377
|
verify: "node --test",
|
|
378
|
-
inputs: ["M001-ROADMAP.md"],
|
|
378
|
+
inputs: [".gsd/milestones/M001/M001-ROADMAP.md"],
|
|
379
379
|
expectedOutput: ["S01-PLAN.md", "T01-PLAN.md"],
|
|
380
380
|
},
|
|
381
381
|
],
|
|
@@ -4,7 +4,10 @@
|
|
|
4
4
|
import assert from "node:assert/strict";
|
|
5
5
|
import test from "node:test";
|
|
6
6
|
|
|
7
|
-
import {
|
|
7
|
+
import {
|
|
8
|
+
measureMemoryPressure,
|
|
9
|
+
shouldCheckMemoryPressure,
|
|
10
|
+
} from "../auto/workflow-memory-pressure.ts";
|
|
8
11
|
|
|
9
12
|
const mb = 1024 * 1024;
|
|
10
13
|
|
|
@@ -69,3 +72,20 @@ test("measureMemoryPressure falls back when heap limit cannot be read", () => {
|
|
|
69
72
|
pct: 0.25,
|
|
70
73
|
});
|
|
71
74
|
});
|
|
75
|
+
|
|
76
|
+
test("shouldCheckMemoryPressure covers the first auto-mode iteration", () => {
|
|
77
|
+
assert.equal(shouldCheckMemoryPressure(1, 5), true);
|
|
78
|
+
assert.equal(shouldCheckMemoryPressure(2, 5), false);
|
|
79
|
+
assert.equal(shouldCheckMemoryPressure(5, 5), true);
|
|
80
|
+
});
|
|
81
|
+
|
|
82
|
+
test("shouldCheckMemoryPressure rejects invalid intervals", () => {
|
|
83
|
+
assert.throws(
|
|
84
|
+
() => shouldCheckMemoryPressure(1, 0),
|
|
85
|
+
/positive integer/,
|
|
86
|
+
);
|
|
87
|
+
assert.throws(
|
|
88
|
+
() => shouldCheckMemoryPressure(1, 1.5),
|
|
89
|
+
/positive integer/,
|
|
90
|
+
);
|
|
91
|
+
});
|
|
@@ -246,7 +246,7 @@ test("executePlanSlice writes task planning state and rendered plan artifacts",
|
|
|
246
246
|
estimate: "15m",
|
|
247
247
|
files: ["src/resources/extensions/gsd/tools/workflow-tool-executors.ts"],
|
|
248
248
|
verify: "node --test",
|
|
249
|
-
inputs: ["ROADMAP.md"],
|
|
249
|
+
inputs: [".gsd/milestones/M001/M001-ROADMAP.md"],
|
|
250
250
|
expectedOutput: ["S01-PLAN.md", "T01-PLAN.md"],
|
|
251
251
|
},
|
|
252
252
|
],
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
import { describe, test } from "node:test";
|
|
2
|
+
import assert from "node:assert/strict";
|
|
3
|
+
import { mkdtempSync, mkdirSync, rmSync, writeFileSync, existsSync, realpathSync } from "node:fs";
|
|
4
|
+
import { join } from "node:path";
|
|
5
|
+
import { tmpdir } from "node:os";
|
|
6
|
+
import { execFileSync } from "node:child_process";
|
|
7
|
+
|
|
8
|
+
import { _gitPathspecForWorktreePath } from "../auto-worktree.ts";
|
|
9
|
+
|
|
10
|
+
function run(cmd: string, args: string[], cwd: string): string {
|
|
11
|
+
return execFileSync(cmd, args, { cwd, stdio: ["ignore", "pipe", "pipe"], encoding: "utf-8" }).trim();
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
describe("worktree git pathspec", () => {
|
|
15
|
+
test("skips external GSD bookkeeping directories outside the git work-tree", () => {
|
|
16
|
+
const root = realpathSync(mkdtempSync(join(tmpdir(), "gsd-pathspec-")));
|
|
17
|
+
const repo = join(root, "project");
|
|
18
|
+
const externalGsd = join(root, ".gsd", "projects", "abc123");
|
|
19
|
+
|
|
20
|
+
try {
|
|
21
|
+
mkdirSync(repo, { recursive: true });
|
|
22
|
+
mkdirSync(join(externalGsd, "milestones", "M002-wa00fm"), { recursive: true });
|
|
23
|
+
mkdirSync(join(externalGsd, "runtime", "units"), { recursive: true });
|
|
24
|
+
run("git", ["init"], repo);
|
|
25
|
+
writeFileSync(join(repo, "README.md"), "# test\n");
|
|
26
|
+
|
|
27
|
+
assert.equal(
|
|
28
|
+
_gitPathspecForWorktreePath(repo, join(externalGsd, "milestones", "M002-wa00fm")),
|
|
29
|
+
null,
|
|
30
|
+
);
|
|
31
|
+
assert.equal(
|
|
32
|
+
_gitPathspecForWorktreePath(repo, join(externalGsd, "runtime", "units")),
|
|
33
|
+
null,
|
|
34
|
+
);
|
|
35
|
+
} finally {
|
|
36
|
+
if (existsSync(root)) rmSync(root, { recursive: true, force: true });
|
|
37
|
+
}
|
|
38
|
+
});
|
|
39
|
+
});
|
|
@@ -30,11 +30,13 @@ function initGitRepoIn(base: string, isolation: "worktree" | "branch" | "none"):
|
|
|
30
30
|
}
|
|
31
31
|
import {
|
|
32
32
|
WorktreeLifecycle,
|
|
33
|
+
resetRecentWorktreeMergeFailuresForTest,
|
|
33
34
|
type WorktreeLifecycleDeps,
|
|
34
35
|
type NotifyCtx,
|
|
35
36
|
} from "../worktree-lifecycle.js";
|
|
36
37
|
import { WorktreeStateProjection } from "../worktree-state-projection.js";
|
|
37
38
|
import { type TaskCommitContext } from "../worktree.js";
|
|
39
|
+
import { MergeConflictError } from "../git-service.js";
|
|
38
40
|
|
|
39
41
|
// ADR-016 phase 2 / C-track retired all worktree-manager + cache + prefs
|
|
40
42
|
// fields from `WorktreeLifecycleDeps`. Tests still pass them as overrides
|
|
@@ -141,6 +143,20 @@ function readJournalEntries(basePath: string): JournalEntry[] {
|
|
|
141
143
|
}
|
|
142
144
|
}
|
|
143
145
|
|
|
146
|
+
function setupMergeWorktree(basePath: string, milestoneId: string): string {
|
|
147
|
+
initGitRepoIn(basePath, "worktree");
|
|
148
|
+
execFileSync("git", ["checkout", "-b", `milestone/${milestoneId}`], { cwd: basePath, stdio: "pipe" });
|
|
149
|
+
execFileSync("git", ["checkout", "main"], { cwd: basePath, stdio: "pipe" });
|
|
150
|
+
const wt = join(basePath, ".gsd", "worktrees", milestoneId);
|
|
151
|
+
execFileSync("git", ["worktree", "add", wt, `milestone/${milestoneId}`], { cwd: basePath, stdio: "pipe" });
|
|
152
|
+
mkdirSync(join(basePath, ".gsd", "milestones", milestoneId), { recursive: true });
|
|
153
|
+
writeFileSync(
|
|
154
|
+
join(basePath, ".gsd", "milestones", milestoneId, `${milestoneId}-ROADMAP.md`),
|
|
155
|
+
`# ${milestoneId}\n- [x] S01: Slice one\n`,
|
|
156
|
+
);
|
|
157
|
+
return wt;
|
|
158
|
+
}
|
|
159
|
+
|
|
144
160
|
// ─── Tests ───────────────────────────────────────────────────────────────────
|
|
145
161
|
|
|
146
162
|
describe("worktree journal events", () => {
|
|
@@ -148,6 +164,7 @@ describe("worktree journal events", () => {
|
|
|
148
164
|
const originalCwd = process.cwd();
|
|
149
165
|
|
|
150
166
|
beforeEach(() => {
|
|
167
|
+
resetRecentWorktreeMergeFailuresForTest();
|
|
151
168
|
// realpathSync to match what `auto-worktree.ts` returns from
|
|
152
169
|
// `resolveWorktreeProjectRoot` (macOS resolves `/var` → `/private/var`).
|
|
153
170
|
tmp = realpathSync(mkdtempSync(join(tmpdir(), "wt-journal-")));
|
|
@@ -284,17 +301,7 @@ describe("worktree journal events", () => {
|
|
|
284
301
|
});
|
|
285
302
|
|
|
286
303
|
test("mergeAndExit emits worktree-merge-failed on error", () => {
|
|
287
|
-
|
|
288
|
-
execFileSync("git", ["checkout", "-b", "milestone/M001"], { cwd: tmp, stdio: "pipe" });
|
|
289
|
-
execFileSync("git", ["checkout", "main"], { cwd: tmp, stdio: "pipe" });
|
|
290
|
-
const wt = join(tmp, ".gsd", "worktrees", "M001");
|
|
291
|
-
execFileSync("git", ["worktree", "add", wt, "milestone/M001"], { cwd: tmp, stdio: "pipe" });
|
|
292
|
-
mkdirSync(join(tmp, ".gsd", "milestones", "M001"), { recursive: true });
|
|
293
|
-
writeFileSync(
|
|
294
|
-
join(tmp, ".gsd", "milestones", "M001", "M001-ROADMAP.md"),
|
|
295
|
-
"# M001\n- [x] S01: Slice one\n",
|
|
296
|
-
);
|
|
297
|
-
|
|
304
|
+
const wt = setupMergeWorktree(tmp, "M001");
|
|
298
305
|
const s = makeSession({ basePath: wt, originalBasePath: tmp });
|
|
299
306
|
const deps = makeDeps({
|
|
300
307
|
mergeMilestoneToMain: () => { throw new Error("conflict in main"); },
|
|
@@ -318,11 +325,56 @@ describe("worktree journal events", () => {
|
|
|
318
325
|
);
|
|
319
326
|
}
|
|
320
327
|
|
|
328
|
+
new WorktreeLifecycle(s, deps).exitMilestone(
|
|
329
|
+
"M001",
|
|
330
|
+
{ merge: true },
|
|
331
|
+
makeNotifyCtx(),
|
|
332
|
+
);
|
|
333
|
+
|
|
321
334
|
const entries = readJournalEntries(tmp);
|
|
322
|
-
const
|
|
335
|
+
const failures = entries.filter(e => e.eventType === "worktree-merge-failed");
|
|
336
|
+
const failed = failures[0];
|
|
323
337
|
assert.ok(failed, "worktree-merge-failed event should be emitted");
|
|
324
338
|
assert.equal(failed!.data?.milestoneId, "M001");
|
|
325
339
|
assert.equal(failed!.data?.error, "conflict in main");
|
|
340
|
+
assert.equal(failures.length, 1, "duplicate merge failures are journaled once");
|
|
341
|
+
});
|
|
342
|
+
|
|
343
|
+
test("merge failure dedupe uses stable conflict category and expires", (t) => {
|
|
344
|
+
let now = 1_000_000;
|
|
345
|
+
t.mock.method(Date, "now", () => now);
|
|
346
|
+
const wt = setupMergeWorktree(tmp, "M001");
|
|
347
|
+
const s = makeSession({ basePath: wt, originalBasePath: tmp });
|
|
348
|
+
let attempt = 0;
|
|
349
|
+
const deps = makeDeps({
|
|
350
|
+
mergeMilestoneToMain: () => {
|
|
351
|
+
attempt += 1;
|
|
352
|
+
throw new MergeConflictError(
|
|
353
|
+
attempt === 1 ? ["src/a.ts"] : ["src/b.ts", "src/c.ts"],
|
|
354
|
+
"squash",
|
|
355
|
+
"milestone/M001",
|
|
356
|
+
"main",
|
|
357
|
+
);
|
|
358
|
+
},
|
|
359
|
+
});
|
|
360
|
+
const lifecycle = new WorktreeLifecycle(s, deps);
|
|
361
|
+
|
|
362
|
+
lifecycle.exitMilestone("M001", { merge: true }, makeNotifyCtx());
|
|
363
|
+
lifecycle.exitMilestone("M001", { merge: true }, makeNotifyCtx());
|
|
364
|
+
|
|
365
|
+
let failures = readJournalEntries(tmp).filter(e => e.eventType === "worktree-merge-failed");
|
|
366
|
+
assert.equal(failures.length, 1, "variable conflict filenames should not bypass dedupe");
|
|
367
|
+
assert.match(
|
|
368
|
+
String(failures[0]!.data?.error),
|
|
369
|
+
/src\/a\.ts/,
|
|
370
|
+
"journal payload keeps the original error message",
|
|
371
|
+
);
|
|
372
|
+
|
|
373
|
+
now += 60_001;
|
|
374
|
+
lifecycle.exitMilestone("M001", { merge: true }, makeNotifyCtx());
|
|
375
|
+
|
|
376
|
+
failures = readJournalEntries(tmp).filter(e => e.eventType === "worktree-merge-failed");
|
|
377
|
+
assert.equal(failures.length, 2, "same merge failure is journaled again after dedupe expiry");
|
|
326
378
|
});
|
|
327
379
|
|
|
328
380
|
test("journal entries have valid flowId, seq, and ts fields", () => {
|
|
@@ -538,6 +538,31 @@ test("restoreToProjectRoot is no-op when originalBasePath is empty", () => {
|
|
|
538
538
|
assert.equal(deps.calls.filter((c) => c.fn === "gitServiceFactory").length, 0);
|
|
539
539
|
});
|
|
540
540
|
|
|
541
|
+
test("restoreToProjectRoot completes session-state restore even when chdir fails (ADR-016 phase 3, #5693)", () => {
|
|
542
|
+
// The verb attempts process.chdir to s.basePath after restoring it. The
|
|
543
|
+
// chdir is best-effort; failure must not abort the session-state restore.
|
|
544
|
+
// We exercise that contract by pointing originalBasePath at a path that
|
|
545
|
+
// cannot be chdir'd into.
|
|
546
|
+
const s = makeSession();
|
|
547
|
+
s.originalBasePath = "/this/path/should/not/exist/in/any/test/env";
|
|
548
|
+
s.basePath = "/project/.gsd/worktrees/M001";
|
|
549
|
+
const deps = makeDeps();
|
|
550
|
+
const lifecycle = new WorktreeLifecycle(s, deps);
|
|
551
|
+
|
|
552
|
+
// Capture cwd so we can confirm we did NOT successfully chdir.
|
|
553
|
+
const cwdBefore = process.cwd();
|
|
554
|
+
lifecycle.restoreToProjectRoot();
|
|
555
|
+
|
|
556
|
+
// Session-state restore happened despite chdir failure.
|
|
557
|
+
assert.equal(s.basePath, "/this/path/should/not/exist/in/any/test/env");
|
|
558
|
+
assert.equal(
|
|
559
|
+
deps.calls.filter((c) => c.fn === "gitServiceFactory").length,
|
|
560
|
+
1,
|
|
561
|
+
);
|
|
562
|
+
// cwd is unchanged because chdir threw and was swallowed.
|
|
563
|
+
assert.equal(process.cwd(), cwdBefore);
|
|
564
|
+
});
|
|
565
|
+
|
|
541
566
|
// ─── adoptSessionRoot (ADR-016 phase 2 / B2, issue #5620) ─────────────────────
|
|
542
567
|
|
|
543
568
|
test("adoptSessionRoot sets basePath and seeds originalBasePath on a fresh session", () => {
|