gsd-pi 2.33.1-dev.ee47f1b → 2.34.0-dev.0150ae9

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 (356) hide show
  1. package/dist/bundled-resource-path.d.ts +8 -0
  2. package/dist/bundled-resource-path.js +14 -0
  3. package/dist/headless-query.js +6 -6
  4. package/dist/resources/extensions/gsd/auto/session.js +27 -32
  5. package/dist/resources/extensions/gsd/auto-dashboard.js +29 -109
  6. package/dist/resources/extensions/gsd/auto-direct-dispatch.js +6 -1
  7. package/dist/resources/extensions/gsd/auto-dispatch.js +52 -81
  8. package/dist/resources/extensions/gsd/auto-loop.js +956 -0
  9. package/dist/resources/extensions/gsd/auto-observability.js +4 -2
  10. package/dist/resources/extensions/gsd/auto-post-unit.js +75 -185
  11. package/dist/resources/extensions/gsd/auto-prompts.js +133 -101
  12. package/dist/resources/extensions/gsd/auto-recovery.js +59 -97
  13. package/dist/resources/extensions/gsd/auto-start.js +330 -309
  14. package/dist/resources/extensions/gsd/auto-supervisor.js +5 -11
  15. package/dist/resources/extensions/gsd/auto-timeout-recovery.js +7 -7
  16. package/dist/resources/extensions/gsd/auto-timers.js +3 -4
  17. package/dist/resources/extensions/gsd/auto-verification.js +35 -73
  18. package/dist/resources/extensions/gsd/auto-worktree-sync.js +167 -0
  19. package/dist/resources/extensions/gsd/auto-worktree.js +291 -126
  20. package/dist/resources/extensions/gsd/auto.js +283 -1013
  21. package/dist/resources/extensions/gsd/captures.js +10 -4
  22. package/dist/resources/extensions/gsd/dispatch-guard.js +7 -8
  23. package/dist/resources/extensions/gsd/docs/preferences-reference.md +25 -18
  24. package/dist/resources/extensions/gsd/doctor-checks.js +3 -4
  25. package/dist/resources/extensions/gsd/git-service.js +1 -1
  26. package/dist/resources/extensions/gsd/gsd-db.js +296 -151
  27. package/dist/resources/extensions/gsd/index.js +92 -228
  28. package/dist/resources/extensions/gsd/post-unit-hooks.js +13 -13
  29. package/dist/resources/extensions/gsd/progress-score.js +61 -156
  30. package/dist/resources/extensions/gsd/quick.js +98 -122
  31. package/dist/resources/extensions/gsd/session-lock.js +13 -0
  32. package/dist/resources/extensions/gsd/templates/preferences.md +1 -0
  33. package/dist/resources/extensions/gsd/undo.js +43 -48
  34. package/dist/resources/extensions/gsd/unit-runtime.js +16 -15
  35. package/dist/resources/extensions/gsd/verification-evidence.js +0 -1
  36. package/dist/resources/extensions/gsd/verification-gate.js +6 -35
  37. package/dist/resources/extensions/gsd/worktree-command.js +30 -24
  38. package/dist/resources/extensions/gsd/worktree-manager.js +2 -3
  39. package/dist/resources/extensions/gsd/worktree-resolver.js +344 -0
  40. package/dist/resources/extensions/gsd/worktree.js +7 -44
  41. package/dist/resources/extensions/mcp-client/index.js +2 -1
  42. package/dist/tool-bootstrap.js +59 -11
  43. package/dist/worktree-cli.js +7 -7
  44. package/package.json +1 -1
  45. package/packages/native/dist/native.d.ts +0 -2
  46. package/packages/native/dist/native.js +0 -2
  47. package/packages/native/src/native.ts +0 -3
  48. package/packages/pi-agent-core/dist/proxy.d.ts +1 -25
  49. package/packages/pi-agent-core/dist/proxy.d.ts.map +1 -1
  50. package/packages/pi-agent-core/dist/proxy.js +1 -1
  51. package/packages/pi-agent-core/dist/proxy.js.map +1 -1
  52. package/packages/pi-agent-core/src/proxy.ts +1 -1
  53. package/packages/pi-ai/dist/api-registry.d.ts +0 -2
  54. package/packages/pi-ai/dist/api-registry.d.ts.map +1 -1
  55. package/packages/pi-ai/dist/api-registry.js +0 -10
  56. package/packages/pi-ai/dist/api-registry.js.map +1 -1
  57. package/packages/pi-ai/dist/models.generated.d.ts +3630 -5483
  58. package/packages/pi-ai/dist/models.generated.d.ts.map +1 -1
  59. package/packages/pi-ai/dist/models.generated.js +735 -2588
  60. package/packages/pi-ai/dist/models.generated.js.map +1 -1
  61. package/packages/pi-ai/dist/providers/anthropic.d.ts +0 -8
  62. package/packages/pi-ai/dist/providers/anthropic.d.ts.map +1 -1
  63. package/packages/pi-ai/dist/providers/anthropic.js +1 -1
  64. package/packages/pi-ai/dist/providers/anthropic.js.map +1 -1
  65. package/packages/pi-ai/dist/providers/github-copilot-headers.d.ts +0 -1
  66. package/packages/pi-ai/dist/providers/github-copilot-headers.d.ts.map +1 -1
  67. package/packages/pi-ai/dist/providers/github-copilot-headers.js +1 -1
  68. package/packages/pi-ai/dist/providers/github-copilot-headers.js.map +1 -1
  69. package/packages/pi-ai/dist/providers/google-gemini-cli.d.ts +1 -43
  70. package/packages/pi-ai/dist/providers/google-gemini-cli.d.ts.map +1 -1
  71. package/packages/pi-ai/dist/providers/google-gemini-cli.js +2 -2
  72. package/packages/pi-ai/dist/providers/google-gemini-cli.js.map +1 -1
  73. package/packages/pi-ai/dist/providers/google-shared.d.ts +0 -4
  74. package/packages/pi-ai/dist/providers/google-shared.d.ts.map +1 -1
  75. package/packages/pi-ai/dist/providers/google-shared.js +1 -1
  76. package/packages/pi-ai/dist/providers/google-shared.js.map +1 -1
  77. package/packages/pi-ai/dist/providers/register-builtins.d.ts +0 -1
  78. package/packages/pi-ai/dist/providers/register-builtins.d.ts.map +1 -1
  79. package/packages/pi-ai/dist/providers/register-builtins.js +1 -1
  80. package/packages/pi-ai/dist/providers/register-builtins.js.map +1 -1
  81. package/packages/pi-ai/dist/utils/event-stream.d.ts +0 -2
  82. package/packages/pi-ai/dist/utils/event-stream.d.ts.map +1 -1
  83. package/packages/pi-ai/dist/utils/event-stream.js +0 -4
  84. package/packages/pi-ai/dist/utils/event-stream.js.map +1 -1
  85. package/packages/pi-ai/dist/utils/overflow.d.ts +0 -4
  86. package/packages/pi-ai/dist/utils/overflow.d.ts.map +1 -1
  87. package/packages/pi-ai/dist/utils/overflow.js +0 -6
  88. package/packages/pi-ai/dist/utils/overflow.js.map +1 -1
  89. package/packages/pi-ai/dist/utils/validation.d.ts +0 -8
  90. package/packages/pi-ai/dist/utils/validation.d.ts.map +1 -1
  91. package/packages/pi-ai/dist/utils/validation.js +0 -14
  92. package/packages/pi-ai/dist/utils/validation.js.map +1 -1
  93. package/packages/pi-ai/src/api-registry.ts +0 -12
  94. package/packages/pi-ai/src/models.generated.ts +1039 -2892
  95. package/packages/pi-ai/src/providers/anthropic.ts +1 -1
  96. package/packages/pi-ai/src/providers/github-copilot-headers.ts +1 -1
  97. package/packages/pi-ai/src/providers/google-gemini-cli.ts +2 -2
  98. package/packages/pi-ai/src/providers/google-shared.ts +1 -1
  99. package/packages/pi-ai/src/providers/register-builtins.ts +1 -1
  100. package/packages/pi-ai/src/utils/event-stream.ts +0 -5
  101. package/packages/pi-ai/src/utils/overflow.ts +1 -8
  102. package/packages/pi-ai/src/utils/validation.ts +0 -15
  103. package/packages/pi-coding-agent/dist/config.d.ts +0 -9
  104. package/packages/pi-coding-agent/dist/config.d.ts.map +1 -1
  105. package/packages/pi-coding-agent/dist/config.js +4 -8
  106. package/packages/pi-coding-agent/dist/config.js.map +1 -1
  107. package/packages/pi-coding-agent/dist/core/export-html/ansi-to-html.d.ts +0 -4
  108. package/packages/pi-coding-agent/dist/core/export-html/ansi-to-html.d.ts.map +1 -1
  109. package/packages/pi-coding-agent/dist/core/export-html/ansi-to-html.js +1 -1
  110. package/packages/pi-coding-agent/dist/core/export-html/ansi-to-html.js.map +1 -1
  111. package/packages/pi-coding-agent/dist/core/extensions/runner.d.ts +0 -5
  112. package/packages/pi-coding-agent/dist/core/extensions/runner.d.ts.map +1 -1
  113. package/packages/pi-coding-agent/dist/core/extensions/runner.js +0 -13
  114. package/packages/pi-coding-agent/dist/core/extensions/runner.js.map +1 -1
  115. package/packages/pi-coding-agent/dist/core/keybindings.d.ts +0 -8
  116. package/packages/pi-coding-agent/dist/core/keybindings.d.ts.map +1 -1
  117. package/packages/pi-coding-agent/dist/core/keybindings.js +2 -2
  118. package/packages/pi-coding-agent/dist/core/keybindings.js.map +1 -1
  119. package/packages/pi-coding-agent/dist/core/lsp/client.d.ts +0 -17
  120. package/packages/pi-coding-agent/dist/core/lsp/client.d.ts.map +1 -1
  121. package/packages/pi-coding-agent/dist/core/lsp/client.js +3 -62
  122. package/packages/pi-coding-agent/dist/core/lsp/client.js.map +1 -1
  123. package/packages/pi-coding-agent/dist/core/lsp/config.d.ts +0 -2
  124. package/packages/pi-coding-agent/dist/core/lsp/config.d.ts.map +1 -1
  125. package/packages/pi-coding-agent/dist/core/lsp/config.js +0 -7
  126. package/packages/pi-coding-agent/dist/core/lsp/config.js.map +1 -1
  127. package/packages/pi-coding-agent/dist/core/lsp/edits.d.ts +0 -5
  128. package/packages/pi-coding-agent/dist/core/lsp/edits.d.ts.map +1 -1
  129. package/packages/pi-coding-agent/dist/core/lsp/edits.js +1 -1
  130. package/packages/pi-coding-agent/dist/core/lsp/edits.js.map +1 -1
  131. package/packages/pi-coding-agent/dist/core/lsp/lspmux.d.ts +0 -1
  132. package/packages/pi-coding-agent/dist/core/lsp/lspmux.d.ts.map +1 -1
  133. package/packages/pi-coding-agent/dist/core/lsp/lspmux.js +1 -1
  134. package/packages/pi-coding-agent/dist/core/lsp/lspmux.js.map +1 -1
  135. package/packages/pi-coding-agent/dist/core/lsp/utils.d.ts +1 -6
  136. package/packages/pi-coding-agent/dist/core/lsp/utils.d.ts.map +1 -1
  137. package/packages/pi-coding-agent/dist/core/lsp/utils.js +1 -28
  138. package/packages/pi-coding-agent/dist/core/lsp/utils.js.map +1 -1
  139. package/packages/pi-coding-agent/dist/core/messages.d.ts +0 -8
  140. package/packages/pi-coding-agent/dist/core/messages.d.ts.map +1 -1
  141. package/packages/pi-coding-agent/dist/core/messages.js +5 -5
  142. package/packages/pi-coding-agent/dist/core/messages.js.map +1 -1
  143. package/packages/pi-coding-agent/dist/core/model-registry.d.ts +0 -3
  144. package/packages/pi-coding-agent/dist/core/model-registry.d.ts.map +1 -1
  145. package/packages/pi-coding-agent/dist/core/model-registry.js +1 -3
  146. package/packages/pi-coding-agent/dist/core/model-registry.js.map +1 -1
  147. package/packages/pi-coding-agent/dist/core/model-resolver.d.ts +1 -26
  148. package/packages/pi-coding-agent/dist/core/model-resolver.d.ts.map +1 -1
  149. package/packages/pi-coding-agent/dist/core/model-resolver.js +3 -59
  150. package/packages/pi-coding-agent/dist/core/model-resolver.js.map +1 -1
  151. package/packages/pi-coding-agent/dist/core/prompt-templates.d.ts +0 -17
  152. package/packages/pi-coding-agent/dist/core/prompt-templates.d.ts.map +1 -1
  153. package/packages/pi-coding-agent/dist/core/prompt-templates.js +2 -2
  154. package/packages/pi-coding-agent/dist/core/prompt-templates.js.map +1 -1
  155. package/packages/pi-coding-agent/dist/core/session-manager.d.ts +0 -4
  156. package/packages/pi-coding-agent/dist/core/session-manager.d.ts.map +1 -1
  157. package/packages/pi-coding-agent/dist/core/session-manager.js +2 -4
  158. package/packages/pi-coding-agent/dist/core/session-manager.js.map +1 -1
  159. package/packages/pi-coding-agent/dist/core/settings-manager.d.ts +0 -12
  160. package/packages/pi-coding-agent/dist/core/settings-manager.d.ts.map +1 -1
  161. package/packages/pi-coding-agent/dist/core/settings-manager.js +2 -2
  162. package/packages/pi-coding-agent/dist/core/settings-manager.js.map +1 -1
  163. package/packages/pi-coding-agent/dist/migrations.d.ts +0 -16
  164. package/packages/pi-coding-agent/dist/migrations.d.ts.map +1 -1
  165. package/packages/pi-coding-agent/dist/migrations.js +2 -2
  166. package/packages/pi-coding-agent/dist/migrations.js.map +1 -1
  167. package/packages/pi-coding-agent/dist/modes/interactive/components/session-selector-search.d.ts +0 -2
  168. package/packages/pi-coding-agent/dist/modes/interactive/components/session-selector-search.d.ts.map +1 -1
  169. package/packages/pi-coding-agent/dist/modes/interactive/components/session-selector-search.js +2 -2
  170. package/packages/pi-coding-agent/dist/modes/interactive/components/session-selector-search.js.map +1 -1
  171. package/packages/pi-coding-agent/dist/modes/interactive/interactive-mode.d.ts +1 -24
  172. package/packages/pi-coding-agent/dist/modes/interactive/interactive-mode.d.ts.map +1 -1
  173. package/packages/pi-coding-agent/dist/modes/interactive/interactive-mode.js +50 -512
  174. package/packages/pi-coding-agent/dist/modes/interactive/interactive-mode.js.map +1 -1
  175. package/packages/pi-coding-agent/dist/modes/interactive/slash-command-handlers.d.ts +71 -0
  176. package/packages/pi-coding-agent/dist/modes/interactive/slash-command-handlers.d.ts.map +1 -0
  177. package/packages/pi-coding-agent/dist/modes/interactive/slash-command-handlers.js +514 -0
  178. package/packages/pi-coding-agent/dist/modes/interactive/slash-command-handlers.js.map +1 -0
  179. package/packages/pi-coding-agent/dist/modes/interactive/theme/theme.d.ts +65 -4
  180. package/packages/pi-coding-agent/dist/modes/interactive/theme/theme.d.ts.map +1 -1
  181. package/packages/pi-coding-agent/dist/modes/interactive/theme/theme.js +6 -23
  182. package/packages/pi-coding-agent/dist/modes/interactive/theme/theme.js.map +1 -1
  183. package/packages/pi-coding-agent/dist/modes/interactive/theme/themes.d.ts +12 -0
  184. package/packages/pi-coding-agent/dist/modes/interactive/theme/themes.d.ts.map +1 -0
  185. package/packages/pi-coding-agent/dist/modes/interactive/theme/themes.js +175 -0
  186. package/packages/pi-coding-agent/dist/modes/interactive/theme/themes.js.map +1 -0
  187. package/packages/pi-coding-agent/dist/utils/changelog.d.ts +0 -4
  188. package/packages/pi-coding-agent/dist/utils/changelog.d.ts.map +1 -1
  189. package/packages/pi-coding-agent/dist/utils/changelog.js +1 -1
  190. package/packages/pi-coding-agent/dist/utils/changelog.js.map +1 -1
  191. package/packages/pi-coding-agent/dist/utils/clipboard-image.d.ts +0 -1
  192. package/packages/pi-coding-agent/dist/utils/clipboard-image.d.ts.map +1 -1
  193. package/packages/pi-coding-agent/dist/utils/clipboard-image.js +1 -1
  194. package/packages/pi-coding-agent/dist/utils/clipboard-image.js.map +1 -1
  195. package/packages/pi-coding-agent/dist/utils/photon.d.ts +0 -19
  196. package/packages/pi-coding-agent/dist/utils/photon.d.ts.map +1 -1
  197. package/packages/pi-coding-agent/dist/utils/photon.js +1 -120
  198. package/packages/pi-coding-agent/dist/utils/photon.js.map +1 -1
  199. package/packages/pi-coding-agent/dist/utils/tools-manager.d.ts +0 -1
  200. package/packages/pi-coding-agent/dist/utils/tools-manager.d.ts.map +1 -1
  201. package/packages/pi-coding-agent/dist/utils/tools-manager.js +1 -1
  202. package/packages/pi-coding-agent/dist/utils/tools-manager.js.map +1 -1
  203. package/packages/pi-coding-agent/package.json +1 -1
  204. package/packages/pi-coding-agent/src/config.ts +5 -10
  205. package/packages/pi-coding-agent/src/core/export-html/ansi-to-html.ts +1 -1
  206. package/packages/pi-coding-agent/src/core/extensions/runner.ts +0 -13
  207. package/packages/pi-coding-agent/src/core/keybindings.ts +2 -2
  208. package/packages/pi-coding-agent/src/core/lsp/client.ts +3 -73
  209. package/packages/pi-coding-agent/src/core/lsp/config.ts +0 -11
  210. package/packages/pi-coding-agent/src/core/lsp/edits.ts +1 -1
  211. package/packages/pi-coding-agent/src/core/lsp/lspmux.ts +1 -1
  212. package/packages/pi-coding-agent/src/core/lsp/utils.ts +1 -33
  213. package/packages/pi-coding-agent/src/core/messages.ts +5 -5
  214. package/packages/pi-coding-agent/src/core/model-registry.ts +0 -2
  215. package/packages/pi-coding-agent/src/core/model-resolver.ts +3 -77
  216. package/packages/pi-coding-agent/src/core/prompt-templates.ts +2 -2
  217. package/packages/pi-coding-agent/src/core/session-manager.ts +2 -4
  218. package/packages/pi-coding-agent/src/core/settings-manager.ts +2 -2
  219. package/packages/pi-coding-agent/src/migrations.ts +2 -2
  220. package/packages/pi-coding-agent/src/modes/interactive/components/session-selector-search.ts +2 -2
  221. package/packages/pi-coding-agent/src/modes/interactive/interactive-mode.ts +50 -561
  222. package/packages/pi-coding-agent/src/modes/interactive/slash-command-handlers.ts +653 -0
  223. package/packages/pi-coding-agent/src/modes/interactive/theme/theme.ts +7 -26
  224. package/packages/pi-coding-agent/src/modes/interactive/theme/themes.ts +196 -0
  225. package/packages/pi-coding-agent/src/utils/changelog.ts +1 -1
  226. package/packages/pi-coding-agent/src/utils/clipboard-image.ts +1 -1
  227. package/packages/pi-coding-agent/src/utils/photon.ts +0 -137
  228. package/packages/pi-coding-agent/src/utils/tools-manager.ts +1 -1
  229. package/packages/pi-tui/dist/components/editor.d.ts +0 -10
  230. package/packages/pi-tui/dist/components/editor.d.ts.map +1 -1
  231. package/packages/pi-tui/dist/components/editor.js +1 -1
  232. package/packages/pi-tui/dist/components/editor.js.map +1 -1
  233. package/packages/pi-tui/dist/overlay-layout.d.ts +55 -0
  234. package/packages/pi-tui/dist/overlay-layout.d.ts.map +1 -0
  235. package/packages/pi-tui/dist/overlay-layout.js +288 -0
  236. package/packages/pi-tui/dist/overlay-layout.js.map +1 -0
  237. package/packages/pi-tui/dist/tui.d.ts +0 -22
  238. package/packages/pi-tui/dist/tui.d.ts.map +1 -1
  239. package/packages/pi-tui/dist/tui.js +6 -272
  240. package/packages/pi-tui/dist/tui.js.map +1 -1
  241. package/packages/pi-tui/dist/utils.d.ts +0 -7
  242. package/packages/pi-tui/dist/utils.d.ts.map +1 -1
  243. package/packages/pi-tui/dist/utils.js +0 -44
  244. package/packages/pi-tui/dist/utils.js.map +1 -1
  245. package/packages/pi-tui/src/components/editor.ts +1 -1
  246. package/packages/pi-tui/src/overlay-layout.ts +372 -0
  247. package/packages/pi-tui/src/tui.ts +11 -312
  248. package/packages/pi-tui/src/utils.ts +0 -43
  249. package/pkg/dist/core/export-html/ansi-to-html.d.ts +0 -4
  250. package/pkg/dist/core/export-html/ansi-to-html.d.ts.map +1 -1
  251. package/pkg/dist/core/export-html/ansi-to-html.js +1 -1
  252. package/pkg/dist/core/export-html/ansi-to-html.js.map +1 -1
  253. package/pkg/dist/modes/interactive/theme/theme.d.ts +65 -4
  254. package/pkg/dist/modes/interactive/theme/theme.d.ts.map +1 -1
  255. package/pkg/dist/modes/interactive/theme/theme.js +6 -23
  256. package/pkg/dist/modes/interactive/theme/theme.js.map +1 -1
  257. package/pkg/dist/modes/interactive/theme/themes.d.ts +12 -0
  258. package/pkg/dist/modes/interactive/theme/themes.d.ts.map +1 -0
  259. package/pkg/dist/modes/interactive/theme/themes.js +175 -0
  260. package/pkg/dist/modes/interactive/theme/themes.js.map +1 -0
  261. package/pkg/package.json +1 -1
  262. package/src/resources/extensions/gsd/auto/session.ts +47 -30
  263. package/src/resources/extensions/gsd/auto-dashboard.ts +28 -131
  264. package/src/resources/extensions/gsd/auto-direct-dispatch.ts +6 -1
  265. package/src/resources/extensions/gsd/auto-dispatch.ts +135 -91
  266. package/src/resources/extensions/gsd/auto-loop.ts +1665 -0
  267. package/src/resources/extensions/gsd/auto-observability.ts +4 -2
  268. package/src/resources/extensions/gsd/auto-post-unit.ts +85 -228
  269. package/src/resources/extensions/gsd/auto-prompts.ts +138 -109
  270. package/src/resources/extensions/gsd/auto-recovery.ts +124 -118
  271. package/src/resources/extensions/gsd/auto-start.ts +440 -354
  272. package/src/resources/extensions/gsd/auto-supervisor.ts +5 -12
  273. package/src/resources/extensions/gsd/auto-timeout-recovery.ts +8 -8
  274. package/src/resources/extensions/gsd/auto-timers.ts +3 -4
  275. package/src/resources/extensions/gsd/auto-verification.ts +76 -90
  276. package/src/resources/extensions/gsd/auto-worktree-sync.ts +204 -0
  277. package/src/resources/extensions/gsd/auto-worktree.ts +389 -141
  278. package/src/resources/extensions/gsd/auto.ts +515 -1199
  279. package/src/resources/extensions/gsd/captures.ts +10 -4
  280. package/src/resources/extensions/gsd/dispatch-guard.ts +13 -9
  281. package/src/resources/extensions/gsd/docs/preferences-reference.md +25 -18
  282. package/src/resources/extensions/gsd/doctor-checks.ts +3 -4
  283. package/src/resources/extensions/gsd/git-service.ts +8 -1
  284. package/src/resources/extensions/gsd/gitignore.ts +4 -2
  285. package/src/resources/extensions/gsd/gsd-db.ts +375 -180
  286. package/src/resources/extensions/gsd/index.ts +104 -263
  287. package/src/resources/extensions/gsd/post-unit-hooks.ts +13 -13
  288. package/src/resources/extensions/gsd/progress-score.ts +65 -200
  289. package/src/resources/extensions/gsd/quick.ts +121 -125
  290. package/src/resources/extensions/gsd/session-lock.ts +11 -0
  291. package/src/resources/extensions/gsd/templates/preferences.md +1 -0
  292. package/src/resources/extensions/gsd/tests/agent-end-retry.test.ts +32 -59
  293. package/src/resources/extensions/gsd/tests/all-milestones-complete-merge.test.ts +75 -27
  294. package/src/resources/extensions/gsd/tests/auto-budget-alerts.test.ts +1 -1
  295. package/src/resources/extensions/gsd/tests/auto-lock-creation.test.ts +37 -0
  296. package/src/resources/extensions/gsd/tests/auto-loop.test.ts +1458 -0
  297. package/src/resources/extensions/gsd/tests/auto-recovery.test.ts +8 -162
  298. package/src/resources/extensions/gsd/tests/auto-secrets-gate.test.ts +2 -108
  299. package/src/resources/extensions/gsd/tests/auto-session-encapsulation.test.ts +1 -3
  300. package/src/resources/extensions/gsd/tests/auto-worktree-milestone-merge.test.ts +0 -3
  301. package/src/resources/extensions/gsd/tests/auto-worktree.test.ts +58 -0
  302. package/src/resources/extensions/gsd/tests/dispatch-guard.test.ts +0 -55
  303. package/src/resources/extensions/gsd/tests/headless-query.test.ts +22 -0
  304. package/src/resources/extensions/gsd/tests/milestone-transition-worktree.test.ts +8 -11
  305. package/src/resources/extensions/gsd/tests/provider-errors.test.ts +4 -6
  306. package/src/resources/extensions/gsd/tests/run-uat.test.ts +3 -3
  307. package/src/resources/extensions/gsd/tests/session-lock-regression.test.ts +64 -0
  308. package/src/resources/extensions/gsd/tests/sidecar-queue.test.ts +181 -0
  309. package/src/resources/extensions/gsd/tests/stale-worktree-cwd.test.ts +0 -3
  310. package/src/resources/extensions/gsd/tests/token-profile.test.ts +6 -6
  311. package/src/resources/extensions/gsd/tests/triage-dispatch.test.ts +6 -6
  312. package/src/resources/extensions/gsd/tests/undo.test.ts +6 -0
  313. package/src/resources/extensions/gsd/tests/verification-evidence.test.ts +24 -26
  314. package/src/resources/extensions/gsd/tests/verification-gate.test.ts +7 -201
  315. package/src/resources/extensions/gsd/tests/worktree-db-integration.test.ts +205 -0
  316. package/src/resources/extensions/gsd/tests/worktree-db.test.ts +442 -0
  317. package/src/resources/extensions/gsd/tests/worktree-e2e.test.ts +0 -3
  318. package/src/resources/extensions/gsd/tests/worktree-resolver.test.ts +705 -0
  319. package/src/resources/extensions/gsd/tests/worktree-sync-milestones.test.ts +57 -106
  320. package/src/resources/extensions/gsd/tests/worktree.test.ts +5 -1
  321. package/src/resources/extensions/gsd/tests/write-gate.test.ts +43 -132
  322. package/src/resources/extensions/gsd/types.ts +90 -81
  323. package/src/resources/extensions/gsd/undo.ts +42 -46
  324. package/src/resources/extensions/gsd/unit-runtime.ts +14 -18
  325. package/src/resources/extensions/gsd/verification-evidence.ts +1 -3
  326. package/src/resources/extensions/gsd/verification-gate.ts +6 -39
  327. package/src/resources/extensions/gsd/worktree-command.ts +36 -24
  328. package/src/resources/extensions/gsd/worktree-manager.ts +2 -3
  329. package/src/resources/extensions/gsd/worktree-resolver.ts +485 -0
  330. package/src/resources/extensions/gsd/worktree.ts +7 -44
  331. package/src/resources/extensions/mcp-client/index.ts +2 -1
  332. package/dist/resources/extensions/gsd/auto-constants.js +0 -5
  333. package/dist/resources/extensions/gsd/auto-idempotency.js +0 -106
  334. package/dist/resources/extensions/gsd/auto-stuck-detection.js +0 -165
  335. package/dist/resources/extensions/gsd/mechanical-completion.js +0 -351
  336. package/packages/pi-coding-agent/dist/modes/interactive/theme/dark.json +0 -85
  337. package/packages/pi-coding-agent/dist/modes/interactive/theme/light.json +0 -84
  338. package/packages/pi-coding-agent/dist/modes/interactive/theme/theme-schema.json +0 -335
  339. package/packages/pi-coding-agent/src/modes/interactive/theme/dark.json +0 -85
  340. package/packages/pi-coding-agent/src/modes/interactive/theme/light.json +0 -84
  341. package/packages/pi-coding-agent/src/modes/interactive/theme/theme-schema.json +0 -335
  342. package/pkg/dist/modes/interactive/theme/dark.json +0 -85
  343. package/pkg/dist/modes/interactive/theme/light.json +0 -84
  344. package/pkg/dist/modes/interactive/theme/theme-schema.json +0 -335
  345. package/src/resources/extensions/gsd/auto-constants.ts +0 -6
  346. package/src/resources/extensions/gsd/auto-idempotency.ts +0 -151
  347. package/src/resources/extensions/gsd/auto-stuck-detection.ts +0 -221
  348. package/src/resources/extensions/gsd/mechanical-completion.ts +0 -430
  349. package/src/resources/extensions/gsd/tests/auto-dispatch-loop.test.ts +0 -691
  350. package/src/resources/extensions/gsd/tests/auto-reentrancy-guard.test.ts +0 -127
  351. package/src/resources/extensions/gsd/tests/auto-skip-loop.test.ts +0 -123
  352. package/src/resources/extensions/gsd/tests/dispatch-stall-guard.test.ts +0 -126
  353. package/src/resources/extensions/gsd/tests/loop-regression.test.ts +0 -874
  354. package/src/resources/extensions/gsd/tests/mechanical-completion.test.ts +0 -356
  355. package/src/resources/extensions/gsd/tests/progress-score.test.ts +0 -206
  356. package/src/resources/extensions/gsd/tests/session-lock.test.ts +0 -434
