gsd-pi 2.59.0 → 2.60.0-dev.2580e65
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/resources/extensions/ask-user-questions.js +7 -4
- package/dist/resources/extensions/gsd/auto/phases.js +62 -1
- package/dist/resources/extensions/gsd/auto-dashboard.js +21 -8
- package/dist/resources/extensions/gsd/auto-dispatch.js +6 -3
- package/dist/resources/extensions/gsd/auto-model-selection.js +57 -3
- package/dist/resources/extensions/gsd/auto-post-unit.js +43 -3
- package/dist/resources/extensions/gsd/auto-prompts.js +49 -20
- package/dist/resources/extensions/gsd/auto-recovery.js +37 -18
- package/dist/resources/extensions/gsd/auto-start.js +9 -5
- package/dist/resources/extensions/gsd/auto-timers.js +11 -5
- package/dist/resources/extensions/gsd/auto-unit-closeout.js +5 -3
- package/dist/resources/extensions/gsd/auto-verification.js +3 -2
- package/dist/resources/extensions/gsd/auto-worktree.js +120 -55
- package/dist/resources/extensions/gsd/auto.js +39 -17
- package/dist/resources/extensions/gsd/bootstrap/agent-end-recovery.js +6 -3
- package/dist/resources/extensions/gsd/bootstrap/db-tools.js +72 -2
- package/dist/resources/extensions/gsd/bootstrap/dynamic-tools.js +4 -10
- package/dist/resources/extensions/gsd/bootstrap/journal-tools.js +2 -1
- package/dist/resources/extensions/gsd/bootstrap/register-hooks.js +58 -5
- package/dist/resources/extensions/gsd/bootstrap/system-context.js +11 -10
- package/dist/resources/extensions/gsd/captures.js +54 -1
- package/dist/resources/extensions/gsd/commands/catalog.js +2 -0
- package/dist/resources/extensions/gsd/commands-codebase.js +48 -21
- package/dist/resources/extensions/gsd/commands-inspect.js +2 -1
- package/dist/resources/extensions/gsd/commands-maintenance.js +32 -19
- package/dist/resources/extensions/gsd/complexity-classifier.js +9 -5
- package/dist/resources/extensions/gsd/context-masker.js +68 -0
- package/dist/resources/extensions/gsd/custom-verification.js +3 -2
- package/dist/resources/extensions/gsd/docs/preferences-reference.md +7 -0
- package/dist/resources/extensions/gsd/gsd-db.js +35 -15
- package/dist/resources/extensions/gsd/guided-flow.js +19 -9
- package/dist/resources/extensions/gsd/init-wizard.js +12 -0
- package/dist/resources/extensions/gsd/markdown-renderer.js +11 -9
- package/dist/resources/extensions/gsd/md-importer.js +5 -4
- package/dist/resources/extensions/gsd/milestone-actions.js +3 -2
- package/dist/resources/extensions/gsd/milestone-ids.js +2 -1
- package/dist/resources/extensions/gsd/model-router.js +199 -45
- package/dist/resources/extensions/gsd/parallel-merge.js +5 -3
- package/dist/resources/extensions/gsd/parallel-orchestrator.js +26 -14
- package/dist/resources/extensions/gsd/phase-anchor.js +56 -0
- package/dist/resources/extensions/gsd/preferences-types.js +2 -0
- package/dist/resources/extensions/gsd/preferences-validation.js +91 -0
- package/dist/resources/extensions/gsd/preferences.js +15 -3
- package/dist/resources/extensions/gsd/prompt-loader.js +3 -2
- package/dist/resources/extensions/gsd/prompts/execute-task.md +2 -0
- package/dist/resources/extensions/gsd/prompts/rethink.md +7 -0
- package/dist/resources/extensions/gsd/prompts/triage-captures.md +6 -1
- package/dist/resources/extensions/gsd/rethink.js +5 -2
- package/dist/resources/extensions/gsd/rule-registry.js +7 -6
- package/dist/resources/extensions/gsd/safe-fs.js +6 -8
- package/dist/resources/extensions/gsd/state.js +1 -1
- package/dist/resources/extensions/gsd/status-guards.js +4 -3
- package/dist/resources/extensions/gsd/tools/complete-milestone.js +3 -2
- package/dist/resources/extensions/gsd/tools/complete-slice.js +3 -2
- package/dist/resources/extensions/gsd/tools/complete-task.js +3 -2
- package/dist/resources/extensions/gsd/tools/plan-milestone.js +3 -2
- package/dist/resources/extensions/gsd/tools/plan-slice.js +3 -2
- package/dist/resources/extensions/gsd/tools/plan-task.js +2 -1
- package/dist/resources/extensions/gsd/tools/reassess-roadmap.js +4 -4
- package/dist/resources/extensions/gsd/tools/reopen-slice.js +2 -1
- package/dist/resources/extensions/gsd/tools/reopen-task.js +2 -1
- package/dist/resources/extensions/gsd/tools/replan-slice.js +2 -1
- package/dist/resources/extensions/gsd/tools/validate-milestone.js +2 -1
- package/dist/resources/extensions/gsd/triage-resolution.js +135 -1
- package/dist/resources/extensions/gsd/triage-ui.js +12 -3
- package/dist/resources/extensions/gsd/workflow-events.js +2 -1
- package/dist/resources/extensions/gsd/workflow-logger.js +37 -4
- package/dist/resources/extensions/gsd/workflow-migration.js +14 -12
- package/dist/resources/extensions/gsd/workflow-projections.js +2 -2
- package/dist/resources/extensions/gsd/workflow-reconcile.js +2 -2
- package/dist/resources/extensions/gsd/worktree-manager.js +26 -14
- package/dist/resources/extensions/shared/interview-ui.js +3 -1
- package/dist/resources/skills/btw/SKILL.md +42 -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/required-server-files.json +3 -3
- package/dist/web/standalone/.next/server/app/_global-error/page.js +3 -3
- package/dist/web/standalone/.next/server/app/_global-error/page_client-reference-manifest.js +1 -1
- package/dist/web/standalone/.next/server/app/_global-error.html +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/page.js +2 -2
- package/dist/web/standalone/.next/server/app/_not-found/page_client-reference-manifest.js +1 -1
- package/dist/web/standalone/.next/server/app/_not-found.html +1 -1
- package/dist/web/standalone/.next/server/app/_not-found.rsc +3 -3
- package/dist/web/standalone/.next/server/app/_not-found.segments/_full.segment.rsc +3 -3
- 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 +3 -3
- 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/boot/route.js +1 -1
- package/dist/web/standalone/.next/server/app/api/boot/route_client-reference-manifest.js +1 -1
- package/dist/web/standalone/.next/server/app/api/bridge-terminal/input/route.js +1 -1
- package/dist/web/standalone/.next/server/app/api/bridge-terminal/input/route_client-reference-manifest.js +1 -1
- package/dist/web/standalone/.next/server/app/api/bridge-terminal/resize/route.js +1 -1
- package/dist/web/standalone/.next/server/app/api/bridge-terminal/resize/route_client-reference-manifest.js +1 -1
- package/dist/web/standalone/.next/server/app/api/bridge-terminal/stream/route.js +2 -2
- package/dist/web/standalone/.next/server/app/api/bridge-terminal/stream/route_client-reference-manifest.js +1 -1
- package/dist/web/standalone/.next/server/app/api/browse-directories/route.js +1 -1
- package/dist/web/standalone/.next/server/app/api/browse-directories/route_client-reference-manifest.js +1 -1
- package/dist/web/standalone/.next/server/app/api/captures/route.js +1 -1
- package/dist/web/standalone/.next/server/app/api/captures/route_client-reference-manifest.js +1 -1
- package/dist/web/standalone/.next/server/app/api/cleanup/route.js +1 -1
- package/dist/web/standalone/.next/server/app/api/cleanup/route_client-reference-manifest.js +1 -1
- package/dist/web/standalone/.next/server/app/api/dev-mode/route.js +1 -1
- package/dist/web/standalone/.next/server/app/api/dev-mode/route_client-reference-manifest.js +1 -1
- package/dist/web/standalone/.next/server/app/api/doctor/route.js +1 -1
- package/dist/web/standalone/.next/server/app/api/doctor/route_client-reference-manifest.js +1 -1
- package/dist/web/standalone/.next/server/app/api/experimental/route.js +2 -2
- package/dist/web/standalone/.next/server/app/api/experimental/route_client-reference-manifest.js +1 -1
- package/dist/web/standalone/.next/server/app/api/export-data/route.js +1 -1
- package/dist/web/standalone/.next/server/app/api/export-data/route_client-reference-manifest.js +1 -1
- package/dist/web/standalone/.next/server/app/api/files/route.js +1 -1
- package/dist/web/standalone/.next/server/app/api/files/route_client-reference-manifest.js +1 -1
- package/dist/web/standalone/.next/server/app/api/forensics/route.js +1 -1
- package/dist/web/standalone/.next/server/app/api/forensics/route_client-reference-manifest.js +1 -1
- package/dist/web/standalone/.next/server/app/api/git/route.js +1 -1
- package/dist/web/standalone/.next/server/app/api/git/route_client-reference-manifest.js +1 -1
- package/dist/web/standalone/.next/server/app/api/history/route.js +1 -1
- package/dist/web/standalone/.next/server/app/api/history/route_client-reference-manifest.js +1 -1
- package/dist/web/standalone/.next/server/app/api/hooks/route.js +1 -1
- package/dist/web/standalone/.next/server/app/api/hooks/route_client-reference-manifest.js +1 -1
- package/dist/web/standalone/.next/server/app/api/inspect/route.js +1 -1
- package/dist/web/standalone/.next/server/app/api/inspect/route_client-reference-manifest.js +1 -1
- package/dist/web/standalone/.next/server/app/api/knowledge/route.js +1 -1
- package/dist/web/standalone/.next/server/app/api/knowledge/route_client-reference-manifest.js +1 -1
- package/dist/web/standalone/.next/server/app/api/live-state/route.js +1 -1
- package/dist/web/standalone/.next/server/app/api/live-state/route_client-reference-manifest.js +1 -1
- package/dist/web/standalone/.next/server/app/api/onboarding/route.js +1 -1
- package/dist/web/standalone/.next/server/app/api/onboarding/route_client-reference-manifest.js +1 -1
- package/dist/web/standalone/.next/server/app/api/preferences/route.js +1 -1
- package/dist/web/standalone/.next/server/app/api/preferences/route_client-reference-manifest.js +1 -1
- package/dist/web/standalone/.next/server/app/api/projects/route.js +1 -1
- package/dist/web/standalone/.next/server/app/api/projects/route_client-reference-manifest.js +1 -1
- package/dist/web/standalone/.next/server/app/api/recovery/route.js +1 -1
- package/dist/web/standalone/.next/server/app/api/recovery/route_client-reference-manifest.js +1 -1
- package/dist/web/standalone/.next/server/app/api/remote-questions/route.js +2 -2
- package/dist/web/standalone/.next/server/app/api/remote-questions/route_client-reference-manifest.js +1 -1
- package/dist/web/standalone/.next/server/app/api/session/browser/route.js +1 -1
- package/dist/web/standalone/.next/server/app/api/session/browser/route_client-reference-manifest.js +1 -1
- package/dist/web/standalone/.next/server/app/api/session/command/route.js +1 -1
- package/dist/web/standalone/.next/server/app/api/session/command/route_client-reference-manifest.js +1 -1
- package/dist/web/standalone/.next/server/app/api/session/events/route.js +2 -2
- package/dist/web/standalone/.next/server/app/api/session/events/route_client-reference-manifest.js +1 -1
- package/dist/web/standalone/.next/server/app/api/session/manage/route.js +1 -1
- package/dist/web/standalone/.next/server/app/api/session/manage/route_client-reference-manifest.js +1 -1
- package/dist/web/standalone/.next/server/app/api/settings-data/route.js +1 -1
- package/dist/web/standalone/.next/server/app/api/settings-data/route_client-reference-manifest.js +1 -1
- package/dist/web/standalone/.next/server/app/api/shutdown/route.js +1 -1
- package/dist/web/standalone/.next/server/app/api/shutdown/route_client-reference-manifest.js +1 -1
- package/dist/web/standalone/.next/server/app/api/skill-health/route.js +1 -1
- package/dist/web/standalone/.next/server/app/api/skill-health/route_client-reference-manifest.js +1 -1
- package/dist/web/standalone/.next/server/app/api/steer/route.js +1 -1
- package/dist/web/standalone/.next/server/app/api/steer/route_client-reference-manifest.js +1 -1
- package/dist/web/standalone/.next/server/app/api/switch-root/route.js +1 -1
- package/dist/web/standalone/.next/server/app/api/switch-root/route_client-reference-manifest.js +1 -1
- package/dist/web/standalone/.next/server/app/api/terminal/input/route.js +2 -2
- package/dist/web/standalone/.next/server/app/api/terminal/input/route_client-reference-manifest.js +1 -1
- package/dist/web/standalone/.next/server/app/api/terminal/resize/route.js +2 -2
- package/dist/web/standalone/.next/server/app/api/terminal/resize/route_client-reference-manifest.js +1 -1
- package/dist/web/standalone/.next/server/app/api/terminal/sessions/route.js +2 -2
- package/dist/web/standalone/.next/server/app/api/terminal/sessions/route_client-reference-manifest.js +1 -1
- package/dist/web/standalone/.next/server/app/api/terminal/stream/route.js +4 -4
- package/dist/web/standalone/.next/server/app/api/terminal/stream/route_client-reference-manifest.js +1 -1
- package/dist/web/standalone/.next/server/app/api/terminal/upload/route.js +1 -1
- package/dist/web/standalone/.next/server/app/api/terminal/upload/route_client-reference-manifest.js +1 -1
- package/dist/web/standalone/.next/server/app/api/undo/route.js +1 -1
- package/dist/web/standalone/.next/server/app/api/undo/route_client-reference-manifest.js +1 -1
- package/dist/web/standalone/.next/server/app/api/update/route.js +1 -1
- package/dist/web/standalone/.next/server/app/api/update/route_client-reference-manifest.js +1 -1
- package/dist/web/standalone/.next/server/app/api/visualizer/route.js +1 -1
- package/dist/web/standalone/.next/server/app/api/visualizer/route_client-reference-manifest.js +1 -1
- package/dist/web/standalone/.next/server/app/index.html +1 -1
- package/dist/web/standalone/.next/server/app/index.rsc +4 -4
- package/dist/web/standalone/.next/server/app/index.segments/__PAGE__.segment.rsc +2 -2
- package/dist/web/standalone/.next/server/app/index.segments/_full.segment.rsc +4 -4
- 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 +3 -3
- package/dist/web/standalone/.next/server/app/index.segments/_tree.segment.rsc +1 -1
- package/dist/web/standalone/.next/server/app/page.js +2 -2
- package/dist/web/standalone/.next/server/app/page_client-reference-manifest.js +1 -1
- package/dist/web/standalone/.next/server/app-paths-manifest.json +17 -17
- package/dist/web/standalone/.next/server/chunks/2229.js +1 -1
- package/dist/web/standalone/.next/server/chunks/7471.js +3 -3
- package/dist/web/standalone/.next/server/middleware-build-manifest.js +1 -1
- package/dist/web/standalone/.next/server/middleware.js +2 -2
- package/dist/web/standalone/.next/server/next-font-manifest.js +1 -1
- package/dist/web/standalone/.next/server/next-font-manifest.json +1 -1
- package/dist/web/standalone/.next/server/pages/404.html +1 -1
- package/dist/web/standalone/.next/server/pages/500.html +2 -2
- package/dist/web/standalone/.next/server/server-reference-manifest.json +1 -1
- package/dist/web/standalone/.next/static/chunks/app/_not-found/{page-2f24283c162b6ab3.js → page-f2a7482d42a5614b.js} +1 -1
- package/dist/web/standalone/.next/static/chunks/app/{layout-9ecfd95f343793f0.js → layout-a16c7a7ecdf0c2cf.js} +1 -1
- package/dist/web/standalone/.next/static/chunks/app/page-0c485498795110d6.js +1 -0
- package/dist/web/standalone/.next/static/chunks/main-app-fdab67f7802d7832.js +1 -0
- package/dist/web/standalone/.next/static/chunks/next/dist/client/components/builtin/global-error-459824ffb8c323dd.js +1 -0
- package/dist/web/standalone/node_modules/node-pty/build/Makefile +2 -2
- package/dist/web/standalone/node_modules/node-pty/build/Release/pty.node +0 -0
- package/dist/web/standalone/node_modules/node-pty/build/pty.target.mk +14 -14
- package/dist/web/standalone/node_modules/node-pty/node-addon-api/node_addon_api.target.mk +14 -14
- package/dist/web/standalone/node_modules/node-pty/node-addon-api/node_addon_api_except.target.mk +14 -14
- package/dist/web/standalone/node_modules/node-pty/node-addon-api/node_addon_api_maybe.target.mk +14 -14
- package/dist/web/standalone/server.js +1 -1
- package/package.json +1 -1
- package/packages/pi-coding-agent/dist/core/extensions/loader.d.ts.map +1 -1
- package/packages/pi-coding-agent/dist/core/extensions/loader.js +5 -0
- package/packages/pi-coding-agent/dist/core/extensions/loader.js.map +1 -1
- package/packages/pi-coding-agent/dist/core/extensions/runner.d.ts +2 -1
- package/packages/pi-coding-agent/dist/core/extensions/runner.d.ts.map +1 -1
- package/packages/pi-coding-agent/dist/core/extensions/runner.js +16 -0
- package/packages/pi-coding-agent/dist/core/extensions/runner.js.map +1 -1
- package/packages/pi-coding-agent/dist/core/extensions/types.d.ts +26 -0
- package/packages/pi-coding-agent/dist/core/extensions/types.d.ts.map +1 -1
- package/packages/pi-coding-agent/dist/core/extensions/types.js.map +1 -1
- package/packages/pi-coding-agent/dist/core/lsp/config.d.ts.map +1 -1
- package/packages/pi-coding-agent/dist/core/lsp/config.js +6 -1
- package/packages/pi-coding-agent/dist/core/lsp/config.js.map +1 -1
- package/packages/pi-coding-agent/dist/core/lsp/defaults.json +2 -2
- package/packages/pi-coding-agent/dist/core/lsp/lsp-legacy-alias.test.d.ts +2 -0
- package/packages/pi-coding-agent/dist/core/lsp/lsp-legacy-alias.test.d.ts.map +1 -0
- package/packages/pi-coding-agent/dist/core/lsp/lsp-legacy-alias.test.js +47 -0
- package/packages/pi-coding-agent/dist/core/lsp/lsp-legacy-alias.test.js.map +1 -0
- package/packages/pi-coding-agent/dist/modes/interactive/controllers/input-controller.d.ts +1 -0
- package/packages/pi-coding-agent/dist/modes/interactive/controllers/input-controller.d.ts.map +1 -1
- package/packages/pi-coding-agent/dist/modes/interactive/controllers/input-controller.js +6 -0
- 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.d.ts +2 -0
- package/packages/pi-coding-agent/dist/modes/interactive/controllers/input-controller.test.d.ts.map +1 -0
- package/packages/pi-coding-agent/dist/modes/interactive/controllers/input-controller.test.js +122 -0
- package/packages/pi-coding-agent/dist/modes/interactive/controllers/input-controller.test.js.map +1 -0
- package/packages/pi-coding-agent/dist/modes/interactive/interactive-mode.d.ts +1 -0
- 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 +30 -0
- package/packages/pi-coding-agent/dist/modes/interactive/interactive-mode.js.map +1 -1
- package/packages/pi-coding-agent/dist/modes/interactive/slash-command-handlers.d.ts.map +1 -1
- package/packages/pi-coding-agent/dist/modes/interactive/slash-command-handlers.js +1 -7
- package/packages/pi-coding-agent/dist/modes/interactive/slash-command-handlers.js.map +1 -1
- package/packages/pi-coding-agent/package.json +1 -1
- package/packages/pi-coding-agent/src/core/extensions/loader.ts +6 -0
- package/packages/pi-coding-agent/src/core/extensions/runner.ts +19 -0
- package/packages/pi-coding-agent/src/core/extensions/types.ts +26 -0
- package/packages/pi-coding-agent/src/core/lsp/config.ts +7 -1
- package/packages/pi-coding-agent/src/core/lsp/defaults.json +2 -2
- package/packages/pi-coding-agent/src/core/lsp/lsp-legacy-alias.test.ts +70 -0
- package/packages/pi-coding-agent/src/modes/interactive/controllers/input-controller.test.ts +156 -0
- package/packages/pi-coding-agent/src/modes/interactive/controllers/input-controller.ts +7 -0
- package/packages/pi-coding-agent/src/modes/interactive/interactive-mode.ts +38 -0
- package/packages/pi-coding-agent/src/modes/interactive/slash-command-handlers.ts +1 -8
- package/pkg/package.json +1 -1
- package/src/resources/extensions/ask-user-questions.ts +7 -3
- package/src/resources/extensions/gsd/auto/phases.ts +70 -1
- package/src/resources/extensions/gsd/auto-dashboard.ts +22 -8
- package/src/resources/extensions/gsd/auto-dispatch.ts +7 -3
- package/src/resources/extensions/gsd/auto-model-selection.ts +77 -6
- package/src/resources/extensions/gsd/auto-post-unit.ts +52 -5
- package/src/resources/extensions/gsd/auto-prompts.ts +54 -20
- package/src/resources/extensions/gsd/auto-recovery.ts +38 -18
- package/src/resources/extensions/gsd/auto-start.ts +10 -9
- package/src/resources/extensions/gsd/auto-timers.ts +12 -5
- package/src/resources/extensions/gsd/auto-unit-closeout.ts +6 -2
- package/src/resources/extensions/gsd/auto-verification.ts +3 -6
- package/src/resources/extensions/gsd/auto-worktree.ts +121 -55
- package/src/resources/extensions/gsd/auto.ts +40 -17
- package/src/resources/extensions/gsd/bootstrap/agent-end-recovery.ts +4 -3
- package/src/resources/extensions/gsd/bootstrap/db-tools.ts +80 -2
- package/src/resources/extensions/gsd/bootstrap/dynamic-tools.ts +4 -16
- package/src/resources/extensions/gsd/bootstrap/journal-tools.ts +2 -1
- package/src/resources/extensions/gsd/bootstrap/register-hooks.ts +61 -4
- package/src/resources/extensions/gsd/bootstrap/system-context.ts +11 -10
- package/src/resources/extensions/gsd/captures.ts +71 -2
- package/src/resources/extensions/gsd/commands/catalog.ts +2 -0
- package/src/resources/extensions/gsd/commands-codebase.ts +52 -20
- package/src/resources/extensions/gsd/commands-inspect.ts +2 -1
- package/src/resources/extensions/gsd/commands-maintenance.ts +28 -19
- package/src/resources/extensions/gsd/complexity-classifier.ts +10 -5
- package/src/resources/extensions/gsd/context-masker.ts +74 -0
- package/src/resources/extensions/gsd/custom-verification.ts +3 -2
- package/src/resources/extensions/gsd/docs/preferences-reference.md +7 -0
- package/src/resources/extensions/gsd/gsd-db.ts +14 -16
- package/src/resources/extensions/gsd/guided-flow.ts +9 -8
- package/src/resources/extensions/gsd/init-wizard.ts +12 -0
- package/src/resources/extensions/gsd/markdown-renderer.ts +11 -17
- package/src/resources/extensions/gsd/md-importer.ts +5 -4
- package/src/resources/extensions/gsd/milestone-actions.ts +3 -2
- package/src/resources/extensions/gsd/milestone-ids.ts +2 -1
- package/src/resources/extensions/gsd/model-router.ts +245 -56
- package/src/resources/extensions/gsd/parallel-merge.ts +5 -3
- package/src/resources/extensions/gsd/parallel-orchestrator.ts +18 -14
- package/src/resources/extensions/gsd/phase-anchor.ts +71 -0
- package/src/resources/extensions/gsd/preferences-types.ts +22 -0
- package/src/resources/extensions/gsd/preferences-validation.ts +83 -0
- package/src/resources/extensions/gsd/preferences.ts +16 -3
- package/src/resources/extensions/gsd/prompt-loader.ts +3 -2
- package/src/resources/extensions/gsd/prompts/execute-task.md +2 -0
- package/src/resources/extensions/gsd/prompts/rethink.md +7 -0
- package/src/resources/extensions/gsd/prompts/triage-captures.md +6 -1
- package/src/resources/extensions/gsd/rethink.ts +5 -2
- package/src/resources/extensions/gsd/rule-registry.ts +7 -6
- package/src/resources/extensions/gsd/safe-fs.ts +6 -5
- package/src/resources/extensions/gsd/state.ts +1 -1
- package/src/resources/extensions/gsd/status-guards.ts +4 -3
- package/src/resources/extensions/gsd/tests/capability-router.test.ts +347 -0
- package/src/resources/extensions/gsd/tests/codebase-generator.test.ts +63 -0
- package/src/resources/extensions/gsd/tests/complexity-classifier.test.ts +27 -2
- package/src/resources/extensions/gsd/tests/context-masker.test.ts +122 -0
- package/src/resources/extensions/gsd/tests/db-path-worktree-symlink.test.ts +4 -4
- package/src/resources/extensions/gsd/tests/integration/state-machine-edge-cases.test.ts +1188 -0
- package/src/resources/extensions/gsd/tests/integration/state-machine-runtime-failures.test.ts +841 -0
- package/src/resources/extensions/gsd/tests/model-router.test.ts +488 -2
- package/src/resources/extensions/gsd/tests/phase-anchor.test.ts +83 -0
- package/src/resources/extensions/gsd/tests/preferences.test.ts +62 -0
- package/src/resources/extensions/gsd/tests/remote-questions.test.ts +21 -0
- package/src/resources/extensions/gsd/tests/silent-catch-diagnostics.test.ts +284 -0
- package/src/resources/extensions/gsd/tests/status-guards.test.ts +4 -0
- package/src/resources/extensions/gsd/tests/stop-backtrack.test.ts +216 -0
- package/src/resources/extensions/gsd/tests/tool-naming.test.ts +1 -1
- package/src/resources/extensions/gsd/tests/workflow-logger-audit.test.ts +120 -0
- package/src/resources/extensions/gsd/tests/workflow-logger.test.ts +6 -6
- package/src/resources/extensions/gsd/tools/complete-milestone.ts +3 -6
- package/src/resources/extensions/gsd/tools/complete-slice.ts +3 -6
- package/src/resources/extensions/gsd/tools/complete-task.ts +3 -6
- package/src/resources/extensions/gsd/tools/plan-milestone.ts +3 -6
- package/src/resources/extensions/gsd/tools/plan-slice.ts +3 -6
- package/src/resources/extensions/gsd/tools/plan-task.ts +2 -3
- package/src/resources/extensions/gsd/tools/reassess-roadmap.ts +4 -6
- package/src/resources/extensions/gsd/tools/reopen-slice.ts +2 -3
- package/src/resources/extensions/gsd/tools/reopen-task.ts +2 -3
- package/src/resources/extensions/gsd/tools/replan-slice.ts +2 -3
- package/src/resources/extensions/gsd/tools/validate-milestone.ts +2 -3
- package/src/resources/extensions/gsd/triage-resolution.ts +151 -1
- package/src/resources/extensions/gsd/triage-ui.ts +12 -3
- package/src/resources/extensions/gsd/types.ts +1 -0
- package/src/resources/extensions/gsd/workflow-events.ts +2 -1
- package/src/resources/extensions/gsd/workflow-logger.ts +52 -5
- package/src/resources/extensions/gsd/workflow-migration.ts +14 -12
- package/src/resources/extensions/gsd/workflow-projections.ts +2 -2
- package/src/resources/extensions/gsd/workflow-reconcile.ts +2 -2
- package/src/resources/extensions/gsd/worktree-manager.ts +16 -14
- package/src/resources/extensions/shared/interview-ui.ts +3 -1
- package/src/resources/extensions/shared/tests/interview-notes-loop.test.ts +144 -0
- package/src/resources/skills/btw/SKILL.md +42 -0
- package/dist/web/standalone/.next/static/chunks/app/page-62be3b5fa91e4c8f.js +0 -1
- package/dist/web/standalone/.next/static/chunks/main-app-d3d4c336195465f9.js +0 -1
- package/dist/web/standalone/.next/static/chunks/next/dist/client/components/builtin/global-error-ab5a8926e07ec673.js +0 -1
- /package/dist/web/standalone/.next/static/{DGvT_c5Vb7Wu3X-fEOVUU → ogyMN7M-3bGGuRY08L5HR}/_buildManifest.js +0 -0
- /package/dist/web/standalone/.next/static/{DGvT_c5Vb7Wu3X-fEOVUU → ogyMN7M-3bGGuRY08L5HR}/_ssgManifest.js +0 -0
|
@@ -8,6 +8,7 @@ export function setupEditorSubmitHandler(host: InteractiveModeStateHost & {
|
|
|
8
8
|
showError: (message: string) => void;
|
|
9
9
|
updateEditorBorderColor: () => void;
|
|
10
10
|
isExtensionCommand: (text: string) => boolean;
|
|
11
|
+
isKnownSlashCommand: (text: string) => boolean;
|
|
11
12
|
queueCompactionMessage: (text: string, mode: "steer" | "followUp") => void;
|
|
12
13
|
updatePendingMessagesDisplay: () => void;
|
|
13
14
|
flushPendingBashComponents: () => void;
|
|
@@ -23,6 +24,12 @@ export function setupEditorSubmitHandler(host: InteractiveModeStateHost & {
|
|
|
23
24
|
host.editor.setText("");
|
|
24
25
|
return;
|
|
25
26
|
}
|
|
27
|
+
if (!host.isKnownSlashCommand(text)) {
|
|
28
|
+
const command = text.split(/\s/)[0];
|
|
29
|
+
host.showError(`Unknown command: ${command}. Use slash autocomplete to see available commands.`);
|
|
30
|
+
host.editor.setText("");
|
|
31
|
+
return;
|
|
32
|
+
}
|
|
26
33
|
}
|
|
27
34
|
|
|
28
35
|
if (text.startsWith("!")) {
|
|
@@ -2371,6 +2371,12 @@ export class InteractiveMode {
|
|
|
2371
2371
|
const text = (this.editor.getExpandedText?.() ?? this.editor.getText()).trim();
|
|
2372
2372
|
if (!text) return;
|
|
2373
2373
|
|
|
2374
|
+
if (text.startsWith("/") && !this.isKnownSlashCommand(text)) {
|
|
2375
|
+
const command = text.split(/\s/)[0];
|
|
2376
|
+
this.showError(`Unknown command: ${command}. Use slash autocomplete to see available commands.`);
|
|
2377
|
+
return;
|
|
2378
|
+
}
|
|
2379
|
+
|
|
2374
2380
|
// Queue input during compaction (extension commands execute immediately)
|
|
2375
2381
|
if (this.session.isCompacting) {
|
|
2376
2382
|
if (this.isExtensionCommand(text)) {
|
|
@@ -2653,6 +2659,12 @@ export class InteractiveMode {
|
|
|
2653
2659
|
}
|
|
2654
2660
|
|
|
2655
2661
|
private queueCompactionMessage(text: string, mode: "steer" | "followUp"): void {
|
|
2662
|
+
if (text.startsWith("/") && !this.isKnownSlashCommand(text)) {
|
|
2663
|
+
const command = text.split(/\s/)[0];
|
|
2664
|
+
this.showError(`Unknown command: ${command}. Use slash autocomplete to see available commands.`);
|
|
2665
|
+
return;
|
|
2666
|
+
}
|
|
2667
|
+
|
|
2656
2668
|
this.compactionQueuedMessages.push({ text, mode });
|
|
2657
2669
|
this.editor.addToHistory?.(text);
|
|
2658
2670
|
this.editor.setText("");
|
|
@@ -2671,6 +2683,32 @@ export class InteractiveMode {
|
|
|
2671
2683
|
return !!extensionRunner.getCommand(commandName);
|
|
2672
2684
|
}
|
|
2673
2685
|
|
|
2686
|
+
private isKnownSlashCommand(text: string): boolean {
|
|
2687
|
+
if (!text.startsWith("/")) return false;
|
|
2688
|
+
|
|
2689
|
+
const spaceIndex = text.indexOf(" ");
|
|
2690
|
+
const commandName = spaceIndex === -1 ? text.slice(1) : text.slice(1, spaceIndex);
|
|
2691
|
+
|
|
2692
|
+
if (BUILTIN_SLASH_COMMANDS.some((command) => command.name === commandName)) {
|
|
2693
|
+
return true;
|
|
2694
|
+
}
|
|
2695
|
+
|
|
2696
|
+
if (this.isExtensionCommand(text)) {
|
|
2697
|
+
return true;
|
|
2698
|
+
}
|
|
2699
|
+
|
|
2700
|
+
if (this.session.promptTemplates.some((template) => template.name === commandName)) {
|
|
2701
|
+
return true;
|
|
2702
|
+
}
|
|
2703
|
+
|
|
2704
|
+
if (commandName.startsWith("skill:") && this.settingsManager.getEnableSkillCommands()) {
|
|
2705
|
+
const skillName = commandName.slice("skill:".length);
|
|
2706
|
+
return this.session.resourceLoader.getSkills().skills.some((skill) => skill.name === skillName);
|
|
2707
|
+
}
|
|
2708
|
+
|
|
2709
|
+
return false;
|
|
2710
|
+
}
|
|
2711
|
+
|
|
2674
2712
|
private async flushCompactionQueue(options?: { willRetry?: boolean }): Promise<void> {
|
|
2675
2713
|
if (this.compactionQueuedMessages.length === 0) {
|
|
2676
2714
|
return;
|
|
@@ -136,7 +136,7 @@ export async function dispatchSlashCommand(
|
|
|
136
136
|
await ctx.handleModelCommand(searchTerm);
|
|
137
137
|
return true;
|
|
138
138
|
}
|
|
139
|
-
if (text.startsWith("/export")) {
|
|
139
|
+
if (text === "/export" || text.startsWith("/export ")) {
|
|
140
140
|
await handleExportCommand(text, ctx);
|
|
141
141
|
return true;
|
|
142
142
|
}
|
|
@@ -236,13 +236,6 @@ export async function dispatchSlashCommand(
|
|
|
236
236
|
return true;
|
|
237
237
|
}
|
|
238
238
|
|
|
239
|
-
// If input starts with "/" but no command matched, show unknown command feedback
|
|
240
|
-
if (text.startsWith("/")) {
|
|
241
|
-
const command = text.split(/\s/)[0];
|
|
242
|
-
ctx.showError(`Unknown command: ${command}. Type /help for available commands.`);
|
|
243
|
-
return true;
|
|
244
|
-
}
|
|
245
|
-
|
|
246
239
|
return false;
|
|
247
240
|
}
|
|
248
241
|
|
package/pkg/package.json
CHANGED
|
@@ -135,10 +135,14 @@ export default function AskUserQuestions(pi: ExtensionAPI) {
|
|
|
135
135
|
}
|
|
136
136
|
}
|
|
137
137
|
|
|
138
|
+
// Try remote first if configured (works in both interactive and headless modes).
|
|
139
|
+
// tryRemoteQuestions returns null when no remote channel is configured, so
|
|
140
|
+
// this is a no-op when the user has not set up Slack/Discord/Telegram.
|
|
141
|
+
const { tryRemoteQuestions } = await import("./remote-questions/manager.js");
|
|
142
|
+
const remoteResult = await tryRemoteQuestions(params.questions, signal);
|
|
143
|
+
if (remoteResult) return { ...remoteResult, details: remoteResult.details as unknown };
|
|
144
|
+
|
|
138
145
|
if (!ctx.hasUI) {
|
|
139
|
-
const { tryRemoteQuestions } = await import("./remote-questions/manager.js");
|
|
140
|
-
const remoteResult = await tryRemoteQuestions(params.questions, signal);
|
|
141
|
-
if (remoteResult) return { ...remoteResult, details: remoteResult.details as unknown };
|
|
142
146
|
return errorResult("Error: UI not available (non-interactive mode)", params.questions);
|
|
143
147
|
}
|
|
144
148
|
|
|
@@ -709,7 +709,7 @@ export async function runDispatch(
|
|
|
709
709
|
// ─── runGuards ────────────────────────────────────────────────────────────────
|
|
710
710
|
|
|
711
711
|
/**
|
|
712
|
-
* Phase 2: Guards — budget ceiling, context window, secrets re-check.
|
|
712
|
+
* Phase 2: Guards — stop directives, budget ceiling, context window, secrets re-check.
|
|
713
713
|
* Returns break to exit the loop, or next to proceed to dispatch.
|
|
714
714
|
*/
|
|
715
715
|
export async function runGuards(
|
|
@@ -718,6 +718,55 @@ export async function runGuards(
|
|
|
718
718
|
): Promise<PhaseResult> {
|
|
719
719
|
const { ctx, pi, s, deps, prefs } = ic;
|
|
720
720
|
|
|
721
|
+
// ── Stop/Backtrack directive guard (#3487) ──
|
|
722
|
+
// Check for unexecuted stop or backtrack captures BEFORE dispatching any unit.
|
|
723
|
+
// This ensures user "halt" directives are honored immediately.
|
|
724
|
+
// IMPORTANT: Fail-closed — any exception during stop handling still breaks the loop
|
|
725
|
+
// to ensure user halt intent is never silently dropped.
|
|
726
|
+
try {
|
|
727
|
+
const { loadStopCaptures, markCaptureExecuted } = await import("../captures.js");
|
|
728
|
+
const stopCaptures = loadStopCaptures(s.basePath);
|
|
729
|
+
if (stopCaptures.length > 0) {
|
|
730
|
+
const first = stopCaptures[0];
|
|
731
|
+
const isBacktrack = first.classification === "backtrack";
|
|
732
|
+
const label = isBacktrack
|
|
733
|
+
? `Backtrack directive: ${first.text}`
|
|
734
|
+
: `Stop directive: ${first.text}`;
|
|
735
|
+
|
|
736
|
+
ctx.ui.notify(label, "warning");
|
|
737
|
+
deps.sendDesktopNotification(
|
|
738
|
+
"GSD", label, "warning", "stop-directive",
|
|
739
|
+
basename(s.originalBasePath || s.basePath),
|
|
740
|
+
);
|
|
741
|
+
|
|
742
|
+
// Pause first — ensures auto-mode stops even if later steps fail
|
|
743
|
+
await deps.pauseAuto(ctx, pi);
|
|
744
|
+
|
|
745
|
+
// For backtrack captures, write the backtrack trigger after pausing
|
|
746
|
+
if (isBacktrack) {
|
|
747
|
+
try {
|
|
748
|
+
const { executeBacktrack } = await import("../triage-resolution.js");
|
|
749
|
+
executeBacktrack(s.basePath, mid, first);
|
|
750
|
+
} catch (e) {
|
|
751
|
+
debugLog("guards", { phase: "backtrack-execution-error", error: String(e) });
|
|
752
|
+
}
|
|
753
|
+
}
|
|
754
|
+
|
|
755
|
+
// Mark captures as executed only after successful pause/transition
|
|
756
|
+
for (const cap of stopCaptures) {
|
|
757
|
+
markCaptureExecuted(s.basePath, cap.id);
|
|
758
|
+
}
|
|
759
|
+
|
|
760
|
+
debugLog("autoLoop", { phase: "exit", reason: isBacktrack ? "user-backtrack" : "user-stop" });
|
|
761
|
+
return { action: "break", reason: isBacktrack ? "user-backtrack" : "user-stop" };
|
|
762
|
+
}
|
|
763
|
+
} catch (e) {
|
|
764
|
+
// Fail-closed: if anything in the stop guard throws, break the loop
|
|
765
|
+
// rather than silently continuing and dropping user halt intent
|
|
766
|
+
debugLog("guards", { phase: "stop-guard-error", error: String(e) });
|
|
767
|
+
return { action: "break", reason: "stop-guard-error" };
|
|
768
|
+
}
|
|
769
|
+
|
|
721
770
|
// Budget ceiling guard
|
|
722
771
|
const budgetCeiling = prefs?.budget_ceiling;
|
|
723
772
|
if (budgetCeiling !== undefined && budgetCeiling > 0) {
|
|
@@ -1205,6 +1254,25 @@ export async function runUnitPhase(
|
|
|
1205
1254
|
s.unitRecoveryCount.delete(`${unitType}/${unitId}`);
|
|
1206
1255
|
}
|
|
1207
1256
|
|
|
1257
|
+
// Write phase handoff anchor after successful research/planning completion
|
|
1258
|
+
const anchorPhases = new Set(["research-milestone", "research-slice", "plan-milestone", "plan-slice"]);
|
|
1259
|
+
if (artifactVerified && mid && anchorPhases.has(unitType)) {
|
|
1260
|
+
try {
|
|
1261
|
+
const { writePhaseAnchor } = await import("../phase-anchor.js");
|
|
1262
|
+
writePhaseAnchor(s.basePath, mid, {
|
|
1263
|
+
phase: unitType,
|
|
1264
|
+
milestoneId: mid,
|
|
1265
|
+
generatedAt: new Date().toISOString(),
|
|
1266
|
+
intent: `Completed ${unitType} for ${unitId}`,
|
|
1267
|
+
decisions: [],
|
|
1268
|
+
blockers: [],
|
|
1269
|
+
nextSteps: [],
|
|
1270
|
+
});
|
|
1271
|
+
} catch (err) { /* non-fatal — anchor is advisory */
|
|
1272
|
+
logWarning("engine", `phase anchor failed: ${err instanceof Error ? err.message : String(err)}`);
|
|
1273
|
+
}
|
|
1274
|
+
}
|
|
1275
|
+
|
|
1208
1276
|
deps.emitJournalEvent({ ts: new Date().toISOString(), flowId: ic.flowId, seq: ic.nextSeq(), eventType: "unit-end", data: { unitType, unitId, status: unitResult.status, artifactVerified, ...(unitResult.errorContext ? { errorContext: unitResult.errorContext } : {}) }, causedBy: { flowId: ic.flowId, seq: unitStartSeq } });
|
|
1209
1277
|
|
|
1210
1278
|
return { action: "next", data: { unitStartedAt: s.currentUnit?.startedAt } };
|
|
@@ -1325,3 +1393,4 @@ export async function runFinalize(
|
|
|
1325
1393
|
|
|
1326
1394
|
return { action: "next", data: undefined as void };
|
|
1327
1395
|
}
|
|
1396
|
+
|
|
@@ -31,6 +31,7 @@ import {
|
|
|
31
31
|
getRtkSessionSavings,
|
|
32
32
|
type RtkSessionSavings,
|
|
33
33
|
} from "../shared/rtk-session-stats.js";
|
|
34
|
+
import { logWarning } from "./workflow-logger.js";
|
|
34
35
|
|
|
35
36
|
// ─── UAT Slice Extraction ─────────────────────────────────────────────────────
|
|
36
37
|
|
|
@@ -285,8 +286,9 @@ export function updateSliceProgressCache(base: string, mid: string, activeSid?:
|
|
|
285
286
|
taskDetails = dbTasks.map(t => ({ id: t.id, title: t.title, done: t.status === "complete" || t.status === "done" }));
|
|
286
287
|
}
|
|
287
288
|
}
|
|
288
|
-
} catch {
|
|
289
|
+
} catch (err) {
|
|
289
290
|
// Non-fatal — just omit task count
|
|
291
|
+
logWarning("dashboard", `operation failed: ${err instanceof Error ? err.message : String(err)}`);
|
|
290
292
|
}
|
|
291
293
|
}
|
|
292
294
|
|
|
@@ -297,8 +299,9 @@ export function updateSliceProgressCache(base: string, mid: string, activeSid?:
|
|
|
297
299
|
activeSliceTasks,
|
|
298
300
|
taskDetails,
|
|
299
301
|
};
|
|
300
|
-
} catch {
|
|
302
|
+
} catch (err) {
|
|
301
303
|
// Non-fatal — widget just won't show progress bar
|
|
304
|
+
logWarning("dashboard", `operation failed: ${err instanceof Error ? err.message : String(err)}`);
|
|
302
305
|
}
|
|
303
306
|
}
|
|
304
307
|
|
|
@@ -332,8 +335,9 @@ function refreshLastCommit(basePath: string): void {
|
|
|
332
335
|
};
|
|
333
336
|
}
|
|
334
337
|
lastCommitFetchedAt = Date.now();
|
|
335
|
-
} catch {
|
|
338
|
+
} catch (err) {
|
|
336
339
|
// Non-fatal — just skip last commit display
|
|
340
|
+
logWarning("dashboard", `operation failed: ${err instanceof Error ? err.message : String(err)}`);
|
|
337
341
|
}
|
|
338
342
|
}
|
|
339
343
|
|
|
@@ -376,7 +380,9 @@ function ensureWidgetModeLoaded(): void {
|
|
|
376
380
|
if (saved && WIDGET_MODES.includes(saved as WidgetMode)) {
|
|
377
381
|
widgetMode = saved as WidgetMode;
|
|
378
382
|
}
|
|
379
|
-
} catch { /* non-fatal — use default */
|
|
383
|
+
} catch (err) { /* non-fatal — use default */
|
|
384
|
+
logWarning("dashboard", `operation failed: ${err instanceof Error ? err.message : String(err)}`);
|
|
385
|
+
}
|
|
380
386
|
}
|
|
381
387
|
|
|
382
388
|
/** Persist widget mode to global preferences YAML. */
|
|
@@ -395,7 +401,9 @@ function persistWidgetMode(mode: WidgetMode): void {
|
|
|
395
401
|
content = content.trimEnd() + "\n" + line + "\n";
|
|
396
402
|
}
|
|
397
403
|
writeFileSync(prefsPath, content, "utf-8");
|
|
398
|
-
} catch { /* non-fatal — mode still set in memory */
|
|
404
|
+
} catch (err) { /* non-fatal — mode still set in memory */
|
|
405
|
+
logWarning("dashboard", `file write failed: ${err instanceof Error ? err.message : String(err)}`);
|
|
406
|
+
}
|
|
399
407
|
}
|
|
400
408
|
|
|
401
409
|
/** Cycle to the next widget mode. Returns the new mode. */
|
|
@@ -458,7 +466,9 @@ export function updateProgressWidget(
|
|
|
458
466
|
|
|
459
467
|
// Cache git branch at widget creation time (not per render)
|
|
460
468
|
let cachedBranch: string | null = null;
|
|
461
|
-
try { cachedBranch = getCurrentBranch(accessors.getBasePath()); } catch { /* not in git repo */
|
|
469
|
+
try { cachedBranch = getCurrentBranch(accessors.getBasePath()); } catch (err) { /* not in git repo */
|
|
470
|
+
logWarning("dashboard", `git branch detection failed: ${err instanceof Error ? err.message : String(err)}`);
|
|
471
|
+
}
|
|
462
472
|
|
|
463
473
|
// Cache short pwd (last 2 path segments only) + worktree/branch info
|
|
464
474
|
let widgetPwd: string;
|
|
@@ -495,7 +505,8 @@ export function updateProgressWidget(
|
|
|
495
505
|
const sessionId = ctx.sessionManager.getSessionId();
|
|
496
506
|
const savings = sessionId ? getRtkSessionSavings(accessors.getBasePath(), sessionId) : null;
|
|
497
507
|
cachedRtkLabel = formatRtkSavingsLabel(savings);
|
|
498
|
-
} catch {
|
|
508
|
+
} catch (err) {
|
|
509
|
+
logWarning("dashboard", `RTK savings lookup failed: ${err instanceof Error ? (err as Error).message : String(err)}`);
|
|
499
510
|
cachedRtkLabel = null;
|
|
500
511
|
}
|
|
501
512
|
};
|
|
@@ -519,7 +530,9 @@ export function updateProgressWidget(
|
|
|
519
530
|
}
|
|
520
531
|
refreshRtkLabel();
|
|
521
532
|
cachedLines = undefined;
|
|
522
|
-
} catch { /* non-fatal */
|
|
533
|
+
} catch (err) { /* non-fatal */
|
|
534
|
+
logWarning("dashboard", `DB status update failed: ${err instanceof Error ? err.message : String(err)}`);
|
|
535
|
+
}
|
|
523
536
|
}, 15_000);
|
|
524
537
|
|
|
525
538
|
return {
|
|
@@ -878,3 +891,4 @@ function padToWidth(s: string, colWidth: number): string {
|
|
|
878
891
|
if (vis >= colWidth) return truncateToWidth(s, colWidth, "…");
|
|
879
892
|
return s + " ".repeat(colWidth - vis);
|
|
880
893
|
}
|
|
894
|
+
|
|
@@ -28,7 +28,7 @@ import {
|
|
|
28
28
|
buildSliceFileName,
|
|
29
29
|
} from "./paths.js";
|
|
30
30
|
import { existsSync, mkdirSync, readFileSync, writeFileSync } from "node:fs";
|
|
31
|
-
import { logError } from "./workflow-logger.js";
|
|
31
|
+
import { logWarning, logError } from "./workflow-logger.js";
|
|
32
32
|
import { join } from "node:path";
|
|
33
33
|
import { hasImplementationArtifacts } from "./auto-recovery.js";
|
|
34
34
|
import {
|
|
@@ -712,7 +712,9 @@ export const DISPATCH_RULES: DispatchRule[] = [
|
|
|
712
712
|
}
|
|
713
713
|
}
|
|
714
714
|
}
|
|
715
|
-
} catch { /* fall through — don't block on DB errors */
|
|
715
|
+
} catch (err) { /* fall through — don't block on DB errors */
|
|
716
|
+
logWarning("dispatch", `verification class check failed: ${err instanceof Error ? err.message : String(err)}`);
|
|
717
|
+
}
|
|
716
718
|
|
|
717
719
|
return {
|
|
718
720
|
action: "dispatch",
|
|
@@ -754,8 +756,9 @@ export async function resolveDispatch(
|
|
|
754
756
|
try {
|
|
755
757
|
const registry = getRegistry();
|
|
756
758
|
return await registry.evaluateDispatch(ctx);
|
|
757
|
-
} catch {
|
|
759
|
+
} catch (err) {
|
|
758
760
|
// Registry not initialized — fall back to inline loop
|
|
761
|
+
logWarning("dispatch", `registry dispatch failed, falling back to inline rules: ${err instanceof Error ? err.message : String(err)}`);
|
|
759
762
|
}
|
|
760
763
|
|
|
761
764
|
for (const rule of DISPATCH_RULES) {
|
|
@@ -779,3 +782,4 @@ export async function resolveDispatch(
|
|
|
779
782
|
export function getDispatchRuleNames(): string[] {
|
|
780
783
|
return DISPATCH_RULES.map((r) => r.name);
|
|
781
784
|
}
|
|
785
|
+
|
|
@@ -10,7 +10,7 @@ import type { GSDPreferences } from "./preferences.js";
|
|
|
10
10
|
import { resolveModelWithFallbacksForUnit, resolveDynamicRoutingConfig } from "./preferences.js";
|
|
11
11
|
import type { ComplexityTier } from "./complexity-classifier.js";
|
|
12
12
|
import { classifyUnitComplexity, tierLabel } from "./complexity-classifier.js";
|
|
13
|
-
import { resolveModelForComplexity, escalateTier } from "./model-router.js";
|
|
13
|
+
import { resolveModelForComplexity, escalateTier, getEligibleModels, loadCapabilityOverrides } from "./model-router.js";
|
|
14
14
|
import { getLedger, getProjectTotals } from "./metrics.js";
|
|
15
15
|
import { unitPhaseLabel } from "./auto-dashboard.js";
|
|
16
16
|
|
|
@@ -107,7 +107,65 @@ export async function selectAndApplyModel(
|
|
|
107
107
|
}
|
|
108
108
|
}
|
|
109
109
|
|
|
110
|
-
|
|
110
|
+
// Load user capability overrides from preferences (D-17: deep-merged with built-in profiles)
|
|
111
|
+
const capabilityOverrides = loadCapabilityOverrides(
|
|
112
|
+
(prefs as { modelOverrides?: Record<string, { capabilities?: Record<string, number> }> } | undefined) ?? {},
|
|
113
|
+
);
|
|
114
|
+
|
|
115
|
+
// Fire before_model_select hook (ADR-004, D-03)
|
|
116
|
+
// Hook can override model selection entirely by returning { modelId }
|
|
117
|
+
let hookOverride: string | undefined;
|
|
118
|
+
if (routingConfig.hooks !== false) {
|
|
119
|
+
const eligible = getEligibleModels(
|
|
120
|
+
classification.tier,
|
|
121
|
+
availableModelIds,
|
|
122
|
+
routingConfig,
|
|
123
|
+
);
|
|
124
|
+
const hookResult = await pi.emitBeforeModelSelect({
|
|
125
|
+
unitType,
|
|
126
|
+
unitId,
|
|
127
|
+
classification: {
|
|
128
|
+
tier: classification.tier,
|
|
129
|
+
reason: classification.reason,
|
|
130
|
+
downgraded: classification.downgraded,
|
|
131
|
+
},
|
|
132
|
+
taskMetadata: classification.taskMetadata as Record<string, unknown> | undefined,
|
|
133
|
+
eligibleModels: eligible,
|
|
134
|
+
phaseConfig: modelConfig ? {
|
|
135
|
+
primary: modelConfig.primary,
|
|
136
|
+
fallbacks: modelConfig.fallbacks ?? [],
|
|
137
|
+
} : undefined,
|
|
138
|
+
});
|
|
139
|
+
if (hookResult?.modelId) {
|
|
140
|
+
hookOverride = hookResult.modelId;
|
|
141
|
+
}
|
|
142
|
+
}
|
|
143
|
+
|
|
144
|
+
let routingResult: ReturnType<typeof resolveModelForComplexity>;
|
|
145
|
+
if (hookOverride) {
|
|
146
|
+
// Hook override bypasses capability scoring entirely
|
|
147
|
+
routingResult = {
|
|
148
|
+
modelId: hookOverride,
|
|
149
|
+
fallbacks: [
|
|
150
|
+
...(modelConfig?.fallbacks ?? []).filter(f => f !== hookOverride),
|
|
151
|
+
...(modelConfig?.primary && modelConfig.primary !== hookOverride ? [modelConfig.primary] : []),
|
|
152
|
+
],
|
|
153
|
+
tier: classification.tier,
|
|
154
|
+
wasDowngraded: hookOverride !== modelConfig?.primary,
|
|
155
|
+
reason: `hook override: ${hookOverride}`,
|
|
156
|
+
selectionMethod: "tier-only",
|
|
157
|
+
};
|
|
158
|
+
} else {
|
|
159
|
+
routingResult = resolveModelForComplexity(
|
|
160
|
+
classification,
|
|
161
|
+
modelConfig,
|
|
162
|
+
routingConfig,
|
|
163
|
+
availableModelIds,
|
|
164
|
+
unitType,
|
|
165
|
+
classification.taskMetadata,
|
|
166
|
+
capabilityOverrides,
|
|
167
|
+
);
|
|
168
|
+
}
|
|
111
169
|
|
|
112
170
|
if (routingResult.wasDowngraded) {
|
|
113
171
|
effectiveModelConfig = {
|
|
@@ -115,10 +173,23 @@ export async function selectAndApplyModel(
|
|
|
115
173
|
fallbacks: routingResult.fallbacks,
|
|
116
174
|
};
|
|
117
175
|
if (verbose) {
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
176
|
+
if (routingResult.selectionMethod === "capability-scored" && routingResult.capabilityScores) {
|
|
177
|
+
// Verbose scoring breakdown for capability-scored decisions (D-20)
|
|
178
|
+
const tierLbl = tierLabel(classification.tier);
|
|
179
|
+
const scores = Object.entries(routingResult.capabilityScores)
|
|
180
|
+
.sort(([, a], [, b]) => b - a)
|
|
181
|
+
.map(([id, score]) => `${id}: ${score.toFixed(1)}`)
|
|
182
|
+
.join(", ");
|
|
183
|
+
ctx.ui.notify(
|
|
184
|
+
`Dynamic routing [${tierLbl}]: ${routingResult.modelId} (capability-scored) — ${scores}`,
|
|
185
|
+
"info",
|
|
186
|
+
);
|
|
187
|
+
} else {
|
|
188
|
+
ctx.ui.notify(
|
|
189
|
+
`Dynamic routing [${tierLabel(classification.tier)}]: ${routingResult.modelId} (${classification.reason})`,
|
|
190
|
+
"info",
|
|
191
|
+
);
|
|
192
|
+
}
|
|
122
193
|
}
|
|
123
194
|
}
|
|
124
195
|
routingTierLabel = ` [${tierLabel(classification.tier)}]`;
|
|
@@ -46,7 +46,7 @@ import {
|
|
|
46
46
|
persistHookState,
|
|
47
47
|
resolveHookArtifactPath,
|
|
48
48
|
} from "./post-unit-hooks.js";
|
|
49
|
-
import { hasPendingCaptures, loadPendingCaptures } from "./captures.js";
|
|
49
|
+
import { hasPendingCaptures, loadPendingCaptures, revertExecutorResolvedCaptures } from "./captures.js";
|
|
50
50
|
import { debugLog } from "./debug-logger.js";
|
|
51
51
|
import { runSafely } from "./auto-utils.js";
|
|
52
52
|
import type { AutoSession, SidecarItem } from "./auto/session.js";
|
|
@@ -279,8 +279,9 @@ export async function postUnitPreVerification(pctx: PostUnitContext, opts?: PreV
|
|
|
279
279
|
try {
|
|
280
280
|
const { getTaskIssueNumberForCommit } = await import("../github-sync/sync.js");
|
|
281
281
|
ghIssueNumber = getTaskIssueNumberForCommit(s.basePath, mid, sid, tid) ?? undefined;
|
|
282
|
-
} catch {
|
|
282
|
+
} catch (err) {
|
|
283
283
|
// GitHub sync not available — skip
|
|
284
|
+
logWarning("engine", `GitHub issue lookup failed: ${err instanceof Error ? err.message : String(err)}`);
|
|
284
285
|
}
|
|
285
286
|
|
|
286
287
|
taskContext = {
|
|
@@ -558,9 +559,7 @@ export async function postUnitPostVerification(pctx: PostUnitContext): Promise<"
|
|
|
558
559
|
} catch (dbErr) {
|
|
559
560
|
// DB unavailable — fail explicitly rather than silently reverting to markdown mutation.
|
|
560
561
|
// Use 'gsd recover' to rebuild DB state from disk if needed.
|
|
561
|
-
|
|
562
|
-
`gsd: retry state-reset failed (DB unavailable): ${(dbErr as Error).message}. Run 'gsd recover' to reconcile.\n`,
|
|
563
|
-
);
|
|
562
|
+
logError("engine", `retry state-reset failed (DB unavailable): ${(dbErr as Error).message}. Run 'gsd recover' to reconcile.`);
|
|
564
563
|
}
|
|
565
564
|
}
|
|
566
565
|
|
|
@@ -594,6 +593,53 @@ export async function postUnitPostVerification(pctx: PostUnitContext): Promise<"
|
|
|
594
593
|
}
|
|
595
594
|
}
|
|
596
595
|
|
|
596
|
+
// ── Fast-path stop detection (#3487) ──
|
|
597
|
+
// Before waiting for triage, check if any PENDING captures contain explicit
|
|
598
|
+
// stop/halt language. If so, pause immediately — don't wait for triage.
|
|
599
|
+
if (s.currentUnit && s.currentUnit.type !== "triage-captures") {
|
|
600
|
+
try {
|
|
601
|
+
const pending = loadPendingCaptures(s.basePath);
|
|
602
|
+
// Match only when the capture text starts with a stop/halt directive word,
|
|
603
|
+
// or the entire text is short and dominated by such a word. This avoids
|
|
604
|
+
// false positives on captures like "add a pause button" or "stop the timer
|
|
605
|
+
// from re-rendering" — those are feature descriptions, not halt directives.
|
|
606
|
+
const STOP_PATTERN = /^(stop|halt|abort|don'?t continue|pause|cease)\b/i;
|
|
607
|
+
const stopCapture = pending.find(c => STOP_PATTERN.test(c.text.trim()));
|
|
608
|
+
if (stopCapture) {
|
|
609
|
+
ctx.ui.notify(
|
|
610
|
+
`Stop directive detected in pending capture ${stopCapture.id}: "${stopCapture.text}" — pausing auto-mode.`,
|
|
611
|
+
"warning",
|
|
612
|
+
);
|
|
613
|
+
debugLog("postUnit", { phase: "fast-stop", captureId: stopCapture.id });
|
|
614
|
+
await pauseAuto(ctx, pi);
|
|
615
|
+
return "stopped";
|
|
616
|
+
}
|
|
617
|
+
} catch (e) {
|
|
618
|
+
debugLog("postUnit", { phase: "fast-stop-error", error: String(e) });
|
|
619
|
+
}
|
|
620
|
+
}
|
|
621
|
+
|
|
622
|
+
// ── Capture protection: revert executor-silenced captures (#3487) ──
|
|
623
|
+
// Non-triage agents can write **Status:** resolved to CAPTURES.md, bypassing
|
|
624
|
+
// the triage pipeline. Revert those to pending before the triage check.
|
|
625
|
+
if (
|
|
626
|
+
s.currentUnit &&
|
|
627
|
+
s.currentUnit.type !== "triage-captures"
|
|
628
|
+
) {
|
|
629
|
+
try {
|
|
630
|
+
const reverted = revertExecutorResolvedCaptures(s.basePath);
|
|
631
|
+
if (reverted > 0) {
|
|
632
|
+
debugLog("postUnit", { phase: "capture-protection", reverted });
|
|
633
|
+
ctx.ui.notify(
|
|
634
|
+
`Reverted ${reverted} capture${reverted === 1 ? "" : "s"} silenced by executor — re-queuing for triage.`,
|
|
635
|
+
"warning",
|
|
636
|
+
);
|
|
637
|
+
}
|
|
638
|
+
} catch (e) {
|
|
639
|
+
debugLog("postUnit", { phase: "capture-protection-error", error: String(e) });
|
|
640
|
+
}
|
|
641
|
+
}
|
|
642
|
+
|
|
597
643
|
// ── Triage check ──
|
|
598
644
|
if (
|
|
599
645
|
!s.stepMode &&
|
|
@@ -685,3 +731,4 @@ export async function postUnitPostVerification(pctx: PostUnitContext): Promise<"
|
|
|
685
731
|
|
|
686
732
|
return "continue";
|
|
687
733
|
}
|
|
734
|
+
|