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.
Files changed (285) hide show
  1. package/README.md +24 -17
  2. package/dist/cli.js +15 -9
  3. package/dist/headless.js +4 -0
  4. package/dist/resource-loader.js +80 -8
  5. package/dist/resources/extensions/bg-shell/process-manager.ts +13 -0
  6. package/dist/resources/extensions/gsd/auto-dashboard.ts +217 -65
  7. package/dist/resources/extensions/gsd/auto-dispatch.ts +2 -2
  8. package/dist/resources/extensions/gsd/auto-post-unit.ts +53 -6
  9. package/dist/resources/extensions/gsd/auto-prompts.ts +27 -14
  10. package/dist/resources/extensions/gsd/auto-recovery.ts +33 -23
  11. package/dist/resources/extensions/gsd/auto-start.ts +25 -10
  12. package/dist/resources/extensions/gsd/auto-verification.ts +41 -7
  13. package/dist/resources/extensions/gsd/auto-worktree-sync.ts +21 -6
  14. package/dist/resources/extensions/gsd/auto-worktree.ts +9 -0
  15. package/dist/resources/extensions/gsd/auto.ts +67 -22
  16. package/dist/resources/extensions/gsd/commands-handlers.ts +3 -11
  17. package/dist/resources/extensions/gsd/commands-logs.ts +536 -0
  18. package/dist/resources/extensions/gsd/commands-prefs-wizard.ts +90 -47
  19. package/dist/resources/extensions/gsd/commands-workflow-templates.ts +544 -0
  20. package/dist/resources/extensions/gsd/commands.ts +75 -29
  21. package/dist/resources/extensions/gsd/dashboard-overlay.ts +2 -1
  22. package/dist/resources/extensions/gsd/doctor-types.ts +13 -0
  23. package/dist/resources/extensions/gsd/doctor.ts +2 -6
  24. package/dist/resources/extensions/gsd/export.ts +28 -2
  25. package/dist/resources/extensions/gsd/gsd-db.ts +19 -0
  26. package/dist/resources/extensions/gsd/index.ts +2 -1
  27. package/dist/resources/extensions/gsd/json-persistence.ts +67 -0
  28. package/dist/resources/extensions/gsd/mechanical-completion.ts +430 -0
  29. package/dist/resources/extensions/gsd/metrics.ts +17 -31
  30. package/dist/resources/extensions/gsd/paths.ts +17 -8
  31. package/dist/resources/extensions/gsd/preferences-models.ts +7 -1
  32. package/dist/resources/extensions/gsd/preferences-validation.ts +2 -1
  33. package/dist/resources/extensions/gsd/prompts/discuss-headless.md +4 -2
  34. package/dist/resources/extensions/gsd/prompts/guided-discuss-milestone.md +1 -1
  35. package/dist/resources/extensions/gsd/prompts/plan-milestone.md +26 -2
  36. package/dist/resources/extensions/gsd/prompts/plan-slice.md +15 -1
  37. package/dist/resources/extensions/gsd/prompts/workflow-start.md +28 -0
  38. package/dist/resources/extensions/gsd/queue-order.ts +10 -11
  39. package/dist/resources/extensions/gsd/routing-history.ts +13 -17
  40. package/dist/resources/extensions/gsd/session-lock.ts +284 -0
  41. package/dist/resources/extensions/gsd/session-status-io.ts +23 -41
  42. package/dist/resources/extensions/gsd/tests/auto-budget-alerts.test.ts +1 -1
  43. package/dist/resources/extensions/gsd/tests/auto-skip-loop.test.ts +1 -1
  44. package/dist/resources/extensions/gsd/tests/commands-logs.test.ts +241 -0
  45. package/dist/resources/extensions/gsd/tests/extension-selector-separator.test.ts +60 -38
  46. package/dist/resources/extensions/gsd/tests/gsd-inspect.test.ts +1 -1
  47. package/dist/resources/extensions/gsd/tests/mechanical-completion.test.ts +356 -0
  48. package/dist/resources/extensions/gsd/tests/parallel-workers-multi-milestone-e2e.test.ts +1 -1
  49. package/dist/resources/extensions/gsd/tests/plan-slice-prompt.test.ts +1 -0
  50. package/dist/resources/extensions/gsd/tests/session-lock.test.ts +315 -0
  51. package/dist/resources/extensions/gsd/tests/token-profile.test.ts +14 -16
  52. package/dist/resources/extensions/gsd/tests/validate-milestone.test.ts +55 -0
  53. package/dist/resources/extensions/gsd/tests/verification-evidence.test.ts +26 -24
  54. package/dist/resources/extensions/gsd/tests/verification-gate.test.ts +136 -7
  55. package/dist/resources/extensions/gsd/tests/workflow-templates.test.ts +173 -0
  56. package/dist/resources/extensions/gsd/types.ts +3 -0
  57. package/dist/resources/extensions/gsd/unit-runtime.ts +16 -13
  58. package/dist/resources/extensions/gsd/verification-evidence.ts +2 -0
  59. package/dist/resources/extensions/gsd/verification-gate.ts +13 -2
  60. package/dist/resources/extensions/gsd/workflow-templates/bugfix.md +87 -0
  61. package/dist/resources/extensions/gsd/workflow-templates/dep-upgrade.md +74 -0
  62. package/dist/resources/extensions/gsd/workflow-templates/full-project.md +41 -0
  63. package/dist/resources/extensions/gsd/workflow-templates/hotfix.md +45 -0
  64. package/dist/resources/extensions/gsd/workflow-templates/refactor.md +83 -0
  65. package/dist/resources/extensions/gsd/workflow-templates/registry.json +85 -0
  66. package/dist/resources/extensions/gsd/workflow-templates/security-audit.md +73 -0
  67. package/dist/resources/extensions/gsd/workflow-templates/small-feature.md +81 -0
  68. package/dist/resources/extensions/gsd/workflow-templates/spike.md +69 -0
  69. package/dist/resources/extensions/gsd/workflow-templates.ts +241 -0
  70. package/dist/resources/extensions/mcp-client/index.ts +459 -0
  71. package/dist/resources/extensions/remote-questions/discord-adapter.ts +9 -20
  72. package/dist/resources/extensions/remote-questions/http-client.ts +76 -0
  73. package/dist/resources/extensions/remote-questions/notify.ts +1 -2
  74. package/dist/resources/extensions/remote-questions/slack-adapter.ts +11 -18
  75. package/dist/resources/extensions/remote-questions/telegram-adapter.ts +8 -20
  76. package/dist/resources/extensions/remote-questions/types.ts +3 -0
  77. package/dist/resources/extensions/shared/mod.ts +3 -0
  78. package/dist/resources/skills/create-gsd-extension/SKILL.md +87 -0
  79. package/dist/resources/skills/create-gsd-extension/references/compaction-session-control.md +77 -0
  80. package/dist/resources/skills/create-gsd-extension/references/custom-commands.md +139 -0
  81. package/dist/resources/skills/create-gsd-extension/references/custom-rendering.md +108 -0
  82. package/dist/resources/skills/create-gsd-extension/references/custom-tools.md +183 -0
  83. package/dist/resources/skills/create-gsd-extension/references/custom-ui.md +490 -0
  84. package/dist/resources/skills/create-gsd-extension/references/events-reference.md +126 -0
  85. package/dist/resources/skills/create-gsd-extension/references/extension-lifecycle.md +64 -0
  86. package/dist/resources/skills/create-gsd-extension/references/extensionapi-reference.md +75 -0
  87. package/dist/resources/skills/create-gsd-extension/references/extensioncontext-reference.md +53 -0
  88. package/dist/resources/skills/create-gsd-extension/references/key-rules-gotchas.md +36 -0
  89. package/dist/resources/skills/create-gsd-extension/references/mode-behavior.md +32 -0
  90. package/dist/resources/skills/create-gsd-extension/references/model-provider-management.md +89 -0
  91. package/dist/resources/skills/create-gsd-extension/references/packaging-distribution.md +55 -0
  92. package/dist/resources/skills/create-gsd-extension/references/remote-execution-overrides.md +90 -0
  93. package/dist/resources/skills/create-gsd-extension/references/state-management.md +70 -0
  94. package/dist/resources/skills/create-gsd-extension/references/system-prompt-modification.md +52 -0
  95. package/dist/resources/skills/create-gsd-extension/templates/extension-skeleton.ts +51 -0
  96. package/dist/resources/skills/create-gsd-extension/templates/stateful-tool-skeleton.ts +143 -0
  97. package/dist/resources/skills/create-gsd-extension/workflows/add-capability.md +57 -0
  98. package/dist/resources/skills/create-gsd-extension/workflows/create-extension.md +156 -0
  99. package/dist/resources/skills/create-gsd-extension/workflows/debug-extension.md +74 -0
  100. package/dist/resources/skills/create-skill/SKILL.md +184 -0
  101. package/dist/resources/skills/create-skill/references/api-security.md +226 -0
  102. package/dist/resources/skills/create-skill/references/be-clear-and-direct.md +531 -0
  103. package/dist/resources/skills/create-skill/references/common-patterns.md +595 -0
  104. package/dist/resources/skills/create-skill/references/core-principles.md +437 -0
  105. package/dist/resources/skills/create-skill/references/executable-code.md +175 -0
  106. package/dist/resources/skills/create-skill/references/gsd-skill-ecosystem.md +68 -0
  107. package/dist/resources/skills/create-skill/references/iteration-and-testing.md +474 -0
  108. package/dist/resources/skills/create-skill/references/recommended-structure.md +168 -0
  109. package/dist/resources/skills/create-skill/references/skill-structure.md +372 -0
  110. package/dist/resources/skills/create-skill/references/use-xml-tags.md +466 -0
  111. package/dist/resources/skills/create-skill/references/using-scripts.md +113 -0
  112. package/dist/resources/skills/create-skill/references/using-templates.md +112 -0
  113. package/dist/resources/skills/create-skill/references/workflows-and-validation.md +510 -0
  114. package/dist/resources/skills/create-skill/templates/router-skill.md +73 -0
  115. package/dist/resources/skills/create-skill/templates/simple-skill.md +33 -0
  116. package/dist/resources/skills/create-skill/workflows/add-reference.md +96 -0
  117. package/dist/resources/skills/create-skill/workflows/add-script.md +93 -0
  118. package/dist/resources/skills/create-skill/workflows/add-template.md +74 -0
  119. package/dist/resources/skills/create-skill/workflows/add-workflow.md +120 -0
  120. package/dist/resources/skills/create-skill/workflows/audit-skill.md +148 -0
  121. package/dist/resources/skills/create-skill/workflows/create-new-skill.md +196 -0
  122. package/dist/resources/skills/create-skill/workflows/get-guidance.md +121 -0
  123. package/dist/resources/skills/create-skill/workflows/upgrade-to-router.md +161 -0
  124. package/dist/resources/skills/create-skill/workflows/verify-skill.md +204 -0
  125. package/package.json +6 -3
  126. package/packages/native/dist/native.d.ts +2 -0
  127. package/packages/native/dist/native.js +19 -5
  128. package/packages/native/src/native.ts +23 -9
  129. package/packages/pi-coding-agent/dist/core/extensions/loader.d.ts.map +1 -1
  130. package/packages/pi-coding-agent/dist/core/extensions/loader.js +13 -0
  131. package/packages/pi-coding-agent/dist/core/extensions/loader.js.map +1 -1
  132. package/packages/pi-coding-agent/dist/core/lsp/client.d.ts.map +1 -1
  133. package/packages/pi-coding-agent/dist/core/lsp/client.js +3 -0
  134. package/packages/pi-coding-agent/dist/core/lsp/client.js.map +1 -1
  135. package/packages/pi-coding-agent/dist/core/settings-manager.d.ts +3 -0
  136. package/packages/pi-coding-agent/dist/core/settings-manager.d.ts.map +1 -1
  137. package/packages/pi-coding-agent/dist/core/settings-manager.js +8 -0
  138. package/packages/pi-coding-agent/dist/core/settings-manager.js.map +1 -1
  139. package/packages/pi-coding-agent/dist/core/system-prompt.d.ts.map +1 -1
  140. package/packages/pi-coding-agent/dist/core/system-prompt.js +10 -0
  141. package/packages/pi-coding-agent/dist/core/system-prompt.js.map +1 -1
  142. package/packages/pi-coding-agent/dist/modes/interactive/interactive-mode.d.ts.map +1 -1
  143. package/packages/pi-coding-agent/dist/modes/interactive/interactive-mode.js +4 -1
  144. package/packages/pi-coding-agent/dist/modes/interactive/interactive-mode.js.map +1 -1
  145. package/packages/pi-coding-agent/package.json +1 -1
  146. package/packages/pi-coding-agent/scripts/copy-assets.cjs +39 -8
  147. package/packages/pi-coding-agent/src/core/extensions/loader.ts +13 -0
  148. package/packages/pi-coding-agent/src/core/lsp/client.ts +3 -0
  149. package/packages/pi-coding-agent/src/core/settings-manager.ts +11 -0
  150. package/packages/pi-coding-agent/src/core/system-prompt.ts +11 -0
  151. package/packages/pi-coding-agent/src/modes/interactive/interactive-mode.ts +4 -1
  152. package/packages/pi-tui/dist/autocomplete.d.ts +3 -0
  153. package/packages/pi-tui/dist/autocomplete.d.ts.map +1 -1
  154. package/packages/pi-tui/dist/autocomplete.js +14 -0
  155. package/packages/pi-tui/dist/autocomplete.js.map +1 -1
  156. package/packages/pi-tui/src/autocomplete.ts +19 -1
  157. package/pkg/package.json +1 -1
  158. package/src/resources/extensions/bg-shell/process-manager.ts +13 -0
  159. package/src/resources/extensions/gsd/auto-dashboard.ts +217 -65
  160. package/src/resources/extensions/gsd/auto-dispatch.ts +2 -2
  161. package/src/resources/extensions/gsd/auto-post-unit.ts +53 -6
  162. package/src/resources/extensions/gsd/auto-prompts.ts +27 -14
  163. package/src/resources/extensions/gsd/auto-recovery.ts +33 -23
  164. package/src/resources/extensions/gsd/auto-start.ts +25 -10
  165. package/src/resources/extensions/gsd/auto-verification.ts +41 -7
  166. package/src/resources/extensions/gsd/auto-worktree-sync.ts +21 -6
  167. package/src/resources/extensions/gsd/auto-worktree.ts +9 -0
  168. package/src/resources/extensions/gsd/auto.ts +67 -22
  169. package/src/resources/extensions/gsd/commands-handlers.ts +3 -11
  170. package/src/resources/extensions/gsd/commands-logs.ts +536 -0
  171. package/src/resources/extensions/gsd/commands-prefs-wizard.ts +90 -47
  172. package/src/resources/extensions/gsd/commands-workflow-templates.ts +544 -0
  173. package/src/resources/extensions/gsd/commands.ts +75 -29
  174. package/src/resources/extensions/gsd/dashboard-overlay.ts +2 -1
  175. package/src/resources/extensions/gsd/doctor-types.ts +13 -0
  176. package/src/resources/extensions/gsd/doctor.ts +2 -6
  177. package/src/resources/extensions/gsd/export.ts +28 -2
  178. package/src/resources/extensions/gsd/gsd-db.ts +19 -0
  179. package/src/resources/extensions/gsd/index.ts +2 -1
  180. package/src/resources/extensions/gsd/json-persistence.ts +67 -0
  181. package/src/resources/extensions/gsd/mechanical-completion.ts +430 -0
  182. package/src/resources/extensions/gsd/metrics.ts +17 -31
  183. package/src/resources/extensions/gsd/paths.ts +17 -8
  184. package/src/resources/extensions/gsd/preferences-models.ts +7 -1
  185. package/src/resources/extensions/gsd/preferences-validation.ts +2 -1
  186. package/src/resources/extensions/gsd/prompts/discuss-headless.md +4 -2
  187. package/src/resources/extensions/gsd/prompts/guided-discuss-milestone.md +1 -1
  188. package/src/resources/extensions/gsd/prompts/plan-milestone.md +26 -2
  189. package/src/resources/extensions/gsd/prompts/plan-slice.md +15 -1
  190. package/src/resources/extensions/gsd/prompts/workflow-start.md +28 -0
  191. package/src/resources/extensions/gsd/queue-order.ts +10 -11
  192. package/src/resources/extensions/gsd/routing-history.ts +13 -17
  193. package/src/resources/extensions/gsd/session-lock.ts +284 -0
  194. package/src/resources/extensions/gsd/session-status-io.ts +23 -41
  195. package/src/resources/extensions/gsd/tests/auto-budget-alerts.test.ts +1 -1
  196. package/src/resources/extensions/gsd/tests/auto-skip-loop.test.ts +1 -1
  197. package/src/resources/extensions/gsd/tests/commands-logs.test.ts +241 -0
  198. package/src/resources/extensions/gsd/tests/extension-selector-separator.test.ts +60 -38
  199. package/src/resources/extensions/gsd/tests/gsd-inspect.test.ts +1 -1
  200. package/src/resources/extensions/gsd/tests/mechanical-completion.test.ts +356 -0
  201. package/src/resources/extensions/gsd/tests/parallel-workers-multi-milestone-e2e.test.ts +1 -1
  202. package/src/resources/extensions/gsd/tests/plan-slice-prompt.test.ts +1 -0
  203. package/src/resources/extensions/gsd/tests/session-lock.test.ts +315 -0
  204. package/src/resources/extensions/gsd/tests/token-profile.test.ts +14 -16
  205. package/src/resources/extensions/gsd/tests/validate-milestone.test.ts +55 -0
  206. package/src/resources/extensions/gsd/tests/verification-evidence.test.ts +26 -24
  207. package/src/resources/extensions/gsd/tests/verification-gate.test.ts +136 -7
  208. package/src/resources/extensions/gsd/tests/workflow-templates.test.ts +173 -0
  209. package/src/resources/extensions/gsd/types.ts +3 -0
  210. package/src/resources/extensions/gsd/unit-runtime.ts +16 -13
  211. package/src/resources/extensions/gsd/verification-evidence.ts +2 -0
  212. package/src/resources/extensions/gsd/verification-gate.ts +13 -2
  213. package/src/resources/extensions/gsd/workflow-templates/bugfix.md +87 -0
  214. package/src/resources/extensions/gsd/workflow-templates/dep-upgrade.md +74 -0
  215. package/src/resources/extensions/gsd/workflow-templates/full-project.md +41 -0
  216. package/src/resources/extensions/gsd/workflow-templates/hotfix.md +45 -0
  217. package/src/resources/extensions/gsd/workflow-templates/refactor.md +83 -0
  218. package/src/resources/extensions/gsd/workflow-templates/registry.json +85 -0
  219. package/src/resources/extensions/gsd/workflow-templates/security-audit.md +73 -0
  220. package/src/resources/extensions/gsd/workflow-templates/small-feature.md +81 -0
  221. package/src/resources/extensions/gsd/workflow-templates/spike.md +69 -0
  222. package/src/resources/extensions/gsd/workflow-templates.ts +241 -0
  223. package/src/resources/extensions/mcp-client/index.ts +459 -0
  224. package/src/resources/extensions/remote-questions/discord-adapter.ts +9 -20
  225. package/src/resources/extensions/remote-questions/http-client.ts +76 -0
  226. package/src/resources/extensions/remote-questions/notify.ts +1 -2
  227. package/src/resources/extensions/remote-questions/slack-adapter.ts +11 -18
  228. package/src/resources/extensions/remote-questions/telegram-adapter.ts +8 -20
  229. package/src/resources/extensions/remote-questions/types.ts +3 -0
  230. package/src/resources/extensions/shared/mod.ts +3 -0
  231. package/src/resources/skills/create-gsd-extension/SKILL.md +87 -0
  232. package/src/resources/skills/create-gsd-extension/references/compaction-session-control.md +77 -0
  233. package/src/resources/skills/create-gsd-extension/references/custom-commands.md +139 -0
  234. package/src/resources/skills/create-gsd-extension/references/custom-rendering.md +108 -0
  235. package/src/resources/skills/create-gsd-extension/references/custom-tools.md +183 -0
  236. package/src/resources/skills/create-gsd-extension/references/custom-ui.md +490 -0
  237. package/src/resources/skills/create-gsd-extension/references/events-reference.md +126 -0
  238. package/src/resources/skills/create-gsd-extension/references/extension-lifecycle.md +64 -0
  239. package/src/resources/skills/create-gsd-extension/references/extensionapi-reference.md +75 -0
  240. package/src/resources/skills/create-gsd-extension/references/extensioncontext-reference.md +53 -0
  241. package/src/resources/skills/create-gsd-extension/references/key-rules-gotchas.md +36 -0
  242. package/src/resources/skills/create-gsd-extension/references/mode-behavior.md +32 -0
  243. package/src/resources/skills/create-gsd-extension/references/model-provider-management.md +89 -0
  244. package/src/resources/skills/create-gsd-extension/references/packaging-distribution.md +55 -0
  245. package/src/resources/skills/create-gsd-extension/references/remote-execution-overrides.md +90 -0
  246. package/src/resources/skills/create-gsd-extension/references/state-management.md +70 -0
  247. package/src/resources/skills/create-gsd-extension/references/system-prompt-modification.md +52 -0
  248. package/src/resources/skills/create-gsd-extension/templates/extension-skeleton.ts +51 -0
  249. package/src/resources/skills/create-gsd-extension/templates/stateful-tool-skeleton.ts +143 -0
  250. package/src/resources/skills/create-gsd-extension/workflows/add-capability.md +57 -0
  251. package/src/resources/skills/create-gsd-extension/workflows/create-extension.md +156 -0
  252. package/src/resources/skills/create-gsd-extension/workflows/debug-extension.md +74 -0
  253. package/src/resources/skills/create-skill/SKILL.md +184 -0
  254. package/src/resources/skills/create-skill/references/api-security.md +226 -0
  255. package/src/resources/skills/create-skill/references/be-clear-and-direct.md +531 -0
  256. package/src/resources/skills/create-skill/references/common-patterns.md +595 -0
  257. package/src/resources/skills/create-skill/references/core-principles.md +437 -0
  258. package/src/resources/skills/create-skill/references/executable-code.md +175 -0
  259. package/src/resources/skills/create-skill/references/gsd-skill-ecosystem.md +68 -0
  260. package/src/resources/skills/create-skill/references/iteration-and-testing.md +474 -0
  261. package/src/resources/skills/create-skill/references/recommended-structure.md +168 -0
  262. package/src/resources/skills/create-skill/references/skill-structure.md +372 -0
  263. package/src/resources/skills/create-skill/references/use-xml-tags.md +466 -0
  264. package/src/resources/skills/create-skill/references/using-scripts.md +113 -0
  265. package/src/resources/skills/create-skill/references/using-templates.md +112 -0
  266. package/src/resources/skills/create-skill/references/workflows-and-validation.md +510 -0
  267. package/src/resources/skills/create-skill/templates/router-skill.md +73 -0
  268. package/src/resources/skills/create-skill/templates/simple-skill.md +33 -0
  269. package/src/resources/skills/create-skill/workflows/add-reference.md +96 -0
  270. package/src/resources/skills/create-skill/workflows/add-script.md +93 -0
  271. package/src/resources/skills/create-skill/workflows/add-template.md +74 -0
  272. package/src/resources/skills/create-skill/workflows/add-workflow.md +120 -0
  273. package/src/resources/skills/create-skill/workflows/audit-skill.md +148 -0
  274. package/src/resources/skills/create-skill/workflows/create-new-skill.md +196 -0
  275. package/src/resources/skills/create-skill/workflows/get-guidance.md +121 -0
  276. package/src/resources/skills/create-skill/workflows/upgrade-to-router.md +161 -0
  277. package/src/resources/skills/create-skill/workflows/verify-skill.md +204 -0
  278. package/dist/resources/extensions/gsd/preferences-hooks.ts +0 -10
  279. package/dist/resources/extensions/mcporter/index.ts +0 -525
  280. package/dist/resources/extensions/shared/progress-widget.ts +0 -282
  281. package/dist/resources/extensions/shared/thinking-widget.ts +0 -107
  282. package/src/resources/extensions/gsd/preferences-hooks.ts +0 -10
  283. package/src/resources/extensions/mcporter/index.ts +0 -525
  284. package/src/resources/extensions/shared/progress-widget.ts +0 -282
  285. 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(): { done: number; total: number; activeSliceTasks: { done: number; total: number } | null } | null {
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
- // ── Line 1: Top bar ───────────────────────────────────────────────
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"))} ${theme.fg("success", modeTag)}`;
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
- lines.push("");
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
- lines.push(truncateToWidth(
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
- const actionLeft = `${pad}${theme.fg("accent", "▸")} ${theme.fg("accent", verb)} ${theme.fg("text", target)}`;
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
- lines.push(rightAlign(actionLeft, phaseBadge, width));
387
- lines.push("");
388
-
389
- if (mid) {
390
- const roadmapSlices = getRoadmapSlicesSync();
391
- if (roadmapSlices) {
392
- const { done, total, activeSliceTasks } = roadmapSlices;
393
- const barWidth = Math.max(8, Math.min(24, Math.floor(width * 0.3)));
394
- const pct = total > 0 ? done / total : 0;
395
- const filled = Math.round(pct * barWidth);
396
- const bar = theme.fg("success", "█".repeat(filled))
397
- + theme.fg("dim", "░".repeat(barWidth - filled));
398
-
399
- let meta = theme.fg("dim", `${done}/${total} slices`);
400
-
401
- if (activeSliceTasks && activeSliceTasks.total > 0) {
402
- // For hooks, show the trigger task number (done), not the next task (done + 1)
403
- const taskNum = isHook
404
- ? Math.max(activeSliceTasks.done, 1)
405
- : Math.min(activeSliceTasks.done + 1, activeSliceTasks.total);
406
- meta += theme.fg("dim", ` · task ${taskNum}/${activeSliceTasks.total}`);
407
- }
408
-
409
- // ETA estimate
410
- const eta = estimateTimeRemaining();
411
- if (eta) {
412
- meta += theme.fg("dim", ` · ${eta}`);
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
- lines.push(truncateToWidth(`${pad}${bar} ${meta}`, width));
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
- lines.push(truncateToWidth(
441
+ leftLines.push(truncateToWidth(
423
442
  `${pad}${theme.fg("dim", "→")} ${theme.fg("dim", `then ${next}`)}`,
424
- width,
443
+ leftColWidth,
425
444
  ));
426
445
  }
427
446
 
428
- // ── Footer info (pwd, tokens, cost, context, model) ──────────────
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 sLeft = sp.map(p => p.includes("\x1b[") ? p : theme.fg("dim", p))
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
- const sRight = modelDisplay
496
- ? `${modelPhase}${theme.fg("dim", modelDisplay)}`
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 summary
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
- lines.push(truncateToWidth(theme.fg("dim", `${pad}${savings}`), width));
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
- lines.push(...ui.hints(hintParts));
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
- // Phase skip: skip reassess when preference or profile says so
130
- if (prefs?.phases?.skip_reassess) return null;
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
- const summary = summarizeDoctorIssues(report.issues);
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 = report.issues
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
- if (inlineLevel !== "minimal") {
593
- const projectInline = await inlineProjectFromDb(base);
594
- if (projectInline) inlined.push(projectInline);
595
- const requirementsInline = await inlineRequirementsFromDb(base, undefined, inlineLevel);
596
- if (requirementsInline) inlined.push(requirementsInline);
597
- const decisionsInline = await inlineDecisionsFromDb(base, mid, undefined, inlineLevel);
598
- if (decisionsInline) inlined.push(decisionsInline);
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
- if (inlineLevel !== "minimal") {
690
- const decisionsInline = await inlineDecisionsFromDb(base, mid, undefined, inlineLevel);
691
- if (decisionsInline) inlined.push(decisionsInline);
692
- const requirementsInline = await inlineRequirementsFromDb(base, sid, inlineLevel);
693
- if (requirementsInline) inlined.push(requirementsInline);
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