@@ -0,0 +1,8 @@
1
+ /**
2
+ * Resolve bundled raw resource files from the package root.
3
+ *
4
+ * Both `src/*.ts` and compiled `dist/*.js` entry points need to load the same
5
+ * raw `.ts` resource modules via jiti. Those modules are shipped under
6
+ * `src/resources/**`, not next to the compiled entry point.
7
+ */
8
+ export declare function resolveBundledSourceResource(importUrl: string, ...segments: string[]): string;
@@ -0,0 +1,14 @@
1
+ import { dirname, join, resolve } from "node:path";
2
+ import { fileURLToPath } from "node:url";
3
+ /**
4
+ * Resolve bundled raw resource files from the package root.
5
+ *
6
+ * Both `src/*.ts` and compiled `dist/*.js` entry points need to load the same
7
+ * raw `.ts` resource modules via jiti. Those modules are shipped under
8
+ * `src/resources/**`, not next to the compiled entry point.
9
+ */
10
+ export function resolveBundledSourceResource(importUrl, ...segments) {
11
+ const moduleDir = dirname(fileURLToPath(importUrl));
12
+ const packageRoot = resolve(moduleDir, "..");
13
+ return join(packageRoot, "src", "resources", ...segments);
14
+ }
@@ -15,14 +15,14 @@
15
15
  */
