gsd-pi 2.38.0-dev.eeb3520 → 2.39.0-dev.20aba06
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +15 -11
- package/dist/app-paths.js +1 -1
- package/dist/cli.js +9 -0
- package/dist/extension-discovery.d.ts +5 -3
- package/dist/extension-discovery.js +14 -9
- package/dist/extension-registry.js +2 -2
- package/dist/remote-questions-config.js +2 -2
- package/dist/resource-loader.js +100 -3
- package/dist/resources/extensions/async-jobs/index.js +10 -0
- package/dist/resources/extensions/browser-tools/index.js +3 -1
- package/dist/resources/extensions/browser-tools/package.json +3 -1
- package/dist/resources/extensions/browser-tools/tools/verify.js +97 -0
- package/dist/resources/extensions/cmux/index.js +55 -1
- package/dist/resources/extensions/context7/package.json +1 -1
- package/dist/resources/extensions/get-secrets-from-user.js +5 -24
- package/dist/resources/extensions/github-sync/cli.js +284 -0
- package/dist/resources/extensions/github-sync/index.js +73 -0
- package/dist/resources/extensions/github-sync/mapping.js +67 -0
- package/dist/resources/extensions/github-sync/sync.js +424 -0
- package/dist/resources/extensions/github-sync/templates.js +118 -0
- package/dist/resources/extensions/github-sync/types.js +7 -0
- package/dist/resources/extensions/google-search/package.json +3 -1
- package/dist/resources/extensions/gsd/auto/session.js +6 -23
- package/dist/resources/extensions/gsd/auto-dashboard.js +7 -0
- package/dist/resources/extensions/gsd/auto-dispatch.js +8 -9
- package/dist/resources/extensions/gsd/auto-loop.js +923 -787
- package/dist/resources/extensions/gsd/auto-post-unit.js +107 -70
- package/dist/resources/extensions/gsd/auto-prompts.js +205 -51
- package/dist/resources/extensions/gsd/auto-start.js +19 -3
- package/dist/resources/extensions/gsd/auto-worktree-sync.js +13 -5
- package/dist/resources/extensions/gsd/auto-worktree.js +3 -3
- package/dist/resources/extensions/gsd/auto.js +149 -100
- package/dist/resources/extensions/gsd/bootstrap/agent-end-recovery.js +126 -0
- package/dist/resources/extensions/gsd/bootstrap/db-tools.js +233 -0
- package/dist/resources/extensions/gsd/bootstrap/dynamic-tools.js +59 -0
- package/dist/resources/extensions/gsd/bootstrap/register-extension.js +38 -0
- package/dist/resources/extensions/gsd/bootstrap/register-hooks.js +156 -0
- package/dist/resources/extensions/gsd/bootstrap/register-shortcuts.js +46 -0
- package/dist/resources/extensions/gsd/bootstrap/system-context.js +300 -0
- package/dist/resources/extensions/gsd/bootstrap/write-gate.js +38 -0
- package/dist/resources/extensions/gsd/captures.js +9 -1
- package/dist/resources/extensions/gsd/commands/catalog.js +278 -0
- package/dist/resources/extensions/gsd/commands/context.js +84 -0
- package/dist/resources/extensions/gsd/commands/dispatcher.js +21 -0
- package/dist/resources/extensions/gsd/commands/handlers/auto.js +72 -0
- package/dist/resources/extensions/gsd/commands/handlers/core.js +246 -0
- package/dist/resources/extensions/gsd/commands/handlers/ops.js +166 -0
- package/dist/resources/extensions/gsd/commands/handlers/parallel.js +94 -0
- package/dist/resources/extensions/gsd/commands/handlers/workflow.js +102 -0
- package/dist/resources/extensions/gsd/commands/index.js +11 -0
- package/dist/resources/extensions/gsd/commands-extensions.js +3 -2
- package/dist/resources/extensions/gsd/commands-handlers.js +17 -4
- package/dist/resources/extensions/gsd/commands-prefs-wizard.js +1 -1
- package/dist/resources/extensions/gsd/commands.js +8 -1169
- package/dist/resources/extensions/gsd/context-budget.js +2 -10
- package/dist/resources/extensions/gsd/dashboard-overlay.js +9 -0
- package/dist/resources/extensions/gsd/detection.js +1 -2
- package/dist/resources/extensions/gsd/docs/preferences-reference.md +0 -2
- package/dist/resources/extensions/gsd/doctor-checks.js +82 -0
- package/dist/resources/extensions/gsd/doctor-environment.js +78 -0
- package/dist/resources/extensions/gsd/doctor-format.js +15 -0
- package/dist/resources/extensions/gsd/doctor-proactive.js +80 -10
- package/dist/resources/extensions/gsd/doctor-providers.js +30 -11
- package/dist/resources/extensions/gsd/doctor.js +234 -12
- package/dist/resources/extensions/gsd/env-utils.js +29 -0
- package/dist/resources/extensions/gsd/exit-command.js +2 -1
- package/dist/resources/extensions/gsd/export-html.js +46 -0
- package/dist/resources/extensions/gsd/export.js +1 -1
- package/dist/resources/extensions/gsd/files.js +48 -9
- package/dist/resources/extensions/gsd/forensics.js +1 -1
- package/dist/resources/extensions/gsd/git-service.js +30 -12
- package/dist/resources/extensions/gsd/gitignore.js +16 -3
- package/dist/resources/extensions/gsd/guided-flow.js +149 -38
- package/dist/resources/extensions/gsd/health-widget-core.js +32 -70
- package/dist/resources/extensions/gsd/health-widget.js +4 -87
- package/dist/resources/extensions/gsd/index.js +4 -1111
- package/dist/resources/extensions/gsd/migrate/parsers.js +1 -1
- package/dist/resources/extensions/gsd/migrate-external.js +18 -1
- package/dist/resources/extensions/gsd/native-git-bridge.js +37 -0
- package/dist/resources/extensions/gsd/package.json +1 -1
- package/dist/resources/extensions/gsd/paths.js +3 -0
- package/dist/resources/extensions/gsd/preferences-models.js +0 -12
- package/dist/resources/extensions/gsd/preferences-types.js +1 -1
- package/dist/resources/extensions/gsd/preferences-validation.js +59 -11
- package/dist/resources/extensions/gsd/preferences.js +22 -11
- package/dist/resources/extensions/gsd/progress-score.js +20 -1
- package/dist/resources/extensions/gsd/prompt-loader.js +6 -2
- package/dist/resources/extensions/gsd/prompts/complete-milestone.md +1 -1
- package/dist/resources/extensions/gsd/prompts/complete-slice.md +1 -1
- package/dist/resources/extensions/gsd/prompts/discuss.md +11 -14
- package/dist/resources/extensions/gsd/prompts/execute-task.md +5 -3
- package/dist/resources/extensions/gsd/prompts/forensics.md +121 -46
- package/dist/resources/extensions/gsd/prompts/guided-complete-slice.md +1 -1
- package/dist/resources/extensions/gsd/prompts/guided-discuss-milestone.md +11 -12
- package/dist/resources/extensions/gsd/prompts/guided-discuss-slice.md +8 -10
- package/dist/resources/extensions/gsd/prompts/guided-execute-task.md +1 -1
- package/dist/resources/extensions/gsd/prompts/guided-plan-milestone.md +1 -1
- package/dist/resources/extensions/gsd/prompts/guided-plan-slice.md +1 -1
- package/dist/resources/extensions/gsd/prompts/guided-research-slice.md +1 -1
- package/dist/resources/extensions/gsd/prompts/guided-resume-task.md +1 -1
- package/dist/resources/extensions/gsd/prompts/plan-milestone.md +1 -1
- package/dist/resources/extensions/gsd/prompts/plan-slice.md +1 -1
- package/dist/resources/extensions/gsd/prompts/queue.md +4 -8
- package/dist/resources/extensions/gsd/prompts/reactive-execute.md +11 -8
- package/dist/resources/extensions/gsd/prompts/reassess-roadmap.md +1 -1
- package/dist/resources/extensions/gsd/prompts/research-milestone.md +1 -1
- package/dist/resources/extensions/gsd/prompts/research-slice.md +1 -1
- package/dist/resources/extensions/gsd/prompts/run-uat.md +28 -11
- package/dist/resources/extensions/gsd/prompts/workflow-start.md +2 -2
- package/dist/resources/extensions/gsd/repo-identity.js +21 -4
- package/dist/resources/extensions/gsd/resource-version.js +2 -1
- package/dist/resources/extensions/gsd/roadmap-mutations.js +24 -0
- package/dist/resources/extensions/gsd/state.js +42 -23
- package/dist/resources/extensions/gsd/templates/runtime.md +21 -0
- package/dist/resources/extensions/gsd/templates/task-plan.md +3 -0
- package/dist/resources/extensions/gsd/visualizer-data.js +27 -2
- package/dist/resources/extensions/gsd/visualizer-views.js +52 -0
- package/dist/resources/extensions/gsd/worktree.js +35 -16
- package/dist/resources/extensions/mcp-client/index.js +14 -1
- package/dist/resources/extensions/remote-questions/status.js +4 -1
- package/dist/resources/extensions/remote-questions/store.js +4 -1
- package/dist/resources/extensions/search-the-web/provider.js +2 -1
- package/dist/resources/extensions/shared/frontmatter.js +1 -1
- package/dist/resources/extensions/subagent/index.js +12 -3
- package/dist/resources/extensions/subagent/isolation.js +2 -1
- package/dist/resources/extensions/ttsr/rule-loader.js +2 -1
- package/dist/resources/extensions/universal-config/package.json +1 -1
- package/dist/welcome-screen.d.ts +13 -0
- package/dist/welcome-screen.js +97 -0
- package/package.json +1 -1
- package/packages/pi-ai/dist/utils/oauth/anthropic.js +2 -2
- package/packages/pi-ai/dist/utils/oauth/anthropic.js.map +1 -1
- package/packages/pi-ai/src/utils/oauth/anthropic.ts +2 -2
- package/packages/pi-coding-agent/dist/core/agent-session.d.ts +12 -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 +107 -24
- package/packages/pi-coding-agent/dist/core/agent-session.js.map +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 +205 -7
- package/packages/pi-coding-agent/dist/core/extensions/loader.js.map +1 -1
- package/packages/pi-coding-agent/dist/core/package-manager.d.ts.map +1 -1
- package/packages/pi-coding-agent/dist/core/package-manager.js +8 -4
- package/packages/pi-coding-agent/dist/core/package-manager.js.map +1 -1
- package/packages/pi-coding-agent/dist/core/skill-tool.test.d.ts +2 -0
- package/packages/pi-coding-agent/dist/core/skill-tool.test.d.ts.map +1 -0
- package/packages/pi-coding-agent/dist/core/skill-tool.test.js +70 -0
- package/packages/pi-coding-agent/dist/core/skill-tool.test.js.map +1 -0
- package/packages/pi-coding-agent/dist/core/skills.d.ts +1 -0
- package/packages/pi-coding-agent/dist/core/skills.d.ts.map +1 -1
- package/packages/pi-coding-agent/dist/core/skills.js +8 -2
- package/packages/pi-coding-agent/dist/core/skills.js.map +1 -1
- package/packages/pi-coding-agent/dist/index.d.ts +1 -1
- package/packages/pi-coding-agent/dist/index.d.ts.map +1 -1
- package/packages/pi-coding-agent/dist/index.js +1 -1
- package/packages/pi-coding-agent/dist/index.js.map +1 -1
- package/packages/pi-coding-agent/dist/modes/interactive/controllers/chat-controller.d.ts +17 -0
- package/packages/pi-coding-agent/dist/modes/interactive/controllers/chat-controller.d.ts.map +1 -0
- package/packages/pi-coding-agent/dist/modes/interactive/controllers/chat-controller.js +244 -0
- package/packages/pi-coding-agent/dist/modes/interactive/controllers/chat-controller.js.map +1 -0
- package/packages/pi-coding-agent/dist/modes/interactive/controllers/extension-ui-controller.d.ts +3 -0
- package/packages/pi-coding-agent/dist/modes/interactive/controllers/extension-ui-controller.d.ts.map +1 -0
- package/packages/pi-coding-agent/dist/modes/interactive/controllers/extension-ui-controller.js +58 -0
- package/packages/pi-coding-agent/dist/modes/interactive/controllers/extension-ui-controller.js.map +1 -0
- package/packages/pi-coding-agent/dist/modes/interactive/controllers/input-controller.d.ts +12 -0
- package/packages/pi-coding-agent/dist/modes/interactive/controllers/input-controller.d.ts.map +1 -0
- package/packages/pi-coding-agent/dist/modes/interactive/controllers/input-controller.js +54 -0
- package/packages/pi-coding-agent/dist/modes/interactive/controllers/input-controller.js.map +1 -0
- package/packages/pi-coding-agent/dist/modes/interactive/controllers/model-controller.d.ts +6 -0
- package/packages/pi-coding-agent/dist/modes/interactive/controllers/model-controller.d.ts.map +1 -0
- package/packages/pi-coding-agent/dist/modes/interactive/controllers/model-controller.js +63 -0
- package/packages/pi-coding-agent/dist/modes/interactive/controllers/model-controller.js.map +1 -0
- package/packages/pi-coding-agent/dist/modes/interactive/interactive-mode-state.d.ts +38 -0
- package/packages/pi-coding-agent/dist/modes/interactive/interactive-mode-state.d.ts.map +1 -0
- package/packages/pi-coding-agent/dist/modes/interactive/interactive-mode-state.js +2 -0
- package/packages/pi-coding-agent/dist/modes/interactive/interactive-mode-state.js.map +1 -0
- package/packages/pi-coding-agent/dist/modes/interactive/interactive-mode.d.ts +1 -1
- package/packages/pi-coding-agent/dist/modes/interactive/interactive-mode.d.ts.map +1 -1
- package/packages/pi-coding-agent/dist/modes/interactive/interactive-mode.js +15 -457
- 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 +122 -23
- package/packages/pi-coding-agent/src/core/extensions/loader.ts +223 -7
- package/packages/pi-coding-agent/src/core/package-manager.ts +8 -4
- package/packages/pi-coding-agent/src/core/skill-tool.test.ts +89 -0
- package/packages/pi-coding-agent/src/core/skills.ts +11 -2
- package/packages/pi-coding-agent/src/index.ts +1 -0
- package/packages/pi-coding-agent/src/modes/interactive/controllers/chat-controller.ts +302 -0
- package/packages/pi-coding-agent/src/modes/interactive/controllers/extension-ui-controller.ts +59 -0
- package/packages/pi-coding-agent/src/modes/interactive/controllers/input-controller.ts +68 -0
- package/packages/pi-coding-agent/src/modes/interactive/controllers/model-controller.ts +71 -0
- package/packages/pi-coding-agent/src/modes/interactive/interactive-mode-state.ts +37 -0
- package/packages/pi-coding-agent/src/modes/interactive/interactive-mode.ts +18 -510
- package/pkg/package.json +1 -1
- package/src/resources/extensions/async-jobs/index.ts +11 -0
- package/src/resources/extensions/browser-tools/index.ts +3 -0
- package/src/resources/extensions/browser-tools/tools/verify.ts +117 -0
- package/src/resources/extensions/cmux/index.ts +57 -1
- package/src/resources/extensions/get-secrets-from-user.ts +5 -24
- package/src/resources/extensions/github-sync/cli.ts +364 -0
- package/src/resources/extensions/github-sync/index.ts +93 -0
- package/src/resources/extensions/github-sync/mapping.ts +81 -0
- package/src/resources/extensions/github-sync/sync.ts +556 -0
- package/src/resources/extensions/github-sync/templates.ts +183 -0
- package/src/resources/extensions/github-sync/tests/cli.test.ts +20 -0
- package/src/resources/extensions/github-sync/tests/commit-linking.test.ts +39 -0
- package/src/resources/extensions/github-sync/tests/mapping.test.ts +104 -0
- package/src/resources/extensions/github-sync/tests/templates.test.ts +110 -0
- package/src/resources/extensions/github-sync/types.ts +47 -0
- package/src/resources/extensions/gsd/auto/session.ts +7 -25
- package/src/resources/extensions/gsd/auto-dashboard.ts +10 -0
- package/src/resources/extensions/gsd/auto-dispatch.ts +7 -9
- package/src/resources/extensions/gsd/auto-loop.ts +1285 -1138
- package/src/resources/extensions/gsd/auto-post-unit.ts +90 -46
- package/src/resources/extensions/gsd/auto-prompts.ts +250 -53
- package/src/resources/extensions/gsd/auto-start.ts +24 -3
- package/src/resources/extensions/gsd/auto-worktree-sync.ts +15 -4
- package/src/resources/extensions/gsd/auto-worktree.ts +3 -3
- package/src/resources/extensions/gsd/auto.ts +152 -111
- package/src/resources/extensions/gsd/bootstrap/agent-end-recovery.ts +142 -0
- package/src/resources/extensions/gsd/bootstrap/db-tools.ts +238 -0
- package/src/resources/extensions/gsd/bootstrap/dynamic-tools.ts +90 -0
- package/src/resources/extensions/gsd/bootstrap/register-extension.ts +46 -0
- package/src/resources/extensions/gsd/bootstrap/register-hooks.ts +167 -0
- package/src/resources/extensions/gsd/bootstrap/register-shortcuts.ts +55 -0
- package/src/resources/extensions/gsd/bootstrap/system-context.ts +340 -0
- package/src/resources/extensions/gsd/bootstrap/write-gate.ts +51 -0
- package/src/resources/extensions/gsd/captures.ts +10 -1
- package/src/resources/extensions/gsd/commands/catalog.ts +301 -0
- package/src/resources/extensions/gsd/commands/context.ts +101 -0
- package/src/resources/extensions/gsd/commands/dispatcher.ts +32 -0
- package/src/resources/extensions/gsd/commands/handlers/auto.ts +74 -0
- package/src/resources/extensions/gsd/commands/handlers/core.ts +274 -0
- package/src/resources/extensions/gsd/commands/handlers/ops.ts +169 -0
- package/src/resources/extensions/gsd/commands/handlers/parallel.ts +118 -0
- package/src/resources/extensions/gsd/commands/handlers/workflow.ts +109 -0
- package/src/resources/extensions/gsd/commands/index.ts +14 -0
- package/src/resources/extensions/gsd/commands-extensions.ts +4 -2
- package/src/resources/extensions/gsd/commands-handlers.ts +18 -3
- package/src/resources/extensions/gsd/commands-prefs-wizard.ts +1 -1
- package/src/resources/extensions/gsd/commands.ts +10 -1307
- package/src/resources/extensions/gsd/context-budget.ts +2 -12
- package/src/resources/extensions/gsd/dashboard-overlay.ts +10 -0
- package/src/resources/extensions/gsd/detection.ts +2 -2
- package/src/resources/extensions/gsd/docs/preferences-reference.md +0 -2
- package/src/resources/extensions/gsd/doctor-checks.ts +75 -0
- package/src/resources/extensions/gsd/doctor-environment.ts +82 -1
- package/src/resources/extensions/gsd/doctor-format.ts +20 -0
- package/src/resources/extensions/gsd/doctor-proactive.ts +106 -10
- package/src/resources/extensions/gsd/doctor-providers.ts +30 -9
- package/src/resources/extensions/gsd/doctor-types.ts +16 -1
- package/src/resources/extensions/gsd/doctor.ts +243 -14
- package/src/resources/extensions/gsd/env-utils.ts +31 -0
- package/src/resources/extensions/gsd/exit-command.ts +2 -2
- package/src/resources/extensions/gsd/export-html.ts +51 -0
- package/src/resources/extensions/gsd/export.ts +1 -1
- package/src/resources/extensions/gsd/files.ts +51 -11
- package/src/resources/extensions/gsd/forensics.ts +1 -1
- package/src/resources/extensions/gsd/git-service.ts +44 -10
- package/src/resources/extensions/gsd/gitignore.ts +17 -3
- package/src/resources/extensions/gsd/guided-flow.ts +177 -44
- package/src/resources/extensions/gsd/health-widget-core.ts +28 -80
- package/src/resources/extensions/gsd/health-widget.ts +4 -89
- package/src/resources/extensions/gsd/index.ts +12 -1307
- package/src/resources/extensions/gsd/migrate/parsers.ts +1 -1
- package/src/resources/extensions/gsd/migrate-external.ts +18 -1
- package/src/resources/extensions/gsd/native-git-bridge.ts +37 -0
- package/src/resources/extensions/gsd/paths.ts +4 -0
- package/src/resources/extensions/gsd/preferences-models.ts +0 -12
- package/src/resources/extensions/gsd/preferences-types.ts +4 -4
- package/src/resources/extensions/gsd/preferences-validation.ts +51 -11
- package/src/resources/extensions/gsd/preferences.ts +25 -11
- package/src/resources/extensions/gsd/progress-score.ts +23 -0
- package/src/resources/extensions/gsd/prompt-loader.ts +7 -2
- package/src/resources/extensions/gsd/prompts/complete-milestone.md +1 -1
- package/src/resources/extensions/gsd/prompts/complete-slice.md +1 -1
- package/src/resources/extensions/gsd/prompts/discuss.md +11 -14
- package/src/resources/extensions/gsd/prompts/execute-task.md +5 -3
- package/src/resources/extensions/gsd/prompts/forensics.md +121 -46
- package/src/resources/extensions/gsd/prompts/guided-complete-slice.md +1 -1
- package/src/resources/extensions/gsd/prompts/guided-discuss-milestone.md +11 -12
- package/src/resources/extensions/gsd/prompts/guided-discuss-slice.md +8 -10
- package/src/resources/extensions/gsd/prompts/guided-execute-task.md +1 -1
- package/src/resources/extensions/gsd/prompts/guided-plan-milestone.md +1 -1
- package/src/resources/extensions/gsd/prompts/guided-plan-slice.md +1 -1
- package/src/resources/extensions/gsd/prompts/guided-research-slice.md +1 -1
- package/src/resources/extensions/gsd/prompts/guided-resume-task.md +1 -1
- package/src/resources/extensions/gsd/prompts/plan-milestone.md +1 -1
- package/src/resources/extensions/gsd/prompts/plan-slice.md +1 -1
- package/src/resources/extensions/gsd/prompts/queue.md +4 -8
- package/src/resources/extensions/gsd/prompts/reactive-execute.md +11 -8
- package/src/resources/extensions/gsd/prompts/reassess-roadmap.md +1 -1
- package/src/resources/extensions/gsd/prompts/research-milestone.md +1 -1
- package/src/resources/extensions/gsd/prompts/research-slice.md +1 -1
- package/src/resources/extensions/gsd/prompts/run-uat.md +28 -11
- package/src/resources/extensions/gsd/prompts/workflow-start.md +2 -2
- package/src/resources/extensions/gsd/repo-identity.ts +23 -4
- package/src/resources/extensions/gsd/resource-version.ts +3 -1
- package/src/resources/extensions/gsd/roadmap-mutations.ts +29 -0
- package/src/resources/extensions/gsd/state.ts +39 -21
- package/src/resources/extensions/gsd/templates/runtime.md +21 -0
- package/src/resources/extensions/gsd/templates/task-plan.md +3 -0
- package/src/resources/extensions/gsd/tests/agent-end-retry.test.ts +21 -18
- package/src/resources/extensions/gsd/tests/auto-loop.test.ts +135 -77
- package/src/resources/extensions/gsd/tests/auto-worktree-milestone-merge.test.ts +4 -3
- package/src/resources/extensions/gsd/tests/cmux.test.ts +93 -0
- package/src/resources/extensions/gsd/tests/derive-state.test.ts +43 -0
- package/src/resources/extensions/gsd/tests/doctor-enhancements.test.ts +266 -0
- package/src/resources/extensions/gsd/tests/doctor-proactive.test.ts +3 -3
- package/src/resources/extensions/gsd/tests/doctor-providers.test.ts +86 -3
- package/src/resources/extensions/gsd/tests/gitignore-tracked-gsd.test.ts +50 -0
- package/src/resources/extensions/gsd/tests/health-widget.test.ts +16 -54
- package/src/resources/extensions/gsd/tests/parsers.test.ts +131 -14
- package/src/resources/extensions/gsd/tests/plan-slice-prompt.test.ts +209 -0
- package/src/resources/extensions/gsd/tests/preferences.test.ts +2 -7
- package/src/resources/extensions/gsd/tests/prompt-contracts.test.ts +59 -0
- package/src/resources/extensions/gsd/tests/provider-errors.test.ts +16 -16
- package/src/resources/extensions/gsd/tests/repo-identity-worktree.test.ts +21 -1
- package/src/resources/extensions/gsd/tests/run-uat.test.ts +16 -4
- package/src/resources/extensions/gsd/tests/skill-activation.test.ts +140 -0
- package/src/resources/extensions/gsd/tests/visualizer-data.test.ts +10 -10
- package/src/resources/extensions/gsd/tests/worktree.test.ts +47 -0
- package/src/resources/extensions/gsd/types.ts +18 -1
- package/src/resources/extensions/gsd/verification-evidence.ts +16 -0
- package/src/resources/extensions/gsd/visualizer-data.ts +52 -2
- package/src/resources/extensions/gsd/visualizer-views.ts +58 -0
- package/src/resources/extensions/gsd/worktree.ts +35 -15
- package/src/resources/extensions/mcp-client/index.ts +17 -1
- package/src/resources/extensions/remote-questions/status.ts +5 -1
- package/src/resources/extensions/remote-questions/store.ts +5 -1
- package/src/resources/extensions/search-the-web/provider.ts +2 -1
- package/src/resources/extensions/shared/frontmatter.ts +1 -1
- package/src/resources/extensions/subagent/index.ts +12 -3
- package/src/resources/extensions/subagent/isolation.ts +3 -1
- package/src/resources/extensions/ttsr/rule-loader.ts +3 -1
- package/dist/resources/extensions/gsd/prompt-compressor.js +0 -393
- package/dist/resources/extensions/gsd/semantic-chunker.js +0 -254
- package/dist/resources/extensions/gsd/summary-distiller.js +0 -212
- package/src/resources/extensions/gsd/prompt-compressor.ts +0 -508
- package/src/resources/extensions/gsd/semantic-chunker.ts +0 -336
- package/src/resources/extensions/gsd/summary-distiller.ts +0 -258
- package/src/resources/extensions/gsd/tests/context-compression.test.ts +0 -193
- package/src/resources/extensions/gsd/tests/prompt-compressor.test.ts +0 -529
- package/src/resources/extensions/gsd/tests/semantic-chunker.test.ts +0 -426
- package/src/resources/extensions/gsd/tests/summary-distiller.test.ts +0 -323
- package/src/resources/extensions/gsd/tests/token-optimization-benchmark.test.ts +0 -1272
- package/src/resources/extensions/gsd/tests/token-optimization-prefs.test.ts +0 -164
|
@@ -9,7 +9,6 @@
|
|
|
9
9
|
*/
|
|
10
10
|
|
|
11
11
|
import { type TokenProvider, getCharsPerToken } from "./token-counter.js";
|
|
12
|
-
import { compressToTarget } from "./prompt-compressor.js";
|
|
13
12
|
|
|
14
13
|
// ─── Budget ratio constants ──────────────────────────────────────────────────
|
|
15
14
|
// Percentages of total context window allocated to each budget category.
|
|
@@ -202,22 +201,13 @@ export function resolveExecutorContextWindow(
|
|
|
202
201
|
}
|
|
203
202
|
|
|
204
203
|
/**
|
|
205
|
-
*
|
|
206
|
-
* Returns the content within budget with maximum information preservation.
|
|
204
|
+
* Reduce content to fit within budget using section-boundary truncation.
|
|
207
205
|
*/
|
|
208
206
|
export function reduceToFit(content: string, budgetChars: number): TruncationResult {
|
|
209
207
|
if (!content || content.length <= budgetChars) {
|
|
210
208
|
return { content, droppedSections: 0 };
|
|
211
209
|
}
|
|
212
|
-
|
|
213
|
-
// Step 1: Try compression
|
|
214
|
-
const compressed = compressToTarget(content, budgetChars);
|
|
215
|
-
if (compressed.compressedChars <= budgetChars) {
|
|
216
|
-
return { content: compressed.content, droppedSections: 0 };
|
|
217
|
-
}
|
|
218
|
-
|
|
219
|
-
// Step 2: Truncate the compressed content at section boundaries
|
|
220
|
-
return truncateAtSectionBoundary(compressed.content, budgetChars);
|
|
210
|
+
return truncateAtSectionBoundary(content, budgetChars);
|
|
221
211
|
}
|
|
222
212
|
|
|
223
213
|
// ─── Internal helpers ────────────────────────────────────────────────────────
|
|
@@ -320,6 +320,16 @@ export class GSDDashboardOverlay {
|
|
|
320
320
|
: progressScore.level === "yellow" ? th.fg("warning", "●")
|
|
321
321
|
: th.fg("error", "●");
|
|
322
322
|
lines.push(row(`${progressIcon} ${th.fg("text", progressScore.summary)}`));
|
|
323
|
+
|
|
324
|
+
// Show signal details when degraded — real-time visibility into what doctor found
|
|
325
|
+
if (progressScore.level !== "green" && progressScore.signals.length > 0) {
|
|
326
|
+
for (const signal of progressScore.signals) {
|
|
327
|
+
const prefix = signal.kind === "positive" ? th.fg("success", " ✓")
|
|
328
|
+
: signal.kind === "negative" ? th.fg("error", " ✗")
|
|
329
|
+
: th.fg("dim", " ·");
|
|
330
|
+
lines.push(row(`${prefix} ${th.fg("dim", signal.label)}`));
|
|
331
|
+
}
|
|
332
|
+
}
|
|
323
333
|
}
|
|
324
334
|
lines.push(blank());
|
|
325
335
|
|
|
@@ -11,6 +11,8 @@ import { join } from "node:path";
|
|
|
11
11
|
import { homedir } from "node:os";
|
|
12
12
|
import { gsdRoot } from "./paths.js";
|
|
13
13
|
|
|
14
|
+
const gsdHome = process.env.GSD_HOME || join(homedir(), ".gsd");
|
|
15
|
+
|
|
14
16
|
// ─── Types ──────────────────────────────────────────────────────────────────────
|
|
15
17
|
|
|
16
18
|
export interface ProjectDetection {
|
|
@@ -400,7 +402,6 @@ function detectVerificationCommands(
|
|
|
400
402
|
* Check if global GSD setup exists (has ~/.gsd/ with preferences).
|
|
401
403
|
*/
|
|
402
404
|
export function hasGlobalSetup(): boolean {
|
|
403
|
-
const gsdHome = join(homedir(), ".gsd");
|
|
404
405
|
return (
|
|
405
406
|
existsSync(join(gsdHome, "preferences.md")) ||
|
|
406
407
|
existsSync(join(gsdHome, "PREFERENCES.md"))
|
|
@@ -412,7 +413,6 @@ export function hasGlobalSetup(): boolean {
|
|
|
412
413
|
* Returns true if ~/.gsd/ doesn't exist or has no preferences or auth.
|
|
413
414
|
*/
|
|
414
415
|
export function isFirstEverLaunch(): boolean {
|
|
415
|
-
const gsdHome = join(homedir(), ".gsd");
|
|
416
416
|
if (!existsSync(gsdHome)) return true;
|
|
417
417
|
|
|
418
418
|
// If we have preferences, not first launch
|
|
@@ -194,8 +194,6 @@ Setting `prefer_skills: []` does **not** disable skill discovery — it just mea
|
|
|
194
194
|
|
|
195
195
|
- `search_provider`: `"brave"`, `"tavily"`, `"ollama"`, `"native"`, or `"auto"` — selects the search backend for research phases. `"native"` forces Anthropic's built-in web search only; provider values force that backend and disable native search; `"auto"` uses the default heuristic. Default: `"auto"`.
|
|
196
196
|
|
|
197
|
-
- `compression_strategy`: `"truncate"` or `"compress"` — controls how context that exceeds the budget is reduced. `"truncate"` (default) drops sections from the end. `"compress"` applies heuristic compression before truncating, preserving more content at the cost of some fidelity. Default: `"truncate"`.
|
|
198
|
-
|
|
199
197
|
- `context_selection`: `"full"` or `"smart"` — controls how files are inlined into context. `"full"` inlines entire files; `"smart"` uses semantic chunking to include only the most relevant sections. Default is derived from `token_profile`.
|
|
200
198
|
|
|
201
199
|
- `parallel`: configures parallel orchestration for running multiple slices concurrently. Keys:
|
|
@@ -657,6 +657,81 @@ export async function checkRuntimeHealth(
|
|
|
657
657
|
} catch {
|
|
658
658
|
// Non-fatal — external state check failed
|
|
659
659
|
}
|
|
660
|
+
|
|
661
|
+
// ── Metrics ledger integrity ───────────────────────────────────────────
|
|
662
|
+
try {
|
|
663
|
+
const metricsPath = join(root, "metrics.json");
|
|
664
|
+
if (existsSync(metricsPath)) {
|
|
665
|
+
try {
|
|
666
|
+
const raw = readFileSync(metricsPath, "utf-8");
|
|
667
|
+
const ledger = JSON.parse(raw);
|
|
668
|
+
if (ledger.version !== 1 || !Array.isArray(ledger.units)) {
|
|
669
|
+
issues.push({
|
|
670
|
+
severity: "warning",
|
|
671
|
+
code: "metrics_ledger_corrupt",
|
|
672
|
+
scope: "project",
|
|
673
|
+
unitId: "project",
|
|
674
|
+
message: "metrics.json has an unexpected structure (version !== 1 or units is not an array) — metrics data may be unreliable",
|
|
675
|
+
file: ".gsd/metrics.json",
|
|
676
|
+
fixable: false,
|
|
677
|
+
});
|
|
678
|
+
}
|
|
679
|
+
} catch {
|
|
680
|
+
issues.push({
|
|
681
|
+
severity: "warning",
|
|
682
|
+
code: "metrics_ledger_corrupt",
|
|
683
|
+
scope: "project",
|
|
684
|
+
unitId: "project",
|
|
685
|
+
message: "metrics.json is not valid JSON — metrics data may be corrupt",
|
|
686
|
+
file: ".gsd/metrics.json",
|
|
687
|
+
fixable: false,
|
|
688
|
+
});
|
|
689
|
+
}
|
|
690
|
+
}
|
|
691
|
+
} catch {
|
|
692
|
+
// Non-fatal — metrics check failed
|
|
693
|
+
}
|
|
694
|
+
|
|
695
|
+
// ── Large planning file detection ──────────────────────────────────────
|
|
696
|
+
// Files over 100KB can cause LLM context pressure. Report the worst offenders.
|
|
697
|
+
try {
|
|
698
|
+
const MAX_FILE_BYTES = 100 * 1024; // 100KB
|
|
699
|
+
const milestonesPath = milestonesDir(basePath);
|
|
700
|
+
if (existsSync(milestonesPath)) {
|
|
701
|
+
const largeFiles: Array<{ path: string; sizeKB: number }> = [];
|
|
702
|
+
function scanForLargeFiles(dir: string, depth = 0): void {
|
|
703
|
+
if (depth > 6) return;
|
|
704
|
+
try {
|
|
705
|
+
for (const entry of readdirSync(dir)) {
|
|
706
|
+
const full = join(dir, entry);
|
|
707
|
+
try {
|
|
708
|
+
const s = statSync(full);
|
|
709
|
+
if (s.isDirectory()) { scanForLargeFiles(full, depth + 1); continue; }
|
|
710
|
+
if (entry.endsWith(".md") && s.size > MAX_FILE_BYTES) {
|
|
711
|
+
largeFiles.push({ path: full.replace(basePath + "/", ""), sizeKB: Math.round(s.size / 1024) });
|
|
712
|
+
}
|
|
713
|
+
} catch { /* skip entry */ }
|
|
714
|
+
}
|
|
715
|
+
} catch { /* skip dir */ }
|
|
716
|
+
}
|
|
717
|
+
scanForLargeFiles(milestonesPath);
|
|
718
|
+
if (largeFiles.length > 0) {
|
|
719
|
+
largeFiles.sort((a, b) => b.sizeKB - a.sizeKB);
|
|
720
|
+
const worst = largeFiles[0]!;
|
|
721
|
+
issues.push({
|
|
722
|
+
severity: "warning",
|
|
723
|
+
code: "large_planning_file",
|
|
724
|
+
scope: "project",
|
|
725
|
+
unitId: "project",
|
|
726
|
+
message: `${largeFiles.length} planning file(s) exceed 100KB — largest: ${worst.path} (${worst.sizeKB}KB). Large files cause LLM context pressure.`,
|
|
727
|
+
file: worst.path,
|
|
728
|
+
fixable: false,
|
|
729
|
+
});
|
|
730
|
+
}
|
|
731
|
+
}
|
|
732
|
+
} catch {
|
|
733
|
+
// Non-fatal — large file scan failed
|
|
734
|
+
}
|
|
660
735
|
}
|
|
661
736
|
|
|
662
737
|
/**
|
|
@@ -407,6 +407,63 @@ function checkGitRemote(basePath: string): EnvironmentCheckResult | null {
|
|
|
407
407
|
return { name: "git_remote", status: "ok", message: "Git remote reachable" };
|
|
408
408
|
}
|
|
409
409
|
|
|
410
|
+
/**
|
|
411
|
+
* Check if the project build passes (opt-in slow check, use --build flag).
|
|
412
|
+
* Runs npm run build and reports failure as env_build.
|
|
413
|
+
*/
|
|
414
|
+
function checkBuildHealth(basePath: string): EnvironmentCheckResult | null {
|
|
415
|
+
const pkgPath = join(basePath, "package.json");
|
|
416
|
+
if (!existsSync(pkgPath)) return null;
|
|
417
|
+
|
|
418
|
+
try {
|
|
419
|
+
const pkg = JSON.parse(readFileSync(pkgPath, "utf-8"));
|
|
420
|
+
const buildScript = pkg.scripts?.build;
|
|
421
|
+
if (!buildScript) return null;
|
|
422
|
+
|
|
423
|
+
const result = tryExec("npm run build 2>&1", basePath);
|
|
424
|
+
if (result === null) {
|
|
425
|
+
return {
|
|
426
|
+
name: "build",
|
|
427
|
+
status: "error",
|
|
428
|
+
message: "Build failed — npm run build exited non-zero",
|
|
429
|
+
detail: "Fix build errors before dispatching work",
|
|
430
|
+
};
|
|
431
|
+
}
|
|
432
|
+
return { name: "build", status: "ok", message: "Build passes" };
|
|
433
|
+
} catch {
|
|
434
|
+
return null;
|
|
435
|
+
}
|
|
436
|
+
}
|
|
437
|
+
|
|
438
|
+
/**
|
|
439
|
+
* Check if tests pass (opt-in slow check, use --test flag).
|
|
440
|
+
* Runs npm test and reports failures as env_test.
|
|
441
|
+
*/
|
|
442
|
+
function checkTestHealth(basePath: string): EnvironmentCheckResult | null {
|
|
443
|
+
const pkgPath = join(basePath, "package.json");
|
|
444
|
+
if (!existsSync(pkgPath)) return null;
|
|
445
|
+
|
|
446
|
+
try {
|
|
447
|
+
const pkg = JSON.parse(readFileSync(pkgPath, "utf-8"));
|
|
448
|
+
const testScript = pkg.scripts?.test;
|
|
449
|
+
// Skip if no test script or the default placeholder
|
|
450
|
+
if (!testScript || testScript.includes("no test specified")) return null;
|
|
451
|
+
|
|
452
|
+
const result = tryExec("npm test 2>&1", basePath);
|
|
453
|
+
if (result === null) {
|
|
454
|
+
return {
|
|
455
|
+
name: "test",
|
|
456
|
+
status: "warning",
|
|
457
|
+
message: "Tests failing — npm test exited non-zero",
|
|
458
|
+
detail: "Fix failing tests before shipping",
|
|
459
|
+
};
|
|
460
|
+
}
|
|
461
|
+
return { name: "test", status: "ok", message: "Tests pass" };
|
|
462
|
+
} catch {
|
|
463
|
+
return null;
|
|
464
|
+
}
|
|
465
|
+
}
|
|
466
|
+
|
|
410
467
|
// ── Public API ─────────────────────────────────────────────────────────────
|
|
411
468
|
|
|
412
469
|
/**
|
|
@@ -454,6 +511,26 @@ export function runFullEnvironmentChecks(basePath: string): EnvironmentCheckResu
|
|
|
454
511
|
return results;
|
|
455
512
|
}
|
|
456
513
|
|
|
514
|
+
/**
|
|
515
|
+
* Run slow opt-in checks (build and/or test).
|
|
516
|
+
* These are never run on the pre-dispatch gate — only on explicit /gsd doctor --build/--test.
|
|
517
|
+
*/
|
|
518
|
+
export function runSlowEnvironmentChecks(
|
|
519
|
+
basePath: string,
|
|
520
|
+
options?: { includeBuild?: boolean; includeTests?: boolean },
|
|
521
|
+
): EnvironmentCheckResult[] {
|
|
522
|
+
const results: EnvironmentCheckResult[] = [];
|
|
523
|
+
if (options?.includeBuild) {
|
|
524
|
+
const buildCheck = checkBuildHealth(basePath);
|
|
525
|
+
if (buildCheck) results.push(buildCheck);
|
|
526
|
+
}
|
|
527
|
+
if (options?.includeTests) {
|
|
528
|
+
const testCheck = checkTestHealth(basePath);
|
|
529
|
+
if (testCheck) results.push(testCheck);
|
|
530
|
+
}
|
|
531
|
+
return results;
|
|
532
|
+
}
|
|
533
|
+
|
|
457
534
|
/**
|
|
458
535
|
* Convert environment check results to DoctorIssue format for the doctor pipeline.
|
|
459
536
|
*/
|
|
@@ -477,12 +554,16 @@ export function environmentResultsToDoctorIssues(results: EnvironmentCheckResult
|
|
|
477
554
|
export async function checkEnvironmentHealth(
|
|
478
555
|
basePath: string,
|
|
479
556
|
issues: DoctorIssue[],
|
|
480
|
-
options?: { includeRemote?: boolean },
|
|
557
|
+
options?: { includeRemote?: boolean; includeBuild?: boolean; includeTests?: boolean },
|
|
481
558
|
): Promise<void> {
|
|
482
559
|
const results = options?.includeRemote
|
|
483
560
|
? runFullEnvironmentChecks(basePath)
|
|
484
561
|
: runEnvironmentChecks(basePath);
|
|
485
562
|
|
|
563
|
+
if (options?.includeBuild || options?.includeTests) {
|
|
564
|
+
results.push(...runSlowEnvironmentChecks(basePath, options));
|
|
565
|
+
}
|
|
566
|
+
|
|
486
567
|
issues.push(...environmentResultsToDoctorIssues(results));
|
|
487
568
|
}
|
|
488
569
|
|
|
@@ -76,3 +76,23 @@ export function formatDoctorIssuesForPrompt(issues: DoctorIssue[]): string {
|
|
|
76
76
|
return `- [${prefix}] ${issue.unitId} | ${issue.code} | ${issue.message}${issue.file ? ` | file: ${issue.file}` : ""} | fixable: ${issue.fixable ? "yes" : "no"}`;
|
|
77
77
|
}).join("\n");
|
|
78
78
|
}
|
|
79
|
+
|
|
80
|
+
/**
|
|
81
|
+
* Serialize a doctor report to JSON — suitable for CI/tooling integration.
|
|
82
|
+
* Usage: /gsd doctor --json
|
|
83
|
+
*/
|
|
84
|
+
export function formatDoctorReportJson(report: DoctorReport): string {
|
|
85
|
+
return JSON.stringify(
|
|
86
|
+
{
|
|
87
|
+
ok: report.ok,
|
|
88
|
+
basePath: report.basePath,
|
|
89
|
+
generatedAt: new Date().toISOString(),
|
|
90
|
+
summary: summarizeDoctorIssues(report.issues),
|
|
91
|
+
issues: report.issues,
|
|
92
|
+
fixesApplied: report.fixesApplied,
|
|
93
|
+
...(report.timing ? { timing: report.timing } : {}),
|
|
94
|
+
},
|
|
95
|
+
null,
|
|
96
|
+
2,
|
|
97
|
+
);
|
|
98
|
+
}
|
|
@@ -26,12 +26,26 @@ import { nativeBranchExists, nativeIsRepo } from "./native-git-bridge.js";
|
|
|
26
26
|
|
|
27
27
|
// ── Health Score Tracking ──────────────────────────────────────────────────
|
|
28
28
|
|
|
29
|
+
/** Compact issue detail stored per snapshot for real-time visibility. */
|
|
30
|
+
export interface HealthIssueDetail {
|
|
31
|
+
code: string;
|
|
32
|
+
message: string;
|
|
33
|
+
severity: "error" | "warning" | "info";
|
|
34
|
+
unitId: string;
|
|
35
|
+
}
|
|
36
|
+
|
|
29
37
|
export interface HealthSnapshot {
|
|
30
38
|
timestamp: number;
|
|
31
39
|
errors: number;
|
|
32
40
|
warnings: number;
|
|
33
41
|
fixesApplied: number;
|
|
34
42
|
unitIndex: number; // which unit dispatch triggered this snapshot
|
|
43
|
+
/** Top issues from the doctor run that produced this snapshot. */
|
|
44
|
+
issues: HealthIssueDetail[];
|
|
45
|
+
/** Fixes that were auto-applied during this snapshot's doctor run. */
|
|
46
|
+
fixes: string[];
|
|
47
|
+
/** Milestone/slice scope this snapshot belongs to (e.g. "M001" or "M001/S02"). */
|
|
48
|
+
scope?: string;
|
|
35
49
|
}
|
|
36
50
|
|
|
37
51
|
/** In-memory health history for the current auto-mode session. */
|
|
@@ -43,11 +57,33 @@ let consecutiveErrorUnits = 0;
|
|
|
43
57
|
/** Unit index counter for health tracking. */
|
|
44
58
|
let healthUnitIndex = 0;
|
|
45
59
|
|
|
60
|
+
/** Previous progress level for state transition detection. */
|
|
61
|
+
let previousProgressLevel: "green" | "yellow" | "red" = "green";
|
|
62
|
+
|
|
63
|
+
/** Callback for state transition notifications. Set by auto-mode. */
|
|
64
|
+
let onLevelChange: ((from: string, to: string, summary: string) => void) | null = null;
|
|
65
|
+
|
|
66
|
+
/**
|
|
67
|
+
* Register a callback for progress level transitions (green→yellow, yellow→red, etc.).
|
|
68
|
+
* Called once when auto-mode starts. Pass null to unregister.
|
|
69
|
+
*/
|
|
70
|
+
export function setLevelChangeCallback(cb: ((from: string, to: string, summary: string) => void) | null): void {
|
|
71
|
+
onLevelChange = cb;
|
|
72
|
+
previousProgressLevel = "green";
|
|
73
|
+
}
|
|
74
|
+
|
|
46
75
|
/**
|
|
47
76
|
* Record a health snapshot after a doctor run.
|
|
48
|
-
* Called from the post-unit hook in auto.ts.
|
|
77
|
+
* Called from the post-unit hook in auto-post-unit.ts.
|
|
49
78
|
*/
|
|
50
|
-
export function recordHealthSnapshot(
|
|
79
|
+
export function recordHealthSnapshot(
|
|
80
|
+
errors: number,
|
|
81
|
+
warnings: number,
|
|
82
|
+
fixesApplied: number,
|
|
83
|
+
issues?: HealthIssueDetail[],
|
|
84
|
+
fixes?: string[],
|
|
85
|
+
scope?: string,
|
|
86
|
+
): void {
|
|
51
87
|
healthUnitIndex++;
|
|
52
88
|
healthHistory.push({
|
|
53
89
|
timestamp: Date.now(),
|
|
@@ -55,6 +91,9 @@ export function recordHealthSnapshot(errors: number, warnings: number, fixesAppl
|
|
|
55
91
|
warnings,
|
|
56
92
|
fixesApplied,
|
|
57
93
|
unitIndex: healthUnitIndex,
|
|
94
|
+
issues: issues ?? [],
|
|
95
|
+
fixes: fixes ?? [],
|
|
96
|
+
scope,
|
|
58
97
|
});
|
|
59
98
|
|
|
60
99
|
// Keep only the last 50 snapshots to bound memory
|
|
@@ -67,6 +106,19 @@ export function recordHealthSnapshot(errors: number, warnings: number, fixesAppl
|
|
|
67
106
|
} else {
|
|
68
107
|
consecutiveErrorUnits = 0;
|
|
69
108
|
}
|
|
109
|
+
|
|
110
|
+
// Detect progress level transitions and notify
|
|
111
|
+
if (onLevelChange) {
|
|
112
|
+
const newLevel = consecutiveErrorUnits >= 3 ? "red"
|
|
113
|
+
: consecutiveErrorUnits >= 1 || getHealthTrend() === "degrading" ? "yellow"
|
|
114
|
+
: "green";
|
|
115
|
+
if (newLevel !== previousProgressLevel) {
|
|
116
|
+
const topIssue = (issues ?? []).find(i => i.severity === "error") ?? (issues ?? [])[0];
|
|
117
|
+
const detail = topIssue ? `: ${topIssue.message}` : "";
|
|
118
|
+
onLevelChange(previousProgressLevel, newLevel, `Health ${previousProgressLevel} → ${newLevel}${detail}`);
|
|
119
|
+
previousProgressLevel = newLevel;
|
|
120
|
+
}
|
|
121
|
+
}
|
|
70
122
|
}
|
|
71
123
|
|
|
72
124
|
/**
|
|
@@ -104,6 +156,27 @@ export function getHealthHistory(): readonly HealthSnapshot[] {
|
|
|
104
156
|
return healthHistory;
|
|
105
157
|
}
|
|
106
158
|
|
|
159
|
+
/**
|
|
160
|
+
* Get the latest health issues from the most recent snapshot.
|
|
161
|
+
* Returns issues from the last snapshot that had any, for real-time visibility.
|
|
162
|
+
*/
|
|
163
|
+
export function getLatestHealthIssues(): HealthIssueDetail[] {
|
|
164
|
+
for (let i = healthHistory.length - 1; i >= 0; i--) {
|
|
165
|
+
if (healthHistory[i]!.issues.length > 0) return healthHistory[i]!.issues;
|
|
166
|
+
}
|
|
167
|
+
return [];
|
|
168
|
+
}
|
|
169
|
+
|
|
170
|
+
/**
|
|
171
|
+
* Get the latest fixes applied from the most recent snapshot.
|
|
172
|
+
*/
|
|
173
|
+
export function getLatestHealthFixes(): string[] {
|
|
174
|
+
for (let i = healthHistory.length - 1; i >= 0; i--) {
|
|
175
|
+
if (healthHistory[i]!.fixes.length > 0) return healthHistory[i]!.fixes;
|
|
176
|
+
}
|
|
177
|
+
return [];
|
|
178
|
+
}
|
|
179
|
+
|
|
107
180
|
/**
|
|
108
181
|
* Reset health tracking state. Called on auto-mode start/stop.
|
|
109
182
|
*/
|
|
@@ -111,6 +184,7 @@ export function resetHealthTracking(): void {
|
|
|
111
184
|
healthHistory = [];
|
|
112
185
|
consecutiveErrorUnits = 0;
|
|
113
186
|
healthUnitIndex = 0;
|
|
187
|
+
previousProgressLevel = "green";
|
|
114
188
|
}
|
|
115
189
|
|
|
116
190
|
// ── Pre-Dispatch Health Gate ───────────────────────────────────────────────
|
|
@@ -285,26 +359,48 @@ export function resetEscalation(): void {
|
|
|
285
359
|
|
|
286
360
|
/**
|
|
287
361
|
* Format a health summary for display in the auto-mode dashboard.
|
|
362
|
+
* Human-readable with full words, not abbreviations.
|
|
288
363
|
*/
|
|
289
364
|
export function formatHealthSummary(): string {
|
|
290
365
|
if (healthHistory.length === 0) return "No health data yet.";
|
|
291
366
|
|
|
292
367
|
const latest = healthHistory[healthHistory.length - 1]!;
|
|
293
368
|
const trend = getHealthTrend();
|
|
294
|
-
const
|
|
369
|
+
const trendLabel = trend === "improving" ? "improving"
|
|
370
|
+
: trend === "degrading" ? "degrading"
|
|
371
|
+
: trend === "stable" ? "stable"
|
|
372
|
+
: "unknown";
|
|
295
373
|
const totalFixes = healthHistory.reduce((sum, s) => sum + s.fixesApplied, 0);
|
|
296
374
|
|
|
297
|
-
const parts = [
|
|
298
|
-
|
|
299
|
-
|
|
300
|
-
|
|
301
|
-
|
|
375
|
+
const parts: string[] = [];
|
|
376
|
+
|
|
377
|
+
// Error/warning summary
|
|
378
|
+
if (latest.errors === 0 && latest.warnings === 0) {
|
|
379
|
+
parts.push("No issues");
|
|
380
|
+
} else {
|
|
381
|
+
const counts: string[] = [];
|
|
382
|
+
if (latest.errors > 0) counts.push(`${latest.errors} error${latest.errors > 1 ? "s" : ""}`);
|
|
383
|
+
if (latest.warnings > 0) counts.push(`${latest.warnings} warning${latest.warnings > 1 ? "s" : ""}`);
|
|
384
|
+
parts.push(counts.join(", "));
|
|
385
|
+
}
|
|
386
|
+
|
|
387
|
+
parts.push(`trend ${trendLabel}`);
|
|
388
|
+
|
|
389
|
+
if (totalFixes > 0) {
|
|
390
|
+
parts.push(`${totalFixes} fix${totalFixes > 1 ? "es" : ""} applied`);
|
|
391
|
+
}
|
|
302
392
|
|
|
303
393
|
if (consecutiveErrorUnits > 0) {
|
|
304
|
-
parts.push(
|
|
394
|
+
parts.push(`${consecutiveErrorUnits} of ${ESCALATION_THRESHOLD} consecutive errors before escalation`);
|
|
395
|
+
}
|
|
396
|
+
|
|
397
|
+
// Include top issue from latest snapshot
|
|
398
|
+
if (latest.issues.length > 0) {
|
|
399
|
+
const topIssue = latest.issues.find(i => i.severity === "error") ?? latest.issues[0]!;
|
|
400
|
+
parts.push(`latest: ${topIssue.message}`);
|
|
305
401
|
}
|
|
306
402
|
|
|
307
|
-
return parts.join("
|
|
403
|
+
return parts.join(" · ");
|
|
308
404
|
}
|
|
309
405
|
|
|
310
406
|
/**
|
|
@@ -51,10 +51,12 @@ function modelToProviderId(model: string): string | null {
|
|
|
51
51
|
const prefix = model.split("/")[0].toLowerCase();
|
|
52
52
|
// Map known prefixes to registry IDs
|
|
53
53
|
const prefixMap: Record<string, string> = {
|
|
54
|
+
"anthropic-vertex": "anthropic-vertex",
|
|
54
55
|
openrouter: "openrouter",
|
|
55
56
|
groq: "groq",
|
|
56
57
|
mistral: "mistral",
|
|
57
58
|
google: "google",
|
|
59
|
+
"google-vertex": "google-vertex",
|
|
58
60
|
anthropic: "anthropic",
|
|
59
61
|
openai: "openai",
|
|
60
62
|
"github-copilot": "github-copilot",
|
|
@@ -88,11 +90,20 @@ function collectConfiguredModelProviders(): Set<string> {
|
|
|
88
90
|
|
|
89
91
|
const modelEntries = typeof models === "object" ? Object.values(models) : [];
|
|
90
92
|
for (const entry of modelEntries) {
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
93
|
+
if (typeof entry === "string") {
|
|
94
|
+
const pid = modelToProviderId(entry);
|
|
95
|
+
if (pid) providers.add(pid);
|
|
96
|
+
continue;
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
if (typeof entry === "object" && entry !== null && "model" in entry) {
|
|
100
|
+
const configuredProvider = "provider" in entry ? (entry as { provider?: unknown }).provider : undefined;
|
|
101
|
+
if (typeof configuredProvider === "string" && configuredProvider.trim().length > 0) {
|
|
102
|
+
providers.add(configuredProvider);
|
|
103
|
+
continue;
|
|
104
|
+
}
|
|
105
|
+
|
|
106
|
+
const modelId = String((entry as { model: unknown }).model);
|
|
96
107
|
const pid = modelToProviderId(modelId);
|
|
97
108
|
if (pid) providers.add(pid);
|
|
98
109
|
}
|
|
@@ -117,6 +128,10 @@ interface KeyLookup {
|
|
|
117
128
|
function resolveKey(providerId: string): KeyLookup {
|
|
118
129
|
const info = PROVIDER_REGISTRY.find(p => p.id === providerId);
|
|
119
130
|
|
|
131
|
+
if (providerId === "anthropic-vertex" && process.env.ANTHROPIC_VERTEX_PROJECT_ID) {
|
|
132
|
+
return { found: true, source: "env", backedOff: false };
|
|
133
|
+
}
|
|
134
|
+
|
|
120
135
|
// Check auth.json
|
|
121
136
|
const authPath = getAuthPath();
|
|
122
137
|
if (existsSync(authPath)) {
|
|
@@ -175,7 +190,9 @@ function checkLlmProviders(): ProviderCheckResult[] {
|
|
|
175
190
|
|
|
176
191
|
for (const providerId of required) {
|
|
177
192
|
const info = PROVIDER_REGISTRY.find(p => p.id === providerId);
|
|
178
|
-
const label =
|
|
193
|
+
const label = providerId === "anthropic-vertex"
|
|
194
|
+
? "Anthropic Vertex"
|
|
195
|
+
: info?.label ?? providerId;
|
|
179
196
|
const lookup = resolveKey(providerId);
|
|
180
197
|
|
|
181
198
|
if (!lookup.found) {
|
|
@@ -196,14 +213,18 @@ function checkLlmProviders(): ProviderCheckResult[] {
|
|
|
196
213
|
continue;
|
|
197
214
|
}
|
|
198
215
|
|
|
199
|
-
const envVar =
|
|
216
|
+
const envVar = providerId === "anthropic-vertex"
|
|
217
|
+
? "ANTHROPIC_VERTEX_PROJECT_ID"
|
|
218
|
+
: info?.envVar ?? `${providerId.toUpperCase()}_API_KEY`;
|
|
200
219
|
results.push({
|
|
201
220
|
name: providerId,
|
|
202
221
|
label,
|
|
203
222
|
category: "llm",
|
|
204
223
|
status: "error",
|
|
205
|
-
message: `${label} —
|
|
206
|
-
detail:
|
|
224
|
+
message: `${label} — not configured`,
|
|
225
|
+
detail: providerId === "anthropic-vertex"
|
|
226
|
+
? "Set ANTHROPIC_VERTEX_PROJECT_ID and authenticate with Google ADC"
|
|
227
|
+
: info?.hasOAuth
|
|
207
228
|
? `Run /gsd keys to authenticate`
|
|
208
229
|
: `Set ${envVar} or run /gsd keys`,
|
|
209
230
|
required: true,
|
|
@@ -53,7 +53,20 @@ export type DoctorIssueCode =
|
|
|
53
53
|
| "stranded_lock_directory"
|
|
54
54
|
// Git / worktree integrity checks
|
|
55
55
|
| "integration_branch_missing"
|
|
56
|
-
| "worktree_directory_orphaned"
|
|
56
|
+
| "worktree_directory_orphaned"
|
|
57
|
+
// GSD state structural checks
|
|
58
|
+
| "circular_slice_dependency"
|
|
59
|
+
| "orphaned_slice_directory"
|
|
60
|
+
| "duplicate_task_id"
|
|
61
|
+
| "task_file_not_in_plan"
|
|
62
|
+
| "stale_replan_file"
|
|
63
|
+
| "future_timestamp"
|
|
64
|
+
// Runtime data integrity
|
|
65
|
+
| "metrics_ledger_corrupt"
|
|
66
|
+
| "large_planning_file"
|
|
67
|
+
// Slow environment checks (opt-in via --build / --test flags)
|
|
68
|
+
| "env_build"
|
|
69
|
+
| "env_test";
|
|
57
70
|
|
|
58
71
|
/**
|
|
59
72
|
* Issue codes that represent expected completion-transition states.
|
|
@@ -83,6 +96,8 @@ export interface DoctorReport {
|
|
|
83
96
|
basePath: string;
|
|
84
97
|
issues: DoctorIssue[];
|
|
85
98
|
fixesApplied: string[];
|
|
99
|
+
/** Per-domain check durations in milliseconds. Present on explicit /gsd doctor runs. */
|
|
100
|
+
timing?: { git: number; runtime: number; environment: number; gsdState: number };
|
|
86
101
|
}
|
|
87
102
|
|
|
88
103
|
export interface DoctorSummary {
|