gsd-pi 2.63.0 → 2.64.0-dev.9c14bd0

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 (448) hide show
  1. package/README.md +46 -134
  2. package/dist/cli.js +48 -6
  3. package/dist/headless-query.js +11 -1
  4. package/dist/help-text.js +4 -1
  5. package/dist/onboarding.js +15 -8
  6. package/dist/resource-loader.js +18 -3
  7. package/dist/resources/extensions/cmux/index.js +21 -12
  8. package/dist/resources/extensions/gsd/auto/detect-stuck.js +27 -0
  9. package/dist/resources/extensions/gsd/auto/finalize-timeout.js +40 -0
  10. package/dist/resources/extensions/gsd/auto/loop.js +4 -0
  11. package/dist/resources/extensions/gsd/auto/phases.js +157 -22
  12. package/dist/resources/extensions/gsd/auto/session.js +12 -0
  13. package/dist/resources/extensions/gsd/auto-dashboard.js +14 -8
  14. package/dist/resources/extensions/gsd/auto-model-selection.js +32 -0
  15. package/dist/resources/extensions/gsd/auto-post-unit.js +222 -11
  16. package/dist/resources/extensions/gsd/auto-prompts.js +25 -0
  17. package/dist/resources/extensions/gsd/auto-recovery.js +15 -7
  18. package/dist/resources/extensions/gsd/auto-start.js +10 -21
  19. package/dist/resources/extensions/gsd/auto-timers.js +2 -1
  20. package/dist/resources/extensions/gsd/auto-tool-tracking.js +17 -0
  21. package/dist/resources/extensions/gsd/auto-verification.js +138 -1
  22. package/dist/resources/extensions/gsd/auto-worktree.js +13 -7
  23. package/dist/resources/extensions/gsd/auto.js +24 -2
  24. package/dist/resources/extensions/gsd/bootstrap/db-tools.js +147 -75
  25. package/dist/resources/extensions/gsd/bootstrap/dynamic-tools.js +13 -0
  26. package/dist/resources/extensions/gsd/bootstrap/query-tools.js +85 -0
  27. package/dist/resources/extensions/gsd/bootstrap/register-extension.js +3 -0
  28. package/dist/resources/extensions/gsd/bootstrap/register-hooks.js +32 -1
  29. package/dist/resources/extensions/gsd/bootstrap/sanitize-complete-milestone.js +54 -0
  30. package/dist/resources/extensions/gsd/bootstrap/system-context.js +30 -2
  31. package/dist/resources/extensions/gsd/commands-handlers.js +9 -4
  32. package/dist/resources/extensions/gsd/constants.js +42 -0
  33. package/dist/resources/extensions/gsd/db-writer.js +72 -4
  34. package/dist/resources/extensions/gsd/forensics.js +20 -4
  35. package/dist/resources/extensions/gsd/gsd-db.js +64 -17
  36. package/dist/resources/extensions/gsd/guided-flow.js +19 -0
  37. package/dist/resources/extensions/gsd/metrics.js +27 -1
  38. package/dist/resources/extensions/gsd/native-git-bridge.js +5 -3
  39. package/dist/resources/extensions/gsd/post-execution-checks.js +407 -0
  40. package/dist/resources/extensions/gsd/pre-execution-checks.js +464 -0
  41. package/dist/resources/extensions/gsd/preferences-types.js +6 -0
  42. package/dist/resources/extensions/gsd/preferences-validation.js +33 -0
  43. package/dist/resources/extensions/gsd/preferences.js +11 -2
  44. package/dist/resources/extensions/gsd/prompt-loader.js +7 -0
  45. package/dist/resources/extensions/gsd/prompts/complete-milestone.md +2 -0
  46. package/dist/resources/extensions/gsd/prompts/complete-slice.md +2 -0
  47. package/dist/resources/extensions/gsd/prompts/doctor-heal.md +1 -0
  48. package/dist/resources/extensions/gsd/prompts/forensics.md +2 -0
  49. package/dist/resources/extensions/gsd/prompts/reassess-roadmap.md +2 -0
  50. package/dist/resources/extensions/gsd/prompts/system.md +4 -7
  51. package/dist/resources/extensions/gsd/prompts/validate-milestone.md +2 -0
  52. package/dist/resources/extensions/gsd/roadmap-mutations.js +1 -1
  53. package/dist/resources/extensions/gsd/roadmap-slices.js +9 -5
  54. package/dist/resources/extensions/gsd/safety/content-validator.js +73 -0
  55. package/dist/resources/extensions/gsd/safety/destructive-guard.js +34 -0
  56. package/dist/resources/extensions/gsd/safety/evidence-collector.js +109 -0
  57. package/dist/resources/extensions/gsd/safety/evidence-cross-ref.js +83 -0
  58. package/dist/resources/extensions/gsd/safety/file-change-validator.js +71 -0
  59. package/dist/resources/extensions/gsd/safety/git-checkpoint.js +91 -0
  60. package/dist/resources/extensions/gsd/safety/safety-harness.js +64 -0
  61. package/dist/resources/extensions/gsd/slice-parallel-conflict.js +67 -0
  62. package/dist/resources/extensions/gsd/slice-parallel-eligibility.js +51 -0
  63. package/dist/resources/extensions/gsd/slice-parallel-orchestrator.js +378 -0
  64. package/dist/resources/extensions/gsd/state.js +74 -14
  65. package/dist/resources/extensions/gsd/status-guards.js +11 -0
  66. package/dist/resources/extensions/gsd/tools/complete-milestone.js +17 -12
  67. package/dist/resources/extensions/gsd/tools/complete-slice.js +40 -26
  68. package/dist/resources/extensions/gsd/tools/complete-task.js +12 -12
  69. package/dist/resources/extensions/gsd/tools/plan-milestone.js +33 -25
  70. package/dist/resources/extensions/gsd/tools/plan-slice.js +5 -8
  71. package/dist/resources/extensions/gsd/verification-evidence.js +18 -0
  72. package/dist/resources/extensions/gsd/workflow-projections.js +21 -5
  73. package/dist/resources/extensions/gsd/worktree-manager.js +82 -29
  74. package/dist/resources/extensions/gsd/worktree-resolver.js +4 -3
  75. package/dist/resources/extensions/mcp-client/auth.js +101 -0
  76. package/dist/resources/extensions/mcp-client/index.js +10 -1
  77. package/dist/resources/extensions/ollama/index.js +28 -22
  78. package/dist/resources/extensions/ollama/model-capabilities.js +37 -34
  79. package/dist/resources/extensions/ollama/ndjson-stream.js +54 -0
  80. package/dist/resources/extensions/ollama/ollama-chat-provider.js +380 -0
  81. package/dist/resources/extensions/ollama/ollama-client.js +23 -32
  82. package/dist/resources/extensions/ollama/ollama-discovery.js +2 -7
  83. package/dist/resources/extensions/ollama/ollama-tool.js +62 -0
  84. package/dist/resources/extensions/ollama/thinking-parser.js +104 -0
  85. package/dist/update-cmd.js +4 -2
  86. package/dist/web/standalone/.next/BUILD_ID +1 -1
  87. package/dist/web/standalone/.next/app-path-routes-manifest.json +15 -15
  88. package/dist/web/standalone/.next/build-manifest.json +3 -3
  89. package/dist/web/standalone/.next/prerender-manifest.json +3 -3
  90. package/dist/web/standalone/.next/required-server-files.json +4 -4
  91. package/dist/web/standalone/.next/server/app/_global-error/page.js +3 -3
  92. package/dist/web/standalone/.next/server/app/_global-error/page_client-reference-manifest.js +1 -1
  93. package/dist/web/standalone/.next/server/app/_global-error.html +2 -2
  94. package/dist/web/standalone/.next/server/app/_global-error.rsc +1 -1
  95. package/dist/web/standalone/.next/server/app/_global-error.segments/_full.segment.rsc +1 -1
  96. package/dist/web/standalone/.next/server/app/_global-error.segments/_global-error/__PAGE__.segment.rsc +1 -1
  97. package/dist/web/standalone/.next/server/app/_global-error.segments/_global-error.segment.rsc +1 -1
  98. package/dist/web/standalone/.next/server/app/_global-error.segments/_head.segment.rsc +1 -1
  99. package/dist/web/standalone/.next/server/app/_global-error.segments/_index.segment.rsc +1 -1
  100. package/dist/web/standalone/.next/server/app/_global-error.segments/_tree.segment.rsc +1 -1
  101. package/dist/web/standalone/.next/server/app/_not-found/page.js +2 -2
  102. package/dist/web/standalone/.next/server/app/_not-found/page_client-reference-manifest.js +1 -1
  103. package/dist/web/standalone/.next/server/app/_not-found.html +1 -1
  104. package/dist/web/standalone/.next/server/app/_not-found.rsc +3 -3
  105. package/dist/web/standalone/.next/server/app/_not-found.segments/_full.segment.rsc +3 -3
  106. package/dist/web/standalone/.next/server/app/_not-found.segments/_head.segment.rsc +1 -1
  107. package/dist/web/standalone/.next/server/app/_not-found.segments/_index.segment.rsc +3 -3
  108. package/dist/web/standalone/.next/server/app/_not-found.segments/_not-found/__PAGE__.segment.rsc +1 -1
  109. package/dist/web/standalone/.next/server/app/_not-found.segments/_not-found.segment.rsc +1 -1
  110. package/dist/web/standalone/.next/server/app/_not-found.segments/_tree.segment.rsc +1 -1
  111. package/dist/web/standalone/.next/server/app/api/boot/route.js +1 -1
  112. package/dist/web/standalone/.next/server/app/api/boot/route.js.nft.json +1 -1
  113. package/dist/web/standalone/.next/server/app/api/boot/route_client-reference-manifest.js +1 -1
  114. package/dist/web/standalone/.next/server/app/api/bridge-terminal/input/route.js +1 -1
  115. package/dist/web/standalone/.next/server/app/api/bridge-terminal/input/route.js.nft.json +1 -1
  116. package/dist/web/standalone/.next/server/app/api/bridge-terminal/input/route_client-reference-manifest.js +1 -1
  117. package/dist/web/standalone/.next/server/app/api/bridge-terminal/resize/route.js +1 -1
  118. package/dist/web/standalone/.next/server/app/api/bridge-terminal/resize/route.js.nft.json +1 -1
  119. package/dist/web/standalone/.next/server/app/api/bridge-terminal/resize/route_client-reference-manifest.js +1 -1
  120. package/dist/web/standalone/.next/server/app/api/bridge-terminal/stream/route.js +2 -2
  121. package/dist/web/standalone/.next/server/app/api/bridge-terminal/stream/route.js.nft.json +1 -1
  122. package/dist/web/standalone/.next/server/app/api/bridge-terminal/stream/route_client-reference-manifest.js +1 -1
  123. package/dist/web/standalone/.next/server/app/api/browse-directories/route.js +1 -1
  124. package/dist/web/standalone/.next/server/app/api/browse-directories/route_client-reference-manifest.js +1 -1
  125. package/dist/web/standalone/.next/server/app/api/captures/route.js +1 -1
  126. package/dist/web/standalone/.next/server/app/api/captures/route.js.nft.json +1 -1
  127. package/dist/web/standalone/.next/server/app/api/captures/route_client-reference-manifest.js +1 -1
  128. package/dist/web/standalone/.next/server/app/api/cleanup/route.js +1 -1
  129. package/dist/web/standalone/.next/server/app/api/cleanup/route.js.nft.json +1 -1
  130. package/dist/web/standalone/.next/server/app/api/cleanup/route_client-reference-manifest.js +1 -1
  131. package/dist/web/standalone/.next/server/app/api/dev-mode/route.js +1 -1
  132. package/dist/web/standalone/.next/server/app/api/dev-mode/route_client-reference-manifest.js +1 -1
  133. package/dist/web/standalone/.next/server/app/api/doctor/route.js +1 -1
  134. package/dist/web/standalone/.next/server/app/api/doctor/route.js.nft.json +1 -1
  135. package/dist/web/standalone/.next/server/app/api/doctor/route_client-reference-manifest.js +1 -1
  136. package/dist/web/standalone/.next/server/app/api/experimental/route.js +2 -2
  137. package/dist/web/standalone/.next/server/app/api/experimental/route_client-reference-manifest.js +1 -1
  138. package/dist/web/standalone/.next/server/app/api/export-data/route.js +1 -1
  139. package/dist/web/standalone/.next/server/app/api/export-data/route.js.nft.json +1 -1
  140. package/dist/web/standalone/.next/server/app/api/export-data/route_client-reference-manifest.js +1 -1
  141. package/dist/web/standalone/.next/server/app/api/files/route.js +1 -1
  142. package/dist/web/standalone/.next/server/app/api/files/route.js.nft.json +1 -1
  143. package/dist/web/standalone/.next/server/app/api/files/route_client-reference-manifest.js +1 -1
  144. package/dist/web/standalone/.next/server/app/api/forensics/route.js +1 -1
  145. package/dist/web/standalone/.next/server/app/api/forensics/route.js.nft.json +1 -1
  146. package/dist/web/standalone/.next/server/app/api/forensics/route_client-reference-manifest.js +1 -1
  147. package/dist/web/standalone/.next/server/app/api/git/route.js +1 -1
  148. package/dist/web/standalone/.next/server/app/api/git/route.js.nft.json +1 -1
  149. package/dist/web/standalone/.next/server/app/api/git/route_client-reference-manifest.js +1 -1
  150. package/dist/web/standalone/.next/server/app/api/history/route.js +1 -1
  151. package/dist/web/standalone/.next/server/app/api/history/route.js.nft.json +1 -1
  152. package/dist/web/standalone/.next/server/app/api/history/route_client-reference-manifest.js +1 -1
  153. package/dist/web/standalone/.next/server/app/api/hooks/route.js +1 -1
  154. package/dist/web/standalone/.next/server/app/api/hooks/route.js.nft.json +1 -1
  155. package/dist/web/standalone/.next/server/app/api/hooks/route_client-reference-manifest.js +1 -1
  156. package/dist/web/standalone/.next/server/app/api/inspect/route.js +1 -1
  157. package/dist/web/standalone/.next/server/app/api/inspect/route.js.nft.json +1 -1
  158. package/dist/web/standalone/.next/server/app/api/inspect/route_client-reference-manifest.js +1 -1
  159. package/dist/web/standalone/.next/server/app/api/knowledge/route.js +1 -1
  160. package/dist/web/standalone/.next/server/app/api/knowledge/route.js.nft.json +1 -1
  161. package/dist/web/standalone/.next/server/app/api/knowledge/route_client-reference-manifest.js +1 -1
  162. package/dist/web/standalone/.next/server/app/api/live-state/route.js +1 -1
  163. package/dist/web/standalone/.next/server/app/api/live-state/route.js.nft.json +1 -1
  164. package/dist/web/standalone/.next/server/app/api/live-state/route_client-reference-manifest.js +1 -1
  165. package/dist/web/standalone/.next/server/app/api/onboarding/route.js +1 -1
  166. package/dist/web/standalone/.next/server/app/api/onboarding/route.js.nft.json +1 -1
  167. package/dist/web/standalone/.next/server/app/api/onboarding/route_client-reference-manifest.js +1 -1
  168. package/dist/web/standalone/.next/server/app/api/preferences/route.js +1 -1
  169. package/dist/web/standalone/.next/server/app/api/preferences/route_client-reference-manifest.js +1 -1
  170. package/dist/web/standalone/.next/server/app/api/projects/route.js +1 -1
  171. package/dist/web/standalone/.next/server/app/api/projects/route.js.nft.json +1 -1
  172. package/dist/web/standalone/.next/server/app/api/projects/route_client-reference-manifest.js +1 -1
  173. package/dist/web/standalone/.next/server/app/api/recovery/route.js +1 -1
  174. package/dist/web/standalone/.next/server/app/api/recovery/route.js.nft.json +1 -1
  175. package/dist/web/standalone/.next/server/app/api/recovery/route_client-reference-manifest.js +1 -1
  176. package/dist/web/standalone/.next/server/app/api/remote-questions/route.js +2 -2
  177. package/dist/web/standalone/.next/server/app/api/remote-questions/route_client-reference-manifest.js +1 -1
  178. package/dist/web/standalone/.next/server/app/api/session/browser/route.js +1 -1
  179. package/dist/web/standalone/.next/server/app/api/session/browser/route.js.nft.json +1 -1
  180. package/dist/web/standalone/.next/server/app/api/session/browser/route_client-reference-manifest.js +1 -1
  181. package/dist/web/standalone/.next/server/app/api/session/command/route.js +1 -1
  182. package/dist/web/standalone/.next/server/app/api/session/command/route.js.nft.json +1 -1
  183. package/dist/web/standalone/.next/server/app/api/session/command/route_client-reference-manifest.js +1 -1
  184. package/dist/web/standalone/.next/server/app/api/session/events/route.js +2 -2
  185. package/dist/web/standalone/.next/server/app/api/session/events/route.js.nft.json +1 -1
  186. package/dist/web/standalone/.next/server/app/api/session/events/route_client-reference-manifest.js +1 -1
  187. package/dist/web/standalone/.next/server/app/api/session/manage/route.js +1 -1
  188. package/dist/web/standalone/.next/server/app/api/session/manage/route.js.nft.json +1 -1
  189. package/dist/web/standalone/.next/server/app/api/session/manage/route_client-reference-manifest.js +1 -1
  190. package/dist/web/standalone/.next/server/app/api/settings-data/route.js +1 -1
  191. package/dist/web/standalone/.next/server/app/api/settings-data/route.js.nft.json +1 -1
  192. package/dist/web/standalone/.next/server/app/api/settings-data/route_client-reference-manifest.js +1 -1
  193. package/dist/web/standalone/.next/server/app/api/shutdown/route.js +1 -1
  194. package/dist/web/standalone/.next/server/app/api/shutdown/route_client-reference-manifest.js +1 -1
  195. package/dist/web/standalone/.next/server/app/api/skill-health/route.js +1 -1
  196. package/dist/web/standalone/.next/server/app/api/skill-health/route.js.nft.json +1 -1
  197. package/dist/web/standalone/.next/server/app/api/skill-health/route_client-reference-manifest.js +1 -1
  198. package/dist/web/standalone/.next/server/app/api/steer/route.js +1 -1
  199. package/dist/web/standalone/.next/server/app/api/steer/route.js.nft.json +1 -1
  200. package/dist/web/standalone/.next/server/app/api/steer/route_client-reference-manifest.js +1 -1
  201. package/dist/web/standalone/.next/server/app/api/switch-root/route.js +1 -1
  202. package/dist/web/standalone/.next/server/app/api/switch-root/route.js.nft.json +1 -1
  203. package/dist/web/standalone/.next/server/app/api/switch-root/route_client-reference-manifest.js +1 -1
  204. package/dist/web/standalone/.next/server/app/api/terminal/input/route.js +2 -2
  205. package/dist/web/standalone/.next/server/app/api/terminal/input/route_client-reference-manifest.js +1 -1
  206. package/dist/web/standalone/.next/server/app/api/terminal/resize/route.js +2 -2
  207. package/dist/web/standalone/.next/server/app/api/terminal/resize/route_client-reference-manifest.js +1 -1
  208. package/dist/web/standalone/.next/server/app/api/terminal/sessions/route.js +2 -2
  209. package/dist/web/standalone/.next/server/app/api/terminal/sessions/route.js.nft.json +1 -1
  210. package/dist/web/standalone/.next/server/app/api/terminal/sessions/route_client-reference-manifest.js +1 -1
  211. package/dist/web/standalone/.next/server/app/api/terminal/stream/route.js +4 -4
  212. package/dist/web/standalone/.next/server/app/api/terminal/stream/route.js.nft.json +1 -1
  213. package/dist/web/standalone/.next/server/app/api/terminal/stream/route_client-reference-manifest.js +1 -1
  214. package/dist/web/standalone/.next/server/app/api/terminal/upload/route.js +1 -1
  215. package/dist/web/standalone/.next/server/app/api/terminal/upload/route_client-reference-manifest.js +1 -1
  216. package/dist/web/standalone/.next/server/app/api/undo/route.js +1 -1
  217. package/dist/web/standalone/.next/server/app/api/undo/route.js.nft.json +1 -1
  218. package/dist/web/standalone/.next/server/app/api/undo/route_client-reference-manifest.js +1 -1
  219. package/dist/web/standalone/.next/server/app/api/update/route.js +1 -1
  220. package/dist/web/standalone/.next/server/app/api/update/route_client-reference-manifest.js +1 -1
  221. package/dist/web/standalone/.next/server/app/api/visualizer/route.js +1 -1
  222. package/dist/web/standalone/.next/server/app/api/visualizer/route.js.nft.json +1 -1
  223. package/dist/web/standalone/.next/server/app/api/visualizer/route_client-reference-manifest.js +1 -1
  224. package/dist/web/standalone/.next/server/app/index.html +1 -1
  225. package/dist/web/standalone/.next/server/app/index.rsc +4 -4
  226. package/dist/web/standalone/.next/server/app/index.segments/__PAGE__.segment.rsc +2 -2
  227. package/dist/web/standalone/.next/server/app/index.segments/_full.segment.rsc +4 -4
  228. package/dist/web/standalone/.next/server/app/index.segments/_head.segment.rsc +1 -1
  229. package/dist/web/standalone/.next/server/app/index.segments/_index.segment.rsc +3 -3
  230. package/dist/web/standalone/.next/server/app/index.segments/_tree.segment.rsc +1 -1
  231. package/dist/web/standalone/.next/server/app/page.js +2 -2
  232. package/dist/web/standalone/.next/server/app/page_client-reference-manifest.js +1 -1
  233. package/dist/web/standalone/.next/server/app-paths-manifest.json +15 -15
  234. package/dist/web/standalone/.next/server/chunks/6897.js +12 -0
  235. package/dist/web/standalone/.next/server/chunks/7471.js +3 -3
  236. package/dist/web/standalone/.next/server/middleware-build-manifest.js +1 -1
  237. package/dist/web/standalone/.next/server/middleware.js +2 -2
  238. package/dist/web/standalone/.next/server/next-font-manifest.js +1 -1
  239. package/dist/web/standalone/.next/server/next-font-manifest.json +1 -1
  240. package/dist/web/standalone/.next/server/pages/404.html +1 -1
  241. package/dist/web/standalone/.next/server/pages/500.html +2 -2
  242. package/dist/web/standalone/.next/server/server-reference-manifest.json +1 -1
  243. package/dist/web/standalone/.next/static/chunks/app/_not-found/{page-2f24283c162b6ab3.js → page-f2a7482d42a5614b.js} +1 -1
  244. package/dist/web/standalone/.next/static/chunks/app/{layout-9ecfd95f343793f0.js → layout-a16c7a7ecdf0c2cf.js} +1 -1
  245. package/dist/web/standalone/.next/static/chunks/app/page-0c485498795110d6.js +1 -0
  246. package/dist/web/standalone/.next/static/chunks/main-app-fdab67f7802d7832.js +1 -0
  247. package/dist/web/standalone/.next/static/chunks/next/dist/client/components/builtin/global-error-459824ffb8c323dd.js +1 -0
  248. package/dist/web/standalone/node_modules/node-pty/build/Makefile +2 -2
  249. package/dist/web/standalone/node_modules/node-pty/build/Release/pty.node +0 -0
  250. package/dist/web/standalone/node_modules/node-pty/build/pty.target.mk +14 -14
  251. package/dist/web/standalone/node_modules/node-pty/node-addon-api/node_addon_api.target.mk +14 -14
  252. package/dist/web/standalone/node_modules/node-pty/node-addon-api/node_addon_api_except.target.mk +14 -14
  253. package/dist/web/standalone/node_modules/node-pty/node-addon-api/node_addon_api_maybe.target.mk +14 -14
  254. package/dist/web/standalone/server.js +1 -1
  255. package/dist/welcome-screen.js +1 -1
  256. package/package.json +1 -1
  257. package/packages/pi-agent-core/dist/agent-loop.d.ts +8 -0
  258. package/packages/pi-agent-core/dist/agent-loop.d.ts.map +1 -1
  259. package/packages/pi-agent-core/dist/agent-loop.js +50 -0
  260. package/packages/pi-agent-core/dist/agent-loop.js.map +1 -1
  261. package/packages/pi-agent-core/src/agent-loop.test.ts +221 -5
  262. package/packages/pi-agent-core/src/agent-loop.ts +53 -0
  263. package/packages/pi-ai/dist/types.d.ts +16 -1
  264. package/packages/pi-ai/dist/types.d.ts.map +1 -1
  265. package/packages/pi-ai/dist/types.js.map +1 -1
  266. package/packages/pi-ai/src/types.ts +18 -1
  267. package/packages/pi-coding-agent/dist/core/auth-storage.d.ts +9 -0
  268. package/packages/pi-coding-agent/dist/core/auth-storage.d.ts.map +1 -1
  269. package/packages/pi-coding-agent/dist/core/auth-storage.js +50 -1
  270. package/packages/pi-coding-agent/dist/core/auth-storage.js.map +1 -1
  271. package/packages/pi-coding-agent/dist/core/auth-storage.test.js +41 -0
  272. package/packages/pi-coding-agent/dist/core/auth-storage.test.js.map +1 -1
  273. package/packages/pi-coding-agent/dist/core/extensions/loader.d.ts +7 -0
  274. package/packages/pi-coding-agent/dist/core/extensions/loader.d.ts.map +1 -1
  275. package/packages/pi-coding-agent/dist/core/extensions/loader.js +31 -4
  276. package/packages/pi-coding-agent/dist/core/extensions/loader.js.map +1 -1
  277. package/packages/pi-coding-agent/dist/core/extensions/loader.test.js +28 -1
  278. package/packages/pi-coding-agent/dist/core/extensions/loader.test.js.map +1 -1
  279. package/packages/pi-coding-agent/dist/core/extensions/provider-registration.test.d.ts +2 -0
  280. package/packages/pi-coding-agent/dist/core/extensions/provider-registration.test.d.ts.map +1 -0
  281. package/packages/pi-coding-agent/dist/core/extensions/provider-registration.test.js +46 -0
  282. package/packages/pi-coding-agent/dist/core/extensions/provider-registration.test.js.map +1 -0
  283. package/packages/pi-coding-agent/dist/core/extensions/types.d.ts +2 -0
  284. package/packages/pi-coding-agent/dist/core/extensions/types.d.ts.map +1 -1
  285. package/packages/pi-coding-agent/dist/core/extensions/types.js.map +1 -1
  286. package/packages/pi-coding-agent/dist/core/model-registry.d.ts +1 -0
  287. package/packages/pi-coding-agent/dist/core/model-registry.d.ts.map +1 -1
  288. package/packages/pi-coding-agent/dist/core/model-registry.js +12 -0
  289. package/packages/pi-coding-agent/dist/core/model-registry.js.map +1 -1
  290. package/packages/pi-coding-agent/dist/core/model-resolver.js +3 -3
  291. package/packages/pi-coding-agent/dist/core/model-resolver.js.map +1 -1
  292. package/packages/pi-coding-agent/dist/core/resource-loader.d.ts +23 -1
  293. package/packages/pi-coding-agent/dist/core/resource-loader.d.ts.map +1 -1
  294. package/packages/pi-coding-agent/dist/core/resource-loader.js +80 -56
  295. package/packages/pi-coding-agent/dist/core/resource-loader.js.map +1 -1
  296. package/packages/pi-coding-agent/dist/core/sdk.d.ts.map +1 -1
  297. package/packages/pi-coding-agent/dist/core/sdk.js +9 -0
  298. package/packages/pi-coding-agent/dist/core/sdk.js.map +1 -1
  299. package/packages/pi-coding-agent/package.json +1 -1
  300. package/packages/pi-coding-agent/src/core/auth-storage.test.ts +53 -0
  301. package/packages/pi-coding-agent/src/core/auth-storage.ts +66 -1
  302. package/packages/pi-coding-agent/src/core/extensions/loader.test.ts +39 -1
  303. package/packages/pi-coding-agent/src/core/extensions/loader.ts +34 -4
  304. package/packages/pi-coding-agent/src/core/extensions/provider-registration.test.ts +81 -0
  305. package/packages/pi-coding-agent/src/core/extensions/types.ts +2 -0
  306. package/packages/pi-coding-agent/src/core/model-registry.ts +14 -0
  307. package/packages/pi-coding-agent/src/core/model-resolver.ts +3 -3
  308. package/packages/pi-coding-agent/src/core/resource-loader.ts +89 -56
  309. package/packages/pi-coding-agent/src/core/sdk.ts +10 -0
  310. package/pkg/package.json +1 -1
  311. package/src/resources/extensions/cmux/index.ts +18 -12
  312. package/src/resources/extensions/gsd/auto/detect-stuck.ts +27 -0
  313. package/src/resources/extensions/gsd/auto/finalize-timeout.ts +46 -0
  314. package/src/resources/extensions/gsd/auto/loop.ts +5 -0
  315. package/src/resources/extensions/gsd/auto/phases.ts +194 -33
  316. package/src/resources/extensions/gsd/auto/session.ts +14 -0
  317. package/src/resources/extensions/gsd/auto-dashboard.ts +16 -7
  318. package/src/resources/extensions/gsd/auto-model-selection.ts +36 -0
  319. package/src/resources/extensions/gsd/auto-post-unit.ts +263 -12
  320. package/src/resources/extensions/gsd/auto-prompts.ts +21 -0
  321. package/src/resources/extensions/gsd/auto-recovery.ts +9 -8
  322. package/src/resources/extensions/gsd/auto-start.ts +11 -20
  323. package/src/resources/extensions/gsd/auto-timers.ts +2 -1
  324. package/src/resources/extensions/gsd/auto-tool-tracking.ts +19 -0
  325. package/src/resources/extensions/gsd/auto-verification.ts +190 -2
  326. package/src/resources/extensions/gsd/auto-worktree.ts +14 -6
  327. package/src/resources/extensions/gsd/auto.ts +26 -1
  328. package/src/resources/extensions/gsd/bootstrap/db-tools.ts +160 -88
  329. package/src/resources/extensions/gsd/bootstrap/dynamic-tools.ts +15 -0
  330. package/src/resources/extensions/gsd/bootstrap/query-tools.ts +98 -0
  331. package/src/resources/extensions/gsd/bootstrap/register-extension.ts +4 -0
  332. package/src/resources/extensions/gsd/bootstrap/register-hooks.ts +36 -1
  333. package/src/resources/extensions/gsd/bootstrap/sanitize-complete-milestone.ts +57 -0
  334. package/src/resources/extensions/gsd/bootstrap/system-context.ts +31 -2
  335. package/src/resources/extensions/gsd/commands-handlers.ts +10 -4
  336. package/src/resources/extensions/gsd/constants.ts +44 -0
  337. package/src/resources/extensions/gsd/db-writer.ts +78 -4
  338. package/src/resources/extensions/gsd/forensics.ts +21 -5
  339. package/src/resources/extensions/gsd/gsd-db.ts +64 -17
  340. package/src/resources/extensions/gsd/guided-flow.ts +22 -0
  341. package/src/resources/extensions/gsd/metrics.ts +28 -1
  342. package/src/resources/extensions/gsd/native-git-bridge.ts +5 -3
  343. package/src/resources/extensions/gsd/post-execution-checks.ts +539 -0
  344. package/src/resources/extensions/gsd/pre-execution-checks.ts +573 -0
  345. package/src/resources/extensions/gsd/preferences-types.ts +44 -0
  346. package/src/resources/extensions/gsd/preferences-validation.ts +33 -0
  347. package/src/resources/extensions/gsd/preferences.ts +13 -2
  348. package/src/resources/extensions/gsd/prompt-loader.ts +8 -0
  349. package/src/resources/extensions/gsd/prompts/complete-milestone.md +2 -0
  350. package/src/resources/extensions/gsd/prompts/complete-slice.md +2 -0
  351. package/src/resources/extensions/gsd/prompts/doctor-heal.md +1 -0
  352. package/src/resources/extensions/gsd/prompts/forensics.md +2 -0
  353. package/src/resources/extensions/gsd/prompts/reassess-roadmap.md +2 -0
  354. package/src/resources/extensions/gsd/prompts/system.md +4 -7
  355. package/src/resources/extensions/gsd/prompts/validate-milestone.md +2 -0
  356. package/src/resources/extensions/gsd/roadmap-mutations.ts +1 -1
  357. package/src/resources/extensions/gsd/roadmap-slices.ts +10 -5
  358. package/src/resources/extensions/gsd/safety/content-validator.ts +98 -0
  359. package/src/resources/extensions/gsd/safety/destructive-guard.ts +49 -0
  360. package/src/resources/extensions/gsd/safety/evidence-collector.ts +151 -0
  361. package/src/resources/extensions/gsd/safety/evidence-cross-ref.ts +120 -0
  362. package/src/resources/extensions/gsd/safety/file-change-validator.ts +108 -0
  363. package/src/resources/extensions/gsd/safety/git-checkpoint.ts +106 -0
  364. package/src/resources/extensions/gsd/safety/safety-harness.ts +105 -0
  365. package/src/resources/extensions/gsd/slice-parallel-conflict.ts +86 -0
  366. package/src/resources/extensions/gsd/slice-parallel-eligibility.ts +73 -0
  367. package/src/resources/extensions/gsd/slice-parallel-orchestrator.ts +477 -0
  368. package/src/resources/extensions/gsd/state.ts +67 -12
  369. package/src/resources/extensions/gsd/status-guards.ts +13 -0
  370. package/src/resources/extensions/gsd/tests/artifact-corruption-2630.test.ts +288 -0
  371. package/src/resources/extensions/gsd/tests/auto-loop.test.ts +34 -13
  372. package/src/resources/extensions/gsd/tests/auto-start-time-persistence.test.ts +50 -0
  373. package/src/resources/extensions/gsd/tests/cmux.test.ts +58 -0
  374. package/src/resources/extensions/gsd/tests/cold-resume-db-reopen.test.ts +51 -0
  375. package/src/resources/extensions/gsd/tests/complete-milestone.test.ts +140 -0
  376. package/src/resources/extensions/gsd/tests/complete-slice-string-coercion.test.ts +211 -0
  377. package/src/resources/extensions/gsd/tests/complete-task.test.ts +39 -0
  378. package/src/resources/extensions/gsd/tests/dashboard-model-label-ordering.test.ts +107 -0
  379. package/src/resources/extensions/gsd/tests/db-access-guardrails.test.ts +109 -0
  380. package/src/resources/extensions/gsd/tests/db-path-worktree-symlink.test.ts +13 -9
  381. package/src/resources/extensions/gsd/tests/db-writer.test.ts +134 -0
  382. package/src/resources/extensions/gsd/tests/deferred-slice-dispatch.test.ts +203 -0
  383. package/src/resources/extensions/gsd/tests/discuss-tool-scoping.test.ts +130 -0
  384. package/src/resources/extensions/gsd/tests/doctor-fix-flag.test.ts +92 -0
  385. package/src/resources/extensions/gsd/tests/enhanced-verification-integration.test.ts +526 -0
  386. package/src/resources/extensions/gsd/tests/finalize-timeout-guard.test.ts +116 -0
  387. package/src/resources/extensions/gsd/tests/flat-rate-routing-guard.test.ts +50 -0
  388. package/src/resources/extensions/gsd/tests/forensics-stuck-loops.test.ts +103 -0
  389. package/src/resources/extensions/gsd/tests/git-checkpoint.test.ts +94 -0
  390. package/src/resources/extensions/gsd/tests/insert-slice-no-wipe.test.ts +88 -0
  391. package/src/resources/extensions/gsd/tests/integration/git-service.test.ts +27 -7
  392. package/src/resources/extensions/gsd/tests/integration/idle-recovery.test.ts +34 -0
  393. package/src/resources/extensions/gsd/tests/metrics.test.ts +116 -1
  394. package/src/resources/extensions/gsd/tests/milestone-status-tool.test.ts +201 -0
  395. package/src/resources/extensions/gsd/tests/plan-milestone-title.test.ts +2 -1
  396. package/src/resources/extensions/gsd/tests/plan-milestone.test.ts +82 -18
  397. package/src/resources/extensions/gsd/tests/post-exec-retry-bypass.test.ts +312 -0
  398. package/src/resources/extensions/gsd/tests/post-execution-checks.test.ts +813 -0
  399. package/src/resources/extensions/gsd/tests/pre-execution-checks.test.ts +999 -0
  400. package/src/resources/extensions/gsd/tests/pre-execution-fail-closed.test.ts +266 -0
  401. package/src/resources/extensions/gsd/tests/pre-execution-pause-wiring.test.ts +457 -0
  402. package/src/resources/extensions/gsd/tests/preferences.test.ts +10 -0
  403. package/src/resources/extensions/gsd/tests/prompt-contracts.test.ts +25 -0
  404. package/src/resources/extensions/gsd/tests/roadmap-slices.test.ts +69 -0
  405. package/src/resources/extensions/gsd/tests/shared-wal.test.ts +30 -0
  406. package/src/resources/extensions/gsd/tests/slice-context-injection.test.ts +50 -0
  407. package/src/resources/extensions/gsd/tests/slice-parallel-conflict.test.ts +92 -0
  408. package/src/resources/extensions/gsd/tests/slice-parallel-eligibility.test.ts +95 -0
  409. package/src/resources/extensions/gsd/tests/slice-parallel-orchestrator.test.ts +83 -0
  410. package/src/resources/extensions/gsd/tests/stuck-detection-coverage.test.ts +42 -0
  411. package/src/resources/extensions/gsd/tests/tool-invocation-error-loop-break.test.ts +103 -0
  412. package/src/resources/extensions/gsd/tests/tool-param-optionality.test.ts +349 -0
  413. package/src/resources/extensions/gsd/tests/worktree-health-dispatch.test.ts +35 -2
  414. package/src/resources/extensions/gsd/tests/worktree-health-monorepo.test.ts +73 -0
  415. package/src/resources/extensions/gsd/tests/worktree-resolver.test.ts +34 -0
  416. package/src/resources/extensions/gsd/tests/worktree-submodule-safety.test.ts +1 -1
  417. package/src/resources/extensions/gsd/tests/worktree-teardown-safety.test.ts +148 -0
  418. package/src/resources/extensions/gsd/tools/complete-milestone.ts +34 -20
  419. package/src/resources/extensions/gsd/tools/complete-slice.ts +41 -26
  420. package/src/resources/extensions/gsd/tools/complete-task.ts +12 -12
  421. package/src/resources/extensions/gsd/tools/plan-milestone.ts +55 -30
  422. package/src/resources/extensions/gsd/tools/plan-slice.ts +13 -8
  423. package/src/resources/extensions/gsd/types.ts +44 -22
  424. package/src/resources/extensions/gsd/verification-evidence.ts +68 -0
  425. package/src/resources/extensions/gsd/workflow-logger.ts +2 -1
  426. package/src/resources/extensions/gsd/workflow-projections.ts +23 -5
  427. package/src/resources/extensions/gsd/worktree-manager.ts +76 -28
  428. package/src/resources/extensions/gsd/worktree-resolver.ts +4 -3
  429. package/src/resources/extensions/mcp-client/auth.ts +149 -0
  430. package/src/resources/extensions/mcp-client/index.ts +16 -1
  431. package/src/resources/extensions/ollama/index.ts +26 -25
  432. package/src/resources/extensions/ollama/model-capabilities.ts +41 -34
  433. package/src/resources/extensions/ollama/ndjson-stream.ts +63 -0
  434. package/src/resources/extensions/ollama/ollama-auth-mode.test.ts +20 -0
  435. package/src/resources/extensions/ollama/ollama-chat-provider.ts +459 -0
  436. package/src/resources/extensions/ollama/ollama-client.ts +30 -30
  437. package/src/resources/extensions/ollama/ollama-discovery.ts +5 -8
  438. package/src/resources/extensions/ollama/ollama-tool.ts +69 -0
  439. package/src/resources/extensions/ollama/tests/ollama-chat-provider-stream.test.ts +82 -0
  440. package/src/resources/extensions/ollama/tests/ollama-discovery.test.ts +0 -27
  441. package/src/resources/extensions/ollama/thinking-parser.ts +116 -0
  442. package/src/resources/extensions/ollama/types.ts +23 -0
  443. package/dist/web/standalone/.next/server/chunks/2229.js +0 -12
  444. package/dist/web/standalone/.next/static/chunks/app/page-62be3b5fa91e4c8f.js +0 -1
  445. package/dist/web/standalone/.next/static/chunks/main-app-d3d4c336195465f9.js +0 -1
  446. package/dist/web/standalone/.next/static/chunks/next/dist/client/components/builtin/global-error-ab5a8926e07ec673.js +0 -1
  447. /package/dist/web/standalone/.next/static/{5FLUBNdqolRyyehCyChPd → SoxM61WC_ia7R2gk4VMpJ}/_buildManifest.js +0 -0
  448. /package/dist/web/standalone/.next/static/{5FLUBNdqolRyyehCyChPd → SoxM61WC_ia7R2gk4VMpJ}/_ssgManifest.js +0 -0
