gsd-pi 2.66.1-dev.ed243f2 → 2.67.0-dev.43b0159
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/claude-cli-check.d.ts +8 -0
- package/dist/claude-cli-check.js +36 -0
- package/dist/cli.js +40 -0
- package/dist/onboarding.js +19 -2
- package/dist/resources/extensions/ask-user-questions.js +79 -11
- package/dist/resources/extensions/claude-code-cli/partial-builder.js +4 -3
- package/dist/resources/extensions/claude-code-cli/readiness.js +63 -12
- package/dist/resources/extensions/claude-code-cli/stream-adapter.js +10 -3
- package/dist/resources/extensions/gsd/auto/loop.js +13 -1
- package/dist/resources/extensions/gsd/auto/phases.js +22 -3
- package/dist/resources/extensions/gsd/auto/run-unit.js +10 -2
- package/dist/resources/extensions/gsd/auto/session.js +1 -1
- package/dist/resources/extensions/gsd/auto-dashboard.js +65 -15
- package/dist/resources/extensions/gsd/auto-dispatch.js +30 -28
- package/dist/resources/extensions/gsd/auto-model-selection.js +12 -3
- package/dist/resources/extensions/gsd/auto-prompts.js +173 -25
- package/dist/resources/extensions/gsd/auto-recovery.js +11 -12
- package/dist/resources/extensions/gsd/auto.js +13 -1
- package/dist/resources/extensions/gsd/bootstrap/agent-end-recovery.js +32 -1
- package/dist/resources/extensions/gsd/bootstrap/db-tools.js +18 -6
- package/dist/resources/extensions/gsd/bootstrap/provider-error-resume.js +5 -0
- package/dist/resources/extensions/gsd/bootstrap/register-hooks.js +59 -5
- package/dist/resources/extensions/gsd/bootstrap/register-shortcuts.js +8 -5
- package/dist/resources/extensions/gsd/bootstrap/write-gate.js +186 -14
- package/dist/resources/extensions/gsd/codebase-generator.js +4 -0
- package/dist/resources/extensions/gsd/commands/catalog.js +2 -1
- package/dist/resources/extensions/gsd/commands/dispatcher.js +1 -1
- package/dist/resources/extensions/gsd/commands/handlers/core.js +94 -4
- package/dist/resources/extensions/gsd/commands-prefs-wizard.js +49 -9
- package/dist/resources/extensions/gsd/context-store.js +134 -2
- package/dist/resources/extensions/gsd/custom-workflow-engine.js +3 -1
- package/dist/resources/extensions/gsd/detection.js +6 -0
- package/dist/resources/extensions/gsd/files.js +19 -2
- package/dist/resources/extensions/gsd/guided-flow.js +12 -8
- package/dist/resources/extensions/gsd/index.js +1 -1
- package/dist/resources/extensions/gsd/parallel-monitor-overlay.js +2 -0
- package/dist/resources/extensions/gsd/parsers-legacy.js +3 -1
- package/dist/resources/extensions/gsd/preferences.js +6 -1
- package/dist/resources/extensions/gsd/prompts/complete-milestone.md +1 -1
- package/dist/resources/extensions/gsd/prompts/complete-slice.md +3 -3
- package/dist/resources/extensions/gsd/prompts/discuss-prepared.md +7 -7
- package/dist/resources/extensions/gsd/prompts/discuss.md +3 -3
- package/dist/resources/extensions/gsd/prompts/execute-task.md +3 -3
- package/dist/resources/extensions/gsd/prompts/guided-discuss-milestone.md +3 -3
- package/dist/resources/extensions/gsd/prompts/guided-discuss-slice.md +3 -1
- package/dist/resources/extensions/gsd/prompts/rethink.md +6 -2
- package/dist/resources/extensions/gsd/prompts/system.md +1 -1
- package/dist/resources/extensions/gsd/prompts/triage-captures.md +1 -1
- package/dist/resources/extensions/gsd/prompts/validate-milestone.md +11 -9
- package/dist/resources/extensions/gsd/prompts/worktree-merge.md +3 -1
- package/dist/resources/extensions/gsd/safety/file-change-validator.js +2 -1
- package/dist/resources/extensions/gsd/state.js +2 -1
- package/dist/resources/extensions/gsd/visualizer-overlay.js +27 -26
- package/dist/resources/extensions/gsd/workflow-reconcile.js +46 -7
- package/dist/resources/extensions/remote-questions/manager.js +8 -0
- package/dist/resources/extensions/shared/interview-ui.js +10 -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 +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/api/settings-data/route.js +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/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 → 6502.b804e48b7919f55e.js} +3 -3
- package/dist/web/standalone/.next/static/chunks/{webpack-9fed74684e1c5bb1.js → webpack-65f0501b197d1c49.js} +1 -1
- package/package.json +1 -1
- package/packages/pi-ai/dist/providers/anthropic-shared.d.ts.map +1 -1
- package/packages/pi-ai/dist/providers/anthropic-shared.js +4 -3
- package/packages/pi-ai/dist/providers/anthropic-shared.js.map +1 -1
- package/packages/pi-ai/dist/utils/json-parse.d.ts.map +1 -1
- package/packages/pi-ai/dist/utils/json-parse.js +11 -1
- package/packages/pi-ai/dist/utils/json-parse.js.map +1 -1
- package/packages/pi-ai/dist/utils/repair-tool-json.d.ts.map +1 -1
- package/packages/pi-ai/dist/utils/repair-tool-json.js +60 -1
- package/packages/pi-ai/dist/utils/repair-tool-json.js.map +1 -1
- package/packages/pi-ai/dist/utils/tests/json-parse.test.d.ts +2 -0
- package/packages/pi-ai/dist/utils/tests/json-parse.test.d.ts.map +1 -0
- package/packages/pi-ai/dist/utils/tests/json-parse.test.js +14 -0
- package/packages/pi-ai/dist/utils/tests/json-parse.test.js.map +1 -0
- package/packages/pi-ai/dist/utils/tests/repair-tool-json.test.js +10 -0
- package/packages/pi-ai/dist/utils/tests/repair-tool-json.test.js.map +1 -1
- package/packages/pi-ai/src/providers/anthropic-shared.ts +4 -3
- package/packages/pi-ai/src/utils/json-parse.ts +11 -1
- package/packages/pi-ai/src/utils/repair-tool-json.ts +69 -1
- package/packages/pi-ai/src/utils/tests/json-parse.test.ts +17 -0
- package/packages/pi-ai/src/utils/tests/repair-tool-json.test.ts +13 -0
- package/packages/pi-coding-agent/dist/core/agent-session.d.ts +3 -0
- package/packages/pi-coding-agent/dist/core/agent-session.d.ts.map +1 -1
- package/packages/pi-coding-agent/dist/core/agent-session.js +1 -0
- package/packages/pi-coding-agent/dist/core/agent-session.js.map +1 -1
- package/packages/pi-coding-agent/dist/core/retry-handler.d.ts +16 -0
- package/packages/pi-coding-agent/dist/core/retry-handler.d.ts.map +1 -1
- package/packages/pi-coding-agent/dist/core/retry-handler.js +58 -1
- package/packages/pi-coding-agent/dist/core/retry-handler.js.map +1 -1
- package/packages/pi-coding-agent/dist/core/retry-handler.test.js +58 -0
- package/packages/pi-coding-agent/dist/core/retry-handler.test.js.map +1 -1
- package/packages/pi-coding-agent/dist/core/sdk.d.ts +3 -0
- package/packages/pi-coding-agent/dist/core/sdk.d.ts.map +1 -1
- package/packages/pi-coding-agent/dist/core/sdk.js +1 -0
- package/packages/pi-coding-agent/dist/core/sdk.js.map +1 -1
- package/packages/pi-coding-agent/dist/modes/interactive/components/__tests__/provider-display-name.test.d.ts +2 -0
- package/packages/pi-coding-agent/dist/modes/interactive/components/__tests__/provider-display-name.test.d.ts.map +1 -0
- package/packages/pi-coding-agent/dist/modes/interactive/components/__tests__/provider-display-name.test.js +17 -0
- package/packages/pi-coding-agent/dist/modes/interactive/components/__tests__/provider-display-name.test.js.map +1 -0
- package/packages/pi-coding-agent/dist/modes/interactive/components/footer.d.ts.map +1 -1
- package/packages/pi-coding-agent/dist/modes/interactive/components/footer.js +2 -1
- package/packages/pi-coding-agent/dist/modes/interactive/components/footer.js.map +1 -1
- package/packages/pi-coding-agent/dist/modes/interactive/components/model-selector.d.ts +1 -0
- package/packages/pi-coding-agent/dist/modes/interactive/components/model-selector.d.ts.map +1 -1
- package/packages/pi-coding-agent/dist/modes/interactive/components/model-selector.js +9 -2
- package/packages/pi-coding-agent/dist/modes/interactive/components/model-selector.js.map +1 -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 +2 -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/scoped-models-selector.d.ts.map +1 -1
- package/packages/pi-coding-agent/dist/modes/interactive/components/scoped-models-selector.js +2 -1
- package/packages/pi-coding-agent/dist/modes/interactive/components/scoped-models-selector.js.map +1 -1
- package/packages/pi-coding-agent/dist/modes/interactive/interactive-mode.js +2 -2
- package/packages/pi-coding-agent/dist/modes/interactive/interactive-mode.js.map +1 -1
- package/packages/pi-coding-agent/package.json +1 -1
- package/packages/pi-coding-agent/src/core/agent-session.ts +4 -0
- package/packages/pi-coding-agent/src/core/retry-handler.test.ts +69 -0
- package/packages/pi-coding-agent/src/core/retry-handler.ts +66 -1
- package/packages/pi-coding-agent/src/core/sdk.ts +5 -0
- package/packages/pi-coding-agent/src/modes/interactive/components/__tests__/provider-display-name.test.ts +18 -0
- package/packages/pi-coding-agent/src/modes/interactive/components/footer.ts +2 -1
- package/packages/pi-coding-agent/src/modes/interactive/components/model-selector.ts +11 -2
- package/packages/pi-coding-agent/src/modes/interactive/components/provider-manager.ts +2 -1
- package/packages/pi-coding-agent/src/modes/interactive/components/scoped-models-selector.ts +2 -1
- package/packages/pi-coding-agent/src/modes/interactive/interactive-mode.ts +2 -2
- package/packages/pi-tui/dist/__tests__/autocomplete.test.js +13 -0
- package/packages/pi-tui/dist/__tests__/autocomplete.test.js.map +1 -1
- package/packages/pi-tui/dist/__tests__/stdin-buffer.test.d.ts +2 -0
- package/packages/pi-tui/dist/__tests__/stdin-buffer.test.d.ts.map +1 -0
- package/packages/pi-tui/dist/__tests__/stdin-buffer.test.js +35 -0
- package/packages/pi-tui/dist/__tests__/stdin-buffer.test.js.map +1 -0
- package/packages/pi-tui/dist/__tests__/tui.test.d.ts +2 -0
- package/packages/pi-tui/dist/__tests__/tui.test.d.ts.map +1 -0
- package/packages/pi-tui/dist/__tests__/tui.test.js +43 -0
- package/packages/pi-tui/dist/__tests__/tui.test.js.map +1 -0
- package/packages/pi-tui/dist/autocomplete.d.ts.map +1 -1
- package/packages/pi-tui/dist/autocomplete.js +9 -7
- package/packages/pi-tui/dist/autocomplete.js.map +1 -1
- package/packages/pi-tui/dist/components/__tests__/editor.test.d.ts +2 -0
- package/packages/pi-tui/dist/components/__tests__/editor.test.d.ts.map +1 -0
- package/packages/pi-tui/dist/components/__tests__/editor.test.js +54 -0
- package/packages/pi-tui/dist/components/__tests__/editor.test.js.map +1 -0
- package/packages/pi-tui/dist/components/editor.d.ts +3 -1
- package/packages/pi-tui/dist/components/editor.d.ts.map +1 -1
- package/packages/pi-tui/dist/components/editor.js +14 -3
- package/packages/pi-tui/dist/components/editor.js.map +1 -1
- package/packages/pi-tui/dist/stdin-buffer.d.ts.map +1 -1
- package/packages/pi-tui/dist/stdin-buffer.js +6 -0
- package/packages/pi-tui/dist/stdin-buffer.js.map +1 -1
- package/packages/pi-tui/dist/tui.d.ts.map +1 -1
- package/packages/pi-tui/dist/tui.js +8 -0
- package/packages/pi-tui/dist/tui.js.map +1 -1
- package/packages/pi-tui/src/__tests__/autocomplete.test.ts +15 -0
- package/packages/pi-tui/src/__tests__/stdin-buffer.test.ts +43 -0
- package/packages/pi-tui/src/__tests__/tui.test.ts +50 -0
- package/packages/pi-tui/src/autocomplete.ts +9 -7
- package/packages/pi-tui/src/components/__tests__/editor.test.ts +64 -0
- package/packages/pi-tui/src/components/editor.ts +14 -3
- package/packages/pi-tui/src/stdin-buffer.ts +7 -0
- package/packages/pi-tui/src/tui.ts +9 -0
- package/pkg/package.json +1 -1
- package/src/resources/extensions/ask-user-questions.ts +103 -11
- package/src/resources/extensions/claude-code-cli/partial-builder.ts +4 -3
- package/src/resources/extensions/claude-code-cli/readiness.ts +67 -12
- package/src/resources/extensions/claude-code-cli/stream-adapter.ts +12 -3
- package/src/resources/extensions/claude-code-cli/tests/partial-builder.test.ts +17 -0
- package/src/resources/extensions/claude-code-cli/tests/stream-adapter.test.ts +18 -0
- package/src/resources/extensions/gsd/auto/loop-deps.ts +2 -1
- package/src/resources/extensions/gsd/auto/loop.ts +14 -1
- package/src/resources/extensions/gsd/auto/phases.ts +27 -4
- package/src/resources/extensions/gsd/auto/run-unit.ts +14 -2
- package/src/resources/extensions/gsd/auto/session.ts +1 -1
- package/src/resources/extensions/gsd/auto-dashboard.ts +76 -16
- package/src/resources/extensions/gsd/auto-dispatch.ts +36 -35
- package/src/resources/extensions/gsd/auto-model-selection.ts +12 -3
- package/src/resources/extensions/gsd/auto-prompts.ts +195 -25
- package/src/resources/extensions/gsd/auto-recovery.ts +15 -15
- package/src/resources/extensions/gsd/auto.ts +12 -1
- package/src/resources/extensions/gsd/bootstrap/agent-end-recovery.ts +34 -1
- package/src/resources/extensions/gsd/bootstrap/db-tools.ts +27 -6
- package/src/resources/extensions/gsd/bootstrap/provider-error-resume.ts +6 -0
- package/src/resources/extensions/gsd/bootstrap/register-hooks.ts +67 -6
- package/src/resources/extensions/gsd/bootstrap/register-shortcuts.ts +11 -8
- package/src/resources/extensions/gsd/bootstrap/write-gate.ts +209 -16
- package/src/resources/extensions/gsd/codebase-generator.ts +4 -0
- package/src/resources/extensions/gsd/commands/catalog.ts +2 -1
- package/src/resources/extensions/gsd/commands/dispatcher.ts +1 -2
- package/src/resources/extensions/gsd/commands/handlers/core.ts +113 -8
- package/src/resources/extensions/gsd/commands-prefs-wizard.ts +49 -11
- package/src/resources/extensions/gsd/context-store.ts +167 -2
- package/src/resources/extensions/gsd/custom-workflow-engine.ts +3 -1
- package/src/resources/extensions/gsd/detection.ts +6 -0
- package/src/resources/extensions/gsd/files.ts +21 -2
- package/src/resources/extensions/gsd/guided-flow.ts +15 -8
- package/src/resources/extensions/gsd/index.ts +6 -0
- package/src/resources/extensions/gsd/parallel-monitor-overlay.ts +2 -0
- package/src/resources/extensions/gsd/parsers-legacy.ts +3 -1
- package/src/resources/extensions/gsd/preferences.ts +6 -1
- package/src/resources/extensions/gsd/prompts/complete-milestone.md +1 -1
- package/src/resources/extensions/gsd/prompts/complete-slice.md +3 -3
- package/src/resources/extensions/gsd/prompts/discuss-prepared.md +7 -7
- package/src/resources/extensions/gsd/prompts/discuss.md +3 -3
- package/src/resources/extensions/gsd/prompts/execute-task.md +3 -3
- package/src/resources/extensions/gsd/prompts/guided-discuss-milestone.md +3 -3
- package/src/resources/extensions/gsd/prompts/guided-discuss-slice.md +3 -1
- package/src/resources/extensions/gsd/prompts/rethink.md +6 -2
- package/src/resources/extensions/gsd/prompts/system.md +1 -1
- package/src/resources/extensions/gsd/prompts/triage-captures.md +1 -1
- package/src/resources/extensions/gsd/prompts/validate-milestone.md +11 -9
- package/src/resources/extensions/gsd/prompts/worktree-merge.md +3 -1
- package/src/resources/extensions/gsd/safety/file-change-validator.ts +4 -1
- package/src/resources/extensions/gsd/state.ts +2 -1
- package/src/resources/extensions/gsd/tests/auto-dashboard.test.ts +52 -1
- package/src/resources/extensions/gsd/tests/auto-loop.test.ts +50 -2
- package/src/resources/extensions/gsd/tests/auto-model-selection.test.ts +21 -7
- package/src/resources/extensions/gsd/tests/auto-recovery.test.ts +48 -0
- package/src/resources/extensions/gsd/tests/codebase-generator.test.ts +22 -0
- package/src/resources/extensions/gsd/tests/commands-workflow-custom.test.ts +12 -0
- package/src/resources/extensions/gsd/tests/context-store.test.ts +176 -0
- package/src/resources/extensions/gsd/tests/core-overlay-fallback.test.ts +76 -0
- package/src/resources/extensions/gsd/tests/custom-engine-loop-integration.test.ts +7 -1
- package/src/resources/extensions/gsd/tests/custom-workflow-engine.test.ts +31 -0
- package/src/resources/extensions/gsd/tests/decision-scope-cascade.test.ts +370 -0
- package/src/resources/extensions/gsd/tests/detection.test.ts +37 -0
- package/src/resources/extensions/gsd/tests/file-change-validator.test.ts +50 -0
- package/src/resources/extensions/gsd/tests/gsd-tools.test.ts +35 -0
- package/src/resources/extensions/gsd/tests/guided-flow-session-isolation.test.ts +34 -0
- package/src/resources/extensions/gsd/tests/health-widget.test.ts +45 -0
- package/src/resources/extensions/gsd/tests/integration/auto-recovery.test.ts +53 -13
- package/src/resources/extensions/gsd/tests/integration/state-machine-runtime-failures.test.ts +2 -2
- package/src/resources/extensions/gsd/tests/journal-integration.test.ts +3 -3
- package/src/resources/extensions/gsd/tests/measurement.test.ts +531 -0
- package/src/resources/extensions/gsd/tests/migrate-writer-integration.test.ts +3 -4
- package/src/resources/extensions/gsd/tests/parallel-monitor-overlay.test.ts +21 -0
- package/src/resources/extensions/gsd/tests/parallel-research-dispatch.test.ts +71 -2
- package/src/resources/extensions/gsd/tests/parsers.test.ts +25 -0
- package/src/resources/extensions/gsd/tests/preferences.test.ts +37 -0
- package/src/resources/extensions/gsd/tests/prompt-contracts.test.ts +26 -4
- package/src/resources/extensions/gsd/tests/provider-errors.test.ts +60 -0
- package/src/resources/extensions/gsd/tests/queue-execution-guard.test.ts +9 -0
- package/src/resources/extensions/gsd/tests/reactive-graph.test.ts +19 -0
- package/src/resources/extensions/gsd/tests/register-shortcuts.test.ts +73 -0
- package/src/resources/extensions/gsd/tests/remote-questions.test.ts +98 -0
- package/src/resources/extensions/gsd/tests/smart-entry-complete.test.ts +2 -2
- package/src/resources/extensions/gsd/tests/validate-milestone.test.ts +26 -0
- package/src/resources/extensions/gsd/tests/visualizer-overlay.test.ts +59 -0
- package/src/resources/extensions/gsd/tests/workflow-reconcile.test.ts +91 -0
- package/src/resources/extensions/gsd/tests/write-gate.test.ts +210 -35
- package/src/resources/extensions/gsd/visualizer-overlay.ts +31 -27
- package/src/resources/extensions/gsd/workflow-reconcile.ts +59 -8
- package/src/resources/extensions/remote-questions/manager.ts +9 -0
- package/src/resources/extensions/shared/interview-ui.ts +13 -0
- /package/dist/web/standalone/.next/static/{HAq0VE4k68rhRvJbQL1VW → CrKrzIIxk55witDF1eS0L}/_buildManifest.js +0 -0
- /package/dist/web/standalone/.next/static/{HAq0VE4k68rhRvJbQL1VW → CrKrzIIxk55witDF1eS0L}/_ssgManifest.js +0 -0
|
@@ -44,6 +44,7 @@ export function showHelp(ctx) {
|
|
|
44
44
|
"SETUP & CONFIGURATION",
|
|
45
45
|
" /gsd init Project init wizard — detect, configure, bootstrap .gsd/",
|
|
46
46
|
" /gsd setup Global setup status [llm|search|remote|keys|prefs]",
|
|
47
|
+
" /gsd model Switch active session model [provider/model|model-id]",
|
|
47
48
|
" /gsd mode Set workflow mode (solo/team) [global|project]",
|
|
48
49
|
" /gsd prefs Manage preferences [global|project|status|wizard|setup|import-claude]",
|
|
49
50
|
" /gsd cmux Manage cmux integration [status|on|off|notifications|sidebar|splits|browser]",
|
|
@@ -77,7 +78,7 @@ export async function handleStatus(ctx) {
|
|
|
77
78
|
return;
|
|
78
79
|
}
|
|
79
80
|
const { GSDDashboardOverlay } = await import("../../dashboard-overlay.js");
|
|
80
|
-
const result = await ctx.ui.custom((tui, theme, _kb, done) => new GSDDashboardOverlay(tui, theme, () => done()), {
|
|
81
|
+
const result = await ctx.ui.custom((tui, theme, _kb, done) => new GSDDashboardOverlay(tui, theme, () => done(true)), {
|
|
81
82
|
overlay: true,
|
|
82
83
|
overlayOptions: {
|
|
83
84
|
width: "70%",
|
|
@@ -99,7 +100,7 @@ export async function handleVisualize(ctx) {
|
|
|
99
100
|
return;
|
|
100
101
|
}
|
|
101
102
|
const { GSDVisualizerOverlay } = await import("../../visualizer-overlay.js");
|
|
102
|
-
const result = await ctx.ui.custom((tui, theme, _kb, done) => new GSDVisualizerOverlay(tui, theme, () => done()), {
|
|
103
|
+
const result = await ctx.ui.custom((tui, theme, _kb, done) => new GSDVisualizerOverlay(tui, theme, () => done(true)), {
|
|
103
104
|
overlay: true,
|
|
104
105
|
overlayOptions: {
|
|
105
106
|
width: "80%",
|
|
@@ -152,7 +153,92 @@ export async function handleSetup(args, ctx) {
|
|
|
152
153
|
" /gsd setup keys — Tool API keys\n" +
|
|
153
154
|
" /gsd setup prefs — Global preferences wizard", "info");
|
|
154
155
|
}
|
|
155
|
-
|
|
156
|
+
function sortModelsForSelection(models, currentModel) {
|
|
157
|
+
return [...models].sort((a, b) => {
|
|
158
|
+
const aCurrent = currentModel && a.provider === currentModel.provider && a.id === currentModel.id;
|
|
159
|
+
const bCurrent = currentModel && b.provider === currentModel.provider && b.id === currentModel.id;
|
|
160
|
+
if (aCurrent && !bCurrent)
|
|
161
|
+
return -1;
|
|
162
|
+
if (!aCurrent && bCurrent)
|
|
163
|
+
return 1;
|
|
164
|
+
const providerCmp = a.provider.localeCompare(b.provider);
|
|
165
|
+
if (providerCmp !== 0)
|
|
166
|
+
return providerCmp;
|
|
167
|
+
return a.id.localeCompare(b.id);
|
|
168
|
+
});
|
|
169
|
+
}
|
|
170
|
+
async function resolveRequestedModel(query, ctx) {
|
|
171
|
+
const { resolveModelId } = await import("../../auto-model-selection.js");
|
|
172
|
+
const models = ctx.modelRegistry.getAvailable();
|
|
173
|
+
const exact = resolveModelId(query, models, ctx.model?.provider);
|
|
174
|
+
if (exact)
|
|
175
|
+
return exact;
|
|
176
|
+
const lowerQuery = query.toLowerCase();
|
|
177
|
+
const partialMatches = models.filter((model) => model.id.toLowerCase().includes(lowerQuery)
|
|
178
|
+
|| `${model.provider}/${model.id}`.toLowerCase().includes(lowerQuery));
|
|
179
|
+
if (partialMatches.length === 1)
|
|
180
|
+
return partialMatches[0];
|
|
181
|
+
if (partialMatches.length === 0 || !ctx.hasUI)
|
|
182
|
+
return undefined;
|
|
183
|
+
const sorted = sortModelsForSelection(partialMatches, ctx.model);
|
|
184
|
+
const optionToModel = new Map();
|
|
185
|
+
const options = sorted.map((model) => {
|
|
186
|
+
const label = `${model.provider}/${model.id}`;
|
|
187
|
+
optionToModel.set(label, model);
|
|
188
|
+
return label;
|
|
189
|
+
});
|
|
190
|
+
options.push("(cancel)");
|
|
191
|
+
const choice = await ctx.ui.select(`Multiple models match "${query}" — choose one:`, options);
|
|
192
|
+
if (!choice || typeof choice !== "string" || choice === "(cancel)")
|
|
193
|
+
return undefined;
|
|
194
|
+
return optionToModel.get(choice);
|
|
195
|
+
}
|
|
196
|
+
async function handleModel(trimmedArgs, ctx, pi) {
|
|
197
|
+
const availableModels = ctx.modelRegistry.getAvailable();
|
|
198
|
+
if (availableModels.length === 0) {
|
|
199
|
+
ctx.ui.notify("No available models found. Check provider auth and model discovery.", "warning");
|
|
200
|
+
return;
|
|
201
|
+
}
|
|
202
|
+
if (!pi) {
|
|
203
|
+
ctx.ui.notify("Model switching is unavailable in this context.", "warning");
|
|
204
|
+
return;
|
|
205
|
+
}
|
|
206
|
+
const trimmed = trimmedArgs.trim();
|
|
207
|
+
let targetModel;
|
|
208
|
+
if (!trimmed) {
|
|
209
|
+
if (!ctx.hasUI) {
|
|
210
|
+
const current = ctx.model ? `${ctx.model.provider}/${ctx.model.id}` : "(none)";
|
|
211
|
+
ctx.ui.notify(`Current model: ${current}\nUsage: /gsd model <provider/model|model-id>`, "info");
|
|
212
|
+
return;
|
|
213
|
+
}
|
|
214
|
+
const optionToModel = new Map();
|
|
215
|
+
const options = sortModelsForSelection(availableModels, ctx.model).map((model) => {
|
|
216
|
+
const isCurrent = ctx.model && model.provider === ctx.model.provider && model.id === ctx.model.id;
|
|
217
|
+
const label = `${isCurrent ? "* " : ""}${model.provider}/${model.id}`;
|
|
218
|
+
optionToModel.set(label, model);
|
|
219
|
+
return label;
|
|
220
|
+
});
|
|
221
|
+
options.push("(cancel)");
|
|
222
|
+
const choice = await ctx.ui.select("Select session model:", options);
|
|
223
|
+
if (!choice || typeof choice !== "string" || choice === "(cancel)")
|
|
224
|
+
return;
|
|
225
|
+
targetModel = optionToModel.get(choice);
|
|
226
|
+
}
|
|
227
|
+
else {
|
|
228
|
+
targetModel = await resolveRequestedModel(trimmed, ctx);
|
|
229
|
+
}
|
|
230
|
+
if (!targetModel) {
|
|
231
|
+
ctx.ui.notify(`Model "${trimmed}" not found. Use /gsd model with an exact provider/model or a unique model ID.`, "warning");
|
|
232
|
+
return;
|
|
233
|
+
}
|
|
234
|
+
const ok = await pi.setModel(targetModel);
|
|
235
|
+
if (!ok) {
|
|
236
|
+
ctx.ui.notify(`No API key for ${targetModel.provider}/${targetModel.id}`, "warning");
|
|
237
|
+
return;
|
|
238
|
+
}
|
|
239
|
+
ctx.ui.notify(`Model: ${targetModel.provider}/${targetModel.id}`, "info");
|
|
240
|
+
}
|
|
241
|
+
export async function handleCoreCommand(trimmed, ctx, pi) {
|
|
156
242
|
if (trimmed === "help" || trimmed === "h" || trimmed === "?") {
|
|
157
243
|
showHelp(ctx);
|
|
158
244
|
return true;
|
|
@@ -177,6 +263,10 @@ export async function handleCoreCommand(trimmed, ctx) {
|
|
|
177
263
|
ctx.ui.notify(`Widget: ${getWidgetMode()}`, "info");
|
|
178
264
|
return true;
|
|
179
265
|
}
|
|
266
|
+
if (trimmed === "model" || trimmed.startsWith("model ")) {
|
|
267
|
+
await handleModel(trimmed.replace(/^model\s*/, "").trim(), ctx, pi);
|
|
268
|
+
return true;
|
|
269
|
+
}
|
|
180
270
|
if (trimmed === "mode" || trimmed.startsWith("mode ")) {
|
|
181
271
|
const modeArgs = trimmed.replace(/^mode\s*/, "").trim();
|
|
182
272
|
const scope = modeArgs === "project" ? "project" : "global";
|
|
@@ -195,7 +285,7 @@ export async function handleCoreCommand(trimmed, ctx) {
|
|
|
195
285
|
}
|
|
196
286
|
if (trimmed === "show-config") {
|
|
197
287
|
const { GSDConfigOverlay, formatConfigText } = await import("../../config-overlay.js");
|
|
198
|
-
const result = await ctx.ui.custom((tui, theme, _kb, done) => new GSDConfigOverlay(tui, theme, () => done()), {
|
|
288
|
+
const result = await ctx.ui.custom((tui, theme, _kb, done) => new GSDConfigOverlay(tui, theme, () => done(true)), {
|
|
199
289
|
overlay: true,
|
|
200
290
|
overlayOptions: {
|
|
201
291
|
width: "65%",
|
|
@@ -137,7 +137,7 @@ export function buildCategorySummaries(prefs) {
|
|
|
137
137
|
const models = prefs.models;
|
|
138
138
|
let modelsSummary = "(not configured)";
|
|
139
139
|
if (models && Object.keys(models).length > 0) {
|
|
140
|
-
const parts = Object.entries(models).map(([phase, model]) => `${phase}: ${model}`);
|
|
140
|
+
const parts = Object.entries(models).map(([phase, model]) => `${phase}: ${formatConfiguredModel(model)}`);
|
|
141
141
|
modelsSummary = parts.join(", ");
|
|
142
142
|
}
|
|
143
143
|
// Timeouts
|
|
@@ -220,8 +220,39 @@ export function buildCategorySummaries(prefs) {
|
|
|
220
220
|
};
|
|
221
221
|
}
|
|
222
222
|
// ─── Category configuration functions ────────────────────────────────────────
|
|
223
|
+
export function formatConfiguredModel(config) {
|
|
224
|
+
if (typeof config === "string")
|
|
225
|
+
return config;
|
|
226
|
+
if (!config || typeof config !== "object")
|
|
227
|
+
return "(invalid)";
|
|
228
|
+
const maybeConfig = config;
|
|
229
|
+
if (typeof maybeConfig.model !== "string" || maybeConfig.model.trim() === "")
|
|
230
|
+
return "(invalid)";
|
|
231
|
+
if (typeof maybeConfig.provider === "string" && maybeConfig.provider && !maybeConfig.model.includes("/")) {
|
|
232
|
+
return `${maybeConfig.provider}/${maybeConfig.model}`;
|
|
233
|
+
}
|
|
234
|
+
return maybeConfig.model;
|
|
235
|
+
}
|
|
236
|
+
export function toPersistedModelId(provider, modelId) {
|
|
237
|
+
if (!provider.trim())
|
|
238
|
+
return modelId;
|
|
239
|
+
const normalizedProvider = provider.trim();
|
|
240
|
+
const normalizedModelId = modelId.trim();
|
|
241
|
+
return normalizedModelId.startsWith(`${normalizedProvider}/`)
|
|
242
|
+
? normalizedModelId
|
|
243
|
+
: `${normalizedProvider}/${normalizedModelId}`;
|
|
244
|
+
}
|
|
223
245
|
async function configureModels(ctx, prefs) {
|
|
224
|
-
const modelPhases = [
|
|
246
|
+
const modelPhases = [
|
|
247
|
+
"research",
|
|
248
|
+
"planning",
|
|
249
|
+
"discuss",
|
|
250
|
+
"execution",
|
|
251
|
+
"execution_simple",
|
|
252
|
+
"completion",
|
|
253
|
+
"validation",
|
|
254
|
+
"subagent",
|
|
255
|
+
];
|
|
225
256
|
const models = prefs.models ?? {};
|
|
226
257
|
const availableModels = ctx.modelRegistry.getAvailable();
|
|
227
258
|
if (availableModels.length > 0) {
|
|
@@ -240,14 +271,20 @@ async function configureModels(ctx, prefs) {
|
|
|
240
271
|
for (const group of byProvider.values()) {
|
|
241
272
|
group.sort((a, b) => a.id.localeCompare(b.id));
|
|
242
273
|
}
|
|
243
|
-
//
|
|
274
|
+
// Display names for providers in the preferences wizard UI.
|
|
275
|
+
const PROVIDER_DISPLAY_NAMES = { anthropic: "anthropic-api" };
|
|
276
|
+
const displayName = (p) => PROVIDER_DISPLAY_NAMES[p] ?? p;
|
|
277
|
+
// Build provider menu with model counts (display name → real name lookup)
|
|
278
|
+
const displayToReal = new Map();
|
|
244
279
|
const providerOptions = providers.map(p => {
|
|
245
280
|
const count = byProvider.get(p).length;
|
|
246
|
-
|
|
281
|
+
const label = `${displayName(p)} (${count} models)`;
|
|
282
|
+
displayToReal.set(label, p);
|
|
283
|
+
return label;
|
|
247
284
|
});
|
|
248
285
|
providerOptions.push("(keep current)", "(clear)", "(type manually)");
|
|
249
286
|
for (const phase of modelPhases) {
|
|
250
|
-
const current = models[phase]
|
|
287
|
+
const current = formatConfiguredModel(models[phase]);
|
|
251
288
|
const phaseLabel = `Model for ${phase} phase${current ? ` (current: ${current})` : ""}`;
|
|
252
289
|
// Step 1: pick provider
|
|
253
290
|
const providerChoice = await ctx.ui.select(`${phaseLabel} — choose provider:`, providerOptions);
|
|
@@ -267,26 +304,26 @@ async function configureModels(ctx, prefs) {
|
|
|
267
304
|
continue;
|
|
268
305
|
}
|
|
269
306
|
// Step 2: pick model within provider
|
|
270
|
-
const providerName = providerChoice.replace(/ \(\d+ models?\)$/, "");
|
|
307
|
+
const providerName = displayToReal.get(providerChoice) ?? providerChoice.replace(/ \(\d+ models?\)$/, "");
|
|
271
308
|
const group = byProvider.get(providerName);
|
|
272
309
|
if (!group)
|
|
273
310
|
continue;
|
|
274
311
|
const modelOptions = group.map(m => m.id);
|
|
275
312
|
modelOptions.push("(keep current)", "(clear)");
|
|
276
|
-
const modelChoice = await ctx.ui.select(`${phaseLabel} — ${providerName}:`, modelOptions);
|
|
313
|
+
const modelChoice = await ctx.ui.select(`${phaseLabel} — ${displayName(providerName)}:`, modelOptions);
|
|
277
314
|
if (modelChoice && typeof modelChoice === "string" && modelChoice !== "(keep current)") {
|
|
278
315
|
if (modelChoice === "(clear)") {
|
|
279
316
|
delete models[phase];
|
|
280
317
|
}
|
|
281
318
|
else {
|
|
282
|
-
models[phase] = modelChoice;
|
|
319
|
+
models[phase] = toPersistedModelId(providerName, modelChoice);
|
|
283
320
|
}
|
|
284
321
|
}
|
|
285
322
|
}
|
|
286
323
|
}
|
|
287
324
|
else {
|
|
288
325
|
for (const phase of modelPhases) {
|
|
289
|
-
const current = models[phase]
|
|
326
|
+
const current = formatConfiguredModel(models[phase]);
|
|
290
327
|
const input = await ctx.ui.input(`Model for ${phase} phase${current ? ` (current: ${current})` : ""}:`, current || "e.g. claude-sonnet-4-20250514");
|
|
291
328
|
if (input !== null && input !== undefined) {
|
|
292
329
|
const val = input.trim();
|
|
@@ -302,6 +339,9 @@ async function configureModels(ctx, prefs) {
|
|
|
302
339
|
if (Object.keys(models).length > 0) {
|
|
303
340
|
prefs.models = models;
|
|
304
341
|
}
|
|
342
|
+
else {
|
|
343
|
+
delete prefs.models;
|
|
344
|
+
}
|
|
305
345
|
}
|
|
306
346
|
async function configureTimeouts(ctx, prefs) {
|
|
307
347
|
const autoSup = prefs.auto_supervisor ?? {};
|
|
@@ -49,7 +49,8 @@ export function queryDecisions(opts) {
|
|
|
49
49
|
}
|
|
50
50
|
/**
|
|
51
51
|
* Query active (non-superseded) requirements with optional filters.
|
|
52
|
-
* -
|
|
52
|
+
* - milestoneId: combined with sliceId for precise filtering (e.g. %M005/S01%)
|
|
53
|
+
* - sliceId: filters where primary_owner LIKE '%pattern%' OR supporting_slices LIKE '%pattern%'
|
|
53
54
|
* - status: filters where status = :status (exact match)
|
|
54
55
|
*
|
|
55
56
|
* Returns [] if DB is not available. Never throws.
|
|
@@ -63,10 +64,22 @@ export function queryRequirements(opts) {
|
|
|
63
64
|
try {
|
|
64
65
|
const clauses = ['superseded_by IS NULL'];
|
|
65
66
|
const params = {};
|
|
66
|
-
|
|
67
|
+
// Combined milestone+slice filtering for precise scoping
|
|
68
|
+
if (opts?.milestoneId && opts?.sliceId) {
|
|
69
|
+
// Use combined pattern like %M005/S01% to avoid cross-milestone contamination
|
|
70
|
+
clauses.push('(primary_owner LIKE :combined_pattern OR supporting_slices LIKE :combined_pattern)');
|
|
71
|
+
params[':combined_pattern'] = `%${opts.milestoneId}/${opts.sliceId}%`;
|
|
72
|
+
}
|
|
73
|
+
else if (opts?.sliceId) {
|
|
74
|
+
// Slice-only filtering (legacy behavior)
|
|
67
75
|
clauses.push('(primary_owner LIKE :slice_pattern OR supporting_slices LIKE :slice_pattern)');
|
|
68
76
|
params[':slice_pattern'] = `%${opts.sliceId}%`;
|
|
69
77
|
}
|
|
78
|
+
else if (opts?.milestoneId) {
|
|
79
|
+
// Milestone-only filtering
|
|
80
|
+
clauses.push('(primary_owner LIKE :milestone_pattern OR supporting_slices LIKE :milestone_pattern)');
|
|
81
|
+
params[':milestone_pattern'] = `%${opts.milestoneId}%`;
|
|
82
|
+
}
|
|
70
83
|
if (opts?.status) {
|
|
71
84
|
clauses.push('status = :status');
|
|
72
85
|
params[':status'] = opts.status;
|
|
@@ -164,3 +177,122 @@ export function queryArtifact(path) {
|
|
|
164
177
|
export function queryProject() {
|
|
165
178
|
return queryArtifact('PROJECT.md');
|
|
166
179
|
}
|
|
180
|
+
// ─── Knowledge Query ───────────────────────────────────────────────────────
|
|
181
|
+
/**
|
|
182
|
+
* Filter KNOWLEDGE.md sections by keyword matching.
|
|
183
|
+
* Uses H2 sections, matches keywords case-insensitively against:
|
|
184
|
+
* 1. Section header text
|
|
185
|
+
* 2. First paragraph of section content (up to first blank line or next heading)
|
|
186
|
+
*
|
|
187
|
+
* Per D020, returns empty string (not null) when no matches found.
|
|
188
|
+
* This signals "no relevant knowledge" vs "file not found".
|
|
189
|
+
*
|
|
190
|
+
* @param content - Full KNOWLEDGE.md content
|
|
191
|
+
* @param keywords - Keywords to match (case-insensitive)
|
|
192
|
+
* @returns Concatenated matching sections with H2 headers, or empty string
|
|
193
|
+
*/
|
|
194
|
+
export async function queryKnowledge(content, keywords) {
|
|
195
|
+
if (!content || keywords.length === 0)
|
|
196
|
+
return '';
|
|
197
|
+
// Lazy import to avoid circular dependency
|
|
198
|
+
const { extractAllSections } = await import('./files.js');
|
|
199
|
+
const sections = extractAllSections(content, 2);
|
|
200
|
+
if (sections.size === 0)
|
|
201
|
+
return '';
|
|
202
|
+
// Normalize keywords for case-insensitive matching
|
|
203
|
+
const normalizedKeywords = keywords.map(k => k.toLowerCase());
|
|
204
|
+
const matchingSections = [];
|
|
205
|
+
for (const [header, body] of sections) {
|
|
206
|
+
// Extract first paragraph: everything up to first blank line or next heading
|
|
207
|
+
const firstParagraph = body.split(/\n\s*\n|\n#/)[0] || '';
|
|
208
|
+
// Check if any keyword matches header or first paragraph
|
|
209
|
+
const headerLower = header.toLowerCase();
|
|
210
|
+
const paragraphLower = firstParagraph.toLowerCase();
|
|
211
|
+
const matches = normalizedKeywords.some(kw => headerLower.includes(kw) || paragraphLower.includes(kw));
|
|
212
|
+
if (matches) {
|
|
213
|
+
matchingSections.push(`## ${header}\n\n${body}`);
|
|
214
|
+
}
|
|
215
|
+
}
|
|
216
|
+
return matchingSections.join('\n\n');
|
|
217
|
+
}
|
|
218
|
+
// ─── Roadmap Excerpt Formatter ─────────────────────────────────────────────
|
|
219
|
+
/**
|
|
220
|
+
* Format a minimal roadmap excerpt for prompt injection.
|
|
221
|
+
* Parses the slice table from roadmap content, extracts:
|
|
222
|
+
* 1. Header row + separator
|
|
223
|
+
* 2. Predecessor row (if sliceId depends on one via the Depends column)
|
|
224
|
+
* 3. Target slice row
|
|
225
|
+
* 4. Reference directive pointing to full roadmap path
|
|
226
|
+
*
|
|
227
|
+
* Per D021, this minimizes injected content while preserving dependency awareness.
|
|
228
|
+
* Returns empty string if sliceId is not found in the table.
|
|
229
|
+
* Never throws.
|
|
230
|
+
*
|
|
231
|
+
* @param roadmapContent - Full content of the M###-ROADMAP.md file
|
|
232
|
+
* @param sliceId - Target slice ID (e.g. 'S02')
|
|
233
|
+
* @param roadmapPath - Optional path for reference directive (defaults to generic)
|
|
234
|
+
*/
|
|
235
|
+
export function formatRoadmapExcerpt(roadmapContent, sliceId, roadmapPath = 'ROADMAP.md') {
|
|
236
|
+
if (!roadmapContent || !sliceId)
|
|
237
|
+
return '';
|
|
238
|
+
const lines = roadmapContent.split('\n');
|
|
239
|
+
// Find the slice table header: | ID | Slice | ... (case insensitive)
|
|
240
|
+
let headerIndex = -1;
|
|
241
|
+
for (let i = 0; i < lines.length; i++) {
|
|
242
|
+
const line = lines[i];
|
|
243
|
+
if (line && /^\s*\|\s*ID\s*\|\s*Slice\s*\|/i.test(line)) {
|
|
244
|
+
headerIndex = i;
|
|
245
|
+
break;
|
|
246
|
+
}
|
|
247
|
+
}
|
|
248
|
+
if (headerIndex === -1)
|
|
249
|
+
return '';
|
|
250
|
+
// The separator should be the next line (|---|---|...)
|
|
251
|
+
const separatorIndex = headerIndex + 1;
|
|
252
|
+
if (separatorIndex >= lines.length)
|
|
253
|
+
return '';
|
|
254
|
+
const headerLine = lines[headerIndex];
|
|
255
|
+
const separatorLine = lines[separatorIndex];
|
|
256
|
+
// Validate separator line looks like |---|---|... (may include : for alignment)
|
|
257
|
+
if (!separatorLine || !/^\s*\|[\s:\-|]+\|/.test(separatorLine))
|
|
258
|
+
return '';
|
|
259
|
+
const sliceRows = [];
|
|
260
|
+
for (let i = separatorIndex + 1; i < lines.length; i++) {
|
|
261
|
+
const line = lines[i];
|
|
262
|
+
if (!line || !line.trim().startsWith('|'))
|
|
263
|
+
break; // End of table
|
|
264
|
+
// Parse row: | ID | Slice | Risk | Depends | Done | After this |
|
|
265
|
+
const cells = line.split('|').map(c => c.trim());
|
|
266
|
+
// cells[0] is empty (before first |), cells[1] is ID, etc.
|
|
267
|
+
if (cells.length < 5)
|
|
268
|
+
continue;
|
|
269
|
+
const id = cells[1] || '';
|
|
270
|
+
const depends = cells[4] || ''; // Depends column (0-indexed: empty, ID, Slice, Risk, Depends, ...)
|
|
271
|
+
sliceRows.push({ line, id, depends });
|
|
272
|
+
}
|
|
273
|
+
// Find target slice row
|
|
274
|
+
const targetRow = sliceRows.find(r => r.id === sliceId);
|
|
275
|
+
if (!targetRow)
|
|
276
|
+
return '';
|
|
277
|
+
// Find predecessor if target depends on one
|
|
278
|
+
// Depends column may contain: '—', 'S01', 'S01, S02', etc.
|
|
279
|
+
let predecessorRow;
|
|
280
|
+
const dependsRaw = targetRow.depends;
|
|
281
|
+
if (dependsRaw && dependsRaw !== '—' && dependsRaw !== '-') {
|
|
282
|
+
// Extract first dependency (e.g. 'S01' from 'S01, S02')
|
|
283
|
+
const depMatch = dependsRaw.match(/S\d+/);
|
|
284
|
+
if (depMatch) {
|
|
285
|
+
predecessorRow = sliceRows.find(r => r.id === depMatch[0]);
|
|
286
|
+
}
|
|
287
|
+
}
|
|
288
|
+
// Build excerpt
|
|
289
|
+
const excerptLines = [headerLine, separatorLine];
|
|
290
|
+
if (predecessorRow) {
|
|
291
|
+
excerptLines.push(predecessorRow.line);
|
|
292
|
+
}
|
|
293
|
+
excerptLines.push(targetRow.line);
|
|
294
|
+
// Add reference directive
|
|
295
|
+
excerptLines.push('');
|
|
296
|
+
excerptLines.push(`> See full roadmap: ${roadmapPath}`);
|
|
297
|
+
return excerptLines.join('\n');
|
|
298
|
+
}
|
|
@@ -135,7 +135,9 @@ export class CustomWorkflowEngine {
|
|
|
135
135
|
* Returns "milestone-complete" when all steps are now done, "continue" otherwise.
|
|
136
136
|
*/
|
|
137
137
|
async reconcile(state, completedStep) {
|
|
138
|
-
|
|
138
|
+
// Re-read the graph from disk so we do not overwrite concurrent
|
|
139
|
+
// workflow edits with a stale in-memory snapshot from deriveState().
|
|
140
|
+
const graph = readGraph(this.runDir);
|
|
139
141
|
// Extract stepId from "<workflowName>/<stepId>"
|
|
140
142
|
const { milestone, slice, task } = parseUnitId(completedStep.unitId);
|
|
141
143
|
const stepId = task ?? slice ?? milestone;
|
|
@@ -170,6 +170,12 @@ const TEST_MARKERS = [
|
|
|
170
170
|
/** Directories skipped during bounded recursive project scans. */
|
|
171
171
|
const RECURSIVE_SCAN_IGNORED_DIRS = new Set([
|
|
172
172
|
".git",
|
|
173
|
+
".gsd",
|
|
174
|
+
".planning",
|
|
175
|
+
".plans",
|
|
176
|
+
".claude",
|
|
177
|
+
".cursor",
|
|
178
|
+
".vscode",
|
|
173
179
|
"node_modules",
|
|
174
180
|
".venv",
|
|
175
181
|
"venv",
|
|
@@ -104,6 +104,23 @@ export function extractAllSections(body, level = 2) {
|
|
|
104
104
|
function escapeRegex(s) {
|
|
105
105
|
return s.replace(/[.*+?^${}()|[\]\\]/g, '\\$&');
|
|
106
106
|
}
|
|
107
|
+
/**
|
|
108
|
+
* Normalize a task-plan file reference that may include inline description text
|
|
109
|
+
* after the path, for example:
|
|
110
|
+
* "docs/file.md — explanation"
|
|
111
|
+
* "docs/file.md - explanation"
|
|
112
|
+
*/
|
|
113
|
+
export function normalizePlannedFileReference(value) {
|
|
114
|
+
const trimmed = value.trim().replace(/`/g, "");
|
|
115
|
+
const match = /^(.*?)(?:\s+(?:—|-)\s+)(.+)$/.exec(trimmed);
|
|
116
|
+
if (!match)
|
|
117
|
+
return trimmed;
|
|
118
|
+
const pathCandidate = match[1].trim();
|
|
119
|
+
if (pathCandidate.includes("/") || pathCandidate.includes("\\") || pathCandidate.includes(".")) {
|
|
120
|
+
return pathCandidate;
|
|
121
|
+
}
|
|
122
|
+
return trimmed;
|
|
123
|
+
}
|
|
107
124
|
/** Parse bullet list items from a text block. */
|
|
108
125
|
export function parseBullets(text) {
|
|
109
126
|
return text.split('\n')
|
|
@@ -540,11 +557,11 @@ export function parseTaskPlanIO(content) {
|
|
|
540
557
|
let match;
|
|
541
558
|
backtickPathRegex.lastIndex = 0;
|
|
542
559
|
while ((match = backtickPathRegex.exec(trimmed)) !== null) {
|
|
543
|
-
const candidate = match[1];
|
|
560
|
+
const candidate = normalizePlannedFileReference(match[1]);
|
|
544
561
|
// Filter out things that look like code tokens rather than file paths
|
|
545
562
|
// (e.g. `true`, `false`, `npm run test`). A file path has at least one
|
|
546
563
|
// dot or slash.
|
|
547
|
-
if (candidate.includes("/") || candidate.includes(".")) {
|
|
564
|
+
if (candidate.includes("/") || candidate.includes("\\") || candidate.includes(".")) {
|
|
548
565
|
paths.push(candidate);
|
|
549
566
|
}
|
|
550
567
|
}
|
|
@@ -142,12 +142,13 @@ export function checkAutoStartAfterDiscuss() {
|
|
|
142
142
|
// Parse PROJECT.md for milestone sequence, warn if any are missing context.
|
|
143
143
|
// Don't block — milestones can be intentionally queued without context.
|
|
144
144
|
const projectFile = resolveGsdRootFile(basePath, "PROJECT");
|
|
145
|
+
let projectIds = [];
|
|
145
146
|
if (projectFile) {
|
|
146
147
|
try {
|
|
147
148
|
const projectContent = readFileSync(projectFile, "utf-8");
|
|
148
|
-
|
|
149
|
-
if (
|
|
150
|
-
const missing =
|
|
149
|
+
projectIds = parseMilestoneSequenceFromProject(projectContent);
|
|
150
|
+
if (projectIds.length > 1) {
|
|
151
|
+
const missing = projectIds.filter(id => {
|
|
151
152
|
const hasContext = !!resolveMilestoneFile(basePath, id, "CONTEXT");
|
|
152
153
|
const hasDraft = !!resolveMilestoneFile(basePath, id, "CONTEXT-DRAFT");
|
|
153
154
|
const hasDir = existsSync(join(gsdRoot(basePath), "milestones", id));
|
|
@@ -165,9 +166,14 @@ export function checkAutoStartAfterDiscuss() {
|
|
|
165
166
|
}
|
|
166
167
|
// Gate 4: Discussion manifest process verification (multi-milestone only)
|
|
167
168
|
// The LLM writes DISCUSSION-MANIFEST.json after each Phase 3 gate decision.
|
|
168
|
-
// If the
|
|
169
|
-
//
|
|
169
|
+
// If the project is multi-milestone, the manifest is required. When it is
|
|
170
|
+
// missing, fail closed instead of assuming the discussion finished.
|
|
170
171
|
const manifestPath = join(gsdRoot(basePath), "DISCUSSION-MANIFEST.json");
|
|
172
|
+
const requiresManifest = projectIds.length > 1 || findMilestoneIds(basePath).length > 1;
|
|
173
|
+
if (requiresManifest && !existsSync(manifestPath)) {
|
|
174
|
+
ctx.ui.notify("Multi-milestone discussion manifest is missing. Auto-start will remain paused until the manifest is written.", "warning");
|
|
175
|
+
return false;
|
|
176
|
+
}
|
|
171
177
|
if (existsSync(manifestPath)) {
|
|
172
178
|
try {
|
|
173
179
|
const manifest = JSON.parse(readFileSync(manifestPath, "utf-8"));
|
|
@@ -178,9 +184,7 @@ export function checkAutoStartAfterDiscuss() {
|
|
|
178
184
|
return false;
|
|
179
185
|
}
|
|
180
186
|
// Cross-check manifest milestones against PROJECT.md if available
|
|
181
|
-
if (
|
|
182
|
-
const projectContent = readFileSync(projectFile, "utf-8");
|
|
183
|
-
const projectIds = parseMilestoneSequenceFromProject(projectContent);
|
|
187
|
+
if (projectIds.length > 0) {
|
|
184
188
|
const manifestIds = Object.keys(manifest.milestones ?? {});
|
|
185
189
|
const untracked = projectIds.filter(id => !manifestIds.includes(id));
|
|
186
190
|
if (untracked.length > 0) {
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
export { isDepthConfirmationAnswer, isDepthVerified, isQueuePhaseActive, setQueuePhaseActive, shouldBlockContextWrite, shouldBlockQueueExecution, } from "./bootstrap/write-gate.js";
|
|
1
|
+
export { isDepthConfirmationAnswer, isDepthVerified, isGateQuestionId, isQueuePhaseActive, setQueuePhaseActive, shouldBlockContextWrite, shouldBlockPendingGate, shouldBlockPendingGateBash, shouldBlockQueueExecution, setPendingGate, clearPendingGate, getPendingGate, } from "./bootstrap/write-gate.js";
|
|
2
2
|
export default async function registerExtension(pi) {
|
|
3
3
|
const { registerGsdExtension } = await import("./bootstrap/register-extension.js");
|
|
4
4
|
registerGsdExtension(pi);
|
|
@@ -406,6 +406,8 @@ export class ParallelMonitorOverlay {
|
|
|
406
406
|
lines.push(t.fg("muted", " ESC/q to close │ ↑↓ scroll"));
|
|
407
407
|
// Apply scroll — use terminal rows as height estimate
|
|
408
408
|
const termHeight = process.stdout.rows || 40;
|
|
409
|
+
const maxScroll = Math.max(0, lines.length - termHeight);
|
|
410
|
+
this.scrollOffset = Math.min(Math.max(this.scrollOffset, 0), maxScroll);
|
|
409
411
|
const visible = lines.slice(this.scrollOffset, this.scrollOffset + termHeight);
|
|
410
412
|
this.cachedLines = visible;
|
|
411
413
|
return visible;
|
|
@@ -177,7 +177,9 @@ function _parsePlanImpl(content) {
|
|
|
177
177
|
for (const line of lines) {
|
|
178
178
|
const cbMatch = line.match(/^-\s+\[([ xX])\]\s+\*\*([\w.]+):\s+(.+?)\*\*\s*(.*)/);
|
|
179
179
|
// Heading-style: ### T01 -- Title, ### T01: Title, ### T01 — Title
|
|
180
|
-
const hdMatch = !cbMatch
|
|
180
|
+
const hdMatch = !cbMatch
|
|
181
|
+
? line.match(/^#{2,4}\s+([A-Z]+\d+(?:\.[A-Z]+\d+)*)\s*(?:--|—|:)\s*(.+)/)
|
|
182
|
+
: null;
|
|
181
183
|
if (cbMatch || hdMatch) {
|
|
182
184
|
const taskId = cbMatch ? cbMatch[2] : hdMatch[1];
|
|
183
185
|
// Skip tasks already found in the Tasks section
|
|
@@ -127,10 +127,12 @@ function loadPreferencesFile(path, scope) {
|
|
|
127
127
|
};
|
|
128
128
|
}
|
|
129
129
|
let _warnedUnrecognizedFormat = false;
|
|
130
|
+
let _warnedSectionParse = false;
|
|
130
131
|
/** @internal Reset the warn-once flags — exported for testing only. */
|
|
131
132
|
export function _resetParseWarningFlag() {
|
|
132
133
|
_warnedUnrecognizedFormat = false;
|
|
133
134
|
_warnedFrontmatterParse = false;
|
|
135
|
+
_warnedSectionParse = false;
|
|
134
136
|
}
|
|
135
137
|
/** @internal Exported for testing only */
|
|
136
138
|
export function parsePreferencesMarkdown(content) {
|
|
@@ -227,7 +229,10 @@ function parseHeadingListFormat(content) {
|
|
|
227
229
|
typed[targetSection] = value;
|
|
228
230
|
}
|
|
229
231
|
catch (e) {
|
|
230
|
-
|
|
232
|
+
if (!_warnedSectionParse) {
|
|
233
|
+
_warnedSectionParse = true;
|
|
234
|
+
logWarning("guided", `preferences section parse failed: ${e.message}`);
|
|
235
|
+
}
|
|
231
236
|
}
|
|
232
237
|
}
|
|
233
238
|
return typed;
|
|
@@ -63,6 +63,6 @@ Then:
|
|
|
63
63
|
13. Do not commit manually — the system auto-commits your changes after this unit completes.
|
|
64
64
|
- Say: "Milestone {{milestoneId}} complete."
|
|
65
65
|
|
|
66
|
-
**Important:** Do NOT skip the code change verification, success criteria, or definition of done verification (steps 3-5). The milestone summary must reflect actual verified outcomes, not assumed success. Verification failures BLOCK completion — there is no override. The milestone stays in its current state until issues are resolved and verification is re-run.
|
|
66
|
+
**Important:** Do NOT skip the code change verification, success criteria, or definition of done verification (steps 3-5). The milestone summary must reflect actual verified outcomes, not assumed success. Verification failures BLOCK completion — there is no override. The milestone stays in its current state until issues are resolved and verification is re-run. **If a verification tool itself fails, errors, or returns unexpected output, treat it as a verification failure** — never rationalize past a tool error ("tool didn't respond, assuming success" is forbidden). A tool that cannot verify is a tool that did not verify.
|
|
67
67
|
|
|
68
68
|
**File system safety:** When scanning milestone directories for evidence, use `ls` or `find` to list directory contents first — never pass a directory path (e.g. `tasks/`, `slices/`) directly to the `read` tool. The `read` tool only accepts file paths, not directories.
|
|
@@ -25,11 +25,11 @@ Then:
|
|
|
25
25
|
4. If the slice plan includes observability/diagnostic surfaces, confirm they work. Skip this for simple slices that don't have observability sections.
|
|
26
26
|
5. If the slice involved runtime behavior, fill the **Operational Readiness** section (Q8) in the slice summary: health signal, failure signal, recovery procedure, and monitoring gaps. Omit entirely for simple slices with no runtime concerns.
|
|
27
27
|
6. If this slice produced evidence that a requirement changed status (Active → Validated, Active → Deferred, etc.), call `gsd_requirement_update` with the requirement ID, updated `status`, and `validation` evidence. Do NOT write `.gsd/REQUIREMENTS.md` directly — the engine renders it from the database.
|
|
28
|
-
7.
|
|
29
|
-
8.
|
|
28
|
+
7. Prepare the slice completion content you will pass to `gsd_complete_slice` using the camelCase fields `milestoneId`, `sliceId`, `sliceTitle`, `oneLiner`, `narrative`, `verification`, and `uatContent`. Do **not** manually write `{{sliceSummaryPath}}`. Do **not** manually write `{{sliceUatPath}}` — the DB-backed tool is the canonical write path for both artifacts.
|
|
29
|
+
8. Draft the UAT content you will pass as `uatContent` — a concrete UAT script with real test cases derived from the slice plan and task summaries. Include preconditions, numbered steps with expected outcomes, and edge cases. This must NOT be a placeholder or generic template — tailor every test case to what this slice actually built.
|
|
30
30
|
9. Review task summaries for `key_decisions`. Append any significant decisions to `.gsd/DECISIONS.md` if missing.
|
|
31
31
|
10. Review task summaries for patterns, gotchas, or non-obvious lessons learned. If any would save future agents from repeating investigation or hitting the same issues, append them to `.gsd/KNOWLEDGE.md`. Only add entries that are genuinely useful — don't pad with obvious observations.
|
|
32
|
-
11. Call `gsd_complete_slice` with milestoneId
|
|
32
|
+
11. Call `gsd_complete_slice` with the camelCase fields `milestoneId`, `sliceId`, `sliceTitle`, `oneLiner`, `narrative`, `verification`, and `uatContent`, plus any optional enrichment fields you have. Do NOT manually mark the roadmap checkbox — the tool writes to the DB, renders `{{sliceSummaryPath}}` and `{{sliceUatPath}}`, and updates the ROADMAP.md projection automatically.
|
|
33
33
|
12. Do not run git commands — the system commits your changes and handles any merge after this unit succeeds.
|
|
34
34
|
13. Update `.gsd/PROJECT.md` if it exists — refresh current state if needed: use the `write` tool with `path: ".gsd/PROJECT.md"` and `content` containing the full updated document reflecting current project state. Do NOT use the `edit` tool for this — PROJECT.md is a full-document refresh.
|
|
35
35
|
|