gsd-pi 2.63.0 → 2.64.0-dev.1a85e85

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 (583) 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/notify-interceptor.js +28 -0
  27. package/dist/resources/extensions/gsd/bootstrap/query-tools.js +85 -0
  28. package/dist/resources/extensions/gsd/bootstrap/register-extension.js +3 -0
  29. package/dist/resources/extensions/gsd/bootstrap/register-hooks.js +40 -1
  30. package/dist/resources/extensions/gsd/bootstrap/register-shortcuts.js +15 -0
  31. package/dist/resources/extensions/gsd/bootstrap/sanitize-complete-milestone.js +54 -0
  32. package/dist/resources/extensions/gsd/bootstrap/system-context.js +50 -2
  33. package/dist/resources/extensions/gsd/commands/catalog.js +7 -1
  34. package/dist/resources/extensions/gsd/commands/handlers/core.js +1 -0
  35. package/dist/resources/extensions/gsd/commands/handlers/notifications-handler.js +103 -0
  36. package/dist/resources/extensions/gsd/commands/handlers/ops.js +5 -0
  37. package/dist/resources/extensions/gsd/commands-handlers.js +9 -4
  38. package/dist/resources/extensions/gsd/constants.js +42 -0
  39. package/dist/resources/extensions/gsd/db-writer.js +72 -4
  40. package/dist/resources/extensions/gsd/forensics.js +20 -4
  41. package/dist/resources/extensions/gsd/gsd-db.js +64 -17
  42. package/dist/resources/extensions/gsd/guided-flow.js +19 -0
  43. package/dist/resources/extensions/gsd/metrics.js +27 -1
  44. package/dist/resources/extensions/gsd/native-git-bridge.js +5 -3
  45. package/dist/resources/extensions/gsd/notification-overlay.js +224 -0
  46. package/dist/resources/extensions/gsd/notification-store.js +268 -0
  47. package/dist/resources/extensions/gsd/notification-widget.js +56 -0
  48. package/dist/resources/extensions/gsd/post-execution-checks.js +407 -0
  49. package/dist/resources/extensions/gsd/pre-execution-checks.js +464 -0
  50. package/dist/resources/extensions/gsd/preferences-types.js +6 -0
  51. package/dist/resources/extensions/gsd/preferences-validation.js +33 -0
  52. package/dist/resources/extensions/gsd/preferences.js +11 -2
  53. package/dist/resources/extensions/gsd/prompt-loader.js +7 -0
  54. package/dist/resources/extensions/gsd/prompts/complete-milestone.md +2 -0
  55. package/dist/resources/extensions/gsd/prompts/complete-slice.md +2 -0
  56. package/dist/resources/extensions/gsd/prompts/doctor-heal.md +1 -0
  57. package/dist/resources/extensions/gsd/prompts/forensics.md +2 -0
  58. package/dist/resources/extensions/gsd/prompts/reassess-roadmap.md +2 -0
  59. package/dist/resources/extensions/gsd/prompts/system.md +4 -7
  60. package/dist/resources/extensions/gsd/prompts/validate-milestone.md +2 -0
  61. package/dist/resources/extensions/gsd/roadmap-mutations.js +1 -1
  62. package/dist/resources/extensions/gsd/roadmap-slices.js +9 -5
  63. package/dist/resources/extensions/gsd/safety/content-validator.js +73 -0
  64. package/dist/resources/extensions/gsd/safety/destructive-guard.js +34 -0
  65. package/dist/resources/extensions/gsd/safety/evidence-collector.js +109 -0
  66. package/dist/resources/extensions/gsd/safety/evidence-cross-ref.js +83 -0
  67. package/dist/resources/extensions/gsd/safety/file-change-validator.js +71 -0
  68. package/dist/resources/extensions/gsd/safety/git-checkpoint.js +91 -0
  69. package/dist/resources/extensions/gsd/safety/safety-harness.js +64 -0
  70. package/dist/resources/extensions/gsd/slice-parallel-conflict.js +67 -0
  71. package/dist/resources/extensions/gsd/slice-parallel-eligibility.js +51 -0
  72. package/dist/resources/extensions/gsd/slice-parallel-orchestrator.js +378 -0
  73. package/dist/resources/extensions/gsd/state.js +74 -14
  74. package/dist/resources/extensions/gsd/status-guards.js +11 -0
  75. package/dist/resources/extensions/gsd/tools/complete-milestone.js +17 -12
  76. package/dist/resources/extensions/gsd/tools/complete-slice.js +40 -26
  77. package/dist/resources/extensions/gsd/tools/complete-task.js +12 -12
  78. package/dist/resources/extensions/gsd/tools/plan-milestone.js +33 -25
  79. package/dist/resources/extensions/gsd/tools/plan-slice.js +5 -8
  80. package/dist/resources/extensions/gsd/verification-evidence.js +18 -0
  81. package/dist/resources/extensions/gsd/workflow-logger.js +8 -0
  82. package/dist/resources/extensions/gsd/workflow-projections.js +21 -5
  83. package/dist/resources/extensions/gsd/worktree-manager.js +82 -29
  84. package/dist/resources/extensions/gsd/worktree-resolver.js +4 -3
  85. package/dist/resources/extensions/mcp-client/auth.js +101 -0
  86. package/dist/resources/extensions/mcp-client/index.js +10 -1
  87. package/dist/resources/extensions/ollama/index.js +28 -22
  88. package/dist/resources/extensions/ollama/model-capabilities.js +37 -34
  89. package/dist/resources/extensions/ollama/ndjson-stream.js +54 -0
  90. package/dist/resources/extensions/ollama/ollama-chat-provider.js +380 -0
  91. package/dist/resources/extensions/ollama/ollama-client.js +23 -32
  92. package/dist/resources/extensions/ollama/ollama-discovery.js +2 -7
  93. package/dist/resources/extensions/ollama/ollama-tool.js +62 -0
  94. package/dist/resources/extensions/ollama/thinking-parser.js +104 -0
  95. package/dist/update-cmd.js +4 -2
  96. package/dist/web/standalone/.next/BUILD_ID +1 -1
  97. package/dist/web/standalone/.next/app-path-routes-manifest.json +19 -18
  98. package/dist/web/standalone/.next/build-manifest.json +3 -3
  99. package/dist/web/standalone/.next/prerender-manifest.json +3 -3
  100. package/dist/web/standalone/.next/required-server-files.json +4 -4
  101. package/dist/web/standalone/.next/routes-manifest.json +6 -0
  102. package/dist/web/standalone/.next/server/app/_global-error/page.js +3 -3
  103. package/dist/web/standalone/.next/server/app/_global-error/page_client-reference-manifest.js +1 -1
  104. package/dist/web/standalone/.next/server/app/_global-error.html +2 -2
  105. package/dist/web/standalone/.next/server/app/_global-error.rsc +1 -1
  106. package/dist/web/standalone/.next/server/app/_global-error.segments/_full.segment.rsc +1 -1
  107. package/dist/web/standalone/.next/server/app/_global-error.segments/_global-error/__PAGE__.segment.rsc +1 -1
  108. package/dist/web/standalone/.next/server/app/_global-error.segments/_global-error.segment.rsc +1 -1
  109. package/dist/web/standalone/.next/server/app/_global-error.segments/_head.segment.rsc +1 -1
  110. package/dist/web/standalone/.next/server/app/_global-error.segments/_index.segment.rsc +1 -1
  111. package/dist/web/standalone/.next/server/app/_global-error.segments/_tree.segment.rsc +1 -1
  112. package/dist/web/standalone/.next/server/app/_not-found/page.js +2 -2
  113. package/dist/web/standalone/.next/server/app/_not-found/page_client-reference-manifest.js +1 -1
  114. package/dist/web/standalone/.next/server/app/_not-found.html +1 -1
  115. package/dist/web/standalone/.next/server/app/_not-found.rsc +3 -3
  116. package/dist/web/standalone/.next/server/app/_not-found.segments/_full.segment.rsc +3 -3
  117. package/dist/web/standalone/.next/server/app/_not-found.segments/_head.segment.rsc +1 -1
  118. package/dist/web/standalone/.next/server/app/_not-found.segments/_index.segment.rsc +3 -3
  119. package/dist/web/standalone/.next/server/app/_not-found.segments/_not-found/__PAGE__.segment.rsc +1 -1
  120. package/dist/web/standalone/.next/server/app/_not-found.segments/_not-found.segment.rsc +1 -1
  121. package/dist/web/standalone/.next/server/app/_not-found.segments/_tree.segment.rsc +1 -1
  122. package/dist/web/standalone/.next/server/app/api/boot/route.js +1 -1
  123. package/dist/web/standalone/.next/server/app/api/boot/route.js.nft.json +1 -1
  124. package/dist/web/standalone/.next/server/app/api/boot/route_client-reference-manifest.js +1 -1
  125. package/dist/web/standalone/.next/server/app/api/bridge-terminal/input/route.js +1 -1
  126. package/dist/web/standalone/.next/server/app/api/bridge-terminal/input/route.js.nft.json +1 -1
  127. package/dist/web/standalone/.next/server/app/api/bridge-terminal/input/route_client-reference-manifest.js +1 -1
  128. package/dist/web/standalone/.next/server/app/api/bridge-terminal/resize/route.js +1 -1
  129. package/dist/web/standalone/.next/server/app/api/bridge-terminal/resize/route.js.nft.json +1 -1
  130. package/dist/web/standalone/.next/server/app/api/bridge-terminal/resize/route_client-reference-manifest.js +1 -1
  131. package/dist/web/standalone/.next/server/app/api/bridge-terminal/stream/route.js +2 -2
  132. package/dist/web/standalone/.next/server/app/api/bridge-terminal/stream/route.js.nft.json +1 -1
  133. package/dist/web/standalone/.next/server/app/api/bridge-terminal/stream/route_client-reference-manifest.js +1 -1
  134. package/dist/web/standalone/.next/server/app/api/browse-directories/route.js +1 -1
  135. package/dist/web/standalone/.next/server/app/api/browse-directories/route_client-reference-manifest.js +1 -1
  136. package/dist/web/standalone/.next/server/app/api/captures/route.js +1 -1
  137. package/dist/web/standalone/.next/server/app/api/captures/route.js.nft.json +1 -1
  138. package/dist/web/standalone/.next/server/app/api/captures/route_client-reference-manifest.js +1 -1
  139. package/dist/web/standalone/.next/server/app/api/cleanup/route.js +1 -1
  140. package/dist/web/standalone/.next/server/app/api/cleanup/route.js.nft.json +1 -1
  141. package/dist/web/standalone/.next/server/app/api/cleanup/route_client-reference-manifest.js +1 -1
  142. package/dist/web/standalone/.next/server/app/api/dev-mode/route.js +1 -1
  143. package/dist/web/standalone/.next/server/app/api/dev-mode/route_client-reference-manifest.js +1 -1
  144. package/dist/web/standalone/.next/server/app/api/doctor/route.js +1 -1
  145. package/dist/web/standalone/.next/server/app/api/doctor/route.js.nft.json +1 -1
  146. package/dist/web/standalone/.next/server/app/api/doctor/route_client-reference-manifest.js +1 -1
  147. package/dist/web/standalone/.next/server/app/api/experimental/route.js +2 -2
  148. package/dist/web/standalone/.next/server/app/api/experimental/route_client-reference-manifest.js +1 -1
  149. package/dist/web/standalone/.next/server/app/api/export-data/route.js +1 -1
  150. package/dist/web/standalone/.next/server/app/api/export-data/route.js.nft.json +1 -1
  151. package/dist/web/standalone/.next/server/app/api/export-data/route_client-reference-manifest.js +1 -1
  152. package/dist/web/standalone/.next/server/app/api/files/route.js +1 -1
  153. package/dist/web/standalone/.next/server/app/api/files/route.js.nft.json +1 -1
  154. package/dist/web/standalone/.next/server/app/api/files/route_client-reference-manifest.js +1 -1
  155. package/dist/web/standalone/.next/server/app/api/forensics/route.js +1 -1
  156. package/dist/web/standalone/.next/server/app/api/forensics/route.js.nft.json +1 -1
  157. package/dist/web/standalone/.next/server/app/api/forensics/route_client-reference-manifest.js +1 -1
  158. package/dist/web/standalone/.next/server/app/api/git/route.js +1 -1
  159. package/dist/web/standalone/.next/server/app/api/git/route.js.nft.json +1 -1
  160. package/dist/web/standalone/.next/server/app/api/git/route_client-reference-manifest.js +1 -1
  161. package/dist/web/standalone/.next/server/app/api/history/route.js +1 -1
  162. package/dist/web/standalone/.next/server/app/api/history/route.js.nft.json +1 -1
  163. package/dist/web/standalone/.next/server/app/api/history/route_client-reference-manifest.js +1 -1
  164. package/dist/web/standalone/.next/server/app/api/hooks/route.js +1 -1
  165. package/dist/web/standalone/.next/server/app/api/hooks/route.js.nft.json +1 -1
  166. package/dist/web/standalone/.next/server/app/api/hooks/route_client-reference-manifest.js +1 -1
  167. package/dist/web/standalone/.next/server/app/api/inspect/route.js +1 -1
  168. package/dist/web/standalone/.next/server/app/api/inspect/route.js.nft.json +1 -1
  169. package/dist/web/standalone/.next/server/app/api/inspect/route_client-reference-manifest.js +1 -1
  170. package/dist/web/standalone/.next/server/app/api/knowledge/route.js +1 -1
  171. package/dist/web/standalone/.next/server/app/api/knowledge/route.js.nft.json +1 -1
  172. package/dist/web/standalone/.next/server/app/api/knowledge/route_client-reference-manifest.js +1 -1
  173. package/dist/web/standalone/.next/server/app/api/live-state/route.js +1 -1
  174. package/dist/web/standalone/.next/server/app/api/live-state/route.js.nft.json +1 -1
  175. package/dist/web/standalone/.next/server/app/api/live-state/route_client-reference-manifest.js +1 -1
  176. package/dist/web/standalone/.next/server/app/api/notifications/route.js +3 -0
  177. package/dist/web/standalone/.next/server/app/api/notifications/route.js.nft.json +1 -0
  178. package/dist/web/standalone/.next/server/app/api/notifications/route_client-reference-manifest.js +1 -0
  179. package/dist/web/standalone/.next/server/app/api/onboarding/route.js +1 -1
  180. package/dist/web/standalone/.next/server/app/api/onboarding/route.js.nft.json +1 -1
  181. package/dist/web/standalone/.next/server/app/api/onboarding/route_client-reference-manifest.js +1 -1
  182. package/dist/web/standalone/.next/server/app/api/preferences/route.js +1 -1
  183. package/dist/web/standalone/.next/server/app/api/preferences/route_client-reference-manifest.js +1 -1
  184. package/dist/web/standalone/.next/server/app/api/projects/route.js +1 -1
  185. package/dist/web/standalone/.next/server/app/api/projects/route.js.nft.json +1 -1
  186. package/dist/web/standalone/.next/server/app/api/projects/route_client-reference-manifest.js +1 -1
  187. package/dist/web/standalone/.next/server/app/api/recovery/route.js +1 -1
  188. package/dist/web/standalone/.next/server/app/api/recovery/route.js.nft.json +1 -1
  189. package/dist/web/standalone/.next/server/app/api/recovery/route_client-reference-manifest.js +1 -1
  190. package/dist/web/standalone/.next/server/app/api/remote-questions/route.js +2 -2
  191. package/dist/web/standalone/.next/server/app/api/remote-questions/route_client-reference-manifest.js +1 -1
  192. package/dist/web/standalone/.next/server/app/api/session/browser/route.js +1 -1
  193. package/dist/web/standalone/.next/server/app/api/session/browser/route.js.nft.json +1 -1
  194. package/dist/web/standalone/.next/server/app/api/session/browser/route_client-reference-manifest.js +1 -1
  195. package/dist/web/standalone/.next/server/app/api/session/command/route.js +1 -1
  196. package/dist/web/standalone/.next/server/app/api/session/command/route.js.nft.json +1 -1
  197. package/dist/web/standalone/.next/server/app/api/session/command/route_client-reference-manifest.js +1 -1
  198. package/dist/web/standalone/.next/server/app/api/session/events/route.js +2 -2
  199. package/dist/web/standalone/.next/server/app/api/session/events/route.js.nft.json +1 -1
  200. package/dist/web/standalone/.next/server/app/api/session/events/route_client-reference-manifest.js +1 -1
  201. package/dist/web/standalone/.next/server/app/api/session/manage/route.js +1 -1
  202. package/dist/web/standalone/.next/server/app/api/session/manage/route.js.nft.json +1 -1
  203. package/dist/web/standalone/.next/server/app/api/session/manage/route_client-reference-manifest.js +1 -1
  204. package/dist/web/standalone/.next/server/app/api/settings-data/route.js +1 -1
  205. package/dist/web/standalone/.next/server/app/api/settings-data/route.js.nft.json +1 -1
  206. package/dist/web/standalone/.next/server/app/api/settings-data/route_client-reference-manifest.js +1 -1
  207. package/dist/web/standalone/.next/server/app/api/shutdown/route.js +1 -1
  208. package/dist/web/standalone/.next/server/app/api/shutdown/route_client-reference-manifest.js +1 -1
  209. package/dist/web/standalone/.next/server/app/api/skill-health/route.js +1 -1
  210. package/dist/web/standalone/.next/server/app/api/skill-health/route.js.nft.json +1 -1
  211. package/dist/web/standalone/.next/server/app/api/skill-health/route_client-reference-manifest.js +1 -1
  212. package/dist/web/standalone/.next/server/app/api/steer/route.js +1 -1
  213. package/dist/web/standalone/.next/server/app/api/steer/route.js.nft.json +1 -1
  214. package/dist/web/standalone/.next/server/app/api/steer/route_client-reference-manifest.js +1 -1
  215. package/dist/web/standalone/.next/server/app/api/switch-root/route.js +1 -1
  216. package/dist/web/standalone/.next/server/app/api/switch-root/route.js.nft.json +1 -1
  217. package/dist/web/standalone/.next/server/app/api/switch-root/route_client-reference-manifest.js +1 -1
  218. package/dist/web/standalone/.next/server/app/api/terminal/input/route.js +2 -2
  219. package/dist/web/standalone/.next/server/app/api/terminal/input/route_client-reference-manifest.js +1 -1
  220. package/dist/web/standalone/.next/server/app/api/terminal/resize/route.js +2 -2
  221. package/dist/web/standalone/.next/server/app/api/terminal/resize/route_client-reference-manifest.js +1 -1
  222. package/dist/web/standalone/.next/server/app/api/terminal/sessions/route.js +2 -2
  223. package/dist/web/standalone/.next/server/app/api/terminal/sessions/route.js.nft.json +1 -1
  224. package/dist/web/standalone/.next/server/app/api/terminal/sessions/route_client-reference-manifest.js +1 -1
  225. package/dist/web/standalone/.next/server/app/api/terminal/stream/route.js +4 -4
  226. package/dist/web/standalone/.next/server/app/api/terminal/stream/route.js.nft.json +1 -1
  227. package/dist/web/standalone/.next/server/app/api/terminal/stream/route_client-reference-manifest.js +1 -1
  228. package/dist/web/standalone/.next/server/app/api/terminal/upload/route.js +1 -1
  229. package/dist/web/standalone/.next/server/app/api/terminal/upload/route_client-reference-manifest.js +1 -1
  230. package/dist/web/standalone/.next/server/app/api/undo/route.js +1 -1
  231. package/dist/web/standalone/.next/server/app/api/undo/route.js.nft.json +1 -1
  232. package/dist/web/standalone/.next/server/app/api/undo/route_client-reference-manifest.js +1 -1
  233. package/dist/web/standalone/.next/server/app/api/update/route.js +1 -1
  234. package/dist/web/standalone/.next/server/app/api/update/route_client-reference-manifest.js +1 -1
  235. package/dist/web/standalone/.next/server/app/api/visualizer/route.js +1 -1
  236. package/dist/web/standalone/.next/server/app/api/visualizer/route.js.nft.json +1 -1
  237. package/dist/web/standalone/.next/server/app/api/visualizer/route_client-reference-manifest.js +1 -1
  238. package/dist/web/standalone/.next/server/app/index.html +1 -1
  239. package/dist/web/standalone/.next/server/app/index.rsc +4 -4
  240. package/dist/web/standalone/.next/server/app/index.segments/__PAGE__.segment.rsc +2 -2
  241. package/dist/web/standalone/.next/server/app/index.segments/_full.segment.rsc +4 -4
  242. package/dist/web/standalone/.next/server/app/index.segments/_head.segment.rsc +1 -1
  243. package/dist/web/standalone/.next/server/app/index.segments/_index.segment.rsc +3 -3
  244. package/dist/web/standalone/.next/server/app/index.segments/_tree.segment.rsc +1 -1
  245. package/dist/web/standalone/.next/server/app/page.js +2 -2
  246. package/dist/web/standalone/.next/server/app/page_client-reference-manifest.js +1 -1
  247. package/dist/web/standalone/.next/server/app-paths-manifest.json +19 -18
  248. package/dist/web/standalone/.next/server/chunks/6897.js +12 -0
  249. package/dist/web/standalone/.next/server/chunks/7471.js +3 -3
  250. package/dist/web/standalone/.next/server/functions-config-manifest.json +1 -0
  251. package/dist/web/standalone/.next/server/middleware-build-manifest.js +1 -1
  252. package/dist/web/standalone/.next/server/middleware.js +2 -2
  253. package/dist/web/standalone/.next/server/next-font-manifest.js +1 -1
  254. package/dist/web/standalone/.next/server/next-font-manifest.json +1 -1
  255. package/dist/web/standalone/.next/server/pages/404.html +1 -1
  256. package/dist/web/standalone/.next/server/pages/500.html +2 -2
  257. package/dist/web/standalone/.next/server/server-reference-manifest.json +1 -1
  258. package/dist/web/standalone/.next/static/chunks/app/_global-error/page-8805a20e15762c3c.js +1 -0
  259. package/dist/web/standalone/.next/static/chunks/app/_not-found/{page-2f24283c162b6ab3.js → page-f2a7482d42a5614b.js} +1 -1
  260. package/dist/web/standalone/.next/static/chunks/app/api/boot/route-8805a20e15762c3c.js +1 -0
  261. package/dist/web/standalone/.next/static/chunks/app/api/bridge-terminal/input/route-8805a20e15762c3c.js +1 -0
  262. package/dist/web/standalone/.next/static/chunks/app/api/bridge-terminal/resize/route-8805a20e15762c3c.js +1 -0
  263. package/dist/web/standalone/.next/static/chunks/app/api/bridge-terminal/stream/route-8805a20e15762c3c.js +1 -0
  264. package/dist/web/standalone/.next/static/chunks/app/api/browse-directories/route-8805a20e15762c3c.js +1 -0
  265. package/dist/web/standalone/.next/static/chunks/app/api/captures/route-8805a20e15762c3c.js +1 -0
  266. package/dist/web/standalone/.next/static/chunks/app/api/cleanup/route-8805a20e15762c3c.js +1 -0
  267. package/dist/web/standalone/.next/static/chunks/app/api/dev-mode/route-8805a20e15762c3c.js +1 -0
  268. package/dist/web/standalone/.next/static/chunks/app/api/doctor/route-8805a20e15762c3c.js +1 -0
  269. package/dist/web/standalone/.next/static/chunks/app/api/experimental/route-8805a20e15762c3c.js +1 -0
  270. package/dist/web/standalone/.next/static/chunks/app/api/export-data/route-8805a20e15762c3c.js +1 -0
  271. package/dist/web/standalone/.next/static/chunks/app/api/files/route-8805a20e15762c3c.js +1 -0
  272. package/dist/web/standalone/.next/static/chunks/app/api/forensics/route-8805a20e15762c3c.js +1 -0
  273. package/dist/web/standalone/.next/static/chunks/app/api/git/route-8805a20e15762c3c.js +1 -0
  274. package/dist/web/standalone/.next/static/chunks/app/api/history/route-8805a20e15762c3c.js +1 -0
  275. package/dist/web/standalone/.next/static/chunks/app/api/hooks/route-8805a20e15762c3c.js +1 -0
  276. package/dist/web/standalone/.next/static/chunks/app/api/inspect/route-8805a20e15762c3c.js +1 -0
  277. package/dist/web/standalone/.next/static/chunks/app/api/knowledge/route-8805a20e15762c3c.js +1 -0
  278. package/dist/web/standalone/.next/static/chunks/app/api/live-state/route-8805a20e15762c3c.js +1 -0
  279. package/dist/web/standalone/.next/static/chunks/app/api/notifications/route-8805a20e15762c3c.js +1 -0
  280. package/dist/web/standalone/.next/static/chunks/app/api/onboarding/route-8805a20e15762c3c.js +1 -0
  281. package/dist/web/standalone/.next/static/chunks/app/api/preferences/route-8805a20e15762c3c.js +1 -0
  282. package/dist/web/standalone/.next/static/chunks/app/api/projects/route-8805a20e15762c3c.js +1 -0
  283. package/dist/web/standalone/.next/static/chunks/app/api/recovery/route-8805a20e15762c3c.js +1 -0
  284. package/dist/web/standalone/.next/static/chunks/app/api/remote-questions/route-8805a20e15762c3c.js +1 -0
  285. package/dist/web/standalone/.next/static/chunks/app/api/session/browser/route-8805a20e15762c3c.js +1 -0
  286. package/dist/web/standalone/.next/static/chunks/app/api/session/command/route-8805a20e15762c3c.js +1 -0
  287. package/dist/web/standalone/.next/static/chunks/app/api/session/events/route-8805a20e15762c3c.js +1 -0
  288. package/dist/web/standalone/.next/static/chunks/app/api/session/manage/route-8805a20e15762c3c.js +1 -0
  289. package/dist/web/standalone/.next/static/chunks/app/api/settings-data/route-8805a20e15762c3c.js +1 -0
  290. package/dist/web/standalone/.next/static/chunks/app/api/shutdown/route-8805a20e15762c3c.js +1 -0
  291. package/dist/web/standalone/.next/static/chunks/app/api/skill-health/route-8805a20e15762c3c.js +1 -0
  292. package/dist/web/standalone/.next/static/chunks/app/api/steer/route-8805a20e15762c3c.js +1 -0
  293. package/dist/web/standalone/.next/static/chunks/app/api/switch-root/route-8805a20e15762c3c.js +1 -0
  294. package/dist/web/standalone/.next/static/chunks/app/api/terminal/input/route-8805a20e15762c3c.js +1 -0
  295. package/dist/web/standalone/.next/static/chunks/app/api/terminal/resize/route-8805a20e15762c3c.js +1 -0
  296. package/dist/web/standalone/.next/static/chunks/app/api/terminal/sessions/route-8805a20e15762c3c.js +1 -0
  297. package/dist/web/standalone/.next/static/chunks/app/api/terminal/stream/route-8805a20e15762c3c.js +1 -0
  298. package/dist/web/standalone/.next/static/chunks/app/api/terminal/upload/route-8805a20e15762c3c.js +1 -0
  299. package/dist/web/standalone/.next/static/chunks/app/api/undo/route-8805a20e15762c3c.js +1 -0
  300. package/dist/web/standalone/.next/static/chunks/app/api/update/route-8805a20e15762c3c.js +1 -0
  301. package/dist/web/standalone/.next/static/chunks/app/api/visualizer/route-8805a20e15762c3c.js +1 -0
  302. package/dist/web/standalone/.next/static/chunks/app/{layout-9ecfd95f343793f0.js → layout-a16c7a7ecdf0c2cf.js} +1 -1
  303. package/dist/web/standalone/.next/static/chunks/app/page-0c485498795110d6.js +1 -0
  304. package/dist/web/standalone/.next/static/chunks/main-app-fdab67f7802d7832.js +1 -0
  305. package/dist/web/standalone/.next/static/chunks/next/dist/client/components/builtin/app-error-8805a20e15762c3c.js +1 -0
  306. package/dist/web/standalone/.next/static/chunks/next/dist/client/components/builtin/forbidden-8805a20e15762c3c.js +1 -0
  307. package/dist/web/standalone/.next/static/chunks/next/dist/client/components/builtin/global-error-459824ffb8c323dd.js +1 -0
  308. package/dist/web/standalone/.next/static/chunks/next/dist/client/components/builtin/not-found-8805a20e15762c3c.js +1 -0
  309. package/dist/web/standalone/.next/static/chunks/next/dist/client/components/builtin/unauthorized-8805a20e15762c3c.js +1 -0
  310. package/dist/web/standalone/.next/static/ffabZXz8JdN3EzX9EKt-R/_buildManifest.js +1 -0
  311. package/dist/web/standalone/node_modules/node-pty/build/Makefile +2 -2
  312. package/dist/web/standalone/node_modules/node-pty/build/Release/pty.node +0 -0
  313. package/dist/web/standalone/node_modules/node-pty/build/pty.target.mk +14 -14
  314. package/dist/web/standalone/node_modules/node-pty/node-addon-api/node_addon_api.target.mk +14 -14
  315. package/dist/web/standalone/node_modules/node-pty/node-addon-api/node_addon_api_except.target.mk +14 -14
  316. package/dist/web/standalone/node_modules/node-pty/node-addon-api/node_addon_api_maybe.target.mk +14 -14
  317. package/dist/web/standalone/server.js +1 -1
  318. package/dist/welcome-screen.js +1 -1
  319. package/package.json +1 -1
  320. package/packages/pi-agent-core/dist/agent-loop.d.ts +8 -0
  321. package/packages/pi-agent-core/dist/agent-loop.d.ts.map +1 -1
  322. package/packages/pi-agent-core/dist/agent-loop.js +70 -3
  323. package/packages/pi-agent-core/dist/agent-loop.js.map +1 -1
  324. package/packages/pi-agent-core/src/agent-loop.test.ts +317 -5
  325. package/packages/pi-agent-core/src/agent-loop.ts +90 -6
  326. package/packages/pi-ai/dist/types.d.ts +16 -1
  327. package/packages/pi-ai/dist/types.d.ts.map +1 -1
  328. package/packages/pi-ai/dist/types.js.map +1 -1
  329. package/packages/pi-ai/src/types.ts +18 -1
  330. package/packages/pi-coding-agent/dist/core/agent-session-tool-refresh.test.d.ts +2 -0
  331. package/packages/pi-coding-agent/dist/core/agent-session-tool-refresh.test.d.ts.map +1 -0
  332. package/packages/pi-coding-agent/dist/core/agent-session-tool-refresh.test.js +38 -0
  333. package/packages/pi-coding-agent/dist/core/agent-session-tool-refresh.test.js.map +1 -0
  334. package/packages/pi-coding-agent/dist/core/agent-session.d.ts.map +1 -1
  335. package/packages/pi-coding-agent/dist/core/agent-session.js +11 -0
  336. package/packages/pi-coding-agent/dist/core/agent-session.js.map +1 -1
  337. package/packages/pi-coding-agent/dist/core/auth-storage.d.ts +9 -0
  338. package/packages/pi-coding-agent/dist/core/auth-storage.d.ts.map +1 -1
  339. package/packages/pi-coding-agent/dist/core/auth-storage.js +50 -1
  340. package/packages/pi-coding-agent/dist/core/auth-storage.js.map +1 -1
  341. package/packages/pi-coding-agent/dist/core/auth-storage.test.js +41 -0
  342. package/packages/pi-coding-agent/dist/core/auth-storage.test.js.map +1 -1
  343. package/packages/pi-coding-agent/dist/core/extensions/loader.d.ts +7 -0
  344. package/packages/pi-coding-agent/dist/core/extensions/loader.d.ts.map +1 -1
  345. package/packages/pi-coding-agent/dist/core/extensions/loader.js +31 -4
  346. package/packages/pi-coding-agent/dist/core/extensions/loader.js.map +1 -1
  347. package/packages/pi-coding-agent/dist/core/extensions/loader.test.js +28 -1
  348. package/packages/pi-coding-agent/dist/core/extensions/loader.test.js.map +1 -1
  349. package/packages/pi-coding-agent/dist/core/extensions/provider-registration.test.d.ts +2 -0
  350. package/packages/pi-coding-agent/dist/core/extensions/provider-registration.test.d.ts.map +1 -0
  351. package/packages/pi-coding-agent/dist/core/extensions/provider-registration.test.js +46 -0
  352. package/packages/pi-coding-agent/dist/core/extensions/provider-registration.test.js.map +1 -0
  353. package/packages/pi-coding-agent/dist/core/extensions/types.d.ts +2 -0
  354. package/packages/pi-coding-agent/dist/core/extensions/types.d.ts.map +1 -1
  355. package/packages/pi-coding-agent/dist/core/extensions/types.js.map +1 -1
  356. package/packages/pi-coding-agent/dist/core/model-registry.d.ts +1 -0
  357. package/packages/pi-coding-agent/dist/core/model-registry.d.ts.map +1 -1
  358. package/packages/pi-coding-agent/dist/core/model-registry.js +12 -0
  359. package/packages/pi-coding-agent/dist/core/model-registry.js.map +1 -1
  360. package/packages/pi-coding-agent/dist/core/model-resolver.js +3 -3
  361. package/packages/pi-coding-agent/dist/core/model-resolver.js.map +1 -1
  362. package/packages/pi-coding-agent/dist/core/resource-loader-cache-reset.test.d.ts +2 -0
  363. package/packages/pi-coding-agent/dist/core/resource-loader-cache-reset.test.d.ts.map +1 -0
  364. package/packages/pi-coding-agent/dist/core/resource-loader-cache-reset.test.js +24 -0
  365. package/packages/pi-coding-agent/dist/core/resource-loader-cache-reset.test.js.map +1 -0
  366. package/packages/pi-coding-agent/dist/core/resource-loader.d.ts +23 -1
  367. package/packages/pi-coding-agent/dist/core/resource-loader.d.ts.map +1 -1
  368. package/packages/pi-coding-agent/dist/core/resource-loader.js +84 -57
  369. package/packages/pi-coding-agent/dist/core/resource-loader.js.map +1 -1
  370. package/packages/pi-coding-agent/dist/core/sdk.d.ts.map +1 -1
  371. package/packages/pi-coding-agent/dist/core/sdk.js +9 -0
  372. package/packages/pi-coding-agent/dist/core/sdk.js.map +1 -1
  373. package/packages/pi-coding-agent/package.json +1 -1
  374. package/packages/pi-coding-agent/src/core/agent-session-tool-refresh.test.ts +64 -0
  375. package/packages/pi-coding-agent/src/core/agent-session.ts +10 -0
  376. package/packages/pi-coding-agent/src/core/auth-storage.test.ts +53 -0
  377. package/packages/pi-coding-agent/src/core/auth-storage.ts +66 -1
  378. package/packages/pi-coding-agent/src/core/extensions/loader.test.ts +39 -1
  379. package/packages/pi-coding-agent/src/core/extensions/loader.ts +34 -4
  380. package/packages/pi-coding-agent/src/core/extensions/provider-registration.test.ts +81 -0
  381. package/packages/pi-coding-agent/src/core/extensions/types.ts +2 -0
  382. package/packages/pi-coding-agent/src/core/model-registry.ts +14 -0
  383. package/packages/pi-coding-agent/src/core/model-resolver.ts +3 -3
  384. package/packages/pi-coding-agent/src/core/resource-loader-cache-reset.test.ts +42 -0
  385. package/packages/pi-coding-agent/src/core/resource-loader.ts +94 -57
  386. package/packages/pi-coding-agent/src/core/sdk.ts +10 -0
  387. package/pkg/package.json +1 -1
  388. package/src/resources/extensions/cmux/index.ts +18 -12
  389. package/src/resources/extensions/gsd/auto/detect-stuck.ts +27 -0
  390. package/src/resources/extensions/gsd/auto/finalize-timeout.ts +46 -0
  391. package/src/resources/extensions/gsd/auto/loop.ts +5 -0
  392. package/src/resources/extensions/gsd/auto/phases.ts +194 -33
  393. package/src/resources/extensions/gsd/auto/session.ts +14 -0
  394. package/src/resources/extensions/gsd/auto-dashboard.ts +16 -7
  395. package/src/resources/extensions/gsd/auto-model-selection.ts +36 -0
  396. package/src/resources/extensions/gsd/auto-post-unit.ts +263 -12
  397. package/src/resources/extensions/gsd/auto-prompts.ts +21 -0
  398. package/src/resources/extensions/gsd/auto-recovery.ts +9 -8
  399. package/src/resources/extensions/gsd/auto-start.ts +11 -20
  400. package/src/resources/extensions/gsd/auto-timers.ts +2 -1
  401. package/src/resources/extensions/gsd/auto-tool-tracking.ts +19 -0
  402. package/src/resources/extensions/gsd/auto-verification.ts +190 -2
  403. package/src/resources/extensions/gsd/auto-worktree.ts +14 -6
  404. package/src/resources/extensions/gsd/auto.ts +26 -1
  405. package/src/resources/extensions/gsd/bootstrap/db-tools.ts +160 -88
  406. package/src/resources/extensions/gsd/bootstrap/dynamic-tools.ts +15 -0
  407. package/src/resources/extensions/gsd/bootstrap/notify-interceptor.ts +34 -0
  408. package/src/resources/extensions/gsd/bootstrap/query-tools.ts +98 -0
  409. package/src/resources/extensions/gsd/bootstrap/register-extension.ts +4 -0
  410. package/src/resources/extensions/gsd/bootstrap/register-hooks.ts +44 -1
  411. package/src/resources/extensions/gsd/bootstrap/register-shortcuts.ts +19 -0
  412. package/src/resources/extensions/gsd/bootstrap/sanitize-complete-milestone.ts +57 -0
  413. package/src/resources/extensions/gsd/bootstrap/system-context.ts +59 -2
  414. package/src/resources/extensions/gsd/commands/catalog.ts +7 -1
  415. package/src/resources/extensions/gsd/commands/handlers/core.ts +1 -0
  416. package/src/resources/extensions/gsd/commands/handlers/notifications-handler.ts +139 -0
  417. package/src/resources/extensions/gsd/commands/handlers/ops.ts +5 -0
  418. package/src/resources/extensions/gsd/commands-handlers.ts +10 -4
  419. package/src/resources/extensions/gsd/constants.ts +44 -0
  420. package/src/resources/extensions/gsd/db-writer.ts +78 -4
  421. package/src/resources/extensions/gsd/forensics.ts +21 -5
  422. package/src/resources/extensions/gsd/gsd-db.ts +64 -17
  423. package/src/resources/extensions/gsd/guided-flow.ts +22 -0
  424. package/src/resources/extensions/gsd/metrics.ts +28 -1
  425. package/src/resources/extensions/gsd/native-git-bridge.ts +5 -3
  426. package/src/resources/extensions/gsd/notification-overlay.ts +267 -0
  427. package/src/resources/extensions/gsd/notification-store.ts +288 -0
  428. package/src/resources/extensions/gsd/notification-widget.ts +68 -0
  429. package/src/resources/extensions/gsd/post-execution-checks.ts +539 -0
  430. package/src/resources/extensions/gsd/pre-execution-checks.ts +573 -0
  431. package/src/resources/extensions/gsd/preferences-types.ts +44 -0
  432. package/src/resources/extensions/gsd/preferences-validation.ts +33 -0
  433. package/src/resources/extensions/gsd/preferences.ts +13 -2
  434. package/src/resources/extensions/gsd/prompt-loader.ts +8 -0
  435. package/src/resources/extensions/gsd/prompts/complete-milestone.md +2 -0
  436. package/src/resources/extensions/gsd/prompts/complete-slice.md +2 -0
  437. package/src/resources/extensions/gsd/prompts/doctor-heal.md +1 -0
  438. package/src/resources/extensions/gsd/prompts/forensics.md +2 -0
  439. package/src/resources/extensions/gsd/prompts/reassess-roadmap.md +2 -0
  440. package/src/resources/extensions/gsd/prompts/system.md +4 -7
  441. package/src/resources/extensions/gsd/prompts/validate-milestone.md +2 -0
  442. package/src/resources/extensions/gsd/roadmap-mutations.ts +1 -1
  443. package/src/resources/extensions/gsd/roadmap-slices.ts +10 -5
  444. package/src/resources/extensions/gsd/safety/content-validator.ts +98 -0
  445. package/src/resources/extensions/gsd/safety/destructive-guard.ts +49 -0
  446. package/src/resources/extensions/gsd/safety/evidence-collector.ts +151 -0
  447. package/src/resources/extensions/gsd/safety/evidence-cross-ref.ts +120 -0
  448. package/src/resources/extensions/gsd/safety/file-change-validator.ts +108 -0
  449. package/src/resources/extensions/gsd/safety/git-checkpoint.ts +106 -0
  450. package/src/resources/extensions/gsd/safety/safety-harness.ts +105 -0
  451. package/src/resources/extensions/gsd/slice-parallel-conflict.ts +86 -0
  452. package/src/resources/extensions/gsd/slice-parallel-eligibility.ts +73 -0
  453. package/src/resources/extensions/gsd/slice-parallel-orchestrator.ts +477 -0
  454. package/src/resources/extensions/gsd/state.ts +67 -12
  455. package/src/resources/extensions/gsd/status-guards.ts +13 -0
  456. package/src/resources/extensions/gsd/tests/artifact-corruption-2630.test.ts +288 -0
  457. package/src/resources/extensions/gsd/tests/auto-loop.test.ts +34 -13
  458. package/src/resources/extensions/gsd/tests/auto-start-time-persistence.test.ts +50 -0
  459. package/src/resources/extensions/gsd/tests/cmux.test.ts +58 -0
  460. package/src/resources/extensions/gsd/tests/cold-resume-db-reopen.test.ts +51 -0
  461. package/src/resources/extensions/gsd/tests/complete-milestone.test.ts +140 -0
  462. package/src/resources/extensions/gsd/tests/complete-slice-string-coercion.test.ts +211 -0
  463. package/src/resources/extensions/gsd/tests/complete-task.test.ts +39 -0
  464. package/src/resources/extensions/gsd/tests/dashboard-model-label-ordering.test.ts +107 -0
  465. package/src/resources/extensions/gsd/tests/db-access-guardrails.test.ts +109 -0
  466. package/src/resources/extensions/gsd/tests/db-path-worktree-symlink.test.ts +13 -9
  467. package/src/resources/extensions/gsd/tests/db-writer.test.ts +134 -0
  468. package/src/resources/extensions/gsd/tests/deferred-slice-dispatch.test.ts +203 -0
  469. package/src/resources/extensions/gsd/tests/discuss-tool-scope-leak.test.ts +76 -0
  470. package/src/resources/extensions/gsd/tests/discuss-tool-scoping.test.ts +130 -0
  471. package/src/resources/extensions/gsd/tests/doctor-fix-flag.test.ts +92 -0
  472. package/src/resources/extensions/gsd/tests/enhanced-verification-integration.test.ts +526 -0
  473. package/src/resources/extensions/gsd/tests/finalize-timeout-guard.test.ts +116 -0
  474. package/src/resources/extensions/gsd/tests/flat-rate-routing-guard.test.ts +50 -0
  475. package/src/resources/extensions/gsd/tests/forensics-stuck-loops.test.ts +103 -0
  476. package/src/resources/extensions/gsd/tests/git-checkpoint.test.ts +94 -0
  477. package/src/resources/extensions/gsd/tests/insert-slice-no-wipe.test.ts +88 -0
  478. package/src/resources/extensions/gsd/tests/integration/git-service.test.ts +27 -7
  479. package/src/resources/extensions/gsd/tests/integration/idle-recovery.test.ts +34 -0
  480. package/src/resources/extensions/gsd/tests/metrics.test.ts +116 -1
  481. package/src/resources/extensions/gsd/tests/milestone-status-tool.test.ts +201 -0
  482. package/src/resources/extensions/gsd/tests/notification-store.test.ts +249 -0
  483. package/src/resources/extensions/gsd/tests/plan-milestone-title.test.ts +2 -1
  484. package/src/resources/extensions/gsd/tests/plan-milestone.test.ts +82 -18
  485. package/src/resources/extensions/gsd/tests/post-exec-retry-bypass.test.ts +312 -0
  486. package/src/resources/extensions/gsd/tests/post-execution-checks.test.ts +813 -0
  487. package/src/resources/extensions/gsd/tests/pre-execution-checks.test.ts +999 -0
  488. package/src/resources/extensions/gsd/tests/pre-execution-fail-closed.test.ts +266 -0
  489. package/src/resources/extensions/gsd/tests/pre-execution-pause-wiring.test.ts +457 -0
  490. package/src/resources/extensions/gsd/tests/preferences.test.ts +10 -0
  491. package/src/resources/extensions/gsd/tests/prompt-contracts.test.ts +25 -0
  492. package/src/resources/extensions/gsd/tests/roadmap-slices.test.ts +69 -0
  493. package/src/resources/extensions/gsd/tests/shared-wal.test.ts +30 -0
  494. package/src/resources/extensions/gsd/tests/slice-context-injection.test.ts +50 -0
  495. package/src/resources/extensions/gsd/tests/slice-parallel-conflict.test.ts +92 -0
  496. package/src/resources/extensions/gsd/tests/slice-parallel-eligibility.test.ts +95 -0
  497. package/src/resources/extensions/gsd/tests/slice-parallel-orchestrator.test.ts +83 -0
  498. package/src/resources/extensions/gsd/tests/stuck-detection-coverage.test.ts +42 -0
  499. package/src/resources/extensions/gsd/tests/tool-invocation-error-loop-break.test.ts +103 -0
  500. package/src/resources/extensions/gsd/tests/tool-param-optionality.test.ts +349 -0
  501. package/src/resources/extensions/gsd/tests/unstructured-continue-context-injection.test.ts +163 -0
  502. package/src/resources/extensions/gsd/tests/worktree-health-dispatch.test.ts +35 -2
  503. package/src/resources/extensions/gsd/tests/worktree-health-monorepo.test.ts +73 -0
  504. package/src/resources/extensions/gsd/tests/worktree-resolver.test.ts +34 -0
  505. package/src/resources/extensions/gsd/tests/worktree-submodule-safety.test.ts +1 -1
  506. package/src/resources/extensions/gsd/tests/worktree-teardown-safety.test.ts +148 -0
  507. package/src/resources/extensions/gsd/tools/complete-milestone.ts +34 -20
  508. package/src/resources/extensions/gsd/tools/complete-slice.ts +41 -26
  509. package/src/resources/extensions/gsd/tools/complete-task.ts +12 -12
  510. package/src/resources/extensions/gsd/tools/plan-milestone.ts +55 -30
  511. package/src/resources/extensions/gsd/tools/plan-slice.ts +13 -8
  512. package/src/resources/extensions/gsd/types.ts +44 -22
  513. package/src/resources/extensions/gsd/verification-evidence.ts +68 -0
  514. package/src/resources/extensions/gsd/workflow-logger.ts +15 -1
  515. package/src/resources/extensions/gsd/workflow-projections.ts +23 -5
  516. package/src/resources/extensions/gsd/worktree-manager.ts +76 -28
  517. package/src/resources/extensions/gsd/worktree-resolver.ts +4 -3
  518. package/src/resources/extensions/mcp-client/auth.ts +149 -0
  519. package/src/resources/extensions/mcp-client/index.ts +16 -1
  520. package/src/resources/extensions/ollama/index.ts +26 -25
  521. package/src/resources/extensions/ollama/model-capabilities.ts +41 -34
  522. package/src/resources/extensions/ollama/ndjson-stream.ts +63 -0
  523. package/src/resources/extensions/ollama/ollama-auth-mode.test.ts +20 -0
  524. package/src/resources/extensions/ollama/ollama-chat-provider.ts +459 -0
  525. package/src/resources/extensions/ollama/ollama-client.ts +30 -30
  526. package/src/resources/extensions/ollama/ollama-discovery.ts +5 -8
  527. package/src/resources/extensions/ollama/ollama-tool.ts +69 -0
  528. package/src/resources/extensions/ollama/tests/ollama-chat-provider-stream.test.ts +82 -0
  529. package/src/resources/extensions/ollama/tests/ollama-discovery.test.ts +0 -27
  530. package/src/resources/extensions/ollama/thinking-parser.ts +116 -0
  531. package/src/resources/extensions/ollama/types.ts +23 -0
  532. package/dist/web/standalone/.next/server/chunks/2229.js +0 -12
  533. package/dist/web/standalone/.next/static/5FLUBNdqolRyyehCyChPd/_buildManifest.js +0 -1
  534. package/dist/web/standalone/.next/static/chunks/app/_global-error/page-c4cc189e7b117ea2.js +0 -1
  535. package/dist/web/standalone/.next/static/chunks/app/api/boot/route-c4cc189e7b117ea2.js +0 -1
  536. package/dist/web/standalone/.next/static/chunks/app/api/bridge-terminal/input/route-c4cc189e7b117ea2.js +0 -1
  537. package/dist/web/standalone/.next/static/chunks/app/api/bridge-terminal/resize/route-c4cc189e7b117ea2.js +0 -1
  538. package/dist/web/standalone/.next/static/chunks/app/api/bridge-terminal/stream/route-c4cc189e7b117ea2.js +0 -1
  539. package/dist/web/standalone/.next/static/chunks/app/api/browse-directories/route-c4cc189e7b117ea2.js +0 -1
  540. package/dist/web/standalone/.next/static/chunks/app/api/captures/route-c4cc189e7b117ea2.js +0 -1
  541. package/dist/web/standalone/.next/static/chunks/app/api/cleanup/route-c4cc189e7b117ea2.js +0 -1
  542. package/dist/web/standalone/.next/static/chunks/app/api/dev-mode/route-c4cc189e7b117ea2.js +0 -1
  543. package/dist/web/standalone/.next/static/chunks/app/api/doctor/route-c4cc189e7b117ea2.js +0 -1
  544. package/dist/web/standalone/.next/static/chunks/app/api/experimental/route-c4cc189e7b117ea2.js +0 -1
  545. package/dist/web/standalone/.next/static/chunks/app/api/export-data/route-c4cc189e7b117ea2.js +0 -1
  546. package/dist/web/standalone/.next/static/chunks/app/api/files/route-c4cc189e7b117ea2.js +0 -1
  547. package/dist/web/standalone/.next/static/chunks/app/api/forensics/route-c4cc189e7b117ea2.js +0 -1
  548. package/dist/web/standalone/.next/static/chunks/app/api/git/route-c4cc189e7b117ea2.js +0 -1
  549. package/dist/web/standalone/.next/static/chunks/app/api/history/route-c4cc189e7b117ea2.js +0 -1
  550. package/dist/web/standalone/.next/static/chunks/app/api/hooks/route-c4cc189e7b117ea2.js +0 -1
  551. package/dist/web/standalone/.next/static/chunks/app/api/inspect/route-c4cc189e7b117ea2.js +0 -1
  552. package/dist/web/standalone/.next/static/chunks/app/api/knowledge/route-c4cc189e7b117ea2.js +0 -1
  553. package/dist/web/standalone/.next/static/chunks/app/api/live-state/route-c4cc189e7b117ea2.js +0 -1
  554. package/dist/web/standalone/.next/static/chunks/app/api/onboarding/route-c4cc189e7b117ea2.js +0 -1
  555. package/dist/web/standalone/.next/static/chunks/app/api/preferences/route-c4cc189e7b117ea2.js +0 -1
  556. package/dist/web/standalone/.next/static/chunks/app/api/projects/route-c4cc189e7b117ea2.js +0 -1
  557. package/dist/web/standalone/.next/static/chunks/app/api/recovery/route-c4cc189e7b117ea2.js +0 -1
  558. package/dist/web/standalone/.next/static/chunks/app/api/remote-questions/route-c4cc189e7b117ea2.js +0 -1
  559. package/dist/web/standalone/.next/static/chunks/app/api/session/browser/route-c4cc189e7b117ea2.js +0 -1
  560. package/dist/web/standalone/.next/static/chunks/app/api/session/command/route-c4cc189e7b117ea2.js +0 -1
  561. package/dist/web/standalone/.next/static/chunks/app/api/session/events/route-c4cc189e7b117ea2.js +0 -1
  562. package/dist/web/standalone/.next/static/chunks/app/api/session/manage/route-c4cc189e7b117ea2.js +0 -1
  563. package/dist/web/standalone/.next/static/chunks/app/api/settings-data/route-c4cc189e7b117ea2.js +0 -1
  564. package/dist/web/standalone/.next/static/chunks/app/api/shutdown/route-c4cc189e7b117ea2.js +0 -1
  565. package/dist/web/standalone/.next/static/chunks/app/api/skill-health/route-c4cc189e7b117ea2.js +0 -1
  566. package/dist/web/standalone/.next/static/chunks/app/api/steer/route-c4cc189e7b117ea2.js +0 -1
  567. package/dist/web/standalone/.next/static/chunks/app/api/switch-root/route-c4cc189e7b117ea2.js +0 -1
  568. package/dist/web/standalone/.next/static/chunks/app/api/terminal/input/route-c4cc189e7b117ea2.js +0 -1
  569. package/dist/web/standalone/.next/static/chunks/app/api/terminal/resize/route-c4cc189e7b117ea2.js +0 -1
  570. package/dist/web/standalone/.next/static/chunks/app/api/terminal/sessions/route-c4cc189e7b117ea2.js +0 -1
  571. package/dist/web/standalone/.next/static/chunks/app/api/terminal/stream/route-c4cc189e7b117ea2.js +0 -1
  572. package/dist/web/standalone/.next/static/chunks/app/api/terminal/upload/route-c4cc189e7b117ea2.js +0 -1
  573. package/dist/web/standalone/.next/static/chunks/app/api/undo/route-c4cc189e7b117ea2.js +0 -1
  574. package/dist/web/standalone/.next/static/chunks/app/api/update/route-c4cc189e7b117ea2.js +0 -1
  575. package/dist/web/standalone/.next/static/chunks/app/api/visualizer/route-c4cc189e7b117ea2.js +0 -1
  576. package/dist/web/standalone/.next/static/chunks/app/page-62be3b5fa91e4c8f.js +0 -1
  577. package/dist/web/standalone/.next/static/chunks/main-app-d3d4c336195465f9.js +0 -1
  578. package/dist/web/standalone/.next/static/chunks/next/dist/client/components/builtin/app-error-c4cc189e7b117ea2.js +0 -1
  579. package/dist/web/standalone/.next/static/chunks/next/dist/client/components/builtin/forbidden-c4cc189e7b117ea2.js +0 -1
  580. package/dist/web/standalone/.next/static/chunks/next/dist/client/components/builtin/global-error-ab5a8926e07ec673.js +0 -1
  581. package/dist/web/standalone/.next/static/chunks/next/dist/client/components/builtin/not-found-c4cc189e7b117ea2.js +0 -1
  582. package/dist/web/standalone/.next/static/chunks/next/dist/client/components/builtin/unauthorized-c4cc189e7b117ea2.js +0 -1
  583. /package/dist/web/standalone/.next/static/{5FLUBNdqolRyyehCyChPd → ffabZXz8JdN3EzX9EKt-R}/_ssgManifest.js +0 -0