@@ -0,0 +1,51 @@
1
+ /**
2
+ * GSD Slice Parallel Eligibility — Pure function to determine which slices
3
+ * within a milestone can run in parallel based on dependency satisfaction.
4
+ *
5
+ * This is the slice-level equivalent of parallel-eligibility.ts (which operates
6
+ * at milestone scope). The key difference is the positional fallback: slices
7
+ * without explicit dependencies use sequential ordering as an implicit constraint.
8
+ */
9
+ // ─── Core Logic ───────────────────────────────────────────────────────────────
10
+ /**
11
+ * Determine which slices are eligible for parallel execution.
12
+ *
13
+ * Rules:
14
+ * 1. Done slices are never eligible (nothing to do).
15
+ * 2. A slice with explicit `depends` entries is eligible when ALL deps
16
+ * appear in `completedSliceIds`.
17
+ * 3. A slice with NO `depends` entries uses positional fallback: it is
18
+ * eligible only when every positionally-earlier slice is done.
19
+ * This preserves backward compatibility with roadmaps that don't
20
+ * declare inter-slice dependencies.
21
+ *
22
+ * @param slices All slices in the milestone (ordered by position).
23
+ * @param completedSliceIds Set of slice IDs that are already complete.
24
+ * @returns Array of eligible slice descriptors.
25
+ */
26
+ export function getEligibleSlices(slices, completedSliceIds) {
27
+ const eligible = [];
28
+ for (let i = 0; i < slices.length; i++) {
29
+ const slice = slices[i];
30
+ // Rule 1: skip done slices
31
+ if (slice.done)
32
+ continue;
33
+ const hasExplicitDeps = slice.depends.length > 0;
34
+ if (hasExplicitDeps) {
35
+ // Rule 2: explicit dependencies — all must be satisfied
36
+ const allDepsSatisfied = slice.depends.every(dep => completedSliceIds.has(dep));
37
+ if (allDepsSatisfied) {
38
+ eligible.push({ id: slice.id });
39
+ }
40
+ }
41
+ else {
42
+ // Rule 3: no deps declared — positional fallback
43
+ // Eligible only if all positionally-earlier slices are done
44
+ const allEarlierDone = slices.slice(0, i).every(earlier => earlier.done || completedSliceIds.has(earlier.id));
45
+ if (allEarlierDone) {
46
+ eligible.push({ id: slice.id });
47
+ }
48
+ }
49
+ }
50
+ return eligible;
51
+ }
@@ -0,0 +1,378 @@
1
+ /**
2
+ * GSD Slice Parallel Orchestrator — Engine for parallel slice execution
3
+ * within a single milestone.
4
+ *
5
+ * Mirrors the existing parallel-orchestrator.ts pattern at slice scope
6
+ * instead of milestone scope. Workers are separate processes spawned via
7
+ * child_process, each running in its own git worktree with GSD_SLICE_LOCK
8
+ * + GSD_MILESTONE_LOCK env vars set.
9
+ *
10
+ * Key differences from milestone-level parallelism:
11
+ * - Scope: slices within one milestone, not milestones within a project
12
+ * - Lock env: GSD_SLICE_LOCK (in addition to GSD_MILESTONE_LOCK)
13
+ * - Conflict check: file overlap between slice plans (slice-parallel-conflict.ts)
14
+ */
15
+ import { spawn } from "node:child_process";
16
+ import { appendFileSync, existsSync, mkdirSync, } from "node:fs";
17
+ import { join, dirname } from "node:path";
18
+ import { fileURLToPath } from "node:url";
19
+ import { gsdRoot } from "./paths.js";
20
+ import { createWorktree, worktreePath, removeWorktree } from "./worktree-manager.js";
21
+ import { writeSessionStatus, } from "./session-status-io.js";
22
+ import { hasFileConflict } from "./slice-parallel-conflict.js";
23
+ import { getErrorMessage } from "./error-utils.js";
24
+ // ─── Module State ──────────────────────────────────────────────────────────
25
+ let sliceState = null;
26
+ // ─── Public API ────────────────────────────────────────────────────────────
27
+ /**
28
+ * Check whether slice-level parallel is currently active.
29
+ */
30
+ export function isSliceParallelActive() {
31
+ return sliceState?.active === true;
32
+ }
33
+ /**
34
+ * Get current slice orchestrator state (read-only snapshot).
35
+ */
36
+ export function getSliceOrchestratorState() {
37
+ return sliceState;
38
+ }
39
+ /**
40
+ * Start parallel execution for eligible slices within a milestone.
41
+ *
42
+ * For each eligible slice: create a worktree, spawn `gsd --mode json --print "/gsd auto"`
43
+ * with env GSD_SLICE_LOCK=<SID> + GSD_MILESTONE_LOCK=<MID> + GSD_PARALLEL_WORKER=1.
44
+ */
45
+ export async function startSliceParallel(basePath, milestoneId, eligibleSlices, opts = {}) {
46
+ // Prevent nesting: if already a parallel worker, refuse
47
+ if (process.env.GSD_PARALLEL_WORKER) {
48
+ return { started: [], errors: [{ sid: "all", error: "Cannot start slice-parallel from within a parallel worker" }] };
49
+ }
50
+ const maxWorkers = opts.maxWorkers ?? 2;
51
+ const budgetCeiling = opts.budgetCeiling;
52
+ // Initialize orchestrator state
53
+ sliceState = {
54
+ active: true,
55
+ workers: new Map(),
56
+ totalCost: 0,
57
+ budgetCeiling,
58
+ maxWorkers,
59
+ startedAt: Date.now(),
60
+ basePath,
61
+ };
62
+ const started = [];
63
+ const errors = [];
64
+ // Filter out conflicting slices (conservative: check all pairs)
65
+ const safeSlices = filterConflictingSlices(basePath, milestoneId, eligibleSlices);
66
+ // Limit to maxWorkers
67
+ const toSpawn = safeSlices.slice(0, maxWorkers);
68
+ for (const slice of toSpawn) {
69
+ try {
70
+ // Create worktree for this slice
71
+ const wtBranch = `slice/${milestoneId}/${slice.id}`;
72
+ const wtName = `${milestoneId}-${slice.id}`;
73
+ const wtPath = worktreePath(basePath, wtName);
74
+ if (!existsSync(wtPath)) {
75
+ createWorktree(basePath, wtName, { branch: wtBranch });
76
+ }
77
+ // Create worker info
78
+ const worker = {
79
+ milestoneId,
80
+ sliceId: slice.id,
81
+ pid: 0,
82
+ process: null,
83
+ worktreePath: wtPath,
84
+ startedAt: Date.now(),
85
+ state: "running",
86
+ completedUnits: 0,
87
+ cost: 0,
88
+ };
89
+ sliceState.workers.set(slice.id, worker);
90
+ // Spawn worker
91
+ const spawned = spawnSliceWorker(basePath, milestoneId, slice.id);
92
+ if (spawned) {
93
+ started.push(slice.id);
94
+ }
95
+ else {
96
+ errors.push({ sid: slice.id, error: "Failed to spawn worker process" });
97
+ worker.state = "error";
98
+ }
99
+ }
100
+ catch (err) {
101
+ errors.push({ sid: slice.id, error: getErrorMessage(err) });
102
+ // Best-effort cleanup of partially created worktree
103
+ const wtName = `${milestoneId}-${slice.id}`;
104
+ try {
105
+ removeWorktree(basePath, wtName, { deleteBranch: true, force: true });
106
+ }
107
+ catch { /* ignore cleanup failures */ }
108
+ }
109
+ }
110
+ // If nothing started, deactivate
111
+ if (started.length === 0) {
112
+ sliceState.active = false;
113
+ }
114
+ return { started, errors };
115
+ }
116
+ /**
117
+ * Stop all slice-parallel workers and deactivate.
118
+ */
119
+ export function stopSliceParallel() {
120
+ if (!sliceState)
121
+ return;
122
+ for (const worker of sliceState.workers.values()) {
123
+ if (worker.process) {
124
+ try {
125
+ worker.process.kill("SIGTERM");
126
+ }
127
+ catch { /* already dead */ }
128
+ }
129
+ worker.cleanup?.();
130
+ worker.cleanup = undefined;
131
+ worker.process = null;
132
+ worker.state = "stopped";
133
+ // Clean up worktree created for this worker
134
+ const wtName = `${worker.milestoneId}-${worker.sliceId}`;
135
+ try {
136
+ removeWorktree(sliceState.basePath, wtName, { deleteBranch: true, force: true });
137
+ }
138
+ catch { /* best-effort cleanup */ }
139
+ }
140
+ sliceState.active = false;
141
+ }
142
+ /**
143
+ * Get aggregate cost across all slice workers.
144
+ */
145
+ export function getSliceAggregateCost() {
146
+ if (!sliceState)
147
+ return 0;
148
+ let total = 0;
149
+ for (const w of sliceState.workers.values()) {
150
+ total += w.cost;
151
+ }
152
+ return total;
153
+ }
154
+ /**
155
+ * Check if budget ceiling has been exceeded.
156
+ */
157
+ export function isSliceBudgetExceeded() {
158
+ if (!sliceState?.budgetCeiling)
159
+ return false;
160
+ return getSliceAggregateCost() >= sliceState.budgetCeiling;
161
+ }
162
+ /**
163
+ * Reset module state (for testing).
164
+ */
165
+ export function resetSliceOrchestrator() {
166
+ if (sliceState) {
167
+ for (const w of sliceState.workers.values()) {
168
+ w.cleanup?.();
169
+ }
170
+ }
171
+ sliceState = null;
172
+ }
173
+ // ─── Internal: Conflict Filtering ──────────────────────────────────────────
174
+ /**
175
+ * Remove slices that have file conflicts with each other.
176
+ * Greedy: add slices to the safe set in order; skip any that conflict
177
+ * with an already-included slice.
178
+ */
179
+ function filterConflictingSlices(basePath, milestoneId, slices) {
180
+ const safe = [];
181
+ for (const candidate of slices) {
182
+ let conflictsWithSafe = false;
183
+ for (const existing of safe) {
184
+ if (hasFileConflict(basePath, milestoneId, candidate.id, existing.id)) {
185
+ conflictsWithSafe = true;
186
+ break;
187
+ }
188
+ }
189
+ if (!conflictsWithSafe) {
190
+ safe.push(candidate);
191
+ }
192
+ }
193
+ return safe;
194
+ }
195
+ // ─── Internal: Worker Spawning ─────────────────────────────────────────────
196
+ /**
197
+ * Resolve the GSD CLI binary path.
198
+ * Same logic as parallel-orchestrator.ts resolveGsdBin().
199
+ */
200
+ function resolveGsdBin() {
201
+ if (process.env.GSD_BIN_PATH && existsSync(process.env.GSD_BIN_PATH)) {
202
+ return process.env.GSD_BIN_PATH;
203
+ }
204
+ let thisDir;
205
+ try {
206
+ thisDir = dirname(fileURLToPath(import.meta.url));
207
+ }
208
+ catch {
209
+ thisDir = process.cwd();
210
+ }
211
+ const candidates = [
212
+ join(thisDir, "..", "..", "..", "loader.js"),
213
+ join(thisDir, "..", "..", "..", "..", "dist", "loader.js"),
214
+ ];
215
+ for (const candidate of candidates) {
216
+ if (existsSync(candidate))
217
+ return candidate;
218
+ }
219
+ return null;
220
+ }
221
+ /**
222
+ * Spawn a worker process for a slice.
223
+ * The worker runs `gsd --mode json --print "/gsd auto"` in the slice's worktree
224
+ * with GSD_SLICE_LOCK, GSD_MILESTONE_LOCK, and GSD_PARALLEL_WORKER set.
225
+ */
226
+ function spawnSliceWorker(basePath, milestoneId, sliceId) {
227
+ if (!sliceState)
228
+ return false;
229
+ const worker = sliceState.workers.get(sliceId);
230
+ if (!worker)
231
+ return false;
232
+ if (worker.process)
233
+ return true;
234
+ const binPath = resolveGsdBin();
235
+ if (!binPath)
236
+ return false;
237
+ let child;
238
+ try {
239
+ child = spawn(process.execPath, [binPath, "--mode", "json", "--print", "/gsd auto"], {
240
+ cwd: worker.worktreePath,
241
+ env: {
242
+ ...process.env,
243
+ GSD_SLICE_LOCK: sliceId,
244
+ GSD_MILESTONE_LOCK: milestoneId,
245
+ GSD_PROJECT_ROOT: basePath,
246
+ GSD_PARALLEL_WORKER: "1",
247
+ },
248
+ stdio: ["ignore", "pipe", "pipe"],
249
+ detached: false,
250
+ });
251
+ }
252
+ catch {
253
+ return false;
254
+ }
255
+ child.on("error", () => {
256
+ if (!sliceState)
257
+ return;
258
+ const w = sliceState.workers.get(sliceId);
259
+ if (w) {
260
+ w.process = null;
261
+ }
262
+ });
263
+ worker.process = child;
264
+ worker.pid = child.pid ?? 0;
265
+ if (!child.pid) {
266
+ worker.process = null;
267
+ return false;
268
+ }
269
+ // ── NDJSON stdout monitoring ────────────────────────────────────────
270
+ if (child.stdout) {
271
+ let stdoutBuffer = "";
272
+ child.stdout.on("data", (data) => {
273
+ stdoutBuffer += data.toString();
274
+ const lines = stdoutBuffer.split("\n");
275
+ stdoutBuffer = lines.pop() || "";
276
+ for (const line of lines) {
277
+ processSliceWorkerLine(basePath, milestoneId, sliceId, line);
278
+ }
279
+ });
280
+ child.stdout.on("close", () => {
281
+ if (stdoutBuffer.trim()) {
282
+ processSliceWorkerLine(basePath, milestoneId, sliceId, stdoutBuffer);
283
+ }
284
+ });
285
+ }
286
+ if (child.stderr) {
287
+ child.stderr.on("data", (data) => {
288
+ appendSliceWorkerLog(basePath, milestoneId, sliceId, data.toString());
289
+ });
290
+ }
291
+ // Update session status
292
+ writeSessionStatus(basePath, {
293
+ milestoneId: `${milestoneId}/${sliceId}`,
294
+ pid: worker.pid,
295
+ state: "running",
296
+ currentUnit: null,
297
+ completedUnits: worker.completedUnits,
298
+ cost: worker.cost,
299
+ lastHeartbeat: Date.now(),
300
+ startedAt: worker.startedAt,
301
+ worktreePath: worker.worktreePath,
302
+ });
303
+ // Store cleanup function
304
+ worker.cleanup = () => {
305
+ child.stdout?.removeAllListeners();
306
+ child.stderr?.removeAllListeners();
307
+ child.removeAllListeners();
308
+ };
309
+ // Handle worker exit
310
+ child.on("exit", (code) => {
311
+ if (!sliceState)
312
+ return;
313
+ const w = sliceState.workers.get(sliceId);
314
+ if (!w)
315
+ return;
316
+ w.cleanup?.();
317
+ w.cleanup = undefined;
318
+ w.process = null;
319
+ if (w.state === "stopped")
320
+ return;
321
+ if (code === 0) {
322
+ w.state = "stopped";
323
+ }
324
+ else {
325
+ w.state = "error";
326
+ appendSliceWorkerLog(basePath, milestoneId, sliceId, `\n[slice-orchestrator] worker exited with code ${code ?? "null"}\n`);
327
+ }
328
+ writeSessionStatus(basePath, {
329
+ milestoneId: `${milestoneId}/${sliceId}`,
330
+ pid: w.pid,
331
+ state: w.state,
332
+ currentUnit: null,
333
+ completedUnits: w.completedUnits,
334
+ cost: w.cost,
335
+ lastHeartbeat: Date.now(),
336
+ startedAt: w.startedAt,
337
+ worktreePath: w.worktreePath,
338
+ });
339
+ });
340
+ return true;
341
+ }
342
+ // ─── NDJSON Processing ──────────────────────────────────────────────────────
343
+ /**
344
+ * Process a single NDJSON line from a slice worker's stdout.
345
+ * Extracts cost from message_end events.
346
+ */
347
+ function processSliceWorkerLine(_basePath, _milestoneId, sliceId, line) {
348
+ if (!line.trim() || !sliceState)
349
+ return;
350
+ let event;
351
+ try {
352
+ event = JSON.parse(line);
353
+ }
354
+ catch {
355
+ return;
356
+ }
357
+ const type = String(event.type ?? "");
358
+ if (type === "message_end") {
359
+ const worker = sliceState.workers.get(sliceId);
360
+ if (worker) {
361
+ const usage = event.usage;
362
+ if (usage?.cost && typeof usage.cost === "number") {
363
+ worker.cost += usage.cost;
364
+ sliceState.totalCost += usage.cost;
365
+ }
366
+ worker.completedUnits++;
367
+ }
368
+ }
369
+ }
370
+ // ─── Logging ────────────────────────────────────────────────────────────────
371
+ function sliceLogDir(basePath) {
372
+ return join(gsdRoot(basePath), "parallel", "slice-logs");
373
+ }
374
+ function appendSliceWorkerLog(basePath, milestoneId, sliceId, text) {
375
+ const dir = sliceLogDir(basePath);
376
+ mkdirSync(dir, { recursive: true });
377
+ appendFileSync(join(dir, `${milestoneId}-${sliceId}.log`), text);
378
+ }
@@ -6,12 +6,13 @@ import { parseSummary, loadFile, parseRequirementCounts, parseContextDependsOn,
6
6
  import { resolveMilestoneFile, resolveSlicePath, resolveSliceFile, resolveTaskFile, resolveTasksDir, resolveGsdRootFile, gsdRoot, } from './paths.js';
7
7
  import { findMilestoneIds } from './milestone-ids.js';
8
8
  import { loadQueueOrder, sortByQueueOrder } from './queue-order.js';
9
+ import { isDeferredStatus } from './status-guards.js';
9
10
  import { nativeBatchParseGsdFiles } from './native-parser-bridge.js';
10
11
  import { join, resolve } from 'path';
11
12
  import { existsSync, readdirSync, readFileSync } from 'node:fs';
12
13
  import { debugCount, debugTime } from './debug-logger.js';
13
- import { extractVerdict } from './verdict-parser.js';
14
14
  import { logWarning, logError } from './workflow-logger.js';
15
+ import { extractVerdict } from './verdict-parser.js';
15
16
  import { isDbAvailable, getAllMilestones, getMilestone, getMilestoneSlices, getSliceTasks, getReplanHistory, getSlice, insertMilestone, insertSlice, updateTaskStatus, getPendingSliceGateCount, } from './gsd-db.js';
16
17
  /**
17
18
  * A "ghost" milestone directory contains only META.json (and no substantive
@@ -568,13 +569,43 @@ export async function deriveStateFromDb(basePath) {
568
569
  const doneSliceIds = new Set(activeMilestoneSlices.filter(s => isStatusDone(s.status)).map(s => s.id));
569
570
  let activeSlice = null;
570
571
  let activeSliceRow = null;
571
- for (const s of activeMilestoneSlices) {
572
- if (isStatusDone(s.status))
573
- continue;
574
- if (s.depends.every(dep => doneSliceIds.has(dep))) {
575
- activeSlice = { id: s.id, title: s.title };
576
- activeSliceRow = s;
577
- break;
572
+ // ── Slice-level parallel worker isolation ─────────────────────────────
573
+ // When GSD_SLICE_LOCK is set, this process is a parallel worker scoped
574
+ // to a single slice. Override activeSlice to only the locked slice ID.
575
+ const sliceLock = process.env.GSD_SLICE_LOCK;
576
+ if (sliceLock) {
577
+ const lockedSlice = activeMilestoneSlices.find(s => s.id === sliceLock);
578
+ if (lockedSlice) {
579
+ activeSlice = { id: lockedSlice.id, title: lockedSlice.title };
580
+ activeSliceRow = lockedSlice;
581
+ }
582
+ else {
583
+ logWarning("state", `GSD_SLICE_LOCK=${sliceLock} not found in active slices — worker has no assigned work`);
584
+ // Don't silently continue — this is a dispatch error
585
+ return {
586
+ activeMilestone, activeSlice: null, activeTask: null,
587
+ phase: 'blocked',
588
+ recentDecisions: [], blockers: [`GSD_SLICE_LOCK=${sliceLock} not found in active milestone slices`],
589
+ nextAction: 'Slice lock references a non-existent slice — check orchestrator dispatch.',
590
+ registry, requirements,
591
+ progress: { milestones: milestoneProgress, slices: sliceProgress },
592
+ };
593
+ }
594
+ }
595
+ else {
596
+ for (const s of activeMilestoneSlices) {
597
+ if (isStatusDone(s.status))
598
+ continue;
599
+ // #2661: Skip deferred slices — a decision explicitly deferred this work.
600
+ // Without this guard the dispatcher would keep dispatching deferred slices
601
+ // because DECISIONS.md is only contextual, not authoritative for dispatch.
602
+ if (isDeferredStatus(s.status))
603
+ continue;
604
+ if (s.depends.every(dep => doneSliceIds.has(dep))) {
605
+ activeSlice = { id: s.id, title: s.title };
606
+ activeSliceRow = s;
607
+ break;
608
+ }
578
609
  }
579
610
  }
580
611
  if (!activeSlice) {
@@ -1188,12 +1219,41 @@ export async function _deriveStateImpl(basePath) {
1188
1219
  // Find the active slice (first incomplete with deps satisfied)
1189
1220
  const doneSliceIds = new Set(activeRoadmap.slices.filter(s => s.done).map(s => s.id));
1190
1221
  let activeSlice = null;
1191
- for (const s of activeRoadmap.slices) {
1192
- if (s.done)
1193
- continue;
1194
- if (s.depends.every(dep => doneSliceIds.has(dep))) {
1195
- activeSlice = { id: s.id, title: s.title };
1196
- break;
1222
+ // ── Slice-level parallel worker isolation ─────────────────────────────
1223
+ // When GSD_SLICE_LOCK is set, override activeSlice to only the locked slice.
1224
+ const sliceLockLegacy = process.env.GSD_SLICE_LOCK;
1225
+ if (sliceLockLegacy) {
1226
+ const lockedSlice = activeRoadmap.slices.find(s => s.id === sliceLockLegacy);
1227
+ if (lockedSlice) {
1228
+ activeSlice = { id: lockedSlice.id, title: lockedSlice.title };
1229
+ }
1230
+ else {
1231
+ logWarning("state", `GSD_SLICE_LOCK=${sliceLockLegacy} not found in active slices — worker has no assigned work`);
1232
+ return {
1233
+ activeMilestone,
1234
+ activeSlice: null,
1235
+ activeTask: null,
1236
+ phase: 'blocked',
1237
+ recentDecisions: [],
1238
+ blockers: [`GSD_SLICE_LOCK=${sliceLockLegacy} not found in active milestone slices`],
1239
+ nextAction: 'Slice lock references a non-existent slice — check orchestrator dispatch.',
1240
+ registry,
1241
+ requirements,
1242
+ progress: {
1243
+ milestones: milestoneProgress,
1244
+ slices: sliceProgress,
1245
+ },
1246
+ };
1247
+ }
1248
+ }
1249
+ else {
1250
+ for (const s of activeRoadmap.slices) {
1251
+ if (s.done)
1252
+ continue;
1253
+ if (s.depends.every(dep => doneSliceIds.has(dep))) {
1254
+ activeSlice = { id: s.id, title: s.title };
1255
+ break;
1256
+ }
1197
1257
  }
1198
1258
  }
1199
1259
  if (!activeSlice) {
@@ -11,3 +11,14 @@
11
11
  export function isClosedStatus(status) {
12
12
  return status === "complete" || status === "done" || status === "skipped";
13
13
  }
14
+ /** Returns true when a slice status indicates it was deferred by a decision. */
15
+ export function isDeferredStatus(status) {
16
+ return status === "deferred";
17
+ }
18
+ /**
19
+ * Returns true when a slice should be skipped during active-slice selection.
20
+ * This includes both closed (complete/done) and deferred slices.
21
+ */
22
+ export function isInactiveStatus(status) {
23
+ return isClosedStatus(status) || isDeferredStatus(status);
24
+ }
@@ -12,24 +12,29 @@ import { resolveMilestonePath, clearPathCache } from "../paths.js";
12
12
  import { isClosedStatus } from "../status-guards.js";
13
13
  import { saveFile, clearParseCache } from "../files.js";
14
14
  import { invalidateStateCache } from "../state.js";
15
- import { renderAllProjections } from "../workflow-projections.js";
15
+ import { renderAllProjections, stripIdPrefix } from "../workflow-projections.js";
16
16
  import { writeManifest } from "../workflow-manifest.js";
17
17
  import { appendEvent } from "../workflow-events.js";
18
18
  import { logWarning } from "../workflow-logger.js";
19
19
  function renderMilestoneSummaryMarkdown(params) {
20
20
  const now = new Date().toISOString();
21
- const keyDecisionsYaml = params.keyDecisions.length > 0
22
- ? params.keyDecisions.map(d => ` - ${d}`).join("\n")
21
+ const displayTitle = stripIdPrefix(params.title, params.milestoneId);
22
+ // Apply defaults for optional enrichment fields (#2771)
23
+ const keyDecisions = params.keyDecisions ?? [];
24
+ const keyFiles = params.keyFiles ?? [];
25
+ const lessonsLearned = params.lessonsLearned ?? [];
26
+ const keyDecisionsYaml = keyDecisions.length > 0
27
+ ? keyDecisions.map(d => ` - ${d}`).join("\n")
23
28
  : " - (none)";
24
- const keyFilesYaml = params.keyFiles.length > 0
25
- ? params.keyFiles.map(f => ` - ${f}`).join("\n")
29
+ const keyFilesYaml = keyFiles.length > 0
30
+ ? keyFiles.map(f => ` - ${f}`).join("\n")
26
31
  : " - (none)";
27
- const lessonsYaml = params.lessonsLearned.length > 0
28
- ? params.lessonsLearned.map(l => ` - ${l}`).join("\n")
32
+ const lessonsYaml = lessonsLearned.length > 0
33
+ ? lessonsLearned.map(l => ` - ${l}`).join("\n")
29
34
  : " - (none)";
30
35
  return `---
31
36
  id: ${params.milestoneId}
32
- title: "${params.title}"
37
+ title: "${displayTitle}"
33
38
  status: complete
34
39
  completed_at: ${now}
35
40
  key_decisions:
@@ -40,7 +45,7 @@ lessons_learned:
40
45
  ${lessonsYaml}
41
46
  ---
42
47
 
43
- # ${params.milestoneId}: ${params.title}
48
+ # ${params.milestoneId}: ${displayTitle}
44
49
 
45
50
  **${params.oneLiner}**
46
51
 
@@ -50,15 +55,15 @@ ${params.narrative}
50
55
 
51
56
  ## Success Criteria Results
52
57
 
53
- ${params.successCriteriaResults}
58
+ ${params.successCriteriaResults ?? "Not provided."}
54
59
 
55
60
  ## Definition of Done Results
56
61
 
57
- ${params.definitionOfDoneResults}
62
+ ${params.definitionOfDoneResults ?? "Not provided."}
58
63
 
59
64
  ## Requirement Outcomes
60
65
 
61
- ${params.requirementOutcomes}
66
+ ${params.requirementOutcomes ?? "Not provided."}
62
67
 
63
68
  ## Deviations
64
69