16
16
  import { createJiti } from '@mariozechner/jiti';
17
17
  import { fileURLToPath } from 'node:url';
18
- import { dirname, join } from 'node:path';
19
- const __dirname = dirname(fileURLToPath(import.meta.url));
18
+ import { resolveBundledSourceResource } from './bundled-resource-path.js';
20
19
  const jiti = createJiti(fileURLToPath(import.meta.url), { interopDefault: true, debug: false });
20
+ const gsdExtensionPath = (...segments) => resolveBundledSourceResource(import.meta.url, 'extensions', 'gsd', ...segments);
21
21
  async function loadExtensionModules() {
22
- const stateModule = await jiti.import(join(__dirname, 'resources/extensions/gsd/state.ts'), {});
23
- const dispatchModule = await jiti.import(join(__dirname, 'resources/extensions/gsd/auto-dispatch.ts'), {});
24
- const sessionModule = await jiti.import(join(__dirname, 'resources/extensions/gsd/session-status-io.ts'), {});
25
- const prefsModule = await jiti.import(join(__dirname, 'resources/extensions/gsd/preferences.ts'), {});
22
+ const stateModule = await jiti.import(gsdExtensionPath('state.ts'), {});
23
+ const dispatchModule = await jiti.import(gsdExtensionPath('auto-dispatch.ts'), {});
24
+ const sessionModule = await jiti.import(gsdExtensionPath('session-status-io.ts'), {});
25
+ const prefsModule = await jiti.import(gsdExtensionPath('preferences.ts'), {});
26
26
  return {
27
27
  deriveState: stateModule.deriveState,
28
28
  resolveDispatch: dispatchModule.resolveDispatch,
@@ -19,17 +19,12 @@
19
19
  export const MAX_UNIT_DISPATCHES = 3;
20
20
  export const STUB_RECOVERY_THRESHOLD = 2;
21
21
  export const MAX_LIFETIME_DISPATCHES = 6;
22
- export const MAX_CONSECUTIVE_SKIPS = 3;
23
- export const DISPATCH_GAP_TIMEOUT_MS = 5_000;
24
- export const MAX_SKIP_DEPTH = 20;
25
22
  export const NEW_SESSION_TIMEOUT_MS = 30_000;
26
- export const DISPATCH_HANG_TIMEOUT_MS = 60_000;
27
23
  // ─── AutoSession ─────────────────────────────────────────────────────────────
28
24
  export class AutoSession {
29
25
  // ── Lifecycle ────────────────────────────────────────────────────────────
30
26
  active = false;
31
27
  paused = false;
32
- pausedForSecrets = false;
33
28
  stepMode = false;
34
29
  verbose = false;
35
30
  cmdCtx = null;
@@ -41,14 +36,11 @@ export class AutoSession {
41
36
  unitDispatchCount = new Map();
42
37
  unitLifetimeDispatches = new Map();
43
38
  unitRecoveryCount = new Map();
44
- unitConsecutiveSkips = new Map();
45
- completedKeySet = new Set();
46
39
  // ── Timers ───────────────────────────────────────────────────────────────
47
40
  unitTimeoutHandle = null;
48
41
  wrapupWarningHandle = null;
49
42
  idleWatchdogHandle = null;
50
43
  continueHereHandle = null;
51
- dispatchGapHandle = null;
52
44
  // ── Current unit ─────────────────────────────────────────────────────────
53
45
  currentUnit = null;
54
46
  currentUnitRouting = null;
@@ -66,12 +58,8 @@ export class AutoSession {
66
58
  pausedSessionFile = null;
67
59
  resourceVersionOnStart = null;
68
60
  lastStateRebuildAt = 0;
69
- // ── Guards ───────────────────────────────────────────────────────────────
70
- handlingAgentEnd = false;
71
- pendingAgentEndRetry = false;
72
- dispatching = false;
73
- skipDepth = 0;
74
- recentlyEvictedKeys = new Set();
61
+ // ── Sidecar queue ─────────────────────────────────────────────────────
62
+ sidecarQueue = [];
75
63
  // ── Metrics ──────────────────────────────────────────────────────────────
76
64
  autoStartTime = 0;
77
65
  lastPromptCharCount;
@@ -79,6 +67,26 @@ export class AutoSession {
79
67
  pendingQuickTasks = [];
80
68
  // ── Signal handler ───────────────────────────────────────────────────────
81
69
  sigtermHandler = null;
70
+ // ── Loop promise state ──────────────────────────────────────────────────
71
+ /**
72
+ * True only while runUnit is rotating into a fresh session. agent_end events
73
+ * emitted from the previous session's abort during this window must be
74
+ * ignored; they do not belong to the new unit.
75
+ */
76
+ sessionSwitchInFlight = false;
77
+ /**
78
+ * One-shot resolver for the current unit's agent_end promise.
79
+ * Non-null only while a unit is in-flight (between sendMessage and agent_end).
80
+ * Scoped to the session to prevent concurrent session corruption.
81
+ */
82
+ pendingResolve = null;
83
+ /**
84
+ * Queue for agent_end events that arrive when no pendingResolve exists.
85
+ * This happens when error-recovery sendMessage retries produce agent_end
86
+ * events between loop iterations. The next runUnit drains this queue
87
+ * instead of waiting for a new event.
88
+ */
89
+ pendingAgentEndQueue = [];
82
90
  // ── Methods ──────────────────────────────────────────────────────────────
83
91
  clearTimers() {
84
92
  if (this.unitTimeoutHandle) {
@@ -97,15 +105,10 @@ export class AutoSession {
97
105
  clearInterval(this.continueHereHandle);
98
106
  this.continueHereHandle = null;
99
107
  }
100
- if (this.dispatchGapHandle) {
101
- clearTimeout(this.dispatchGapHandle);
102
- this.dispatchGapHandle = null;
103
- }
104
108
  }
105
109
  resetDispatchCounters() {
106
110
  this.unitDispatchCount.clear();
107
111
  this.unitLifetimeDispatches.clear();
108
- this.unitConsecutiveSkips.clear();
109
112
  }
110
113
  get lockBasePath() {
111
114
  return this.originalBasePath || this.basePath;
@@ -123,7 +126,6 @@ export class AutoSession {
123
126
  // Lifecycle
124
127
  this.active = false;
125
128
  this.paused = false;
126
- this.pausedForSecrets = false;
127
129
  this.stepMode = false;
128
130
  this.verbose = false;
129
131
  this.cmdCtx = null;
@@ -135,9 +137,6 @@ export class AutoSession {
135
137
  this.unitDispatchCount.clear();
136
138
  this.unitLifetimeDispatches.clear();
137
139
  this.unitRecoveryCount.clear();
138
- this.unitConsecutiveSkips.clear();
139
- // Note: completedKeySet is intentionally NOT cleared — it persists
140
- // across restarts to prevent re-dispatching completed units.
141
140
  // Unit
142
141
  this.currentUnit = null;
143
142
  this.currentUnitRouting = null;
@@ -155,19 +154,18 @@ export class AutoSession {
155
154
  this.pausedSessionFile = null;
156
155
  this.resourceVersionOnStart = null;
157
156
  this.lastStateRebuildAt = 0;
158
- // Guards
159
- this.handlingAgentEnd = false;
160
- this.pendingAgentEndRetry = false;
161
- this.dispatching = false;
162
- this.skipDepth = 0;
163
- this.recentlyEvictedKeys.clear();
164
157
  // Metrics
165
158
  this.autoStartTime = 0;
166
159
  this.lastPromptCharCount = undefined;
167
160
  this.lastBaselineCharCount = undefined;
168
161
  this.pendingQuickTasks = [];
162
+ this.sidecarQueue = [];
169
163
  // Signal handler
170
164
  this.sigtermHandler = null;
165
+ // Loop promise state
166
+ this.sessionSwitchInFlight = false;
167
+ this.pendingResolve = null;
168
+ this.pendingAgentEndQueue = [];
171
169
  }
172
170
  toJSON() {
173
171
  return {
@@ -178,10 +176,7 @@ export class AutoSession {
178
176
  currentMilestoneId: this.currentMilestoneId,
179
177
  currentUnit: this.currentUnit,
180
178
  completedUnits: this.completedUnits.length,
181
- completedKeySet: this.completedKeySet.size,
182
179
  unitDispatchCount: Object.fromEntries(this.unitDispatchCount),
183
- dispatching: this.dispatching,
184
- skipDepth: this.skipDepth,
185
180
  };
186
181
  }
187
182
  }
@@ -7,42 +7,47 @@
7
7
  */
8
8
  import { getCurrentBranch } from "./worktree.js";
9
9
  import { getActiveHook } from "./post-unit-hooks.js";
10
- import { getLedger, getProjectTotals, formatCost, formatTierSavings } from "./metrics.js";
11
- import { getHealthTrend, getConsecutiveErrorUnits } from "./doctor-proactive.js";
10
+ import { getLedger, getProjectTotals, formatTierSavings } from "./metrics.js";
12
11
  import { resolveMilestoneFile, resolveSliceFile, } from "./paths.js";
13
12
  import { parseRoadmap, parsePlan } from "./files.js";
14
13
  import { readFileSync, existsSync } from "node:fs";
15
14
  import { truncateToWidth, visibleWidth } from "@gsd/pi-tui";
16
15
  import { makeUI, GLYPH, INDENT } from "../shared/mod.js";
17
- import { parseUnitId } from "./unit-id.js";
18
16
  // ─── Unit Description Helpers ─────────────────────────────────────────────────
19
- /** Canonical verb and phase label for each known unit type. */
20
- const UNIT_TYPE_INFO = {
21
- "research-milestone": { verb: "researching", phaseLabel: "RESEARCH" },
22
- "research-slice": { verb: "researching", phaseLabel: "RESEARCH" },
23
- "plan-milestone": { verb: "planning", phaseLabel: "PLAN" },
24
- "plan-slice": { verb: "planning", phaseLabel: "PLAN" },
25
- "execute-task": { verb: "executing", phaseLabel: "EXECUTE" },
26
- "complete-slice": { verb: "completing", phaseLabel: "COMPLETE" },
27
- "replan-slice": { verb: "replanning", phaseLabel: "REPLAN" },
28
- "rewrite-docs": { verb: "rewriting", phaseLabel: "REWRITE" },
29
- "reassess-roadmap": { verb: "reassessing", phaseLabel: "REASSESS" },
30
- "run-uat": { verb: "running UAT", phaseLabel: "UAT" },
31
- };
32
17
  export function unitVerb(unitType) {
33
18
  if (unitType.startsWith("hook/"))
34
19
  return `hook: ${unitType.slice(5)}`;
35
- return UNIT_TYPE_INFO[unitType]?.verb ?? unitType;
20
+ switch (unitType) {
21
+ case "research-milestone":
22
+ case "research-slice": return "researching";
23
+ case "plan-milestone":
24
+ case "plan-slice": return "planning";
25
+ case "execute-task": return "executing";
26
+ case "complete-slice": return "completing";
27
+ case "replan-slice": return "replanning";
28
+ case "rewrite-docs": return "rewriting";
29
+ case "reassess-roadmap": return "reassessing";
30
+ case "run-uat": return "running UAT";
31
+ default: return unitType;
32
+ }
36
33
  }
37
34
  export function unitPhaseLabel(unitType) {
38
35
  if (unitType.startsWith("hook/"))
39
36
  return "HOOK";
40
- return UNIT_TYPE_INFO[unitType]?.phaseLabel ?? unitType.toUpperCase();
37
+ switch (unitType) {
38
+ case "research-milestone": return "RESEARCH";
39
+ case "research-slice": return "RESEARCH";
40
+ case "plan-milestone": return "PLAN";
41
+ case "plan-slice": return "PLAN";
42
+ case "execute-task": return "EXECUTE";
43
+ case "complete-slice": return "COMPLETE";
44
+ case "replan-slice": return "REPLAN";
45
+ case "rewrite-docs": return "REWRITE";
46
+ case "reassess-roadmap": return "REASSESS";
47
+ case "run-uat": return "UAT";
48
+ default: return unitType.toUpperCase();
49
+ }
41
50
  }
42
- /**
43
- * Describe the expected next step after the current unit completes.
44
- * Unit types here mirror the keys in UNIT_TYPE_INFO above.
45
- */
46
51
  function peekNext(unitType, state) {
47
52
  // Show active hook info in progress display
48
53
  const activeHookState = getActiveHook();
@@ -237,12 +242,6 @@ export function updateProgressWidget(ctx, unitType, unitId, state, accessors, ti
237
242
  }
238
243
  if (cachedBranch)
239
244
  widgetPwd = `${widgetPwd} (${cachedBranch})`;
240
- // Set a string-array fallback first — this is the only version RPC mode will
241
- // see, since the factory widget set below is not supported in RPC mode.
242
- const progressText = buildProgressTextLines(verb, phaseLabel, unitId, mid, slice, task, next, accessors, tierBadge, widgetPwd);
243
- ctx.ui.setWidget("gsd-progress", progressText);
244
- // Set the factory-based widget — in TUI mode this replaces the string-array
245
- // version with a dynamic, animated widget. In RPC mode this call is a no-op.
246
245
  ctx.ui.setWidget("gsd-progress", (tui, theme) => {
247
246
  let pulseBright = true;
248
247
  let cachedLines;
@@ -288,11 +287,7 @@ export function updateProgressWidget(ctx, unitType, unitId, state, accessors, ti
288
287
  lines.push(truncateToWidth(`${pad}${theme.fg("text", theme.bold(`${slice.id}: ${slice.title}`))}`, width));
289
288
  }
290
289
  lines.push("");
291
- const isHook = unitType.startsWith("hook/");
292
- const hookParsed = isHook ? parseUnitId(unitId) : undefined;
293
- const target = isHook
294
- ? (hookParsed.task ?? hookParsed.slice ?? unitId)
295
- : (task ? `${task.id}: ${task.title}` : unitId);
290
+ const target = task ? `${task.id}: ${task.title}` : unitId;
296
291
  const actionLeft = `${pad}${theme.fg("accent", "▸")} ${theme.fg("accent", verb)} ${theme.fg("text", target)}`;
297
292
  const tierTag = tierBadge ? theme.fg("dim", `[${tierBadge}] `) : "";
298
293
  const phaseBadge = `${tierTag}${theme.fg("dim", phaseLabel)}`;
@@ -309,10 +304,7 @@ export function updateProgressWidget(ctx, unitType, unitId, state, accessors, ti
309
304
  + theme.fg("dim", "░".repeat(barWidth - filled));
310
305
  let meta = theme.fg("dim", `${done}/${total} slices`);
311
306
  if (activeSliceTasks && activeSliceTasks.total > 0) {
312
- // For hooks, show the trigger task number (done), not the next task (done + 1)
313
- const taskNum = isHook
314
- ? Math.max(activeSliceTasks.done, 1)
315
- : Math.min(activeSliceTasks.done + 1, activeSliceTasks.total);
307
+ const taskNum = Math.min(activeSliceTasks.done + 1, activeSliceTasks.total);
316
308
  meta += theme.fg("dim", ` · task ${taskNum}/${activeSliceTasks.total}`);
317
309
  }
318
310
  // ETA estimate
@@ -374,8 +366,6 @@ export function updateProgressWidget(ctx, unitType, unitId, state, accessors, ti
374
366
  }
375
367
  if (cumulativeCost)
376
368
  sp.push(`$${cumulativeCost.toFixed(3)}`);
377
- else if (autoTotals?.apiRequests)
378
- sp.push(`${autoTotals.apiRequests} reqs`);
379
369
  const cxDisplay = cxPct === "?"
380
370
  ? `?/${formatWidgetTokens(cxWindow)}`
381
371
  : `${cxPct}%/${formatWidgetTokens(cxWindow)}`;
@@ -429,76 +419,6 @@ export function updateProgressWidget(ctx, unitType, unitId, state, accessors, ti
429
419
  };
430
420
  });
431
421
  }
432
- // ─── Text Fallback for RPC Mode ───────────────────────────────────────────
433
- /**
434
- * Build a compact string-array representation of the progress widget.
435
- * Used as a fallback when the factory-based widget cannot render (RPC mode).
436
- */
437
- // ─── Model Health Indicator ───────────────────────────────────────────────────
438
- /**
439
- * Compute a traffic-light health indicator from observable signals.
440
- * 🟢 progressing well — no errors, trend stable/improving
441
- * 🟡 struggling — some errors or degrading trend
442
- * 🔴 stuck — consecutive errors, likely needs attention
443
- */
444
- export function getModelHealthIndicator() {
445
- const trend = getHealthTrend();
446
- const consecutiveErrors = getConsecutiveErrorUnits();
447
- if (consecutiveErrors >= 3) {
448
- return { emoji: "🔴", label: "stuck" };
449
- }
450
- if (consecutiveErrors >= 1 || trend === "degrading") {
451
- return { emoji: "🟡", label: "struggling" };
452
- }
453
- if (trend === "improving") {
454
- return { emoji: "🟢", label: "progressing well" };
455
- }
456
- // stable or unknown
457
- return { emoji: "🟢", label: "progressing" };
458
- }
459
- function buildProgressTextLines(verb, phaseLabel, unitId, mid, slice, task, next, accessors, tierBadge, widgetPwd) {
460
- const mode = accessors.isStepMode() ? "step" : "auto";
461
- const elapsed = formatAutoElapsed(accessors.getAutoStartTime());
462
- const tierStr = tierBadge ? ` [${tierBadge}]` : "";
463
- const lines = [];
464
- lines.push(`[GSD ${mode}] ${verb} ${unitId}${tierStr}${elapsed ? ` — ${elapsed}` : ""}`);
465
- if (mid)
466
- lines.push(` Milestone: ${mid.id} — ${mid.title}`);
467
- if (slice)
468
- lines.push(` Slice: ${slice.id} — ${slice.title}`);
469
- if (task)
470
- lines.push(` Task: ${task.id} — ${task.title}`);
471
- // Progress bar
472
- const sp = cachedSliceProgress;
473
- if (sp && sp.total > 0) {
474
- const pct = Math.round((sp.done / sp.total) * 100);
475
- const taskInfo = sp.activeSliceTasks
476
- ? ` (tasks: ${sp.activeSliceTasks.done}/${sp.activeSliceTasks.total})`
477
- : "";
478
- lines.push(` Progress: ${sp.done}/${sp.total} slices (${pct}%)${taskInfo}`);
479
- }
480
- // Cost / tokens
481
- const ledger = getLedger();
482
- const totals = ledger ? getProjectTotals(ledger.units) : null;
483
- if (totals) {
484
- const parts = [];
485
- if (totals.tokens.input || totals.tokens.output) {
486
- parts.push(`tokens: ${formatWidgetTokens(totals.tokens.input)}↑ ${formatWidgetTokens(totals.tokens.output)}↓`);
487
- }
488
- if (totals.cost > 0) {
489
- parts.push(`cost: ${formatCost(totals.cost)}`);
490
- }
491
- if (parts.length > 0)
492
- lines.push(` ${parts.join(" — ")}`);
493
- }
494
- if (next)
495
- lines.push(` Next: ${next}`);
496
- // Model health indicator
497
- const health = getModelHealthIndicator();
498
- lines.push(` Health: ${health.emoji} ${health.label}`);
499
- lines.push(` ${widgetPwd}`);
500
- return lines;
501
- }
502
422
  // ─── Right-align Helper ───────────────────────────────────────────────────────
503
423
  /** Right-align helper: build a line with left content and right content. */
504
424
  function rightAlign(left, right, width) {
@@ -147,10 +147,15 @@ export async function dispatchDirectPhase(ctx, pi, phase, base) {
147
147
  ctx.ui.notify("Cannot dispatch run-uat: no UAT file found.", "warning");
148
148
  return;
149
149
  }
150
+ const uatContent = await loadFile(uatFile);
151
+ if (!uatContent) {
152
+ ctx.ui.notify("Cannot dispatch run-uat: UAT file is empty.", "warning");
153
+ return;
154
+ }
150
155
  const uatPath = relSliceFile(base, mid, sid, "UAT");
151
156
  unitType = "run-uat";
152
157
  unitId = `${mid}/${sid}`;
153
- prompt = await buildRunUatPrompt(mid, sid, uatPath, base);
158
+ prompt = await buildRunUatPrompt(mid, sid, uatPath, uatContent, base);
154
159
  break;
155
160
  }
156
161
  case "replan":
@@ -8,36 +8,24 @@
8
8
  * data structure that is inspectable, testable per-rule, and extensible
9
9
  * without modifying orchestration code.
10
10
  */
11
- import { loadFile, loadActiveOverrides, parseRoadmap } from "./files.js";
11
+ import { loadFile, loadActiveOverrides } from "./files.js";
12
12
  import { resolveMilestoneFile, resolveMilestonePath, resolveSliceFile, resolveTaskFile, relSliceFile, buildMilestoneFileName, } from "./paths.js";
13
13
  import { existsSync, mkdirSync, writeFileSync } from "node:fs";
14
14
  import { join } from "node:path";
15
15
  import { buildResearchMilestonePrompt, buildPlanMilestonePrompt, buildResearchSlicePrompt, buildPlanSlicePrompt, buildExecuteTaskPrompt, buildCompleteSlicePrompt, buildCompleteMilestonePrompt, buildValidateMilestonePrompt, buildReplanSlicePrompt, buildRunUatPrompt, buildReassessRoadmapPrompt, buildRewriteDocsPrompt, checkNeedsReassessment, checkNeedsRunUat, } from "./auto-prompts.js";
16
+ function missingSliceStop(mid, phase) {
17
+ return {
18
+ action: "stop",
19
+ reason: `${mid}: phase "${phase}" has no active slice — run /gsd doctor.`,
20
+ level: "error",
21
+ };
22
+ }
16
23
  // ─── Rewrite Circuit Breaker ──────────────────────────────────────────────
17
24
  const MAX_REWRITE_ATTEMPTS = 3;
18
25
  let rewriteAttemptCount = 0;
19
26
  export function resetRewriteCircuitBreaker() {
20
27
  rewriteAttemptCount = 0;
21
28
  }
22
- /**
23
- * Guard for accessing activeSlice/activeTask in dispatch rules.
24
- * Returns a stop action if the expected ref is null (corrupt state).
25
- */
26
- function requireSlice(state) {
27
- if (!state.activeSlice) {
28
- return { action: "stop", reason: `Phase "${state.phase}" but no active slice — run /gsd doctor.`, level: "error" };
29
- }
30
- return { sid: state.activeSlice.id, sTitle: state.activeSlice.title };
31
- }
32
- function requireTask(state) {
33
- if (!state.activeSlice || !state.activeTask) {
34
- return { action: "stop", reason: `Phase "${state.phase}" but no active slice/task — run /gsd doctor.`, level: "error" };
35
- }
36
- return { sid: state.activeSlice.id, sTitle: state.activeSlice.title, tid: state.activeTask.id, tTitle: state.activeTask.title };
37
- }
38
- function isStopAction(v) {
39
- return typeof v === "object" && v !== null && "action" in v;
40
- }
41
29
  // ─── Rules ────────────────────────────────────────────────────────────────
42
30
  const DISPATCH_RULES = [
43
31
  {
@@ -67,10 +55,10 @@ const DISPATCH_RULES = [
67
55
  match: async ({ state, mid, midTitle, basePath }) => {
68
56
  if (state.phase !== "summarizing")
69
57
  return null;
70
- const sliceRef = requireSlice(state);
71
- if (isStopAction(sliceRef))
72
- return sliceRef;
73
- const { sid, sTitle } = sliceRef;
58
+ if (!state.activeSlice)
59
+ return missingSliceStop(mid, state.phase);
60
+ const sid = state.activeSlice.id;
61
+ const sTitle = state.activeSlice.title;
74
62
  return {
75
63
  action: "dispatch",
76
64
  unitType: "complete-slice",
@@ -79,57 +67,28 @@ const DISPATCH_RULES = [
79
67
  };
80
68
  },
81
69
  },
82
- {
83
- name: "uat-verdict-gate (non-PASS blocks progression)",
84
- match: async ({ mid, basePath, prefs }) => {
85
- // Only applies when UAT dispatch is enabled
86
- if (!prefs?.uat_dispatch)
87
- return null;
88
- const roadmapFile = resolveMilestoneFile(basePath, mid, "ROADMAP");
89
- const roadmapContent = roadmapFile ? await loadFile(roadmapFile) : null;
90
- if (!roadmapContent)
91
- return null;
92
- const roadmap = parseRoadmap(roadmapContent);
93
- for (const slice of roadmap.slices.filter(s => s.done)) {
94
- const resultFile = resolveSliceFile(basePath, mid, slice.id, "UAT-RESULT");
95
- if (!resultFile)
96
- continue;
97
- const content = await loadFile(resultFile);
98
- if (!content)
99
- continue;
100
- const verdictMatch = content.match(/verdict:\s*([\w-]+)/i);
101
- const verdict = verdictMatch?.[1]?.toLowerCase();
102
- if (verdict && verdict !== "pass" && verdict !== "passed") {
103
- return {
104
- action: "stop",
105
- reason: `UAT verdict for ${slice.id} is "${verdict}" — blocking progression until resolved.\nReview the UAT result and update the verdict to PASS, or re-run /gsd auto after fixing.`,
106
- level: "warning",
107
- };
108
- }
109
- }
110
- return null;
111
- },
112
- },
113
70
  {
114
71
  name: "run-uat (post-completion)",
115
72
  match: async ({ state, mid, basePath, prefs }) => {
116
73
  const needsRunUat = await checkNeedsRunUat(basePath, mid, state, prefs);
117
74
  if (!needsRunUat)
118
75
  return null;
119
- const { sliceId } = needsRunUat;
76
+ const { sliceId, uatType } = needsRunUat;
77
+ const uatFile = resolveSliceFile(basePath, mid, sliceId, "UAT");
78
+ const uatContent = await loadFile(uatFile);
120
79
  return {
121
80
  action: "dispatch",
122
81
  unitType: "run-uat",
123
82
  unitId: `${mid}/${sliceId}`,
124
- prompt: await buildRunUatPrompt(mid, sliceId, relSliceFile(basePath, mid, sliceId, "UAT"), basePath),
83
+ prompt: await buildRunUatPrompt(mid, sliceId, relSliceFile(basePath, mid, sliceId, "UAT"), uatContent ?? "", basePath),
84
+ pauseAfterDispatch: uatType !== "artifact-driven",
125
85
  };
126
86
  },
127
87
  },
128
88
  {
129
89
  name: "reassess-roadmap (post-completion)",
130
90
  match: async ({ state, mid, midTitle, basePath, prefs }) => {
131
- // Reassess is opt-in: only fire when explicitly enabled
132
- if (!prefs?.phases?.reassess_after_slice)
91
+ if (prefs?.phases?.skip_reassess || !prefs?.phases?.reassess_after_slice)
133
92
  return null;
134
93
  const needsReassess = await checkNeedsReassessment(basePath, mid, state);
135
94
  if (!needsReassess)
@@ -160,7 +119,7 @@ const DISPATCH_RULES = [
160
119
  if (state.phase !== "pre-planning")
161
120
  return null;
162
121
  const contextFile = resolveMilestoneFile(basePath, mid, "CONTEXT");
163
- const hasContext = !!(contextFile && await loadFile(contextFile));
122
+ const hasContext = !!(contextFile && (await loadFile(contextFile)));
164
123
  if (hasContext)
165
124
  return null; // fall through to next rule
166
125
  return {
@@ -210,10 +169,10 @@ const DISPATCH_RULES = [
210
169
  // Phase skip: skip research when preference or profile says so
211
170
  if (prefs?.phases?.skip_research || prefs?.phases?.skip_slice_research)
212
171
  return null;
213
- const sliceRef = requireSlice(state);
214
- if (isStopAction(sliceRef))
215
- return sliceRef;
216
- const { sid, sTitle } = sliceRef;
172
+ if (!state.activeSlice)
173
+ return missingSliceStop(mid, state.phase);
174
+ const sid = state.activeSlice.id;
175
+ const sTitle = state.activeSlice.title;
217
176
  const researchFile = resolveSliceFile(basePath, mid, sid, "RESEARCH");
218
177
  if (researchFile)
219
178
  return null; // has research, fall through
@@ -235,10 +194,10 @@ const DISPATCH_RULES = [
235
194
  match: async ({ state, mid, midTitle, basePath }) => {
236
195
  if (state.phase !== "planning")
237
196
  return null;
238
- const sliceRef = requireSlice(state);
239
- if (isStopAction(sliceRef))
240
- return sliceRef;
241
- const { sid, sTitle } = sliceRef;
197
+ if (!state.activeSlice)
198
+ return missingSliceStop(mid, state.phase);
199
+ const sid = state.activeSlice.id;
200
+ const sTitle = state.activeSlice.title;
242
201
  return {
243
202
  action: "dispatch",
244
203
  unitType: "plan-slice",
@@ -252,10 +211,10 @@ const DISPATCH_RULES = [
252
211
  match: async ({ state, mid, midTitle, basePath }) => {
253
212
  if (state.phase !== "replanning-slice")
254
213
  return null;
255
- const sliceRef = requireSlice(state);
256
- if (isStopAction(sliceRef))
257
- return sliceRef;
258
- const { sid, sTitle } = sliceRef;
214
+ if (!state.activeSlice)
215
+ return missingSliceStop(mid, state.phase);
216
+ const sid = state.activeSlice.id;
217
+ const sTitle = state.activeSlice.title;
259
218
  return {
260
219
  action: "dispatch",
261
220
  unitType: "replan-slice",
@@ -269,10 +228,10 @@ const DISPATCH_RULES = [
269
228
  match: async ({ state, mid, midTitle, basePath }) => {
270
229
  if (state.phase !== "executing" || !state.activeTask)
271
230
  return null;
272
- const sliceRef = requireSlice(state);
273
- if (isStopAction(sliceRef))
274
- return sliceRef;
275
- const { sid, sTitle } = sliceRef;
231
+ if (!state.activeSlice)
232
+ return missingSliceStop(mid, state.phase);
233
+ const sid = state.activeSlice.id;
234
+ const sTitle = state.activeSlice.title;
276
235
  const tid = state.activeTask.id;
277
236
  // Guard: if the slice plan exists but the individual task plan files are
278
237
  // missing, the planner created S##-PLAN.md with task entries but never
@@ -296,10 +255,10 @@ const DISPATCH_RULES = [
296
255
  match: async ({ state, mid, basePath }) => {
297
256
  if (state.phase !== "executing" || !state.activeTask)
298
257
  return null;
299
- const sliceRef = requireSlice(state);
300
- if (isStopAction(sliceRef))
301
- return sliceRef;
302
- const { sid, sTitle } = sliceRef;
258
+ if (!state.activeSlice)
259
+ return missingSliceStop(mid, state.phase);
260
+ const sid = state.activeSlice.id;
261
+ const sTitle = state.activeSlice.title;
303
262
  const tid = state.activeTask.id;
304
263
  const tTitle = state.activeTask.title;
305
264
  return {
@@ -357,6 +316,18 @@ const DISPATCH_RULES = [
357
316
  };
358
317
  },
359
318
  },
319
+ {
320
+ name: "complete → stop",
321
+ match: async ({ state }) => {
322
+ if (state.phase !== "complete")
323
+ return null;
324
+ return {
325
+ action: "stop",
326
+ reason: "All milestones complete.",
327
+ level: "info",
328
+ };
329
+ },
330
+ },
360
331
  ];
361
332
  // ─── Resolver ─────────────────────────────────────────────────────────────
362
333
  /**
@@ -378,5 +349,5 @@ export async function resolveDispatch(ctx) {
378
349
  }
379
350
  /** Exposed for testing — returns the rule names in evaluation order. */
380
351
  export function getDispatchRuleNames() {
381
- return DISPATCH_RULES.map(r => r.name);
352
+ return DISPATCH_RULES.map((r) => r.name);
382
353
  }