gsd-pi 2.57.0-dev.f22a903 → 2.58.0-dev.778d6ac

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 (643) hide show
  1. package/README.md +1 -1
  2. package/dist/cli.js +49 -35
  3. package/dist/headless-ui.d.ts +17 -0
  4. package/dist/headless-ui.js +97 -3
  5. package/dist/headless.js +67 -6
  6. package/dist/help-text.js +1 -0
  7. package/dist/onboarding.js +44 -0
  8. package/dist/resource-loader.js +16 -1
  9. package/dist/resources/agents/researcher.md +1 -1
  10. package/dist/resources/extensions/ask-user-questions.js +16 -3
  11. package/dist/resources/extensions/async-jobs/extension-manifest.json +1 -1
  12. package/dist/resources/extensions/bg-shell/extension-manifest.json +1 -1
  13. package/dist/resources/extensions/browser-tools/extension-manifest.json +1 -1
  14. package/dist/resources/extensions/claude-code-cli/partial-builder.js +14 -6
  15. package/dist/resources/extensions/claude-code-cli/stream-adapter.js +59 -36
  16. package/dist/resources/extensions/context7/extension-manifest.json +1 -1
  17. package/dist/resources/extensions/get-secrets-from-user.js +8 -5
  18. package/dist/resources/extensions/google-search/extension-manifest.json +1 -1
  19. package/dist/resources/extensions/google-search/index.js +2 -1
  20. package/dist/resources/extensions/gsd/auto/phases.js +25 -21
  21. package/dist/resources/extensions/gsd/auto-artifact-paths.js +2 -2
  22. package/dist/resources/extensions/gsd/auto-dashboard.js +37 -20
  23. package/dist/resources/extensions/gsd/auto-dispatch.js +17 -2
  24. package/dist/resources/extensions/gsd/auto-model-selection.js +26 -3
  25. package/dist/resources/extensions/gsd/auto-post-unit.js +16 -4
  26. package/dist/resources/extensions/gsd/auto-prompts.js +1 -1
  27. package/dist/resources/extensions/gsd/auto-recovery.js +13 -5
  28. package/dist/resources/extensions/gsd/auto-start.js +35 -22
  29. package/dist/resources/extensions/gsd/auto-worktree.js +196 -12
  30. package/dist/resources/extensions/gsd/auto.js +4 -0
  31. package/dist/resources/extensions/gsd/bootstrap/agent-end-recovery.js +32 -0
  32. package/dist/resources/extensions/gsd/bootstrap/db-tools.js +80 -8
  33. package/dist/resources/extensions/gsd/bootstrap/dynamic-tools.js +32 -1
  34. package/dist/resources/extensions/gsd/bootstrap/register-hooks.js +33 -18
  35. package/dist/resources/extensions/gsd/bootstrap/system-context.js +44 -11
  36. package/dist/resources/extensions/gsd/bootstrap/write-gate.js +67 -0
  37. package/dist/resources/extensions/gsd/captures.js +56 -4
  38. package/dist/resources/extensions/gsd/db-writer.js +116 -8
  39. package/dist/resources/extensions/gsd/doctor-git-checks.js +28 -0
  40. package/dist/resources/extensions/gsd/doctor-providers.js +2 -1
  41. package/dist/resources/extensions/gsd/doctor-runtime-checks.js +5 -4
  42. package/dist/resources/extensions/gsd/doctor.js +3 -1
  43. package/dist/resources/extensions/gsd/error-classifier.js +13 -10
  44. package/dist/resources/extensions/gsd/extension-manifest.json +16 -1
  45. package/dist/resources/extensions/gsd/forensics.js +123 -20
  46. package/dist/resources/extensions/gsd/git-service.js +23 -1
  47. package/dist/resources/extensions/gsd/gitignore.js +33 -0
  48. package/dist/resources/extensions/gsd/gsd-db.js +36 -9
  49. package/dist/resources/extensions/gsd/guided-flow.js +106 -44
  50. package/dist/resources/extensions/gsd/health-widget-core.js +31 -0
  51. package/dist/resources/extensions/gsd/health-widget.js +17 -0
  52. package/dist/resources/extensions/gsd/index.js +1 -1
  53. package/dist/resources/extensions/gsd/memory-extractor.js +7 -0
  54. package/dist/resources/extensions/gsd/migrate-external.js +8 -1
  55. package/dist/resources/extensions/gsd/milestone-validation-gates.js +45 -0
  56. package/dist/resources/extensions/gsd/model-cost-table.js +18 -0
  57. package/dist/resources/extensions/gsd/model-router.js +35 -1
  58. package/dist/resources/extensions/gsd/native-git-bridge.js +17 -0
  59. package/dist/resources/extensions/gsd/notifications.js +16 -1
  60. package/dist/resources/extensions/gsd/parallel-eligibility.js +13 -2
  61. package/dist/resources/extensions/gsd/parallel-merge.js +78 -5
  62. package/dist/resources/extensions/gsd/parsers-legacy.js +20 -3
  63. package/dist/resources/extensions/gsd/paths.js +43 -0
  64. package/dist/resources/extensions/gsd/preferences-models.js +14 -1
  65. package/dist/resources/extensions/gsd/preferences-types.js +2 -1
  66. package/dist/resources/extensions/gsd/preferences.js +13 -16
  67. package/dist/resources/extensions/gsd/prompt-loader.js +4 -1
  68. package/dist/resources/extensions/gsd/prompts/complete-milestone.md +1 -1
  69. package/dist/resources/extensions/gsd/prompts/complete-slice.md +4 -2
  70. package/dist/resources/extensions/gsd/prompts/discuss-headless.md +1 -1
  71. package/dist/resources/extensions/gsd/prompts/discuss.md +1 -1
  72. package/dist/resources/extensions/gsd/prompts/execute-task.md +3 -1
  73. package/dist/resources/extensions/gsd/prompts/forensics.md +2 -2
  74. package/dist/resources/extensions/gsd/prompts/guided-discuss-milestone.md +1 -1
  75. package/dist/resources/extensions/gsd/prompts/guided-discuss-slice.md +1 -1
  76. package/dist/resources/extensions/gsd/prompts/plan-slice.md +2 -0
  77. package/dist/resources/extensions/gsd/prompts/rethink.md +1 -1
  78. package/dist/resources/extensions/gsd/prompts/triage-captures.md +1 -0
  79. package/dist/resources/extensions/gsd/repo-identity.js +205 -11
  80. package/dist/resources/extensions/gsd/rethink.js +5 -0
  81. package/dist/resources/extensions/gsd/roadmap-slices.js +5 -4
  82. package/dist/resources/extensions/gsd/state.js +85 -27
  83. package/dist/resources/extensions/gsd/tests/dist-redirect.mjs +20 -1
  84. package/dist/resources/extensions/gsd/tools/complete-task.js +34 -71
  85. package/dist/resources/extensions/gsd/tools/plan-milestone.js +12 -2
  86. package/dist/resources/extensions/gsd/tools/reassess-roadmap.js +29 -1
  87. package/dist/resources/extensions/gsd/tools/validate-milestone.js +14 -3
  88. package/dist/resources/extensions/gsd/triage-resolution.js +22 -7
  89. package/dist/resources/extensions/gsd/undo.js +2 -2
  90. package/dist/resources/extensions/gsd/unit-ownership.js +164 -33
  91. package/dist/resources/extensions/gsd/verdict-parser.js +20 -8
  92. package/dist/resources/extensions/gsd/workflow-manifest.js +24 -5
  93. package/dist/resources/extensions/gsd/workflow-projections.js +95 -63
  94. package/dist/resources/extensions/gsd/workflow-reconcile.js +35 -5
  95. package/dist/resources/extensions/gsd/workspace-index.js +24 -0
  96. package/dist/resources/extensions/gsd/worktree-manager.js +105 -1
  97. package/dist/resources/extensions/gsd/worktree-resolver.js +20 -3
  98. package/dist/resources/extensions/mcp-client/index.js +11 -7
  99. package/dist/resources/extensions/ollama/index.js +112 -0
  100. package/dist/resources/extensions/ollama/model-capabilities.js +115 -0
  101. package/dist/resources/extensions/ollama/ollama-client.js +168 -0
  102. package/dist/resources/extensions/ollama/ollama-commands.js +194 -0
  103. package/dist/resources/extensions/ollama/ollama-discovery.js +69 -0
  104. package/dist/resources/extensions/ollama/ollama-tool.js +184 -0
  105. package/dist/resources/extensions/ollama/types.js +2 -0
  106. package/dist/resources/extensions/search-the-web/extension-manifest.json +1 -1
  107. package/dist/resources/extensions/shared/interview-ui.js +11 -1
  108. package/dist/resources/skills/create-gsd-extension/SKILL.md +5 -3
  109. package/dist/resources/skills/create-gsd-extension/references/key-rules-gotchas.md +5 -4
  110. package/dist/resources/skills/create-gsd-extension/workflows/add-capability.md +2 -2
  111. package/dist/resources/skills/create-gsd-extension/workflows/create-extension.md +4 -4
  112. package/dist/resources/skills/create-gsd-extension/workflows/debug-extension.md +5 -3
  113. package/dist/startup-model-validation.d.ts +39 -0
  114. package/dist/startup-model-validation.js +50 -0
  115. package/dist/web/standalone/.next/BUILD_ID +1 -1
  116. package/dist/web/standalone/.next/app-path-routes-manifest.json +16 -16
  117. package/dist/web/standalone/.next/build-manifest.json +3 -3
  118. package/dist/web/standalone/.next/prerender-manifest.json +3 -3
  119. package/dist/web/standalone/.next/react-loadable-manifest.json +1 -1
  120. package/dist/web/standalone/.next/server/app/_global-error/page_client-reference-manifest.js +1 -1
  121. package/dist/web/standalone/.next/server/app/_global-error.html +2 -2
  122. package/dist/web/standalone/.next/server/app/_global-error.rsc +1 -1
  123. package/dist/web/standalone/.next/server/app/_global-error.segments/_full.segment.rsc +1 -1
  124. package/dist/web/standalone/.next/server/app/_global-error.segments/_global-error/__PAGE__.segment.rsc +1 -1
  125. package/dist/web/standalone/.next/server/app/_global-error.segments/_global-error.segment.rsc +1 -1
  126. package/dist/web/standalone/.next/server/app/_global-error.segments/_head.segment.rsc +1 -1
  127. package/dist/web/standalone/.next/server/app/_global-error.segments/_index.segment.rsc +1 -1
  128. package/dist/web/standalone/.next/server/app/_global-error.segments/_tree.segment.rsc +1 -1
  129. package/dist/web/standalone/.next/server/app/_not-found/page_client-reference-manifest.js +1 -1
  130. package/dist/web/standalone/.next/server/app/_not-found.html +1 -1
  131. package/dist/web/standalone/.next/server/app/_not-found.rsc +2 -2
  132. package/dist/web/standalone/.next/server/app/_not-found.segments/_full.segment.rsc +2 -2
  133. package/dist/web/standalone/.next/server/app/_not-found.segments/_head.segment.rsc +1 -1
  134. package/dist/web/standalone/.next/server/app/_not-found.segments/_index.segment.rsc +2 -2
  135. package/dist/web/standalone/.next/server/app/_not-found.segments/_not-found/__PAGE__.segment.rsc +1 -1
  136. package/dist/web/standalone/.next/server/app/_not-found.segments/_not-found.segment.rsc +1 -1
  137. package/dist/web/standalone/.next/server/app/_not-found.segments/_tree.segment.rsc +2 -2
  138. package/dist/web/standalone/.next/server/app/api/boot/route_client-reference-manifest.js +1 -1
  139. package/dist/web/standalone/.next/server/app/api/bridge-terminal/input/route_client-reference-manifest.js +1 -1
  140. package/dist/web/standalone/.next/server/app/api/bridge-terminal/resize/route_client-reference-manifest.js +1 -1
  141. package/dist/web/standalone/.next/server/app/api/bridge-terminal/stream/route_client-reference-manifest.js +1 -1
  142. package/dist/web/standalone/.next/server/app/api/browse-directories/route_client-reference-manifest.js +1 -1
  143. package/dist/web/standalone/.next/server/app/api/captures/route.js +1 -1
  144. package/dist/web/standalone/.next/server/app/api/captures/route_client-reference-manifest.js +1 -1
  145. package/dist/web/standalone/.next/server/app/api/cleanup/route.js +1 -1
  146. package/dist/web/standalone/.next/server/app/api/cleanup/route_client-reference-manifest.js +1 -1
  147. package/dist/web/standalone/.next/server/app/api/dev-mode/route_client-reference-manifest.js +1 -1
  148. package/dist/web/standalone/.next/server/app/api/doctor/route.js +1 -1
  149. package/dist/web/standalone/.next/server/app/api/doctor/route_client-reference-manifest.js +1 -1
  150. package/dist/web/standalone/.next/server/app/api/experimental/route_client-reference-manifest.js +1 -1
  151. package/dist/web/standalone/.next/server/app/api/export-data/route.js +1 -1
  152. package/dist/web/standalone/.next/server/app/api/export-data/route_client-reference-manifest.js +1 -1
  153. package/dist/web/standalone/.next/server/app/api/files/route_client-reference-manifest.js +1 -1
  154. package/dist/web/standalone/.next/server/app/api/forensics/route.js +1 -1
  155. package/dist/web/standalone/.next/server/app/api/forensics/route_client-reference-manifest.js +1 -1
  156. package/dist/web/standalone/.next/server/app/api/git/route_client-reference-manifest.js +1 -1
  157. package/dist/web/standalone/.next/server/app/api/history/route.js +1 -1
  158. package/dist/web/standalone/.next/server/app/api/history/route_client-reference-manifest.js +1 -1
  159. package/dist/web/standalone/.next/server/app/api/hooks/route.js +1 -1
  160. package/dist/web/standalone/.next/server/app/api/hooks/route_client-reference-manifest.js +1 -1
  161. package/dist/web/standalone/.next/server/app/api/inspect/route_client-reference-manifest.js +1 -1
  162. package/dist/web/standalone/.next/server/app/api/knowledge/route_client-reference-manifest.js +1 -1
  163. package/dist/web/standalone/.next/server/app/api/live-state/route_client-reference-manifest.js +1 -1
  164. package/dist/web/standalone/.next/server/app/api/onboarding/route_client-reference-manifest.js +1 -1
  165. package/dist/web/standalone/.next/server/app/api/preferences/route_client-reference-manifest.js +1 -1
  166. package/dist/web/standalone/.next/server/app/api/projects/route_client-reference-manifest.js +1 -1
  167. package/dist/web/standalone/.next/server/app/api/recovery/route.js +1 -1
  168. package/dist/web/standalone/.next/server/app/api/recovery/route_client-reference-manifest.js +1 -1
  169. package/dist/web/standalone/.next/server/app/api/remote-questions/route_client-reference-manifest.js +1 -1
  170. package/dist/web/standalone/.next/server/app/api/session/browser/route_client-reference-manifest.js +1 -1
  171. package/dist/web/standalone/.next/server/app/api/session/command/route_client-reference-manifest.js +1 -1
  172. package/dist/web/standalone/.next/server/app/api/session/events/route_client-reference-manifest.js +1 -1
  173. package/dist/web/standalone/.next/server/app/api/session/manage/route_client-reference-manifest.js +1 -1
  174. package/dist/web/standalone/.next/server/app/api/settings-data/route.js +1 -1
  175. package/dist/web/standalone/.next/server/app/api/settings-data/route_client-reference-manifest.js +1 -1
  176. package/dist/web/standalone/.next/server/app/api/shutdown/route_client-reference-manifest.js +1 -1
  177. package/dist/web/standalone/.next/server/app/api/skill-health/route.js +1 -1
  178. package/dist/web/standalone/.next/server/app/api/skill-health/route_client-reference-manifest.js +1 -1
  179. package/dist/web/standalone/.next/server/app/api/steer/route_client-reference-manifest.js +1 -1
  180. package/dist/web/standalone/.next/server/app/api/switch-root/route_client-reference-manifest.js +1 -1
  181. package/dist/web/standalone/.next/server/app/api/terminal/input/route_client-reference-manifest.js +1 -1
  182. package/dist/web/standalone/.next/server/app/api/terminal/resize/route_client-reference-manifest.js +1 -1
  183. package/dist/web/standalone/.next/server/app/api/terminal/sessions/route_client-reference-manifest.js +1 -1
  184. package/dist/web/standalone/.next/server/app/api/terminal/stream/route_client-reference-manifest.js +1 -1
  185. package/dist/web/standalone/.next/server/app/api/terminal/upload/route_client-reference-manifest.js +1 -1
  186. package/dist/web/standalone/.next/server/app/api/undo/route.js +1 -1
  187. package/dist/web/standalone/.next/server/app/api/undo/route_client-reference-manifest.js +1 -1
  188. package/dist/web/standalone/.next/server/app/api/update/route.js +1 -1
  189. package/dist/web/standalone/.next/server/app/api/update/route_client-reference-manifest.js +1 -1
  190. package/dist/web/standalone/.next/server/app/api/visualizer/route.js +1 -1
  191. package/dist/web/standalone/.next/server/app/api/visualizer/route_client-reference-manifest.js +1 -1
  192. package/dist/web/standalone/.next/server/app/index.html +1 -1
  193. package/dist/web/standalone/.next/server/app/index.rsc +2 -2
  194. package/dist/web/standalone/.next/server/app/index.segments/__PAGE__.segment.rsc +1 -1
  195. package/dist/web/standalone/.next/server/app/index.segments/_full.segment.rsc +2 -2
  196. package/dist/web/standalone/.next/server/app/index.segments/_head.segment.rsc +1 -1
  197. package/dist/web/standalone/.next/server/app/index.segments/_index.segment.rsc +2 -2
  198. package/dist/web/standalone/.next/server/app/index.segments/_tree.segment.rsc +2 -2
  199. package/dist/web/standalone/.next/server/app/page_client-reference-manifest.js +1 -1
  200. package/dist/web/standalone/.next/server/app-paths-manifest.json +16 -16
  201. package/dist/web/standalone/.next/server/chunks/2229.js +2 -2
  202. package/dist/web/standalone/.next/server/middleware-build-manifest.js +1 -1
  203. package/dist/web/standalone/.next/server/middleware-react-loadable-manifest.js +1 -1
  204. package/dist/web/standalone/.next/server/pages/404.html +1 -1
  205. package/dist/web/standalone/.next/server/pages/500.html +2 -2
  206. package/dist/web/standalone/.next/server/server-reference-manifest.json +1 -1
  207. package/dist/web/standalone/.next/static/chunks/6502.7593d7797a4b3999.js +9 -0
  208. package/dist/web/standalone/.next/static/chunks/{webpack-61d3afac6d0f0ce7.js → webpack-a1c1e452c6b32d04.js} +1 -1
  209. package/dist/web/standalone/.next/static/css/f6e8833d46e738d8.css +1 -0
  210. package/dist/web-mode.js +2 -1
  211. package/package.json +2 -2
  212. package/packages/daemon/src/cli.ts +49 -0
  213. package/packages/daemon/src/daemon.test.ts +104 -1
  214. package/packages/daemon/src/daemon.ts +24 -1
  215. package/packages/daemon/src/discord-bot.ts +73 -3
  216. package/packages/daemon/src/event-bridge.ts +15 -9
  217. package/packages/daemon/src/event-formatter.ts +30 -2
  218. package/packages/daemon/src/index.ts +9 -0
  219. package/packages/daemon/src/launchd.test.ts +356 -0
  220. package/packages/daemon/src/launchd.ts +242 -0
  221. package/packages/daemon/src/message-batcher.test.ts +2 -2
  222. package/packages/daemon/src/message-batcher.ts +9 -3
  223. package/packages/daemon/src/orchestrator.test.ts +1 -0
  224. package/packages/daemon/src/orchestrator.ts +106 -2
  225. package/packages/native/dist/ast/index.js +9 -5
  226. package/packages/native/dist/ast/types.js +2 -1
  227. package/packages/native/dist/clipboard/index.js +12 -7
  228. package/packages/native/dist/clipboard/types.js +2 -1
  229. package/packages/native/dist/diff/index.js +12 -7
  230. package/packages/native/dist/diff/types.js +2 -1
  231. package/packages/native/dist/fd/index.js +6 -3
  232. package/packages/native/dist/fd/types.js +2 -1
  233. package/packages/native/dist/glob/index.js +9 -5
  234. package/packages/native/dist/glob/types.js +2 -1
  235. package/packages/native/dist/grep/index.js +9 -5
  236. package/packages/native/dist/grep/types.js +2 -1
  237. package/packages/native/dist/gsd-parser/index.js +18 -11
  238. package/packages/native/dist/gsd-parser/types.js +2 -1
  239. package/packages/native/dist/highlight/index.js +12 -7
  240. package/packages/native/dist/highlight/types.js +2 -1
  241. package/packages/native/dist/html/index.js +6 -3
  242. package/packages/native/dist/html/types.js +2 -1
  243. package/packages/native/dist/image/index.js +10 -5
  244. package/packages/native/dist/image/types.js +7 -4
  245. package/packages/native/dist/index.js +70 -17
  246. package/packages/native/dist/json-parse/index.js +13 -8
  247. package/packages/native/dist/native.js +47 -10
  248. package/packages/native/dist/ps/index.js +15 -9
  249. package/packages/native/dist/ps/types.js +2 -1
  250. package/packages/native/dist/stream-process/index.js +12 -7
  251. package/packages/native/dist/text/index.js +24 -14
  252. package/packages/native/dist/text/types.js +5 -2
  253. package/packages/native/dist/truncate/index.js +12 -7
  254. package/packages/native/dist/ttsr/index.js +12 -7
  255. package/packages/native/dist/ttsr/types.js +2 -1
  256. package/packages/native/dist/xxhash/index.js +9 -5
  257. package/packages/native/package.json +19 -19
  258. package/packages/native/src/__tests__/module-compat.test.mjs +91 -0
  259. package/packages/native/src/native.ts +9 -8
  260. package/packages/pi-agent-core/dist/agent-loop.js +3 -2
  261. package/packages/pi-agent-core/dist/agent-loop.js.map +1 -1
  262. package/packages/pi-agent-core/dist/proxy.d.ts +1 -1
  263. package/packages/pi-agent-core/dist/proxy.d.ts.map +1 -1
  264. package/packages/pi-agent-core/dist/proxy.js.map +1 -1
  265. package/packages/pi-agent-core/src/agent-loop.test.ts +45 -0
  266. package/packages/pi-agent-core/src/agent-loop.ts +3 -2
  267. package/packages/pi-agent-core/src/proxy.ts +1 -1
  268. package/packages/pi-ai/dist/env-api-keys.js +1 -0
  269. package/packages/pi-ai/dist/env-api-keys.js.map +1 -1
  270. package/packages/pi-ai/dist/index.d.ts +1 -0
  271. package/packages/pi-ai/dist/index.d.ts.map +1 -1
  272. package/packages/pi-ai/dist/index.js +1 -0
  273. package/packages/pi-ai/dist/index.js.map +1 -1
  274. package/packages/pi-ai/dist/providers/anthropic-shared.d.ts.map +1 -1
  275. package/packages/pi-ai/dist/providers/anthropic-shared.js +19 -2
  276. package/packages/pi-ai/dist/providers/anthropic-shared.js.map +1 -1
  277. package/packages/pi-ai/dist/providers/anthropic-shared.test.d.ts +2 -0
  278. package/packages/pi-ai/dist/providers/anthropic-shared.test.d.ts.map +1 -0
  279. package/packages/pi-ai/dist/providers/anthropic-shared.test.js +25 -0
  280. package/packages/pi-ai/dist/providers/anthropic-shared.test.js.map +1 -0
  281. package/packages/pi-ai/dist/types.d.ts +3 -3
  282. package/packages/pi-ai/dist/types.d.ts.map +1 -1
  283. package/packages/pi-ai/dist/types.js.map +1 -1
  284. package/packages/pi-ai/dist/utils/json-parse.d.ts +3 -0
  285. package/packages/pi-ai/dist/utils/json-parse.d.ts.map +1 -1
  286. package/packages/pi-ai/dist/utils/json-parse.js +24 -1
  287. package/packages/pi-ai/dist/utils/json-parse.js.map +1 -1
  288. package/packages/pi-ai/dist/utils/repair-tool-json.d.ts +37 -0
  289. package/packages/pi-ai/dist/utils/repair-tool-json.d.ts.map +1 -0
  290. package/packages/pi-ai/dist/utils/repair-tool-json.js +75 -0
  291. package/packages/pi-ai/dist/utils/repair-tool-json.js.map +1 -0
  292. package/packages/pi-ai/dist/utils/tests/repair-tool-json.test.d.ts +2 -0
  293. package/packages/pi-ai/dist/utils/tests/repair-tool-json.test.d.ts.map +1 -0
  294. package/packages/pi-ai/dist/utils/tests/repair-tool-json.test.js +73 -0
  295. package/packages/pi-ai/dist/utils/tests/repair-tool-json.test.js.map +1 -0
  296. package/packages/pi-ai/src/env-api-keys.ts +1 -0
  297. package/packages/pi-ai/src/index.ts +1 -0
  298. package/packages/pi-ai/src/providers/anthropic-shared.test.ts +29 -0
  299. package/packages/pi-ai/src/providers/anthropic-shared.ts +17 -2
  300. package/packages/pi-ai/src/types.ts +3 -2
  301. package/packages/pi-ai/src/utils/json-parse.ts +28 -1
  302. package/packages/pi-ai/src/utils/repair-tool-json.ts +88 -0
  303. package/packages/pi-ai/src/utils/tests/repair-tool-json.test.ts +102 -0
  304. package/packages/pi-coding-agent/dist/core/agent-session.d.ts +4 -0
  305. package/packages/pi-coding-agent/dist/core/agent-session.d.ts.map +1 -1
  306. package/packages/pi-coding-agent/dist/core/agent-session.js +31 -0
  307. package/packages/pi-coding-agent/dist/core/agent-session.js.map +1 -1
  308. package/packages/pi-coding-agent/dist/core/compaction/compaction.d.ts +17 -1
  309. package/packages/pi-coding-agent/dist/core/compaction/compaction.d.ts.map +1 -1
  310. package/packages/pi-coding-agent/dist/core/compaction/compaction.js +62 -2
  311. package/packages/pi-coding-agent/dist/core/compaction/compaction.js.map +1 -1
  312. package/packages/pi-coding-agent/dist/core/compaction/compaction.test.d.ts +6 -0
  313. package/packages/pi-coding-agent/dist/core/compaction/compaction.test.d.ts.map +1 -0
  314. package/packages/pi-coding-agent/dist/core/compaction/compaction.test.js +176 -0
  315. package/packages/pi-coding-agent/dist/core/compaction/compaction.test.js.map +1 -0
  316. package/packages/pi-coding-agent/dist/core/exec.d.ts.map +1 -1
  317. package/packages/pi-coding-agent/dist/core/exec.js +3 -1
  318. package/packages/pi-coding-agent/dist/core/exec.js.map +1 -1
  319. package/packages/pi-coding-agent/dist/core/extensions/extension-manifest.d.ts +28 -0
  320. package/packages/pi-coding-agent/dist/core/extensions/extension-manifest.d.ts.map +1 -0
  321. package/packages/pi-coding-agent/dist/core/extensions/extension-manifest.js +37 -0
  322. package/packages/pi-coding-agent/dist/core/extensions/extension-manifest.js.map +1 -0
  323. package/packages/pi-coding-agent/dist/core/extensions/extension-manifest.test.d.ts +2 -0
  324. package/packages/pi-coding-agent/dist/core/extensions/extension-manifest.test.d.ts.map +1 -0
  325. package/packages/pi-coding-agent/dist/core/extensions/extension-manifest.test.js +63 -0
  326. package/packages/pi-coding-agent/dist/core/extensions/extension-manifest.test.js.map +1 -0
  327. package/packages/pi-coding-agent/dist/core/extensions/extension-sort.d.ts +19 -0
  328. package/packages/pi-coding-agent/dist/core/extensions/extension-sort.d.ts.map +1 -0
  329. package/packages/pi-coding-agent/dist/core/extensions/extension-sort.js +115 -0
  330. package/packages/pi-coding-agent/dist/core/extensions/extension-sort.js.map +1 -0
  331. package/packages/pi-coding-agent/dist/core/extensions/extension-sort.test.d.ts +2 -0
  332. package/packages/pi-coding-agent/dist/core/extensions/extension-sort.test.d.ts.map +1 -0
  333. package/packages/pi-coding-agent/dist/core/extensions/extension-sort.test.js +109 -0
  334. package/packages/pi-coding-agent/dist/core/extensions/extension-sort.test.js.map +1 -0
  335. package/packages/pi-coding-agent/dist/core/extensions/index.d.ts +4 -0
  336. package/packages/pi-coding-agent/dist/core/extensions/index.d.ts.map +1 -1
  337. package/packages/pi-coding-agent/dist/core/extensions/index.js +2 -0
  338. package/packages/pi-coding-agent/dist/core/extensions/index.js.map +1 -1
  339. package/packages/pi-coding-agent/dist/core/extensions/loader.d.ts +5 -0
  340. package/packages/pi-coding-agent/dist/core/extensions/loader.d.ts.map +1 -1
  341. package/packages/pi-coding-agent/dist/core/extensions/loader.js +5 -0
  342. package/packages/pi-coding-agent/dist/core/extensions/loader.js.map +1 -1
  343. package/packages/pi-coding-agent/dist/core/image-overflow-recovery.d.ts +44 -0
  344. package/packages/pi-coding-agent/dist/core/image-overflow-recovery.d.ts.map +1 -0
  345. package/packages/pi-coding-agent/dist/core/image-overflow-recovery.js +97 -0
  346. package/packages/pi-coding-agent/dist/core/image-overflow-recovery.js.map +1 -0
  347. package/packages/pi-coding-agent/dist/core/image-overflow-recovery.test.d.ts +2 -0
  348. package/packages/pi-coding-agent/dist/core/image-overflow-recovery.test.d.ts.map +1 -0
  349. package/packages/pi-coding-agent/dist/core/image-overflow-recovery.test.js +181 -0
  350. package/packages/pi-coding-agent/dist/core/image-overflow-recovery.test.js.map +1 -0
  351. package/packages/pi-coding-agent/dist/core/index.d.ts +1 -1
  352. package/packages/pi-coding-agent/dist/core/index.d.ts.map +1 -1
  353. package/packages/pi-coding-agent/dist/core/index.js +1 -1
  354. package/packages/pi-coding-agent/dist/core/index.js.map +1 -1
  355. package/packages/pi-coding-agent/dist/core/lsp/index.d.ts.map +1 -1
  356. package/packages/pi-coding-agent/dist/core/lsp/index.js +3 -0
  357. package/packages/pi-coding-agent/dist/core/lsp/index.js.map +1 -1
  358. package/packages/pi-coding-agent/dist/core/lsp/lspmux.d.ts.map +1 -1
  359. package/packages/pi-coding-agent/dist/core/lsp/lspmux.js +3 -0
  360. package/packages/pi-coding-agent/dist/core/lsp/lspmux.js.map +1 -1
  361. package/packages/pi-coding-agent/dist/core/messages.d.ts.map +1 -1
  362. package/packages/pi-coding-agent/dist/core/messages.js +31 -2
  363. package/packages/pi-coding-agent/dist/core/messages.js.map +1 -1
  364. package/packages/pi-coding-agent/dist/core/messages.test.d.ts +9 -0
  365. package/packages/pi-coding-agent/dist/core/messages.test.d.ts.map +1 -0
  366. package/packages/pi-coding-agent/dist/core/messages.test.js +86 -0
  367. package/packages/pi-coding-agent/dist/core/messages.test.js.map +1 -0
  368. package/packages/pi-coding-agent/dist/core/model-resolver.d.ts.map +1 -1
  369. package/packages/pi-coding-agent/dist/core/model-resolver.js +1 -0
  370. package/packages/pi-coding-agent/dist/core/model-resolver.js.map +1 -1
  371. package/packages/pi-coding-agent/dist/core/resource-loader.d.ts +10 -0
  372. package/packages/pi-coding-agent/dist/core/resource-loader.d.ts.map +1 -1
  373. package/packages/pi-coding-agent/dist/core/resource-loader.js +12 -1
  374. package/packages/pi-coding-agent/dist/core/resource-loader.js.map +1 -1
  375. package/packages/pi-coding-agent/dist/core/retry-handler.d.ts +6 -0
  376. package/packages/pi-coding-agent/dist/core/retry-handler.d.ts.map +1 -1
  377. package/packages/pi-coding-agent/dist/core/retry-handler.js +48 -1
  378. package/packages/pi-coding-agent/dist/core/retry-handler.js.map +1 -1
  379. package/packages/pi-coding-agent/dist/core/retry-handler.test.d.ts +9 -0
  380. package/packages/pi-coding-agent/dist/core/retry-handler.test.d.ts.map +1 -0
  381. package/packages/pi-coding-agent/dist/core/retry-handler.test.js +193 -0
  382. package/packages/pi-coding-agent/dist/core/retry-handler.test.js.map +1 -0
  383. package/packages/pi-coding-agent/dist/core/tools/hashline-read.d.ts.map +1 -1
  384. package/packages/pi-coding-agent/dist/core/tools/hashline-read.js +10 -3
  385. package/packages/pi-coding-agent/dist/core/tools/hashline-read.js.map +1 -1
  386. package/packages/pi-coding-agent/dist/core/tools/read.d.ts.map +1 -1
  387. package/packages/pi-coding-agent/dist/core/tools/read.js +13 -4
  388. package/packages/pi-coding-agent/dist/core/tools/read.js.map +1 -1
  389. package/packages/pi-coding-agent/dist/core/tools/spawn-shell-windows.test.d.ts +16 -0
  390. package/packages/pi-coding-agent/dist/core/tools/spawn-shell-windows.test.d.ts.map +1 -0
  391. package/packages/pi-coding-agent/dist/core/tools/spawn-shell-windows.test.js +80 -0
  392. package/packages/pi-coding-agent/dist/core/tools/spawn-shell-windows.test.js.map +1 -0
  393. package/packages/pi-coding-agent/dist/index.d.ts +2 -2
  394. package/packages/pi-coding-agent/dist/index.d.ts.map +1 -1
  395. package/packages/pi-coding-agent/dist/index.js +1 -1
  396. package/packages/pi-coding-agent/dist/index.js.map +1 -1
  397. package/packages/pi-coding-agent/dist/modes/interactive/controllers/chat-controller.d.ts.map +1 -1
  398. package/packages/pi-coding-agent/dist/modes/interactive/controllers/chat-controller.js +4 -0
  399. package/packages/pi-coding-agent/dist/modes/interactive/controllers/chat-controller.js.map +1 -1
  400. package/packages/pi-coding-agent/dist/modes/rpc/remote-terminal.d.ts +1 -0
  401. package/packages/pi-coding-agent/dist/modes/rpc/remote-terminal.d.ts.map +1 -1
  402. package/packages/pi-coding-agent/dist/modes/rpc/remote-terminal.js +5 -0
  403. package/packages/pi-coding-agent/dist/modes/rpc/remote-terminal.js.map +1 -1
  404. package/packages/pi-coding-agent/package.json +1 -1
  405. package/packages/pi-coding-agent/src/core/agent-session.ts +38 -1
  406. package/packages/pi-coding-agent/src/core/compaction/compaction.test.ts +236 -0
  407. package/packages/pi-coding-agent/src/core/compaction/compaction.ts +94 -1
  408. package/packages/pi-coding-agent/src/core/exec.ts +3 -1
  409. package/packages/pi-coding-agent/src/core/extensions/extension-manifest.test.ts +77 -0
  410. package/packages/pi-coding-agent/src/core/extensions/extension-manifest.ts +62 -0
  411. package/packages/pi-coding-agent/src/core/extensions/extension-sort.test.ts +134 -0
  412. package/packages/pi-coding-agent/src/core/extensions/extension-sort.ts +137 -0
  413. package/packages/pi-coding-agent/src/core/extensions/index.ts +4 -0
  414. package/packages/pi-coding-agent/src/core/extensions/loader.ts +5 -0
  415. package/packages/pi-coding-agent/src/core/image-overflow-recovery.test.ts +228 -0
  416. package/packages/pi-coding-agent/src/core/image-overflow-recovery.ts +118 -0
  417. package/packages/pi-coding-agent/src/core/index.ts +6 -0
  418. package/packages/pi-coding-agent/src/core/lsp/index.ts +3 -0
  419. package/packages/pi-coding-agent/src/core/lsp/lspmux.ts +3 -0
  420. package/packages/pi-coding-agent/src/core/messages.test.ts +114 -0
  421. package/packages/pi-coding-agent/src/core/messages.ts +29 -2
  422. package/packages/pi-coding-agent/src/core/model-resolver.ts +1 -0
  423. package/packages/pi-coding-agent/src/core/resource-loader.ts +20 -1
  424. package/packages/pi-coding-agent/src/core/retry-handler.test.ts +255 -0
  425. package/packages/pi-coding-agent/src/core/retry-handler.ts +52 -1
  426. package/packages/pi-coding-agent/src/core/tools/hashline-read.ts +11 -3
  427. package/packages/pi-coding-agent/src/core/tools/read.ts +14 -4
  428. package/packages/pi-coding-agent/src/core/tools/spawn-shell-windows.test.ts +92 -0
  429. package/packages/pi-coding-agent/src/index.ts +6 -0
  430. package/packages/pi-coding-agent/src/modes/interactive/controllers/chat-controller.ts +7 -0
  431. package/packages/pi-coding-agent/src/modes/rpc/remote-terminal.ts +6 -0
  432. package/packages/pi-tui/dist/terminal.d.ts +2 -0
  433. package/packages/pi-tui/dist/terminal.d.ts.map +1 -1
  434. package/packages/pi-tui/dist/terminal.js +9 -0
  435. package/packages/pi-tui/dist/terminal.js.map +1 -1
  436. package/packages/pi-tui/dist/tui.d.ts.map +1 -1
  437. package/packages/pi-tui/dist/tui.js +9 -0
  438. package/packages/pi-tui/dist/tui.js.map +1 -1
  439. package/packages/pi-tui/src/terminal.ts +14 -0
  440. package/packages/pi-tui/src/tui.ts +8 -0
  441. package/pkg/package.json +1 -1
  442. package/scripts/ensure-workspace-builds.cjs +45 -14
  443. package/src/resources/agents/researcher.md +1 -1
  444. package/src/resources/extensions/ask-user-questions.ts +21 -3
  445. package/src/resources/extensions/async-jobs/extension-manifest.json +1 -1
  446. package/src/resources/extensions/bg-shell/extension-manifest.json +1 -1
  447. package/src/resources/extensions/browser-tools/extension-manifest.json +1 -1
  448. package/src/resources/extensions/claude-code-cli/partial-builder.ts +13 -6
  449. package/src/resources/extensions/claude-code-cli/stream-adapter.ts +63 -35
  450. package/src/resources/extensions/claude-code-cli/tests/partial-builder.test.ts +28 -0
  451. package/src/resources/extensions/claude-code-cli/tests/stream-adapter.test.ts +108 -1
  452. package/src/resources/extensions/context7/extension-manifest.json +1 -1
  453. package/src/resources/extensions/get-secrets-from-user.ts +8 -5
  454. package/src/resources/extensions/google-search/extension-manifest.json +1 -1
  455. package/src/resources/extensions/google-search/index.ts +2 -1
  456. package/src/resources/extensions/gsd/auto/loop-deps.ts +1 -0
  457. package/src/resources/extensions/gsd/auto/phases.ts +43 -34
  458. package/src/resources/extensions/gsd/auto-artifact-paths.ts +2 -2
  459. package/src/resources/extensions/gsd/auto-dashboard.ts +37 -19
  460. package/src/resources/extensions/gsd/auto-dispatch.ts +18 -2
  461. package/src/resources/extensions/gsd/auto-model-selection.ts +26 -5
  462. package/src/resources/extensions/gsd/auto-post-unit.ts +18 -4
  463. package/src/resources/extensions/gsd/auto-prompts.ts +1 -1
  464. package/src/resources/extensions/gsd/auto-recovery.ts +12 -5
  465. package/src/resources/extensions/gsd/auto-start.ts +35 -26
  466. package/src/resources/extensions/gsd/auto-worktree.ts +190 -9
  467. package/src/resources/extensions/gsd/auto.ts +5 -0
  468. package/src/resources/extensions/gsd/bootstrap/agent-end-recovery.ts +31 -0
  469. package/src/resources/extensions/gsd/bootstrap/db-tools.ts +85 -8
  470. package/src/resources/extensions/gsd/bootstrap/dynamic-tools.ts +38 -1
  471. package/src/resources/extensions/gsd/bootstrap/register-hooks.ts +31 -19
  472. package/src/resources/extensions/gsd/bootstrap/system-context.ts +50 -11
  473. package/src/resources/extensions/gsd/bootstrap/write-gate.ts +75 -0
  474. package/src/resources/extensions/gsd/captures.ts +63 -3
  475. package/src/resources/extensions/gsd/db-writer.ts +140 -7
  476. package/src/resources/extensions/gsd/doctor-git-checks.ts +26 -0
  477. package/src/resources/extensions/gsd/doctor-providers.ts +2 -1
  478. package/src/resources/extensions/gsd/doctor-runtime-checks.ts +5 -4
  479. package/src/resources/extensions/gsd/doctor.ts +3 -1
  480. package/src/resources/extensions/gsd/error-classifier.ts +14 -11
  481. package/src/resources/extensions/gsd/extension-manifest.json +16 -1
  482. package/src/resources/extensions/gsd/forensics.ts +144 -20
  483. package/src/resources/extensions/gsd/git-service.ts +26 -3
  484. package/src/resources/extensions/gsd/gitignore.ts +33 -0
  485. package/src/resources/extensions/gsd/gsd-db.ts +43 -7
  486. package/src/resources/extensions/gsd/guided-flow.ts +114 -45
  487. package/src/resources/extensions/gsd/health-widget-core.ts +34 -0
  488. package/src/resources/extensions/gsd/health-widget.ts +17 -0
  489. package/src/resources/extensions/gsd/index.ts +1 -0
  490. package/src/resources/extensions/gsd/memory-extractor.ts +8 -0
  491. package/src/resources/extensions/gsd/migrate-external.ts +9 -1
  492. package/src/resources/extensions/gsd/milestone-validation-gates.ts +56 -0
  493. package/src/resources/extensions/gsd/model-cost-table.ts +19 -0
  494. package/src/resources/extensions/gsd/model-router.ts +35 -1
  495. package/src/resources/extensions/gsd/native-git-bridge.ts +17 -0
  496. package/src/resources/extensions/gsd/notifications.ts +16 -0
  497. package/src/resources/extensions/gsd/parallel-eligibility.ts +15 -2
  498. package/src/resources/extensions/gsd/parallel-merge.ts +87 -4
  499. package/src/resources/extensions/gsd/parsers-legacy.ts +22 -3
  500. package/src/resources/extensions/gsd/paths.ts +42 -0
  501. package/src/resources/extensions/gsd/preferences-models.ts +14 -1
  502. package/src/resources/extensions/gsd/preferences-types.ts +2 -1
  503. package/src/resources/extensions/gsd/preferences.ts +13 -15
  504. package/src/resources/extensions/gsd/prompt-loader.ts +4 -1
  505. package/src/resources/extensions/gsd/prompts/complete-milestone.md +1 -1
  506. package/src/resources/extensions/gsd/prompts/complete-slice.md +4 -2
  507. package/src/resources/extensions/gsd/prompts/discuss-headless.md +1 -1
  508. package/src/resources/extensions/gsd/prompts/discuss.md +1 -1
  509. package/src/resources/extensions/gsd/prompts/execute-task.md +3 -1
  510. package/src/resources/extensions/gsd/prompts/forensics.md +2 -2
  511. package/src/resources/extensions/gsd/prompts/guided-discuss-milestone.md +1 -1
  512. package/src/resources/extensions/gsd/prompts/guided-discuss-slice.md +1 -1
  513. package/src/resources/extensions/gsd/prompts/plan-slice.md +2 -0
  514. package/src/resources/extensions/gsd/prompts/rethink.md +1 -1
  515. package/src/resources/extensions/gsd/prompts/triage-captures.md +1 -0
  516. package/src/resources/extensions/gsd/repo-identity.ts +186 -11
  517. package/src/resources/extensions/gsd/rethink.ts +6 -0
  518. package/src/resources/extensions/gsd/roadmap-slices.ts +5 -4
  519. package/src/resources/extensions/gsd/state.ts +84 -32
  520. package/src/resources/extensions/gsd/tests/auto-loop.test.ts +47 -0
  521. package/src/resources/extensions/gsd/tests/auto-mode-interactive-guard.test.ts +71 -0
  522. package/src/resources/extensions/gsd/tests/auto-model-selection.test.ts +71 -1
  523. package/src/resources/extensions/gsd/tests/captures.test.ts +103 -0
  524. package/src/resources/extensions/gsd/tests/cli-provider-rate-limit.test.ts +47 -0
  525. package/src/resources/extensions/gsd/tests/complete-milestone.test.ts +27 -0
  526. package/src/resources/extensions/gsd/tests/complete-slice.test.ts +21 -0
  527. package/src/resources/extensions/gsd/tests/completion-hierarchy-guards.test.ts +192 -0
  528. package/src/resources/extensions/gsd/tests/db-path-worktree-symlink.test.ts +131 -0
  529. package/src/resources/extensions/gsd/tests/db-writer.test.ts +7 -12
  530. package/src/resources/extensions/gsd/tests/derive-state-db.test.ts +78 -5
  531. package/src/resources/extensions/gsd/tests/derive-state.test.ts +29 -0
  532. package/src/resources/extensions/gsd/tests/discord-invite-links.test.ts +47 -0
  533. package/src/resources/extensions/gsd/tests/discuss-empty-db-fallback.test.ts +127 -0
  534. package/src/resources/extensions/gsd/tests/discuss-queued-milestones.test.ts +40 -0
  535. package/src/resources/extensions/gsd/tests/dist-redirect.mjs +20 -1
  536. package/src/resources/extensions/gsd/tests/doctor-providers.test.ts +117 -0
  537. package/src/resources/extensions/gsd/tests/dynamic-routing-default.test.ts +20 -0
  538. package/src/resources/extensions/gsd/tests/empty-content-abort-loop.test.ts +74 -0
  539. package/src/resources/extensions/gsd/tests/event-replay-idempotency.test.ts +140 -0
  540. package/src/resources/extensions/gsd/tests/forensics-context-persist.test.ts +129 -0
  541. package/src/resources/extensions/gsd/tests/forensics-db-completion.test.ts +96 -0
  542. package/src/resources/extensions/gsd/tests/forensics-dedup.test.ts +31 -0
  543. package/src/resources/extensions/gsd/tests/gsd-tools.test.ts +125 -12
  544. package/src/resources/extensions/gsd/tests/gsdroot-worktree-detection.test.ts +164 -0
  545. package/src/resources/extensions/gsd/tests/guided-flow-dynamic-routing.test.ts +135 -0
  546. package/src/resources/extensions/gsd/tests/guided-flow-session-isolation.test.ts +97 -0
  547. package/src/resources/extensions/gsd/tests/health-widget.test.ts +67 -0
  548. package/src/resources/extensions/gsd/tests/hook-key-parsing.test.ts +107 -0
  549. package/src/resources/extensions/gsd/tests/integration/auto-recovery.test.ts +111 -1
  550. package/src/resources/extensions/gsd/tests/integration/auto-worktree-milestone-merge.test.ts +101 -0
  551. package/src/resources/extensions/gsd/tests/integration/auto-worktree.test.ts +59 -0
  552. package/src/resources/extensions/gsd/tests/integration/doctor-false-positives.test.ts +243 -0
  553. package/src/resources/extensions/gsd/tests/integration/gitignore-staging-2570.test.ts +150 -0
  554. package/src/resources/extensions/gsd/tests/integration/parallel-merge.test.ts +110 -0
  555. package/src/resources/extensions/gsd/tests/integration/run-uat.test.ts +1 -1
  556. package/src/resources/extensions/gsd/tests/integration/state-machine-live-validation.test.ts +959 -0
  557. package/src/resources/extensions/gsd/tests/memory-extractor.test.ts +85 -2
  558. package/src/resources/extensions/gsd/tests/migrate-external-worktree.test.ts +105 -0
  559. package/src/resources/extensions/gsd/tests/milestone-status-authoritative.test.ts +116 -0
  560. package/src/resources/extensions/gsd/tests/model-cost-table.test.ts +34 -0
  561. package/src/resources/extensions/gsd/tests/model-router.test.ts +68 -3
  562. package/src/resources/extensions/gsd/tests/model-unittype-mapping.test.ts +28 -0
  563. package/src/resources/extensions/gsd/tests/notifications.test.ts +45 -0
  564. package/src/resources/extensions/gsd/tests/parallel-commit-scope.test.ts +159 -0
  565. package/src/resources/extensions/gsd/tests/parallel-eligibility-ghost.test.ts +150 -0
  566. package/src/resources/extensions/gsd/tests/plan-milestone-title.test.ts +70 -0
  567. package/src/resources/extensions/gsd/tests/plan-milestone.test.ts +33 -1
  568. package/src/resources/extensions/gsd/tests/project-relocation-recovery.test.ts +297 -0
  569. package/src/resources/extensions/gsd/tests/prompt-contracts.test.ts +29 -0
  570. package/src/resources/extensions/gsd/tests/prompt-loader-replacement.test.ts +178 -0
  571. package/src/resources/extensions/gsd/tests/prompt-tool-names.test.ts +69 -0
  572. package/src/resources/extensions/gsd/tests/provider-errors.test.ts +38 -0
  573. package/src/resources/extensions/gsd/tests/queue-execution-guard.test.ts +157 -0
  574. package/src/resources/extensions/gsd/tests/quick-turn-end-cleanup.test.ts +90 -0
  575. package/src/resources/extensions/gsd/tests/reassess-handler.test.ts +117 -0
  576. package/src/resources/extensions/gsd/tests/reconciliation-edge-cases.test.ts +162 -0
  577. package/src/resources/extensions/gsd/tests/roadmap-slices.test.ts +97 -0
  578. package/src/resources/extensions/gsd/tests/secure-env-collect.test.ts +134 -0
  579. package/src/resources/extensions/gsd/tests/slice-disk-reconcile.test.ts +233 -0
  580. package/src/resources/extensions/gsd/tests/stash-queued-context-files.test.ts +305 -0
  581. package/src/resources/extensions/gsd/tests/state-corruption-2945.test.ts +405 -0
  582. package/src/resources/extensions/gsd/tests/state-derivation-parity.test.ts +257 -0
  583. package/src/resources/extensions/gsd/tests/state-machine-full-walkthrough.test.ts +1628 -0
  584. package/src/resources/extensions/gsd/tests/stop-auto-race-null-unit.test.ts +106 -0
  585. package/src/resources/extensions/gsd/tests/stuck-detection-coverage.test.ts +174 -0
  586. package/src/resources/extensions/gsd/tests/summary-render-parity.test.ts +221 -0
  587. package/src/resources/extensions/gsd/tests/tool-naming.test.ts +2 -1
  588. package/src/resources/extensions/gsd/tests/triage-resolution.test.ts +8 -0
  589. package/src/resources/extensions/gsd/tests/uat-stuck-loop-orphaned-worktree.test.ts +289 -0
  590. package/src/resources/extensions/gsd/tests/unit-ownership.test.ts +100 -17
  591. package/src/resources/extensions/gsd/tests/vacuum-recovery.test.ts +154 -0
  592. package/src/resources/extensions/gsd/tests/validate-milestone-write-order.test.ts +4 -1
  593. package/src/resources/extensions/gsd/tests/verdict-parser.test.ts +156 -0
  594. package/src/resources/extensions/gsd/tests/verification-operational-gate.test.ts +82 -0
  595. package/src/resources/extensions/gsd/tests/workflow-logger.test.ts +48 -0
  596. package/src/resources/extensions/gsd/tests/workflow-manifest.test.ts +92 -0
  597. package/src/resources/extensions/gsd/tests/workflow-projections.test.ts +4 -2
  598. package/src/resources/extensions/gsd/tests/worktree-db-respawn-truncation.test.ts +140 -0
  599. package/src/resources/extensions/gsd/tests/worktree-nested-git-safety.test.ts +101 -0
  600. package/src/resources/extensions/gsd/tests/worktree-resolver.test.ts +48 -1
  601. package/src/resources/extensions/gsd/tests/worktree-sync-milestones.test.ts +29 -5
  602. package/src/resources/extensions/gsd/tests/zombie-gsd-state.test.ts +95 -0
  603. package/src/resources/extensions/gsd/tools/complete-task.ts +36 -74
  604. package/src/resources/extensions/gsd/tools/plan-milestone.ts +13 -1
  605. package/src/resources/extensions/gsd/tools/reassess-roadmap.ts +36 -0
  606. package/src/resources/extensions/gsd/tools/validate-milestone.ts +20 -2
  607. package/src/resources/extensions/gsd/triage-resolution.ts +23 -6
  608. package/src/resources/extensions/gsd/types.ts +4 -2
  609. package/src/resources/extensions/gsd/undo.ts +2 -2
  610. package/src/resources/extensions/gsd/unit-ownership.ts +206 -35
  611. package/src/resources/extensions/gsd/verdict-parser.ts +21 -6
  612. package/src/resources/extensions/gsd/workflow-logger.ts +3 -1
  613. package/src/resources/extensions/gsd/workflow-manifest.ts +22 -5
  614. package/src/resources/extensions/gsd/workflow-projections.ts +97 -64
  615. package/src/resources/extensions/gsd/workflow-reconcile.ts +39 -10
  616. package/src/resources/extensions/gsd/workspace-index.ts +30 -0
  617. package/src/resources/extensions/gsd/worktree-manager.ts +120 -1
  618. package/src/resources/extensions/gsd/worktree-resolver.ts +22 -3
  619. package/src/resources/extensions/mcp-client/index.ts +13 -7
  620. package/src/resources/extensions/mcp-client/tests/server-name-spaces.test.ts +55 -0
  621. package/src/resources/extensions/ollama/index.ts +130 -0
  622. package/src/resources/extensions/ollama/model-capabilities.ts +145 -0
  623. package/src/resources/extensions/ollama/ollama-client.ts +196 -0
  624. package/src/resources/extensions/ollama/ollama-commands.ts +248 -0
  625. package/src/resources/extensions/ollama/ollama-discovery.ts +106 -0
  626. package/src/resources/extensions/ollama/ollama-tool.ts +218 -0
  627. package/src/resources/extensions/ollama/tests/model-capabilities.test.ts +162 -0
  628. package/src/resources/extensions/ollama/tests/ollama-client.test.ts +38 -0
  629. package/src/resources/extensions/ollama/tests/ollama-discovery.test.ts +28 -0
  630. package/src/resources/extensions/ollama/types.ts +130 -0
  631. package/src/resources/extensions/search-the-web/extension-manifest.json +1 -1
  632. package/src/resources/extensions/shared/interview-ui.ts +12 -1
  633. package/src/resources/extensions/shared/tests/ask-user-freetext.test.ts +156 -0
  634. package/src/resources/skills/create-gsd-extension/SKILL.md +5 -3
  635. package/src/resources/skills/create-gsd-extension/references/key-rules-gotchas.md +5 -4
  636. package/src/resources/skills/create-gsd-extension/workflows/add-capability.md +2 -2
  637. package/src/resources/skills/create-gsd-extension/workflows/create-extension.md +4 -4
  638. package/src/resources/skills/create-gsd-extension/workflows/debug-extension.md +5 -3
  639. package/dist/web/standalone/.next/static/chunks/6502.8b732f67a11b11b4.js +0 -9
  640. package/dist/web/standalone/.next/static/css/a58ef8a151aa0493.css +0 -1
  641. package/src/resources/extensions/gsd/tests/empty-db-reconciliation.test.ts +0 -79
  642. /package/dist/web/standalone/.next/static/{OS7_z6QaL6uqp8q5pjHSJ → R0D4xaIPl5kg93edN7Oo0}/_buildManifest.js +0 -0
  643. /package/dist/web/standalone/.next/static/{OS7_z6QaL6uqp8q5pjHSJ → R0D4xaIPl5kg93edN7Oo0}/_ssgManifest.js +0 -0
