gsd-pi 2.82.0-dev.c22380fc3 → 2.82.0-dev.e7a7f1ed5
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 +5 -4
- 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/claude-code-cli/stream-adapter.js +1 -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 +11 -0
- package/dist/resources/extensions/gsd/auto/phases.js +81 -31
- 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-direct-dispatch.js +1 -0
- package/dist/resources/extensions/gsd/auto-dispatch.js +18 -17
- 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 +71 -14
- package/dist/resources/extensions/gsd/auto-start.js +87 -14
- package/dist/resources/extensions/gsd/auto-verification.js +45 -26
- package/dist/resources/extensions/gsd/auto-worktree.js +176 -10
- package/dist/resources/extensions/gsd/auto.js +37 -5
- package/dist/resources/extensions/gsd/bootstrap/agent-end-recovery.js +31 -7
- package/dist/resources/extensions/gsd/bootstrap/db-tools.js +9 -8
- package/dist/resources/extensions/gsd/bootstrap/register-hooks.js +4 -2
- 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/commands-prefs-wizard.js +7 -2
- package/dist/resources/extensions/gsd/crash-recovery.js +43 -5
- package/dist/resources/extensions/gsd/db/milestone-leases.js +24 -0
- 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-git-checks.js +46 -1
- 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 +45 -3
- package/dist/resources/extensions/gsd/gsd-db.js +21 -6
- package/dist/resources/extensions/gsd/guided-flow-queue.js +4 -3
- package/dist/resources/extensions/gsd/guided-flow.js +101 -116
- package/dist/resources/extensions/gsd/guided-unit-context.js +23 -0
- package/dist/resources/extensions/gsd/migrate/parsers.js +10 -0
- 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/queue-reorder-ui.js +30 -13
- 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 +11 -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/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-mcp.js +17 -1
- package/dist/resources/extensions/gsd/workflow-projections.js +6 -8
- package/dist/resources/extensions/gsd/worktree-lifecycle.js +33 -8
- 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 +13 -13
- 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/browse-directories/route.js +1 -1
- 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 +13 -13
- 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/mcp-server/src/workflow-tools.test.ts +1 -1
- package/packages/native/tsconfig.json +2 -1
- package/packages/native/tsconfig.tsbuildinfo +1 -1
- package/packages/pi-ai/dist/providers/google-gemini-cli.d.ts.map +1 -1
- package/packages/pi-ai/dist/providers/google-gemini-cli.js +5 -0
- package/packages/pi-ai/dist/providers/google-gemini-cli.js.map +1 -1
- package/packages/pi-ai/dist/providers/google-gemini-cli.test.d.ts +2 -0
- package/packages/pi-ai/dist/providers/google-gemini-cli.test.d.ts.map +1 -0
- package/packages/pi-ai/dist/providers/google-gemini-cli.test.js +41 -0
- package/packages/pi-ai/dist/providers/google-gemini-cli.test.js.map +1 -0
- 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/google-gemini-cli.test.ts +49 -0
- package/packages/pi-ai/src/providers/google-gemini-cli.ts +7 -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/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/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/modes/interactive/components/footer.ts +23 -7
- package/packages/pi-coding-agent/tsconfig.tsbuildinfo +1 -1
- package/packages/pi-tui/dist/__tests__/terminal.test.d.ts +2 -0
- package/packages/pi-tui/dist/__tests__/terminal.test.d.ts.map +1 -0
- package/packages/pi-tui/dist/__tests__/terminal.test.js +103 -0
- package/packages/pi-tui/dist/__tests__/terminal.test.js.map +1 -0
- package/packages/pi-tui/dist/terminal.d.ts +2 -0
- package/packages/pi-tui/dist/terminal.d.ts.map +1 -1
- package/packages/pi-tui/dist/terminal.js +12 -0
- package/packages/pi-tui/dist/terminal.js.map +1 -1
- package/packages/pi-tui/src/__tests__/terminal.test.ts +121 -0
- package/packages/pi-tui/src/terminal.ts +11 -0
- package/packages/pi-tui/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/stream-adapter.ts +1 -1
- package/src/resources/extensions/claude-code-cli/tests/partial-builder.test.ts +19 -2
- package/src/resources/extensions/claude-code-cli/tests/stream-adapter.test.ts +9 -0
- package/src/resources/extensions/cmux/index.ts +6 -0
- package/src/resources/extensions/gsd/auto/contracts.ts +14 -6
- 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 +11 -0
- package/src/resources/extensions/gsd/auto/phases.ts +90 -38
- 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-direct-dispatch.ts +1 -0
- package/src/resources/extensions/gsd/auto-dispatch.ts +19 -17
- 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 +74 -11
- package/src/resources/extensions/gsd/auto-start.ts +94 -12
- package/src/resources/extensions/gsd/auto-verification.ts +58 -36
- package/src/resources/extensions/gsd/auto-worktree.ts +193 -10
- package/src/resources/extensions/gsd/auto.ts +40 -5
- package/src/resources/extensions/gsd/bootstrap/agent-end-recovery.ts +42 -7
- package/src/resources/extensions/gsd/bootstrap/db-tools.ts +9 -8
- package/src/resources/extensions/gsd/bootstrap/register-hooks.ts +4 -2
- 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/commands-prefs-wizard.ts +8 -3
- package/src/resources/extensions/gsd/crash-recovery.ts +44 -4
- package/src/resources/extensions/gsd/db/milestone-leases.ts +26 -0
- 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-git-checks.ts +45 -1
- package/src/resources/extensions/gsd/doctor-runtime-checks.ts +25 -13
- package/src/resources/extensions/gsd/doctor-types.ts +1 -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 +51 -4
- package/src/resources/extensions/gsd/gsd-db.ts +21 -6
- package/src/resources/extensions/gsd/guided-flow-queue.ts +4 -3
- package/src/resources/extensions/gsd/guided-flow.ts +134 -133
- package/src/resources/extensions/gsd/guided-unit-context.ts +30 -0
- package/src/resources/extensions/gsd/migrate/parsers.ts +11 -0
- 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/queue-reorder-ui.ts +31 -13
- 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 +13 -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-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 +56 -0
- package/src/resources/extensions/gsd/tests/auto-orchestrator.test.ts +80 -1
- package/src/resources/extensions/gsd/tests/auto-paused-ui-cleanup.test.ts +35 -7
- 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 +91 -6
- package/src/resources/extensions/gsd/tests/auto-start-orphan-bootstrap.test.ts +1 -0
- package/src/resources/extensions/gsd/tests/auto-stop-notification.test.ts +20 -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/checkout-branch-stash-guard.test.ts +87 -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/crash-recovery-via-db.test.ts +86 -2
- package/src/resources/extensions/gsd/tests/custom-engine-loop-integration.test.ts +2 -0
- 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 +66 -0
- package/src/resources/extensions/gsd/tests/dispatch-guard.test.ts +27 -0
- package/src/resources/extensions/gsd/tests/doctor-empty-worktree.test.ts +65 -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/gsd-db.test.ts +11 -0
- 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-runtime.test.ts +20 -0
- package/src/resources/extensions/gsd/tests/integration/git-service.test.ts +112 -1
- package/src/resources/extensions/gsd/tests/integration/state-machine-runtime-failures.test.ts +6 -1
- package/src/resources/extensions/gsd/tests/journal-integration.test.ts +46 -0
- package/src/resources/extensions/gsd/tests/merge-db-cycle.test.ts +179 -0
- package/src/resources/extensions/gsd/tests/migrate-validator-parsers.test.ts +24 -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.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/prefs-wizard-coverage.test.ts +59 -0
- package/src/resources/extensions/gsd/tests/prompt-loader.test.ts +23 -0
- package/src/resources/extensions/gsd/tests/provider-errors.test.ts +37 -1
- package/src/resources/extensions/gsd/tests/queue-reorder-ui.test.ts +54 -0
- package/src/resources/extensions/gsd/tests/remediation-completion-guard.test.ts +89 -2
- package/src/resources/extensions/gsd/tests/run-uat-replay-cap.test.ts +2 -3
- 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-reconciliation-drift.test.ts +119 -23
- package/src/resources/extensions/gsd/tests/status-guards.test.ts +13 -1
- 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/validate-milestone-stuck-guard.test.ts +29 -2
- 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 +19 -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/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/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-mcp.ts +18 -1
- package/src/resources/extensions/gsd/workflow-projections.ts +6 -8
- package/src/resources/extensions/gsd/worktree-lifecycle.ts +41 -8
- 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/{Wop3A7KRGyR06H3rla_1- → 4dSwdrs__8NwCZggxP9KF}/_buildManifest.js +0 -0
- /package/dist/web/standalone/.next/static/{Wop3A7KRGyR06H3rla_1- → 4dSwdrs__8NwCZggxP9KF}/_ssgManifest.js +0 -0
package/README.md
CHANGED
|
@@ -336,7 +336,7 @@ Plan (with integrated research) → Execute (per task) → Complete → Reassess
|
|
|
336
336
|
Validate Milestone → Complete Milestone
|
|
337
337
|
```
|
|
338
338
|
|
|
339
|
-
**Plan** scouts the codebase, researches relevant docs, and decomposes the slice into tasks with must-haves (mechanically verifiable outcomes). **Execute** runs each task in a fresh context window with only the relevant files pre-loaded
|
|
339
|
+
**Plan** scouts the codebase, researches relevant docs, and decomposes the slice into tasks with must-haves (mechanically verifiable outcomes). **Execute** runs each task in a fresh context window with only the relevant files pre-loaded, then runs configured verification commands (lint, test, etc.) with auto-fix retries before the task closeout commit or snapshot is published. Failed or incomplete verification blocks execute-task closeout. **Complete** writes the summary, UAT script, marks the roadmap, and commits with meaningful messages derived from task summaries. **Reassess** checks if the roadmap still makes sense given what was learned. **Validate Milestone** runs a reconciliation gate after all slices complete — comparing roadmap success criteria against actual results before sealing the milestone.
|
|
340
340
|
|
|
341
341
|
When progressive planning is enabled, the first slice is fully planned up front while later slices may appear in `M###-ROADMAP.md` with a `` `[sketch]` `` badge. A sketch slice has an approved title, dependency shape, demo line, and scope boundary, but it has not yet been expanded into task plans; auto mode runs `refine-slice` just before execution to turn the sketch into a full slice plan using the latest prior-slice summaries.
|
|
342
342
|
|
|
@@ -376,7 +376,7 @@ The database is authoritative for milestones, slices, tasks, requirements, summa
|
|
|
376
376
|
|
|
377
377
|
10. **Adaptive replanning** — After each slice completes, the roadmap is reassessed. If the work revealed new information that changes the plan, slices are reordered, added, or removed before continuing.
|
|
378
378
|
|
|
379
|
-
11. **Verification enforcement** — Configure
|
|
379
|
+
11. **Verification enforcement** — Configure simple executable commands (`npm run lint`, `npm run test`, etc.) that run automatically after task execution. Verification commands must not use shell composition or control syntax such as pipes, redirects, semicolons, backticks, or command substitution. Failures trigger auto-fix retries before advancing. Execute-task commits and snapshots are deferred until verification passes; failed or incomplete verification blocks closeout instead of publishing changes. Auto-discovered checks from `package.json` and Python pytest project markers (`python-project`) run in advisory mode — they log warnings but don't block on pre-existing errors. Configurable via `verification_commands`, `verification_auto_fix`, and `verification_max_retries` preferences.
|
|
380
380
|
|
|
381
381
|
12. **Milestone validation** — After all slices complete, a `validate-milestone` gate compares roadmap success criteria against actual results before sealing the milestone.
|
|
382
382
|
|
|
@@ -502,7 +502,8 @@ On first run, GSD launches a branded setup wizard that walks you through LLM pro
|
|
|
502
502
|
| `/gsd rethink` | Conversational project reorganization |
|
|
503
503
|
| `/gsd mcp` | MCP server status and connectivity |
|
|
504
504
|
| `/gsd status` | Progress dashboard |
|
|
505
|
-
| `/gsd
|
|
505
|
+
| `/gsd brief <mode>` | Generate a visual HTML brief (diagram, plan, diff, recap, table, slides) |
|
|
506
|
+
| `/gsd queue` | Queue/reorder future milestones (`pending`, `queued`, or legacy `planned`; safe during auto mode) |
|
|
506
507
|
| `/gsd prefs` | Model selection, timeouts, budget ceiling |
|
|
507
508
|
| `/gsd migrate` | Migrate a v1 `.planning` directory to `.gsd` format |
|
|
508
509
|
| `/gsd help` | Categorized command reference for all GSD subcommands |
|
|
@@ -669,7 +670,7 @@ auto_report: true
|
|
|
669
670
|
| `context_mode.exec_stdout_cap_bytes` | Persisted stdout cap for `gsd_exec` output (default: 1048576) |
|
|
670
671
|
| `context_mode.exec_digest_chars` | Trailing stdout characters returned to the agent context (default: 300) |
|
|
671
672
|
| `context_mode.exec_env_allowlist` | Environment variables forwarded to sandboxed `gsd_exec` runs in addition to `PATH` and `HOME` |
|
|
672
|
-
| `verification_commands` | Array of
|
|
673
|
+
| `verification_commands` | Array of simple executable commands to run after task execution (e.g., `["npm run lint", "npm run test"]`); avoid pipes, redirects, semicolons, backticks, and command substitution |
|
|
673
674
|
| `verification_auto_fix` | Auto-retry on verification failures (default: true) |
|
|
674
675
|
| `verification_max_retries` | Max retries for verification failures (default: 2) |
|
|
675
676
|
| `phases.require_slice_discussion` | Pause auto-mode before each slice for human discussion review |
|
|
@@ -1 +1 @@
|
|
|
1
|
-
|
|
1
|
+
68e342bd44fe9191
|
|
@@ -448,6 +448,13 @@ What differed from the plan and why (or "None").
|
|
|
448
448
|
|
|
449
449
|
The one-liner must be substantive: "JWT auth with refresh rotation using jose" not "Authentication implemented."
|
|
450
450
|
|
|
451
|
+
When `key_files` or `key_decisions` are empty, render them as empty YAML lists:
|
|
452
|
+
|
|
453
|
+
```yaml
|
|
454
|
+
key_files: []
|
|
455
|
+
key_decisions: []
|
|
456
|
+
```
|
|
457
|
+
|
|
451
458
|
**Slice summary:** Written when all tasks in a slice complete. Compresses all task summaries. Includes `drill_down_paths` to each task summary. During slice completion, review task summaries for `key_decisions` and ensure any significant ones are captured in `.gsd/DECISIONS.md`.
|
|
452
459
|
|
|
453
460
|
**Milestone summary:** Updated each time a slice completes. Compresses all slice summaries. This is what gets injected into later slice planning instead of loading many individual summaries.
|
|
@@ -560,7 +567,7 @@ In all modes, slices and tasks commit sequentially on the active branch; there a
|
|
|
560
567
|
|
|
561
568
|
1. **Milestone starts** → capture the current integration branch.
|
|
562
569
|
2. **Optional isolation** → create `milestone/M001` only when `git.isolation` is `worktree` or `branch`.
|
|
563
|
-
3. **Per-task commits** — atomic, descriptive, bisectable.
|
|
570
|
+
3. **Per-task commits** — atomic, descriptive, bisectable, and published only after execute-task verification passes.
|
|
564
571
|
4. **Slice completes** → write slice summary, UAT script, roadmap checkbox, and milestone summary.
|
|
565
572
|
5. **Milestone completes** → if isolated, squash-merge the milestone branch back to the captured integration branch and clean up the worktree/branch.
|
|
566
573
|
|
|
@@ -574,6 +581,8 @@ fix: handle empty state rebuild
|
|
|
574
581
|
|
|
575
582
|
In `none` mode these commits land directly on the current branch. In isolated modes they land on `milestone/<MID>` and are squashed back at milestone completion.
|
|
576
583
|
|
|
584
|
+
Execute-task closeout is fail-closed: the system writes verification evidence first, defers the task commit or snapshot until verification passes, and pauses instead of publishing changes when verification fails or cannot complete.
|
|
585
|
+
|
|
577
586
|
### Commit Conventions
|
|
578
587
|
|
|
579
588
|
| When | Format | Example |
|
|
@@ -105,9 +105,10 @@ export function mapUsage(sdkUsage, totalCostUsd) {
|
|
|
105
105
|
output: sdkUsage.output_tokens,
|
|
106
106
|
cacheRead: sdkUsage.cache_read_input_tokens,
|
|
107
107
|
cacheWrite: sdkUsage.cache_creation_input_tokens,
|
|
108
|
+
// Claude Agent SDK result usage is cumulative across its internal loop;
|
|
109
|
+
// repeated cache reads do not represent additional live context.
|
|
108
110
|
totalTokens: sdkUsage.input_tokens +
|
|
109
111
|
sdkUsage.output_tokens +
|
|
110
|
-
sdkUsage.cache_read_input_tokens +
|
|
111
112
|
sdkUsage.cache_creation_input_tokens,
|
|
112
113
|
cost: {
|
|
113
114
|
input: 0,
|
|
@@ -269,7 +269,7 @@ function makeErrorMessage(model, errorMsg) {
|
|
|
269
269
|
export function isClaudeCodeAbortErrorMessage(message) {
|
|
270
270
|
if (!message)
|
|
271
271
|
return false;
|
|
272
|
-
return /\b(?:claude code process aborted by user|request aborted by user|process aborted by user)\b/i.test(message);
|
|
272
|
+
return /\b(?:claude code process aborted by user|request aborted by user|process aborted by user|aborterror)\b/i.test(message);
|
|
273
273
|
}
|
|
274
274
|
function isBareClaudeCodeAbortErrorMessage(message) {
|
|
275
275
|
if (!message)
|
|
@@ -319,6 +319,11 @@ export class CmuxClient {
|
|
|
319
319
|
const stdout = await this.runAsync(["send-surface", "--surface", surfaceId, payload]);
|
|
320
320
|
return stdout !== null;
|
|
321
321
|
}
|
|
322
|
+
// Send Ctrl-C (ETX) to a surface to interrupt the running command.
|
|
323
|
+
async sendInterrupt(surfaceId) {
|
|
324
|
+
const stdout = await this.runAsync(["send-surface", "--surface", surfaceId, "\x03"]);
|
|
325
|
+
return stdout !== null;
|
|
326
|
+
}
|
|
322
327
|
}
|
|
323
328
|
export function syncCmuxSidebar(preferences, state) {
|
|
324
329
|
const client = CmuxClient.fromPreferences(preferences);
|
|
@@ -6,9 +6,14 @@
|
|
|
6
6
|
* failures that merit retry.
|
|
7
7
|
*/
|
|
8
8
|
/**
|
|
9
|
-
* Error codes indicating infrastructure failures
|
|
10
|
-
*
|
|
11
|
-
*
|
|
9
|
+
* Error codes indicating infrastructure-level failures from the OS,
|
|
10
|
+
* filesystem, or network. This set includes permanent resource failures
|
|
11
|
+
* (ENOSPC, ENOMEM, EROFS), transient resource exhaustion (EAGAIN, ENOBUFS),
|
|
12
|
+
* and network/offline errors (ECONNREFUSED, ENOTFOUND, ENETUNREACH).
|
|
13
|
+
*
|
|
14
|
+
* Transient git failures are retried separately through
|
|
15
|
+
* TRANSIENT_GIT_RETRY_CODES in native-git-bridge.ts before escalating to the
|
|
16
|
+
* auto-loop.
|
|
12
17
|
*/
|
|
13
18
|
export const INFRA_ERROR_CODES = new Set([
|
|
14
19
|
"ENOSPC", // disk full
|
|
@@ -18,6 +23,7 @@ export const INFRA_ERROR_CODES = new Set([
|
|
|
18
23
|
"EMFILE", // too many open files (process)
|
|
19
24
|
"ENFILE", // too many open files (system)
|
|
20
25
|
"EAGAIN", // resource temporarily unavailable (resource exhaustion)
|
|
26
|
+
"ENOBUFS", // no buffer space available (transient pipe exhaustion)
|
|
21
27
|
"ECONNREFUSED", // connection refused (offline / local server down)
|
|
22
28
|
"ENOTFOUND", // DNS lookup failed (offline / no network)
|
|
23
29
|
"ENETUNREACH", // network unreachable (offline / no route)
|
|
@@ -35,7 +35,7 @@ import { createWorkflowTurnReporter } from "./workflow-turn-reporter.js";
|
|
|
35
35
|
import { validateWorkflowSessionLock } from "./workflow-session-lock.js";
|
|
36
36
|
import { dequeueSidecarItem } from "./workflow-sidecar-queue.js";
|
|
37
37
|
import { maintainWorkerHeartbeat } from "./workflow-worker-heartbeat.js";
|
|
38
|
-
import { measureMemoryPressure } from "./workflow-memory-pressure.js";
|
|
38
|
+
import { measureMemoryPressure, shouldCheckMemoryPressure, } from "./workflow-memory-pressure.js";
|
|
39
39
|
import { buildSidecarIterationData } from "./workflow-sidecar-iteration.js";
|
|
40
40
|
import { createExecutionGraphUnitDispatchDeps, runUnitPhaseViaContract, } from "./workflow-unit-dispatch.js";
|
|
41
41
|
import { handleCustomEngineDispatchOutcome } from "./workflow-custom-engine-dispatch-outcome.js";
|
|
@@ -130,9 +130,9 @@ function logCustomVerifyRetrySaveFailure(err) {
|
|
|
130
130
|
});
|
|
131
131
|
}
|
|
132
132
|
// ── Memory pressure monitoring (#3331) ──────────────────────────────────
|
|
133
|
-
// Check heap usage every N iterations and trigger
|
|
134
|
-
// the OS OOM killer sends SIGKILL. The threshold is
|
|
135
|
-
// limit (--max-old-space-size or default ~1.5-4GB depending on platform).
|
|
133
|
+
// Check heap usage on session startup, then every N iterations, and trigger
|
|
134
|
+
// graceful shutdown before the OS OOM killer sends SIGKILL. The threshold is
|
|
135
|
+
// 90% of the V8 heap limit (--max-old-space-size or default ~1.5-4GB depending on platform).
|
|
136
136
|
const MEMORY_CHECK_INTERVAL = 5; // check every 5 iterations
|
|
137
137
|
const MAX_CUSTOM_ENGINE_VERIFY_RETRIES = 3;
|
|
138
138
|
async function enforceMinRequestInterval(s, prefs) {
|
|
@@ -262,7 +262,7 @@ export async function autoLoop(ctx, pi, s, deps, options) {
|
|
|
262
262
|
}
|
|
263
263
|
// ── Memory pressure check (#3331) ──
|
|
264
264
|
// Graceful shutdown before OOM killer sends SIGKILL.
|
|
265
|
-
if (iteration
|
|
265
|
+
if (shouldCheckMemoryPressure(iteration, MEMORY_CHECK_INTERVAL)) {
|
|
266
266
|
const mem = measureMemoryPressure();
|
|
267
267
|
debugLog("autoLoop", { phase: "memory-check", ...mem });
|
|
268
268
|
const memoryDecision = decideMemoryPressure({ ...mem, iteration });
|
|
@@ -117,6 +117,17 @@ export class AutoOrchestrator {
|
|
|
117
117
|
await this.deps.health.postAdvanceRecord(stopped);
|
|
118
118
|
return stopped;
|
|
119
119
|
}
|
|
120
|
+
if (!("unitType" in decision)) {
|
|
121
|
+
const blocked = {
|
|
122
|
+
kind: "blocked",
|
|
123
|
+
reason: decision.reason,
|
|
124
|
+
action: decision.action,
|
|
125
|
+
stateSnapshot: reconciliation.stateSnapshot,
|
|
126
|
+
};
|
|
127
|
+
await this.deps.runtime.journalTransition({ name: "advance-blocked", reason: blocked.reason });
|
|
128
|
+
await this.deps.health.postAdvanceRecord(blocked);
|
|
129
|
+
return blocked;
|
|
130
|
+
}
|
|
120
131
|
const nextKey = `${decision.unitType}:${decision.unitId}`;
|
|
121
132
|
// Record every dispatch decision in the ring buffer before pre-flight
|
|
122
133
|
// checks so the stuck-loop detector observes the full decision history
|
|
@@ -44,6 +44,7 @@ import { resolveManifest } from "../unit-context-manifest.js";
|
|
|
44
44
|
import { createWorktreeSafetyModule } from "../worktree-safety.js";
|
|
45
45
|
import { isSuspiciousGhostCompletion } from "../auto-unit-closeout.js";
|
|
46
46
|
import { decideVerificationRetry, verificationRetryKey } from "./verification-retry-policy.js";
|
|
47
|
+
import { buildPhaseHandoffOutcome, setAutoOutcomeWidget } from "../auto-dashboard.js";
|
|
47
48
|
// ─── Path Comparison Helper ───────────────────────────────────────────────
|
|
48
49
|
/** Compare two paths for physical identity, tolerating trailing slashes and symlinks. */
|
|
49
50
|
function isSamePathLocal(a, b) {
|
|
@@ -103,6 +104,12 @@ function unitWritesSource(unitType) {
|
|
|
103
104
|
function formatWorktreeSafetyFailure(result) {
|
|
104
105
|
return `Worktree Safety failed (${result.kind}): ${result.reason} ${result.remediation}`;
|
|
105
106
|
}
|
|
107
|
+
function formatWorktreeSafetyStopReason(result) {
|
|
108
|
+
if (result.kind === "empty-worktree-with-project-content") {
|
|
109
|
+
return `Worktree Safety failed (${result.kind}). Run /gsd doctor fix, then /gsd auto.`;
|
|
110
|
+
}
|
|
111
|
+
return `Worktree Safety failed (${result.kind}).`;
|
|
112
|
+
}
|
|
106
113
|
function resolveEmptyWorktreeWithProjectContent(unitRoot, projectRoot) {
|
|
107
114
|
if (isSamePathLocal(unitRoot, projectRoot))
|
|
108
115
|
return false;
|
|
@@ -176,7 +183,7 @@ async function validateSourceWriteWorktreeSafety(ic, unitType, unitId, milestone
|
|
|
176
183
|
projectRoot,
|
|
177
184
|
});
|
|
178
185
|
ctx.ui.notify(msg, "error");
|
|
179
|
-
await deps.stopAuto(ctx, pi,
|
|
186
|
+
await deps.stopAuto(ctx, pi, formatWorktreeSafetyStopReason(result));
|
|
180
187
|
return { action: "break", reason: result.kind };
|
|
181
188
|
}
|
|
182
189
|
// ─── Session timeout auto-resume state ────────────────────────────────────────
|
|
@@ -968,7 +975,14 @@ export async function runDispatch(ic, preData, loopState) {
|
|
|
968
975
|
prompt = preDispatchResult.prompt;
|
|
969
976
|
}
|
|
970
977
|
const guardBasePath = _resolveDispatchGuardBasePath(s);
|
|
971
|
-
|
|
978
|
+
let mainBranch = "main";
|
|
979
|
+
try {
|
|
980
|
+
mainBranch = deps.getMainBranch(guardBasePath);
|
|
981
|
+
}
|
|
982
|
+
catch (err) {
|
|
983
|
+
debugLog("autoLoop", { phase: "getMainBranch-failed", error: String(err) });
|
|
984
|
+
}
|
|
985
|
+
const priorSliceBlocker = deps.getPriorSliceCompletionBlocker(guardBasePath, mainBranch, unitType, unitId);
|
|
972
986
|
if (priorSliceBlocker) {
|
|
973
987
|
await deps.stopAuto(ctx, pi, priorSliceBlocker);
|
|
974
988
|
debugLog("autoLoop", { phase: "exit", reason: "prior-slice-blocker" });
|
|
@@ -1324,35 +1338,8 @@ export async function runUnitPhase(ic, iterData, loopState, sidecarItem) {
|
|
|
1324
1338
|
s.currentUnit.type === unitType &&
|
|
1325
1339
|
s.currentUnit.id === unitId);
|
|
1326
1340
|
const previousTier = s.currentUnitRouting?.tier;
|
|
1327
|
-
// Scope workflow-logger buffer to this unit so post-finalize drains are
|
|
1328
|
-
// per-unit. Without this, the module-level _buffer accumulates across every
|
|
1329
|
-
// unit in the same Node process (see workflow-logger.ts module header).
|
|
1330
|
-
_resetLogs();
|
|
1331
1341
|
const dispatchKey = `${unitType}/${unitId}`;
|
|
1332
|
-
|
|
1333
|
-
s.currentUnit = { type: unitType, id: unitId, startedAt: Date.now() };
|
|
1334
|
-
s.lastGitActionFailure = null;
|
|
1335
|
-
s.lastGitActionStatus = null;
|
|
1336
|
-
s.lastUnitAgentEndMessages = null;
|
|
1337
|
-
setCurrentPhase(unitType, {
|
|
1338
|
-
basePath: s.basePath,
|
|
1339
|
-
traceId: ic.flowId,
|
|
1340
|
-
turnId: `iter-${ic.iteration}`,
|
|
1341
|
-
causedBy: "unit-start",
|
|
1342
|
-
});
|
|
1343
|
-
s.lastToolInvocationError = null; // #2883: clear stale error from previous unit
|
|
1344
|
-
const unitStartSeq = ic.nextSeq();
|
|
1345
|
-
deps.emitJournalEvent({ ts: new Date().toISOString(), flowId: ic.flowId, seq: unitStartSeq, eventType: "unit-start", data: { unitType, unitId } });
|
|
1346
|
-
deps.captureAvailableSkills();
|
|
1347
|
-
writeUnitRuntimeRecord(s.basePath, unitType, unitId, s.currentUnit.startedAt, {
|
|
1348
|
-
phase: "dispatched",
|
|
1349
|
-
wrapupWarningSent: false,
|
|
1350
|
-
timeoutAt: null,
|
|
1351
|
-
lastProgressAt: s.currentUnit.startedAt,
|
|
1352
|
-
progressCount: 0,
|
|
1353
|
-
lastProgressKind: "dispatch",
|
|
1354
|
-
recoveryAttempts: 0, // Reset so re-dispatched units get full recovery budget (#2322)
|
|
1355
|
-
});
|
|
1342
|
+
const nextDispatchCount = (s.unitDispatchCount.get(dispatchKey) ?? 0) + 1;
|
|
1356
1343
|
// Status bar (widget + preconditions deferred until after model selection — see #2899)
|
|
1357
1344
|
ctx.ui.setStatus("gsd-auto", "auto");
|
|
1358
1345
|
if (mid)
|
|
@@ -1406,7 +1393,7 @@ export async function runUnitPhase(ic, iterData, loopState, sidecarItem) {
|
|
|
1406
1393
|
finalPrompt = `${capped}\n\n---\n\n${finalPrompt}`;
|
|
1407
1394
|
s.pendingCrashRecovery = null;
|
|
1408
1395
|
}
|
|
1409
|
-
else if (
|
|
1396
|
+
else if (nextDispatchCount > 1) {
|
|
1410
1397
|
const diagnostic = deps.getDeepDiagnostic(s.basePath);
|
|
1411
1398
|
if (diagnostic) {
|
|
1412
1399
|
const cappedDiag = diagnostic.length > MAX_RECOVERY_CHARS
|
|
@@ -1445,6 +1432,11 @@ export async function runUnitPhase(ic, iterData, loopState, sidecarItem) {
|
|
|
1445
1432
|
logWarning("engine", "Prompt reorder failed", { error: msg });
|
|
1446
1433
|
}
|
|
1447
1434
|
// Select and apply model (with tier escalation on retry — normal units only)
|
|
1435
|
+
const prevUnitRouting = s.currentUnitRouting;
|
|
1436
|
+
const prevUnitModel = s.currentUnitModel;
|
|
1437
|
+
const prevDispatchedModelId = s.currentDispatchedModelId;
|
|
1438
|
+
const prevSessionModel = ctx.model;
|
|
1439
|
+
const prevSessionThinkingLevel = pi.getThinkingLevel();
|
|
1448
1440
|
const modelResult = await deps.selectAndApplyModel(ctx, pi, unitType, unitId, s.basePath, prefs, s.verbose, s.autoModeStartModel, sidecarItem ? undefined : { isRetry, previousTier }, undefined, s.manualSessionModelOverride, s.autoModeStartThinkingLevel);
|
|
1449
1441
|
s.currentUnitRouting =
|
|
1450
1442
|
modelResult.routing;
|
|
@@ -1488,12 +1480,58 @@ export async function runUnitPhase(ic, iterData, loopState, sidecarItem) {
|
|
|
1488
1480
|
? ctx.modelRegistry.getProviderAuthMode(ctx.model.provider)
|
|
1489
1481
|
: undefined,
|
|
1490
1482
|
baseUrl: s.currentUnitModel?.baseUrl ?? ctx.model?.baseUrl,
|
|
1483
|
+
activeTools: typeof pi.getActiveTools === "function" ? pi.getActiveTools() : [],
|
|
1491
1484
|
});
|
|
1492
1485
|
if (compatibilityError) {
|
|
1486
|
+
s.currentUnitRouting = prevUnitRouting;
|
|
1487
|
+
s.currentUnitModel = prevUnitModel;
|
|
1488
|
+
s.currentDispatchedModelId = prevDispatchedModelId;
|
|
1489
|
+
if (s.checkpointSha) {
|
|
1490
|
+
cleanupCheckpoint(s.basePath, unitId);
|
|
1491
|
+
s.checkpointSha = null;
|
|
1492
|
+
}
|
|
1493
|
+
if (prevSessionModel) {
|
|
1494
|
+
const ok = await pi.setModel(prevSessionModel, { persist: false });
|
|
1495
|
+
if (!ok) {
|
|
1496
|
+
ctx.ui.notify("Failed to restore previous session model after compatibility check failure.", "warning");
|
|
1497
|
+
}
|
|
1498
|
+
if (prevSessionThinkingLevel) {
|
|
1499
|
+
pi.setThinkingLevel(prevSessionThinkingLevel);
|
|
1500
|
+
}
|
|
1501
|
+
}
|
|
1493
1502
|
ctx.ui.notify(compatibilityError, "error");
|
|
1494
1503
|
await deps.stopAuto(ctx, pi, compatibilityError);
|
|
1495
1504
|
return { action: "break", reason: "workflow-capability" };
|
|
1496
1505
|
}
|
|
1506
|
+
// Scope workflow-logger buffer to this unit so post-finalize drains are
|
|
1507
|
+
// per-unit. Without this, the module-level _buffer accumulates across every
|
|
1508
|
+
// unit in the same Node process (see workflow-logger.ts module header).
|
|
1509
|
+
_resetLogs();
|
|
1510
|
+
const unitStartedAt = Date.now();
|
|
1511
|
+
s.unitDispatchCount.set(dispatchKey, nextDispatchCount);
|
|
1512
|
+
s.currentUnit = { type: unitType, id: unitId, startedAt: unitStartedAt };
|
|
1513
|
+
s.lastGitActionFailure = null;
|
|
1514
|
+
s.lastGitActionStatus = null;
|
|
1515
|
+
s.lastUnitAgentEndMessages = null;
|
|
1516
|
+
setCurrentPhase(unitType, {
|
|
1517
|
+
basePath: s.basePath,
|
|
1518
|
+
traceId: ic.flowId,
|
|
1519
|
+
turnId: `iter-${ic.iteration}`,
|
|
1520
|
+
causedBy: "unit-start",
|
|
1521
|
+
});
|
|
1522
|
+
s.lastToolInvocationError = null; // #2883: clear stale error from previous unit
|
|
1523
|
+
const unitStartSeq = ic.nextSeq();
|
|
1524
|
+
deps.emitJournalEvent({ ts: new Date().toISOString(), flowId: ic.flowId, seq: unitStartSeq, eventType: "unit-start", data: { unitType, unitId } });
|
|
1525
|
+
deps.captureAvailableSkills();
|
|
1526
|
+
writeUnitRuntimeRecord(s.basePath, unitType, unitId, unitStartedAt, {
|
|
1527
|
+
phase: "dispatched",
|
|
1528
|
+
wrapupWarningSent: false,
|
|
1529
|
+
timeoutAt: null,
|
|
1530
|
+
lastProgressAt: unitStartedAt,
|
|
1531
|
+
progressCount: 0,
|
|
1532
|
+
lastProgressKind: "dispatch",
|
|
1533
|
+
recoveryAttempts: 0, // Reset so re-dispatched units get full recovery budget (#2322)
|
|
1534
|
+
});
|
|
1497
1535
|
// Progress widget + preconditions — deferred to after model selection so the
|
|
1498
1536
|
// widget's first render tick shows the correct model (#2899).
|
|
1499
1537
|
deps.updateProgressWidget(ctx, unitType, unitId, state);
|
|
@@ -1923,6 +1961,18 @@ export async function runFinalize(ic, iterData, loopState, sidecarItem) {
|
|
|
1923
1961
|
lastProgressAt: Date.now(),
|
|
1924
1962
|
lastProgressKind: "finalize-success",
|
|
1925
1963
|
});
|
|
1964
|
+
if (!preUnitSnapshot.type.startsWith("hook/") &&
|
|
1965
|
+
preUnitSnapshot.type !== "custom-step" &&
|
|
1966
|
+
preUnitSnapshot.type !== "complete-milestone") {
|
|
1967
|
+
setAutoOutcomeWidget(ctx, {
|
|
1968
|
+
...buildPhaseHandoffOutcome({
|
|
1969
|
+
unitType: preUnitSnapshot.type,
|
|
1970
|
+
unitId: preUnitSnapshot.id,
|
|
1971
|
+
agentEndMessages: s.lastUnitAgentEndMessages,
|
|
1972
|
+
}),
|
|
1973
|
+
startedAt: s.autoStartTime,
|
|
1974
|
+
});
|
|
1975
|
+
}
|
|
1926
1976
|
}
|
|
1927
1977
|
s.currentUnit = null;
|
|
1928
1978
|
clearCurrentPhase();
|
|
@@ -4,6 +4,18 @@ import { createRequire } from "node:module";
|
|
|
4
4
|
const require = createRequire(import.meta.url);
|
|
5
5
|
const DEFAULT_MEMORY_PRESSURE_THRESHOLD = 0.85;
|
|
6
6
|
const DEFAULT_HEAP_LIMIT_MB = 4096;
|
|
7
|
+
/**
|
|
8
|
+
* Returns true on auto-mode startup, then every configured interval.
|
|
9
|
+
*
|
|
10
|
+
* Iteration 1 is checked explicitly so early session memory pressure cannot
|
|
11
|
+
* bypass the periodic interval guard.
|
|
12
|
+
*/
|
|
13
|
+
export function shouldCheckMemoryPressure(iteration, interval) {
|
|
14
|
+
if (!Number.isInteger(interval) || interval <= 0) {
|
|
15
|
+
throw new Error("Memory pressure check interval must be a positive integer");
|
|
16
|
+
}
|
|
17
|
+
return iteration === 1 || iteration % interval === 0;
|
|
18
|
+
}
|
|
7
19
|
function defaultHeapLimitBytes() {
|
|
8
20
|
const v8 = require("node:v8");
|
|
9
21
|
const limit = v8.getHeapStatistics?.().heap_size_limit;
|
|
@@ -27,6 +27,19 @@ export function extractUatSliceId(unitId) {
|
|
|
27
27
|
return slice;
|
|
28
28
|
return null;
|
|
29
29
|
}
|
|
30
|
+
export function buildPhaseHandoffOutcome(input) {
|
|
31
|
+
const phase = unitPhaseLabel(input.unitType);
|
|
32
|
+
const detail = extractLastAssistantSummary(input.agentEndMessages) ??
|
|
33
|
+
`Completed ${unitVerb(input.unitType)} ${input.unitId}.`;
|
|
34
|
+
return {
|
|
35
|
+
status: "complete",
|
|
36
|
+
title: `${phase} complete`,
|
|
37
|
+
detail,
|
|
38
|
+
unitLabel: `${unitVerb(input.unitType)} ${input.unitId}`,
|
|
39
|
+
nextAction: "Preparing the next phase. Review this handoff while the next session starts.",
|
|
40
|
+
commands: ["/gsd status for overview", "/gsd visualize to inspect", "/gsd notifications for history"],
|
|
41
|
+
};
|
|
42
|
+
}
|
|
30
43
|
// ─── Unit Description Helpers ─────────────────────────────────────────────────
|
|
31
44
|
export function unitVerb(unitType) {
|
|
32
45
|
if (unitType.startsWith("hook/"))
|
|
@@ -464,7 +477,6 @@ export function _resetWidgetModeForTests() {
|
|
|
464
477
|
export function updateProgressWidget(ctx, unitType, unitId, state, accessors, tierBadge) {
|
|
465
478
|
if (!ctx.hasUI)
|
|
466
479
|
return;
|
|
467
|
-
ctx.ui.setWidget("gsd-outcome", undefined);
|
|
468
480
|
// Welcome header is a startup-only banner — permanently suppress it once
|
|
469
481
|
// auto-mode activates. The dashboard widget owns all status from here.
|
|
470
482
|
// Note: setHeader(undefined) restores the built-in header (logo +
|
|
@@ -927,3 +939,56 @@ function normalizeRollupText(value) {
|
|
|
927
939
|
return null;
|
|
928
940
|
return clean;
|
|
929
941
|
}
|
|
942
|
+
function isAssistantMessage(value) {
|
|
943
|
+
if (!value || typeof value !== "object")
|
|
944
|
+
return false;
|
|
945
|
+
const record = value;
|
|
946
|
+
if (record.role === "assistant")
|
|
947
|
+
return true;
|
|
948
|
+
const message = record.message;
|
|
949
|
+
if (message && typeof message === "object") {
|
|
950
|
+
return message.role === "assistant";
|
|
951
|
+
}
|
|
952
|
+
return false;
|
|
953
|
+
}
|
|
954
|
+
function extractLastAssistantSummary(messages) {
|
|
955
|
+
if (!messages || messages.length === 0)
|
|
956
|
+
return null;
|
|
957
|
+
for (let i = messages.length - 1; i >= 0; i--) {
|
|
958
|
+
if (!isAssistantMessage(messages[i]))
|
|
959
|
+
continue;
|
|
960
|
+
const text = extractMessageText(messages[i]);
|
|
961
|
+
const clean = normalizeRollupText(text);
|
|
962
|
+
if (clean)
|
|
963
|
+
return truncateToWidth(clean, 220, "…");
|
|
964
|
+
}
|
|
965
|
+
return null;
|
|
966
|
+
}
|
|
967
|
+
function extractMessageText(value) {
|
|
968
|
+
if (typeof value === "string")
|
|
969
|
+
return value;
|
|
970
|
+
if (!value || typeof value !== "object")
|
|
971
|
+
return null;
|
|
972
|
+
const record = value;
|
|
973
|
+
if (typeof record.content === "string")
|
|
974
|
+
return record.content;
|
|
975
|
+
const message = record.message;
|
|
976
|
+
if (message && typeof message === "object") {
|
|
977
|
+
return extractMessageText(message);
|
|
978
|
+
}
|
|
979
|
+
const content = record.content;
|
|
980
|
+
if (Array.isArray(content)) {
|
|
981
|
+
const parts = content
|
|
982
|
+
.map((part) => {
|
|
983
|
+
if (typeof part === "string")
|
|
984
|
+
return part;
|
|
985
|
+
if (!part || typeof part !== "object")
|
|
986
|
+
return "";
|
|
987
|
+
const partRecord = part;
|
|
988
|
+
return typeof partRecord.text === "string" ? partRecord.text : "";
|
|
989
|
+
})
|
|
990
|
+
.filter(Boolean);
|
|
991
|
+
return parts.length > 0 ? parts.join(" ") : null;
|
|
992
|
+
}
|
|
993
|
+
return null;
|
|
994
|
+
}
|
|
@@ -224,6 +224,7 @@ export async function dispatchDirectPhase(ctx, pi, phase, base) {
|
|
|
224
224
|
unitType,
|
|
225
225
|
authMode: ctx.model?.provider ? ctx.modelRegistry.getProviderAuthMode(ctx.model.provider) : undefined,
|
|
226
226
|
baseUrl: ctx.model?.baseUrl,
|
|
227
|
+
activeTools: typeof pi.getActiveTools === "function" ? pi.getActiveTools() : [],
|
|
227
228
|
});
|
|
228
229
|
if (compatibilityError) {
|
|
229
230
|
ctx.ui.notify(compatibilityError, "error");
|
|
@@ -102,6 +102,9 @@ function missingSliceStop(mid, phase) {
|
|
|
102
102
|
level: "error",
|
|
103
103
|
};
|
|
104
104
|
}
|
|
105
|
+
function isRegistryMilestoneComplete(state, mid) {
|
|
106
|
+
return state.registry.some((milestone) => milestone.id === mid && milestone.status === "complete");
|
|
107
|
+
}
|
|
105
108
|
/**
|
|
106
109
|
* Check for milestone slices missing SUMMARY files.
|
|
107
110
|
* Returns array of missing slice IDs, or empty array if all present or DB unavailable.
|
|
@@ -247,6 +250,8 @@ export const DISPATCH_RULES = [
|
|
|
247
250
|
return null;
|
|
248
251
|
if (!MILESTONE_ID_RE.test(mid))
|
|
249
252
|
return null;
|
|
253
|
+
if (isRegistryMilestoneComplete(state, mid))
|
|
254
|
+
return null;
|
|
250
255
|
// Align with the plan-v2 gate's lookup semantics: whitespace-only counts
|
|
251
256
|
// as missing, and an auto worktree may fall back to GSD_PROJECT_ROOT.
|
|
252
257
|
if (hasFinalizedMilestoneContext(basePath, mid))
|
|
@@ -294,9 +299,7 @@ export const DISPATCH_RULES = [
|
|
|
294
299
|
const attempts = incrementUatCount(basePath, mid, sliceId);
|
|
295
300
|
if (attempts > MAX_UAT_ATTEMPTS) {
|
|
296
301
|
return {
|
|
297
|
-
action: "
|
|
298
|
-
reason: `run-uat for ${mid}/${sliceId} has been dispatched ${attempts - 1} times without producing a verdict. Verification commands may be broken — fix the UAT spec or manually write an ASSESSMENT verdict.`,
|
|
299
|
-
level: "warning",
|
|
302
|
+
action: "skip",
|
|
300
303
|
};
|
|
301
304
|
}
|
|
302
305
|
const uatFile = resolveSliceFile(basePath, mid, sliceId, "UAT");
|
|
@@ -557,6 +560,8 @@ export const DISPATCH_RULES = [
|
|
|
557
560
|
match: async ({ state, mid, midTitle, basePath, prefs, structuredQuestionsAvailable }) => {
|
|
558
561
|
if (state.phase !== "pre-planning")
|
|
559
562
|
return null;
|
|
563
|
+
if (isRegistryMilestoneComplete(state, mid))
|
|
564
|
+
return null;
|
|
560
565
|
const contextFile = resolveMilestoneFile(basePath, mid, "CONTEXT");
|
|
561
566
|
const hasContext = !!(contextFile && (await loadFile(contextFile)));
|
|
562
567
|
if (hasContext)
|
|
@@ -1091,19 +1096,19 @@ export const DISPATCH_RULES = [
|
|
|
1091
1096
|
return { action: "skip" };
|
|
1092
1097
|
}
|
|
1093
1098
|
}
|
|
1094
|
-
// Safety guard (#2675): block completion when VALIDATION
|
|
1095
|
-
//
|
|
1096
|
-
// terminal
|
|
1097
|
-
//
|
|
1099
|
+
// Safety guard (#2675, #5747, #5920): block completion when VALIDATION
|
|
1100
|
+
// verdict is anything other than pass. The state machine treats these
|
|
1101
|
+
// verdicts as terminal, but completing-milestone should NOT proceed —
|
|
1102
|
+
// remediation or human attention is needed.
|
|
1098
1103
|
const validationFile = resolveMilestoneFile(basePath, mid, "VALIDATION");
|
|
1099
1104
|
if (validationFile) {
|
|
1100
1105
|
const validationContent = await loadFile(validationFile);
|
|
1101
1106
|
if (validationContent) {
|
|
1102
1107
|
const verdict = extractVerdict(validationContent);
|
|
1103
|
-
if (verdict
|
|
1108
|
+
if (verdict !== "pass") {
|
|
1104
1109
|
return {
|
|
1105
1110
|
action: "stop",
|
|
1106
|
-
reason: `Cannot complete milestone ${mid}: VALIDATION verdict is "
|
|
1111
|
+
reason: `Cannot complete milestone ${mid}: VALIDATION verdict is "${verdict}". Address the validation findings and re-run validation, or update the verdict manually.`,
|
|
1107
1112
|
level: "warning",
|
|
1108
1113
|
};
|
|
1109
1114
|
}
|
|
@@ -1118,16 +1123,12 @@ export const DISPATCH_RULES = [
|
|
|
1118
1123
|
level: "error",
|
|
1119
1124
|
};
|
|
1120
1125
|
}
|
|
1121
|
-
// Safety
|
|
1122
|
-
// artifacts
|
|
1123
|
-
//
|
|
1126
|
+
// Safety signal (#1703, #5097): detect milestones with only .gsd/
|
|
1127
|
+
// artifacts. This no longer hard-blocks completion because some
|
|
1128
|
+
// milestones are intentionally planning/documentation-only.
|
|
1124
1129
|
const artifactCheck = hasImplementationArtifacts(basePath, mid);
|
|
1125
1130
|
if (artifactCheck === "absent") {
|
|
1126
|
-
|
|
1127
|
-
action: "stop",
|
|
1128
|
-
reason: `Cannot complete milestone ${mid}: no implementation files found outside .gsd/. The milestone has only plan files — actual code changes are required.`,
|
|
1129
|
-
level: "error",
|
|
1130
|
-
};
|
|
1131
|
+
logWarning("dispatch", `Milestone ${mid} has no implementation files outside .gsd/ — continuing complete-milestone dispatch (planning-only/documentation-only milestone).`);
|
|
1131
1132
|
}
|
|
1132
1133
|
if (artifactCheck === "unknown") {
|
|
1133
1134
|
logWarning("dispatch", `Implementation artifact check inconclusive for ${mid} — proceeding (git context unavailable)`);
|
|
@@ -494,6 +494,8 @@ autoModeStartThinkingLevel) {
|
|
|
494
494
|
* Handles formats: "provider/model", "bare-id", "org/model-name" (OpenRouter).
|
|
495
495
|
*/
|
|
496
496
|
export function resolveModelId(modelId, availableModels, currentProvider) {
|
|
497
|
+
if (!modelId)
|
|
498
|
+
return undefined;
|
|
497
499
|
const slashIdx = modelId.indexOf("/");
|
|
498
500
|
if (slashIdx !== -1) {
|
|
499
501
|
const maybeProvider = modelId.substring(0, slashIdx);
|