@@ -402,6 +402,23 @@ export async function saveDecisionToDb(fields, basePath) {
402
402
  adapter?.prepare('DELETE FROM decisions WHERE id = :id').run({ ':id': id });
403
403
  throw diskErr;
404
404
  }
405
+ // #2661: When a decision defers a slice, update the slice status in the DB
406
+ // so the dispatcher skips it. Without this, STATE.md and DECISIONS.md are
407
+ // in split-brain: the decision says "deferred" but the state still says
408
+ // "active", causing auto-mode to keep dispatching the deferred work.
409
+ try {
410
+ const sliceRef = extractDeferredSliceRef(fields);
411
+ if (sliceRef) {
412
+ db.updateSliceStatus(sliceRef.milestoneId, sliceRef.sliceId, 'deferred');
413
+ }
414
+ }
415
+ catch (deferErr) {
416
+ // Non-fatal — log but don't fail the decision save
417
+ logError('manifest', 'failed to update deferred slice status', {
418
+ fn: 'saveDecisionToDb',
419
+ error: String(deferErr.message),
420
+ });
421
+ }
405
422
  // Invalidate file-read caches so deriveState() sees the updated markdown.
406
423
  // Do NOT clear the artifacts table — we just wrote to it intentionally.
407
424
  invalidateStateCache();
