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
|
@@ -10,6 +10,7 @@ import { execFileSync } from "node:child_process";
|
|
|
10
10
|
import { existsSync, lstatSync, mkdirSync, readFileSync, realpathSync, rmSync, symlinkSync } from "node:fs";
|
|
11
11
|
import { homedir } from "node:os";
|
|
12
12
|
import { join, resolve } from "node:path";
|
|
13
|
+
const gsdHome = process.env.GSD_HOME || join(homedir(), ".gsd");
|
|
13
14
|
// ─── Repo Identity ──────────────────────────────────────────────────────────
|
|
14
15
|
/**
|
|
15
16
|
* Get the git remote URL for "origin", or "" if no remote is configured.
|
|
@@ -84,14 +85,30 @@ function resolveGitRoot(basePath) {
|
|
|
84
85
|
return resolve(basePath);
|
|
85
86
|
}
|
|
86
87
|
}
|
|
88
|
+
/**
|
|
89
|
+
* Validate a GSD_PROJECT_ID value.
|
|
90
|
+
*
|
|
91
|
+
* Must contain only alphanumeric characters, hyphens, and underscores.
|
|
92
|
+
* Call this once at startup so the user gets immediate feedback on bad values.
|
|
93
|
+
*/
|
|
94
|
+
export function validateProjectId(id) {
|
|
95
|
+
return /^[a-zA-Z0-9_-]+$/.test(id);
|
|
96
|
+
}
|
|
87
97
|
/**
|
|
88
98
|
* Compute a stable identity for a repository.
|
|
89
99
|
*
|
|
90
|
-
*
|
|
91
|
-
*
|
|
92
|
-
*
|
|
100
|
+
* If `GSD_PROJECT_ID` is set, returns it directly (validation is expected
|
|
101
|
+
* to have already happened at startup via `validateProjectId`).
|
|
102
|
+
*
|
|
103
|
+
* Otherwise returns SHA-256 of `${remoteUrl}\n${resolvedRoot}`, truncated
|
|
104
|
+
* to 12 hex chars. Deterministic: same repo always produces the same hash
|
|
105
|
+
* regardless of which worktree the caller is inside.
|
|
93
106
|
*/
|
|
94
107
|
export function repoIdentity(basePath) {
|
|
108
|
+
const projectId = process.env.GSD_PROJECT_ID;
|
|
109
|
+
if (projectId) {
|
|
110
|
+
return projectId;
|
|
111
|
+
}
|
|
95
112
|
const remoteUrl = getRemoteUrl(basePath);
|
|
96
113
|
const root = resolveGitRoot(basePath);
|
|
97
114
|
const input = `${remoteUrl}\n${root}`;
|
|
@@ -105,7 +122,7 @@ export function repoIdentity(basePath) {
|
|
|
105
122
|
* otherwise `~/.gsd/projects/<hash>`.
|
|
106
123
|
*/
|
|
107
124
|
export function externalGsdRoot(basePath) {
|
|
108
|
-
const base = process.env.GSD_STATE_DIR ||
|
|
125
|
+
const base = process.env.GSD_STATE_DIR || gsdHome;
|
|
109
126
|
return join(base, "projects", repoIdentity(basePath));
|
|
110
127
|
}
|
|
111
128
|
// ─── Symlink Management ─────────────────────────────────────────────────────
|
|
@@ -9,6 +9,7 @@ import { loadJsonFileOrNull } from "./json-persistence.js";
|
|
|
9
9
|
import { join } from "node:path";
|
|
10
10
|
import { homedir } from "node:os";
|
|
11
11
|
import { resolveProjectRoot } from "./worktree.js";
|
|
12
|
+
const gsdHome = process.env.GSD_HOME || join(homedir(), ".gsd");
|
|
12
13
|
// ─── Resource Staleness ───────────────────────────────────────────────────
|
|
13
14
|
/**
|
|
14
15
|
* Read the resource version (semver) from the managed-resources manifest.
|
|
@@ -19,7 +20,7 @@ function isManifestWithVersion(data) {
|
|
|
19
20
|
return data !== null && typeof data === "object" && "gsdVersion" in data && typeof data.gsdVersion === "string";
|
|
20
21
|
}
|
|
21
22
|
export function readResourceVersion() {
|
|
22
|
-
const agentDir = process.env.GSD_CODING_AGENT_DIR || join(
|
|
23
|
+
const agentDir = process.env.GSD_CODING_AGENT_DIR || join(gsdHome, "agent");
|
|
23
24
|
const manifestPath = join(agentDir, "managed-resources.json");
|
|
24
25
|
const manifest = loadJsonFileOrNull(manifestPath, isManifestWithVersion);
|
|
25
26
|
return manifest?.gsdVersion ?? null;
|
|
@@ -32,6 +32,30 @@ export function markSliceDoneInRoadmap(basePath, mid, sid) {
|
|
|
32
32
|
clearParseCache();
|
|
33
33
|
return true;
|
|
34
34
|
}
|
|
35
|
+
/**
|
|
36
|
+
* Mark a slice as not done ([ ]) in the milestone roadmap.
|
|
37
|
+
* Idempotent — no-op if already unchecked or if the slice isn't found.
|
|
38
|
+
*
|
|
39
|
+
* @returns true if the roadmap was modified, false if no change was needed
|
|
40
|
+
*/
|
|
41
|
+
export function markSliceUndoneInRoadmap(basePath, mid, sid) {
|
|
42
|
+
const roadmapFile = resolveMilestoneFile(basePath, mid, "ROADMAP");
|
|
43
|
+
if (!roadmapFile)
|
|
44
|
+
return false;
|
|
45
|
+
let content;
|
|
46
|
+
try {
|
|
47
|
+
content = readFileSync(roadmapFile, "utf-8");
|
|
48
|
+
}
|
|
49
|
+
catch {
|
|
50
|
+
return false;
|
|
51
|
+
}
|
|
52
|
+
const updated = content.replace(new RegExp(`^(\\s*-\\s+)\\[x\\]\\s+\\*\\*${sid}:`, "m"), `$1[ ] **${sid}:`);
|
|
53
|
+
if (updated === content)
|
|
54
|
+
return false;
|
|
55
|
+
atomicWriteSync(roadmapFile, updated);
|
|
56
|
+
clearParseCache();
|
|
57
|
+
return true;
|
|
58
|
+
}
|
|
35
59
|
/**
|
|
36
60
|
* Mark a task as done ([x]) in the slice plan.
|
|
37
61
|
* Idempotent — no-op if already checked or if the task isn't found.
|
|
@@ -3,7 +3,7 @@
|
|
|
3
3
|
// Pure TypeScript, zero Pi dependencies.
|
|
4
4
|
import { parseRoadmap, parsePlan, parseSummary, loadFile, parseRequirementCounts, parseContextDependsOn, } from './files.js';
|
|
5
5
|
import { resolveMilestoneFile, resolveSlicePath, resolveSliceFile, resolveTaskFile, resolveTasksDir, resolveGsdRootFile, gsdRoot, } from './paths.js';
|
|
6
|
-
import { findMilestoneIds } from './
|
|
6
|
+
import { findMilestoneIds } from './milestone-ids.js';
|
|
7
7
|
import { nativeBatchParseGsdFiles } from './native-parser-bridge.js';
|
|
8
8
|
import { join, resolve } from 'path';
|
|
9
9
|
import { existsSync, readdirSync } from 'node:fs';
|
|
@@ -82,8 +82,13 @@ export async function getActiveMilestoneId(basePath) {
|
|
|
82
82
|
// A draft milestone is still "active" — this function only determines which milestone is current.
|
|
83
83
|
}
|
|
84
84
|
const roadmap = parseRoadmap(content);
|
|
85
|
-
if (!isMilestoneComplete(roadmap))
|
|
86
|
-
|
|
85
|
+
if (!isMilestoneComplete(roadmap)) {
|
|
86
|
+
// Summary is the terminal artifact — if it exists, the milestone is
|
|
87
|
+
// complete even when roadmap checkboxes weren't ticked (#864).
|
|
88
|
+
const summaryFile = resolveMilestoneFile(basePath, mid, "SUMMARY");
|
|
89
|
+
if (!summaryFile)
|
|
90
|
+
return mid;
|
|
91
|
+
}
|
|
87
92
|
}
|
|
88
93
|
return null;
|
|
89
94
|
}
|
|
@@ -202,8 +207,14 @@ async function _deriveStateImpl(basePath) {
|
|
|
202
207
|
}
|
|
203
208
|
const rmap = parseRoadmap(rc);
|
|
204
209
|
roadmapCache.set(mid, rmap);
|
|
205
|
-
if (!isMilestoneComplete(rmap))
|
|
210
|
+
if (!isMilestoneComplete(rmap)) {
|
|
211
|
+
// Summary is the terminal artifact — if it exists, the milestone is
|
|
212
|
+
// complete even when roadmap checkboxes weren't ticked (#864).
|
|
213
|
+
const sf = resolveMilestoneFile(basePath, mid, "SUMMARY");
|
|
214
|
+
if (sf)
|
|
215
|
+
completeMilestoneIds.add(mid);
|
|
206
216
|
continue;
|
|
217
|
+
}
|
|
207
218
|
const sf = resolveMilestoneFile(basePath, mid, "SUMMARY");
|
|
208
219
|
if (sf)
|
|
209
220
|
completeMilestoneIds.add(mid);
|
|
@@ -303,29 +314,37 @@ async function _deriveStateImpl(basePath) {
|
|
|
303
314
|
registry.push({ id: mid, title, status: 'complete' });
|
|
304
315
|
}
|
|
305
316
|
}
|
|
306
|
-
else
|
|
307
|
-
//
|
|
308
|
-
|
|
309
|
-
const
|
|
310
|
-
|
|
311
|
-
|
|
312
|
-
|
|
313
|
-
|
|
314
|
-
//
|
|
317
|
+
else {
|
|
318
|
+
// Roadmap slices not all checked — but if a summary exists, the milestone
|
|
319
|
+
// is still complete. The summary is the terminal artifact (#864).
|
|
320
|
+
const summaryFile = resolveMilestoneFile(basePath, mid, "SUMMARY");
|
|
321
|
+
if (summaryFile) {
|
|
322
|
+
registry.push({ id: mid, title, status: 'complete' });
|
|
323
|
+
}
|
|
324
|
+
else if (!activeMilestoneFound) {
|
|
325
|
+
// Check milestone-level dependencies before promoting to active
|
|
326
|
+
const contextFile = resolveMilestoneFile(basePath, mid, "CONTEXT");
|
|
327
|
+
const contextContent = contextFile ? await cachedLoadFile(contextFile) : null;
|
|
328
|
+
const deps = parseContextDependsOn(contextContent);
|
|
329
|
+
const depsUnmet = deps.some(dep => !completeMilestoneIds.has(dep));
|
|
330
|
+
if (depsUnmet) {
|
|
331
|
+
registry.push({ id: mid, title, status: 'pending', dependsOn: deps });
|
|
332
|
+
// Do NOT set activeMilestoneFound — let the loop continue to the next milestone
|
|
333
|
+
}
|
|
334
|
+
else {
|
|
335
|
+
activeMilestone = { id: mid, title };
|
|
336
|
+
activeRoadmap = roadmap;
|
|
337
|
+
activeMilestoneFound = true;
|
|
338
|
+
registry.push({ id: mid, title, status: 'active', ...(deps.length > 0 ? { dependsOn: deps } : {}) });
|
|
339
|
+
}
|
|
315
340
|
}
|
|
316
341
|
else {
|
|
317
|
-
|
|
318
|
-
|
|
319
|
-
|
|
320
|
-
registry.push({ id: mid, title, status: '
|
|
342
|
+
const contextFile2 = resolveMilestoneFile(basePath, mid, "CONTEXT");
|
|
343
|
+
const contextContent2 = contextFile2 ? await cachedLoadFile(contextFile2) : null;
|
|
344
|
+
const deps2 = parseContextDependsOn(contextContent2);
|
|
345
|
+
registry.push({ id: mid, title, status: 'pending', ...(deps2.length > 0 ? { dependsOn: deps2 } : {}) });
|
|
321
346
|
}
|
|
322
347
|
}
|
|
323
|
-
else {
|
|
324
|
-
const contextFile2 = resolveMilestoneFile(basePath, mid, "CONTEXT");
|
|
325
|
-
const contextContent2 = contextFile2 ? await cachedLoadFile(contextFile2) : null;
|
|
326
|
-
const deps2 = parseContextDependsOn(contextContent2);
|
|
327
|
-
registry.push({ id: mid, title, status: 'pending', ...(deps2.length > 0 ? { dependsOn: deps2 } : {}) });
|
|
328
|
-
}
|
|
329
348
|
}
|
|
330
349
|
const milestoneProgress = {
|
|
331
350
|
done: registry.filter(entry => entry.status === 'complete').length,
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
# Runtime Context
|
|
2
|
+
|
|
3
|
+
## Stack
|
|
4
|
+
- **Language:** (e.g., TypeScript, Python, Go)
|
|
5
|
+
- **Framework:** (e.g., Next.js, FastAPI, Gin)
|
|
6
|
+
- **Build:** (e.g., npm run build, cargo build)
|
|
7
|
+
- **Test:** (e.g., npm run test, pytest)
|
|
8
|
+
- **Lint:** (e.g., npm run lint, ruff check)
|
|
9
|
+
|
|
10
|
+
## Environment
|
|
11
|
+
- **Node version:** (e.g., 20.x)
|
|
12
|
+
- **Package manager:** (e.g., npm, pnpm, yarn)
|
|
13
|
+
- **Required env vars:** (list any needed for local dev)
|
|
14
|
+
|
|
15
|
+
## Dev Server
|
|
16
|
+
- **Start command:** (e.g., npm run dev)
|
|
17
|
+
- **Default port:** (e.g., 3000)
|
|
18
|
+
- **Health check:** (e.g., curl http://localhost:3000/health)
|
|
19
|
+
|
|
20
|
+
## Notes
|
|
21
|
+
(Any runtime-specific context the executor needs to know)
|
|
@@ -3,6 +3,9 @@
|
|
|
3
3
|
# Tasks with 10+ estimated steps or 12+ estimated files trigger a warning to consider splitting.
|
|
4
4
|
estimated_steps: {{estimatedSteps}}
|
|
5
5
|
estimated_files: {{estimatedFiles}}
|
|
6
|
+
# Installed skills the planner expects the executor to load before coding.
|
|
7
|
+
skills_used:
|
|
8
|
+
- {{skillName}}
|
|
6
9
|
---
|
|
7
10
|
|
|
8
11
|
# {{taskId}}: {{taskTitle}}
|
|
@@ -1,15 +1,18 @@
|
|
|
1
1
|
// Data loader for workflow visualizer overlay — aggregates state + metrics.
|
|
2
2
|
import { existsSync, readFileSync, statSync } from 'node:fs';
|
|
3
|
+
import { join } from 'node:path';
|
|
3
4
|
import { deriveState } from './state.js';
|
|
4
5
|
import { parseRoadmap, parsePlan, parseSummary, loadFile } from './files.js';
|
|
5
|
-
import { findMilestoneIds } from './
|
|
6
|
-
import { resolveMilestoneFile, resolveSliceFile, resolveGsdRootFile } from './paths.js';
|
|
6
|
+
import { findMilestoneIds } from './milestone-ids.js';
|
|
7
|
+
import { resolveMilestoneFile, resolveSliceFile, resolveGsdRootFile, gsdRoot } from './paths.js';
|
|
7
8
|
import { getLedger, getProjectTotals, aggregateByPhase, aggregateBySlice, aggregateByModel, aggregateByTier, formatTierSavings, loadLedgerFromDisk, } from './metrics.js';
|
|
8
9
|
import { loadAllCaptures, countPendingCaptures } from './captures.js';
|
|
9
10
|
import { loadEffectiveGSDPreferences } from './preferences.js';
|
|
10
11
|
import { runProviderChecks } from './doctor-providers.js';
|
|
11
12
|
import { generateSkillHealthReport } from './skill-health.js';
|
|
12
13
|
import { runEnvironmentChecks } from './doctor-environment.js';
|
|
14
|
+
import { computeProgressScore } from './progress-score.js';
|
|
15
|
+
import { getHealthHistory } from './doctor-proactive.js';
|
|
13
16
|
// ─── Critical Path ────────────────────────────────────────────────────────────
|
|
14
17
|
export function computeCriticalPath(milestones) {
|
|
15
18
|
const empty = {
|
|
@@ -392,6 +395,26 @@ function loadHealth(units, totals, basePath) {
|
|
|
392
395
|
environmentIssues = runEnvironmentChecks(basePath).filter(r => r.status !== "ok");
|
|
393
396
|
}
|
|
394
397
|
catch { /* non-fatal */ }
|
|
398
|
+
// Doctor run history — persisted across sessions (sync read to keep loadHealth sync)
|
|
399
|
+
let doctorHistory = [];
|
|
400
|
+
try {
|
|
401
|
+
const historyPath = join(gsdRoot(basePath), "doctor-history.jsonl");
|
|
402
|
+
if (existsSync(historyPath)) {
|
|
403
|
+
const lines = readFileSync(historyPath, "utf-8").split("\n").filter(l => l.trim());
|
|
404
|
+
doctorHistory = lines.slice(-20).reverse().map(l => JSON.parse(l));
|
|
405
|
+
}
|
|
406
|
+
}
|
|
407
|
+
catch { /* non-fatal */ }
|
|
408
|
+
// Current progress score — only meaningful when auto-mode has health data
|
|
409
|
+
let progressScore = null;
|
|
410
|
+
try {
|
|
411
|
+
const history = getHealthHistory();
|
|
412
|
+
if (history.length > 0) {
|
|
413
|
+
const score = computeProgressScore();
|
|
414
|
+
progressScore = { level: score.level, summary: score.summary, signals: score.signals };
|
|
415
|
+
}
|
|
416
|
+
}
|
|
417
|
+
catch { /* non-fatal */ }
|
|
395
418
|
return {
|
|
396
419
|
budgetCeiling,
|
|
397
420
|
tokenProfile,
|
|
@@ -405,6 +428,8 @@ function loadHealth(units, totals, basePath) {
|
|
|
405
428
|
providers,
|
|
406
429
|
skillSummary,
|
|
407
430
|
environmentIssues,
|
|
431
|
+
doctorHistory,
|
|
432
|
+
progressScore,
|
|
408
433
|
};
|
|
409
434
|
}
|
|
410
435
|
const RECENT_ENTRY_LIMIT = 3;
|
|
@@ -872,6 +872,58 @@ export function renderHealthView(data, th, width) {
|
|
|
872
872
|
}
|
|
873
873
|
}
|
|
874
874
|
}
|
|
875
|
+
// Progress score section — current traffic light status
|
|
876
|
+
if (health.progressScore) {
|
|
877
|
+
lines.push("");
|
|
878
|
+
lines.push(th.fg("accent", th.bold("Progress Score")));
|
|
879
|
+
lines.push("");
|
|
880
|
+
const ps = health.progressScore;
|
|
881
|
+
const scoreColor = ps.level === "green" ? "success" : ps.level === "yellow" ? "warning" : "error";
|
|
882
|
+
const scoreIcon = ps.level === "green" ? "●" : ps.level === "yellow" ? "◐" : "○";
|
|
883
|
+
lines.push(` ${th.fg(scoreColor, scoreIcon)} ${th.fg(scoreColor, ps.summary)}`);
|
|
884
|
+
for (const signal of ps.signals) {
|
|
885
|
+
const prefix = signal.kind === "positive" ? th.fg("success", " ✓")
|
|
886
|
+
: signal.kind === "negative" ? th.fg("error", " ✗")
|
|
887
|
+
: th.fg("dim", " ·");
|
|
888
|
+
lines.push(` ${prefix} ${th.fg("dim", signal.label)}`);
|
|
889
|
+
}
|
|
890
|
+
}
|
|
891
|
+
// Doctor history section — persisted across sessions
|
|
892
|
+
const doctorHistory = health.doctorHistory ?? [];
|
|
893
|
+
if (doctorHistory.length > 0) {
|
|
894
|
+
lines.push("");
|
|
895
|
+
lines.push(th.fg("accent", th.bold("Doctor History")));
|
|
896
|
+
lines.push("");
|
|
897
|
+
for (const entry of doctorHistory.slice(0, 10)) {
|
|
898
|
+
const icon = entry.ok ? th.fg("success", "✓") : th.fg("error", "✗");
|
|
899
|
+
const ts = entry.ts.replace("T", " ").slice(0, 19);
|
|
900
|
+
const scopeTag = entry.scope ? th.fg("accent", ` [${entry.scope}]`) : "";
|
|
901
|
+
// Prefer human-readable summary, fall back to counts
|
|
902
|
+
const detail = entry.summary
|
|
903
|
+
? th.fg("text", entry.summary)
|
|
904
|
+
: th.fg("text", `${entry.errors} errors, ${entry.warnings} warnings, ${entry.fixes} fixes`);
|
|
905
|
+
lines.push(` ${icon} ${th.fg("dim", ts)}${scopeTag} ${detail}`);
|
|
906
|
+
// Show issue details if available
|
|
907
|
+
if (entry.issues && entry.issues.length > 0) {
|
|
908
|
+
for (const issue of entry.issues.slice(0, 3)) {
|
|
909
|
+
const issuePfx = issue.severity === "error" ? th.fg("error", " ✗") : th.fg("warning", " ⚠");
|
|
910
|
+
lines.push(` ${issuePfx} ${th.fg("dim", truncateToWidth(issue.message, width - 12))}`);
|
|
911
|
+
}
|
|
912
|
+
if (entry.issues.length > 3) {
|
|
913
|
+
lines.push(` ${th.fg("dim", `+${entry.issues.length - 3} more`)}`);
|
|
914
|
+
}
|
|
915
|
+
}
|
|
916
|
+
// Show fixes if available
|
|
917
|
+
if (entry.fixDescriptions && entry.fixDescriptions.length > 0) {
|
|
918
|
+
for (const fix of entry.fixDescriptions.slice(0, 2)) {
|
|
919
|
+
lines.push(` ${th.fg("success", "↳")} ${th.fg("dim", truncateToWidth(fix, width - 12))}`);
|
|
920
|
+
}
|
|
921
|
+
}
|
|
922
|
+
}
|
|
923
|
+
if (doctorHistory.length > 10) {
|
|
924
|
+
lines.push(` ${th.fg("dim", `...${doctorHistory.length - 10} older entries`)}`);
|
|
925
|
+
}
|
|
926
|
+
}
|
|
875
927
|
// Skills section
|
|
876
928
|
if (health.skillSummary?.total > 0) {
|
|
877
929
|
lines.push("");
|
|
@@ -57,42 +57,61 @@ export function captureIntegrationBranch(basePath, milestoneId, options) {
|
|
|
57
57
|
writeIntegrationBranch(basePath, milestoneId, current, options);
|
|
58
58
|
}
|
|
59
59
|
// ─── Pure Utility Functions (unchanged) ────────────────────────────────────
|
|
60
|
+
/**
|
|
61
|
+
* Find the worktrees segment in a path, supporting both direct
|
|
62
|
+
* (`/.gsd/worktrees/`) and symlink-resolved (`/.gsd/projects/<hash>/worktrees/`)
|
|
63
|
+
* layouts. When `.gsd` is a symlink to `~/.gsd/projects/<hash>`, resolved
|
|
64
|
+
* paths contain the intermediate `projects/<hash>/` segment that the old
|
|
65
|
+
* single-marker check missed.
|
|
66
|
+
*/
|
|
67
|
+
function findWorktreeSegment(normalizedPath) {
|
|
68
|
+
// Direct layout: /.gsd/worktrees/<name>
|
|
69
|
+
const directMarker = "/.gsd/worktrees/";
|
|
70
|
+
const idx = normalizedPath.indexOf(directMarker);
|
|
71
|
+
if (idx !== -1) {
|
|
72
|
+
return { gsdIdx: idx, afterWorktrees: idx + directMarker.length };
|
|
73
|
+
}
|
|
74
|
+
// Symlink-resolved layout: /.gsd/projects/<hash>/worktrees/<name>
|
|
75
|
+
const symlinkRe = /\/\.gsd\/projects\/[a-f0-9]+\/worktrees\//;
|
|
76
|
+
const match = normalizedPath.match(symlinkRe);
|
|
77
|
+
if (match && match.index !== undefined) {
|
|
78
|
+
return { gsdIdx: match.index, afterWorktrees: match.index + match[0].length };
|
|
79
|
+
}
|
|
80
|
+
return null;
|
|
81
|
+
}
|
|
60
82
|
/**
|
|
61
83
|
* Detect the active worktree name from the current working directory.
|
|
62
84
|
* Returns null if not inside a GSD worktree (.gsd/worktrees/<name>/).
|
|
63
85
|
*/
|
|
64
86
|
export function detectWorktreeName(basePath) {
|
|
65
87
|
const normalizedPath = basePath.replaceAll("\\", "/");
|
|
66
|
-
const
|
|
67
|
-
|
|
68
|
-
if (idx === -1)
|
|
88
|
+
const seg = findWorktreeSegment(normalizedPath);
|
|
89
|
+
if (!seg)
|
|
69
90
|
return null;
|
|
70
|
-
const afterMarker = normalizedPath.slice(
|
|
91
|
+
const afterMarker = normalizedPath.slice(seg.afterWorktrees);
|
|
71
92
|
const name = afterMarker.split("/")[0];
|
|
72
93
|
return name || null;
|
|
73
94
|
}
|
|
74
95
|
/**
|
|
75
96
|
* Resolve the project root from a path that may be inside a worktree.
|
|
76
|
-
* If the path contains
|
|
77
|
-
*
|
|
97
|
+
* If the path contains a worktrees segment, returns the portion before
|
|
98
|
+
* `/.gsd/`. Otherwise returns the input unchanged.
|
|
78
99
|
*
|
|
79
100
|
* Use this in commands that call `process.cwd()` to ensure they always
|
|
80
101
|
* operate against the real project root, not a worktree subdirectory.
|
|
81
102
|
*/
|
|
82
103
|
export function resolveProjectRoot(basePath) {
|
|
83
104
|
const normalizedPath = basePath.replaceAll("\\", "/");
|
|
84
|
-
const
|
|
85
|
-
|
|
86
|
-
if (idx === -1)
|
|
105
|
+
const seg = findWorktreeSegment(normalizedPath);
|
|
106
|
+
if (!seg)
|
|
87
107
|
return basePath;
|
|
88
|
-
// Return the original path up to the
|
|
89
|
-
// Account for potential OS-specific separators
|
|
108
|
+
// Return the original path up to the /.gsd/ boundary
|
|
90
109
|
const sep = basePath.includes("\\") ? "\\" : "/";
|
|
91
|
-
const
|
|
92
|
-
const
|
|
93
|
-
if (
|
|
94
|
-
return basePath.slice(0,
|
|
95
|
-
return basePath.slice(0,
|
|
110
|
+
const gsdMarker = `${sep}.gsd${sep}`;
|
|
111
|
+
const gsdIdx = basePath.indexOf(gsdMarker);
|
|
112
|
+
if (gsdIdx !== -1)
|
|
113
|
+
return basePath.slice(0, gsdIdx);
|
|
114
|
+
return basePath.slice(0, seg.gsdIdx);
|
|
96
115
|
}
|
|
97
116
|
/**
|
|
98
117
|
* Get the slice branch name, namespaced by worktree when inside one.
|
|
@@ -76,6 +76,19 @@ function readConfigs() {
|
|
|
76
76
|
function getServerConfig(name) {
|
|
77
77
|
return readConfigs().find((s) => s.name === name);
|
|
78
78
|
}
|
|
79
|
+
/** Resolve ${VAR} references in env values against process.env. */
|
|
80
|
+
function resolveEnv(env) {
|
|
81
|
+
const resolved = {};
|
|
82
|
+
for (const [key, value] of Object.entries(env)) {
|
|
83
|
+
if (typeof value === "string") {
|
|
84
|
+
resolved[key] = value.replace(/\$\{([^}]+)\}/g, (_match, varName) => process.env[varName] ?? "");
|
|
85
|
+
}
|
|
86
|
+
else {
|
|
87
|
+
resolved[key] = value;
|
|
88
|
+
}
|
|
89
|
+
}
|
|
90
|
+
return resolved;
|
|
91
|
+
}
|
|
79
92
|
async function getOrConnect(name, signal) {
|
|
80
93
|
const existing = connections.get(name);
|
|
81
94
|
if (existing)
|
|
@@ -89,7 +102,7 @@ async function getOrConnect(name, signal) {
|
|
|
89
102
|
transport = new StdioClientTransport({
|
|
90
103
|
command: config.command,
|
|
91
104
|
args: config.args,
|
|
92
|
-
env: config.env ? { ...process.env, ...config.env } : undefined,
|
|
105
|
+
env: config.env ? { ...process.env, ...resolveEnv(config.env) } : undefined,
|
|
93
106
|
cwd: config.cwd,
|
|
94
107
|
stderr: "pipe",
|
|
95
108
|
});
|
|
@@ -5,8 +5,11 @@ import { existsSync, readdirSync } from "node:fs";
|
|
|
5
5
|
import { join } from "node:path";
|
|
6
6
|
import { homedir } from "node:os";
|
|
7
7
|
import { readPromptRecord } from "./store.js";
|
|
8
|
+
function getGsdHome() {
|
|
9
|
+
return process.env.GSD_HOME || join(homedir(), ".gsd");
|
|
10
|
+
}
|
|
8
11
|
export function getLatestPromptSummary() {
|
|
9
|
-
const runtimeDir = join(
|
|
12
|
+
const runtimeDir = join(getGsdHome(), "runtime", "remote-questions");
|
|
10
13
|
if (!existsSync(runtimeDir))
|
|
11
14
|
return null;
|
|
12
15
|
const files = readdirSync(runtimeDir).filter((f) => f.endsWith(".json"));
|
|
@@ -4,8 +4,11 @@
|
|
|
4
4
|
import { existsSync, mkdirSync, readFileSync, writeFileSync } from "node:fs";
|
|
5
5
|
import { join } from "node:path";
|
|
6
6
|
import { homedir } from "node:os";
|
|
7
|
+
function getGsdHome() {
|
|
8
|
+
return process.env.GSD_HOME || join(homedir(), ".gsd");
|
|
9
|
+
}
|
|
7
10
|
function runtimeDir() {
|
|
8
|
-
return join(
|
|
11
|
+
return join(getGsdHome(), "runtime", "remote-questions");
|
|
9
12
|
}
|
|
10
13
|
function recordPath(id) {
|
|
11
14
|
return join(runtimeDir(), `${id}.json`);
|
|
@@ -15,7 +15,8 @@ import { resolveSearchProviderFromPreferences } from '../gsd/preferences.js';
|
|
|
15
15
|
// Compute authFilePath locally instead of importing from app-paths.ts,
|
|
16
16
|
// because extensions are copied to ~/.gsd/agent/extensions/ at runtime
|
|
17
17
|
// where the relative import '../../../app-paths.ts' doesn't resolve.
|
|
18
|
-
const
|
|
18
|
+
const gsdHome = process.env.GSD_HOME || join(homedir(), '.gsd');
|
|
19
|
+
const authFilePath = join(gsdHome, 'agent', 'auth.json');
|
|
19
20
|
const VALID_PREFERENCES = new Set(['tavily', 'brave', 'ollama', 'auto']);
|
|
20
21
|
const PREFERENCE_KEY = 'search_provider';
|
|
21
22
|
/** Returns the Tavily API key from the environment, or empty string if not set. */
|
|
@@ -45,7 +45,7 @@ export function parseFrontmatterMap(lines) {
|
|
|
45
45
|
continue;
|
|
46
46
|
}
|
|
47
47
|
// Array item (2-space indent)
|
|
48
|
-
const arrayMatch = line.match(/^ - (.*)$/);
|
|
48
|
+
const arrayMatch = line.match(/^ - ?(.*)$/);
|
|
49
49
|
if (arrayMatch && currentKey) {
|
|
50
50
|
// If there's a pending nested object, push it
|
|
51
51
|
if (currentObj && Object.keys(currentObj).length > 0) {
|
|
@@ -360,7 +360,7 @@ async function runSingleAgent(defaultCwd, agents, agentName, task, cwd, step, si
|
|
|
360
360
|
}
|
|
361
361
|
}
|
|
362
362
|
}
|
|
363
|
-
async function runSingleAgentInCmuxSplit(cmuxClient,
|
|
363
|
+
async function runSingleAgentInCmuxSplit(cmuxClient, directionOrSurfaceId, defaultCwd, agents, agentName, task, cwd, step, signal, onUpdate, makeDetails) {
|
|
364
364
|
const agent = agents.find((a) => a.name === agentName);
|
|
365
365
|
if (!agent) {
|
|
366
366
|
return runSingleAgent(defaultCwd, agents, agentName, task, cwd, step, signal, onUpdate, makeDetails);
|
|
@@ -397,7 +397,12 @@ async function runSingleAgentInCmuxSplit(cmuxClient, direction, defaultCwd, agen
|
|
|
397
397
|
const stdoutPath = path.join(tmpOutputDir, "stdout.jsonl");
|
|
398
398
|
const stderrPath = path.join(tmpOutputDir, "stderr.log");
|
|
399
399
|
const exitPath = path.join(tmpOutputDir, "exit.code");
|
|
400
|
-
|
|
400
|
+
// Accept either a pre-created surface ID or a direction to create a new split
|
|
401
|
+
const isDirection = directionOrSurfaceId === "right" || directionOrSurfaceId === "down"
|
|
402
|
+
|| directionOrSurfaceId === "left" || directionOrSurfaceId === "up";
|
|
403
|
+
const cmuxSurfaceId = isDirection
|
|
404
|
+
? await cmuxClient.createSplit(directionOrSurfaceId)
|
|
405
|
+
: directionOrSurfaceId;
|
|
401
406
|
if (!cmuxSurfaceId) {
|
|
402
407
|
return runSingleAgent(defaultCwd, agents, agentName, task, cwd, step, signal, onUpdate, makeDetails);
|
|
403
408
|
}
|
|
@@ -656,10 +661,14 @@ export default function (pi) {
|
|
|
656
661
|
const MAX_RETRIES = 1; // Retry failed tasks once
|
|
657
662
|
const batchId = crypto.randomUUID();
|
|
658
663
|
const batchSize = params.tasks.length;
|
|
664
|
+
// Pre-create a grid layout for cmux splits so agents get a clean tiled arrangement
|
|
665
|
+
const gridSurfaces = cmuxSplitsEnabled
|
|
666
|
+
? await cmuxClient.createGridLayout(Math.min(batchSize, MAX_CONCURRENCY))
|
|
667
|
+
: [];
|
|
659
668
|
const results = await mapWithConcurrencyLimit(params.tasks, MAX_CONCURRENCY, async (t, index) => {
|
|
660
669
|
const workerId = registerWorker(t.agent, t.task, index, batchSize, batchId);
|
|
661
670
|
const runTask = () => cmuxSplitsEnabled
|
|
662
|
-
? runSingleAgentInCmuxSplit(cmuxClient, index % 2 === 0 ? "right" : "down", ctx.cwd, agents, t.agent, t.task, t.cwd, undefined, signal, (partial) => {
|
|
671
|
+
? runSingleAgentInCmuxSplit(cmuxClient, gridSurfaces[index] ?? (index % 2 === 0 ? "right" : "down"), ctx.cwd, agents, t.agent, t.task, t.cwd, undefined, signal, (partial) => {
|
|
663
672
|
if (partial.details?.results[0]) {
|
|
664
673
|
allResults[index] = partial.details.results[0];
|
|
665
674
|
emitParallelUpdate();
|
|
@@ -17,8 +17,9 @@ const execFile = promisify(execFileCb);
|
|
|
17
17
|
function encodeCwd(cwd) {
|
|
18
18
|
return cwd.replace(/\//g, "--");
|
|
19
19
|
}
|
|
20
|
+
const gsdHome = process.env.GSD_HOME || path.join(os.homedir(), ".gsd");
|
|
20
21
|
function getIsolationBaseDir(cwd, taskId) {
|
|
21
|
-
return path.join(
|
|
22
|
+
return path.join(gsdHome, "wt", encodeCwd(cwd), taskId);
|
|
22
23
|
}
|
|
23
24
|
// Track active isolation dirs for cleanup on exit
|
|
24
25
|
const activeIsolations = new Set();
|
|
@@ -8,6 +8,7 @@
|
|
|
8
8
|
import { readdirSync, readFileSync, existsSync } from "node:fs";
|
|
9
9
|
import { join, basename } from "node:path";
|
|
10
10
|
import { homedir } from "node:os";
|
|
11
|
+
const gsdHome = process.env.GSD_HOME || join(homedir(), ".gsd");
|
|
11
12
|
import { splitFrontmatter, parseFrontmatterMap } from "../shared/frontmatter.js";
|
|
12
13
|
function parseRuleFile(filePath) {
|
|
13
14
|
let content;
|
|
@@ -56,7 +57,7 @@ function scanDir(dir) {
|
|
|
56
57
|
* Project rules override global rules with the same name.
|
|
57
58
|
*/
|
|
58
59
|
export function loadRules(cwd) {
|
|
59
|
-
const globalDir = join(
|
|
60
|
+
const globalDir = join(gsdHome, "agent", "rules");
|
|
60
61
|
const projectDir = join(cwd, ".gsd", "rules");
|
|
61
62
|
const globalRules = scanDir(globalDir);
|
|
62
63
|
const projectRules = scanDir(projectDir);
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* GSD Welcome Screen
|
|
3
|
+
*
|
|
4
|
+
* Two-panel bar layout: full-width accent bars at top/bottom (matching the
|
|
5
|
+
* auto-mode progress widget style), logo left (fixed width), info right.
|
|
6
|
+
* Falls back to simple text on narrow terminals (<70 cols) or non-TTY.
|
|
7
|
+
*/
|
|
8
|
+
export interface WelcomeScreenOptions {
|
|
9
|
+
version: string;
|
|
10
|
+
modelName?: string;
|
|
11
|
+
provider?: string;
|
|
12
|
+
}
|
|
13
|
+
export declare function printWelcomeScreen(opts: WelcomeScreenOptions): void;
|