gsd-pi 2.44.0-dev.62b5d6c → 2.44.0-dev.73f2fd5
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 +30 -12
- package/dist/resources/extensions/gsd/auto/infra-errors.js +3 -0
- package/dist/resources/extensions/gsd/auto/phases.js +36 -36
- package/dist/resources/extensions/gsd/auto-prompts.js +24 -1
- package/dist/resources/extensions/gsd/auto-start.js +10 -0
- package/dist/resources/extensions/gsd/auto-timers.js +57 -3
- package/dist/resources/extensions/gsd/auto-worktree-sync.js +4 -0
- package/dist/resources/extensions/gsd/auto-worktree.js +9 -6
- package/dist/resources/extensions/gsd/auto.js +30 -3
- package/dist/resources/extensions/gsd/bootstrap/db-tools.js +156 -0
- package/dist/resources/extensions/gsd/bootstrap/system-context.js +46 -12
- package/dist/resources/extensions/gsd/commands/catalog.js +6 -1
- package/dist/resources/extensions/gsd/commands/handlers/core.js +1 -0
- package/dist/resources/extensions/gsd/commands/handlers/ops.js +5 -0
- package/dist/resources/extensions/gsd/commands/handlers/workflow.js +5 -0
- package/dist/resources/extensions/gsd/commands-mcp-status.js +187 -0
- package/dist/resources/extensions/gsd/db-writer.js +34 -16
- package/dist/resources/extensions/gsd/doctor.js +8 -0
- package/dist/resources/extensions/gsd/git-service.js +8 -3
- package/dist/resources/extensions/gsd/gsd-db.js +12 -1
- package/dist/resources/extensions/gsd/markdown-renderer.js +1 -1
- package/dist/resources/extensions/gsd/preferences.js +9 -1
- package/dist/resources/extensions/gsd/prompts/complete-milestone.md +2 -4
- package/dist/resources/extensions/gsd/prompts/plan-slice.md +1 -1
- package/dist/resources/extensions/gsd/prompts/reassess-roadmap.md +6 -6
- package/dist/resources/extensions/gsd/prompts/replan-slice.md +3 -14
- package/dist/resources/extensions/gsd/prompts/validate-milestone.md +7 -37
- package/dist/resources/extensions/gsd/provider-error-pause.js +7 -0
- package/dist/resources/extensions/gsd/state.js +19 -2
- package/dist/resources/extensions/gsd/tools/plan-slice.js +1 -0
- package/dist/resources/extensions/gsd/tools/plan-task.js +1 -0
- package/dist/resources/extensions/gsd/tools/replan-slice.js +2 -0
- package/dist/resources/extensions/gsd/tools/validate-milestone.js +88 -0
- package/dist/resources/extensions/gsd/worktree-resolver.js +6 -0
- package/dist/resources/extensions/mcp-client/index.js +14 -0
- package/dist/web/standalone/.next/BUILD_ID +1 -1
- package/dist/web/standalone/.next/app-path-routes-manifest.json +17 -17
- package/dist/web/standalone/.next/build-manifest.json +2 -2
- package/dist/web/standalone/.next/prerender-manifest.json +3 -3
- package/dist/web/standalone/.next/server/app/_global-error.html +2 -2
- 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.html +1 -1
- package/dist/web/standalone/.next/server/app/_not-found.rsc +1 -1
- package/dist/web/standalone/.next/server/app/_not-found.segments/_full.segment.rsc +1 -1
- package/dist/web/standalone/.next/server/app/_not-found.segments/_head.segment.rsc +1 -1
- package/dist/web/standalone/.next/server/app/_not-found.segments/_index.segment.rsc +1 -1
- package/dist/web/standalone/.next/server/app/_not-found.segments/_not-found/__PAGE__.segment.rsc +1 -1
- package/dist/web/standalone/.next/server/app/_not-found.segments/_not-found.segment.rsc +1 -1
- package/dist/web/standalone/.next/server/app/_not-found.segments/_tree.segment.rsc +1 -1
- package/dist/web/standalone/.next/server/app/index.html +1 -1
- package/dist/web/standalone/.next/server/app/index.rsc +1 -1
- 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 +1 -1
- package/dist/web/standalone/.next/server/app/index.segments/_head.segment.rsc +1 -1
- package/dist/web/standalone/.next/server/app/index.segments/_index.segment.rsc +1 -1
- package/dist/web/standalone/.next/server/app/index.segments/_tree.segment.rsc +1 -1
- package/dist/web/standalone/.next/server/app-paths-manifest.json +17 -17
- package/dist/web/standalone/.next/server/pages/404.html +1 -1
- package/dist/web/standalone/.next/server/pages/500.html +2 -2
- package/dist/web/standalone/.next/server/server-reference-manifest.json +1 -1
- package/package.json +1 -1
- package/packages/pi-coding-agent/dist/core/auth-storage.d.ts +3 -1
- package/packages/pi-coding-agent/dist/core/auth-storage.d.ts.map +1 -1
- package/packages/pi-coding-agent/dist/core/auth-storage.js +15 -1
- package/packages/pi-coding-agent/dist/core/auth-storage.js.map +1 -1
- package/packages/pi-coding-agent/dist/core/auth-storage.test.js +6 -8
- package/packages/pi-coding-agent/dist/core/auth-storage.test.js.map +1 -1
- package/packages/pi-coding-agent/dist/core/extensions/runner.test.js +24 -26
- package/packages/pi-coding-agent/dist/core/extensions/runner.test.js.map +1 -1
- package/packages/pi-coding-agent/dist/core/fs-utils.test.js +29 -48
- package/packages/pi-coding-agent/dist/core/fs-utils.test.js.map +1 -1
- package/packages/pi-coding-agent/dist/core/local-model-check.d.ts +15 -0
- package/packages/pi-coding-agent/dist/core/local-model-check.d.ts.map +1 -0
- package/packages/pi-coding-agent/dist/core/local-model-check.js +41 -0
- package/packages/pi-coding-agent/dist/core/local-model-check.js.map +1 -0
- package/packages/pi-coding-agent/dist/core/model-registry.d.ts +11 -0
- package/packages/pi-coding-agent/dist/core/model-registry.d.ts.map +1 -1
- package/packages/pi-coding-agent/dist/core/model-registry.js +20 -1
- package/packages/pi-coding-agent/dist/core/model-registry.js.map +1 -1
- package/packages/pi-coding-agent/dist/core/resolve-config-value.test.js +34 -44
- package/packages/pi-coding-agent/dist/core/resolve-config-value.test.js.map +1 -1
- package/packages/pi-coding-agent/dist/core/session-manager.test.js +30 -34
- package/packages/pi-coding-agent/dist/core/session-manager.test.js.map +1 -1
- package/packages/pi-coding-agent/dist/core/settings-manager.d.ts +3 -0
- package/packages/pi-coding-agent/dist/core/settings-manager.d.ts.map +1 -1
- package/packages/pi-coding-agent/dist/core/settings-manager.js +6 -0
- package/packages/pi-coding-agent/dist/core/settings-manager.js.map +1 -1
- package/packages/pi-coding-agent/dist/core/tools/edit-diff.test.js +10 -12
- package/packages/pi-coding-agent/dist/core/tools/edit-diff.test.js.map +1 -1
- package/packages/pi-coding-agent/dist/main.d.ts.map +1 -1
- package/packages/pi-coding-agent/dist/main.js +17 -0
- package/packages/pi-coding-agent/dist/main.js.map +1 -1
- package/packages/pi-coding-agent/dist/modes/interactive/components/__tests__/timestamp.test.d.ts +2 -0
- package/packages/pi-coding-agent/dist/modes/interactive/components/__tests__/timestamp.test.d.ts.map +1 -0
- package/packages/pi-coding-agent/dist/modes/interactive/components/__tests__/timestamp.test.js +32 -0
- package/packages/pi-coding-agent/dist/modes/interactive/components/__tests__/timestamp.test.js.map +1 -0
- package/packages/pi-coding-agent/dist/modes/interactive/components/assistant-message.d.ts +3 -1
- package/packages/pi-coding-agent/dist/modes/interactive/components/assistant-message.d.ts.map +1 -1
- package/packages/pi-coding-agent/dist/modes/interactive/components/assistant-message.js +8 -1
- package/packages/pi-coding-agent/dist/modes/interactive/components/assistant-message.js.map +1 -1
- package/packages/pi-coding-agent/dist/modes/interactive/components/settings-selector.d.ts +2 -0
- package/packages/pi-coding-agent/dist/modes/interactive/components/settings-selector.d.ts.map +1 -1
- package/packages/pi-coding-agent/dist/modes/interactive/components/settings-selector.js +12 -0
- package/packages/pi-coding-agent/dist/modes/interactive/components/settings-selector.js.map +1 -1
- package/packages/pi-coding-agent/dist/modes/interactive/components/timestamp.d.ts +15 -0
- package/packages/pi-coding-agent/dist/modes/interactive/components/timestamp.d.ts.map +1 -0
- package/packages/pi-coding-agent/dist/modes/interactive/components/timestamp.js +40 -0
- package/packages/pi-coding-agent/dist/modes/interactive/components/timestamp.js.map +1 -0
- package/packages/pi-coding-agent/dist/modes/interactive/components/tool-execution.d.ts.map +1 -1
- package/packages/pi-coding-agent/dist/modes/interactive/components/tool-execution.js +4 -1
- package/packages/pi-coding-agent/dist/modes/interactive/components/tool-execution.js.map +1 -1
- package/packages/pi-coding-agent/dist/modes/interactive/components/user-message.d.ts +5 -2
- package/packages/pi-coding-agent/dist/modes/interactive/components/user-message.d.ts.map +1 -1
- package/packages/pi-coding-agent/dist/modes/interactive/components/user-message.js +13 -2
- package/packages/pi-coding-agent/dist/modes/interactive/components/user-message.js.map +1 -1
- package/packages/pi-coding-agent/dist/modes/interactive/controllers/chat-controller.d.ts.map +1 -1
- package/packages/pi-coding-agent/dist/modes/interactive/controllers/chat-controller.js +17 -8
- package/packages/pi-coding-agent/dist/modes/interactive/controllers/chat-controller.js.map +1 -1
- package/packages/pi-coding-agent/dist/modes/interactive/interactive-mode.d.ts.map +1 -1
- package/packages/pi-coding-agent/dist/modes/interactive/interactive-mode.js +7 -3
- package/packages/pi-coding-agent/dist/modes/interactive/interactive-mode.js.map +1 -1
- package/packages/pi-coding-agent/dist/resources/extensions/memory/storage.test.js +43 -47
- package/packages/pi-coding-agent/dist/resources/extensions/memory/storage.test.js.map +1 -1
- package/packages/pi-coding-agent/src/core/auth-storage.test.ts +7 -7
- package/packages/pi-coding-agent/src/core/auth-storage.ts +15 -1
- package/packages/pi-coding-agent/src/core/extensions/runner.test.ts +26 -26
- package/packages/pi-coding-agent/src/core/fs-utils.test.ts +31 -43
- package/packages/pi-coding-agent/src/core/local-model-check.ts +45 -0
- package/packages/pi-coding-agent/src/core/model-registry.ts +21 -1
- package/packages/pi-coding-agent/src/core/resolve-config-value.test.ts +40 -45
- package/packages/pi-coding-agent/src/core/session-manager.test.ts +33 -33
- package/packages/pi-coding-agent/src/core/settings-manager.ts +9 -0
- package/packages/pi-coding-agent/src/core/tools/edit-diff.test.ts +17 -17
- package/packages/pi-coding-agent/src/main.ts +19 -0
- package/packages/pi-coding-agent/src/modes/interactive/components/__tests__/timestamp.test.ts +38 -0
- package/packages/pi-coding-agent/src/modes/interactive/components/assistant-message.ts +10 -0
- package/packages/pi-coding-agent/src/modes/interactive/components/settings-selector.ts +15 -0
- package/packages/pi-coding-agent/src/modes/interactive/components/timestamp.ts +48 -0
- package/packages/pi-coding-agent/src/modes/interactive/components/tool-execution.ts +3 -1
- package/packages/pi-coding-agent/src/modes/interactive/components/user-message.ts +18 -3
- package/packages/pi-coding-agent/src/modes/interactive/controllers/chat-controller.ts +16 -7
- package/packages/pi-coding-agent/src/modes/interactive/interactive-mode.ts +8 -1
- package/packages/pi-coding-agent/src/resources/extensions/memory/storage.test.ts +74 -74
- package/src/resources/extensions/gsd/auto/infra-errors.ts +3 -0
- package/src/resources/extensions/gsd/auto/phases.ts +45 -48
- package/src/resources/extensions/gsd/auto-prompts.ts +24 -1
- package/src/resources/extensions/gsd/auto-start.ts +14 -0
- package/src/resources/extensions/gsd/auto-timers.ts +64 -3
- package/src/resources/extensions/gsd/auto-worktree-sync.ts +5 -0
- package/src/resources/extensions/gsd/auto-worktree.ts +9 -6
- package/src/resources/extensions/gsd/auto.ts +37 -3
- package/src/resources/extensions/gsd/bootstrap/db-tools.ts +148 -0
- package/src/resources/extensions/gsd/bootstrap/system-context.ts +48 -11
- package/src/resources/extensions/gsd/commands/catalog.ts +6 -1
- package/src/resources/extensions/gsd/commands/handlers/core.ts +1 -0
- package/src/resources/extensions/gsd/commands/handlers/ops.ts +5 -0
- package/src/resources/extensions/gsd/commands/handlers/workflow.ts +8 -0
- package/src/resources/extensions/gsd/commands-mcp-status.ts +247 -0
- package/src/resources/extensions/gsd/db-writer.ts +39 -17
- package/src/resources/extensions/gsd/doctor.ts +7 -1
- package/src/resources/extensions/gsd/git-service.ts +6 -2
- package/src/resources/extensions/gsd/gsd-db.ts +16 -1
- package/src/resources/extensions/gsd/markdown-renderer.ts +1 -1
- package/src/resources/extensions/gsd/preferences.ts +11 -1
- package/src/resources/extensions/gsd/prompts/complete-milestone.md +2 -4
- package/src/resources/extensions/gsd/prompts/plan-slice.md +1 -1
- package/src/resources/extensions/gsd/prompts/reassess-roadmap.md +6 -6
- package/src/resources/extensions/gsd/prompts/replan-slice.md +3 -14
- package/src/resources/extensions/gsd/prompts/validate-milestone.md +7 -37
- package/src/resources/extensions/gsd/provider-error-pause.ts +9 -0
- package/src/resources/extensions/gsd/state.ts +19 -1
- package/src/resources/extensions/gsd/tests/all-milestones-complete-merge.test.ts +99 -99
- package/src/resources/extensions/gsd/tests/auto-lock-creation.test.ts +14 -16
- package/src/resources/extensions/gsd/tests/auto-paused-session-validation.test.ts +43 -57
- package/src/resources/extensions/gsd/tests/auto-pr-bugs.test.ts +88 -0
- package/src/resources/extensions/gsd/tests/auto-preflight.test.ts +11 -13
- package/src/resources/extensions/gsd/tests/auto-recovery.test.ts +465 -523
- package/src/resources/extensions/gsd/tests/auto-secrets-gate.test.ts +73 -75
- package/src/resources/extensions/gsd/tests/auto-start-needs-discussion.test.ts +34 -56
- package/src/resources/extensions/gsd/tests/auto-worktree-milestone-merge.test.ts +533 -656
- package/src/resources/extensions/gsd/tests/auto-worktree.test.ts +165 -143
- package/src/resources/extensions/gsd/tests/cache-staleness-regression.test.ts +29 -52
- package/src/resources/extensions/gsd/tests/captures.test.ts +148 -176
- package/src/resources/extensions/gsd/tests/claude-import-tui.test.ts +32 -33
- package/src/resources/extensions/gsd/tests/collect-from-manifest.test.ts +141 -143
- package/src/resources/extensions/gsd/tests/commands-inspect-open-db.test.ts +25 -25
- package/src/resources/extensions/gsd/tests/commands-logs.test.ts +81 -81
- package/src/resources/extensions/gsd/tests/complete-milestone.test.ts +38 -59
- package/src/resources/extensions/gsd/tests/complete-slice.test.ts +228 -263
- package/src/resources/extensions/gsd/tests/complete-task.test.ts +250 -302
- package/src/resources/extensions/gsd/tests/completed-units-metrics-sync.test.ts +114 -0
- package/src/resources/extensions/gsd/tests/context-store.test.ts +354 -367
- package/src/resources/extensions/gsd/tests/continue-here.test.ts +68 -72
- package/src/resources/extensions/gsd/tests/cost-projection.test.ts +92 -106
- package/src/resources/extensions/gsd/tests/crash-recovery.test.ts +27 -35
- package/src/resources/extensions/gsd/tests/dashboard-budget.test.ts +220 -237
- package/src/resources/extensions/gsd/tests/db-writer.test.ts +465 -416
- package/src/resources/extensions/gsd/tests/definition-loader.test.ts +76 -92
- package/src/resources/extensions/gsd/tests/derive-state-crossval.test.ts +68 -83
- package/src/resources/extensions/gsd/tests/derive-state-db.test.ts +210 -181
- package/src/resources/extensions/gsd/tests/derive-state-deps.test.ts +78 -101
- package/src/resources/extensions/gsd/tests/derive-state.test.ts +192 -227
- package/src/resources/extensions/gsd/tests/detection.test.ts +232 -278
- package/src/resources/extensions/gsd/tests/dev-engine-wrapper.test.ts +30 -34
- package/src/resources/extensions/gsd/tests/dispatch-guard.test.ts +164 -180
- package/src/resources/extensions/gsd/tests/dispatch-missing-task-plans.test.ts +43 -49
- package/src/resources/extensions/gsd/tests/dispatch-uat-last-completed.test.ts +28 -32
- package/src/resources/extensions/gsd/tests/doctor-completion-deferral.test.ts +27 -29
- package/src/resources/extensions/gsd/tests/doctor-delimiter-fix.test.ts +34 -38
- package/src/resources/extensions/gsd/tests/doctor-enhancements.test.ts +54 -75
- package/src/resources/extensions/gsd/tests/doctor-environment-worktree.test.ts +21 -32
- package/src/resources/extensions/gsd/tests/doctor-environment.test.ts +72 -97
- package/src/resources/extensions/gsd/tests/doctor-fixlevel.test.ts +38 -44
- package/src/resources/extensions/gsd/tests/doctor-git.test.ts +104 -145
- package/src/resources/extensions/gsd/tests/doctor-proactive.test.ts +84 -106
- package/src/resources/extensions/gsd/tests/doctor-roadmap-summary-atomicity.test.ts +54 -60
- package/src/resources/extensions/gsd/tests/doctor-runtime.test.ts +72 -93
- package/src/resources/extensions/gsd/tests/doctor.test.ts +104 -134
- package/src/resources/extensions/gsd/tests/ensure-db-open.test.ts +123 -131
- package/src/resources/extensions/gsd/tests/est-annotation-timeout.test.ts +120 -0
- package/src/resources/extensions/gsd/tests/exit-command.test.ts +20 -24
- package/src/resources/extensions/gsd/tests/feature-branch-lifecycle-integration.test.ts +48 -57
- package/src/resources/extensions/gsd/tests/files-loadfile-eisdir.test.ts +5 -7
- package/src/resources/extensions/gsd/tests/flag-file-db.test.ts +30 -42
- package/src/resources/extensions/gsd/tests/freeform-decisions.test.ts +198 -206
- package/src/resources/extensions/gsd/tests/git-locale.test.ts +13 -27
- package/src/resources/extensions/gsd/tests/git-service.test.ts +285 -388
- package/src/resources/extensions/gsd/tests/gitignore-tracked-gsd.test.ts +31 -39
- package/src/resources/extensions/gsd/tests/graph-operations.test.ts +63 -69
- package/src/resources/extensions/gsd/tests/gsd-db.test.ts +255 -264
- package/src/resources/extensions/gsd/tests/gsd-inspect.test.ts +108 -119
- package/src/resources/extensions/gsd/tests/gsd-recover.test.ts +81 -103
- package/src/resources/extensions/gsd/tests/gsd-tools.test.ts +229 -262
- package/src/resources/extensions/gsd/tests/headless-answers.test.ts +13 -13
- package/src/resources/extensions/gsd/tests/health-widget.test.ts +29 -37
- package/src/resources/extensions/gsd/tests/idle-recovery.test.ts +81 -102
- package/src/resources/extensions/gsd/tests/infra-error.test.ts +20 -2
- package/src/resources/extensions/gsd/tests/init-wizard.test.ts +16 -18
- package/src/resources/extensions/gsd/tests/integration-edge.test.ts +41 -46
- package/src/resources/extensions/gsd/tests/integration-lifecycle.test.ts +42 -53
- package/src/resources/extensions/gsd/tests/integration-mixed-milestones.test.ts +75 -91
- package/src/resources/extensions/gsd/tests/integration-proof.test.ts +18 -18
- package/src/resources/extensions/gsd/tests/knowledge.test.ts +89 -0
- package/src/resources/extensions/gsd/tests/markdown-renderer.test.ts +150 -194
- package/src/resources/extensions/gsd/tests/mcp-status.test.ts +103 -0
- package/src/resources/extensions/gsd/tests/md-importer.test.ts +101 -125
- package/src/resources/extensions/gsd/tests/memory-extractor.test.ts +45 -54
- package/src/resources/extensions/gsd/tests/memory-store.test.ts +80 -93
- package/src/resources/extensions/gsd/tests/merge-conflict-stops-loop.test.ts +66 -0
- package/src/resources/extensions/gsd/tests/migrate-command.test.ts +57 -66
- package/src/resources/extensions/gsd/tests/migrate-hierarchy.test.ts +83 -93
- package/src/resources/extensions/gsd/tests/migrate-parser.test.ts +161 -170
- package/src/resources/extensions/gsd/tests/migrate-transformer.test.ts +125 -141
- package/src/resources/extensions/gsd/tests/migrate-validator-parsers.test.ts +107 -131
- package/src/resources/extensions/gsd/tests/migrate-writer-integration.test.ts +87 -96
- package/src/resources/extensions/gsd/tests/migrate-writer.test.ts +125 -164
- package/src/resources/extensions/gsd/tests/must-have-parser.test.ts +81 -94
- package/src/resources/extensions/gsd/tests/none-mode-gates.test.ts +35 -36
- package/src/resources/extensions/gsd/tests/overrides.test.ts +99 -106
- package/src/resources/extensions/gsd/tests/parallel-crash-recovery.test.ts +40 -47
- package/src/resources/extensions/gsd/tests/parallel-worker-monitoring.test.ts +25 -28
- package/src/resources/extensions/gsd/tests/parallel-workers-multi-milestone-e2e.test.ts +66 -83
- package/src/resources/extensions/gsd/tests/park-edge-cases.test.ts +54 -77
- package/src/resources/extensions/gsd/tests/park-milestone.test.ts +68 -115
- package/src/resources/extensions/gsd/tests/parsers.test.ts +546 -611
- package/src/resources/extensions/gsd/tests/paths.test.ts +72 -87
- package/src/resources/extensions/gsd/tests/post-unit-hooks.test.ts +77 -117
- package/src/resources/extensions/gsd/tests/preferences.test.ts +27 -0
- package/src/resources/extensions/gsd/tests/prompt-contracts.test.ts +11 -7
- package/src/resources/extensions/gsd/tests/prompt-db.test.ts +56 -56
- package/src/resources/extensions/gsd/tests/queue-draft-detection.test.ts +93 -119
- package/src/resources/extensions/gsd/tests/queue-order.test.ts +70 -82
- package/src/resources/extensions/gsd/tests/queue-reorder-e2e.test.ts +42 -55
- package/src/resources/extensions/gsd/tests/quick-auto-guard.test.ts +100 -0
- package/src/resources/extensions/gsd/tests/quick-branch-lifecycle.test.ts +45 -73
- package/src/resources/extensions/gsd/tests/reassess-prompt.test.ts +28 -38
- package/src/resources/extensions/gsd/tests/replan-slice.test.ts +73 -80
- package/src/resources/extensions/gsd/tests/repo-identity-worktree.test.ts +71 -74
- package/src/resources/extensions/gsd/tests/requirements.test.ts +70 -75
- package/src/resources/extensions/gsd/tests/retry-state-reset.test.ts +44 -66
- package/src/resources/extensions/gsd/tests/roadmap-parse-regression.test.ts +114 -181
- package/src/resources/extensions/gsd/tests/rule-registry.test.ts +63 -65
- package/src/resources/extensions/gsd/tests/run-uat.test.ts +66 -128
- package/src/resources/extensions/gsd/tests/session-lock-multipath.test.ts +18 -25
- package/src/resources/extensions/gsd/tests/session-lock-regression.test.ts +37 -44
- package/src/resources/extensions/gsd/tests/shared-wal.test.ts +19 -26
- package/src/resources/extensions/gsd/tests/sqlite-unavailable-gate.test.ts +63 -0
- package/src/resources/extensions/gsd/tests/stalled-tool-recovery.test.ts +6 -8
- package/src/resources/extensions/gsd/tests/stop-auto-merge-back.test.ts +67 -0
- package/src/resources/extensions/gsd/tests/symlink-numbered-variants.test.ts +22 -28
- package/src/resources/extensions/gsd/tests/terminated-transient.test.ts +49 -0
- package/src/resources/extensions/gsd/tests/token-savings.test.ts +54 -56
- package/src/resources/extensions/gsd/tests/tool-call-loop-guard.test.ts +23 -25
- package/src/resources/extensions/gsd/tests/tool-naming.test.ts +10 -11
- package/src/resources/extensions/gsd/tests/unique-milestone-ids.test.ts +66 -82
- package/src/resources/extensions/gsd/tests/unit-runtime.test.ts +46 -47
- package/src/resources/extensions/gsd/tests/visualizer-critical-path.test.ts +20 -22
- package/src/resources/extensions/gsd/tests/visualizer-data.test.ts +84 -86
- package/src/resources/extensions/gsd/tests/visualizer-overlay.test.ts +41 -43
- package/src/resources/extensions/gsd/tests/visualizer-views.test.ts +94 -96
- package/src/resources/extensions/gsd/tests/windows-path-normalization.test.ts +11 -13
- package/src/resources/extensions/gsd/tests/worker-registry.test.ts +27 -29
- package/src/resources/extensions/gsd/tests/workflow-templates.test.ts +50 -52
- package/src/resources/extensions/gsd/tests/worktree-bugfix.test.ts +10 -13
- package/src/resources/extensions/gsd/tests/worktree-db-integration.test.ts +14 -18
- package/src/resources/extensions/gsd/tests/worktree-db.test.ts +38 -39
- package/src/resources/extensions/gsd/tests/worktree-e2e.test.ts +17 -21
- package/src/resources/extensions/gsd/tests/worktree-health.test.ts +25 -30
- package/src/resources/extensions/gsd/tests/worktree-integration.test.ts +30 -37
- package/src/resources/extensions/gsd/tests/worktree-symlink-removal.test.ts +15 -22
- package/src/resources/extensions/gsd/tests/worktree-sync-milestones.test.ts +59 -66
- package/src/resources/extensions/gsd/tests/worktree.test.ts +44 -50
- package/src/resources/extensions/gsd/tools/plan-slice.ts +2 -0
- package/src/resources/extensions/gsd/tools/plan-task.ts +2 -0
- package/src/resources/extensions/gsd/tools/replan-slice.ts +3 -0
- package/src/resources/extensions/gsd/tools/validate-milestone.ts +127 -0
- package/src/resources/extensions/gsd/worktree-resolver.ts +7 -0
- package/src/resources/extensions/mcp-client/index.ts +20 -0
- /package/dist/web/standalone/.next/static/{fOnWQBjWXMKUs4bqTg530 → kxxAA66bah_yhPYqLBHE2}/_buildManifest.js +0 -0
- /package/dist/web/standalone/.next/static/{fOnWQBjWXMKUs4bqTg530 → kxxAA66bah_yhPYqLBHE2}/_ssgManifest.js +0 -0
|
@@ -27,7 +27,9 @@ import { debugLog } from "../debug-logger.js";
|
|
|
27
27
|
import { gsdRoot } from "../paths.js";
|
|
28
28
|
import { atomicWriteSync } from "../atomic-write.js";
|
|
29
29
|
import { PROJECT_FILES } from "../detection.js";
|
|
30
|
+
import { MergeConflictError } from "../git-service.js";
|
|
30
31
|
import { join } from "node:path";
|
|
32
|
+
import { existsSync, cpSync } from "node:fs";
|
|
31
33
|
|
|
32
34
|
// ─── generateMilestoneReport ──────────────────────────────────────────────────
|
|
33
35
|
|
|
@@ -233,26 +235,23 @@ export async function runPreDispatch(
|
|
|
233
235
|
loopState.stuckRecoveryAttempts = 0;
|
|
234
236
|
|
|
235
237
|
// Worktree lifecycle on milestone transition — merge current, enter next
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
s.currentMilestoneId!,
|
|
245
|
-
`[GSD] ${s.currentMilestoneId} complete`,
|
|
246
|
-
`Milestone ${s.currentMilestoneId} completed by GSD auto-mode.\n\nSee .gsd/${s.currentMilestoneId}/ for details.`,
|
|
238
|
+
try {
|
|
239
|
+
deps.resolver.mergeAndExit(s.currentMilestoneId!, ctx.ui);
|
|
240
|
+
} catch (mergeErr) {
|
|
241
|
+
if (mergeErr instanceof MergeConflictError) {
|
|
242
|
+
// Real code conflicts — stop the loop instead of retrying forever (#2330)
|
|
243
|
+
ctx.ui.notify(
|
|
244
|
+
`Merge conflict: ${mergeErr.conflictedFiles.join(", ")}. Resolve conflicts manually and run /gsd auto to resume.`,
|
|
245
|
+
"error",
|
|
247
246
|
);
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
}
|
|
251
|
-
} catch {
|
|
252
|
-
// Non-fatal — PR creation is best-effort
|
|
247
|
+
await deps.stopAuto(ctx, pi, `Merge conflict on milestone ${s.currentMilestoneId}`);
|
|
248
|
+
return { action: "break", reason: "merge-conflict" };
|
|
253
249
|
}
|
|
250
|
+
// Non-conflict errors — log and continue
|
|
254
251
|
}
|
|
255
252
|
|
|
253
|
+
// PR creation (auto_pr) is handled inside mergeMilestoneToMain (#2302)
|
|
254
|
+
|
|
256
255
|
deps.invalidateAllCaches();
|
|
257
256
|
|
|
258
257
|
state = await deps.deriveState(s.basePath);
|
|
@@ -279,9 +278,17 @@ export async function runPreDispatch(
|
|
|
279
278
|
// Reset completed-units tracking for the new milestone — stale entries
|
|
280
279
|
// from the previous milestone cause the dispatch loop to skip units
|
|
281
280
|
// that haven't actually been completed in the new milestone's context.
|
|
281
|
+
// Archive the old completed-units.json instead of wiping it (#2313).
|
|
282
282
|
s.completedUnits = [];
|
|
283
283
|
try {
|
|
284
284
|
const completedKeysPath = join(gsdRoot(s.basePath), "completed-units.json");
|
|
285
|
+
if (existsSync(completedKeysPath) && s.currentMilestoneId) {
|
|
286
|
+
const archivePath = join(
|
|
287
|
+
gsdRoot(s.basePath),
|
|
288
|
+
`completed-units-${s.currentMilestoneId}.json`,
|
|
289
|
+
);
|
|
290
|
+
cpSync(completedKeysPath, archivePath);
|
|
291
|
+
}
|
|
285
292
|
atomicWriteSync(completedKeysPath, JSON.stringify([], null, 2));
|
|
286
293
|
} catch { /* non-fatal */ }
|
|
287
294
|
|
|
@@ -322,25 +329,20 @@ export async function runPreDispatch(
|
|
|
322
329
|
if (incomplete.length === 0 && state.registry.length > 0) {
|
|
323
330
|
// All milestones complete — merge milestone branch before stopping
|
|
324
331
|
if (s.currentMilestoneId) {
|
|
325
|
-
|
|
326
|
-
|
|
327
|
-
|
|
328
|
-
|
|
329
|
-
|
|
330
|
-
|
|
331
|
-
|
|
332
|
-
s.basePath,
|
|
333
|
-
s.currentMilestoneId,
|
|
334
|
-
`[GSD] ${s.currentMilestoneId} complete`,
|
|
335
|
-
`Milestone ${s.currentMilestoneId} completed by GSD auto-mode.\n\nSee .gsd/${s.currentMilestoneId}/ for details.`,
|
|
332
|
+
try {
|
|
333
|
+
deps.resolver.mergeAndExit(s.currentMilestoneId, ctx.ui);
|
|
334
|
+
} catch (mergeErr) {
|
|
335
|
+
if (mergeErr instanceof MergeConflictError) {
|
|
336
|
+
ctx.ui.notify(
|
|
337
|
+
`Merge conflict: ${mergeErr.conflictedFiles.join(", ")}. Resolve conflicts manually and run /gsd auto to resume.`,
|
|
338
|
+
"error",
|
|
336
339
|
);
|
|
337
|
-
|
|
338
|
-
|
|
339
|
-
}
|
|
340
|
-
} catch {
|
|
341
|
-
// Non-fatal — PR creation is best-effort
|
|
340
|
+
await deps.stopAuto(ctx, pi, `Merge conflict on milestone ${s.currentMilestoneId}`);
|
|
341
|
+
return { action: "break", reason: "merge-conflict" };
|
|
342
342
|
}
|
|
343
343
|
}
|
|
344
|
+
|
|
345
|
+
// PR creation (auto_pr) is handled inside mergeMilestoneToMain (#2302)
|
|
344
346
|
}
|
|
345
347
|
deps.sendDesktopNotification(
|
|
346
348
|
"GSD",
|
|
@@ -422,25 +424,20 @@ export async function runPreDispatch(
|
|
|
422
424
|
if (state.phase === "complete") {
|
|
423
425
|
// Milestone merge on complete (before closeout so branch state is clean)
|
|
424
426
|
if (s.currentMilestoneId) {
|
|
425
|
-
|
|
426
|
-
|
|
427
|
-
|
|
428
|
-
|
|
429
|
-
|
|
430
|
-
|
|
431
|
-
|
|
432
|
-
s.basePath,
|
|
433
|
-
s.currentMilestoneId,
|
|
434
|
-
`[GSD] ${s.currentMilestoneId} complete`,
|
|
435
|
-
`Milestone ${s.currentMilestoneId} completed by GSD auto-mode.\n\nSee .gsd/${s.currentMilestoneId}/ for details.`,
|
|
427
|
+
try {
|
|
428
|
+
deps.resolver.mergeAndExit(s.currentMilestoneId, ctx.ui);
|
|
429
|
+
} catch (mergeErr) {
|
|
430
|
+
if (mergeErr instanceof MergeConflictError) {
|
|
431
|
+
ctx.ui.notify(
|
|
432
|
+
`Merge conflict: ${mergeErr.conflictedFiles.join(", ")}. Resolve conflicts manually and run /gsd auto to resume.`,
|
|
433
|
+
"error",
|
|
436
434
|
);
|
|
437
|
-
|
|
438
|
-
|
|
439
|
-
}
|
|
440
|
-
} catch {
|
|
441
|
-
// Non-fatal — PR creation is best-effort
|
|
435
|
+
await deps.stopAuto(ctx, pi, `Merge conflict on milestone ${s.currentMilestoneId}`);
|
|
436
|
+
return { action: "break", reason: "merge-conflict" };
|
|
442
437
|
}
|
|
443
438
|
}
|
|
439
|
+
|
|
440
|
+
// PR creation (auto_pr) is handled inside mergeMilestoneToMain (#2302)
|
|
444
441
|
}
|
|
445
442
|
deps.sendDesktopNotification(
|
|
446
443
|
"GSD",
|
|
@@ -1307,6 +1307,12 @@ export async function buildCompleteMilestonePrompt(
|
|
|
1307
1307
|
roadmapPath: roadmapRel,
|
|
1308
1308
|
inlinedContext,
|
|
1309
1309
|
milestoneSummaryPath,
|
|
1310
|
+
skillActivation: buildSkillActivationBlock({
|
|
1311
|
+
base,
|
|
1312
|
+
milestoneId: mid,
|
|
1313
|
+
milestoneTitle: midTitle,
|
|
1314
|
+
extraContext: [inlinedContext],
|
|
1315
|
+
}),
|
|
1310
1316
|
});
|
|
1311
1317
|
}
|
|
1312
1318
|
|
|
@@ -1390,6 +1396,12 @@ export async function buildValidateMilestonePrompt(
|
|
|
1390
1396
|
inlinedContext,
|
|
1391
1397
|
validationPath: validationOutputPath,
|
|
1392
1398
|
remediationRound: String(remediationRound),
|
|
1399
|
+
skillActivation: buildSkillActivationBlock({
|
|
1400
|
+
base,
|
|
1401
|
+
milestoneId: mid,
|
|
1402
|
+
milestoneTitle: midTitle,
|
|
1403
|
+
extraContext: [inlinedContext],
|
|
1404
|
+
}),
|
|
1393
1405
|
});
|
|
1394
1406
|
}
|
|
1395
1407
|
|
|
@@ -1500,6 +1512,12 @@ export async function buildRunUatPrompt(
|
|
|
1500
1512
|
uatResultPath,
|
|
1501
1513
|
uatType,
|
|
1502
1514
|
inlinedContext,
|
|
1515
|
+
skillActivation: buildSkillActivationBlock({
|
|
1516
|
+
base,
|
|
1517
|
+
milestoneId: mid,
|
|
1518
|
+
sliceId,
|
|
1519
|
+
extraContext: [inlinedContext],
|
|
1520
|
+
}),
|
|
1503
1521
|
});
|
|
1504
1522
|
}
|
|
1505
1523
|
|
|
@@ -1552,11 +1570,16 @@ export async function buildReassessRoadmapPrompt(
|
|
|
1552
1570
|
milestoneTitle: midTitle,
|
|
1553
1571
|
completedSliceId,
|
|
1554
1572
|
roadmapPath: roadmapRel,
|
|
1555
|
-
completedSliceSummaryPath: summaryRel,
|
|
1556
1573
|
assessmentPath,
|
|
1557
1574
|
inlinedContext,
|
|
1558
1575
|
deferredCaptures,
|
|
1559
1576
|
commitInstruction: reassessCommitInstruction,
|
|
1577
|
+
skillActivation: buildSkillActivationBlock({
|
|
1578
|
+
base,
|
|
1579
|
+
milestoneId: mid,
|
|
1580
|
+
milestoneTitle: midTitle,
|
|
1581
|
+
extraContext: [inlinedContext, deferredCaptures],
|
|
1582
|
+
}),
|
|
1560
1583
|
});
|
|
1561
1584
|
}
|
|
1562
1585
|
|
|
@@ -551,6 +551,20 @@ export async function bootstrapAutoSession(
|
|
|
551
551
|
}
|
|
552
552
|
}
|
|
553
553
|
|
|
554
|
+
// Gate: abort bootstrap if the DB file exists but the provider is
|
|
555
|
+
// still unavailable after both open attempts above. Without this,
|
|
556
|
+
// auto-mode starts but every gsd_task_complete / gsd_slice_complete
|
|
557
|
+
// call returns "db_unavailable", triggering artifact-retry which
|
|
558
|
+
// re-dispatches the same task — producing an infinite loop (#2419).
|
|
559
|
+
if (existsSync(gsdDbPath) && !isDbAvailable()) {
|
|
560
|
+
ctx.ui.notify(
|
|
561
|
+
"SQLite database exists but failed to open. Auto-mode cannot proceed without a working database provider. " +
|
|
562
|
+
"Check for corrupt gsd.db or missing native SQLite bindings.",
|
|
563
|
+
"error",
|
|
564
|
+
);
|
|
565
|
+
return releaseLockAndReturn();
|
|
566
|
+
}
|
|
567
|
+
|
|
554
568
|
// Initialize metrics
|
|
555
569
|
initMetrics(s.basePath);
|
|
556
570
|
|
|
@@ -8,6 +8,7 @@
|
|
|
8
8
|
|
|
9
9
|
import type { ExtensionAPI, ExtensionContext } from "@gsd/pi-coding-agent";
|
|
10
10
|
import { readUnitRuntimeRecord, writeUnitRuntimeRecord } from "./unit-runtime.js";
|
|
11
|
+
import { isDbAvailable, getMilestoneSlices, getSliceTasks } from "./gsd-db.js";
|
|
11
12
|
import { resolveAutoSupervisorConfig } from "./preferences.js";
|
|
12
13
|
import type { GSDPreferences } from "./preferences.js";
|
|
13
14
|
import { computeBudgets, resolveExecutorContextWindow } from "./context-budget.js";
|
|
@@ -32,6 +33,8 @@ export interface SupervisionContext {
|
|
|
32
33
|
buildSnapshotOpts: () => CloseoutOptions & Record<string, unknown>;
|
|
33
34
|
buildRecoveryContext: () => RecoveryContext;
|
|
34
35
|
pauseAuto: (ctx?: ExtensionContext, pi?: ExtensionAPI) => Promise<void>;
|
|
36
|
+
/** Optional task estimate string (e.g. "30m", "2h") for timeout scaling (#2243). */
|
|
37
|
+
taskEstimate?: string;
|
|
35
38
|
}
|
|
36
39
|
|
|
37
40
|
/**
|
|
@@ -41,13 +44,71 @@ export interface SupervisionContext {
|
|
|
41
44
|
* 3. Hard timeout (pause + recovery)
|
|
42
45
|
* 4. Context-pressure monitor (continue-here)
|
|
43
46
|
*/
|
|
47
|
+
|
|
48
|
+
/**
|
|
49
|
+
* Parse a task estimate string (e.g. "30m", "2h", "1h30m") into minutes.
|
|
50
|
+
* Returns null if the string cannot be parsed.
|
|
51
|
+
*/
|
|
52
|
+
export function parseEstimateMinutes(estimate: string): number | null {
|
|
53
|
+
if (!estimate || typeof estimate !== "string") return null;
|
|
54
|
+
const trimmed = estimate.trim();
|
|
55
|
+
if (!trimmed) return null;
|
|
56
|
+
|
|
57
|
+
let totalMinutes = 0;
|
|
58
|
+
let matched = false;
|
|
59
|
+
|
|
60
|
+
// Match hours component
|
|
61
|
+
const hoursMatch = trimmed.match(/(\d+)\s*h/i);
|
|
62
|
+
if (hoursMatch) {
|
|
63
|
+
totalMinutes += Number(hoursMatch[1]) * 60;
|
|
64
|
+
matched = true;
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
// Match minutes component
|
|
68
|
+
const minutesMatch = trimmed.match(/(\d+)\s*m/i);
|
|
69
|
+
if (minutesMatch) {
|
|
70
|
+
totalMinutes += Number(minutesMatch[1]);
|
|
71
|
+
matched = true;
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
return matched ? totalMinutes : null;
|
|
75
|
+
}
|
|
76
|
+
|
|
44
77
|
export function startUnitSupervision(sctx: SupervisionContext): void {
|
|
45
78
|
const { s, ctx, pi, unitType, unitId, prefs, buildSnapshotOpts, buildRecoveryContext, pauseAuto } = sctx;
|
|
46
79
|
|
|
47
80
|
const supervisor = resolveAutoSupervisorConfig();
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
81
|
+
|
|
82
|
+
// Scale timeouts based on task estimate annotations (#2243).
|
|
83
|
+
// If the task has an est: annotation, use it to extend the hard and soft timeouts
|
|
84
|
+
// so longer tasks don't get prematurely timed out.
|
|
85
|
+
let taskEstimate = sctx.taskEstimate;
|
|
86
|
+
if (!taskEstimate && unitType === "task" && isDbAvailable()) {
|
|
87
|
+
// Look up the task estimate from the DB (#2243).
|
|
88
|
+
try {
|
|
89
|
+
if (s.currentMilestoneId) {
|
|
90
|
+
const slices = getMilestoneSlices(s.currentMilestoneId);
|
|
91
|
+
for (const slice of slices) {
|
|
92
|
+
const tasks = getSliceTasks(s.currentMilestoneId, slice.id);
|
|
93
|
+
const task = tasks.find(t => t.id === unitId);
|
|
94
|
+
if (task?.estimate) {
|
|
95
|
+
taskEstimate = task.estimate;
|
|
96
|
+
break;
|
|
97
|
+
}
|
|
98
|
+
}
|
|
99
|
+
}
|
|
100
|
+
} catch {
|
|
101
|
+
// Non-fatal — fall through with no estimate
|
|
102
|
+
}
|
|
103
|
+
}
|
|
104
|
+
const estimateMinutes = taskEstimate ? parseEstimateMinutes(taskEstimate) : null;
|
|
105
|
+
const timeoutScale = estimateMinutes && estimateMinutes > 0
|
|
106
|
+
? Math.max(1, estimateMinutes / 10) // 10min task = 1x, 30min = 3x, 2h = 12x
|
|
107
|
+
: 1;
|
|
108
|
+
|
|
109
|
+
const softTimeoutMs = (supervisor.soft_timeout_minutes ?? 0) * 60 * 1000 * timeoutScale;
|
|
110
|
+
const idleTimeoutMs = (supervisor.idle_timeout_minutes ?? 0) * 60 * 1000; // idle not scaled — idle is idle
|
|
111
|
+
const hardTimeoutMs = (supervisor.hard_timeout_minutes ?? 0) * 60 * 1000 * timeoutScale;
|
|
51
112
|
|
|
52
113
|
// ── 1. Soft timeout warning ──
|
|
53
114
|
s.wrapupWarningHandle = setTimeout(() => {
|
|
@@ -93,6 +93,11 @@ export function syncStateToProjectRoot(
|
|
|
93
93
|
{ force: true },
|
|
94
94
|
);
|
|
95
95
|
|
|
96
|
+
// 3. metrics.json — session cost/token tracking (#2313).
|
|
97
|
+
// Without this, metrics accumulated in the worktree are invisible from the
|
|
98
|
+
// project root and never appear in the dashboard or skill-health reports.
|
|
99
|
+
safeCopy(join(wtGsd, "metrics.json"), join(prGsd, "metrics.json"), { force: true });
|
|
100
|
+
|
|
96
101
|
// 4. Runtime records — unit dispatch state used by selfHealRuntimeRecords().
|
|
97
102
|
// Without this, a crash during a unit leaves the runtime record only in the
|
|
98
103
|
// worktree. If the next session resolves basePath before worktree re-entry,
|
|
@@ -162,6 +162,7 @@ export function syncGsdStateToWorktree(
|
|
|
162
162
|
"OVERRIDES.md",
|
|
163
163
|
"QUEUE.md",
|
|
164
164
|
"completed-units.json",
|
|
165
|
+
"metrics.json",
|
|
165
166
|
];
|
|
166
167
|
for (const f of rootFiles) {
|
|
167
168
|
const src = join(mainGsd, f);
|
|
@@ -325,8 +326,9 @@ export function syncWorktreeStateBack(
|
|
|
325
326
|
// ── 1. Sync root-level .gsd/ files back ──────────────────────────────
|
|
326
327
|
// The worktree is authoritative — complete-milestone updates REQUIREMENTS,
|
|
327
328
|
// PROJECT, etc. These must overwrite main's copies so they survive teardown.
|
|
328
|
-
// Also includes QUEUE.md
|
|
329
|
-
// milestone closeout and lost on teardown without explicit sync
|
|
329
|
+
// Also includes QUEUE.md, completed-units.json, and metrics.json which are
|
|
330
|
+
// written during milestone closeout and lost on teardown without explicit sync
|
|
331
|
+
// (#1787, #2313).
|
|
330
332
|
const rootFiles = [
|
|
331
333
|
"DECISIONS.md",
|
|
332
334
|
"REQUIREMENTS.md",
|
|
@@ -335,6 +337,7 @@ export function syncWorktreeStateBack(
|
|
|
335
337
|
"OVERRIDES.md",
|
|
336
338
|
"QUEUE.md",
|
|
337
339
|
"completed-units.json",
|
|
340
|
+
"metrics.json",
|
|
338
341
|
];
|
|
339
342
|
for (const f of rootFiles) {
|
|
340
343
|
const src = join(wtGsd, f);
|
|
@@ -1320,9 +1323,9 @@ export function mergeMilestoneToMain(
|
|
|
1320
1323
|
}
|
|
1321
1324
|
}
|
|
1322
1325
|
|
|
1323
|
-
// 9b. Auto-create PR if enabled (
|
|
1326
|
+
// 9b. Auto-create PR if enabled (#2302: no longer gated on pushed/auto_push)
|
|
1324
1327
|
let prCreated = false;
|
|
1325
|
-
if (prefs.auto_pr === true &&
|
|
1328
|
+
if (prefs.auto_pr === true && !nothingToCommit) {
|
|
1326
1329
|
const remote = prefs.remote ?? "origin";
|
|
1327
1330
|
const prTarget = prefs.pr_target_branch ?? mainBranch;
|
|
1328
1331
|
try {
|
|
@@ -1332,9 +1335,9 @@ export function mergeMilestoneToMain(
|
|
|
1332
1335
|
stdio: ["ignore", "pipe", "pipe"],
|
|
1333
1336
|
encoding: "utf-8",
|
|
1334
1337
|
});
|
|
1335
|
-
// Create PR via gh CLI
|
|
1338
|
+
// Create PR via gh CLI with explicit --head and --base (#2302)
|
|
1336
1339
|
execFileSync("gh", [
|
|
1337
|
-
"pr", "create",
|
|
1340
|
+
"pr", "create", "--draft",
|
|
1338
1341
|
"--base", prTarget,
|
|
1339
1342
|
"--head", milestoneBranch,
|
|
1340
1343
|
"--title", `Milestone ${milestoneId} complete`,
|
|
@@ -610,14 +610,48 @@ export async function stopAuto(
|
|
|
610
610
|
}
|
|
611
611
|
|
|
612
612
|
// ── Step 4: Auto-worktree exit ──
|
|
613
|
+
// When the milestone is complete (has a SUMMARY), merge the worktree branch
|
|
614
|
+
// back to main so code isn't stranded on the worktree branch (#2317).
|
|
615
|
+
// For incomplete milestones, preserve the branch for later resumption.
|
|
613
616
|
try {
|
|
614
617
|
if (s.currentMilestoneId) {
|
|
615
618
|
const notifyCtx = ctx
|
|
616
619
|
? { notify: ctx.ui.notify.bind(ctx.ui) }
|
|
617
620
|
: { notify: () => {} };
|
|
618
|
-
buildResolver()
|
|
619
|
-
|
|
620
|
-
|
|
621
|
+
const resolver = buildResolver();
|
|
622
|
+
|
|
623
|
+
// Check if the milestone is complete — SUMMARY file is the authoritative signal.
|
|
624
|
+
let milestoneComplete = false;
|
|
625
|
+
try {
|
|
626
|
+
const summaryPath = resolveMilestoneFile(
|
|
627
|
+
s.originalBasePath || s.basePath,
|
|
628
|
+
s.currentMilestoneId,
|
|
629
|
+
"SUMMARY",
|
|
630
|
+
);
|
|
631
|
+
if (!summaryPath) {
|
|
632
|
+
// Also check in the worktree path (SUMMARY may not be synced yet)
|
|
633
|
+
const wtSummaryPath = resolveMilestoneFile(
|
|
634
|
+
s.basePath,
|
|
635
|
+
s.currentMilestoneId,
|
|
636
|
+
"SUMMARY",
|
|
637
|
+
);
|
|
638
|
+
milestoneComplete = wtSummaryPath !== null;
|
|
639
|
+
} else {
|
|
640
|
+
milestoneComplete = true;
|
|
641
|
+
}
|
|
642
|
+
} catch {
|
|
643
|
+
// Non-fatal — fall through to preserveBranch path
|
|
644
|
+
}
|
|
645
|
+
|
|
646
|
+
if (milestoneComplete) {
|
|
647
|
+
// Milestone is complete — merge worktree branch back to main
|
|
648
|
+
resolver.mergeAndExit(s.currentMilestoneId, notifyCtx);
|
|
649
|
+
} else {
|
|
650
|
+
// Milestone still in progress — preserve branch for later resumption
|
|
651
|
+
resolver.exitMilestone(s.currentMilestoneId, notifyCtx, {
|
|
652
|
+
preserveBranch: true,
|
|
653
|
+
});
|
|
654
|
+
}
|
|
621
655
|
}
|
|
622
656
|
} catch (e) {
|
|
623
657
|
debugLog("stop-cleanup-worktree", { error: e instanceof Error ? e.message : String(e) });
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import { Type } from "@sinclair/typebox";
|
|
2
2
|
import type { ExtensionAPI } from "@gsd/pi-coding-agent";
|
|
3
|
+
import { Text } from "@gsd/pi-tui";
|
|
3
4
|
|
|
4
5
|
import { findMilestoneIds, nextMilestoneId, claimReservedId, getReservedMilestoneIds } from "../guided-flow.js";
|
|
5
6
|
import { loadEffectiveGSDPreferences } from "../preferences.js";
|
|
@@ -87,6 +88,22 @@ export function registerDbTools(pi: ExtensionAPI): void {
|
|
|
87
88
|
], { description: "Who made this decision: 'human' (user directed), 'agent' (LLM decided autonomously), or 'collaborative' (discussed and agreed). Default: 'agent'" })),
|
|
88
89
|
}),
|
|
89
90
|
execute: decisionSaveExecute,
|
|
91
|
+
renderCall(args: any, theme: any) {
|
|
92
|
+
let text = theme.fg("toolTitle", theme.bold("decision_save "));
|
|
93
|
+
if (args.scope) text += theme.fg("accent", `[${args.scope}] `);
|
|
94
|
+
if (args.decision) text += theme.fg("muted", args.decision);
|
|
95
|
+
if (args.choice) text += theme.fg("dim", ` — ${args.choice}`);
|
|
96
|
+
return new Text(text, 0, 0);
|
|
97
|
+
},
|
|
98
|
+
renderResult(result: any, _options: any, theme: any) {
|
|
99
|
+
const d = result.details;
|
|
100
|
+
if (result.isError || d?.error) {
|
|
101
|
+
return new Text(theme.fg("error", `Error: ${d?.error ?? "unknown"}`), 0, 0);
|
|
102
|
+
}
|
|
103
|
+
let text = theme.fg("success", `Decision ${d?.id ?? ""} saved`);
|
|
104
|
+
if (d?.id) text += theme.fg("dim", ` → DECISIONS.md`);
|
|
105
|
+
return new Text(text, 0, 0);
|
|
106
|
+
},
|
|
90
107
|
};
|
|
91
108
|
|
|
92
109
|
pi.registerTool(decisionSaveTool);
|
|
@@ -157,6 +174,22 @@ export function registerDbTools(pi: ExtensionAPI): void {
|
|
|
157
174
|
supporting_slices: Type.Optional(Type.String({ description: "Supporting slices" })),
|
|
158
175
|
}),
|
|
159
176
|
execute: requirementUpdateExecute,
|
|
177
|
+
renderCall(args: any, theme: any) {
|
|
178
|
+
let text = theme.fg("toolTitle", theme.bold("requirement_update "));
|
|
179
|
+
if (args.id) text += theme.fg("accent", args.id);
|
|
180
|
+
const fields = ["status", "validation", "notes", "description"].filter((f) => args[f]);
|
|
181
|
+
if (fields.length > 0) text += theme.fg("dim", ` (${fields.join(", ")})`);
|
|
182
|
+
return new Text(text, 0, 0);
|
|
183
|
+
},
|
|
184
|
+
renderResult(result: any, _options: any, theme: any) {
|
|
185
|
+
const d = result.details;
|
|
186
|
+
if (result.isError || d?.error) {
|
|
187
|
+
return new Text(theme.fg("error", `Error: ${d?.error ?? "unknown"}`), 0, 0);
|
|
188
|
+
}
|
|
189
|
+
let text = theme.fg("success", `Requirement ${d?.id ?? ""} updated`);
|
|
190
|
+
text += theme.fg("dim", ` → REQUIREMENTS.md`);
|
|
191
|
+
return new Text(text, 0, 0);
|
|
192
|
+
},
|
|
160
193
|
};
|
|
161
194
|
|
|
162
195
|
pi.registerTool(requirementUpdateTool);
|
|
@@ -235,6 +268,22 @@ export function registerDbTools(pi: ExtensionAPI): void {
|
|
|
235
268
|
content: Type.String({ description: "The full markdown content of the artifact" }),
|
|
236
269
|
}),
|
|
237
270
|
execute: summarySaveExecute,
|
|
271
|
+
renderCall(args: any, theme: any) {
|
|
272
|
+
let text = theme.fg("toolTitle", theme.bold("summary_save "));
|
|
273
|
+
if (args.artifact_type) text += theme.fg("accent", args.artifact_type);
|
|
274
|
+
const path = [args.milestone_id, args.slice_id, args.task_id].filter(Boolean).join("/");
|
|
275
|
+
if (path) text += theme.fg("dim", ` ${path}`);
|
|
276
|
+
return new Text(text, 0, 0);
|
|
277
|
+
},
|
|
278
|
+
renderResult(result: any, _options: any, theme: any) {
|
|
279
|
+
const d = result.details;
|
|
280
|
+
if (result.isError || d?.error) {
|
|
281
|
+
return new Text(theme.fg("error", `Error: ${d?.error ?? "unknown"}`), 0, 0);
|
|
282
|
+
}
|
|
283
|
+
let text = theme.fg("success", `${d?.artifact_type ?? "Artifact"} saved`);
|
|
284
|
+
if (d?.path) text += theme.fg("dim", ` → ${d.path}`);
|
|
285
|
+
return new Text(text, 0, 0);
|
|
286
|
+
},
|
|
238
287
|
};
|
|
239
288
|
|
|
240
289
|
pi.registerTool(summarySaveTool);
|
|
@@ -248,6 +297,7 @@ export function registerDbTools(pi: ExtensionAPI): void {
|
|
|
248
297
|
// This guarantees the ID shown in the UI matches the one materialised on disk.
|
|
249
298
|
const reserved = claimReservedId();
|
|
250
299
|
if (reserved) {
|
|
300
|
+
await ensureMilestoneDbRow(reserved);
|
|
251
301
|
return {
|
|
252
302
|
content: [{ type: "text" as const, text: reserved }],
|
|
253
303
|
details: { operation: "generate_milestone_id", id: reserved, source: "reserved" } as any,
|
|
@@ -259,6 +309,7 @@ export function registerDbTools(pi: ExtensionAPI): void {
|
|
|
259
309
|
const uniqueEnabled = !!loadEffectiveGSDPreferences()?.preferences?.unique_milestone_ids;
|
|
260
310
|
const allIds = [...new Set([...existingIds, ...getReservedMilestoneIds()])];
|
|
261
311
|
const newId = nextMilestoneId(allIds, uniqueEnabled);
|
|
312
|
+
await ensureMilestoneDbRow(newId);
|
|
262
313
|
return {
|
|
263
314
|
content: [{ type: "text" as const, text: newId }],
|
|
264
315
|
details: { operation: "generate_milestone_id", id: newId, existingCount: existingIds.length, uniqueEnabled } as any,
|
|
@@ -272,6 +323,23 @@ export function registerDbTools(pi: ExtensionAPI): void {
|
|
|
272
323
|
}
|
|
273
324
|
};
|
|
274
325
|
|
|
326
|
+
/**
|
|
327
|
+
* Insert a minimal DB row for a milestone ID so it's visible to the state
|
|
328
|
+
* machine. Uses INSERT OR IGNORE — safe to call even if gsd_plan_milestone
|
|
329
|
+
* later writes the full row. Silently skips if the DB isn't available yet
|
|
330
|
+
* (pre-migration).
|
|
331
|
+
*/
|
|
332
|
+
async function ensureMilestoneDbRow(milestoneId: string): Promise<void> {
|
|
333
|
+
const dbAvailable = await ensureDbOpen();
|
|
334
|
+
if (!dbAvailable) return;
|
|
335
|
+
try {
|
|
336
|
+
const { insertMilestone } = await import("../gsd-db.js");
|
|
337
|
+
insertMilestone({ id: milestoneId, status: "queued" });
|
|
338
|
+
} catch {
|
|
339
|
+
// Non-fatal — the safety-net in deriveStateFromDb will catch this
|
|
340
|
+
}
|
|
341
|
+
}
|
|
342
|
+
|
|
275
343
|
const milestoneGenerateIdTool = {
|
|
276
344
|
name: "gsd_milestone_generate_id",
|
|
277
345
|
label: "Generate Milestone ID",
|
|
@@ -288,6 +356,18 @@ export function registerDbTools(pi: ExtensionAPI): void {
|
|
|
288
356
|
],
|
|
289
357
|
parameters: Type.Object({}),
|
|
290
358
|
execute: milestoneGenerateIdExecute,
|
|
359
|
+
renderCall(_args: any, theme: any) {
|
|
360
|
+
return new Text(theme.fg("toolTitle", theme.bold("milestone_generate_id")), 0, 0);
|
|
361
|
+
},
|
|
362
|
+
renderResult(result: any, _options: any, theme: any) {
|
|
363
|
+
const d = result.details;
|
|
364
|
+
if (result.isError || d?.error) {
|
|
365
|
+
return new Text(theme.fg("error", `Error: ${d?.error ?? "unknown"}`), 0, 0);
|
|
366
|
+
}
|
|
367
|
+
let text = theme.fg("success", `Generated ${d?.id ?? "ID"}`);
|
|
368
|
+
if (d?.source === "reserved") text += theme.fg("dim", " (reserved)");
|
|
369
|
+
return new Text(text, 0, 0);
|
|
370
|
+
},
|
|
291
371
|
};
|
|
292
372
|
|
|
293
373
|
pi.registerTool(milestoneGenerateIdTool);
|
|
@@ -794,6 +874,74 @@ export function registerDbTools(pi: ExtensionAPI): void {
|
|
|
794
874
|
pi.registerTool(milestoneCompleteTool);
|
|
795
875
|
registerAlias(pi, milestoneCompleteTool, "gsd_milestone_complete", "gsd_complete_milestone");
|
|
796
876
|
|
|
877
|
+
// ─── gsd_validate_milestone (gsd_milestone_validate alias) ─────────────
|
|
878
|
+
|
|
879
|
+
const milestoneValidateExecute = async (_toolCallId: string, params: any, _signal: AbortSignal | undefined, _onUpdate: unknown, _ctx: unknown) => {
|
|
880
|
+
const dbAvailable = await ensureDbOpen();
|
|
881
|
+
if (!dbAvailable) {
|
|
882
|
+
return {
|
|
883
|
+
content: [{ type: "text" as const, text: "Error: GSD database is not available. Cannot validate milestone." }],
|
|
884
|
+
details: { operation: "validate_milestone", error: "db_unavailable" } as any,
|
|
885
|
+
};
|
|
886
|
+
}
|
|
887
|
+
try {
|
|
888
|
+
const { handleValidateMilestone } = await import("../tools/validate-milestone.js");
|
|
889
|
+
const result = await handleValidateMilestone(params, process.cwd());
|
|
890
|
+
if ("error" in result) {
|
|
891
|
+
return {
|
|
892
|
+
content: [{ type: "text" as const, text: `Error validating milestone: ${result.error}` }],
|
|
893
|
+
details: { operation: "validate_milestone", error: result.error } as any,
|
|
894
|
+
};
|
|
895
|
+
}
|
|
896
|
+
return {
|
|
897
|
+
content: [{ type: "text" as const, text: `Validated milestone ${result.milestoneId} — verdict: ${result.verdict}. Written to ${result.validationPath}` }],
|
|
898
|
+
details: {
|
|
899
|
+
operation: "validate_milestone",
|
|
900
|
+
milestoneId: result.milestoneId,
|
|
901
|
+
verdict: result.verdict,
|
|
902
|
+
validationPath: result.validationPath,
|
|
903
|
+
} as any,
|
|
904
|
+
};
|
|
905
|
+
} catch (err) {
|
|
906
|
+
const msg = err instanceof Error ? err.message : String(err);
|
|
907
|
+
process.stderr.write(`gsd-db: validate_milestone tool failed: ${msg}\n`);
|
|
908
|
+
return {
|
|
909
|
+
content: [{ type: "text" as const, text: `Error validating milestone: ${msg}` }],
|
|
910
|
+
details: { operation: "validate_milestone", error: msg } as any,
|
|
911
|
+
};
|
|
912
|
+
}
|
|
913
|
+
};
|
|
914
|
+
|
|
915
|
+
const milestoneValidateTool = {
|
|
916
|
+
name: "gsd_validate_milestone",
|
|
917
|
+
label: "Validate Milestone",
|
|
918
|
+
description:
|
|
919
|
+
"Validate a milestone before completion — persist validation results to the DB, render VALIDATION.md to disk. " +
|
|
920
|
+
"Records verdict (pass/needs-attention/needs-remediation) and rationale.",
|
|
921
|
+
promptSnippet: "Validate a GSD milestone (DB write + VALIDATION.md render)",
|
|
922
|
+
promptGuidelines: [
|
|
923
|
+
"Use gsd_validate_milestone when all slices are done and the milestone needs validation before completion.",
|
|
924
|
+
"Parameters: milestoneId, verdict, remediationRound, successCriteriaChecklist, sliceDeliveryAudit, crossSliceIntegration, requirementCoverage, verdictRationale, remediationPlan (optional).",
|
|
925
|
+
"If verdict is 'needs-remediation', also provide remediationPlan and use gsd_reassess_roadmap to add remediation slices to the roadmap.",
|
|
926
|
+
"On success, returns validationPath where VALIDATION.md was written.",
|
|
927
|
+
],
|
|
928
|
+
parameters: Type.Object({
|
|
929
|
+
milestoneId: Type.String({ description: "Milestone ID (e.g. M001)" }),
|
|
930
|
+
verdict: StringEnum(["pass", "needs-attention", "needs-remediation"], { description: "Validation verdict" }),
|
|
931
|
+
remediationRound: Type.Number({ description: "Remediation round (0 for first validation)" }),
|
|
932
|
+
successCriteriaChecklist: Type.String({ description: "Markdown checklist of success criteria with pass/fail and evidence" }),
|
|
933
|
+
sliceDeliveryAudit: Type.String({ description: "Markdown table auditing each slice's claimed vs delivered output" }),
|
|
934
|
+
crossSliceIntegration: Type.String({ description: "Markdown describing any cross-slice boundary mismatches" }),
|
|
935
|
+
requirementCoverage: Type.String({ description: "Markdown describing any unaddressed requirements" }),
|
|
936
|
+
verdictRationale: Type.String({ description: "Why this verdict was chosen" }),
|
|
937
|
+
remediationPlan: Type.Optional(Type.String({ description: "Remediation plan (required if verdict is needs-remediation)" })),
|
|
938
|
+
}),
|
|
939
|
+
execute: milestoneValidateExecute,
|
|
940
|
+
};
|
|
941
|
+
|
|
942
|
+
pi.registerTool(milestoneValidateTool);
|
|
943
|
+
registerAlias(pi, milestoneValidateTool, "gsd_milestone_validate", "gsd_validate_milestone");
|
|
944
|
+
|
|
797
945
|
// ─── gsd_replan_slice (gsd_slice_replan alias) ─────────────────────────
|
|
798
946
|
|
|
799
947
|
const replanSliceExecute = async (_toolCallId: string, params: any, _signal: AbortSignal | undefined, _onUpdate: unknown, _ctx: unknown) => {
|