gsd-pi 2.65.0-dev.5c8557b → 2.65.0-dev.800ece0
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/dist/mcp-server.js +6 -2
- package/dist/resources/extensions/browser-tools/capture.js +20 -1
- package/dist/resources/extensions/browser-tools/tests/capture-sharp-optional.test.cjs +93 -0
- package/dist/resources/extensions/gsd/auto/finalize-timeout.js +2 -0
- package/dist/resources/extensions/gsd/auto/loop.js +2 -2
- package/dist/resources/extensions/gsd/auto/phases.js +48 -5
- package/dist/resources/extensions/gsd/auto/run-unit.js +13 -2
- package/dist/resources/extensions/gsd/auto/session.js +4 -0
- package/dist/resources/extensions/gsd/auto/types.js +2 -0
- package/dist/resources/extensions/gsd/auto-dashboard.js +2 -1
- package/dist/resources/extensions/gsd/auto-dispatch.js +99 -9
- package/dist/resources/extensions/gsd/auto-model-selection.js +7 -5
- package/dist/resources/extensions/gsd/auto-post-unit.js +17 -6
- package/dist/resources/extensions/gsd/auto-prompts.js +24 -0
- package/dist/resources/extensions/gsd/auto-recovery.js +40 -22
- package/dist/resources/extensions/gsd/auto-start.js +175 -12
- package/dist/resources/extensions/gsd/auto-tool-tracking.js +10 -0
- package/dist/resources/extensions/gsd/auto-worktree.js +29 -7
- package/dist/resources/extensions/gsd/auto.js +21 -15
- package/dist/resources/extensions/gsd/bootstrap/agent-end-recovery.js +17 -4
- package/dist/resources/extensions/gsd/bootstrap/db-tools.js +10 -0
- package/dist/resources/extensions/gsd/bootstrap/query-tools.js +6 -4
- package/dist/resources/extensions/gsd/bootstrap/register-extension.js +5 -1
- package/dist/resources/extensions/gsd/bootstrap/register-hooks.js +11 -3
- package/dist/resources/extensions/gsd/bootstrap/system-context.js +3 -1
- package/dist/resources/extensions/gsd/bootstrap/write-gate.js +31 -1
- package/dist/resources/extensions/gsd/commands/context.js +8 -1
- package/dist/resources/extensions/gsd/commands/handlers/core.js +23 -2
- package/dist/resources/extensions/gsd/commands-extensions.js +1 -1
- package/dist/resources/extensions/gsd/config-overlay.js +312 -0
- package/dist/resources/extensions/gsd/db-writer.js +13 -3
- package/dist/resources/extensions/gsd/detection.js +1 -1
- package/dist/resources/extensions/gsd/dispatch-guard.js +2 -1
- package/dist/resources/extensions/gsd/docs/preferences-reference.md +1 -0
- package/dist/resources/extensions/gsd/doctor.js +2 -1
- package/dist/resources/extensions/gsd/files.js +17 -0
- package/dist/resources/extensions/gsd/gitignore.js +1 -0
- package/dist/resources/extensions/gsd/gsd-db.js +47 -4
- package/dist/resources/extensions/gsd/guided-flow.js +220 -29
- package/dist/resources/extensions/gsd/index.js +1 -1
- package/dist/resources/extensions/gsd/json-persistence.js +5 -2
- package/dist/resources/extensions/gsd/md-importer.js +14 -7
- package/dist/resources/extensions/gsd/notification-overlay.js +1 -1
- package/dist/resources/extensions/gsd/notification-widget.js +2 -1
- package/dist/resources/extensions/gsd/parallel-monitor-overlay.js +1 -1
- package/dist/resources/extensions/gsd/parallel-orchestrator.js +17 -11
- package/dist/resources/extensions/gsd/pre-execution-checks.js +26 -5
- package/dist/resources/extensions/gsd/preferences-types.js +3 -0
- package/dist/resources/extensions/gsd/preferences-validation.js +45 -1
- package/dist/resources/extensions/gsd/preferences.js +9 -2
- package/dist/resources/extensions/gsd/preparation.js +1092 -0
- package/dist/resources/extensions/gsd/prompt-validation.js +67 -0
- package/dist/resources/extensions/gsd/prompts/complete-milestone.md +3 -3
- package/dist/resources/extensions/gsd/prompts/complete-slice.md +1 -1
- package/dist/resources/extensions/gsd/prompts/discuss-prepared.md +424 -0
- package/dist/resources/extensions/gsd/prompts/discuss.md +2 -0
- package/dist/resources/extensions/gsd/prompts/guided-discuss-milestone.md +6 -1
- package/dist/resources/extensions/gsd/prompts/guided-discuss-slice.md +5 -4
- package/dist/resources/extensions/gsd/prompts/parallel-research-slices.md +23 -0
- package/dist/resources/extensions/gsd/prompts/queue.md +2 -0
- package/dist/resources/extensions/gsd/prompts/rethink.md +2 -1
- package/dist/resources/extensions/gsd/prompts/system.md +2 -2
- package/dist/resources/extensions/gsd/prompts/validate-milestone.md +56 -23
- package/dist/resources/extensions/gsd/quick.js +19 -15
- package/dist/resources/extensions/gsd/reactive-graph.js +12 -0
- package/dist/resources/extensions/gsd/roadmap-slices.js +24 -5
- package/dist/resources/extensions/gsd/safety/content-validator.js +3 -3
- package/dist/resources/extensions/gsd/session-lock.js +23 -1
- package/dist/resources/extensions/gsd/state.js +115 -28
- package/dist/resources/extensions/gsd/templates/context-enhanced.md +138 -0
- package/dist/resources/extensions/gsd/tools/complete-milestone.js +15 -3
- package/dist/resources/extensions/gsd/tools/complete-slice.js +27 -6
- package/dist/resources/extensions/gsd/tools/complete-task.js +31 -7
- package/dist/resources/extensions/gsd/tools/plan-milestone.js +7 -5
- package/dist/resources/extensions/gsd/tools/reassess-roadmap.js +5 -2
- package/dist/resources/extensions/gsd/tools/reopen-milestone.js +119 -0
- package/dist/resources/extensions/gsd/tools/reopen-slice.js +30 -0
- package/dist/resources/extensions/gsd/tools/reopen-task.js +18 -0
- package/dist/resources/extensions/gsd/triage-resolution.js +33 -16
- package/dist/resources/extensions/gsd/undo.js +3 -2
- package/dist/resources/extensions/gsd/workflow-events.js +1 -0
- package/dist/resources/extensions/gsd/workflow-logger.js +1 -1
- package/dist/resources/extensions/gsd/workflow-projections.js +7 -9
- package/dist/resources/extensions/gsd/workflow-reconcile.js +100 -9
- package/dist/resources/extensions/gsd/workflow-templates.js +11 -2
- package/dist/resources/extensions/gsd/worktree-manager.js +5 -2
- package/dist/resources/extensions/gsd/worktree.js +9 -0
- package/dist/resources/extensions/shared/interview-ui.js +1 -1
- package/dist/resources/extensions/subagent/agents.js +19 -5
- package/dist/web/standalone/.next/BUILD_ID +1 -1
- package/dist/web/standalone/.next/app-path-routes-manifest.json +18 -18
- 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 +1 -1
- 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 +18 -18
- package/dist/web/standalone/.next/server/middleware-build-manifest.js +1 -1
- package/dist/web/standalone/.next/server/middleware-react-loadable-manifest.js +1 -1
- package/dist/web/standalone/.next/server/pages/404.html +1 -1
- package/dist/web/standalone/.next/server/pages/500.html +2 -2
- package/dist/web/standalone/.next/server/server-reference-manifest.json +1 -1
- package/dist/web/standalone/.next/static/chunks/6502.8874bcae249c02e1.js +9 -0
- package/dist/web/standalone/.next/static/chunks/{webpack-a1c1e452c6b32d04.js → webpack-9fed74684e1c5bb1.js} +1 -1
- package/package.json +1 -1
- package/packages/pi-coding-agent/dist/core/retry-handler.d.ts.map +1 -1
- package/packages/pi-coding-agent/dist/core/retry-handler.js +30 -19
- package/packages/pi-coding-agent/dist/core/retry-handler.js.map +1 -1
- package/packages/pi-coding-agent/dist/core/retry-handler.test.js +51 -0
- package/packages/pi-coding-agent/dist/core/retry-handler.test.js.map +1 -1
- package/packages/pi-coding-agent/dist/core/sdk.js +9 -9
- package/packages/pi-coding-agent/dist/core/sdk.js.map +1 -1
- package/packages/pi-coding-agent/dist/modes/interactive/components/provider-manager.d.ts +2 -1
- package/packages/pi-coding-agent/dist/modes/interactive/components/provider-manager.d.ts.map +1 -1
- package/packages/pi-coding-agent/dist/modes/interactive/components/provider-manager.js +10 -1
- package/packages/pi-coding-agent/dist/modes/interactive/components/provider-manager.js.map +1 -1
- package/packages/pi-coding-agent/dist/modes/interactive/components/tool-execution.d.ts +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 +20 -5
- package/packages/pi-coding-agent/dist/modes/interactive/components/tool-execution.js.map +1 -1
- package/packages/pi-coding-agent/dist/modes/interactive/controllers/input-controller.js +15 -1
- package/packages/pi-coding-agent/dist/modes/interactive/controllers/input-controller.js.map +1 -1
- package/packages/pi-coding-agent/dist/modes/interactive/controllers/input-controller.test.js +18 -0
- package/packages/pi-coding-agent/dist/modes/interactive/controllers/input-controller.test.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 +4 -0
- package/packages/pi-coding-agent/dist/modes/interactive/interactive-mode.js.map +1 -1
- package/packages/pi-coding-agent/src/core/retry-handler.test.ts +80 -0
- package/packages/pi-coding-agent/src/core/retry-handler.ts +37 -25
- package/packages/pi-coding-agent/src/core/sdk.ts +9 -9
- package/packages/pi-coding-agent/src/modes/interactive/components/provider-manager.ts +10 -0
- package/packages/pi-coding-agent/src/modes/interactive/components/tool-execution.ts +20 -4
- package/packages/pi-coding-agent/src/modes/interactive/controllers/input-controller.test.ts +27 -0
- package/packages/pi-coding-agent/src/modes/interactive/controllers/input-controller.ts +16 -1
- package/packages/pi-coding-agent/src/modes/interactive/interactive-mode.ts +5 -0
- package/packages/pi-tui/dist/components/image.d.ts +2 -0
- package/packages/pi-tui/dist/components/image.d.ts.map +1 -1
- package/packages/pi-tui/dist/components/image.js +4 -0
- package/packages/pi-tui/dist/components/image.js.map +1 -1
- package/packages/pi-tui/dist/components/image.test.d.ts +6 -0
- package/packages/pi-tui/dist/components/image.test.d.ts.map +1 -0
- package/packages/pi-tui/dist/components/image.test.js +32 -0
- package/packages/pi-tui/dist/components/image.test.js.map +1 -0
- package/packages/pi-tui/dist/tui.d.ts.map +1 -1
- package/packages/pi-tui/dist/tui.js +3 -1
- package/packages/pi-tui/dist/tui.js.map +1 -1
- package/packages/pi-tui/src/components/image.test.ts +36 -0
- package/packages/pi-tui/src/components/image.ts +5 -0
- package/packages/pi-tui/src/tui.ts +3 -1
- package/src/resources/extensions/browser-tools/capture.ts +19 -1
- package/src/resources/extensions/browser-tools/tests/capture-sharp-optional.test.cjs +93 -0
- package/src/resources/extensions/gsd/auto/finalize-timeout.ts +3 -0
- package/src/resources/extensions/gsd/auto/loop.ts +2 -2
- package/src/resources/extensions/gsd/auto/phases.ts +68 -3
- package/src/resources/extensions/gsd/auto/run-unit.ts +12 -2
- package/src/resources/extensions/gsd/auto/session.ts +4 -0
- package/src/resources/extensions/gsd/auto/types.ts +5 -0
- package/src/resources/extensions/gsd/auto-dashboard.ts +2 -1
- package/src/resources/extensions/gsd/auto-dispatch.ts +110 -9
- package/src/resources/extensions/gsd/auto-model-selection.ts +7 -5
- package/src/resources/extensions/gsd/auto-post-unit.ts +16 -6
- package/src/resources/extensions/gsd/auto-prompts.ts +31 -0
- package/src/resources/extensions/gsd/auto-recovery.ts +29 -23
- package/src/resources/extensions/gsd/auto-start.ts +188 -10
- package/src/resources/extensions/gsd/auto-tool-tracking.ts +10 -0
- package/src/resources/extensions/gsd/auto-worktree.ts +28 -7
- package/src/resources/extensions/gsd/auto.ts +19 -8
- package/src/resources/extensions/gsd/bootstrap/agent-end-recovery.ts +16 -4
- package/src/resources/extensions/gsd/bootstrap/db-tools.ts +10 -0
- package/src/resources/extensions/gsd/bootstrap/query-tools.ts +5 -4
- package/src/resources/extensions/gsd/bootstrap/register-extension.ts +4 -1
- package/src/resources/extensions/gsd/bootstrap/register-hooks.ts +11 -3
- package/src/resources/extensions/gsd/bootstrap/system-context.ts +3 -1
- package/src/resources/extensions/gsd/bootstrap/write-gate.ts +36 -1
- package/src/resources/extensions/gsd/commands/context.ts +7 -1
- package/src/resources/extensions/gsd/commands/handlers/core.ts +26 -2
- package/src/resources/extensions/gsd/commands-extensions.ts +1 -1
- package/src/resources/extensions/gsd/config-overlay.ts +331 -0
- package/src/resources/extensions/gsd/db-writer.ts +11 -3
- package/src/resources/extensions/gsd/detection.ts +1 -1
- package/src/resources/extensions/gsd/dispatch-guard.ts +2 -1
- package/src/resources/extensions/gsd/docs/preferences-reference.md +1 -0
- package/src/resources/extensions/gsd/doctor.ts +2 -1
- package/src/resources/extensions/gsd/files.ts +19 -0
- package/src/resources/extensions/gsd/gitignore.ts +1 -0
- package/src/resources/extensions/gsd/gsd-db.ts +46 -4
- package/src/resources/extensions/gsd/guided-flow.ts +254 -30
- package/src/resources/extensions/gsd/index.ts +1 -0
- package/src/resources/extensions/gsd/json-persistence.ts +6 -3
- package/src/resources/extensions/gsd/md-importer.ts +13 -6
- package/src/resources/extensions/gsd/notification-overlay.ts +1 -1
- package/src/resources/extensions/gsd/notification-widget.ts +2 -1
- package/src/resources/extensions/gsd/parallel-monitor-overlay.ts +1 -1
- package/src/resources/extensions/gsd/parallel-orchestrator.ts +19 -11
- package/src/resources/extensions/gsd/pre-execution-checks.ts +32 -7
- package/src/resources/extensions/gsd/preferences-types.ts +25 -0
- package/src/resources/extensions/gsd/preferences-validation.ts +45 -1
- package/src/resources/extensions/gsd/preferences.ts +9 -2
- package/src/resources/extensions/gsd/preparation.ts +1419 -0
- package/src/resources/extensions/gsd/prompt-validation.ts +88 -0
- package/src/resources/extensions/gsd/prompts/complete-milestone.md +3 -3
- package/src/resources/extensions/gsd/prompts/complete-slice.md +1 -1
- package/src/resources/extensions/gsd/prompts/discuss-prepared.md +424 -0
- package/src/resources/extensions/gsd/prompts/discuss.md +2 -0
- package/src/resources/extensions/gsd/prompts/guided-discuss-milestone.md +6 -1
- package/src/resources/extensions/gsd/prompts/guided-discuss-slice.md +5 -4
- package/src/resources/extensions/gsd/prompts/parallel-research-slices.md +23 -0
- package/src/resources/extensions/gsd/prompts/queue.md +2 -0
- package/src/resources/extensions/gsd/prompts/rethink.md +2 -1
- package/src/resources/extensions/gsd/prompts/system.md +2 -2
- package/src/resources/extensions/gsd/prompts/validate-milestone.md +56 -23
- package/src/resources/extensions/gsd/quick.ts +20 -15
- package/src/resources/extensions/gsd/reactive-graph.ts +18 -0
- package/src/resources/extensions/gsd/roadmap-slices.ts +21 -5
- package/src/resources/extensions/gsd/safety/content-validator.ts +3 -3
- package/src/resources/extensions/gsd/session-lock.ts +17 -1
- package/src/resources/extensions/gsd/state.ts +115 -26
- package/src/resources/extensions/gsd/templates/context-enhanced.md +138 -0
- package/src/resources/extensions/gsd/tests/adversarial-review-fixes.test.ts +223 -0
- package/src/resources/extensions/gsd/tests/auto-model-selection.test.ts +33 -2
- package/src/resources/extensions/gsd/tests/auto-remediate-slice-status.test.ts +56 -0
- package/src/resources/extensions/gsd/tests/clear-stale-autostart.test.ts +41 -0
- package/src/resources/extensions/gsd/tests/complete-slice-verification-gate.test.ts +72 -0
- package/src/resources/extensions/gsd/tests/complete-task-normalize-lists.test.ts +54 -0
- package/src/resources/extensions/gsd/tests/defer-milestone-stamp.test.ts +30 -0
- package/src/resources/extensions/gsd/tests/derive-state-db.test.ts +4 -3
- package/src/resources/extensions/gsd/tests/discuss-incremental-persistence.test.ts +36 -0
- package/src/resources/extensions/gsd/tests/discuss-slice-structured-questions.test.ts +46 -0
- package/src/resources/extensions/gsd/tests/dispatch-guard-closed-status.test.ts +33 -0
- package/src/resources/extensions/gsd/tests/dispatcher-stuck-planning.test.ts +37 -0
- package/src/resources/extensions/gsd/tests/error-success-mask.test.ts +37 -0
- package/src/resources/extensions/gsd/tests/finalize-timeout-guard.test.ts +125 -0
- package/src/resources/extensions/gsd/tests/find-missing-summaries-closed.test.ts +48 -0
- package/src/resources/extensions/gsd/tests/format-shortcut.test.ts +69 -0
- package/src/resources/extensions/gsd/tests/frontmatter-parse-noise.test.ts +42 -0
- package/src/resources/extensions/gsd/tests/gitignore-bg-shell.test.ts +38 -0
- package/src/resources/extensions/gsd/tests/guided-flow-state-rebuild.test.ts +103 -0
- package/src/resources/extensions/gsd/tests/import-done-milestones.test.ts +42 -0
- package/src/resources/extensions/gsd/tests/integration/auto-recovery.test.ts +11 -9
- package/src/resources/extensions/gsd/tests/integration/state-machine-edge-cases.test.ts +4 -2
- package/src/resources/extensions/gsd/tests/integration/state-machine-live-validation.test.ts +28 -30
- package/src/resources/extensions/gsd/tests/integration/test-isolation.ts +53 -0
- package/src/resources/extensions/gsd/tests/integration-prepared-discussion.test.ts +525 -0
- package/src/resources/extensions/gsd/tests/isolation-none-branch-guard.test.ts +62 -0
- package/src/resources/extensions/gsd/tests/journal-integration.test.ts +11 -10
- package/src/resources/extensions/gsd/tests/needs-remediation-revalidation.test.ts +48 -0
- package/src/resources/extensions/gsd/tests/note-captures-executed.test.ts +46 -0
- package/src/resources/extensions/gsd/tests/orphaned-worktree-audit.test.ts +189 -0
- package/src/resources/extensions/gsd/tests/parallel-research-dispatch.test.ts +77 -0
- package/src/resources/extensions/gsd/tests/phantom-ghost-detection.test.ts +55 -0
- package/src/resources/extensions/gsd/tests/phantom-milestone-default-queued.test.ts +39 -0
- package/src/resources/extensions/gsd/tests/pre-exec-backtick-strip.test.ts +68 -0
- package/src/resources/extensions/gsd/tests/pre-execution-checks.test.ts +284 -20
- package/src/resources/extensions/gsd/tests/pre-execution-fail-closed.test.ts +2 -2
- package/src/resources/extensions/gsd/tests/pre-execution-pause-wiring.test.ts +2 -2
- package/src/resources/extensions/gsd/tests/preparation.test.ts +1211 -0
- package/src/resources/extensions/gsd/tests/project-root-cwd-crash.test.ts +53 -0
- package/src/resources/extensions/gsd/tests/projection-no-plan-overwrite.test.ts +83 -0
- package/src/resources/extensions/gsd/tests/prompt-builder.test.ts +669 -0
- package/src/resources/extensions/gsd/tests/prompt-contracts.test.ts +7 -4
- package/src/resources/extensions/gsd/tests/prompt-step-ordering.test.ts +85 -0
- package/src/resources/extensions/gsd/tests/provider-errors.test.ts +2 -1
- package/src/resources/extensions/gsd/tests/query-tools-db-open.test.ts +47 -0
- package/src/resources/extensions/gsd/tests/queued-discuss-fast-path.test.ts +107 -0
- package/src/resources/extensions/gsd/tests/reactive-graph.test.ts +45 -0
- package/src/resources/extensions/gsd/tests/restore-tools-after-discuss.test.ts +63 -0
- package/src/resources/extensions/gsd/tests/rogue-file-detection.test.ts +4 -5
- package/src/resources/extensions/gsd/tests/run-uat-replay-cap.test.ts +51 -0
- package/src/resources/extensions/gsd/tests/show-config-command.test.ts +56 -0
- package/src/resources/extensions/gsd/tests/skip-slice-state-rebuild.test.ts +31 -0
- package/src/resources/extensions/gsd/tests/skipped-validation-completion.test.ts +39 -0
- package/src/resources/extensions/gsd/tests/slice-sequence-insert.test.ts +51 -0
- package/src/resources/extensions/gsd/tests/smart-entry-complete.test.ts +1 -1
- package/src/resources/extensions/gsd/tests/stale-lockfile-recovery.test.ts +36 -0
- package/src/resources/extensions/gsd/tests/stale-queued-milestone.test.ts +147 -0
- package/src/resources/extensions/gsd/tests/stale-worktree-cwd.test.ts +13 -0
- package/src/resources/extensions/gsd/tests/stash-pop-gsd-conflict.test.ts +21 -0
- package/src/resources/extensions/gsd/tests/stash-queued-context-files.test.ts +21 -0
- package/src/resources/extensions/gsd/tests/state-machine-full-walkthrough.test.ts +6 -7
- package/src/resources/extensions/gsd/tests/status-db-open.test.ts +47 -0
- package/src/resources/extensions/gsd/tests/stuck-detection-coverage.test.ts +1 -0
- package/src/resources/extensions/gsd/tests/subagent-agent-discovery.test.ts +47 -0
- package/src/resources/extensions/gsd/tests/symlink-extension-discovery.test.ts +125 -0
- package/src/resources/extensions/gsd/tests/sync-worktree-skip-current.test.ts +65 -0
- package/src/resources/extensions/gsd/tests/tool-invocation-error-loop-break.test.ts +29 -1
- package/src/resources/extensions/gsd/tests/triage-resolution.test.ts +2 -1
- package/src/resources/extensions/gsd/tests/validate-milestone.test.ts +3 -4
- package/src/resources/extensions/gsd/tests/verification-operational-gate.test.ts +15 -0
- package/src/resources/extensions/gsd/tests/verify-artifact-tightened.test.ts +89 -0
- package/src/resources/extensions/gsd/tests/wave1-critical-regressions.test.ts +49 -0
- package/src/resources/extensions/gsd/tests/wave2-events-regressions.test.ts +48 -0
- package/src/resources/extensions/gsd/tests/wave3-session-regressions.test.ts +47 -0
- package/src/resources/extensions/gsd/tests/wave4-write-safety-regressions.test.ts +70 -0
- package/src/resources/extensions/gsd/tests/wave5-consistency-regressions.test.ts +165 -0
- package/src/resources/extensions/gsd/tests/worker-model-override.test.ts +48 -0
- package/src/resources/extensions/gsd/tests/workflow-logger-audit.test.ts +6 -3
- package/src/resources/extensions/gsd/tests/worktree-expected-warnings.test.ts +38 -0
- package/src/resources/extensions/gsd/tests/worktree-integration.test.ts +16 -0
- package/src/resources/extensions/gsd/tests/worktree-main-branch.test.ts +20 -0
- package/src/resources/extensions/gsd/tests/worktree-sync-milestones.test.ts +16 -17
- package/src/resources/extensions/gsd/tests/worktree-sync-tasks.test.ts +13 -9
- package/src/resources/extensions/gsd/tests/worktree.test.ts +26 -9
- package/src/resources/extensions/gsd/tests/write-gate.test.ts +127 -2
- package/src/resources/extensions/gsd/tests/zero-slice-roadmap-guided.test.ts +19 -0
- package/src/resources/extensions/gsd/tools/complete-milestone.ts +13 -3
- package/src/resources/extensions/gsd/tools/complete-slice.ts +26 -6
- package/src/resources/extensions/gsd/tools/complete-task.ts +29 -7
- package/src/resources/extensions/gsd/tools/plan-milestone.ts +11 -9
- package/src/resources/extensions/gsd/tools/reassess-roadmap.ts +5 -2
- package/src/resources/extensions/gsd/tools/reopen-milestone.ts +152 -0
- package/src/resources/extensions/gsd/tools/reopen-slice.ts +27 -0
- package/src/resources/extensions/gsd/tools/reopen-task.ts +17 -0
- package/src/resources/extensions/gsd/triage-resolution.ts +37 -17
- package/src/resources/extensions/gsd/types.ts +4 -0
- package/src/resources/extensions/gsd/undo.ts +3 -2
- package/src/resources/extensions/gsd/workflow-events.ts +5 -3
- package/src/resources/extensions/gsd/workflow-logger.ts +1 -1
- package/src/resources/extensions/gsd/workflow-projections.ts +7 -8
- package/src/resources/extensions/gsd/workflow-reconcile.ts +109 -8
- package/src/resources/extensions/gsd/workflow-templates.ts +11 -2
- package/src/resources/extensions/gsd/worktree-manager.ts +4 -2
- package/src/resources/extensions/gsd/worktree.ts +10 -0
- package/src/resources/extensions/shared/interview-ui.ts +1 -1
- package/src/resources/extensions/shared/tests/interview-notes-loop.test.ts +8 -10
- package/src/resources/extensions/subagent/agents.ts +30 -6
- package/dist/web/standalone/.next/static/chunks/6502.7593d7797a4b3999.js +0 -9
- /package/dist/web/standalone/.next/static/{qq3YfHPfyqvh3DIMVmsRH → E0hBt4ifuG7QBbhUR5-6U}/_buildManifest.js +0 -0
- /package/dist/web/standalone/.next/static/{qq3YfHPfyqvh3DIMVmsRH → E0hBt4ifuG7QBbhUR5-6U}/_ssgManifest.js +0 -0
|
@@ -8,6 +8,7 @@ import { runEnvironmentChecks } from "../../doctor-environment.js";
|
|
|
8
8
|
import { deriveState } from "../../state.js";
|
|
9
9
|
import { handleCmux } from "../../commands-cmux.js";
|
|
10
10
|
import { projectRoot } from "../context.js";
|
|
11
|
+
import { formatShortcut } from "../../files.js";
|
|
11
12
|
|
|
12
13
|
export function showHelp(ctx: ExtensionCommandContext): void {
|
|
13
14
|
const lines = [
|
|
@@ -24,12 +25,12 @@ export function showHelp(ctx: ExtensionCommandContext): void {
|
|
|
24
25
|
" /gsd new-milestone Create milestone from headless context (used by gsd headless)",
|
|
25
26
|
"",
|
|
26
27
|
"VISIBILITY",
|
|
27
|
-
|
|
28
|
+
` /gsd status Show progress dashboard (${formatShortcut("Ctrl+Alt+G")})`,
|
|
28
29
|
" /gsd visualize Interactive 10-tab TUI (progress, timeline, deps, metrics, health, agent, changes, knowledge, captures, export)",
|
|
29
30
|
" /gsd queue Show queued/dispatched units and execution order",
|
|
30
31
|
" /gsd history View execution history [--cost] [--phase] [--model] [N]",
|
|
31
32
|
" /gsd changelog Show categorized release notes [version]",
|
|
32
|
-
|
|
33
|
+
` /gsd notifications View persistent notification history [clear|tail|filter] (${formatShortcut("Ctrl+Alt+N")})`,
|
|
33
34
|
"",
|
|
34
35
|
"COURSE CORRECTION",
|
|
35
36
|
" /gsd steer <desc> Apply user override to active work",
|
|
@@ -52,6 +53,7 @@ export function showHelp(ctx: ExtensionCommandContext): void {
|
|
|
52
53
|
" /gsd cmux Manage cmux integration [status|on|off|notifications|sidebar|splits|browser]",
|
|
53
54
|
" /gsd config Set API keys for external tools",
|
|
54
55
|
" /gsd keys API key manager [list|add|remove|test|rotate|doctor]",
|
|
56
|
+
" /gsd show-config Show effective configuration (models, routing, toggles)",
|
|
55
57
|
" /gsd hooks Show post-unit hook configuration",
|
|
56
58
|
" /gsd extensions Manage extensions [list|enable|disable|info]",
|
|
57
59
|
" /gsd fast Toggle OpenAI service tier [on|off|flex|status]",
|
|
@@ -71,6 +73,9 @@ export function showHelp(ctx: ExtensionCommandContext): void {
|
|
|
71
73
|
|
|
72
74
|
export async function handleStatus(ctx: ExtensionCommandContext): Promise<void> {
|
|
73
75
|
const basePath = projectRoot();
|
|
76
|
+
// Open DB in cold sessions so status uses DB-backed state, not filesystem fallback (#3385)
|
|
77
|
+
const { ensureDbOpen } = await import("../../bootstrap/dynamic-tools.js");
|
|
78
|
+
await ensureDbOpen();
|
|
74
79
|
const state = await deriveState(basePath);
|
|
75
80
|
|
|
76
81
|
if (state.registry.length === 0) {
|
|
@@ -214,6 +219,25 @@ export async function handleCoreCommand(trimmed: string, ctx: ExtensionCommandCo
|
|
|
214
219
|
await handleCmux(trimmed.replace(/^cmux\s*/, "").trim(), ctx);
|
|
215
220
|
return true;
|
|
216
221
|
}
|
|
222
|
+
if (trimmed === "show-config") {
|
|
223
|
+
const { GSDConfigOverlay, formatConfigText } = await import("../../config-overlay.js");
|
|
224
|
+
const result = await ctx.ui.custom<void>(
|
|
225
|
+
(tui, theme, _kb, done) => new GSDConfigOverlay(tui, theme, () => done()),
|
|
226
|
+
{
|
|
227
|
+
overlay: true,
|
|
228
|
+
overlayOptions: {
|
|
229
|
+
width: "65%",
|
|
230
|
+
minWidth: 55,
|
|
231
|
+
maxHeight: "85%",
|
|
232
|
+
anchor: "center",
|
|
233
|
+
},
|
|
234
|
+
},
|
|
235
|
+
);
|
|
236
|
+
if (result === undefined) {
|
|
237
|
+
ctx.ui.notify(formatConfigText(), "info");
|
|
238
|
+
}
|
|
239
|
+
return true;
|
|
240
|
+
}
|
|
217
241
|
if (trimmed === "setup" || trimmed.startsWith("setup ")) {
|
|
218
242
|
await handleSetup(trimmed.replace(/^setup\s*/, "").trim(), ctx);
|
|
219
243
|
return true;
|
|
@@ -105,7 +105,7 @@ function discoverManifests(): Map<string, ExtensionManifest> {
|
|
|
105
105
|
const manifests = new Map<string, ExtensionManifest>();
|
|
106
106
|
if (!existsSync(extDir)) return manifests;
|
|
107
107
|
for (const entry of readdirSync(extDir, { withFileTypes: true })) {
|
|
108
|
-
if (!entry.isDirectory()) continue;
|
|
108
|
+
if (!entry.isDirectory() && !entry.isSymbolicLink()) continue;
|
|
109
109
|
const m = readManifest(join(extDir, entry.name));
|
|
110
110
|
if (m) manifests.set(m.id, m);
|
|
111
111
|
}
|
|
@@ -0,0 +1,331 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* GSD Configuration Overlay
|
|
3
|
+
*
|
|
4
|
+
* Read-only TUI overlay showing the effective GSD configuration:
|
|
5
|
+
* token profile, model assignments, dynamic routing, git settings,
|
|
6
|
+
* budget, workflow toggles, and preference file sources.
|
|
7
|
+
* Opened via `/gsd show-config` or `/gsd config`.
|
|
8
|
+
*/
|
|
9
|
+
|
|
10
|
+
import type { Theme } from "@gsd/pi-coding-agent";
|
|
11
|
+
import { matchesKey, Key, truncateToWidth } from "@gsd/pi-tui";
|
|
12
|
+
|
|
13
|
+
import {
|
|
14
|
+
loadEffectiveGSDPreferences,
|
|
15
|
+
loadGlobalGSDPreferences,
|
|
16
|
+
loadProjectGSDPreferences,
|
|
17
|
+
getGlobalGSDPreferencesPath,
|
|
18
|
+
getProjectGSDPreferencesPath,
|
|
19
|
+
resolveDynamicRoutingConfig,
|
|
20
|
+
resolveEffectiveProfile,
|
|
21
|
+
resolveModelWithFallbacksForUnit,
|
|
22
|
+
resolveAutoSupervisorConfig,
|
|
23
|
+
} from "./preferences.js";
|
|
24
|
+
|
|
25
|
+
// ─── Data Collection ──────────────────────────────────────────────────────
|
|
26
|
+
|
|
27
|
+
interface ConfigSection {
|
|
28
|
+
title: string;
|
|
29
|
+
rows: Array<{ label: string; value: string; accent?: boolean }>;
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
function collectConfigSections(): ConfigSection[] {
|
|
33
|
+
const sections: ConfigSection[] = [];
|
|
34
|
+
|
|
35
|
+
const globalPrefs = loadGlobalGSDPreferences();
|
|
36
|
+
const projectPrefs = loadProjectGSDPreferences();
|
|
37
|
+
const effective = loadEffectiveGSDPreferences();
|
|
38
|
+
const prefs = effective?.preferences;
|
|
39
|
+
|
|
40
|
+
// ─── Sources ─────────────────────────────────────────────────────────
|
|
41
|
+
sections.push({
|
|
42
|
+
title: "Sources",
|
|
43
|
+
rows: [
|
|
44
|
+
{ label: "Global", value: globalPrefs ? globalPrefs.path : `(none) ${getGlobalGSDPreferencesPath()}` },
|
|
45
|
+
{ label: "Project", value: projectPrefs ? projectPrefs.path : `(none) ${getProjectGSDPreferencesPath()}` },
|
|
46
|
+
],
|
|
47
|
+
});
|
|
48
|
+
|
|
49
|
+
// ─── Profile ─────────────────────────────────────────────────────────
|
|
50
|
+
const profile = resolveEffectiveProfile();
|
|
51
|
+
const profileRows: ConfigSection["rows"] = [
|
|
52
|
+
{ label: "Token profile", value: `${profile}${!prefs?.token_profile ? " (default)" : ""}`, accent: true },
|
|
53
|
+
];
|
|
54
|
+
if (prefs?.mode) profileRows.push({ label: "Workflow mode", value: prefs.mode });
|
|
55
|
+
sections.push({ title: "Profile", rows: profileRows });
|
|
56
|
+
|
|
57
|
+
// ─── Models ──────────────────────────────────────────────────────────
|
|
58
|
+
const unitTypes: Array<[string, string]> = [
|
|
59
|
+
["research", "research-milestone"],
|
|
60
|
+
["planning", "plan-milestone"],
|
|
61
|
+
["discuss", "discuss-milestone"],
|
|
62
|
+
["execution", "execute-task"],
|
|
63
|
+
["completion", "complete-slice"],
|
|
64
|
+
["validation", "run-uat"],
|
|
65
|
+
];
|
|
66
|
+
|
|
67
|
+
const modelRows: ConfigSection["rows"] = [];
|
|
68
|
+
for (const [label, unitType] of unitTypes) {
|
|
69
|
+
const resolved = resolveModelWithFallbacksForUnit(unitType);
|
|
70
|
+
if (resolved) {
|
|
71
|
+
let val = resolved.primary;
|
|
72
|
+
if (resolved.fallbacks.length > 0) {
|
|
73
|
+
val += ` \u2192 ${resolved.fallbacks.join(" \u2192 ")}`;
|
|
74
|
+
}
|
|
75
|
+
modelRows.push({ label, value: val });
|
|
76
|
+
} else {
|
|
77
|
+
modelRows.push({ label, value: "(inherit)" });
|
|
78
|
+
}
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
// subagent is a direct config key
|
|
82
|
+
const models = prefs?.models as Record<string, unknown> | undefined;
|
|
83
|
+
const subVal = models?.subagent;
|
|
84
|
+
if (subVal) {
|
|
85
|
+
const model = typeof subVal === "string" ? subVal : (subVal as { model?: string })?.model ?? "?";
|
|
86
|
+
modelRows.push({ label: "subagent", value: model });
|
|
87
|
+
} else {
|
|
88
|
+
modelRows.push({ label: "subagent", value: "(inherit)" });
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
sections.push({ title: "Models", rows: modelRows });
|
|
92
|
+
|
|
93
|
+
// ─── Dynamic Routing ─────────────────────────────────────────────────
|
|
94
|
+
const routing = resolveDynamicRoutingConfig();
|
|
95
|
+
const routingRows: ConfigSection["rows"] = [
|
|
96
|
+
{ label: "Enabled", value: routing.enabled ? "yes" : "no", accent: routing.enabled },
|
|
97
|
+
];
|
|
98
|
+
if (routing.enabled) {
|
|
99
|
+
routingRows.push({ label: "Escalate on fail", value: routing.escalate_on_failure !== false ? "yes" : "no" });
|
|
100
|
+
routingRows.push({ label: "Budget pressure", value: routing.budget_pressure !== false ? "yes" : "no" });
|
|
101
|
+
routingRows.push({ label: "Cross-provider", value: routing.cross_provider !== false ? "yes" : "no" });
|
|
102
|
+
if (routing.tier_models) {
|
|
103
|
+
const tm = routing.tier_models;
|
|
104
|
+
if (tm.light) routingRows.push({ label: "[L] light", value: tm.light });
|
|
105
|
+
if (tm.standard) routingRows.push({ label: "[S] standard", value: tm.standard });
|
|
106
|
+
if (tm.heavy) routingRows.push({ label: "[H] heavy", value: tm.heavy });
|
|
107
|
+
}
|
|
108
|
+
}
|
|
109
|
+
sections.push({ title: "Dynamic Routing", rows: routingRows });
|
|
110
|
+
|
|
111
|
+
// ─── Git ─────────────────────────────────────────────────────────────
|
|
112
|
+
if (prefs?.git) {
|
|
113
|
+
const g = prefs.git;
|
|
114
|
+
const gitRows: ConfigSection["rows"] = [];
|
|
115
|
+
if (g.isolation !== undefined) gitRows.push({ label: "Isolation", value: String(g.isolation) });
|
|
116
|
+
if (g.auto_push !== undefined) gitRows.push({ label: "Auto push", value: String(g.auto_push) });
|
|
117
|
+
if (g.push_branches !== undefined) gitRows.push({ label: "Push branches", value: String(g.push_branches) });
|
|
118
|
+
if (g.merge_strategy) gitRows.push({ label: "Merge strategy", value: g.merge_strategy });
|
|
119
|
+
if (g.main_branch) gitRows.push({ label: "Main branch", value: g.main_branch });
|
|
120
|
+
if (g.remote) gitRows.push({ label: "Remote", value: g.remote });
|
|
121
|
+
if (gitRows.length > 0) sections.push({ title: "Git", rows: gitRows });
|
|
122
|
+
}
|
|
123
|
+
|
|
124
|
+
// ─── Budget ──────────────────────────────────────────────────────────
|
|
125
|
+
if (prefs?.budget_ceiling !== undefined || prefs?.budget_enforcement) {
|
|
126
|
+
const budgetRows: ConfigSection["rows"] = [];
|
|
127
|
+
if (prefs.budget_ceiling !== undefined) budgetRows.push({ label: "Ceiling", value: `$${prefs.budget_ceiling}` });
|
|
128
|
+
if (prefs.budget_enforcement) budgetRows.push({ label: "Enforcement", value: String(prefs.budget_enforcement) });
|
|
129
|
+
sections.push({ title: "Budget", rows: budgetRows });
|
|
130
|
+
}
|
|
131
|
+
|
|
132
|
+
// ─── Auto Supervisor ─────────────────────────────────────────────────
|
|
133
|
+
if (prefs?.auto_supervisor) {
|
|
134
|
+
const sup = resolveAutoSupervisorConfig();
|
|
135
|
+
const supRows: ConfigSection["rows"] = [];
|
|
136
|
+
if (sup.model) supRows.push({ label: "Model", value: sup.model });
|
|
137
|
+
supRows.push({ label: "Soft timeout", value: `${sup.soft_timeout_minutes}m` });
|
|
138
|
+
supRows.push({ label: "Idle timeout", value: `${sup.idle_timeout_minutes}m` });
|
|
139
|
+
supRows.push({ label: "Hard timeout", value: `${sup.hard_timeout_minutes}m` });
|
|
140
|
+
sections.push({ title: "Auto Supervisor", rows: supRows });
|
|
141
|
+
}
|
|
142
|
+
|
|
143
|
+
// ─── Toggles ─────────────────────────────────────────────────────────
|
|
144
|
+
const toggleRows: ConfigSection["rows"] = [];
|
|
145
|
+
if (prefs?.phases) {
|
|
146
|
+
const p = prefs.phases;
|
|
147
|
+
if (p.skip_research) toggleRows.push({ label: "skip_research", value: "on" });
|
|
148
|
+
if (p.skip_reassess) toggleRows.push({ label: "skip_reassess", value: "on" });
|
|
149
|
+
if (p.skip_slice_research) toggleRows.push({ label: "skip_slice_research", value: "on" });
|
|
150
|
+
if (p.skip_milestone_validation) toggleRows.push({ label: "skip_milestone_validation", value: "on" });
|
|
151
|
+
if (p.require_slice_discussion) toggleRows.push({ label: "require_slice_discussion", value: "on" });
|
|
152
|
+
}
|
|
153
|
+
if (prefs?.uat_dispatch) toggleRows.push({ label: "uat_dispatch", value: "on" });
|
|
154
|
+
if (prefs?.auto_visualize) toggleRows.push({ label: "auto_visualize", value: "on" });
|
|
155
|
+
if (prefs?.auto_report === false) toggleRows.push({ label: "auto_report", value: "off" });
|
|
156
|
+
if (prefs?.show_token_cost) toggleRows.push({ label: "show_token_cost", value: "on" });
|
|
157
|
+
if (prefs?.forensics_dedup) toggleRows.push({ label: "forensics_dedup", value: "on" });
|
|
158
|
+
if (prefs?.unique_milestone_ids) toggleRows.push({ label: "unique_milestone_ids", value: "on" });
|
|
159
|
+
if (prefs?.service_tier) toggleRows.push({ label: "service_tier", value: prefs.service_tier });
|
|
160
|
+
if (prefs?.search_provider && prefs.search_provider !== "auto") toggleRows.push({ label: "search_provider", value: prefs.search_provider });
|
|
161
|
+
if (prefs?.context_selection) toggleRows.push({ label: "context_selection", value: prefs.context_selection });
|
|
162
|
+
if (prefs?.widget_mode && prefs.widget_mode !== "full") toggleRows.push({ label: "widget_mode", value: prefs.widget_mode });
|
|
163
|
+
if (prefs?.experimental?.rtk) toggleRows.push({ label: "experimental.rtk", value: "on" });
|
|
164
|
+
if (toggleRows.length > 0) sections.push({ title: "Toggles", rows: toggleRows });
|
|
165
|
+
|
|
166
|
+
// ─── Parallel ────────────────────────────────────────────────────────
|
|
167
|
+
if (prefs?.parallel) {
|
|
168
|
+
const pc = prefs.parallel;
|
|
169
|
+
const parallelRows: ConfigSection["rows"] = [];
|
|
170
|
+
if (pc.max_workers !== undefined) parallelRows.push({ label: "Max workers", value: String(pc.max_workers) });
|
|
171
|
+
if (pc.merge_strategy) parallelRows.push({ label: "Merge strategy", value: pc.merge_strategy });
|
|
172
|
+
if (pc.auto_merge) parallelRows.push({ label: "Auto merge", value: pc.auto_merge });
|
|
173
|
+
if (parallelRows.length > 0) sections.push({ title: "Parallel", rows: parallelRows });
|
|
174
|
+
}
|
|
175
|
+
|
|
176
|
+
// ─── Hooks ───────────────────────────────────────────────────────────
|
|
177
|
+
const postHooks = prefs?.post_unit_hooks?.filter(h => h.enabled !== false) ?? [];
|
|
178
|
+
const preHooks = prefs?.pre_dispatch_hooks?.filter(h => h.enabled !== false) ?? [];
|
|
179
|
+
if (postHooks.length > 0 || preHooks.length > 0) {
|
|
180
|
+
const hookRows: ConfigSection["rows"] = [];
|
|
181
|
+
if (preHooks.length > 0) hookRows.push({ label: "Pre-dispatch", value: `${preHooks.length} active` });
|
|
182
|
+
if (postHooks.length > 0) hookRows.push({ label: "Post-unit", value: `${postHooks.length} active` });
|
|
183
|
+
sections.push({ title: "Hooks", rows: hookRows });
|
|
184
|
+
}
|
|
185
|
+
|
|
186
|
+
// ─── Warnings ────────────────────────────────────────────────────────
|
|
187
|
+
const warnings = [
|
|
188
|
+
...(globalPrefs?.warnings ?? []),
|
|
189
|
+
...(projectPrefs?.warnings ?? []),
|
|
190
|
+
];
|
|
191
|
+
if (warnings.length > 0) {
|
|
192
|
+
sections.push({
|
|
193
|
+
title: "Warnings",
|
|
194
|
+
rows: warnings.map(w => ({ label: "\u26a0", value: w })),
|
|
195
|
+
});
|
|
196
|
+
}
|
|
197
|
+
|
|
198
|
+
return sections;
|
|
199
|
+
}
|
|
200
|
+
|
|
201
|
+
// ─── Plain Text Formatter (headless/RPC fallback) ─────────────────────────
|
|
202
|
+
|
|
203
|
+
export function formatConfigText(): string {
|
|
204
|
+
const sections = collectConfigSections();
|
|
205
|
+
const lines: string[] = ["GSD Configuration\n"];
|
|
206
|
+
|
|
207
|
+
let maxLabel = 0;
|
|
208
|
+
for (const section of sections) {
|
|
209
|
+
for (const row of section.rows) {
|
|
210
|
+
if (row.label.length > maxLabel) maxLabel = row.label.length;
|
|
211
|
+
}
|
|
212
|
+
}
|
|
213
|
+
const pad = Math.min(maxLabel + 2, 24);
|
|
214
|
+
|
|
215
|
+
for (const section of sections) {
|
|
216
|
+
lines.push("");
|
|
217
|
+
lines.push(section.title.toUpperCase());
|
|
218
|
+
for (const row of section.rows) {
|
|
219
|
+
lines.push(` ${row.label.padEnd(pad)}${row.value}`);
|
|
220
|
+
}
|
|
221
|
+
}
|
|
222
|
+
|
|
223
|
+
return lines.join("\n");
|
|
224
|
+
}
|
|
225
|
+
|
|
226
|
+
// ─── Overlay Class ────────────────────────────────────────────────────────
|
|
227
|
+
|
|
228
|
+
export class GSDConfigOverlay {
|
|
229
|
+
private tui: { requestRender: () => void };
|
|
230
|
+
private theme: Theme;
|
|
231
|
+
private onClose: () => void;
|
|
232
|
+
private sections: ConfigSection[];
|
|
233
|
+
private cachedLines?: string[];
|
|
234
|
+
private scrollOffset = 0;
|
|
235
|
+
private disposed = false;
|
|
236
|
+
|
|
237
|
+
constructor(
|
|
238
|
+
tui: { requestRender: () => void },
|
|
239
|
+
theme: Theme,
|
|
240
|
+
onClose: () => void,
|
|
241
|
+
) {
|
|
242
|
+
this.tui = tui;
|
|
243
|
+
this.theme = theme;
|
|
244
|
+
this.onClose = onClose;
|
|
245
|
+
this.sections = collectConfigSections();
|
|
246
|
+
}
|
|
247
|
+
|
|
248
|
+
invalidate(): void {
|
|
249
|
+
this.cachedLines = undefined;
|
|
250
|
+
}
|
|
251
|
+
|
|
252
|
+
dispose(): void {
|
|
253
|
+
this.disposed = true;
|
|
254
|
+
}
|
|
255
|
+
|
|
256
|
+
handleInput(data: string): void {
|
|
257
|
+
if (matchesKey(data, Key.escape) || data === "q") {
|
|
258
|
+
this.dispose();
|
|
259
|
+
this.onClose();
|
|
260
|
+
return;
|
|
261
|
+
}
|
|
262
|
+
if (matchesKey(data, Key.down) || data === "j") {
|
|
263
|
+
this.scrollOffset++;
|
|
264
|
+
this.cachedLines = undefined;
|
|
265
|
+
this.tui.requestRender();
|
|
266
|
+
return;
|
|
267
|
+
}
|
|
268
|
+
if (matchesKey(data, Key.up) || data === "k") {
|
|
269
|
+
this.scrollOffset = Math.max(0, this.scrollOffset - 1);
|
|
270
|
+
this.cachedLines = undefined;
|
|
271
|
+
this.tui.requestRender();
|
|
272
|
+
return;
|
|
273
|
+
}
|
|
274
|
+
if (matchesKey(data, Key.pageDown)) {
|
|
275
|
+
this.scrollOffset += 10;
|
|
276
|
+
this.cachedLines = undefined;
|
|
277
|
+
this.tui.requestRender();
|
|
278
|
+
return;
|
|
279
|
+
}
|
|
280
|
+
if (matchesKey(data, Key.pageUp)) {
|
|
281
|
+
this.scrollOffset = Math.max(0, this.scrollOffset - 10);
|
|
282
|
+
this.cachedLines = undefined;
|
|
283
|
+
this.tui.requestRender();
|
|
284
|
+
return;
|
|
285
|
+
}
|
|
286
|
+
}
|
|
287
|
+
|
|
288
|
+
render(width: number): string[] {
|
|
289
|
+
if (this.cachedLines) return this.cachedLines;
|
|
290
|
+
|
|
291
|
+
const t = this.theme;
|
|
292
|
+
const w = Math.max(width, 50);
|
|
293
|
+
const allLines: string[] = [];
|
|
294
|
+
|
|
295
|
+
// Header
|
|
296
|
+
allLines.push(t.bold(t.fg("accent", " GSD Configuration ")));
|
|
297
|
+
allLines.push(t.fg("muted", "\u2500".repeat(w)));
|
|
298
|
+
|
|
299
|
+
// Find max label width for alignment
|
|
300
|
+
let maxLabel = 0;
|
|
301
|
+
for (const section of this.sections) {
|
|
302
|
+
for (const row of section.rows) {
|
|
303
|
+
if (row.label.length > maxLabel) maxLabel = row.label.length;
|
|
304
|
+
}
|
|
305
|
+
}
|
|
306
|
+
const labelPad = Math.min(maxLabel + 2, 24);
|
|
307
|
+
|
|
308
|
+
for (const section of this.sections) {
|
|
309
|
+
allLines.push("");
|
|
310
|
+
allLines.push(t.bold(t.fg("accent", ` ${section.title}`)));
|
|
311
|
+
|
|
312
|
+
for (const row of section.rows) {
|
|
313
|
+
const label = t.fg("muted", ` ${row.label.padEnd(labelPad)}`);
|
|
314
|
+
const value = row.accent ? t.bold(row.value) : row.value;
|
|
315
|
+
allLines.push(truncateToWidth(`${label}${value}`, w));
|
|
316
|
+
}
|
|
317
|
+
}
|
|
318
|
+
|
|
319
|
+
allLines.push("");
|
|
320
|
+
allLines.push(t.fg("muted", ` ${"\u2500".repeat(w - 4)}`));
|
|
321
|
+
allLines.push(t.fg("muted", " esc/q close \u2502 \u2191\u2193/jk scroll \u2502 /gsd prefs to edit"));
|
|
322
|
+
|
|
323
|
+
// Apply scroll
|
|
324
|
+
const maxScroll = Math.max(0, allLines.length - 20);
|
|
325
|
+
this.scrollOffset = Math.min(this.scrollOffset, maxScroll);
|
|
326
|
+
const visible = allLines.slice(this.scrollOffset);
|
|
327
|
+
|
|
328
|
+
this.cachedLines = visible;
|
|
329
|
+
return visible;
|
|
330
|
+
}
|
|
331
|
+
}
|
|
@@ -345,8 +345,12 @@ export async function saveRequirementToDb(
|
|
|
345
345
|
await saveFile(filePath, md);
|
|
346
346
|
} catch (diskErr) {
|
|
347
347
|
logError('manifest', 'disk write failed, rolling back DB row', { fn: 'saveRequirementToDb', error: String((diskErr as Error).message) });
|
|
348
|
-
|
|
349
|
-
|
|
348
|
+
try {
|
|
349
|
+
const rollbackAdapter = db._getAdapter();
|
|
350
|
+
rollbackAdapter?.prepare('DELETE FROM requirements WHERE id = :id').run({ ':id': id });
|
|
351
|
+
} catch (rollbackErr) {
|
|
352
|
+
logError('manifest', 'SPLIT BRAIN: disk write failed AND DB rollback failed — DB has orphaned row', { fn: 'saveRequirementToDb', id, error: String((rollbackErr as Error).message) });
|
|
353
|
+
}
|
|
350
354
|
throw diskErr;
|
|
351
355
|
}
|
|
352
356
|
invalidateStateCache();
|
|
@@ -466,7 +470,11 @@ export async function saveDecisionToDb(
|
|
|
466
470
|
await saveFile(filePath, md);
|
|
467
471
|
} catch (diskErr) {
|
|
468
472
|
logError('manifest', 'disk write failed, rolling back DB row', { fn: 'saveDecisionToDb', error: String((diskErr as Error).message) });
|
|
469
|
-
|
|
473
|
+
try {
|
|
474
|
+
adapter?.prepare('DELETE FROM decisions WHERE id = :id').run({ ':id': id });
|
|
475
|
+
} catch (rollbackErr) {
|
|
476
|
+
logError('manifest', 'SPLIT BRAIN: disk write failed AND DB rollback failed — DB has orphaned row', { fn: 'saveDecisionToDb', id, error: String((rollbackErr as Error).message) });
|
|
477
|
+
}
|
|
470
478
|
throw diskErr;
|
|
471
479
|
}
|
|
472
480
|
// #2661: When a decision defers a slice, update the slice status in the DB
|
|
@@ -1114,7 +1114,7 @@ function resolveVersionCatalogAccessors(
|
|
|
1114
1114
|
return accessors;
|
|
1115
1115
|
}
|
|
1116
1116
|
|
|
1117
|
-
function scanProjectFiles(basePath: string): string[] {
|
|
1117
|
+
export function scanProjectFiles(basePath: string): string[] {
|
|
1118
1118
|
const files: string[] = [];
|
|
1119
1119
|
const queue: Array<{ path: string; depth: number }> = [{ path: basePath, depth: 0 }];
|
|
1120
1120
|
|
|
@@ -5,6 +5,7 @@ import { findMilestoneIds } from "./guided-flow.js";
|
|
|
5
5
|
import { parseUnitId } from "./unit-id.js";
|
|
6
6
|
import { isDbAvailable, getMilestoneSlices } from "./gsd-db.js";
|
|
7
7
|
import { parseRoadmap } from "./parsers-legacy.js";
|
|
8
|
+
import { isClosedStatus } from "./status-guards.js";
|
|
8
9
|
import { readFileSync } from "node:fs";
|
|
9
10
|
|
|
10
11
|
const SLICE_DISPATCH_TYPES = new Set([
|
|
@@ -57,7 +58,7 @@ export function getPriorSliceCompletionBlocker(
|
|
|
57
58
|
if (rows.length > 0) {
|
|
58
59
|
slices = rows.map((r) => ({
|
|
59
60
|
id: r.id,
|
|
60
|
-
done: r.status
|
|
61
|
+
done: isClosedStatus(r.status),
|
|
61
62
|
depends: r.depends ?? [],
|
|
62
63
|
}));
|
|
63
64
|
}
|
|
@@ -211,6 +211,7 @@ Setting `prefer_skills: []` does **not** disable skill discovery — it just mea
|
|
|
211
211
|
- `budget_ceiling`: number — optional per-parallel-run budget ceiling.
|
|
212
212
|
- `merge_strategy`: `"per-slice"` or `"per-milestone"` — when to merge worktree results back. Default: `"per-milestone"`.
|
|
213
213
|
- `auto_merge`: `"auto"`, `"confirm"`, or `"manual"` — merge behavior after completion. `"auto"` merges immediately; `"confirm"` asks first; `"manual"` leaves branches for you. Default: `"confirm"`.
|
|
214
|
+
- `worker_model`: string — optional model override for parallel milestone workers. When set, workers use this model (e.g. `"claude-haiku-4-5"`) instead of inheriting the coordinator's model. Useful for cost savings on execution-heavy milestones.
|
|
214
215
|
|
|
215
216
|
- `verification_commands`: string[] — shell commands to run as verification after task execution (e.g., `["npm test", "npm run lint"]`). Commands run in order; if any fails, the task is marked as needing fixes.
|
|
216
217
|
|
|
@@ -87,7 +87,8 @@ function validatePreferenceShape(preferences: GSDPreferences): string[] {
|
|
|
87
87
|
return issues;
|
|
88
88
|
}
|
|
89
89
|
|
|
90
|
-
|
|
90
|
+
/** Build STATE.md content from derived state. Exported for guided-flow pre-dispatch rebuild (#3475). */
|
|
91
|
+
export function buildStateMarkdown(state: Awaited<ReturnType<typeof deriveState>>): string {
|
|
91
92
|
const lines: string[] = [];
|
|
92
93
|
lines.push("# GSD State", "");
|
|
93
94
|
|
|
@@ -70,6 +70,25 @@ export function clearParseCache(): void {
|
|
|
70
70
|
for (const cb of _cacheClearCallbacks) cb();
|
|
71
71
|
}
|
|
72
72
|
|
|
73
|
+
// ─── Platform shortcuts ───────────────────────────────────────────────────
|
|
74
|
+
|
|
75
|
+
const IS_MAC = process.platform === "darwin";
|
|
76
|
+
|
|
77
|
+
/**
|
|
78
|
+
* Format a keyboard shortcut for the current OS.
|
|
79
|
+
* Input: modifier key combo like "Ctrl+Alt+G"
|
|
80
|
+
* Output: "⌃⌥G" on macOS, "Ctrl+Alt+G" on Windows/Linux.
|
|
81
|
+
*/
|
|
82
|
+
export function formatShortcut(combo: string): string {
|
|
83
|
+
if (!IS_MAC) return combo;
|
|
84
|
+
return combo
|
|
85
|
+
.replace(/Ctrl\+Alt\+/i, "⌃⌥")
|
|
86
|
+
.replace(/Ctrl\+/i, "⌃")
|
|
87
|
+
.replace(/Alt\+/i, "⌥")
|
|
88
|
+
.replace(/Shift\+/i, "⇧")
|
|
89
|
+
.replace(/Cmd\+/i, "⌘");
|
|
90
|
+
}
|
|
91
|
+
|
|
73
92
|
// ─── Helpers ───────────────────────────────────────────────────────────────
|
|
74
93
|
|
|
75
94
|
/** Extract the text after a heading at a given level, up to the next heading of same or higher level. */
|
|
@@ -409,6 +409,7 @@ function initSchema(db: DbAdapter, fileBacked: boolean): void {
|
|
|
409
409
|
db.exec("CREATE INDEX IF NOT EXISTS idx_milestones_status ON milestones(status)");
|
|
410
410
|
db.exec("CREATE INDEX IF NOT EXISTS idx_quality_gates_pending ON quality_gates(milestone_id, slice_id, status)");
|
|
411
411
|
db.exec("CREATE INDEX IF NOT EXISTS idx_verification_evidence_task ON verification_evidence(milestone_id, slice_id, task_id)");
|
|
412
|
+
db.exec("CREATE UNIQUE INDEX IF NOT EXISTS idx_verification_evidence_dedup ON verification_evidence(task_id, slice_id, milestone_id, command, verdict)");
|
|
412
413
|
|
|
413
414
|
// v14 index — slice dependency lookups
|
|
414
415
|
db.exec("CREATE INDEX IF NOT EXISTS idx_slice_deps_target ON slice_dependencies(milestone_id, depends_on_slice_id)");
|
|
@@ -450,6 +451,25 @@ function migrateSchema(db: DbAdapter): void {
|
|
|
450
451
|
const currentVersion = row ? (row["v"] as number) : 0;
|
|
451
452
|
if (currentVersion >= SCHEMA_VERSION) return;
|
|
452
453
|
|
|
454
|
+
// Backup database before migration so a mid-migration crash doesn't
|
|
455
|
+
// leave a partially-migrated DB with no recovery path.
|
|
456
|
+
// WAL-safe: checkpoint first to flush WAL into the main DB file, then copy.
|
|
457
|
+
if (currentPath && currentPath !== ":memory:" && existsSync(currentPath)) {
|
|
458
|
+
try {
|
|
459
|
+
const backupPath = `${currentPath}.backup-v${currentVersion}`;
|
|
460
|
+
if (!existsSync(backupPath)) {
|
|
461
|
+
// Flush WAL to main DB file before copying — without this, the backup
|
|
462
|
+
// may be missing committed data that only exists in the -wal file.
|
|
463
|
+
try { db.exec("PRAGMA wal_checkpoint(TRUNCATE)"); } catch { /* checkpoint is best-effort */ }
|
|
464
|
+
copyFileSync(currentPath, backupPath);
|
|
465
|
+
}
|
|
466
|
+
} catch (backupErr) {
|
|
467
|
+
// Log but proceed — blocking migration leaves the DB stuck at an old
|
|
468
|
+
// schema version permanently on read-only or full filesystems.
|
|
469
|
+
logWarning("db", `Pre-migration backup failed: ${backupErr instanceof Error ? backupErr.message : String(backupErr)}`);
|
|
470
|
+
}
|
|
471
|
+
}
|
|
472
|
+
|
|
453
473
|
db.exec("BEGIN");
|
|
454
474
|
try {
|
|
455
475
|
if (currentVersion < 2) {
|
|
@@ -722,6 +742,7 @@ function migrateSchema(db: DbAdapter): void {
|
|
|
722
742
|
db.exec("CREATE INDEX IF NOT EXISTS idx_milestones_status ON milestones(status)");
|
|
723
743
|
db.exec("CREATE INDEX IF NOT EXISTS idx_quality_gates_pending ON quality_gates(milestone_id, slice_id, status)");
|
|
724
744
|
db.exec("CREATE INDEX IF NOT EXISTS idx_verification_evidence_task ON verification_evidence(milestone_id, slice_id, task_id)");
|
|
745
|
+
db.exec("CREATE UNIQUE INDEX IF NOT EXISTS idx_verification_evidence_dedup ON verification_evidence(task_id, slice_id, milestone_id, command, verdict)");
|
|
725
746
|
db.prepare("INSERT INTO schema_version (version, applied_at) VALUES (:version, :applied_at)").run({
|
|
726
747
|
":version": 13,
|
|
727
748
|
":applied_at": new Date().toISOString(),
|
|
@@ -997,9 +1018,21 @@ export function _resetProvider(): void {
|
|
|
997
1018
|
|
|
998
1019
|
export function upsertDecision(d: Omit<Decision, "seq">): void {
|
|
999
1020
|
if (!currentDb) throw new GSDError(GSD_STALE_STATE, "gsd-db: No database open");
|
|
1021
|
+
// Use ON CONFLICT DO UPDATE instead of INSERT OR REPLACE to preserve the
|
|
1022
|
+
// seq column. INSERT OR REPLACE deletes then reinserts, resetting seq and
|
|
1023
|
+
// corrupting decision ordering in DECISIONS.md after reconcile replay.
|
|
1000
1024
|
currentDb.prepare(
|
|
1001
|
-
`INSERT
|
|
1002
|
-
VALUES (:id, :when_context, :scope, :decision, :choice, :rationale, :revisable, :made_by, :superseded_by)
|
|
1025
|
+
`INSERT INTO decisions (id, when_context, scope, decision, choice, rationale, revisable, made_by, superseded_by)
|
|
1026
|
+
VALUES (:id, :when_context, :scope, :decision, :choice, :rationale, :revisable, :made_by, :superseded_by)
|
|
1027
|
+
ON CONFLICT(id) DO UPDATE SET
|
|
1028
|
+
when_context = excluded.when_context,
|
|
1029
|
+
scope = excluded.scope,
|
|
1030
|
+
decision = excluded.decision,
|
|
1031
|
+
choice = excluded.choice,
|
|
1032
|
+
rationale = excluded.rationale,
|
|
1033
|
+
revisable = excluded.revisable,
|
|
1034
|
+
made_by = excluded.made_by,
|
|
1035
|
+
superseded_by = excluded.superseded_by`,
|
|
1003
1036
|
).run({
|
|
1004
1037
|
":id": d.id,
|
|
1005
1038
|
":when_context": d.when_context,
|
|
@@ -1119,7 +1152,9 @@ export function insertMilestone(m: {
|
|
|
1119
1152
|
).run({
|
|
1120
1153
|
":id": m.id,
|
|
1121
1154
|
":title": m.title ?? "",
|
|
1122
|
-
"
|
|
1155
|
+
// Default to "queued" — never auto-create milestones as "active" (#3380).
|
|
1156
|
+
// Callers that need "active" must pass it explicitly.
|
|
1157
|
+
":status": m.status ?? "queued",
|
|
1123
1158
|
":depends_on": JSON.stringify(m.depends_on ?? []),
|
|
1124
1159
|
":created_at": new Date().toISOString(),
|
|
1125
1160
|
":vision": m.planning?.vision ?? "",
|
|
@@ -1349,6 +1384,13 @@ export function updateTaskStatus(milestoneId: string, sliceId: string, taskId: s
|
|
|
1349
1384
|
});
|
|
1350
1385
|
}
|
|
1351
1386
|
|
|
1387
|
+
export function setTaskBlockerDiscovered(milestoneId: string, sliceId: string, taskId: string, discovered: boolean): void {
|
|
1388
|
+
if (!currentDb) return;
|
|
1389
|
+
currentDb.prepare(
|
|
1390
|
+
`UPDATE tasks SET blocker_discovered = :discovered WHERE milestone_id = :mid AND slice_id = :sid AND id = :tid`,
|
|
1391
|
+
).run({ ":discovered": discovered ? 1 : 0, ":mid": milestoneId, ":sid": sliceId, ":tid": taskId });
|
|
1392
|
+
}
|
|
1393
|
+
|
|
1352
1394
|
export function upsertTaskPlanning(milestoneId: string, sliceId: string, taskId: string, planning: Partial<TaskPlanningRecord>): void {
|
|
1353
1395
|
if (!currentDb) throw new GSDError(GSD_STALE_STATE, "gsd-db: No database open");
|
|
1354
1396
|
currentDb.prepare(
|
|
@@ -1543,7 +1585,7 @@ export function insertVerificationEvidence(e: {
|
|
|
1543
1585
|
}): void {
|
|
1544
1586
|
if (!currentDb) throw new GSDError(GSD_STALE_STATE, "gsd-db: No database open");
|
|
1545
1587
|
currentDb.prepare(
|
|
1546
|
-
`INSERT INTO verification_evidence (task_id, slice_id, milestone_id, command, exit_code, verdict, duration_ms, created_at)
|
|
1588
|
+
`INSERT OR IGNORE INTO verification_evidence (task_id, slice_id, milestone_id, command, exit_code, verdict, duration_ms, created_at)
|
|
1547
1589
|
VALUES (:task_id, :slice_id, :milestone_id, :command, :exit_code, :verdict, :duration_ms, :created_at)`,
|
|
1548
1590
|
).run({
|
|
1549
1591
|
":task_id": e.taskId,
|