gsd-pi 2.28.0-dev.e19bf89 → 2.29.0-dev.2ccf3fb
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 +24 -17
- package/dist/cli.js +15 -9
- package/dist/resource-loader.js +80 -8
- package/dist/resources/extensions/bg-shell/process-manager.ts +13 -0
- package/dist/resources/extensions/gsd/auto-dashboard.ts +186 -65
- package/dist/resources/extensions/gsd/auto-post-unit.ts +14 -6
- package/dist/resources/extensions/gsd/auto-recovery.ts +33 -23
- package/dist/resources/extensions/gsd/auto-start.ts +25 -10
- package/dist/resources/extensions/gsd/auto-verification.ts +41 -7
- package/dist/resources/extensions/gsd/auto-worktree-sync.ts +21 -6
- package/dist/resources/extensions/gsd/auto.ts +67 -22
- package/dist/resources/extensions/gsd/commands-handlers.ts +3 -11
- package/dist/resources/extensions/gsd/commands-logs.ts +536 -0
- package/dist/resources/extensions/gsd/commands-prefs-wizard.ts +90 -47
- package/dist/resources/extensions/gsd/commands-workflow-templates.ts +544 -0
- package/dist/resources/extensions/gsd/commands.ts +75 -29
- package/dist/resources/extensions/gsd/dashboard-overlay.ts +2 -1
- package/dist/resources/extensions/gsd/doctor-types.ts +13 -0
- package/dist/resources/extensions/gsd/doctor.ts +2 -6
- package/dist/resources/extensions/gsd/export.ts +28 -2
- package/dist/resources/extensions/gsd/gsd-db.ts +19 -0
- package/dist/resources/extensions/gsd/index.ts +2 -1
- package/dist/resources/extensions/gsd/json-persistence.ts +67 -0
- package/dist/resources/extensions/gsd/metrics.ts +17 -31
- package/dist/resources/extensions/gsd/paths.ts +0 -8
- package/dist/resources/extensions/gsd/prompts/guided-discuss-milestone.md +1 -1
- package/dist/resources/extensions/gsd/prompts/workflow-start.md +28 -0
- package/dist/resources/extensions/gsd/queue-order.ts +10 -11
- package/dist/resources/extensions/gsd/routing-history.ts +13 -17
- package/dist/resources/extensions/gsd/session-lock.ts +284 -0
- package/dist/resources/extensions/gsd/session-status-io.ts +23 -41
- package/dist/resources/extensions/gsd/tests/auto-budget-alerts.test.ts +1 -1
- package/dist/resources/extensions/gsd/tests/auto-skip-loop.test.ts +1 -1
- package/dist/resources/extensions/gsd/tests/commands-logs.test.ts +241 -0
- package/dist/resources/extensions/gsd/tests/extension-selector-separator.test.ts +60 -38
- package/dist/resources/extensions/gsd/tests/gsd-inspect.test.ts +1 -1
- package/dist/resources/extensions/gsd/tests/parallel-workers-multi-milestone-e2e.test.ts +1 -1
- package/dist/resources/extensions/gsd/tests/session-lock.test.ts +315 -0
- package/dist/resources/extensions/gsd/tests/validate-milestone.test.ts +55 -0
- package/dist/resources/extensions/gsd/tests/verification-evidence.test.ts +26 -24
- package/dist/resources/extensions/gsd/tests/verification-gate.test.ts +136 -7
- package/dist/resources/extensions/gsd/tests/workflow-templates.test.ts +173 -0
- package/dist/resources/extensions/gsd/types.ts +1 -0
- package/dist/resources/extensions/gsd/unit-runtime.ts +16 -13
- package/dist/resources/extensions/gsd/verification-evidence.ts +2 -0
- package/dist/resources/extensions/gsd/verification-gate.ts +13 -2
- package/dist/resources/extensions/gsd/workflow-templates/bugfix.md +87 -0
- package/dist/resources/extensions/gsd/workflow-templates/dep-upgrade.md +74 -0
- package/dist/resources/extensions/gsd/workflow-templates/full-project.md +41 -0
- package/dist/resources/extensions/gsd/workflow-templates/hotfix.md +45 -0
- package/dist/resources/extensions/gsd/workflow-templates/refactor.md +83 -0
- package/dist/resources/extensions/gsd/workflow-templates/registry.json +85 -0
- package/dist/resources/extensions/gsd/workflow-templates/security-audit.md +73 -0
- package/dist/resources/extensions/gsd/workflow-templates/small-feature.md +81 -0
- package/dist/resources/extensions/gsd/workflow-templates/spike.md +69 -0
- package/dist/resources/extensions/gsd/workflow-templates.ts +241 -0
- package/dist/resources/extensions/mcp-client/index.ts +459 -0
- package/dist/resources/extensions/remote-questions/discord-adapter.ts +9 -20
- package/dist/resources/extensions/remote-questions/http-client.ts +76 -0
- package/dist/resources/extensions/remote-questions/notify.ts +1 -2
- package/dist/resources/extensions/remote-questions/slack-adapter.ts +11 -18
- package/dist/resources/extensions/remote-questions/telegram-adapter.ts +8 -20
- package/dist/resources/extensions/remote-questions/types.ts +3 -0
- package/dist/resources/extensions/shared/mod.ts +3 -0
- package/dist/resources/skills/create-gsd-extension/SKILL.md +87 -0
- package/dist/resources/skills/create-gsd-extension/references/compaction-session-control.md +77 -0
- package/dist/resources/skills/create-gsd-extension/references/custom-commands.md +139 -0
- package/dist/resources/skills/create-gsd-extension/references/custom-rendering.md +108 -0
- package/dist/resources/skills/create-gsd-extension/references/custom-tools.md +183 -0
- package/dist/resources/skills/create-gsd-extension/references/custom-ui.md +490 -0
- package/dist/resources/skills/create-gsd-extension/references/events-reference.md +126 -0
- package/dist/resources/skills/create-gsd-extension/references/extension-lifecycle.md +64 -0
- package/dist/resources/skills/create-gsd-extension/references/extensionapi-reference.md +75 -0
- package/dist/resources/skills/create-gsd-extension/references/extensioncontext-reference.md +53 -0
- package/dist/resources/skills/create-gsd-extension/references/key-rules-gotchas.md +36 -0
- package/dist/resources/skills/create-gsd-extension/references/mode-behavior.md +32 -0
- package/dist/resources/skills/create-gsd-extension/references/model-provider-management.md +89 -0
- package/dist/resources/skills/create-gsd-extension/references/packaging-distribution.md +55 -0
- package/dist/resources/skills/create-gsd-extension/references/remote-execution-overrides.md +90 -0
- package/dist/resources/skills/create-gsd-extension/references/state-management.md +70 -0
- package/dist/resources/skills/create-gsd-extension/references/system-prompt-modification.md +52 -0
- package/dist/resources/skills/create-gsd-extension/templates/extension-skeleton.ts +51 -0
- package/dist/resources/skills/create-gsd-extension/templates/stateful-tool-skeleton.ts +143 -0
- package/dist/resources/skills/create-gsd-extension/workflows/add-capability.md +57 -0
- package/dist/resources/skills/create-gsd-extension/workflows/create-extension.md +156 -0
- package/dist/resources/skills/create-gsd-extension/workflows/debug-extension.md +74 -0
- package/dist/resources/skills/create-skill/SKILL.md +184 -0
- package/dist/resources/skills/create-skill/references/api-security.md +226 -0
- package/dist/resources/skills/create-skill/references/be-clear-and-direct.md +531 -0
- package/dist/resources/skills/create-skill/references/common-patterns.md +595 -0
- package/dist/resources/skills/create-skill/references/core-principles.md +437 -0
- package/dist/resources/skills/create-skill/references/executable-code.md +175 -0
- package/dist/resources/skills/create-skill/references/gsd-skill-ecosystem.md +68 -0
- package/dist/resources/skills/create-skill/references/iteration-and-testing.md +474 -0
- package/dist/resources/skills/create-skill/references/recommended-structure.md +168 -0
- package/dist/resources/skills/create-skill/references/skill-structure.md +372 -0
- package/dist/resources/skills/create-skill/references/use-xml-tags.md +466 -0
- package/dist/resources/skills/create-skill/references/using-scripts.md +113 -0
- package/dist/resources/skills/create-skill/references/using-templates.md +112 -0
- package/dist/resources/skills/create-skill/references/workflows-and-validation.md +510 -0
- package/dist/resources/skills/create-skill/templates/router-skill.md +73 -0
- package/dist/resources/skills/create-skill/templates/simple-skill.md +33 -0
- package/dist/resources/skills/create-skill/workflows/add-reference.md +96 -0
- package/dist/resources/skills/create-skill/workflows/add-script.md +93 -0
- package/dist/resources/skills/create-skill/workflows/add-template.md +74 -0
- package/dist/resources/skills/create-skill/workflows/add-workflow.md +120 -0
- package/dist/resources/skills/create-skill/workflows/audit-skill.md +148 -0
- package/dist/resources/skills/create-skill/workflows/create-new-skill.md +196 -0
- package/dist/resources/skills/create-skill/workflows/get-guidance.md +121 -0
- package/dist/resources/skills/create-skill/workflows/upgrade-to-router.md +161 -0
- package/dist/resources/skills/create-skill/workflows/verify-skill.md +204 -0
- package/package.json +6 -3
- package/packages/native/dist/native.d.ts +2 -0
- package/packages/native/dist/native.js +19 -5
- package/packages/native/src/native.ts +23 -9
- package/packages/pi-coding-agent/dist/core/extensions/loader.d.ts.map +1 -1
- package/packages/pi-coding-agent/dist/core/extensions/loader.js +13 -0
- package/packages/pi-coding-agent/dist/core/extensions/loader.js.map +1 -1
- package/packages/pi-coding-agent/dist/core/settings-manager.d.ts +3 -0
- package/packages/pi-coding-agent/dist/core/settings-manager.d.ts.map +1 -1
- package/packages/pi-coding-agent/dist/core/settings-manager.js +8 -0
- package/packages/pi-coding-agent/dist/core/settings-manager.js.map +1 -1
- package/packages/pi-coding-agent/dist/core/system-prompt.d.ts.map +1 -1
- package/packages/pi-coding-agent/dist/core/system-prompt.js +10 -0
- package/packages/pi-coding-agent/dist/core/system-prompt.js.map +1 -1
- package/packages/pi-coding-agent/dist/modes/interactive/interactive-mode.d.ts.map +1 -1
- package/packages/pi-coding-agent/dist/modes/interactive/interactive-mode.js +4 -1
- 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/scripts/copy-assets.cjs +39 -8
- package/packages/pi-coding-agent/src/core/extensions/loader.ts +13 -0
- package/packages/pi-coding-agent/src/core/settings-manager.ts +11 -0
- package/packages/pi-coding-agent/src/core/system-prompt.ts +11 -0
- package/packages/pi-coding-agent/src/modes/interactive/interactive-mode.ts +4 -1
- package/packages/pi-tui/dist/autocomplete.d.ts +3 -0
- package/packages/pi-tui/dist/autocomplete.d.ts.map +1 -1
- package/packages/pi-tui/dist/autocomplete.js +14 -0
- package/packages/pi-tui/dist/autocomplete.js.map +1 -1
- package/packages/pi-tui/src/autocomplete.ts +19 -1
- package/pkg/package.json +1 -1
- package/src/resources/extensions/bg-shell/process-manager.ts +13 -0
- package/src/resources/extensions/gsd/auto-dashboard.ts +186 -65
- package/src/resources/extensions/gsd/auto-post-unit.ts +14 -6
- package/src/resources/extensions/gsd/auto-recovery.ts +33 -23
- package/src/resources/extensions/gsd/auto-start.ts +25 -10
- package/src/resources/extensions/gsd/auto-verification.ts +41 -7
- package/src/resources/extensions/gsd/auto-worktree-sync.ts +21 -6
- package/src/resources/extensions/gsd/auto.ts +67 -22
- package/src/resources/extensions/gsd/commands-handlers.ts +3 -11
- package/src/resources/extensions/gsd/commands-logs.ts +536 -0
- package/src/resources/extensions/gsd/commands-prefs-wizard.ts +90 -47
- package/src/resources/extensions/gsd/commands-workflow-templates.ts +544 -0
- package/src/resources/extensions/gsd/commands.ts +75 -29
- package/src/resources/extensions/gsd/dashboard-overlay.ts +2 -1
- package/src/resources/extensions/gsd/doctor-types.ts +13 -0
- package/src/resources/extensions/gsd/doctor.ts +2 -6
- package/src/resources/extensions/gsd/export.ts +28 -2
- package/src/resources/extensions/gsd/gsd-db.ts +19 -0
- package/src/resources/extensions/gsd/index.ts +2 -1
- package/src/resources/extensions/gsd/json-persistence.ts +67 -0
- package/src/resources/extensions/gsd/metrics.ts +17 -31
- package/src/resources/extensions/gsd/paths.ts +0 -8
- package/src/resources/extensions/gsd/prompts/guided-discuss-milestone.md +1 -1
- package/src/resources/extensions/gsd/prompts/workflow-start.md +28 -0
- package/src/resources/extensions/gsd/queue-order.ts +10 -11
- package/src/resources/extensions/gsd/routing-history.ts +13 -17
- package/src/resources/extensions/gsd/session-lock.ts +284 -0
- package/src/resources/extensions/gsd/session-status-io.ts +23 -41
- package/src/resources/extensions/gsd/tests/auto-budget-alerts.test.ts +1 -1
- package/src/resources/extensions/gsd/tests/auto-skip-loop.test.ts +1 -1
- package/src/resources/extensions/gsd/tests/commands-logs.test.ts +241 -0
- package/src/resources/extensions/gsd/tests/extension-selector-separator.test.ts +60 -38
- package/src/resources/extensions/gsd/tests/gsd-inspect.test.ts +1 -1
- package/src/resources/extensions/gsd/tests/parallel-workers-multi-milestone-e2e.test.ts +1 -1
- package/src/resources/extensions/gsd/tests/session-lock.test.ts +315 -0
- package/src/resources/extensions/gsd/tests/validate-milestone.test.ts +55 -0
- package/src/resources/extensions/gsd/tests/verification-evidence.test.ts +26 -24
- package/src/resources/extensions/gsd/tests/verification-gate.test.ts +136 -7
- package/src/resources/extensions/gsd/tests/workflow-templates.test.ts +173 -0
- package/src/resources/extensions/gsd/types.ts +1 -0
- package/src/resources/extensions/gsd/unit-runtime.ts +16 -13
- package/src/resources/extensions/gsd/verification-evidence.ts +2 -0
- package/src/resources/extensions/gsd/verification-gate.ts +13 -2
- package/src/resources/extensions/gsd/workflow-templates/bugfix.md +87 -0
- package/src/resources/extensions/gsd/workflow-templates/dep-upgrade.md +74 -0
- package/src/resources/extensions/gsd/workflow-templates/full-project.md +41 -0
- package/src/resources/extensions/gsd/workflow-templates/hotfix.md +45 -0
- package/src/resources/extensions/gsd/workflow-templates/refactor.md +83 -0
- package/src/resources/extensions/gsd/workflow-templates/registry.json +85 -0
- package/src/resources/extensions/gsd/workflow-templates/security-audit.md +73 -0
- package/src/resources/extensions/gsd/workflow-templates/small-feature.md +81 -0
- package/src/resources/extensions/gsd/workflow-templates/spike.md +69 -0
- package/src/resources/extensions/gsd/workflow-templates.ts +241 -0
- package/src/resources/extensions/mcp-client/index.ts +459 -0
- package/src/resources/extensions/remote-questions/discord-adapter.ts +9 -20
- package/src/resources/extensions/remote-questions/http-client.ts +76 -0
- package/src/resources/extensions/remote-questions/notify.ts +1 -2
- package/src/resources/extensions/remote-questions/slack-adapter.ts +11 -18
- package/src/resources/extensions/remote-questions/telegram-adapter.ts +8 -20
- package/src/resources/extensions/remote-questions/types.ts +3 -0
- package/src/resources/extensions/shared/mod.ts +3 -0
- package/src/resources/skills/create-gsd-extension/SKILL.md +87 -0
- package/src/resources/skills/create-gsd-extension/references/compaction-session-control.md +77 -0
- package/src/resources/skills/create-gsd-extension/references/custom-commands.md +139 -0
- package/src/resources/skills/create-gsd-extension/references/custom-rendering.md +108 -0
- package/src/resources/skills/create-gsd-extension/references/custom-tools.md +183 -0
- package/src/resources/skills/create-gsd-extension/references/custom-ui.md +490 -0
- package/src/resources/skills/create-gsd-extension/references/events-reference.md +126 -0
- package/src/resources/skills/create-gsd-extension/references/extension-lifecycle.md +64 -0
- package/src/resources/skills/create-gsd-extension/references/extensionapi-reference.md +75 -0
- package/src/resources/skills/create-gsd-extension/references/extensioncontext-reference.md +53 -0
- package/src/resources/skills/create-gsd-extension/references/key-rules-gotchas.md +36 -0
- package/src/resources/skills/create-gsd-extension/references/mode-behavior.md +32 -0
- package/src/resources/skills/create-gsd-extension/references/model-provider-management.md +89 -0
- package/src/resources/skills/create-gsd-extension/references/packaging-distribution.md +55 -0
- package/src/resources/skills/create-gsd-extension/references/remote-execution-overrides.md +90 -0
- package/src/resources/skills/create-gsd-extension/references/state-management.md +70 -0
- package/src/resources/skills/create-gsd-extension/references/system-prompt-modification.md +52 -0
- package/src/resources/skills/create-gsd-extension/templates/extension-skeleton.ts +51 -0
- package/src/resources/skills/create-gsd-extension/templates/stateful-tool-skeleton.ts +143 -0
- package/src/resources/skills/create-gsd-extension/workflows/add-capability.md +57 -0
- package/src/resources/skills/create-gsd-extension/workflows/create-extension.md +156 -0
- package/src/resources/skills/create-gsd-extension/workflows/debug-extension.md +74 -0
- package/src/resources/skills/create-skill/SKILL.md +184 -0
- package/src/resources/skills/create-skill/references/api-security.md +226 -0
- package/src/resources/skills/create-skill/references/be-clear-and-direct.md +531 -0
- package/src/resources/skills/create-skill/references/common-patterns.md +595 -0
- package/src/resources/skills/create-skill/references/core-principles.md +437 -0
- package/src/resources/skills/create-skill/references/executable-code.md +175 -0
- package/src/resources/skills/create-skill/references/gsd-skill-ecosystem.md +68 -0
- package/src/resources/skills/create-skill/references/iteration-and-testing.md +474 -0
- package/src/resources/skills/create-skill/references/recommended-structure.md +168 -0
- package/src/resources/skills/create-skill/references/skill-structure.md +372 -0
- package/src/resources/skills/create-skill/references/use-xml-tags.md +466 -0
- package/src/resources/skills/create-skill/references/using-scripts.md +113 -0
- package/src/resources/skills/create-skill/references/using-templates.md +112 -0
- package/src/resources/skills/create-skill/references/workflows-and-validation.md +510 -0
- package/src/resources/skills/create-skill/templates/router-skill.md +73 -0
- package/src/resources/skills/create-skill/templates/simple-skill.md +33 -0
- package/src/resources/skills/create-skill/workflows/add-reference.md +96 -0
- package/src/resources/skills/create-skill/workflows/add-script.md +93 -0
- package/src/resources/skills/create-skill/workflows/add-template.md +74 -0
- package/src/resources/skills/create-skill/workflows/add-workflow.md +120 -0
- package/src/resources/skills/create-skill/workflows/audit-skill.md +148 -0
- package/src/resources/skills/create-skill/workflows/create-new-skill.md +196 -0
- package/src/resources/skills/create-skill/workflows/get-guidance.md +121 -0
- package/src/resources/skills/create-skill/workflows/upgrade-to-router.md +161 -0
- package/src/resources/skills/create-skill/workflows/verify-skill.md +204 -0
- package/dist/resources/extensions/gsd/preferences-hooks.ts +0 -10
- package/dist/resources/extensions/mcporter/index.ts +0 -525
- package/dist/resources/extensions/shared/progress-widget.ts +0 -282
- package/dist/resources/extensions/shared/thinking-widget.ts +0 -107
- package/src/resources/extensions/gsd/preferences-hooks.ts +0 -10
- package/src/resources/extensions/mcporter/index.ts +0 -525
- package/src/resources/extensions/shared/progress-widget.ts +0 -282
- package/src/resources/extensions/shared/thinking-widget.ts +0 -107
package/README.md
CHANGED
|
@@ -24,20 +24,21 @@ One command. Walk away. Come back to a built project with clean git history.
|
|
|
24
24
|
|
|
25
25
|
---
|
|
26
26
|
|
|
27
|
-
## What's New in v2.
|
|
28
|
-
|
|
29
|
-
-
|
|
30
|
-
-
|
|
31
|
-
-
|
|
32
|
-
-
|
|
33
|
-
- **
|
|
34
|
-
- **
|
|
35
|
-
- **CI/CD Pipeline** — three-stage promotion (Dev → Test → Prod) with automated versioning
|
|
36
|
-
- **Docker support** — containerized builds with multi-stage Dockerfile
|
|
37
|
-
- **`/gsd keys`** — full API key lifecycle management (list, add, remove, test, rotate, doctor)
|
|
38
|
-
- **Milestone parking** — park in-progress milestones to work on something else, unpark to resume
|
|
39
|
-
- **Studio** — experimental Electron desktop app (early preview)
|
|
27
|
+
## What's New in v2.29
|
|
28
|
+
|
|
29
|
+
- **Node.js 24 LTS** — CI, Docker, and package config all upgraded to Node 24 (Krypton)
|
|
30
|
+
- **`searchExcludeDirs` setting** — blacklist directories from `@` file autocomplete (e.g., `node_modules`, `dist`)
|
|
31
|
+
- **Automated releases** — prod-release now auto-generates changelogs, bumps versions, and publishes to npm
|
|
32
|
+
- **`/gsd logs`** — browse activity, debug, and metrics logs from within a session
|
|
33
|
+
- **Configurable screenshots** — browser-tools now support custom resolution, format, and quality
|
|
34
|
+
- **Pre-commit secret scanning** — automatic detection of hardcoded secrets in CI and locally
|
|
40
35
|
- **Per-project MCP config** — `.gsd/mcp.json` for project-scoped MCP server definitions
|
|
36
|
+
- **API request metrics** — track request counts for Copilot/subscription users
|
|
37
|
+
- **`/gsd keys`** — full API key lifecycle management (list, add, remove, test, rotate, doctor)
|
|
38
|
+
- **Advisory verification gate** — auto-discovered checks (lint/test from package.json) no longer doom-loop on pre-existing errors
|
|
39
|
+
- **Worktree living doc sync** — DECISIONS, REQUIREMENTS, PROJECT, and KNOWLEDGE now sync between worktree and project root
|
|
40
|
+
- **Windows non-ASCII path support** — `cpSync` fallback for usernames with special characters
|
|
41
|
+
- **`needs-discussion` routing** — milestones with draft context now route to the interactive discussion flow instead of stopping
|
|
41
42
|
|
|
42
43
|
See the full [Changelog](./CHANGELOG.md) for details.
|
|
43
44
|
|
|
@@ -62,6 +63,8 @@ Full documentation is available in the [`docs/`](./docs/) directory:
|
|
|
62
63
|
- **[CI/CD Pipeline](./docs/ci-cd-pipeline.md)** — three-stage promotion pipeline (Dev → Test → Prod)
|
|
63
64
|
- **[VS Code Extension](./vscode-extension/README.md)** — chat participant, sidebar dashboard, RPC integration
|
|
64
65
|
- **[Visualizer](./docs/visualizer.md)** — workflow visualizer with stats and discussion status
|
|
66
|
+
- **[Remote Questions](./docs/remote-questions.md)** — route decisions to Slack or Discord when human input is needed
|
|
67
|
+
- **[Dynamic Model Routing](./docs/dynamic-model-routing.md)** — complexity-based model selection and budget pressure
|
|
65
68
|
- **[Migration from v1](./docs/migration.md)** — `.planning` → `.gsd` migration
|
|
66
69
|
|
|
67
70
|
---
|
|
@@ -175,7 +178,7 @@ Auto mode is a state machine driven by files on disk. It reads `.gsd/STATE.md`,
|
|
|
175
178
|
|
|
176
179
|
9. **Adaptive replanning** — After each slice completes, the roadmap is reassessed. If the work revealed new information that changes the plan, slices are reordered, added, or removed before continuing.
|
|
177
180
|
|
|
178
|
-
10. **Verification enforcement** — Configure shell commands (`npm run lint`, `npm run test`, etc.) that run automatically after task execution. Failures trigger auto-fix retries before advancing. Configurable via `verification_commands`, `verification_auto_fix`, and `verification_max_retries` preferences.
|
|
181
|
+
10. **Verification enforcement** — Configure shell commands (`npm run lint`, `npm run test`, etc.) that run automatically after task execution. Failures trigger auto-fix retries before advancing. Auto-discovered checks from `package.json` run in advisory mode — they log warnings but don't block on pre-existing errors. Configurable via `verification_commands`, `verification_auto_fix`, and `verification_max_retries` preferences.
|
|
179
182
|
|
|
180
183
|
11. **Milestone validation** — After all slices complete, a `validate-milestone` gate compares roadmap success criteria against actual results before sealing the milestone.
|
|
181
184
|
|
|
@@ -307,6 +310,7 @@ On first run, GSD launches a branded setup wizard that walks you through LLM pro
|
|
|
307
310
|
| `/gsd cleanup` | Archive phase directories from completed milestones |
|
|
308
311
|
| `/gsd doctor` | Runtime health checks with auto-fix for common issues |
|
|
309
312
|
| `/gsd keys` | API key manager — list, add, remove, test, rotate, doctor |
|
|
313
|
+
| `/gsd logs` | Browse activity, debug, and metrics logs |
|
|
310
314
|
| `/gsd export --html` | Generate HTML report for current or completed milestone |
|
|
311
315
|
| `/worktree` (`/wt`) | Git worktree lifecycle — create, switch, merge, remove |
|
|
312
316
|
| `/voice` | Toggle real-time speech-to-text (macOS, Linux) |
|
|
@@ -447,6 +451,7 @@ auto_report: true
|
|
|
447
451
|
| `verification_max_retries` | Max retries for verification failures (default: 2) |
|
|
448
452
|
| `require_slice_discussion` | Pause auto-mode before each slice for human discussion review |
|
|
449
453
|
| `auto_report` | Auto-generate HTML reports after milestone completion (default: true) |
|
|
454
|
+
| `searchExcludeDirs` | Directories to exclude from `@` file autocomplete (e.g., `["node_modules", ".git", "dist"]`) |
|
|
450
455
|
|
|
451
456
|
### Agent Instructions
|
|
452
457
|
|
|
@@ -478,7 +483,7 @@ See the full [Token Optimization Guide](./docs/token-optimization.md) for detail
|
|
|
478
483
|
|
|
479
484
|
### Bundled Tools
|
|
480
485
|
|
|
481
|
-
GSD ships with
|
|
486
|
+
GSD ships with 16 extensions, all loaded automatically:
|
|
482
487
|
|
|
483
488
|
| Extension | What it provides |
|
|
484
489
|
| ---------------------- | ---------------------------------------------------------------------------------------------------------------------- |
|
|
@@ -490,12 +495,14 @@ GSD ships with 14 extensions, all loaded automatically:
|
|
|
490
495
|
| **Background Shell** | Long-running process management with readiness detection |
|
|
491
496
|
| **Subagent** | Delegated tasks with isolated context windows |
|
|
492
497
|
| **Mac Tools** | macOS native app automation via Accessibility APIs |
|
|
493
|
-
| **
|
|
498
|
+
| **MCP Client** | Native MCP server integration via @modelcontextprotocol/sdk |
|
|
494
499
|
| **Voice** | Real-time speech-to-text transcription (macOS, Linux — Ubuntu 22.04+) |
|
|
495
500
|
| **Slash Commands** | Custom command creation |
|
|
496
501
|
| **LSP** | Language Server Protocol integration — diagnostics, go-to-definition, references, hover, symbols, rename, code actions |
|
|
497
502
|
| **Ask User Questions** | Structured user input with single/multi-select |
|
|
498
503
|
| **Secure Env Collect** | Masked secret collection without manual .env editing |
|
|
504
|
+
| **Remote Questions** | Route decisions to Slack/Discord when human input is needed in headless/CI mode |
|
|
505
|
+
| **Universal Config** | Discover and import MCP servers and rules from other AI coding tools |
|
|
499
506
|
|
|
500
507
|
### Bundled Agents
|
|
501
508
|
|
|
@@ -597,7 +604,7 @@ gsd (CLI binary)
|
|
|
597
604
|
|
|
598
605
|
## Requirements
|
|
599
606
|
|
|
600
|
-
- **Node.js** ≥
|
|
607
|
+
- **Node.js** ≥ 22.0.0 (24 LTS recommended)
|
|
601
608
|
- **An LLM provider** — any of the 20+ supported providers (see [Use Any Model](#use-any-model))
|
|
602
609
|
- **Git** — initialized automatically if missing
|
|
603
610
|
|
package/dist/cli.js
CHANGED
|
@@ -71,6 +71,21 @@ function parseCliArgs(argv) {
|
|
|
71
71
|
}
|
|
72
72
|
const cliFlags = parseCliArgs(process.argv);
|
|
73
73
|
const isPrintMode = cliFlags.print || cliFlags.mode !== undefined;
|
|
74
|
+
// Early resource-skew check — must run before TTY gate so version mismatch
|
|
75
|
+
// errors surface even in non-TTY environments.
|
|
76
|
+
exitIfManagedResourcesAreNewer(agentDir);
|
|
77
|
+
// Early TTY check — must come before heavy initialization to avoid dangling
|
|
78
|
+
// handles that prevent process.exit() from completing promptly.
|
|
79
|
+
const hasSubcommand = cliFlags.messages.length > 0;
|
|
80
|
+
if (!process.stdin.isTTY && !isPrintMode && !hasSubcommand && !cliFlags.listModels) {
|
|
81
|
+
process.stderr.write('[gsd] Error: Interactive mode requires a terminal (TTY).\n');
|
|
82
|
+
process.stderr.write('[gsd] Non-interactive alternatives:\n');
|
|
83
|
+
process.stderr.write('[gsd] gsd --print "your message" Single-shot prompt\n');
|
|
84
|
+
process.stderr.write('[gsd] gsd --mode rpc JSON-RPC over stdin/stdout\n');
|
|
85
|
+
process.stderr.write('[gsd] gsd --mode mcp MCP server over stdin/stdout\n');
|
|
86
|
+
process.stderr.write('[gsd] gsd --mode text "message" Text output mode\n');
|
|
87
|
+
process.exit(1);
|
|
88
|
+
}
|
|
74
89
|
// `gsd <subcommand> --help` — show subcommand-specific help
|
|
75
90
|
const subcommand = cliFlags.messages[0];
|
|
76
91
|
if (subcommand && process.argv.includes('--help')) {
|
|
@@ -420,14 +435,5 @@ if (enabledModelPatterns && enabledModelPatterns.length > 0) {
|
|
|
420
435
|
session.setScopedModels(scopedModels);
|
|
421
436
|
}
|
|
422
437
|
}
|
|
423
|
-
if (!process.stdin.isTTY) {
|
|
424
|
-
process.stderr.write('[gsd] Error: Interactive mode requires a terminal (TTY).\n');
|
|
425
|
-
process.stderr.write('[gsd] Non-interactive alternatives:\n');
|
|
426
|
-
process.stderr.write('[gsd] gsd --print "your message" Single-shot prompt\n');
|
|
427
|
-
process.stderr.write('[gsd] gsd --mode rpc JSON-RPC over stdin/stdout\n');
|
|
428
|
-
process.stderr.write('[gsd] gsd --mode mcp MCP server over stdin/stdout\n');
|
|
429
|
-
process.stderr.write('[gsd] gsd --mode text "message" Text output mode\n');
|
|
430
|
-
process.exit(1);
|
|
431
|
-
}
|
|
432
438
|
const interactiveMode = new InteractiveMode(session);
|
|
433
439
|
await interactiveMode.run();
|
package/dist/resource-loader.js
CHANGED
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import { DefaultResourceLoader } from '@gsd/pi-coding-agent';
|
|
2
|
+
import { createHash } from 'node:crypto';
|
|
2
3
|
import { homedir } from 'node:os';
|
|
3
|
-
import { chmodSync, cpSync, existsSync, mkdirSync, readFileSync, readdirSync, rmSync, statSync, writeFileSync } from 'node:fs';
|
|
4
|
+
import { chmodSync, copyFileSync, cpSync, existsSync, mkdirSync, readFileSync, readdirSync, rmSync, statSync, writeFileSync } from 'node:fs';
|
|
4
5
|
import { dirname, join, relative, resolve } from 'node:path';
|
|
5
6
|
import { fileURLToPath } from 'node:url';
|
|
6
7
|
import { compareSemver } from './update-check.js';
|
|
@@ -41,7 +42,11 @@ function getBundledGsdVersion() {
|
|
|
41
42
|
}
|
|
42
43
|
}
|
|
43
44
|
function writeManagedResourceManifest(agentDir) {
|
|
44
|
-
const manifest = {
|
|
45
|
+
const manifest = {
|
|
46
|
+
gsdVersion: getBundledGsdVersion(),
|
|
47
|
+
syncedAt: Date.now(),
|
|
48
|
+
contentHash: computeResourceFingerprint(),
|
|
49
|
+
};
|
|
45
50
|
writeFileSync(getManagedResourceManifestPath(agentDir), JSON.stringify(manifest));
|
|
46
51
|
}
|
|
47
52
|
export function readManagedResourceVersion(agentDir) {
|
|
@@ -53,6 +58,44 @@ export function readManagedResourceVersion(agentDir) {
|
|
|
53
58
|
return null;
|
|
54
59
|
}
|
|
55
60
|
}
|
|
61
|
+
function readManagedResourceManifest(agentDir) {
|
|
62
|
+
try {
|
|
63
|
+
return JSON.parse(readFileSync(getManagedResourceManifestPath(agentDir), 'utf-8'));
|
|
64
|
+
}
|
|
65
|
+
catch {
|
|
66
|
+
return null;
|
|
67
|
+
}
|
|
68
|
+
}
|
|
69
|
+
/**
|
|
70
|
+
* Computes a lightweight content fingerprint of the bundled resources directory.
|
|
71
|
+
*
|
|
72
|
+
* Walks all files under resourcesDir and hashes their relative paths + sizes.
|
|
73
|
+
* This catches same-version content changes (npm link dev workflow, hotfixes
|
|
74
|
+
* within a release) without the cost of reading every file's contents.
|
|
75
|
+
*
|
|
76
|
+
* ~1ms for a typical resources tree (~100 files) — just stat calls, no reads.
|
|
77
|
+
*/
|
|
78
|
+
function computeResourceFingerprint() {
|
|
79
|
+
const entries = [];
|
|
80
|
+
collectFileEntries(resourcesDir, resourcesDir, entries);
|
|
81
|
+
entries.sort();
|
|
82
|
+
return createHash('sha256').update(entries.join('\n')).digest('hex').slice(0, 16);
|
|
83
|
+
}
|
|
84
|
+
function collectFileEntries(dir, root, out) {
|
|
85
|
+
if (!existsSync(dir))
|
|
86
|
+
return;
|
|
87
|
+
for (const entry of readdirSync(dir, { withFileTypes: true })) {
|
|
88
|
+
const fullPath = join(dir, entry.name);
|
|
89
|
+
if (entry.isDirectory()) {
|
|
90
|
+
collectFileEntries(fullPath, root, out);
|
|
91
|
+
}
|
|
92
|
+
else {
|
|
93
|
+
const rel = relative(root, fullPath);
|
|
94
|
+
const size = statSync(fullPath).size;
|
|
95
|
+
out.push(`${rel}:${size}`);
|
|
96
|
+
}
|
|
97
|
+
}
|
|
98
|
+
}
|
|
56
99
|
export function getNewerManagedResourceVersion(agentDir, currentVersion) {
|
|
57
100
|
const managedVersion = readManagedResourceVersion(agentDir);
|
|
58
101
|
if (!managedVersion) {
|
|
@@ -111,10 +154,34 @@ function syncResourceDir(srcDir, destDir) {
|
|
|
111
154
|
rmSync(target, { recursive: true, force: true });
|
|
112
155
|
}
|
|
113
156
|
}
|
|
114
|
-
|
|
157
|
+
try {
|
|
158
|
+
cpSync(srcDir, destDir, { recursive: true, force: true });
|
|
159
|
+
}
|
|
160
|
+
catch {
|
|
161
|
+
// Fallback for Windows paths with non-ASCII characters where cpSync
|
|
162
|
+
// fails with the \\?\ extended-length prefix (#1178).
|
|
163
|
+
copyDirRecursive(srcDir, destDir);
|
|
164
|
+
}
|
|
115
165
|
makeTreeWritable(destDir);
|
|
116
166
|
}
|
|
117
167
|
}
|
|
168
|
+
/**
|
|
169
|
+
* Recursive directory copy using copyFileSync — workaround for cpSync failures
|
|
170
|
+
* on Windows paths containing non-ASCII characters (#1178).
|
|
171
|
+
*/
|
|
172
|
+
function copyDirRecursive(src, dest) {
|
|
173
|
+
mkdirSync(dest, { recursive: true });
|
|
174
|
+
for (const entry of readdirSync(src, { withFileTypes: true })) {
|
|
175
|
+
const srcPath = join(src, entry.name);
|
|
176
|
+
const destPath = join(dest, entry.name);
|
|
177
|
+
if (entry.isDirectory()) {
|
|
178
|
+
copyDirRecursive(srcPath, destPath);
|
|
179
|
+
}
|
|
180
|
+
else {
|
|
181
|
+
copyFileSync(srcPath, destPath);
|
|
182
|
+
}
|
|
183
|
+
}
|
|
184
|
+
}
|
|
118
185
|
/**
|
|
119
186
|
* Syncs all bundled resources to agentDir (~/.gsd/agent/) on every launch.
|
|
120
187
|
*
|
|
@@ -132,12 +199,17 @@ function syncResourceDir(srcDir, destDir) {
|
|
|
132
199
|
*/
|
|
133
200
|
export function initResources(agentDir) {
|
|
134
201
|
mkdirSync(agentDir, { recursive: true });
|
|
135
|
-
// Skip the full copy when
|
|
136
|
-
//
|
|
202
|
+
// Skip the full copy when both version AND content fingerprint match.
|
|
203
|
+
// Version-only checks miss same-version content changes (npm link dev workflow,
|
|
204
|
+
// hotfixes within a release). The content hash catches those at ~1ms cost.
|
|
137
205
|
const currentVersion = getBundledGsdVersion();
|
|
138
|
-
const
|
|
139
|
-
if (
|
|
140
|
-
|
|
206
|
+
const manifest = readManagedResourceManifest(agentDir);
|
|
207
|
+
if (manifest && manifest.gsdVersion === currentVersion) {
|
|
208
|
+
// Version matches — check content fingerprint for same-version staleness.
|
|
209
|
+
const currentHash = computeResourceFingerprint();
|
|
210
|
+
if (manifest.contentHash && manifest.contentHash === currentHash) {
|
|
211
|
+
return;
|
|
212
|
+
}
|
|
141
213
|
}
|
|
142
214
|
syncResourceDir(bundledExtensionsDir, join(agentDir, 'extensions'));
|
|
143
215
|
syncResourceDir(join(resourcesDir, 'agents'), join(agentDir, 'agents'));
|
|
@@ -375,6 +375,19 @@ export function cleanupAll(): void {
|
|
|
375
375
|
processes.clear();
|
|
376
376
|
}
|
|
377
377
|
|
|
378
|
+
/**
|
|
379
|
+
* Kill all alive, non-persistent bg processes.
|
|
380
|
+
* Called between auto-mode units to prevent orphaned servers from
|
|
381
|
+
* keeping ports bound across task boundaries (#1209).
|
|
382
|
+
*/
|
|
383
|
+
export function killSessionProcesses(): void {
|
|
384
|
+
for (const [id, bg] of processes) {
|
|
385
|
+
if (bg.alive && !bg.persistAcrossSessions) {
|
|
386
|
+
killProcess(id, "SIGTERM");
|
|
387
|
+
}
|
|
388
|
+
}
|
|
389
|
+
}
|
|
390
|
+
|
|
378
391
|
async function waitForProcessExit(bg: BgProcess, timeoutMs: number): Promise<boolean> {
|
|
379
392
|
if (!bg.alive) return true;
|
|
380
393
|
await new Promise<void>((resolve) => {
|
|
@@ -204,6 +204,13 @@ export function estimateTimeRemaining(): string | null {
|
|
|
204
204
|
|
|
205
205
|
// ─── Slice Progress Cache ─────────────────────────────────────────────────────
|
|
206
206
|
|
|
207
|
+
/** Cached task detail for the widget task checklist */
|
|
208
|
+
interface CachedTaskDetail {
|
|
209
|
+
id: string;
|
|
210
|
+
title: string;
|
|
211
|
+
done: boolean;
|
|
212
|
+
}
|
|
213
|
+
|
|
207
214
|
/** Cached slice progress for the widget — avoid async in render */
|
|
208
215
|
let cachedSliceProgress: {
|
|
209
216
|
done: number;
|
|
@@ -211,6 +218,8 @@ let cachedSliceProgress: {
|
|
|
211
218
|
milestoneId: string;
|
|
212
219
|
/** Real task progress for the active slice, if its plan file exists */
|
|
213
220
|
activeSliceTasks: { done: number; total: number } | null;
|
|
221
|
+
/** Full task list for the active slice checklist */
|
|
222
|
+
taskDetails: CachedTaskDetail[] | null;
|
|
214
223
|
} | null = null;
|
|
215
224
|
|
|
216
225
|
export function updateSliceProgressCache(base: string, mid: string, activeSid?: string): void {
|
|
@@ -221,6 +230,7 @@ export function updateSliceProgressCache(base: string, mid: string, activeSid?:
|
|
|
221
230
|
const roadmap = parseRoadmap(content);
|
|
222
231
|
|
|
223
232
|
let activeSliceTasks: { done: number; total: number } | null = null;
|
|
233
|
+
let taskDetails: CachedTaskDetail[] | null = null;
|
|
224
234
|
if (activeSid) {
|
|
225
235
|
try {
|
|
226
236
|
const planFile = resolveSliceFile(base, mid, activeSid, "PLAN");
|
|
@@ -231,6 +241,7 @@ export function updateSliceProgressCache(base: string, mid: string, activeSid?:
|
|
|
231
241
|
done: plan.tasks.filter(t => t.done).length,
|
|
232
242
|
total: plan.tasks.length,
|
|
233
243
|
};
|
|
244
|
+
taskDetails = plan.tasks.map(t => ({ id: t.id, title: t.title, done: t.done }));
|
|
234
245
|
}
|
|
235
246
|
} catch {
|
|
236
247
|
// Non-fatal — just omit task count
|
|
@@ -242,13 +253,19 @@ export function updateSliceProgressCache(base: string, mid: string, activeSid?:
|
|
|
242
253
|
total: roadmap.slices.length,
|
|
243
254
|
milestoneId: mid,
|
|
244
255
|
activeSliceTasks,
|
|
256
|
+
taskDetails,
|
|
245
257
|
};
|
|
246
258
|
} catch {
|
|
247
259
|
// Non-fatal — widget just won't show progress bar
|
|
248
260
|
}
|
|
249
261
|
}
|
|
250
262
|
|
|
251
|
-
export function getRoadmapSlicesSync(): {
|
|
263
|
+
export function getRoadmapSlicesSync(): {
|
|
264
|
+
done: number;
|
|
265
|
+
total: number;
|
|
266
|
+
activeSliceTasks: { done: number; total: number } | null;
|
|
267
|
+
taskDetails: CachedTaskDetail[] | null;
|
|
268
|
+
} | null {
|
|
252
269
|
return cachedSliceProgress;
|
|
253
270
|
}
|
|
254
271
|
|
|
@@ -349,87 +366,84 @@ export function updateProgressWidget(
|
|
|
349
366
|
const lines: string[] = [];
|
|
350
367
|
const pad = INDENT.base;
|
|
351
368
|
|
|
352
|
-
// ──
|
|
369
|
+
// ── Top bar ─────────────────────────────────────────────────────
|
|
353
370
|
lines.push(...ui.bar());
|
|
354
371
|
|
|
372
|
+
// ── Header: GSD AUTO ... elapsed ────────────────────────────────
|
|
355
373
|
const dot = pulseBright
|
|
356
374
|
? theme.fg("accent", GLYPH.statusActive)
|
|
357
375
|
: theme.fg("dim", GLYPH.statusPending);
|
|
358
376
|
const elapsed = formatAutoElapsed(accessors.getAutoStartTime());
|
|
359
377
|
const modeTag = accessors.isStepMode() ? "NEXT" : "AUTO";
|
|
360
|
-
const headerLeft = `${pad}${dot} ${theme.fg("accent", theme.bold("GSD"))}
|
|
378
|
+
const headerLeft = `${pad}${dot} ${theme.fg("accent", theme.bold("GSD"))} ${theme.fg("success", modeTag)}`;
|
|
361
379
|
const headerRight = elapsed ? theme.fg("dim", elapsed) : "";
|
|
362
380
|
lines.push(rightAlign(headerLeft, headerRight, width));
|
|
363
381
|
|
|
364
|
-
|
|
365
|
-
|
|
366
|
-
if (mid)
|
|
367
|
-
lines.push(truncateToWidth(`${pad}${theme.fg("dim", mid.title)}`, width));
|
|
368
|
-
}
|
|
369
|
-
|
|
382
|
+
// ── Context: project · slice · action (merged into one line) ────
|
|
383
|
+
const contextParts: string[] = [];
|
|
384
|
+
if (mid) contextParts.push(theme.fg("dim", mid.title));
|
|
370
385
|
if (slice && unitType !== "research-milestone" && unitType !== "plan-milestone") {
|
|
371
|
-
|
|
372
|
-
`${pad}${theme.fg("text", theme.bold(`${slice.id}: ${slice.title}`))}`,
|
|
373
|
-
width,
|
|
374
|
-
));
|
|
386
|
+
contextParts.push(theme.fg("text", theme.bold(`${slice.id}: ${slice.title}`)));
|
|
375
387
|
}
|
|
376
|
-
|
|
377
|
-
lines.push("");
|
|
378
|
-
|
|
379
388
|
const isHook = unitType.startsWith("hook/");
|
|
380
389
|
const target = isHook
|
|
381
390
|
? (unitId.split("/").pop() ?? unitId)
|
|
382
391
|
: (task ? `${task.id}: ${task.title}` : unitId);
|
|
383
|
-
|
|
392
|
+
contextParts.push(`${theme.fg("accent", "▸")} ${theme.fg("accent", verb)} ${theme.fg("text", target)}`);
|
|
393
|
+
|
|
384
394
|
const tierTag = tierBadge ? theme.fg("dim", `[${tierBadge}] `) : "";
|
|
385
395
|
const phaseBadge = `${tierTag}${theme.fg("dim", phaseLabel)}`;
|
|
386
|
-
|
|
387
|
-
lines.push(
|
|
388
|
-
|
|
389
|
-
|
|
390
|
-
|
|
391
|
-
|
|
392
|
-
|
|
393
|
-
|
|
394
|
-
|
|
395
|
-
|
|
396
|
-
|
|
397
|
-
|
|
398
|
-
|
|
399
|
-
|
|
400
|
-
|
|
401
|
-
|
|
402
|
-
|
|
403
|
-
|
|
404
|
-
|
|
405
|
-
|
|
406
|
-
|
|
407
|
-
|
|
408
|
-
|
|
409
|
-
|
|
410
|
-
|
|
411
|
-
|
|
412
|
-
|
|
413
|
-
|
|
396
|
+
const contextLine = contextParts.join(theme.fg("dim", " · "));
|
|
397
|
+
lines.push(rightAlign(`${pad}${contextLine}`, phaseBadge, width));
|
|
398
|
+
|
|
399
|
+
// ── Two-column body ─────────────────────────────────────────────
|
|
400
|
+
// Left: progress, ETA, next, stats (fixed) | Right: task checklist (fixed, adjacent)
|
|
401
|
+
// Both columns sit left-to-center; empty space is on the right.
|
|
402
|
+
const divider = theme.fg("dim", "│");
|
|
403
|
+
const minTwoColWidth = 100;
|
|
404
|
+
const rightColFixed = 44;
|
|
405
|
+
const colGap = 5; // breathing room between columns
|
|
406
|
+
// Left column takes remaining space — no truncation on wide terminals
|
|
407
|
+
const useTwoCol = width >= minTwoColWidth;
|
|
408
|
+
const rightColWidth = useTwoCol ? rightColFixed : 0;
|
|
409
|
+
const leftColWidth = useTwoCol ? width - rightColWidth - colGap : width;
|
|
410
|
+
|
|
411
|
+
const roadmapSlices = mid ? getRoadmapSlicesSync() : null;
|
|
412
|
+
|
|
413
|
+
// Build left column: progress bar, ETA, next step, token stats
|
|
414
|
+
const leftLines: string[] = [];
|
|
415
|
+
|
|
416
|
+
if (roadmapSlices) {
|
|
417
|
+
const { done, total, activeSliceTasks } = roadmapSlices;
|
|
418
|
+
const barWidth = Math.max(6, Math.min(18, Math.floor(leftColWidth * 0.4)));
|
|
419
|
+
const pct = total > 0 ? done / total : 0;
|
|
420
|
+
const filled = Math.round(pct * barWidth);
|
|
421
|
+
const bar = theme.fg("success", "█".repeat(filled))
|
|
422
|
+
+ theme.fg("dim", "░".repeat(barWidth - filled));
|
|
423
|
+
|
|
424
|
+
let meta = theme.fg("dim", `${done}/${total} slices`);
|
|
425
|
+
if (activeSliceTasks && activeSliceTasks.total > 0) {
|
|
426
|
+
const taskNum = isHook
|
|
427
|
+
? Math.max(activeSliceTasks.done, 1)
|
|
428
|
+
: Math.min(activeSliceTasks.done + 1, activeSliceTasks.total);
|
|
429
|
+
meta += theme.fg("dim", ` · task ${taskNum}/${activeSliceTasks.total}`);
|
|
430
|
+
}
|
|
431
|
+
leftLines.push(truncateToWidth(`${pad}${bar} ${meta}`, leftColWidth));
|
|
414
432
|
|
|
415
|
-
|
|
433
|
+
const eta = estimateTimeRemaining();
|
|
434
|
+
if (eta) {
|
|
435
|
+
leftLines.push(truncateToWidth(`${pad}${theme.fg("dim", eta)}`, leftColWidth));
|
|
416
436
|
}
|
|
417
437
|
}
|
|
418
438
|
|
|
419
|
-
lines.push("");
|
|
420
|
-
|
|
421
439
|
if (next) {
|
|
422
|
-
|
|
440
|
+
leftLines.push(truncateToWidth(
|
|
423
441
|
`${pad}${theme.fg("dim", "→")} ${theme.fg("dim", `then ${next}`)}`,
|
|
424
|
-
|
|
442
|
+
leftColWidth,
|
|
425
443
|
));
|
|
426
444
|
}
|
|
427
445
|
|
|
428
|
-
//
|
|
429
|
-
lines.push("");
|
|
430
|
-
lines.push(truncateToWidth(theme.fg("dim", `${pad}${widgetPwd}`), width, theme.fg("dim", "…")));
|
|
431
|
-
|
|
432
|
-
// Token stats from current unit session + cumulative cost from metrics
|
|
446
|
+
// Token stats
|
|
433
447
|
{
|
|
434
448
|
const cmdCtx = accessors.getCmdCtx();
|
|
435
449
|
let totalInput = 0, totalOutput = 0;
|
|
@@ -464,7 +478,6 @@ export function updateProgressWidget(
|
|
|
464
478
|
if (totalOutput) sp.push(`↓${formatWidgetTokens(totalOutput)}`);
|
|
465
479
|
if (totalCacheRead) sp.push(`R${formatWidgetTokens(totalCacheRead)}`);
|
|
466
480
|
if (totalCacheWrite) sp.push(`W${formatWidgetTokens(totalCacheWrite)}`);
|
|
467
|
-
// Cache hit rate for current unit
|
|
468
481
|
if (totalCacheRead + totalInput > 0) {
|
|
469
482
|
const hitRate = Math.round((totalCacheRead / (totalCacheRead + totalInput)) * 100);
|
|
470
483
|
sp.push(`\u26A1${hitRate}%`);
|
|
@@ -483,33 +496,134 @@ export function updateProgressWidget(
|
|
|
483
496
|
sp.push(cxDisplay);
|
|
484
497
|
}
|
|
485
498
|
|
|
486
|
-
const
|
|
499
|
+
const tokenLine = sp.map(p => p.includes("\x1b[") ? p : theme.fg("dim", p))
|
|
487
500
|
.join(theme.fg("dim", " "));
|
|
501
|
+
leftLines.push(truncateToWidth(`${pad}${tokenLine}`, leftColWidth));
|
|
488
502
|
|
|
489
503
|
const modelId = cmdCtx?.model?.id ?? "";
|
|
490
504
|
const modelProvider = cmdCtx?.model?.provider ?? "";
|
|
491
|
-
const modelPhase = phaseLabel ? theme.fg("dim", `[${phaseLabel}] `) : "";
|
|
492
505
|
const modelDisplay = modelProvider && modelId
|
|
493
506
|
? `${modelProvider}/${modelId}`
|
|
494
507
|
: modelId;
|
|
495
|
-
|
|
496
|
-
|
|
497
|
-
|
|
498
|
-
lines.push(rightAlign(`${pad}${sLeft}`, sRight, width));
|
|
508
|
+
if (modelDisplay) {
|
|
509
|
+
leftLines.push(truncateToWidth(`${pad}${theme.fg("dim", modelDisplay)}`, leftColWidth));
|
|
510
|
+
}
|
|
499
511
|
|
|
500
|
-
// Dynamic routing savings
|
|
512
|
+
// Dynamic routing savings
|
|
501
513
|
if (mLedger && mLedger.units.some(u => u.tier)) {
|
|
502
514
|
const savings = formatTierSavings(mLedger.units);
|
|
503
515
|
if (savings) {
|
|
504
|
-
|
|
516
|
+
leftLines.push(truncateToWidth(`${pad}${theme.fg("dim", savings)}`, leftColWidth));
|
|
517
|
+
}
|
|
518
|
+
}
|
|
519
|
+
}
|
|
520
|
+
|
|
521
|
+
// Build right column: task checklist (pegged to right edge)
|
|
522
|
+
const rightLines: string[] = [];
|
|
523
|
+
const taskDetails = roadmapSlices?.taskDetails ?? null;
|
|
524
|
+
const maxVisibleTasks = 8;
|
|
525
|
+
const rpad = " ";
|
|
526
|
+
|
|
527
|
+
if (useTwoCol) {
|
|
528
|
+
if (taskDetails && taskDetails.length > 0) {
|
|
529
|
+
const visibleTasks = taskDetails.slice(0, maxVisibleTasks);
|
|
530
|
+
for (const t of visibleTasks) {
|
|
531
|
+
const isCurrent = task && t.id === task.id;
|
|
532
|
+
const glyph = t.done
|
|
533
|
+
? theme.fg("success", GLYPH.statusDone)
|
|
534
|
+
: isCurrent
|
|
535
|
+
? theme.fg("accent", "▸")
|
|
536
|
+
: theme.fg("dim", " ");
|
|
537
|
+
const label = isCurrent
|
|
538
|
+
? theme.fg("text", `${t.id}: ${t.title}`)
|
|
539
|
+
: t.done
|
|
540
|
+
? theme.fg("dim", `${t.id}: ${t.title}`)
|
|
541
|
+
: theme.fg("text", `${t.id}: ${t.title}`);
|
|
542
|
+
rightLines.push(truncateToWidth(`${rpad}${glyph} ${label}`, rightColWidth));
|
|
543
|
+
}
|
|
544
|
+
if (taskDetails.length > maxVisibleTasks) {
|
|
545
|
+
rightLines.push(truncateToWidth(
|
|
546
|
+
`${rpad}${theme.fg("dim", ` …+${taskDetails.length - maxVisibleTasks} more`)}`,
|
|
547
|
+
rightColWidth,
|
|
548
|
+
));
|
|
549
|
+
}
|
|
550
|
+
} else if (roadmapSlices?.activeSliceTasks) {
|
|
551
|
+
const { done: tDone, total: tTotal } = roadmapSlices.activeSliceTasks;
|
|
552
|
+
rightLines.push(`${rpad}${theme.fg("dim", `${tDone}/${tTotal} tasks`)}`);
|
|
553
|
+
}
|
|
554
|
+
} else {
|
|
555
|
+
// Narrow single-column: task list goes into left column
|
|
556
|
+
if (taskDetails && taskDetails.length > 0) {
|
|
557
|
+
for (const t of taskDetails.slice(0, maxVisibleTasks)) {
|
|
558
|
+
const isCurrent = task && t.id === task.id;
|
|
559
|
+
const glyph = t.done
|
|
560
|
+
? theme.fg("success", GLYPH.statusDone)
|
|
561
|
+
: isCurrent
|
|
562
|
+
? theme.fg("accent", "▸")
|
|
563
|
+
: theme.fg("dim", " ");
|
|
564
|
+
const label = isCurrent
|
|
565
|
+
? theme.fg("text", `${t.id}: ${t.title}`)
|
|
566
|
+
: t.done
|
|
567
|
+
? theme.fg("dim", `${t.id}: ${t.title}`)
|
|
568
|
+
: theme.fg("text", `${t.id}: ${t.title}`);
|
|
569
|
+
leftLines.push(truncateToWidth(`${pad}${glyph} ${label}`, leftColWidth));
|
|
570
|
+
}
|
|
571
|
+
}
|
|
572
|
+
// Add progress bar inline
|
|
573
|
+
if (roadmapSlices) {
|
|
574
|
+
const { done, total, activeSliceTasks } = roadmapSlices;
|
|
575
|
+
const barWidth = Math.max(6, Math.min(18, Math.floor(leftColWidth * 0.4)));
|
|
576
|
+
const pct = total > 0 ? done / total : 0;
|
|
577
|
+
const filled = Math.round(pct * barWidth);
|
|
578
|
+
const bar = theme.fg("success", "█".repeat(filled))
|
|
579
|
+
+ theme.fg("dim", "░".repeat(barWidth - filled));
|
|
580
|
+
let meta = theme.fg("dim", `${done}/${total} slices`);
|
|
581
|
+
if (activeSliceTasks && activeSliceTasks.total > 0) {
|
|
582
|
+
const taskNum = isHook
|
|
583
|
+
? Math.max(activeSliceTasks.done, 1)
|
|
584
|
+
: Math.min(activeSliceTasks.done + 1, activeSliceTasks.total);
|
|
585
|
+
meta += theme.fg("dim", ` · task ${taskNum}/${activeSliceTasks.total}`);
|
|
505
586
|
}
|
|
587
|
+
const eta = estimateTimeRemaining();
|
|
588
|
+
if (eta) meta += theme.fg("dim", ` · ${eta}`);
|
|
589
|
+
leftLines.push(truncateToWidth(`${pad}${bar} ${meta}`, leftColWidth));
|
|
590
|
+
}
|
|
591
|
+
if (next) {
|
|
592
|
+
leftLines.push(truncateToWidth(
|
|
593
|
+
`${pad}${theme.fg("dim", "→")} ${theme.fg("dim", `then ${next}`)}`,
|
|
594
|
+
leftColWidth,
|
|
595
|
+
));
|
|
506
596
|
}
|
|
507
597
|
}
|
|
508
598
|
|
|
599
|
+
// Compose columns
|
|
600
|
+
if (useTwoCol) {
|
|
601
|
+
const maxRows = Math.max(leftLines.length, rightLines.length);
|
|
602
|
+
if (maxRows > 0) {
|
|
603
|
+
lines.push(""); // spacer before columns
|
|
604
|
+
for (let i = 0; i < maxRows; i++) {
|
|
605
|
+
const left = padToWidth(leftLines[i] ?? "", leftColWidth);
|
|
606
|
+
const gap = " ".repeat(colGap - 2); // colGap minus divider and its trailing space
|
|
607
|
+
const right = rightLines[i] ?? "";
|
|
608
|
+
lines.push(truncateToWidth(`${left}${gap}${divider} ${right}`, width));
|
|
609
|
+
}
|
|
610
|
+
}
|
|
611
|
+
} else {
|
|
612
|
+
// Narrow single-column: just stack
|
|
613
|
+
if (leftLines.length > 0) {
|
|
614
|
+
lines.push("");
|
|
615
|
+
for (const l of leftLines) lines.push(l);
|
|
616
|
+
}
|
|
617
|
+
}
|
|
618
|
+
|
|
619
|
+
// ── Footer: pwd + hints ─────────────────────────────────────────
|
|
620
|
+
lines.push("");
|
|
509
621
|
const hintParts: string[] = [];
|
|
510
622
|
hintParts.push("esc pause");
|
|
511
623
|
hintParts.push(process.platform === "darwin" ? "⌃⌥G dashboard" : "Ctrl+Alt+G dashboard");
|
|
512
|
-
|
|
624
|
+
const hintStr = theme.fg("dim", hintParts.join(" | "));
|
|
625
|
+
const pwdStr = theme.fg("dim", widgetPwd);
|
|
626
|
+
lines.push(rightAlign(`${pad}${pwdStr}`, hintStr, width));
|
|
513
627
|
|
|
514
628
|
lines.push(...ui.bar());
|
|
515
629
|
|
|
@@ -597,3 +711,10 @@ function rightAlign(left: string, right: string, width: number): string {
|
|
|
597
711
|
const gap = Math.max(1, width - leftVis - rightVis);
|
|
598
712
|
return truncateToWidth(left + " ".repeat(gap) + right, width);
|
|
599
713
|
}
|
|
714
|
+
|
|
715
|
+
/** Pad a string with trailing spaces to fill exactly `colWidth` (ANSI-aware). */
|
|
716
|
+
function padToWidth(s: string, colWidth: number): string {
|
|
717
|
+
const vis = visibleWidth(s);
|
|
718
|
+
if (vis >= colWidth) return truncateToWidth(s, colWidth);
|
|
719
|
+
return s + " ".repeat(colWidth - vis);
|
|
720
|
+
}
|