@@ -414,6 +431,33 @@ export async function saveDecisionToDb(fields, basePath) {
414
431
  throw err;
415
432
  }
416
433
  }
434
+ /**
435
+ * Extract a milestone/slice reference from a deferral decision.
436
+ *
437
+ * Detects deferrals by checking:
438
+ * - scope contains "defer" (e.g., "deferral", "defer")
439
+ * - choice or decision contains "defer" + an M###/S## pattern
440
+ *
441
+ * Returns { milestoneId, sliceId } if found, null otherwise.
442
+ */
443
+ export function extractDeferredSliceRef(fields) {
444
+ const isDeferral = /\bdefer(?:ral|red|ring|s)?\b/i.test(fields.scope) ||
445
+ /\bdefer(?:ral|red|ring|s)?\b/i.test(fields.choice) ||
446
+ /\bdefer(?:ral|red|ring|s)?\b/i.test(fields.decision);
447
+ if (!isDeferral)
448
+ return null;
449
+ // Look for M###/S## pattern in choice first, then decision
450
+ const slicePattern = /\b(M\d{3,4})\/(S\d{2,3})\b/;
451
+ const choiceMatch = fields.choice.match(slicePattern);
452
+ if (choiceMatch) {
453
+ return { milestoneId: choiceMatch[1], sliceId: choiceMatch[2] };
454
+ }
455
+ const decisionMatch = fields.decision.match(slicePattern);
456
+ if (decisionMatch) {
457
+ return { milestoneId: decisionMatch[1], sliceId: decisionMatch[2] };
458
+ }
459
+ return null;
460
+ }
417
461
  // ─── Update Requirement in DB + Regenerate Markdown ───────────────────────