@@ -21,8 +21,10 @@ import {
21
21
  import {
22
22
  saveDecisionToDb,
23
23
  updateRequirementInDb,
24
+ saveRequirementToDb,
24
25
  saveArtifactToDb,
25
26
  nextDecisionId,
27
+ nextRequirementId,
26
28
  } from '../db-writer.ts';
27
29
  import type { Requirement } from '../types.ts';
28
30
 
@@ -160,18 +162,11 @@ describe('gsd-tools', () => {
160
162
  assert.ok(mdContent.includes('R001'), 'REQUIREMENTS.md should contain R001');
161
163
  assert.ok(mdContent.includes('validated'), 'REQUIREMENTS.md should reflect updated status');
162
164
 
163
- // Updating non-existent requirement throws
164
- let threwForMissing = false;
165
- try {
166
- await updateRequirementInDb('R999', { status: 'deferred' }, tmpDir);
167
- } catch (err) {
168
- threwForMissing = true;
169
- assert.ok(
170
- (err as Error).message.includes('R999'),
171
- 'Error should mention the missing requirement ID',
172
- );
173
- }
174
- assert.ok(threwForMissing, 'Should throw for non-existent requirement');
165
+ // Updating non-existent requirement upserts (creates it) — see #2919
166
+ await updateRequirementInDb('R999', { status: 'deferred' }, tmpDir);
167
+ const upserted = getRequirementById('R999');
168
+ assert.ok(upserted !== null, 'R999 should be created by upsert');
169
+ assert.deepStrictEqual(upserted!.status, 'deferred', 'Upserted requirement should have the updated status');
175
170
 
176
171
  closeDatabase();
177
172
  } finally {
@@ -263,6 +258,124 @@ describe('gsd-tools', () => {
263
258
  assert.deepStrictEqual(fallbackId, 'D001', 'nextDecisionId should return D001 when DB unavailable');
264
259
  });
265
260
 
261
+ test('gsd_requirement_save creates new requirement', async () => {
262
+ const tmpDir = makeTmpDir();
263
+ try {
264
+ const dbPath = path.join(tmpDir, '.gsd', 'gsd.db');
265
+ openDatabase(dbPath);
266
+
267
+ // (a) saveRequirementToDb creates a new requirement with auto-assigned ID
268
+ const result = await saveRequirementToDb(
269
+ {
270
+ class: 'functional',
271
+ status: 'active',
272
+ description: 'Must support dark mode',
273
+ why: 'Accessibility requirement',
274
+ source: 'user-research',
275
+ },
276
+ tmpDir,
277
+ );
278
+
279
+ assert.deepStrictEqual(result.id, 'R001', 'First requirement should be R001');
280
+
281
+ // Verify DB row exists
282
+ const row = getRequirementById('R001');
283
+ assert.ok(row !== null, 'Requirement R001 should exist in DB');
284
+ assert.deepStrictEqual(row!.class, 'functional', 'Class should match');
285
+ assert.deepStrictEqual(row!.description, 'Must support dark mode', 'Description should match');
286
+ assert.deepStrictEqual(row!.status, 'active', 'Status should match');
287
+
288
+ // Verify REQUIREMENTS.md was generated
289
+ const mdPath = path.join(tmpDir, '.gsd', 'REQUIREMENTS.md');
290
+ assert.ok(fs.existsSync(mdPath), 'REQUIREMENTS.md should be created');
291
+ const mdContent = fs.readFileSync(mdPath, 'utf-8');
292
+ assert.ok(mdContent.includes('R001'), 'REQUIREMENTS.md should contain R001');
293
+ assert.ok(mdContent.includes('dark mode'), 'REQUIREMENTS.md should contain description');
294
+
295
+ // (b) Auto-assigns correct next ID
296
+ const result2 = await saveRequirementToDb(
297
+ {
298
+ class: 'non-functional',
299
+ status: 'active',
300
+ description: 'Must load in under 2 seconds',
301
+ why: 'Performance SLA',
302
+ source: 'design',
303
+ },
304
+ tmpDir,
305
+ );
306
+ assert.deepStrictEqual(result2.id, 'R002', 'Second requirement should be R002');
307
+
308
+ closeDatabase();
309
+ } finally {
310
+ cleanupDir(tmpDir);
311
+ }
312
+ });
313
+
314
+ test('nextRequirementId computes correct next ID', async () => {
315
+ const tmpDir = makeTmpDir();
316
+ try {
317
+ const dbPath = path.join(tmpDir, '.gsd', 'gsd.db');
318
+ openDatabase(dbPath);
319
+
320
+ // No requirements yet
321
+ const id1 = await nextRequirementId();
322
+ assert.deepStrictEqual(id1, 'R001', 'Should return R001 when no requirements exist');
323
+
324
+ // Add one requirement
325
+ upsertRequirement({
326
+ id: 'R001',
327
+ class: 'functional',
328
+ status: 'active',
329
+ description: 'Test',
330
+ why: '',
331
+ source: '',
332
+ primary_owner: '',
333
+ supporting_slices: '',
334
+ validation: '',
335
+ notes: '',
336
+ full_content: '',
337
+ superseded_by: null,
338
+ });
339
+
340
+ const id2 = await nextRequirementId();
341
+ assert.deepStrictEqual(id2, 'R002', 'Should return R002 after R001 exists');
342
+
343
+ closeDatabase();
344
+ } finally {
345
+ cleanupDir(tmpDir);
346
+ }
347
+ });
348
+
349
+ test('gsd_requirement_update upserts when requirement not in DB', async () => {
350
+ const tmpDir = makeTmpDir();
351
+ try {
352
+ const dbPath = path.join(tmpDir, '.gsd', 'gsd.db');
353
+ openDatabase(dbPath);
354
+
355
+ // Requirement R025 does NOT exist in DB — simulates the bug scenario
356
+ // where requirements exist in REQUIREMENTS.md but were never imported.
357
+ // updateRequirementInDb should create the row instead of throwing.
358
+ await updateRequirementInDb(
359
+ 'R025',
360
+ { status: 'validated', validation: 'Integration tests pass' },
361
+ tmpDir,
362
+ );
363
+
364
+ const created = getRequirementById('R025');
365
+ assert.ok(created !== null, 'R025 should be created by upsert');
366
+ assert.deepStrictEqual(created!.status, 'validated', 'Status should be set');
367
+ assert.deepStrictEqual(created!.validation, 'Integration tests pass', 'Validation should be set');
368
+
369
+ // Verify REQUIREMENTS.md was generated
370
+ const mdPath = path.join(tmpDir, '.gsd', 'REQUIREMENTS.md');
371
+ assert.ok(fs.existsSync(mdPath), 'REQUIREMENTS.md should be created');
372
+
373
+ closeDatabase();
374
+ } finally {
375
+ cleanupDir(tmpDir);
376
+ }
377
+ });
378
+
266
379
  test('Tool result format', async () => {
267
380
  const tmpDir = makeTmpDir();
268
381
  try {
@@ -0,0 +1,164 @@
1
+ /**
2
+ * gsdroot-worktree-detection.test.ts — Regression test for #2594.
3
+ *
4
+ * gsdRoot() must return the worktree's own .gsd directory when the basePath
5
+ * is inside a .gsd/worktrees/<name>/ structure, not walk up to the project
6
+ * root's .gsd via the git-root probe.
7
+ *
8
+ * The bug: when a git worktree lives at /project/.gsd/worktrees/M008/,
9
+ * probeGsdRoot() runs `git rev-parse --show-toplevel` which can return the
10
+ * main project root (not the worktree root) depending on git version and
11
+ * worktree setup. The walk-up then finds /project/.gsd and returns that
12
+ * instead of the worktree's own .gsd path.
13
+ */
14
+
15
+ import { describe, test, beforeEach, afterEach } from "node:test";
16
+ import assert from "node:assert/strict";
17
+ import { mkdirSync, rmSync, writeFileSync } from "node:fs";
18
+ import { join } from "node:path";
19
+ import { mkdtempSync, realpathSync } from "node:fs";
20
+ import { tmpdir } from "node:os";
21
+ import { spawnSync } from "node:child_process";
22
+
23
+ import { gsdRoot, _clearGsdRootCache } from "../paths.ts";
24
+
25
+ describe("gsdRoot() worktree detection (#2594)", () => {
26
+ let projectRoot: string;
27
+ let projectGsd: string;
28
+
29
+ beforeEach(() => {
30
+ _clearGsdRootCache();
31
+ // Create a temporary project with a git repo to simulate real conditions.
32
+ // realpathSync handles macOS /tmp -> /private/tmp.
33
+ projectRoot = realpathSync(mkdtempSync(join(tmpdir(), "gsdroot-wt-")));
34
+ projectGsd = join(projectRoot, ".gsd");
35
+ mkdirSync(projectGsd, { recursive: true });
36
+
37
+ // Initialize a git repo in the project root so git rev-parse works
38
+ spawnSync("git", ["init", "--initial-branch=main"], {
39
+ cwd: projectRoot,
40
+ stdio: "ignore",
41
+ });
42
+ spawnSync("git", ["config", "user.email", "test@test.com"], {
43
+ cwd: projectRoot,
44
+ stdio: "ignore",
45
+ });
46
+ spawnSync("git", ["config", "user.name", "Test"], {
47
+ cwd: projectRoot,
48
+ stdio: "ignore",
49
+ });
50
+ // Create an initial commit so we have a HEAD
51
+ writeFileSync(join(projectRoot, "README.md"), "# Test");
52
+ spawnSync("git", ["add", "."], { cwd: projectRoot, stdio: "ignore" });
53
+ spawnSync("git", ["commit", "-m", "init"], {
54
+ cwd: projectRoot,
55
+ stdio: "ignore",
56
+ });
57
+ });
58
+
59
+ afterEach(() => {
60
+ _clearGsdRootCache();
61
+ rmSync(projectRoot, { recursive: true, force: true });
62
+ });
63
+
64
+ test("returns worktree .gsd when basePath is a worktree with its own .gsd (fast path)", () => {
65
+ // Simulates a worktree that already had copyPlanningArtifacts() run,
66
+ // so it has its own .gsd/ directory.
67
+ const worktreeBase = join(projectGsd, "worktrees", "M008");
68
+ const worktreeGsd = join(worktreeBase, ".gsd");
69
+ mkdirSync(worktreeGsd, { recursive: true });
70
+
71
+ const result = gsdRoot(worktreeBase);
72
+ assert.equal(
73
+ result,
74
+ worktreeGsd,
75
+ `Expected worktree .gsd (${worktreeGsd}), got ${result}. ` +
76
+ "gsdRoot() should use the fast path for an existing worktree .gsd.",
77
+ );
78
+ });
79
+
80
+ test("returns worktree .gsd path (not project root .gsd) when worktree .gsd does not exist yet", () => {
81
+ // This is the core #2594 bug: the worktree directory exists but its .gsd
82
+ // subdirectory hasn't been created yet. Without the fix, probeGsdRoot()
83
+ // walks up from the worktree path, finds /project/.gsd, and returns it.
84
+ // With the fix, it detects the .gsd/worktrees/<name>/ pattern and returns
85
+ // the worktree-local .gsd path as the creation fallback.
86
+ const worktreeBase = join(projectGsd, "worktrees", "M008");
87
+ mkdirSync(worktreeBase, { recursive: true });
88
+ // NOTE: no .gsd/ inside worktreeBase
89
+
90
+ const result = gsdRoot(worktreeBase);
91
+ const expected = join(worktreeBase, ".gsd");
92
+
93
+ // Without the fix, this returns projectGsd (/project/.gsd) because the
94
+ // walk-up from worktreeBase finds it. With the fix, it returns the
95
+ // worktree-local path.
96
+ assert.notEqual(
97
+ result,
98
+ projectGsd,
99
+ "gsdRoot() must NOT return the project root .gsd when basePath is inside .gsd/worktrees/",
100
+ );
101
+ assert.equal(
102
+ result,
103
+ expected,
104
+ `Expected worktree-local .gsd (${expected}), got ${result}.`,
105
+ );
106
+ });
107
+
108
+ test("returns worktree .gsd when basePath is a real git worktree inside .gsd/worktrees/", () => {
109
+ // Create a real git worktree at .gsd/worktrees/M010
110
+ const worktreeName = "M010";
111
+ const worktreeBase = join(projectGsd, "worktrees", worktreeName);
112
+
113
+ // Use git worktree add to create a real worktree
114
+ const result = spawnSync(
115
+ "git",
116
+ ["worktree", "add", "-b", `milestone/${worktreeName}`, worktreeBase],
117
+ { cwd: projectRoot, encoding: "utf-8" },
118
+ );
119
+
120
+ if (result.status !== 0) {
121
+ // If git worktree add fails, skip the test gracefully
122
+ assert.ok(true, "Skipped: git worktree add not available");
123
+ return;
124
+ }
125
+
126
+ // The real git worktree exists at worktreeBase but has NO .gsd/ subdir yet
127
+ const gsdResult = gsdRoot(worktreeBase);
128
+ const expected = join(worktreeBase, ".gsd");
129
+
130
+ assert.notEqual(
131
+ gsdResult,
132
+ projectGsd,
133
+ "gsdRoot() must NOT escape to project root .gsd from inside a git worktree",
134
+ );
135
+ assert.equal(
136
+ gsdResult,
137
+ expected,
138
+ `Expected worktree-local .gsd (${expected}), got ${gsdResult}`,
139
+ );
140
+
141
+ // Cleanup worktree
142
+ spawnSync("git", ["worktree", "remove", "--force", worktreeBase], {
143
+ cwd: projectRoot,
144
+ stdio: "ignore",
145
+ });
146
+ });
147
+
148
+ test("still returns project .gsd for normal (non-worktree) basePath", () => {
149
+ const result = gsdRoot(projectRoot);
150
+ assert.equal(result, projectGsd);
151
+ });
152
+
153
+ test("still returns project .gsd for a subdirectory of the project", () => {
154
+ const subdir = join(projectRoot, "src", "lib");
155
+ mkdirSync(subdir, { recursive: true });
156
+
157
+ const result = gsdRoot(subdir);
158
+ assert.equal(
159
+ result,
160
+ projectGsd,
161
+ "Non-worktree subdirectories should still resolve to project .gsd",
162
+ );
163
+ });
164
+ });
@@ -0,0 +1,135 @@
1
+ /**
2
+ * Guided-flow dynamic routing — regression test for #2958.
3
+ *
4
+ * Verifies that dispatchWorkflow() routes through the dynamic routing pipeline
5
+ * (selectAndApplyModel from auto-model-selection.ts) instead of bypassing it
6
+ * with a direct call to resolveModelWithFallbacksForUnit.
7
+ *
8
+ * Copyright (c) 2026 Jeremy McSpadden <jeremy@fluxlabs.net>
9
+ */
10
+
11
+ import test from "node:test";
12
+ import assert from "node:assert/strict";
13
+ import { readFileSync } from "node:fs";
14
+ import { join, dirname } from "node:path";
15
+ import { fileURLToPath } from "node:url";
16
+
17
+ const __dirname = dirname(fileURLToPath(import.meta.url));
18
+ const gsdDir = join(__dirname, "..");
19
+
20
+ function readSrc(file: string): string {
21
+ return readFileSync(join(gsdDir, file), "utf-8");
22
+ }
23
+
24
+ const guidedFlowSrc = readSrc("guided-flow.ts");
25
+
26
+ // ═══════════════════════════════════════════════════════════════════════════
27
+ // #2958: dispatchWorkflow must route through dynamic routing pipeline
28
+ // ═══════════════════════════════════════════════════════════════════════════
29
+
30
+ test("#2958: guided-flow imports selectAndApplyModel from auto-model-selection", () => {
31
+ assert.ok(
32
+ guidedFlowSrc.includes("selectAndApplyModel"),
33
+ "guided-flow.ts must import and use selectAndApplyModel from auto-model-selection.ts",
34
+ );
35
+ });
36
+
37
+ test("#2958: dispatchWorkflow does not call resolveModelWithFallbacksForUnit directly", () => {
38
+ // Extract the dispatchWorkflow function body
39
+ const fnStart = guidedFlowSrc.indexOf("async function dispatchWorkflow(");
40
+ assert.ok(fnStart !== -1, "dispatchWorkflow function not found");
41
+
42
+ // Find the function body by tracking brace depth
43
+ const openBrace = guidedFlowSrc.indexOf("{", fnStart);
44
+ let depth = 1;
45
+ let pos = openBrace + 1;
46
+ while (depth > 0 && pos < guidedFlowSrc.length) {
47
+ if (guidedFlowSrc[pos] === "{") depth++;
48
+ else if (guidedFlowSrc[pos] === "}") depth--;
49
+ pos++;
50
+ }
51
+ const fnBody = guidedFlowSrc.slice(openBrace, pos);
52
+
53
+ assert.ok(
54
+ !fnBody.includes("resolveModelWithFallbacksForUnit"),
55
+ "dispatchWorkflow must NOT call resolveModelWithFallbacksForUnit directly — " +
56
+ "it must route through selectAndApplyModel for dynamic routing support (#2958)",
57
+ );
58
+ });
59
+
60
+ test("#2958: dispatchWorkflow calls selectAndApplyModel for model selection", () => {
61
+ // Extract the dispatchWorkflow function body
62
+ const fnStart = guidedFlowSrc.indexOf("async function dispatchWorkflow(");
63
+ assert.ok(fnStart !== -1, "dispatchWorkflow function not found");
64
+
65
+ const openBrace = guidedFlowSrc.indexOf("{", fnStart);
66
+ let depth = 1;
67
+ let pos = openBrace + 1;
68
+ while (depth > 0 && pos < guidedFlowSrc.length) {
69
+ if (guidedFlowSrc[pos] === "{") depth++;
70
+ else if (guidedFlowSrc[pos] === "}") depth--;
71
+ pos++;
72
+ }
73
+ const fnBody = guidedFlowSrc.slice(openBrace, pos);
74
+
75
+ assert.ok(
76
+ fnBody.includes("selectAndApplyModel"),
77
+ "dispatchWorkflow must call selectAndApplyModel to route through the dynamic routing pipeline (#2958)",
78
+ );
79
+ });
80
+
81
+ test("#2958: dispatchWorkflow does not use resolveAvailableModel inline", () => {
82
+ const fnStart = guidedFlowSrc.indexOf("async function dispatchWorkflow(");
83
+ assert.ok(fnStart !== -1, "dispatchWorkflow function not found");
84
+
85
+ const openBrace = guidedFlowSrc.indexOf("{", fnStart);
86
+ let depth = 1;
87
+ let pos = openBrace + 1;
88
+ while (depth > 0 && pos < guidedFlowSrc.length) {
89
+ if (guidedFlowSrc[pos] === "{") depth++;
90
+ else if (guidedFlowSrc[pos] === "}") depth--;
91
+ pos++;
92
+ }
93
+ const fnBody = guidedFlowSrc.slice(openBrace, pos);
94
+
95
+ assert.ok(
96
+ !fnBody.includes("resolveAvailableModel"),
97
+ "dispatchWorkflow must NOT use resolveAvailableModel inline — " +
98
+ "model resolution is handled by selectAndApplyModel (#2958)",
99
+ );
100
+ });
101
+
102
+ test("#2958: guided-flow does not import resolveModelWithFallbacksForUnit", () => {
103
+ // The import should be removed since dispatchWorkflow was the only consumer
104
+ // Check if resolveModelWithFallbacksForUnit is still used elsewhere in the file
105
+ const fnStart = guidedFlowSrc.indexOf("async function dispatchWorkflow(");
106
+ const beforeDispatch = guidedFlowSrc.slice(0, fnStart);
107
+ const afterFnEnd = (() => {
108
+ const openBrace = guidedFlowSrc.indexOf("{", fnStart);
109
+ let depth = 1;
110
+ let p = openBrace + 1;
111
+ while (depth > 0 && p < guidedFlowSrc.length) {
112
+ if (guidedFlowSrc[p] === "{") depth++;
113
+ else if (guidedFlowSrc[p] === "}") depth--;
114
+ p++;
115
+ }
116
+ return guidedFlowSrc.slice(p);
117
+ })();
118
+
119
+ // If resolveModelWithFallbacksForUnit is not used outside dispatchWorkflow,
120
+ // the import should be removed
121
+ const usedOutside = beforeDispatch.includes("resolveModelWithFallbacksForUnit(")
122
+ || afterFnEnd.includes("resolveModelWithFallbacksForUnit(");
123
+
124
+ if (!usedOutside) {
125
+ // Verify the import line was cleaned up
126
+ const importLines = guidedFlowSrc.split("\n").filter(l =>
127
+ l.includes("import") && l.includes("resolveModelWithFallbacksForUnit"),
128
+ );
129
+ assert.equal(
130
+ importLines.length,
131
+ 0,
132
+ "resolveModelWithFallbacksForUnit import should be removed when no longer used outside dispatchWorkflow",
133
+ );
134
+ }
135
+ });
@@ -0,0 +1,97 @@
1
+ /**
2
+ * Regression test for #2985 Bugs 3 & 4:
3
+ * Bug 3 — module-level pendingAutoStart singleton clobbers concurrent sessions.
4
+ * Bug 4 — getDiscussionMilestoneId() returns wrong project's milestone under concurrency.
5
+ *
6
+ * pendingAutoStart must be keyed by basePath so concurrent discuss sessions
7
+ * in different projects are independent. getDiscussionMilestoneId() must accept
8
+ * a basePath parameter to perform a keyed lookup.
9
+ */
10
+
11
+ import { describe, test, beforeEach } from "node:test";
12
+ import assert from "node:assert/strict";
13
+
14
+ import {
15
+ getDiscussionMilestoneId,
16
+ setPendingAutoStart,
17
+ clearPendingAutoStart,
18
+ } from "../guided-flow.ts";
19
+
20
+ // ─── Tests ─────────────────────────────────────────────────────────────────
21
+
22
+ describe("#2985 Bug 3 — concurrent discuss sessions must be independent", () => {
23
+ beforeEach(() => {
24
+ clearPendingAutoStart();
25
+ });
26
+
27
+ test("second session does not clobber first session's pending auto-start", () => {
28
+ // Simulate two concurrent discuss sessions for different projects
29
+ const projectA = "/projects/alpha";
30
+ const projectB = "/projects/beta";
31
+
32
+ setPendingAutoStart(projectA, {
33
+ basePath: projectA,
34
+ milestoneId: "M001-aaa111",
35
+ });
36
+
37
+ setPendingAutoStart(projectB, {
38
+ basePath: projectB,
39
+ milestoneId: "M002-bbb222",
40
+ });
41
+
42
+ // Both sessions should be retrievable
43
+ const milestoneA = getDiscussionMilestoneId(projectA);
44
+ const milestoneB = getDiscussionMilestoneId(projectB);
45
+
46
+ assert.equal(milestoneA, "M001-aaa111", "projectA's milestone should be preserved");
47
+ assert.equal(milestoneB, "M002-bbb222", "projectB's milestone should be preserved");
48
+ });
49
+
50
+ test("clearing one session does not affect the other", () => {
51
+ const projectA = "/projects/alpha";
52
+ const projectB = "/projects/beta";
53
+
54
+ setPendingAutoStart(projectA, { basePath: projectA, milestoneId: "M001-aaa111" });
55
+ setPendingAutoStart(projectB, { basePath: projectB, milestoneId: "M002-bbb222" });
56
+
57
+ // Clear only projectA
58
+ clearPendingAutoStart(projectA);
59
+
60
+ assert.equal(getDiscussionMilestoneId(projectA), null, "projectA should be cleared");
61
+ assert.equal(getDiscussionMilestoneId(projectB), "M002-bbb222", "projectB should survive");
62
+ });
63
+ });
64
+
65
+ describe("#2985 Bug 4 — getDiscussionMilestoneId must be keyed by basePath", () => {
66
+ beforeEach(() => {
67
+ clearPendingAutoStart();
68
+ });
69
+
70
+ test("getDiscussionMilestoneId(basePath) returns correct milestone for each project", () => {
71
+ setPendingAutoStart("/proj/a", { basePath: "/proj/a", milestoneId: "M001" });
72
+ setPendingAutoStart("/proj/b", { basePath: "/proj/b", milestoneId: "M002" });
73
+
74
+ assert.equal(getDiscussionMilestoneId("/proj/a"), "M001");
75
+ assert.equal(getDiscussionMilestoneId("/proj/b"), "M002");
76
+ assert.equal(getDiscussionMilestoneId("/proj/unknown"), null);
77
+ });
78
+
79
+ test("getDiscussionMilestoneId() without basePath returns null when multiple sessions exist", () => {
80
+ setPendingAutoStart("/proj/a", { basePath: "/proj/a", milestoneId: "M001" });
81
+ setPendingAutoStart("/proj/b", { basePath: "/proj/b", milestoneId: "M002" });
82
+
83
+ // Without a key, the function should not blindly return the first entry
84
+ const result = getDiscussionMilestoneId();
85
+ // When there's ambiguity (multiple sessions), it should return null
86
+ // to force callers to be explicit
87
+ assert.equal(result, null, "should not return arbitrary milestone when multiple sessions exist");
88
+ });
89
+
90
+ test("getDiscussionMilestoneId() without basePath returns the milestone when only one session", () => {
91
+ setPendingAutoStart("/proj/a", { basePath: "/proj/a", milestoneId: "M001" });
92
+
93
+ // With only one session, backward compat — return it
94
+ const result = getDiscussionMilestoneId();
95
+ assert.equal(result, "M001", "should return the only active milestone for backward compat");
96
+ });
97
+ });
@@ -6,6 +6,7 @@ import { tmpdir } from "node:os";
6
6
  import {
7
7
  buildHealthLines,
8
8
  detectHealthWidgetProjectState,
9
+ formatRelativeTime,
9
10
  type HealthWidgetData,
10
11
  } from "../health-widget-core.ts";
11
12
 
@@ -34,6 +35,8 @@ function activeData(overrides: Partial<HealthWidgetData> = {}): HealthWidgetData
34
35
  providerIssue: null,
35
36
  environmentErrorCount: 0,
36
37
  environmentWarningCount: 0,
38
+ lastCommitEpoch: null,
39
+ lastCommitMessage: null,
37
40
  lastRefreshed: Date.now(),
38
41
  ...overrides,
39
42
  };
@@ -98,6 +101,70 @@ test("buildHealthLines: active state with issues reports issue summary", (t) =>
98
101
  assert.match(lines[0]!, /Env: 1 error/);
99
102
  });
100
103
 
104
+ // ── Last commit display ──────────────────────────────────────────────────
105
+
106
+ test("buildHealthLines: shows last commit with relative time and message", (t) => {
107
+ const epoch = Math.floor(Date.now() / 1000) - 300; // 5 minutes ago
108
+ const lines = buildHealthLines(activeData({
109
+ lastCommitEpoch: epoch,
110
+ lastCommitMessage: "feat(widget): add health display",
111
+ }));
112
+ assert.equal(lines.length, 1);
113
+ assert.match(lines[0]!, /Last commit: 5m ago/);
114
+ assert.match(lines[0]!, /feat\(widget\): add health display/);
115
+ });
116
+
117
+ test("buildHealthLines: truncates long commit messages", (t) => {
118
+ const epoch = Math.floor(Date.now() / 1000) - 60;
119
+ const longMsg = "a".repeat(80);
120
+ const lines = buildHealthLines(activeData({
121
+ lastCommitEpoch: epoch,
122
+ lastCommitMessage: longMsg,
123
+ }));
124
+ assert.equal(lines.length, 1);
125
+ assert.match(lines[0]!, /a{49}…/);
126
+ assert.ok(!lines[0]!.includes("a".repeat(51)), "message is truncated");
127
+ });
128
+
129
+ test("buildHealthLines: no last commit section when epoch is null", (t) => {
130
+ const lines = buildHealthLines(activeData({ lastCommitEpoch: null }));
131
+ assert.equal(lines.length, 1);
132
+ assert.ok(!lines[0]!.includes("Last commit"), "no last commit when null");
133
+ });
134
+
135
+ test("buildHealthLines: last commit without message shows only time", (t) => {
136
+ const epoch = Math.floor(Date.now() / 1000) - 3600; // 1 hour ago
137
+ const lines = buildHealthLines(activeData({
138
+ lastCommitEpoch: epoch,
139
+ lastCommitMessage: null,
140
+ }));
141
+ assert.equal(lines.length, 1);
142
+ assert.match(lines[0]!, /Last commit: 1h ago/);
143
+ assert.ok(!lines[0]!.includes(" — "), "no dash separator when no message");
144
+ });
145
+
146
+ // ── formatRelativeTime ───────────────────────────────────────────────────
147
+
148
+ test("formatRelativeTime: just now for <60s", () => {
149
+ const epoch = Math.floor(Date.now() / 1000) - 30;
150
+ assert.equal(formatRelativeTime(epoch), "just now");
151
+ });
152
+
153
+ test("formatRelativeTime: minutes", () => {
154
+ const epoch = Math.floor(Date.now() / 1000) - 300;
155
+ assert.equal(formatRelativeTime(epoch), "5m ago");
156
+ });
157
+
158
+ test("formatRelativeTime: hours", () => {
159
+ const epoch = Math.floor(Date.now() / 1000) - 7200;
160
+ assert.equal(formatRelativeTime(epoch), "2h ago");
161
+ });
162
+
163
+ test("formatRelativeTime: days", () => {
164
+ const epoch = Math.floor(Date.now() / 1000) - 172800;
165
+ assert.equal(formatRelativeTime(epoch), "2d ago");
166
+ });
167
+
101
168
  test("detectHealthWidgetProjectState: metrics file alone does not imply project", (t) => {
102
169
  const dir = makeTempDir("metrics-only");
103
170
  t.after(() => { cleanup(dir); });