gsd-pi 2.28.0-dev.e19bf89 → 2.29.0-dev.23d50d0
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/headless.js +4 -0
- 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 +217 -65
- package/dist/resources/extensions/gsd/auto-dispatch.ts +2 -2
- package/dist/resources/extensions/gsd/auto-post-unit.ts +53 -6
- package/dist/resources/extensions/gsd/auto-prompts.ts +27 -14
- 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-worktree.ts +9 -0
- 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/mechanical-completion.ts +430 -0
- package/dist/resources/extensions/gsd/metrics.ts +17 -31
- package/dist/resources/extensions/gsd/paths.ts +17 -8
- package/dist/resources/extensions/gsd/preferences-models.ts +7 -1
- package/dist/resources/extensions/gsd/preferences-validation.ts +2 -1
- package/dist/resources/extensions/gsd/prompts/discuss-headless.md +4 -2
- package/dist/resources/extensions/gsd/prompts/guided-discuss-milestone.md +1 -1
- package/dist/resources/extensions/gsd/prompts/plan-milestone.md +26 -2
- package/dist/resources/extensions/gsd/prompts/plan-slice.md +15 -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/mechanical-completion.test.ts +356 -0
- package/dist/resources/extensions/gsd/tests/parallel-workers-multi-milestone-e2e.test.ts +1 -1
- package/dist/resources/extensions/gsd/tests/plan-slice-prompt.test.ts +1 -0
- package/dist/resources/extensions/gsd/tests/session-lock.test.ts +315 -0
- package/dist/resources/extensions/gsd/tests/token-profile.test.ts +14 -16
- 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 +3 -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/lsp/client.d.ts.map +1 -1
- package/packages/pi-coding-agent/dist/core/lsp/client.js +3 -0
- package/packages/pi-coding-agent/dist/core/lsp/client.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/lsp/client.ts +3 -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 +217 -65
- package/src/resources/extensions/gsd/auto-dispatch.ts +2 -2
- package/src/resources/extensions/gsd/auto-post-unit.ts +53 -6
- package/src/resources/extensions/gsd/auto-prompts.ts +27 -14
- 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-worktree.ts +9 -0
- 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/mechanical-completion.ts +430 -0
- package/src/resources/extensions/gsd/metrics.ts +17 -31
- package/src/resources/extensions/gsd/paths.ts +17 -8
- package/src/resources/extensions/gsd/preferences-models.ts +7 -1
- package/src/resources/extensions/gsd/preferences-validation.ts +2 -1
- package/src/resources/extensions/gsd/prompts/discuss-headless.md +4 -2
- package/src/resources/extensions/gsd/prompts/guided-discuss-milestone.md +1 -1
- package/src/resources/extensions/gsd/prompts/plan-milestone.md +26 -2
- package/src/resources/extensions/gsd/prompts/plan-slice.md +15 -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/mechanical-completion.test.ts +356 -0
- package/src/resources/extensions/gsd/tests/parallel-workers-multi-milestone-e2e.test.ts +1 -1
- package/src/resources/extensions/gsd/tests/plan-slice-prompt.test.ts +1 -0
- package/src/resources/extensions/gsd/tests/session-lock.test.ts +315 -0
- package/src/resources/extensions/gsd/tests/token-profile.test.ts +14 -16
- 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 +3 -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
|
@@ -11,6 +11,7 @@ import type { GSDState } from "./types.js";
|
|
|
11
11
|
import { getCurrentBranch } from "./worktree.js";
|
|
12
12
|
import { getActiveHook } from "./post-unit-hooks.js";
|
|
13
13
|
import { getLedger, getProjectTotals, formatCost, formatTokenCount, formatTierSavings } from "./metrics.js";
|
|
14
|
+
import { getHealthTrend, getConsecutiveErrorUnits } from "./doctor-proactive.js";
|
|
14
15
|
import {
|
|
15
16
|
resolveMilestoneFile,
|
|
16
17
|
resolveSliceFile,
|
|
@@ -204,6 +205,13 @@ export function estimateTimeRemaining(): string | null {
|
|
|
204
205
|
|
|
205
206
|
// ─── Slice Progress Cache ─────────────────────────────────────────────────────
|
|
206
207
|
|
|
208
|
+
/** Cached task detail for the widget task checklist */
|
|
209
|
+
interface CachedTaskDetail {
|
|
210
|
+
id: string;
|
|
211
|
+
title: string;
|
|
212
|
+
done: boolean;
|
|
213
|
+
}
|
|
214
|
+
|
|
207
215
|
/** Cached slice progress for the widget — avoid async in render */
|
|
208
216
|
let cachedSliceProgress: {
|
|
209
217
|
done: number;
|
|
@@ -211,6 +219,8 @@ let cachedSliceProgress: {
|
|
|
211
219
|
milestoneId: string;
|
|
212
220
|
/** Real task progress for the active slice, if its plan file exists */
|
|
213
221
|
activeSliceTasks: { done: number; total: number } | null;
|
|
222
|
+
/** Full task list for the active slice checklist */
|
|
223
|
+
taskDetails: CachedTaskDetail[] | null;
|
|
214
224
|
} | null = null;
|
|
215
225
|
|
|
216
226
|
export function updateSliceProgressCache(base: string, mid: string, activeSid?: string): void {
|
|
@@ -221,6 +231,7 @@ export function updateSliceProgressCache(base: string, mid: string, activeSid?:
|
|
|
221
231
|
const roadmap = parseRoadmap(content);
|
|
222
232
|
|
|
223
233
|
let activeSliceTasks: { done: number; total: number } | null = null;
|
|
234
|
+
let taskDetails: CachedTaskDetail[] | null = null;
|
|
224
235
|
if (activeSid) {
|
|
225
236
|
try {
|
|
226
237
|
const planFile = resolveSliceFile(base, mid, activeSid, "PLAN");
|
|
@@ -231,6 +242,7 @@ export function updateSliceProgressCache(base: string, mid: string, activeSid?:
|
|
|
231
242
|
done: plan.tasks.filter(t => t.done).length,
|
|
232
243
|
total: plan.tasks.length,
|
|
233
244
|
};
|
|
245
|
+
taskDetails = plan.tasks.map(t => ({ id: t.id, title: t.title, done: t.done }));
|
|
234
246
|
}
|
|
235
247
|
} catch {
|
|
236
248
|
// Non-fatal — just omit task count
|
|
@@ -242,13 +254,19 @@ export function updateSliceProgressCache(base: string, mid: string, activeSid?:
|
|
|
242
254
|
total: roadmap.slices.length,
|
|
243
255
|
milestoneId: mid,
|
|
244
256
|
activeSliceTasks,
|
|
257
|
+
taskDetails,
|
|
245
258
|
};
|
|
246
259
|
} catch {
|
|
247
260
|
// Non-fatal — widget just won't show progress bar
|
|
248
261
|
}
|
|
249
262
|
}
|
|
250
263
|
|
|
251
|
-
export function getRoadmapSlicesSync(): {
|
|
264
|
+
export function getRoadmapSlicesSync(): {
|
|
265
|
+
done: number;
|
|
266
|
+
total: number;
|
|
267
|
+
activeSliceTasks: { done: number; total: number } | null;
|
|
268
|
+
taskDetails: CachedTaskDetail[] | null;
|
|
269
|
+
} | null {
|
|
252
270
|
return cachedSliceProgress;
|
|
253
271
|
}
|
|
254
272
|
|
|
@@ -349,87 +367,84 @@ export function updateProgressWidget(
|
|
|
349
367
|
const lines: string[] = [];
|
|
350
368
|
const pad = INDENT.base;
|
|
351
369
|
|
|
352
|
-
// ──
|
|
370
|
+
// ── Top bar ─────────────────────────────────────────────────────
|
|
353
371
|
lines.push(...ui.bar());
|
|
354
372
|
|
|
373
|
+
// ── Header: GSD AUTO ... elapsed ────────────────────────────────
|
|
355
374
|
const dot = pulseBright
|
|
356
375
|
? theme.fg("accent", GLYPH.statusActive)
|
|
357
376
|
: theme.fg("dim", GLYPH.statusPending);
|
|
358
377
|
const elapsed = formatAutoElapsed(accessors.getAutoStartTime());
|
|
359
378
|
const modeTag = accessors.isStepMode() ? "NEXT" : "AUTO";
|
|
360
|
-
const headerLeft = `${pad}${dot} ${theme.fg("accent", theme.bold("GSD"))}
|
|
379
|
+
const headerLeft = `${pad}${dot} ${theme.fg("accent", theme.bold("GSD"))} ${theme.fg("success", modeTag)}`;
|
|
361
380
|
const headerRight = elapsed ? theme.fg("dim", elapsed) : "";
|
|
362
381
|
lines.push(rightAlign(headerLeft, headerRight, width));
|
|
363
382
|
|
|
364
|
-
|
|
365
|
-
|
|
366
|
-
if (mid)
|
|
367
|
-
lines.push(truncateToWidth(`${pad}${theme.fg("dim", mid.title)}`, width));
|
|
368
|
-
}
|
|
369
|
-
|
|
383
|
+
// ── Context: project · slice · action (merged into one line) ────
|
|
384
|
+
const contextParts: string[] = [];
|
|
385
|
+
if (mid) contextParts.push(theme.fg("dim", mid.title));
|
|
370
386
|
if (slice && unitType !== "research-milestone" && unitType !== "plan-milestone") {
|
|
371
|
-
|
|
372
|
-
`${pad}${theme.fg("text", theme.bold(`${slice.id}: ${slice.title}`))}`,
|
|
373
|
-
width,
|
|
374
|
-
));
|
|
387
|
+
contextParts.push(theme.fg("text", theme.bold(`${slice.id}: ${slice.title}`)));
|
|
375
388
|
}
|
|
376
|
-
|
|
377
|
-
lines.push("");
|
|
378
|
-
|
|
379
389
|
const isHook = unitType.startsWith("hook/");
|
|
380
390
|
const target = isHook
|
|
381
391
|
? (unitId.split("/").pop() ?? unitId)
|
|
382
392
|
: (task ? `${task.id}: ${task.title}` : unitId);
|
|
383
|
-
|
|
393
|
+
contextParts.push(`${theme.fg("accent", "▸")} ${theme.fg("accent", verb)} ${theme.fg("text", target)}`);
|
|
394
|
+
|
|
384
395
|
const tierTag = tierBadge ? theme.fg("dim", `[${tierBadge}] `) : "";
|
|
385
396
|
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
|
-
|
|
397
|
+
const contextLine = contextParts.join(theme.fg("dim", " · "));
|
|
398
|
+
lines.push(rightAlign(`${pad}${contextLine}`, phaseBadge, width));
|
|
399
|
+
|
|
400
|
+
// ── Two-column body ─────────────────────────────────────────────
|
|
401
|
+
// Left: progress, ETA, next, stats (fixed) | Right: task checklist (fixed, adjacent)
|
|
402
|
+
// Both columns sit left-to-center; empty space is on the right.
|
|
403
|
+
const divider = theme.fg("dim", "│");
|
|
404
|
+
const minTwoColWidth = 100;
|
|
405
|
+
const rightColFixed = 44;
|
|
406
|
+
const colGap = 5; // breathing room between columns
|
|
407
|
+
// Left column takes remaining space — no truncation on wide terminals
|
|
408
|
+
const useTwoCol = width >= minTwoColWidth;
|
|
409
|
+
const rightColWidth = useTwoCol ? rightColFixed : 0;
|
|
410
|
+
const leftColWidth = useTwoCol ? width - rightColWidth - colGap : width;
|
|
411
|
+
|
|
412
|
+
const roadmapSlices = mid ? getRoadmapSlicesSync() : null;
|
|
413
|
+
|
|
414
|
+
// Build left column: progress bar, ETA, next step, token stats
|
|
415
|
+
const leftLines: string[] = [];
|
|
416
|
+
|
|
417
|
+
if (roadmapSlices) {
|
|
418
|
+
const { done, total, activeSliceTasks } = roadmapSlices;
|
|
419
|
+
const barWidth = Math.max(6, Math.min(18, Math.floor(leftColWidth * 0.4)));
|
|
420
|
+
const pct = total > 0 ? done / total : 0;
|
|
421
|
+
const filled = Math.round(pct * barWidth);
|
|
422
|
+
const bar = theme.fg("success", "█".repeat(filled))
|
|
423
|
+
+ theme.fg("dim", "░".repeat(barWidth - filled));
|
|
424
|
+
|
|
425
|
+
let meta = theme.fg("dim", `${done}/${total} slices`);
|
|
426
|
+
if (activeSliceTasks && activeSliceTasks.total > 0) {
|
|
427
|
+
const taskNum = isHook
|
|
428
|
+
? Math.max(activeSliceTasks.done, 1)
|
|
429
|
+
: Math.min(activeSliceTasks.done + 1, activeSliceTasks.total);
|
|
430
|
+
meta += theme.fg("dim", ` · task ${taskNum}/${activeSliceTasks.total}`);
|
|
431
|
+
}
|
|
432
|
+
leftLines.push(truncateToWidth(`${pad}${bar} ${meta}`, leftColWidth));
|
|
414
433
|
|
|
415
|
-
|
|
434
|
+
const eta = estimateTimeRemaining();
|
|
435
|
+
if (eta) {
|
|
436
|
+
leftLines.push(truncateToWidth(`${pad}${theme.fg("dim", eta)}`, leftColWidth));
|
|
416
437
|
}
|
|
417
438
|
}
|
|
418
439
|
|
|
419
|
-
lines.push("");
|
|
420
|
-
|
|
421
440
|
if (next) {
|
|
422
|
-
|
|
441
|
+
leftLines.push(truncateToWidth(
|
|
423
442
|
`${pad}${theme.fg("dim", "→")} ${theme.fg("dim", `then ${next}`)}`,
|
|
424
|
-
|
|
443
|
+
leftColWidth,
|
|
425
444
|
));
|
|
426
445
|
}
|
|
427
446
|
|
|
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
|
|
447
|
+
// Token stats
|
|
433
448
|
{
|
|
434
449
|
const cmdCtx = accessors.getCmdCtx();
|
|
435
450
|
let totalInput = 0, totalOutput = 0;
|
|
@@ -464,7 +479,6 @@ export function updateProgressWidget(
|
|
|
464
479
|
if (totalOutput) sp.push(`↓${formatWidgetTokens(totalOutput)}`);
|
|
465
480
|
if (totalCacheRead) sp.push(`R${formatWidgetTokens(totalCacheRead)}`);
|
|
466
481
|
if (totalCacheWrite) sp.push(`W${formatWidgetTokens(totalCacheWrite)}`);
|
|
467
|
-
// Cache hit rate for current unit
|
|
468
482
|
if (totalCacheRead + totalInput > 0) {
|
|
469
483
|
const hitRate = Math.round((totalCacheRead / (totalCacheRead + totalInput)) * 100);
|
|
470
484
|
sp.push(`\u26A1${hitRate}%`);
|
|
@@ -483,33 +497,134 @@ export function updateProgressWidget(
|
|
|
483
497
|
sp.push(cxDisplay);
|
|
484
498
|
}
|
|
485
499
|
|
|
486
|
-
const
|
|
500
|
+
const tokenLine = sp.map(p => p.includes("\x1b[") ? p : theme.fg("dim", p))
|
|
487
501
|
.join(theme.fg("dim", " "));
|
|
502
|
+
leftLines.push(truncateToWidth(`${pad}${tokenLine}`, leftColWidth));
|
|
488
503
|
|
|
489
504
|
const modelId = cmdCtx?.model?.id ?? "";
|
|
490
505
|
const modelProvider = cmdCtx?.model?.provider ?? "";
|
|
491
|
-
const modelPhase = phaseLabel ? theme.fg("dim", `[${phaseLabel}] `) : "";
|
|
492
506
|
const modelDisplay = modelProvider && modelId
|
|
493
507
|
? `${modelProvider}/${modelId}`
|
|
494
508
|
: modelId;
|
|
495
|
-
|
|
496
|
-
|
|
497
|
-
|
|
498
|
-
lines.push(rightAlign(`${pad}${sLeft}`, sRight, width));
|
|
509
|
+
if (modelDisplay) {
|
|
510
|
+
leftLines.push(truncateToWidth(`${pad}${theme.fg("dim", modelDisplay)}`, leftColWidth));
|
|
511
|
+
}
|
|
499
512
|
|
|
500
|
-
// Dynamic routing savings
|
|
513
|
+
// Dynamic routing savings
|
|
501
514
|
if (mLedger && mLedger.units.some(u => u.tier)) {
|
|
502
515
|
const savings = formatTierSavings(mLedger.units);
|
|
503
516
|
if (savings) {
|
|
504
|
-
|
|
517
|
+
leftLines.push(truncateToWidth(`${pad}${theme.fg("dim", savings)}`, leftColWidth));
|
|
518
|
+
}
|
|
519
|
+
}
|
|
520
|
+
}
|
|
521
|
+
|
|
522
|
+
// Build right column: task checklist (pegged to right edge)
|
|
523
|
+
const rightLines: string[] = [];
|
|
524
|
+
const taskDetails = roadmapSlices?.taskDetails ?? null;
|
|
525
|
+
const maxVisibleTasks = 8;
|
|
526
|
+
const rpad = " ";
|
|
527
|
+
|
|
528
|
+
if (useTwoCol) {
|
|
529
|
+
if (taskDetails && taskDetails.length > 0) {
|
|
530
|
+
const visibleTasks = taskDetails.slice(0, maxVisibleTasks);
|
|
531
|
+
for (const t of visibleTasks) {
|
|
532
|
+
const isCurrent = task && t.id === task.id;
|
|
533
|
+
const glyph = t.done
|
|
534
|
+
? theme.fg("success", GLYPH.statusDone)
|
|
535
|
+
: isCurrent
|
|
536
|
+
? theme.fg("accent", "▸")
|
|
537
|
+
: theme.fg("dim", " ");
|
|
538
|
+
const label = isCurrent
|
|
539
|
+
? theme.fg("text", `${t.id}: ${t.title}`)
|
|
540
|
+
: t.done
|
|
541
|
+
? theme.fg("dim", `${t.id}: ${t.title}`)
|
|
542
|
+
: theme.fg("text", `${t.id}: ${t.title}`);
|
|
543
|
+
rightLines.push(truncateToWidth(`${rpad}${glyph} ${label}`, rightColWidth));
|
|
544
|
+
}
|
|
545
|
+
if (taskDetails.length > maxVisibleTasks) {
|
|
546
|
+
rightLines.push(truncateToWidth(
|
|
547
|
+
`${rpad}${theme.fg("dim", ` …+${taskDetails.length - maxVisibleTasks} more`)}`,
|
|
548
|
+
rightColWidth,
|
|
549
|
+
));
|
|
550
|
+
}
|
|
551
|
+
} else if (roadmapSlices?.activeSliceTasks) {
|
|
552
|
+
const { done: tDone, total: tTotal } = roadmapSlices.activeSliceTasks;
|
|
553
|
+
rightLines.push(`${rpad}${theme.fg("dim", `${tDone}/${tTotal} tasks`)}`);
|
|
554
|
+
}
|
|
555
|
+
} else {
|
|
556
|
+
// Narrow single-column: task list goes into left column
|
|
557
|
+
if (taskDetails && taskDetails.length > 0) {
|
|
558
|
+
for (const t of taskDetails.slice(0, maxVisibleTasks)) {
|
|
559
|
+
const isCurrent = task && t.id === task.id;
|
|
560
|
+
const glyph = t.done
|
|
561
|
+
? theme.fg("success", GLYPH.statusDone)
|
|
562
|
+
: isCurrent
|
|
563
|
+
? theme.fg("accent", "▸")
|
|
564
|
+
: theme.fg("dim", " ");
|
|
565
|
+
const label = isCurrent
|
|
566
|
+
? theme.fg("text", `${t.id}: ${t.title}`)
|
|
567
|
+
: t.done
|
|
568
|
+
? theme.fg("dim", `${t.id}: ${t.title}`)
|
|
569
|
+
: theme.fg("text", `${t.id}: ${t.title}`);
|
|
570
|
+
leftLines.push(truncateToWidth(`${pad}${glyph} ${label}`, leftColWidth));
|
|
571
|
+
}
|
|
572
|
+
}
|
|
573
|
+
// Add progress bar inline
|
|
574
|
+
if (roadmapSlices) {
|
|
575
|
+
const { done, total, activeSliceTasks } = roadmapSlices;
|
|
576
|
+
const barWidth = Math.max(6, Math.min(18, Math.floor(leftColWidth * 0.4)));
|
|
577
|
+
const pct = total > 0 ? done / total : 0;
|
|
578
|
+
const filled = Math.round(pct * barWidth);
|
|
579
|
+
const bar = theme.fg("success", "█".repeat(filled))
|
|
580
|
+
+ theme.fg("dim", "░".repeat(barWidth - filled));
|
|
581
|
+
let meta = theme.fg("dim", `${done}/${total} slices`);
|
|
582
|
+
if (activeSliceTasks && activeSliceTasks.total > 0) {
|
|
583
|
+
const taskNum = isHook
|
|
584
|
+
? Math.max(activeSliceTasks.done, 1)
|
|
585
|
+
: Math.min(activeSliceTasks.done + 1, activeSliceTasks.total);
|
|
586
|
+
meta += theme.fg("dim", ` · task ${taskNum}/${activeSliceTasks.total}`);
|
|
587
|
+
}
|
|
588
|
+
const eta = estimateTimeRemaining();
|
|
589
|
+
if (eta) meta += theme.fg("dim", ` · ${eta}`);
|
|
590
|
+
leftLines.push(truncateToWidth(`${pad}${bar} ${meta}`, leftColWidth));
|
|
591
|
+
}
|
|
592
|
+
if (next) {
|
|
593
|
+
leftLines.push(truncateToWidth(
|
|
594
|
+
`${pad}${theme.fg("dim", "→")} ${theme.fg("dim", `then ${next}`)}`,
|
|
595
|
+
leftColWidth,
|
|
596
|
+
));
|
|
597
|
+
}
|
|
598
|
+
}
|
|
599
|
+
|
|
600
|
+
// Compose columns
|
|
601
|
+
if (useTwoCol) {
|
|
602
|
+
const maxRows = Math.max(leftLines.length, rightLines.length);
|
|
603
|
+
if (maxRows > 0) {
|
|
604
|
+
lines.push(""); // spacer before columns
|
|
605
|
+
for (let i = 0; i < maxRows; i++) {
|
|
606
|
+
const left = padToWidth(leftLines[i] ?? "", leftColWidth);
|
|
607
|
+
const gap = " ".repeat(colGap - 2); // colGap minus divider and its trailing space
|
|
608
|
+
const right = rightLines[i] ?? "";
|
|
609
|
+
lines.push(truncateToWidth(`${left}${gap}${divider} ${right}`, width));
|
|
505
610
|
}
|
|
506
611
|
}
|
|
612
|
+
} else {
|
|
613
|
+
// Narrow single-column: just stack
|
|
614
|
+
if (leftLines.length > 0) {
|
|
615
|
+
lines.push("");
|
|
616
|
+
for (const l of leftLines) lines.push(l);
|
|
617
|
+
}
|
|
507
618
|
}
|
|
508
619
|
|
|
620
|
+
// ── Footer: pwd + hints ─────────────────────────────────────────
|
|
621
|
+
lines.push("");
|
|
509
622
|
const hintParts: string[] = [];
|
|
510
623
|
hintParts.push("esc pause");
|
|
511
624
|
hintParts.push(process.platform === "darwin" ? "⌃⌥G dashboard" : "Ctrl+Alt+G dashboard");
|
|
512
|
-
|
|
625
|
+
const hintStr = theme.fg("dim", hintParts.join(" | "));
|
|
626
|
+
const pwdStr = theme.fg("dim", widgetPwd);
|
|
627
|
+
lines.push(rightAlign(`${pad}${pwdStr}`, hintStr, width));
|
|
513
628
|
|
|
514
629
|
lines.push(...ui.bar());
|
|
515
630
|
|
|
@@ -535,6 +650,31 @@ export function updateProgressWidget(
|
|
|
535
650
|
* Build a compact string-array representation of the progress widget.
|
|
536
651
|
* Used as a fallback when the factory-based widget cannot render (RPC mode).
|
|
537
652
|
*/
|
|
653
|
+
// ─── Model Health Indicator ───────────────────────────────────────────────────
|
|
654
|
+
|
|
655
|
+
/**
|
|
656
|
+
* Compute a traffic-light health indicator from observable signals.
|
|
657
|
+
* 🟢 progressing well — no errors, trend stable/improving
|
|
658
|
+
* 🟡 struggling — some errors or degrading trend
|
|
659
|
+
* 🔴 stuck — consecutive errors, likely needs attention
|
|
660
|
+
*/
|
|
661
|
+
export function getModelHealthIndicator(): { emoji: string; label: string } {
|
|
662
|
+
const trend = getHealthTrend();
|
|
663
|
+
const consecutiveErrors = getConsecutiveErrorUnits();
|
|
664
|
+
|
|
665
|
+
if (consecutiveErrors >= 3) {
|
|
666
|
+
return { emoji: "🔴", label: "stuck" };
|
|
667
|
+
}
|
|
668
|
+
if (consecutiveErrors >= 1 || trend === "degrading") {
|
|
669
|
+
return { emoji: "🟡", label: "struggling" };
|
|
670
|
+
}
|
|
671
|
+
if (trend === "improving") {
|
|
672
|
+
return { emoji: "🟢", label: "progressing well" };
|
|
673
|
+
}
|
|
674
|
+
// stable or unknown
|
|
675
|
+
return { emoji: "🟢", label: "progressing" };
|
|
676
|
+
}
|
|
677
|
+
|
|
538
678
|
function buildProgressTextLines(
|
|
539
679
|
verb: string,
|
|
540
680
|
phaseLabel: string,
|
|
@@ -583,6 +723,11 @@ function buildProgressTextLines(
|
|
|
583
723
|
}
|
|
584
724
|
|
|
585
725
|
if (next) lines.push(` Next: ${next}`);
|
|
726
|
+
|
|
727
|
+
// Model health indicator
|
|
728
|
+
const health = getModelHealthIndicator();
|
|
729
|
+
lines.push(` Health: ${health.emoji} ${health.label}`);
|
|
730
|
+
|
|
586
731
|
lines.push(` ${widgetPwd}`);
|
|
587
732
|
|
|
588
733
|
return lines;
|
|
@@ -597,3 +742,10 @@ function rightAlign(left: string, right: string, width: number): string {
|
|
|
597
742
|
const gap = Math.max(1, width - leftVis - rightVis);
|
|
598
743
|
return truncateToWidth(left + " ".repeat(gap) + right, width);
|
|
599
744
|
}
|
|
745
|
+
|
|
746
|
+
/** Pad a string with trailing spaces to fill exactly `colWidth` (ANSI-aware). */
|
|
747
|
+
function padToWidth(s: string, colWidth: number): string {
|
|
748
|
+
const vis = visibleWidth(s);
|
|
749
|
+
if (vis >= colWidth) return truncateToWidth(s, colWidth);
|
|
750
|
+
return s + " ".repeat(colWidth - vis);
|
|
751
|
+
}
|
|
@@ -126,8 +126,8 @@ const DISPATCH_RULES: DispatchRule[] = [
|
|
|
126
126
|
{
|
|
127
127
|
name: "reassess-roadmap (post-completion)",
|
|
128
128
|
match: async ({ state, mid, midTitle, basePath, prefs }) => {
|
|
129
|
-
//
|
|
130
|
-
if (prefs?.phases?.
|
|
129
|
+
// Reassess is opt-in: only fire when explicitly enabled
|
|
130
|
+
if (!prefs?.phases?.reassess_after_slice) return null;
|
|
131
131
|
const needsReassess = await checkNeedsReassessment(basePath, mid, state);
|
|
132
132
|
if (!needsReassess) return null;
|
|
133
133
|
return {
|
|
@@ -35,6 +35,7 @@ import {
|
|
|
35
35
|
import { writeUnitRuntimeRecord, clearUnitRuntimeRecord } from "./unit-runtime.js";
|
|
36
36
|
import { resolveAutoSupervisorConfig, loadEffectiveGSDPreferences } from "./preferences.js";
|
|
37
37
|
import { runGSDDoctor, rebuildState, summarizeDoctorIssues } from "./doctor.js";
|
|
38
|
+
import { COMPLETION_TRANSITION_CODES } from "./doctor-types.js";
|
|
38
39
|
import { recordHealthSnapshot, checkHealEscalation } from "./doctor-proactive.js";
|
|
39
40
|
import { syncStateToProjectRoot } from "./auto-worktree-sync.js";
|
|
40
41
|
import { resetRewriteCircuitBreaker } from "./auto-dispatch.js";
|
|
@@ -154,13 +155,17 @@ export async function postUnitPreVerification(pctx: PostUnitContext): Promise<"d
|
|
|
154
155
|
ctx.ui.notify(`Post-hook: applied ${report.fixesApplied.length} fix(es).`, "info");
|
|
155
156
|
}
|
|
156
157
|
|
|
157
|
-
// Proactive health tracking
|
|
158
|
-
|
|
158
|
+
// Proactive health tracking — exclude completion-transition codes at task level
|
|
159
|
+
// since they are expected after the last task and resolved by complete-slice
|
|
160
|
+
const issuesForHealth = effectiveFixLevel === "task"
|
|
161
|
+
? report.issues.filter(i => !COMPLETION_TRANSITION_CODES.has(i.code))
|
|
162
|
+
: report.issues;
|
|
163
|
+
const summary = summarizeDoctorIssues(issuesForHealth);
|
|
159
164
|
recordHealthSnapshot(summary.errors, summary.warnings, report.fixesApplied.length);
|
|
160
165
|
|
|
161
166
|
// Check if we should escalate to LLM-assisted heal
|
|
162
167
|
if (summary.errors > 0) {
|
|
163
|
-
const unresolvedErrors =
|
|
168
|
+
const unresolvedErrors = issuesForHealth
|
|
164
169
|
.filter(i => i.severity === "error" && !i.fixable)
|
|
165
170
|
.map(i => ({ code: i.code, message: i.message, unitId: i.unitId }));
|
|
166
171
|
const escalation = checkHealEscalation(summary.errors, unresolvedErrors);
|
|
@@ -171,7 +176,7 @@ export async function postUnitPreVerification(pctx: PostUnitContext): Promise<"d
|
|
|
171
176
|
);
|
|
172
177
|
try {
|
|
173
178
|
const { formatDoctorIssuesForPrompt, formatDoctorReport } = await import("./doctor.js");
|
|
174
|
-
const { dispatchDoctorHeal } = await import("./commands.js");
|
|
179
|
+
const { dispatchDoctorHeal } = await import("./commands-handlers.js");
|
|
175
180
|
const actionable = report.issues.filter(i => i.severity === "error");
|
|
176
181
|
const reportText = formatDoctorReport(report, { scope: doctorScope, includeWarnings: true });
|
|
177
182
|
const structuredIssues = formatDoctorIssuesForPrompt(actionable);
|
|
@@ -197,10 +202,13 @@ export async function postUnitPreVerification(pctx: PostUnitContext): Promise<"d
|
|
|
197
202
|
}
|
|
198
203
|
}
|
|
199
204
|
|
|
200
|
-
// Prune dead bg-shell processes
|
|
205
|
+
// Prune dead bg-shell processes and kill non-persistent live ones.
|
|
206
|
+
// Without killing live processes between units, dev servers spawned during
|
|
207
|
+
// one task keep ports bound, causing conflicts in subsequent tasks (#1209).
|
|
201
208
|
try {
|
|
202
|
-
const { pruneDeadProcesses } = await import("../bg-shell/process-manager.js");
|
|
209
|
+
const { pruneDeadProcesses, killSessionProcesses } = await import("../bg-shell/process-manager.js");
|
|
203
210
|
pruneDeadProcesses();
|
|
211
|
+
killSessionProcesses();
|
|
204
212
|
} catch {
|
|
205
213
|
// Non-fatal
|
|
206
214
|
}
|
|
@@ -323,6 +331,45 @@ export async function postUnitPostVerification(pctx: PostUnitContext): Promise<"
|
|
|
323
331
|
}
|
|
324
332
|
}
|
|
325
333
|
|
|
334
|
+
// ── Mechanical completion (ADR-003) ──
|
|
335
|
+
// After task execution, attempt mechanical slice and milestone completion
|
|
336
|
+
// instead of dispatching LLM sessions for complete-slice / validate-milestone.
|
|
337
|
+
if (s.currentUnit?.type === "execute-task" && !s.stepMode) {
|
|
338
|
+
try {
|
|
339
|
+
const [mid, sid] = s.currentUnit.id.split("/");
|
|
340
|
+
if (mid && sid) {
|
|
341
|
+
const state = await deriveState(s.basePath);
|
|
342
|
+
if (state.phase === "summarizing" && state.activeSlice?.id === sid) {
|
|
343
|
+
const { mechanicalSliceCompletion } = await import("./mechanical-completion.js");
|
|
344
|
+
const ok = await mechanicalSliceCompletion(s.basePath, mid, sid);
|
|
345
|
+
if (ok) {
|
|
346
|
+
invalidateAllCaches();
|
|
347
|
+
autoCommitCurrentBranch(s.basePath, "mechanical-completion", `${mid}/${sid}`);
|
|
348
|
+
ctx.ui.notify(`Mechanical completion: ${sid} summary + roadmap updated.`, "info");
|
|
349
|
+
|
|
350
|
+
// Re-derive state — check if milestone is now ready for validation
|
|
351
|
+
invalidateAllCaches();
|
|
352
|
+
const postSliceState = await deriveState(s.basePath);
|
|
353
|
+
if (postSliceState.phase === "validating-milestone" || postSliceState.phase === "completing-milestone") {
|
|
354
|
+
const { aggregateMilestoneVerification, generateMilestoneSummary } = await import("./mechanical-completion.js");
|
|
355
|
+
const validation = await aggregateMilestoneVerification(s.basePath, mid);
|
|
356
|
+
if (validation.verdict !== "failed") {
|
|
357
|
+
await generateMilestoneSummary(s.basePath, mid);
|
|
358
|
+
invalidateAllCaches();
|
|
359
|
+
autoCommitCurrentBranch(s.basePath, "mechanical-milestone-completion", mid);
|
|
360
|
+
ctx.ui.notify(`Mechanical completion: ${mid} validation + summary written.`, "info");
|
|
361
|
+
}
|
|
362
|
+
}
|
|
363
|
+
}
|
|
364
|
+
// If !ok, summarizing phase persists → dispatch rule fires as LLM fallback
|
|
365
|
+
}
|
|
366
|
+
}
|
|
367
|
+
} catch (err) {
|
|
368
|
+
process.stderr.write(`gsd-mechanical: completion failed: ${(err as Error).message}\n`);
|
|
369
|
+
// Non-fatal — fall through to normal dispatch
|
|
370
|
+
}
|
|
371
|
+
}
|
|
372
|
+
|
|
326
373
|
// ── Post-unit hooks ──
|
|
327
374
|
if (s.currentUnit && !s.stepMode) {
|
|
328
375
|
const hookUnit = checkPostUnitHooks(s.currentUnit.type, s.currentUnit.id, s.basePath);
|
|
@@ -589,14 +589,18 @@ export async function buildPlanMilestonePrompt(mid: string, midTitle: string, ba
|
|
|
589
589
|
const { inlinePriorMilestoneSummary } = await import("./files.js");
|
|
590
590
|
const priorSummaryInline = await inlinePriorMilestoneSummary(mid, base);
|
|
591
591
|
if (priorSummaryInline) inlined.push(priorSummaryInline);
|
|
592
|
-
|
|
593
|
-
|
|
594
|
-
|
|
595
|
-
|
|
596
|
-
|
|
597
|
-
|
|
598
|
-
|
|
599
|
-
|
|
592
|
+
// Build source file paths for the planner to read on demand (reduces inlining)
|
|
593
|
+
const sourcePaths: string[] = [];
|
|
594
|
+
if (existsSync(resolveGsdRootFile(base, "PROJECT")))
|
|
595
|
+
sourcePaths.push(`- **Project**: \`${relGsdRootFile("PROJECT")}\``);
|
|
596
|
+
if (existsSync(resolveGsdRootFile(base, "REQUIREMENTS")))
|
|
597
|
+
sourcePaths.push(`- **Requirements**: \`${relGsdRootFile("REQUIREMENTS")}\``);
|
|
598
|
+
if (existsSync(resolveGsdRootFile(base, "DECISIONS")))
|
|
599
|
+
sourcePaths.push(`- **Decisions**: \`${relGsdRootFile("DECISIONS")}\``);
|
|
600
|
+
const sourceFilePaths = sourcePaths.length > 0
|
|
601
|
+
? sourcePaths.join("\n")
|
|
602
|
+
: "_No project/requirements/decisions files found._";
|
|
603
|
+
|
|
600
604
|
const knowledgeInlinePM = await inlineGsdRootFile(base, "knowledge.md", "Project Knowledge");
|
|
601
605
|
if (knowledgeInlinePM) inlined.push(knowledgeInlinePM);
|
|
602
606
|
inlined.push(inlineTemplate("roadmap", "Roadmap"));
|
|
@@ -615,6 +619,7 @@ export async function buildPlanMilestonePrompt(mid: string, midTitle: string, ba
|
|
|
615
619
|
|
|
616
620
|
const outputRelPath = relMilestoneFile(base, mid, "ROADMAP");
|
|
617
621
|
const secretsOutputPath = join(base, relMilestoneFile(base, mid, "SECRETS"));
|
|
622
|
+
const researchOutputRelPath = relMilestoneFile(base, mid, "RESEARCH");
|
|
618
623
|
return loadPrompt("plan-milestone", {
|
|
619
624
|
workingDirectory: base,
|
|
620
625
|
milestoneId: mid, milestoneTitle: midTitle,
|
|
@@ -624,6 +629,9 @@ export async function buildPlanMilestonePrompt(mid: string, midTitle: string, ba
|
|
|
624
629
|
outputPath: join(base, outputRelPath),
|
|
625
630
|
secretsOutputPath,
|
|
626
631
|
inlinedContext,
|
|
632
|
+
sourceFilePaths,
|
|
633
|
+
researchOutputPath: join(base, researchOutputRelPath),
|
|
634
|
+
...buildSkillDiscoveryVars(),
|
|
627
635
|
});
|
|
628
636
|
}
|
|
629
637
|
|
|
@@ -686,12 +694,16 @@ export async function buildPlanSlicePrompt(
|
|
|
686
694
|
inlined.push(await inlineFile(roadmapPath, roadmapRel, "Milestone Roadmap"));
|
|
687
695
|
const researchInline = await inlineFileOptional(researchPath, researchRel, "Slice Research");
|
|
688
696
|
if (researchInline) inlined.push(researchInline);
|
|
689
|
-
|
|
690
|
-
|
|
691
|
-
|
|
692
|
-
|
|
693
|
-
|
|
694
|
-
|
|
697
|
+
// Build source file paths for the planner to read on demand (reduces inlining)
|
|
698
|
+
const sliceSourcePaths: string[] = [];
|
|
699
|
+
if (existsSync(resolveGsdRootFile(base, "REQUIREMENTS")))
|
|
700
|
+
sliceSourcePaths.push(`- **Requirements**: \`${relGsdRootFile("REQUIREMENTS")}\``);
|
|
701
|
+
if (existsSync(resolveGsdRootFile(base, "DECISIONS")))
|
|
702
|
+
sliceSourcePaths.push(`- **Decisions**: \`${relGsdRootFile("DECISIONS")}\``);
|
|
703
|
+
const sliceSourceFilePaths = sliceSourcePaths.length > 0
|
|
704
|
+
? sliceSourcePaths.join("\n")
|
|
705
|
+
: "_No requirements/decisions files found._";
|
|
706
|
+
|
|
695
707
|
const knowledgeInlinePS = await inlineGsdRootFile(base, "knowledge.md", "Project Knowledge");
|
|
696
708
|
if (knowledgeInlinePS) inlined.push(knowledgeInlinePS);
|
|
697
709
|
inlined.push(inlineTemplate("plan", "Slice Plan"));
|
|
@@ -726,6 +738,7 @@ export async function buildPlanSlicePrompt(
|
|
|
726
738
|
dependencySummaries: depContent,
|
|
727
739
|
executorContextConstraints,
|
|
728
740
|
commitInstruction,
|
|
741
|
+
sourceFilePaths: sliceSourceFilePaths,
|
|
729
742
|
});
|
|
730
743
|
}
|
|
731
744
|
|