418
462
  /**
419
463
  * Update a requirement in DB and regenerate REQUIREMENTS.md.
@@ -422,10 +466,34 @@ export async function saveDecisionToDb(fields, basePath) {
422
466
  export async function updateRequirementInDb(id, updates, basePath) {
423
467
  try {
424
468
  const db = await import('./gsd-db.js');
425
- const existing = db.getRequirementById(id);
426
- // If requirement doesn't exist in DB, create a skeleton and merge updates.
427
- // This handles the case where requirements were written to REQUIREMENTS.md
428
- // but never imported into the database (see #2919).
469
+ let existing = db.getRequirementById(id);
470
+ // If requirement doesn't exist in DB, seed the entire requirements table
471
+ // from REQUIREMENTS.md first (#3346). This handles the standard workflow
472
+ // where requirements are authored in markdown during discussion but never
473
+ // imported into the database — making gsd_requirement_update always fail
474
+ // with "not_found" at milestone completion.
475
+ if (!existing) {
476
+ const reqFilePath = resolveGsdRootFile(basePath, 'REQUIREMENTS');
477
+ try {
478
+ const content = readFileSync(reqFilePath, 'utf-8');
479
+ const { parseRequirementsSections } = await import('./md-importer.js');
480
+ const parsed = parseRequirementsSections(content);
481
+ if (parsed.length > 0) {
482
+ logWarning('manifest', `Seeding ${parsed.length} requirements from REQUIREMENTS.md into DB (first update triggers import)`, { fn: 'updateRequirementInDb' });
483
+ for (const req of parsed) {
484
+ // Only seed if not already in DB (avoid overwriting concurrent inserts)
485
+ if (!db.getRequirementById(req.id)) {
486
+ db.upsertRequirement(req);
487
+ }
488
+ }
489
+ // Re-check after seeding
490
+ existing = db.getRequirementById(id);
491
+ }
492
+ }
493
+ catch {
494
+ // REQUIREMENTS.md missing or unparseable — fall through to skeleton
495
+ }
496
+ }
429
497
  const base = existing ?? {
430
498
  id,
431
499
  class: '',
@@ -498,13 +498,29 @@ function getDbCompletionCounts() {
498
498
  };
499
499
  }
500
500
  // ─── Anomaly Detectors ───────────────────────────────────────────────────────
501
- function detectStuckLoops(units, anomalies) {
502
- const counts = new Map();
501
+ /**
502
+ * Detect units that were dispatched multiple times (stuck in a loop).
503
+ *
504
+ * Counts distinct dispatches by grouping on (type, id, startedAt) first to
505
+ * collapse idle-watchdog duplicate snapshots (#1943), then counts unique
506
+ * startedAt values per type/id to determine actual dispatch count.
507
+ *
508
+ * Exported for testability.
509
+ */
510
+ export function detectStuckLoops(units, anomalies) {
511
+ // First, collect unique startedAt values per type/id key
512
+ const dispatchMap = new Map();
503
513
  for (const u of units) {
504
514
  const key = `${u.type}/${u.id}`;
505
- counts.set(key, (counts.get(key) ?? 0) + 1);
515
+ let starts = dispatchMap.get(key);
516
+ if (!starts) {
517
+ starts = new Set();
518
+ dispatchMap.set(key, starts);
519
+ }
520
+ starts.add(u.startedAt);
506
521
  }
507
- for (const [key, count] of counts) {
522
+ for (const [key, starts] of dispatchMap) {
523
+ const count = starts.size;
508
524
  if (count > 1) {
509
525
  const [unitType, ...idParts] = key.split("/");
510
526
  anomalies.push({
@@ -1023,11 +1023,12 @@ export function insertMilestone(m) {
1023
1023
  ":boundary_map_markdown": m.planning?.boundaryMapMarkdown ?? "",
1024
1024
  });
1025
1025
  }
1026
- export function upsertMilestonePlanning(milestoneId, planning, title) {
1026
+ export function upsertMilestonePlanning(milestoneId, planning) {
1027
1027
  if (!currentDb)
1028
1028
  throw new GSDError(GSD_STALE_STATE, "gsd-db: No database open");
1029
1029
  currentDb.prepare(`UPDATE milestones SET
1030
- title = COALESCE(:title, title),
1030
+ title = COALESCE(NULLIF(:title, ''), title),
1031
+ status = COALESCE(NULLIF(:status, ''), status),
1031
1032
  vision = COALESCE(:vision, vision),
1032
1033
  success_criteria = COALESCE(:success_criteria, success_criteria),
1033
1034
  key_risks = COALESCE(:key_risks, key_risks),
@@ -1041,7 +1042,8 @@ export function upsertMilestonePlanning(milestoneId, planning, title) {
1041
1042
  boundary_map_markdown = COALESCE(:boundary_map_markdown, boundary_map_markdown)
1042
1043
  WHERE id = :id`).run({
1043
1044
  ":id": milestoneId,
1044
- ":title": title ?? null,
1045
+ ":title": planning.title ?? "",
1046
+ ":status": planning.status ?? "",
1045
1047
  ":vision": planning.vision ?? null,
1046
1048
  ":success_criteria": planning.successCriteria ? JSON.stringify(planning.successCriteria) : null,
1047
1049
  ":key_risks": planning.keyRisks ? JSON.stringify(planning.keyRisks) : null,
@@ -1058,13 +1060,25 @@ export function upsertMilestonePlanning(milestoneId, planning, title) {
1058
1060
  export function insertSlice(s) {
1059
1061
  if (!currentDb)
1060
1062
  throw new GSDError(GSD_STALE_STATE, "gsd-db: No database open");
1061
- currentDb.prepare(`INSERT OR IGNORE INTO slices (
1063
+ currentDb.prepare(`INSERT INTO slices (
1062
1064
  milestone_id, id, title, status, risk, depends, demo, created_at,
1063
1065
  goal, success_criteria, proof_level, integration_closure, observability_impact, sequence
1064
1066
  ) VALUES (
1065
1067
  :milestone_id, :id, :title, :status, :risk, :depends, :demo, :created_at,
1066
1068
  :goal, :success_criteria, :proof_level, :integration_closure, :observability_impact, :sequence
1067
- )`).run({
1069
+ )
1070
+ ON CONFLICT (milestone_id, id) DO UPDATE SET
1071
+ title = CASE WHEN :raw_title IS NOT NULL THEN excluded.title ELSE slices.title END,
1072
+ status = CASE WHEN slices.status IN ('complete', 'done') THEN slices.status ELSE excluded.status END,
1073
+ risk = CASE WHEN :raw_risk IS NOT NULL THEN excluded.risk ELSE slices.risk END,
1074
+ depends = excluded.depends,
1075
+ demo = CASE WHEN :raw_demo IS NOT NULL THEN excluded.demo ELSE slices.demo END,
1076
+ goal = CASE WHEN :raw_goal IS NOT NULL THEN excluded.goal ELSE slices.goal END,
1077
+ success_criteria = CASE WHEN :raw_success_criteria IS NOT NULL THEN excluded.success_criteria ELSE slices.success_criteria END,
1078
+ proof_level = CASE WHEN :raw_proof_level IS NOT NULL THEN excluded.proof_level ELSE slices.proof_level END,
1079
+ integration_closure = CASE WHEN :raw_integration_closure IS NOT NULL THEN excluded.integration_closure ELSE slices.integration_closure END,
1080
+ observability_impact = CASE WHEN :raw_observability_impact IS NOT NULL THEN excluded.observability_impact ELSE slices.observability_impact END,
1081
+ sequence = CASE WHEN :raw_sequence IS NOT NULL THEN excluded.sequence ELSE slices.sequence END`).run({
1068
1082
  ":milestone_id": s.milestoneId,
1069
1083
  ":id": s.id,
1070
1084
  ":title": s.title ?? "",
@@ -1079,6 +1093,16 @@ export function insertSlice(s) {
1079
1093
  ":integration_closure": s.planning?.integrationClosure ?? "",
1080
1094
  ":observability_impact": s.planning?.observabilityImpact ?? "",
1081
1095
  ":sequence": s.sequence ?? 0,
1096
+ // Raw sentinel params: NULL when caller omitted the field, used in ON CONFLICT guards
1097
+ ":raw_title": s.title ?? null,
1098
+ ":raw_risk": s.risk ?? null,
1099
+ ":raw_demo": s.demo ?? null,
1100
+ ":raw_goal": s.planning?.goal ?? null,
1101
+ ":raw_success_criteria": s.planning?.successCriteria ?? null,
1102
+ ":raw_proof_level": s.planning?.proofLevel ?? null,
1103
+ ":raw_integration_closure": s.planning?.integrationClosure ?? null,
1104
+ ":raw_observability_impact": s.planning?.observabilityImpact ?? null,
1105
+ ":raw_sequence": s.sequence ?? null,
1082
1106
  });
1083
1107
  }
1084
1108
  export function upsertSlicePlanning(milestoneId, sliceId, planning) {
@@ -1574,19 +1598,31 @@ export function reconcileWorktreeDb(mainDbPath, worktreeDbPath) {
1574
1598
  definition_of_done, requirement_coverage, boundary_map_markdown
1575
1599
  FROM wt.milestones
1576
1600
  `).run());
1577
- // Merge slices — preserve worktree progress (status, summaries, planning)
1601
+ // Merge slices — preserve worktree progress but never downgrade completed status (#2558).
1602
+ // Uses INSERT OR REPLACE with a subquery that picks the best status — if the main DB
1603
+ // already has a completed slice, keep that status even if the worktree copy is stale.
1578
1604
  merged.slices = countChanges(adapter.prepare(`
1579
1605
  INSERT OR REPLACE INTO slices (
1580
1606
  milestone_id, id, title, status, risk, depends, demo, created_at, completed_at,
1581
1607
  full_summary_md, full_uat_md, goal, success_criteria, proof_level,
1582
1608
  integration_closure, observability_impact, sequence, replan_triggered_at
1583
1609
  )
1584
- SELECT milestone_id, id, title, status, risk, depends, demo, created_at, completed_at,
1585
- full_summary_md, full_uat_md, goal, success_criteria, proof_level,
1586
- integration_closure, observability_impact, sequence, replan_triggered_at
1587
- FROM wt.slices
1610
+ SELECT w.milestone_id, w.id, w.title,
1611
+ CASE
1612
+ WHEN m.status IN ('complete', 'done') AND w.status NOT IN ('complete', 'done')
1613
+ THEN m.status ELSE w.status
1614
+ END,
1615
+ w.risk, w.depends, w.demo, w.created_at,
1616
+ CASE
1617
+ WHEN m.status IN ('complete', 'done') AND w.status NOT IN ('complete', 'done')
1618
+ THEN m.completed_at ELSE w.completed_at
1619
+ END,
1620
+ w.full_summary_md, w.full_uat_md, w.goal, w.success_criteria, w.proof_level,
1621
+ w.integration_closure, w.observability_impact, w.sequence, w.replan_triggered_at
1622
+ FROM wt.slices w
1623
+ LEFT JOIN slices m ON m.milestone_id = w.milestone_id AND m.id = w.id
1588
1624
  `).run());
1589
- // Merge tasks — preserve execution results, status, summaries
1625
+ // Merge tasks — preserve execution results, never downgrade completed status (#2558)
1590
1626
  merged.tasks = countChanges(adapter.prepare(`
1591
1627
  INSERT OR REPLACE INTO tasks (
1592
1628
  milestone_id, slice_id, id, title, status, one_liner, narrative,
@@ -1595,12 +1631,23 @@ export function reconcileWorktreeDb(mainDbPath, worktreeDbPath) {
1595
1631
  description, estimate, files, verify, inputs, expected_output,
1596
1632
  observability_impact, full_plan_md, sequence
1597
1633
  )
1598
- SELECT milestone_id, slice_id, id, title, status, one_liner, narrative,
1599
- verification_result, duration, completed_at, blocker_discovered,
1600
- deviations, known_issues, key_files, key_decisions, full_summary_md,
1601
- description, estimate, files, verify, inputs, expected_output,
1602
- observability_impact, full_plan_md, sequence
1603
- FROM wt.tasks
1634
+ SELECT w.milestone_id, w.slice_id, w.id, w.title,
1635
+ CASE
1636
+ WHEN m.status IN ('complete', 'done') AND w.status NOT IN ('complete', 'done')
1637
+ THEN m.status ELSE w.status
1638
+ END,
1639
+ w.one_liner, w.narrative,
1640
+ w.verification_result, w.duration,
1641
+ CASE
1642
+ WHEN m.status IN ('complete', 'done') AND w.status NOT IN ('complete', 'done')
1643
+ THEN m.completed_at ELSE w.completed_at
1644
+ END,
1645
+ w.blocker_discovered,
1646
+ w.deviations, w.known_issues, w.key_files, w.key_decisions, w.full_summary_md,
1647
+ w.description, w.estimate, w.files, w.verify, w.inputs, w.expected_output,
1648
+ w.observability_impact, w.full_plan_md, w.sequence
1649
+ FROM wt.tasks w
1650
+ LEFT JOIN tasks m ON m.milestone_id = w.milestone_id AND m.slice_id = w.slice_id AND m.id = w.id
1604
1651
  `).run());
1605
1652
  // Merge memories — keep worktree-learned insights
1606
1653
  merged.memories = countChanges(adapter.prepare(`
@@ -33,6 +33,7 @@ import { debugLog } from "./debug-logger.js";
33
33
  import { findMilestoneIds, nextMilestoneId, reserveMilestoneId, getReservedMilestoneIds, clearReservedMilestoneIds } from "./milestone-ids.js";
34
34
  import { parkMilestone, discardMilestone } from "./milestone-actions.js";
35
35
  import { selectAndApplyModel } from "./auto-model-selection.js";
36
+ import { DISCUSS_TOOLS_ALLOWLIST } from "./constants.js";
36
37
  // ─── Re-exports (preserve public API for existing importers) ────────────────
37
38
  export { MILESTONE_ID_RE, generateMilestoneSuffix, nextMilestoneId, extractMilestoneSeq, parseMilestoneId, milestoneIdSort, maxMilestoneNum, findMilestoneIds, reserveMilestoneId, claimReservedId, getReservedMilestoneIds, clearReservedMilestoneIds, } from "./milestone-ids.js";
38
39
  export { showQueue, handleQueueReorder, showQueueAdd, buildExistingMilestonesContext, } from "./guided-flow-queue.js";
@@ -242,6 +243,24 @@ async function dispatchWorkflow(pi, note, customType = "gsd-run", ctx, unitType)
242
243
  });
243
244
  }
244
245
  }
246
+ // Scope tools for discuss flows (#2949).
247
+ // Providers with grammar-based constrained decoding (xAI/Grok) return
248
+ // "Grammar is too complex" when the combined tool schema is too large.
249
+ // Discuss flows only need a small subset of GSD tools — strip the heavy
250
+ // planning/execution/completion tools to keep the grammar within limits.
251
+ if (unitType?.startsWith("discuss-")) {
252
+ const currentTools = pi.getActiveTools();
253
+ // Keep all non-GSD tools (builtins, other extensions) and only the
254
+ // GSD tools on the discuss allowlist.
255
+ const scopedTools = currentTools.filter((t) => !t.startsWith("gsd_") || DISCUSS_TOOLS_ALLOWLIST.includes(t));
256
+ pi.setActiveTools(scopedTools);
257
+ debugLog("discuss-tool-scoping", {
258
+ unitType,
259
+ before: currentTools.length,
260
+ after: scopedTools.length,
261
+ removed: currentTools.length - scopedTools.length,
262
+ });
263
+ }
245
264
  const workflowPath = process.env.GSD_WORKFLOW_PATH ?? join(process.env.HOME ?? "~", ".gsd", "agent", "GSD-WORKFLOW.md");
246
265
  const workflow = readFileSync(workflowPath, "utf-8");
247
266
  pi.sendMessage({
@@ -412,7 +412,33 @@ export function loadLedgerFromDisk(base) {
412
412
  return loadJsonFileOrNull(metricsPath(base), isMetricsLedger);
413
413
  }
414
414
  function loadLedger(base) {
415
- return loadJsonFile(metricsPath(base), isMetricsLedger, defaultLedger);
415
+ const raw = loadJsonFile(metricsPath(base), isMetricsLedger, defaultLedger);
416
+ const before = raw.units.length;
417
+ raw.units = deduplicateUnits(raw.units);
418
+ if (raw.units.length < before) {
419
+ // Persist the cleaned ledger so duplicates don't re-accumulate
420
+ saveLedger(base, raw);
421
+ }
422
+ return raw;
423
+ }
424
+ /**
425
+ * Collapse duplicate entries with the same (type, id, startedAt) triple.
426
+ * Keeps the entry with the highest finishedAt (the most complete snapshot).
427
+ *
428
+ * This is a defensive measure against idle-watchdog race conditions that can
429
+ * produce duplicate entries on disk despite the in-memory idempotency guard
430
+ * in snapshotUnitMetrics(). See #1943.
431
+ */
432
+ function deduplicateUnits(units) {
433
+ const map = new Map();
434
+ for (const u of units) {
435
+ const key = `${u.type}\0${u.id}\0${u.startedAt}`;
436
+ const existing = map.get(key);
437
+ if (!existing || u.finishedAt > existing.finishedAt) {
438
+ map.set(key, u);
439
+ }
440
+ }
441
+ return Array.from(map.values());
416
442
  }
417
443
  function saveLedger(base, data) {
418
444
  saveJsonFile(metricsPath(base), data);
@@ -569,10 +569,12 @@ export function nativeAddAllWithExclusions(basePath, exclusions) {
569
569
  return;
570
570
  }
571
571
  // When .gsd is a symlink, git rejects `:!.gsd/...` pathspecs with
572
- // "beyond a symbolic link". Fall back to plain `git add -A` which
573
- // respects .gitignore (where .gsd/ is listed by default).
572
+ // "beyond a symbolic link". Fall back to `git add -u` which only
573
+ // stages changes to already-tracked files O(tracked) not O(filesystem).
574
+ // Using `git add -A` here would traverse the entire working tree,
575
+ // hanging indefinitely on repos with large untracked data dirs. (#1977)
574
576
  if (stderr.includes("beyond a symbolic link")) {
575
- nativeAddAll(basePath);
577
+ gitFileExec(basePath, ["add", "-u"]);
576
578
  return;
577
579
  }
578
580
  throw new GSDError(GSD_GIT_ERROR, `git add -A with exclusions failed in ${basePath}: ${getErrorMessage(err)}`);
@@ -0,0 +1,224 @@
1
+ // GSD Extension — Notification History Overlay
2
+ // Scrollable panel showing all persisted notifications with severity filtering.
3
+ // Toggled with Ctrl+Alt+N or opened from /gsd notifications.
4
+ import { truncateToWidth, visibleWidth, matchesKey, Key } from "@gsd/pi-tui";
5
+ import { readNotifications, markAllRead, clearNotifications, } from "./notification-store.js";
6
+ import { padRight, joinColumns } from "../shared/mod.js";
7
+ const FILTER_CYCLE = ["all", "error", "warning", "info"];
8
+ function severityIcon(severity) {
9
+ switch (severity) {
10
+ case "error": return "✗";
11
+ case "warning": return "⚠";
12
+ case "success": return "✓";
13
+ case "info":
14
+ default: return "●";
15
+ }
16
+ }
17
+ function formatTimestamp(ts) {
18
+ try {
19
+ const d = new Date(ts);
20
+ const now = Date.now();
21
+ const diffMs = now - d.getTime();
22
+ if (diffMs < 60_000)
23
+ return "just now";
24
+ if (diffMs < 3600_000)
25
+ return `${Math.floor(diffMs / 60_000)}m ago`;
26
+ if (diffMs < 86400_000)
27
+ return `${Math.floor(diffMs / 3600_000)}h ago`;
28
+ return `${Math.floor(diffMs / 86400_000)}d ago`;
29
+ }
30
+ catch {
31
+ return ts.slice(11, 19); // fallback: HH:MM:SS
32
+ }
33
+ }
34
+ export class GSDNotificationOverlay {
35
+ tui;
36
+ theme;
37
+ onClose;
38
+ cachedWidth;
39
+ cachedLines;
40
+ scrollOffset = 0;
41
+ filterIndex = 0;
42
+ entries = [];
43
+ refreshTimer;
44
+ disposed = false;
45
+ resizeHandler = null;
46
+ constructor(tui, theme, onClose) {
47
+ this.tui = tui;
48
+ this.theme = theme;
49
+ this.onClose = onClose;
50
+ // Mark all as read on open
51
+ markAllRead();
52
+ this.entries = readNotifications();
53
+ // Resize handler
54
+ this.resizeHandler = () => {
55
+ if (this.disposed)
56
+ return;
57
+ this.invalidate();
58
+ this.tui.requestRender();
59
+ };
60
+ process.stdout.on("resize", this.resizeHandler);
61
+ // Refresh every 3s for new notifications
62
+ this.refreshTimer = setInterval(() => {
63
+ if (this.disposed)
64
+ return;
65
+ const fresh = readNotifications();
66
+ if (fresh.length !== this.entries.length) {
67
+ this.entries = fresh;
68
+ markAllRead();
69
+ this.invalidate();
70
+ this.tui.requestRender();
71
+ }
72
+ }, 3000);
73
+ }
74
+ get filter() {
75
+ return FILTER_CYCLE[this.filterIndex];
76
+ }
77
+ get filteredEntries() {
78
+ if (this.filter === "all")
79
+ return this.entries;
80
+ return this.entries.filter((e) => e.severity === this.filter);
81
+ }
82
+ handleInput(data) {
83
+ if (matchesKey(data, Key.escape) || matchesKey(data, Key.ctrl("c")) || matchesKey(data, Key.ctrlAlt("n"))) {
84
+ this.dispose();
85
+ this.onClose();
86
+ return;
87
+ }
88
+ // Scroll
89
+ if (matchesKey(data, Key.down) || matchesKey(data, "j")) {
90
+ this.scrollOffset++;
91
+ this.invalidate();
92
+ this.tui.requestRender();
93
+ return;
94
+ }
95
+ if (matchesKey(data, Key.up) || matchesKey(data, "k")) {
96
+ this.scrollOffset = Math.max(0, this.scrollOffset - 1);
97
+ this.invalidate();
98
+ this.tui.requestRender();
99
+ return;
100
+ }
101
+ if (data === "g") {
102
+ this.scrollOffset = 0;
103
+ this.invalidate();
104
+ this.tui.requestRender();
105
+ return;
106
+ }
107
+ if (data === "G") {
108
+ this.scrollOffset = 999;
109
+ this.invalidate();
110
+ this.tui.requestRender();
111
+ return;
112
+ }
113
+ // Filter cycle
114
+ if (data === "f") {
115
+ this.filterIndex = (this.filterIndex + 1) % FILTER_CYCLE.length;
116
+ this.scrollOffset = 0;
117
+ this.invalidate();
118
+ this.tui.requestRender();
119
+ return;
120
+ }
121
+ // Clear all
122
+ if (data === "c") {
123
+ clearNotifications();
124
+ this.entries = [];
125
+ this.scrollOffset = 0;
126
+ this.invalidate();
127
+ this.tui.requestRender();
128
+ return;
129
+ }
130
+ }
131
+ render(width) {
132
+ if (this.cachedLines && this.cachedWidth === width) {
133
+ return this.cachedLines;
134
+ }
135
+ const content = this.buildContentLines(width);
136
+ const viewportHeight = Math.max(5, process.stdout.rows ? process.stdout.rows - 8 : 24);
137
+ const chromeHeight = 2; // top + bottom border
138
+ const visibleContentRows = Math.max(1, viewportHeight - chromeHeight);
139
+ const maxScroll = Math.max(0, content.length - visibleContentRows);
140
+ this.scrollOffset = Math.min(this.scrollOffset, maxScroll);
141
+ const visibleContent = content.slice(this.scrollOffset, this.scrollOffset + visibleContentRows);
142
+ const lines = this.wrapInBox(visibleContent, width);
143
+ this.cachedWidth = width;
144
+ this.cachedLines = lines;
145
+ return lines;
146
+ }
147
+ invalidate() {
148
+ this.cachedLines = undefined;
149
+ this.cachedWidth = undefined;
150
+ }
151
+ dispose() {
152
+ this.disposed = true;
153
+ clearInterval(this.refreshTimer);
154
+ if (this.resizeHandler) {
155
+ process.stdout.removeListener("resize", this.resizeHandler);
156
+ this.resizeHandler = null;
157
+ }
158
+ }
159
+ wrapInBox(inner, width) {
160
+ const th = this.theme;
161
+ const border = (s) => th.fg("borderAccent", s);
162
+ const innerWidth = width - 4;
163
+ const lines = [];
164
+ lines.push(border("╭" + "─".repeat(width - 2) + "╮"));
165
+ for (const line of inner) {
166
+ const truncated = truncateToWidth(line, innerWidth);
167
+ const padWidth = Math.max(0, innerWidth - visibleWidth(truncated));
168
+ lines.push(border("│") + " " + truncated + " ".repeat(padWidth) + " " + border("│"));
169
+ }
170
+ lines.push(border("╰" + "─".repeat(width - 2) + "╯"));
171
+ return lines;
172
+ }
173
+ buildContentLines(width) {
174
+ const th = this.theme;
175
+ const shellWidth = width - 4;
176
+ const contentWidth = Math.min(shellWidth, 128);
177
+ const sidePad = Math.max(0, Math.floor((shellWidth - contentWidth) / 2));
178
+ const leftMargin = " ".repeat(sidePad);
179
+ const lines = [];
180
+ const row = (content = "") => {
181
+ const truncated = truncateToWidth(content, contentWidth);
182
+ return leftMargin + padRight(truncated, contentWidth);
183
+ };
184
+ const blank = () => row("");
185
+ const hr = () => row(th.fg("dim", "─".repeat(contentWidth)));
186
+ // Header
187
+ const title = th.fg("accent", th.bold("Notifications"));
188
+ const filterLabel = this.filter === "all"
189
+ ? th.fg("dim", "all")
190
+ : th.fg(this.filter === "error" ? "error" : this.filter === "warning" ? "warning" : "dim", this.filter);
191
+ const count = `${this.filteredEntries.length} entries`;
192
+ lines.push(row(joinColumns(`${title} ${th.fg("dim", "filter:")} ${filterLabel}`, th.fg("dim", count), contentWidth)));
193
+ lines.push(hr());
194
+ // Controls
195
+ lines.push(row(th.fg("dim", "↑/↓ scroll f filter c clear Esc close")));
196
+ lines.push(blank());
197
+ // Entries
198
+ const filtered = this.filteredEntries;
199
+ if (filtered.length === 0) {
200
+ lines.push(blank());
201
+ lines.push(row(th.fg("dim", this.entries.length === 0
202
+ ? "No notifications yet."
203
+ : `No ${this.filter} notifications.`)));
204
+ lines.push(blank());
205
+ return lines;
206
+ }
207
+ for (const entry of filtered) {
208
+ const icon = severityIcon(entry.severity);
209
+ const coloredIcon = entry.severity === "error" ? th.fg("error", icon)
210
+ : entry.severity === "warning" ? th.fg("warning", icon)
211
+ : entry.severity === "success" ? th.fg("success", icon)
212
+ : th.fg("dim", icon);
213
+ const time = th.fg("dim", formatTimestamp(entry.ts));
214
+ const source = entry.source === "workflow-logger" ? th.fg("dim", " [engine]") : "";
215
+ // First line: icon + timestamp + source
216
+ const msgMaxWidth = contentWidth - 20;
217
+ const msg = entry.message.length > msgMaxWidth
218
+ ? entry.message.slice(0, msgMaxWidth - 1) + "…"
219
+ : entry.message;
220
+ lines.push(row(`${coloredIcon} ${time}${source} ${msg}`));
221
+ }
222
+ return lines;
223
+ }
224
+ }