gsd-pi 2.58.0 → 2.59.0-dev.023bd39

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 (843) hide show
  1. package/README.md +1 -1
  2. package/dist/cli.js +60 -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 +199 -12
  30. package/dist/resources/extensions/gsd/bootstrap/agent-end-recovery.js +32 -0
  31. package/dist/resources/extensions/gsd/bootstrap/db-tools.js +80 -8
  32. package/dist/resources/extensions/gsd/bootstrap/dynamic-tools.js +32 -1
  33. package/dist/resources/extensions/gsd/bootstrap/register-hooks.js +42 -34
  34. package/dist/resources/extensions/gsd/bootstrap/system-context.js +66 -12
  35. package/dist/resources/extensions/gsd/bootstrap/write-gate.js +67 -0
  36. package/dist/resources/extensions/gsd/captures.js +56 -4
  37. package/dist/resources/extensions/gsd/codebase-generator.js +279 -0
  38. package/dist/resources/extensions/gsd/commands/catalog.js +10 -1
  39. package/dist/resources/extensions/gsd/commands/handlers/ops.js +5 -0
  40. package/dist/resources/extensions/gsd/commands-codebase.js +115 -0
  41. package/dist/resources/extensions/gsd/commands-prefs-wizard.js +41 -4
  42. package/dist/resources/extensions/gsd/complexity-classifier.js +8 -6
  43. package/dist/resources/extensions/gsd/db-writer.js +116 -8
  44. package/dist/resources/extensions/gsd/doctor-git-checks.js +76 -1
  45. package/dist/resources/extensions/gsd/doctor-proactive.js +34 -1
  46. package/dist/resources/extensions/gsd/doctor-providers.js +2 -1
  47. package/dist/resources/extensions/gsd/doctor-runtime-checks.js +5 -4
  48. package/dist/resources/extensions/gsd/doctor.js +3 -1
  49. package/dist/resources/extensions/gsd/error-classifier.js +12 -10
  50. package/dist/resources/extensions/gsd/extension-manifest.json +16 -1
  51. package/dist/resources/extensions/gsd/forensics.js +123 -20
  52. package/dist/resources/extensions/gsd/git-service.js +105 -2
  53. package/dist/resources/extensions/gsd/gitignore.js +33 -0
  54. package/dist/resources/extensions/gsd/gsd-db.js +36 -9
  55. package/dist/resources/extensions/gsd/guided-flow.js +106 -44
  56. package/dist/resources/extensions/gsd/health-widget-core.js +31 -0
  57. package/dist/resources/extensions/gsd/health-widget.js +17 -0
  58. package/dist/resources/extensions/gsd/index.js +1 -1
  59. package/dist/resources/extensions/gsd/memory-extractor.js +7 -0
  60. package/dist/resources/extensions/gsd/migrate-external.js +8 -1
  61. package/dist/resources/extensions/gsd/milestone-validation-gates.js +45 -0
  62. package/dist/resources/extensions/gsd/model-cost-table.js +18 -0
  63. package/dist/resources/extensions/gsd/model-router.js +35 -1
  64. package/dist/resources/extensions/gsd/native-git-bridge.js +39 -0
  65. package/dist/resources/extensions/gsd/notifications.js +16 -1
  66. package/dist/resources/extensions/gsd/parallel-eligibility.js +13 -2
  67. package/dist/resources/extensions/gsd/parallel-merge.js +78 -5
  68. package/dist/resources/extensions/gsd/parsers-legacy.js +20 -3
  69. package/dist/resources/extensions/gsd/paths.js +45 -0
  70. package/dist/resources/extensions/gsd/preferences-models.js +14 -1
  71. package/dist/resources/extensions/gsd/preferences-types.js +3 -1
  72. package/dist/resources/extensions/gsd/preferences.js +13 -16
  73. package/dist/resources/extensions/gsd/prompt-loader.js +4 -1
  74. package/dist/resources/extensions/gsd/prompts/complete-milestone.md +1 -1
  75. package/dist/resources/extensions/gsd/prompts/complete-slice.md +4 -2
  76. package/dist/resources/extensions/gsd/prompts/discuss-headless.md +1 -1
  77. package/dist/resources/extensions/gsd/prompts/discuss.md +1 -1
  78. package/dist/resources/extensions/gsd/prompts/execute-task.md +3 -1
  79. package/dist/resources/extensions/gsd/prompts/forensics.md +2 -2
  80. package/dist/resources/extensions/gsd/prompts/guided-discuss-milestone.md +1 -1
  81. package/dist/resources/extensions/gsd/prompts/guided-discuss-slice.md +1 -1
  82. package/dist/resources/extensions/gsd/prompts/plan-slice.md +2 -0
  83. package/dist/resources/extensions/gsd/prompts/rethink.md +1 -1
  84. package/dist/resources/extensions/gsd/prompts/triage-captures.md +1 -0
  85. package/dist/resources/extensions/gsd/repo-identity.js +205 -11
  86. package/dist/resources/extensions/gsd/rethink.js +5 -0
  87. package/dist/resources/extensions/gsd/roadmap-slices.js +5 -4
  88. package/dist/resources/extensions/gsd/state.js +85 -27
  89. package/dist/resources/extensions/gsd/tests/dist-redirect.mjs +20 -1
  90. package/dist/resources/extensions/gsd/tools/complete-task.js +34 -71
  91. package/dist/resources/extensions/gsd/tools/plan-milestone.js +12 -2
  92. package/dist/resources/extensions/gsd/tools/reassess-roadmap.js +29 -1
  93. package/dist/resources/extensions/gsd/tools/validate-milestone.js +14 -3
  94. package/dist/resources/extensions/gsd/triage-resolution.js +22 -7
  95. package/dist/resources/extensions/gsd/undo.js +2 -2
  96. package/dist/resources/extensions/gsd/unit-ownership.js +164 -33
  97. package/dist/resources/extensions/gsd/verdict-parser.js +20 -8
  98. package/dist/resources/extensions/gsd/watch/header-renderer.js +241 -0
  99. package/dist/resources/extensions/gsd/workflow-manifest.js +24 -5
  100. package/dist/resources/extensions/gsd/workflow-projections.js +95 -63
  101. package/dist/resources/extensions/gsd/workflow-reconcile.js +35 -5
  102. package/dist/resources/extensions/gsd/workspace-index.js +24 -0
  103. package/dist/resources/extensions/gsd/worktree-manager.js +105 -1
  104. package/dist/resources/extensions/gsd/worktree-resolver.js +20 -3
  105. package/dist/resources/extensions/mcp-client/index.js +11 -7
  106. package/dist/resources/extensions/ollama/index.js +112 -0
  107. package/dist/resources/extensions/ollama/model-capabilities.js +115 -0
  108. package/dist/resources/extensions/ollama/ollama-client.js +168 -0
  109. package/dist/resources/extensions/ollama/ollama-commands.js +194 -0
  110. package/dist/resources/extensions/ollama/ollama-discovery.js +69 -0
  111. package/dist/resources/extensions/ollama/ollama-tool.js +184 -0
  112. package/dist/resources/extensions/ollama/types.js +2 -0
  113. package/dist/resources/extensions/search-the-web/extension-manifest.json +1 -1
  114. package/dist/resources/extensions/search-the-web/url-utils.js +17 -0
  115. package/dist/resources/extensions/shared/interview-ui.js +11 -1
  116. package/dist/resources/skills/btw/SKILL.md +42 -0
  117. package/dist/resources/skills/create-gsd-extension/SKILL.md +5 -3
  118. package/dist/resources/skills/create-gsd-extension/references/key-rules-gotchas.md +5 -4
  119. package/dist/resources/skills/create-gsd-extension/workflows/add-capability.md +2 -2
  120. package/dist/resources/skills/create-gsd-extension/workflows/create-extension.md +4 -4
  121. package/dist/resources/skills/create-gsd-extension/workflows/debug-extension.md +5 -3
  122. package/dist/security-overrides.d.ts +11 -0
  123. package/dist/security-overrides.js +41 -0
  124. package/dist/startup-model-validation.d.ts +39 -0
  125. package/dist/startup-model-validation.js +50 -0
  126. package/dist/web/standalone/.next/BUILD_ID +1 -1
  127. package/dist/web/standalone/.next/app-path-routes-manifest.json +14 -14
  128. package/dist/web/standalone/.next/build-manifest.json +4 -4
  129. package/dist/web/standalone/.next/prerender-manifest.json +3 -3
  130. package/dist/web/standalone/.next/react-loadable-manifest.json +1 -1
  131. package/dist/web/standalone/.next/required-server-files.json +4 -4
  132. package/dist/web/standalone/.next/server/app/_global-error/page.js +3 -3
  133. package/dist/web/standalone/.next/server/app/_global-error/page_client-reference-manifest.js +1 -1
  134. package/dist/web/standalone/.next/server/app/_global-error.html +2 -2
  135. package/dist/web/standalone/.next/server/app/_global-error.rsc +1 -1
  136. package/dist/web/standalone/.next/server/app/_global-error.segments/_full.segment.rsc +1 -1
  137. package/dist/web/standalone/.next/server/app/_global-error.segments/_global-error/__PAGE__.segment.rsc +1 -1
  138. package/dist/web/standalone/.next/server/app/_global-error.segments/_global-error.segment.rsc +1 -1
  139. package/dist/web/standalone/.next/server/app/_global-error.segments/_head.segment.rsc +1 -1
  140. package/dist/web/standalone/.next/server/app/_global-error.segments/_index.segment.rsc +1 -1
  141. package/dist/web/standalone/.next/server/app/_global-error.segments/_tree.segment.rsc +1 -1
  142. package/dist/web/standalone/.next/server/app/_not-found/page.js +2 -2
  143. package/dist/web/standalone/.next/server/app/_not-found/page_client-reference-manifest.js +1 -1
  144. package/dist/web/standalone/.next/server/app/_not-found.html +1 -1
  145. package/dist/web/standalone/.next/server/app/_not-found.rsc +4 -4
  146. package/dist/web/standalone/.next/server/app/_not-found.segments/_full.segment.rsc +4 -4
  147. package/dist/web/standalone/.next/server/app/_not-found.segments/_head.segment.rsc +1 -1
  148. package/dist/web/standalone/.next/server/app/_not-found.segments/_index.segment.rsc +4 -4
  149. package/dist/web/standalone/.next/server/app/_not-found.segments/_not-found/__PAGE__.segment.rsc +1 -1
  150. package/dist/web/standalone/.next/server/app/_not-found.segments/_not-found.segment.rsc +1 -1
  151. package/dist/web/standalone/.next/server/app/_not-found.segments/_tree.segment.rsc +2 -2
  152. package/dist/web/standalone/.next/server/app/api/boot/route.js +1 -1
  153. package/dist/web/standalone/.next/server/app/api/boot/route_client-reference-manifest.js +1 -1
  154. package/dist/web/standalone/.next/server/app/api/bridge-terminal/input/route.js +1 -1
  155. package/dist/web/standalone/.next/server/app/api/bridge-terminal/input/route_client-reference-manifest.js +1 -1
  156. package/dist/web/standalone/.next/server/app/api/bridge-terminal/resize/route.js +1 -1
  157. package/dist/web/standalone/.next/server/app/api/bridge-terminal/resize/route_client-reference-manifest.js +1 -1
  158. package/dist/web/standalone/.next/server/app/api/bridge-terminal/stream/route.js +2 -2
  159. package/dist/web/standalone/.next/server/app/api/bridge-terminal/stream/route_client-reference-manifest.js +1 -1
  160. package/dist/web/standalone/.next/server/app/api/browse-directories/route.js +1 -1
  161. package/dist/web/standalone/.next/server/app/api/browse-directories/route_client-reference-manifest.js +1 -1
  162. package/dist/web/standalone/.next/server/app/api/captures/route.js +1 -1
  163. package/dist/web/standalone/.next/server/app/api/captures/route_client-reference-manifest.js +1 -1
  164. package/dist/web/standalone/.next/server/app/api/cleanup/route.js +1 -1
  165. package/dist/web/standalone/.next/server/app/api/cleanup/route_client-reference-manifest.js +1 -1
  166. package/dist/web/standalone/.next/server/app/api/dev-mode/route.js +1 -1
  167. package/dist/web/standalone/.next/server/app/api/dev-mode/route_client-reference-manifest.js +1 -1
  168. package/dist/web/standalone/.next/server/app/api/doctor/route.js +1 -1
  169. package/dist/web/standalone/.next/server/app/api/doctor/route_client-reference-manifest.js +1 -1
  170. package/dist/web/standalone/.next/server/app/api/experimental/route.js +2 -2
  171. package/dist/web/standalone/.next/server/app/api/experimental/route_client-reference-manifest.js +1 -1
  172. package/dist/web/standalone/.next/server/app/api/export-data/route.js +1 -1
  173. package/dist/web/standalone/.next/server/app/api/export-data/route_client-reference-manifest.js +1 -1
  174. package/dist/web/standalone/.next/server/app/api/files/route.js +1 -1
  175. package/dist/web/standalone/.next/server/app/api/files/route_client-reference-manifest.js +1 -1
  176. package/dist/web/standalone/.next/server/app/api/forensics/route.js +1 -1
  177. package/dist/web/standalone/.next/server/app/api/forensics/route_client-reference-manifest.js +1 -1
  178. package/dist/web/standalone/.next/server/app/api/git/route.js +1 -1
  179. package/dist/web/standalone/.next/server/app/api/git/route_client-reference-manifest.js +1 -1
  180. package/dist/web/standalone/.next/server/app/api/history/route.js +1 -1
  181. package/dist/web/standalone/.next/server/app/api/history/route_client-reference-manifest.js +1 -1
  182. package/dist/web/standalone/.next/server/app/api/hooks/route.js +1 -1
  183. package/dist/web/standalone/.next/server/app/api/hooks/route_client-reference-manifest.js +1 -1
  184. package/dist/web/standalone/.next/server/app/api/inspect/route.js +1 -1
  185. package/dist/web/standalone/.next/server/app/api/inspect/route_client-reference-manifest.js +1 -1
  186. package/dist/web/standalone/.next/server/app/api/knowledge/route.js +1 -1
  187. package/dist/web/standalone/.next/server/app/api/knowledge/route_client-reference-manifest.js +1 -1
  188. package/dist/web/standalone/.next/server/app/api/live-state/route.js +1 -1
  189. package/dist/web/standalone/.next/server/app/api/live-state/route_client-reference-manifest.js +1 -1
  190. package/dist/web/standalone/.next/server/app/api/onboarding/route.js +1 -1
  191. package/dist/web/standalone/.next/server/app/api/onboarding/route_client-reference-manifest.js +1 -1
  192. package/dist/web/standalone/.next/server/app/api/preferences/route.js +1 -1
  193. package/dist/web/standalone/.next/server/app/api/preferences/route_client-reference-manifest.js +1 -1
  194. package/dist/web/standalone/.next/server/app/api/projects/route.js +1 -1
  195. package/dist/web/standalone/.next/server/app/api/projects/route_client-reference-manifest.js +1 -1
  196. package/dist/web/standalone/.next/server/app/api/recovery/route.js +1 -1
  197. package/dist/web/standalone/.next/server/app/api/recovery/route_client-reference-manifest.js +1 -1
  198. package/dist/web/standalone/.next/server/app/api/remote-questions/route.js +2 -2
  199. package/dist/web/standalone/.next/server/app/api/remote-questions/route_client-reference-manifest.js +1 -1
  200. package/dist/web/standalone/.next/server/app/api/session/browser/route.js +1 -1
  201. package/dist/web/standalone/.next/server/app/api/session/browser/route_client-reference-manifest.js +1 -1
  202. package/dist/web/standalone/.next/server/app/api/session/command/route.js +1 -1
  203. package/dist/web/standalone/.next/server/app/api/session/command/route_client-reference-manifest.js +1 -1
  204. package/dist/web/standalone/.next/server/app/api/session/events/route.js +2 -2
  205. package/dist/web/standalone/.next/server/app/api/session/events/route_client-reference-manifest.js +1 -1
  206. package/dist/web/standalone/.next/server/app/api/session/manage/route.js +1 -1
  207. package/dist/web/standalone/.next/server/app/api/session/manage/route_client-reference-manifest.js +1 -1
  208. package/dist/web/standalone/.next/server/app/api/settings-data/route.js +1 -1
  209. package/dist/web/standalone/.next/server/app/api/settings-data/route_client-reference-manifest.js +1 -1
  210. package/dist/web/standalone/.next/server/app/api/shutdown/route.js +1 -1
  211. package/dist/web/standalone/.next/server/app/api/shutdown/route_client-reference-manifest.js +1 -1
  212. package/dist/web/standalone/.next/server/app/api/skill-health/route.js +1 -1
  213. package/dist/web/standalone/.next/server/app/api/skill-health/route_client-reference-manifest.js +1 -1
  214. package/dist/web/standalone/.next/server/app/api/steer/route.js +1 -1
  215. package/dist/web/standalone/.next/server/app/api/steer/route_client-reference-manifest.js +1 -1
  216. package/dist/web/standalone/.next/server/app/api/switch-root/route.js +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_client-reference-manifest.js +1 -1
  224. package/dist/web/standalone/.next/server/app/api/terminal/stream/route.js +4 -4
  225. package/dist/web/standalone/.next/server/app/api/terminal/stream/route_client-reference-manifest.js +1 -1
  226. package/dist/web/standalone/.next/server/app/api/terminal/upload/route.js +1 -1
  227. package/dist/web/standalone/.next/server/app/api/terminal/upload/route_client-reference-manifest.js +1 -1
  228. package/dist/web/standalone/.next/server/app/api/undo/route.js +1 -1
  229. package/dist/web/standalone/.next/server/app/api/undo/route_client-reference-manifest.js +1 -1
  230. package/dist/web/standalone/.next/server/app/api/update/route.js +1 -1
  231. package/dist/web/standalone/.next/server/app/api/update/route_client-reference-manifest.js +1 -1
  232. package/dist/web/standalone/.next/server/app/api/visualizer/route.js +1 -1
  233. package/dist/web/standalone/.next/server/app/api/visualizer/route_client-reference-manifest.js +1 -1
  234. package/dist/web/standalone/.next/server/app/index.html +1 -1
  235. package/dist/web/standalone/.next/server/app/index.rsc +5 -5
  236. package/dist/web/standalone/.next/server/app/index.segments/__PAGE__.segment.rsc +2 -2
  237. package/dist/web/standalone/.next/server/app/index.segments/_full.segment.rsc +5 -5
  238. package/dist/web/standalone/.next/server/app/index.segments/_head.segment.rsc +1 -1
  239. package/dist/web/standalone/.next/server/app/index.segments/_index.segment.rsc +4 -4
  240. package/dist/web/standalone/.next/server/app/index.segments/_tree.segment.rsc +2 -2
  241. package/dist/web/standalone/.next/server/app/page.js +2 -2
  242. package/dist/web/standalone/.next/server/app/page_client-reference-manifest.js +1 -1
  243. package/dist/web/standalone/.next/server/app-paths-manifest.json +14 -14
  244. package/dist/web/standalone/.next/server/chunks/2229.js +2 -2
  245. package/dist/web/standalone/.next/server/chunks/7471.js +3 -3
  246. package/dist/web/standalone/.next/server/middleware-build-manifest.js +1 -1
  247. package/dist/web/standalone/.next/server/middleware-react-loadable-manifest.js +1 -1
  248. package/dist/web/standalone/.next/server/middleware.js +2 -2
  249. package/dist/web/standalone/.next/server/next-font-manifest.js +1 -1
  250. package/dist/web/standalone/.next/server/next-font-manifest.json +1 -1
  251. package/dist/web/standalone/.next/server/pages/404.html +1 -1
  252. package/dist/web/standalone/.next/server/pages/500.html +2 -2
  253. package/dist/web/standalone/.next/server/server-reference-manifest.json +1 -1
  254. package/dist/web/standalone/.next/static/chunks/6502.7593d7797a4b3999.js +9 -0
  255. package/dist/web/standalone/.next/static/chunks/app/_not-found/{page-2f24283c162b6ab3.js → page-f2a7482d42a5614b.js} +1 -1
  256. package/dist/web/standalone/.next/static/chunks/app/{layout-9ecfd95f343793f0.js → layout-a16c7a7ecdf0c2cf.js} +1 -1
  257. package/dist/web/standalone/.next/static/chunks/app/page-0c485498795110d6.js +1 -0
  258. package/dist/web/standalone/.next/static/chunks/main-app-fdab67f7802d7832.js +1 -0
  259. package/dist/web/standalone/.next/static/chunks/next/dist/client/components/builtin/global-error-459824ffb8c323dd.js +1 -0
  260. package/dist/web/standalone/.next/static/chunks/{webpack-61d3afac6d0f0ce7.js → webpack-a1c1e452c6b32d04.js} +1 -1
  261. package/dist/web/standalone/.next/static/css/f6e8833d46e738d8.css +1 -0
  262. package/dist/web/standalone/node_modules/node-pty/build/Makefile +2 -2
  263. package/dist/web/standalone/node_modules/node-pty/build/Release/pty.node +0 -0
  264. package/dist/web/standalone/node_modules/node-pty/build/pty.target.mk +14 -14
  265. package/dist/web/standalone/node_modules/node-pty/node-addon-api/node_addon_api.target.mk +14 -14
  266. package/dist/web/standalone/node_modules/node-pty/node-addon-api/node_addon_api_except.target.mk +14 -14
  267. package/dist/web/standalone/node_modules/node-pty/node-addon-api/node_addon_api_maybe.target.mk +14 -14
  268. package/dist/web/standalone/server.js +1 -1
  269. package/dist/web-mode.js +2 -1
  270. package/dist/welcome-screen.d.ts +1 -0
  271. package/dist/welcome-screen.js +32 -6
  272. package/package.json +2 -2
  273. package/packages/daemon/src/daemon.ts +1 -1
  274. package/packages/daemon/src/discord-bot.ts +11 -0
  275. package/packages/daemon/src/event-bridge.ts +15 -9
  276. package/packages/daemon/src/event-formatter.ts +30 -2
  277. package/packages/daemon/src/message-batcher.test.ts +2 -2
  278. package/packages/daemon/src/message-batcher.ts +9 -3
  279. package/packages/daemon/src/orchestrator.test.ts +1 -0
  280. package/packages/daemon/src/orchestrator.ts +106 -2
  281. package/packages/native/dist/ast/index.js +9 -5
  282. package/packages/native/dist/ast/types.js +2 -1
  283. package/packages/native/dist/clipboard/index.js +12 -7
  284. package/packages/native/dist/clipboard/types.js +2 -1
  285. package/packages/native/dist/diff/index.js +12 -7
  286. package/packages/native/dist/diff/types.js +2 -1
  287. package/packages/native/dist/fd/index.js +6 -3
  288. package/packages/native/dist/fd/types.js +2 -1
  289. package/packages/native/dist/glob/index.js +9 -5
  290. package/packages/native/dist/glob/types.js +2 -1
  291. package/packages/native/dist/grep/index.js +9 -5
  292. package/packages/native/dist/grep/types.js +2 -1
  293. package/packages/native/dist/gsd-parser/index.js +18 -11
  294. package/packages/native/dist/gsd-parser/types.js +2 -1
  295. package/packages/native/dist/highlight/index.js +12 -7
  296. package/packages/native/dist/highlight/types.js +2 -1
  297. package/packages/native/dist/html/index.js +6 -3
  298. package/packages/native/dist/html/types.js +2 -1
  299. package/packages/native/dist/image/index.js +10 -5
  300. package/packages/native/dist/image/types.js +7 -4
  301. package/packages/native/dist/index.js +70 -17
  302. package/packages/native/dist/json-parse/index.js +13 -8
  303. package/packages/native/dist/native.js +47 -10
  304. package/packages/native/dist/ps/index.js +15 -9
  305. package/packages/native/dist/ps/types.js +2 -1
  306. package/packages/native/dist/stream-process/index.js +12 -7
  307. package/packages/native/dist/text/index.js +24 -14
  308. package/packages/native/dist/text/types.js +5 -2
  309. package/packages/native/dist/truncate/index.js +12 -7
  310. package/packages/native/dist/ttsr/index.js +12 -7
  311. package/packages/native/dist/ttsr/types.js +2 -1
  312. package/packages/native/dist/xxhash/index.js +9 -5
  313. package/packages/native/package.json +19 -19
  314. package/packages/native/src/__tests__/module-compat.test.mjs +91 -0
  315. package/packages/native/src/native.ts +9 -8
  316. package/packages/pi-agent-core/dist/agent-loop.js +3 -2
  317. package/packages/pi-agent-core/dist/agent-loop.js.map +1 -1
  318. package/packages/pi-agent-core/dist/proxy.d.ts +1 -1
  319. package/packages/pi-agent-core/dist/proxy.d.ts.map +1 -1
  320. package/packages/pi-agent-core/dist/proxy.js.map +1 -1
  321. package/packages/pi-agent-core/src/agent-loop.test.ts +45 -0
  322. package/packages/pi-agent-core/src/agent-loop.ts +3 -2
  323. package/packages/pi-agent-core/src/proxy.ts +1 -1
  324. package/packages/pi-ai/dist/env-api-keys.js +1 -0
  325. package/packages/pi-ai/dist/env-api-keys.js.map +1 -1
  326. package/packages/pi-ai/dist/index.d.ts +1 -0
  327. package/packages/pi-ai/dist/index.d.ts.map +1 -1
  328. package/packages/pi-ai/dist/index.js +1 -0
  329. package/packages/pi-ai/dist/index.js.map +1 -1
  330. package/packages/pi-ai/dist/providers/anthropic-shared.d.ts.map +1 -1
  331. package/packages/pi-ai/dist/providers/anthropic-shared.js +19 -2
  332. package/packages/pi-ai/dist/providers/anthropic-shared.js.map +1 -1
  333. package/packages/pi-ai/dist/providers/anthropic-shared.test.d.ts +2 -0
  334. package/packages/pi-ai/dist/providers/anthropic-shared.test.d.ts.map +1 -0
  335. package/packages/pi-ai/dist/providers/anthropic-shared.test.js +25 -0
  336. package/packages/pi-ai/dist/providers/anthropic-shared.test.js.map +1 -0
  337. package/packages/pi-ai/dist/types.d.ts +3 -3
  338. package/packages/pi-ai/dist/types.d.ts.map +1 -1
  339. package/packages/pi-ai/dist/types.js.map +1 -1
  340. package/packages/pi-ai/dist/utils/json-parse.d.ts +3 -0
  341. package/packages/pi-ai/dist/utils/json-parse.d.ts.map +1 -1
  342. package/packages/pi-ai/dist/utils/json-parse.js +24 -1
  343. package/packages/pi-ai/dist/utils/json-parse.js.map +1 -1
  344. package/packages/pi-ai/dist/utils/repair-tool-json.d.ts +37 -0
  345. package/packages/pi-ai/dist/utils/repair-tool-json.d.ts.map +1 -0
  346. package/packages/pi-ai/dist/utils/repair-tool-json.js +75 -0
  347. package/packages/pi-ai/dist/utils/repair-tool-json.js.map +1 -0
  348. package/packages/pi-ai/dist/utils/tests/repair-tool-json.test.d.ts +2 -0
  349. package/packages/pi-ai/dist/utils/tests/repair-tool-json.test.d.ts.map +1 -0
  350. package/packages/pi-ai/dist/utils/tests/repair-tool-json.test.js +73 -0
  351. package/packages/pi-ai/dist/utils/tests/repair-tool-json.test.js.map +1 -0
  352. package/packages/pi-ai/src/env-api-keys.ts +1 -0
  353. package/packages/pi-ai/src/index.ts +1 -0
  354. package/packages/pi-ai/src/providers/anthropic-shared.test.ts +29 -0
  355. package/packages/pi-ai/src/providers/anthropic-shared.ts +17 -2
  356. package/packages/pi-ai/src/types.ts +3 -2
  357. package/packages/pi-ai/src/utils/json-parse.ts +28 -1
  358. package/packages/pi-ai/src/utils/repair-tool-json.ts +88 -0
  359. package/packages/pi-ai/src/utils/tests/repair-tool-json.test.ts +102 -0
  360. package/packages/pi-coding-agent/dist/core/agent-session.d.ts +4 -0
  361. package/packages/pi-coding-agent/dist/core/agent-session.d.ts.map +1 -1
  362. package/packages/pi-coding-agent/dist/core/agent-session.js +31 -0
  363. package/packages/pi-coding-agent/dist/core/agent-session.js.map +1 -1
  364. package/packages/pi-coding-agent/dist/core/compaction/compaction.d.ts +17 -1
  365. package/packages/pi-coding-agent/dist/core/compaction/compaction.d.ts.map +1 -1
  366. package/packages/pi-coding-agent/dist/core/compaction/compaction.js +62 -2
  367. package/packages/pi-coding-agent/dist/core/compaction/compaction.js.map +1 -1
  368. package/packages/pi-coding-agent/dist/core/compaction/compaction.test.d.ts +6 -0
  369. package/packages/pi-coding-agent/dist/core/compaction/compaction.test.d.ts.map +1 -0
  370. package/packages/pi-coding-agent/dist/core/compaction/compaction.test.js +176 -0
  371. package/packages/pi-coding-agent/dist/core/compaction/compaction.test.js.map +1 -0
  372. package/packages/pi-coding-agent/dist/core/exec.d.ts.map +1 -1
  373. package/packages/pi-coding-agent/dist/core/exec.js +3 -1
  374. package/packages/pi-coding-agent/dist/core/exec.js.map +1 -1
  375. package/packages/pi-coding-agent/dist/core/extensions/extension-manifest.d.ts +28 -0
  376. package/packages/pi-coding-agent/dist/core/extensions/extension-manifest.d.ts.map +1 -0
  377. package/packages/pi-coding-agent/dist/core/extensions/extension-manifest.js +37 -0
  378. package/packages/pi-coding-agent/dist/core/extensions/extension-manifest.js.map +1 -0
  379. package/packages/pi-coding-agent/dist/core/extensions/extension-manifest.test.d.ts +2 -0
  380. package/packages/pi-coding-agent/dist/core/extensions/extension-manifest.test.d.ts.map +1 -0
  381. package/packages/pi-coding-agent/dist/core/extensions/extension-manifest.test.js +63 -0
  382. package/packages/pi-coding-agent/dist/core/extensions/extension-manifest.test.js.map +1 -0
  383. package/packages/pi-coding-agent/dist/core/extensions/extension-sort.d.ts +19 -0
  384. package/packages/pi-coding-agent/dist/core/extensions/extension-sort.d.ts.map +1 -0
  385. package/packages/pi-coding-agent/dist/core/extensions/extension-sort.js +115 -0
  386. package/packages/pi-coding-agent/dist/core/extensions/extension-sort.js.map +1 -0
  387. package/packages/pi-coding-agent/dist/core/extensions/extension-sort.test.d.ts +2 -0
  388. package/packages/pi-coding-agent/dist/core/extensions/extension-sort.test.d.ts.map +1 -0
  389. package/packages/pi-coding-agent/dist/core/extensions/extension-sort.test.js +109 -0
  390. package/packages/pi-coding-agent/dist/core/extensions/extension-sort.test.js.map +1 -0
  391. package/packages/pi-coding-agent/dist/core/extensions/index.d.ts +4 -0
  392. package/packages/pi-coding-agent/dist/core/extensions/index.d.ts.map +1 -1
  393. package/packages/pi-coding-agent/dist/core/extensions/index.js +2 -0
  394. package/packages/pi-coding-agent/dist/core/extensions/index.js.map +1 -1
  395. package/packages/pi-coding-agent/dist/core/extensions/loader.d.ts +5 -0
  396. package/packages/pi-coding-agent/dist/core/extensions/loader.d.ts.map +1 -1
  397. package/packages/pi-coding-agent/dist/core/extensions/loader.js +5 -0
  398. package/packages/pi-coding-agent/dist/core/extensions/loader.js.map +1 -1
  399. package/packages/pi-coding-agent/dist/core/image-overflow-recovery.d.ts +44 -0
  400. package/packages/pi-coding-agent/dist/core/image-overflow-recovery.d.ts.map +1 -0
  401. package/packages/pi-coding-agent/dist/core/image-overflow-recovery.js +97 -0
  402. package/packages/pi-coding-agent/dist/core/image-overflow-recovery.js.map +1 -0
  403. package/packages/pi-coding-agent/dist/core/image-overflow-recovery.test.d.ts +2 -0
  404. package/packages/pi-coding-agent/dist/core/image-overflow-recovery.test.d.ts.map +1 -0
  405. package/packages/pi-coding-agent/dist/core/image-overflow-recovery.test.js +181 -0
  406. package/packages/pi-coding-agent/dist/core/image-overflow-recovery.test.js.map +1 -0
  407. package/packages/pi-coding-agent/dist/core/index.d.ts +1 -1
  408. package/packages/pi-coding-agent/dist/core/index.d.ts.map +1 -1
  409. package/packages/pi-coding-agent/dist/core/index.js +1 -1
  410. package/packages/pi-coding-agent/dist/core/index.js.map +1 -1
  411. package/packages/pi-coding-agent/dist/core/lsp/index.d.ts.map +1 -1
  412. package/packages/pi-coding-agent/dist/core/lsp/index.js +3 -0
  413. package/packages/pi-coding-agent/dist/core/lsp/index.js.map +1 -1
  414. package/packages/pi-coding-agent/dist/core/lsp/lspmux.d.ts.map +1 -1
  415. package/packages/pi-coding-agent/dist/core/lsp/lspmux.js +3 -0
  416. package/packages/pi-coding-agent/dist/core/lsp/lspmux.js.map +1 -1
  417. package/packages/pi-coding-agent/dist/core/messages.d.ts.map +1 -1
  418. package/packages/pi-coding-agent/dist/core/messages.js +31 -2
  419. package/packages/pi-coding-agent/dist/core/messages.js.map +1 -1
  420. package/packages/pi-coding-agent/dist/core/messages.test.d.ts +9 -0
  421. package/packages/pi-coding-agent/dist/core/messages.test.d.ts.map +1 -0
  422. package/packages/pi-coding-agent/dist/core/messages.test.js +86 -0
  423. package/packages/pi-coding-agent/dist/core/messages.test.js.map +1 -0
  424. package/packages/pi-coding-agent/dist/core/model-resolver.d.ts.map +1 -1
  425. package/packages/pi-coding-agent/dist/core/model-resolver.js +1 -0
  426. package/packages/pi-coding-agent/dist/core/model-resolver.js.map +1 -1
  427. package/packages/pi-coding-agent/dist/core/resolve-config-value.d.ts +8 -0
  428. package/packages/pi-coding-agent/dist/core/resolve-config-value.d.ts.map +1 -1
  429. package/packages/pi-coding-agent/dist/core/resolve-config-value.js +23 -2
  430. package/packages/pi-coding-agent/dist/core/resolve-config-value.js.map +1 -1
  431. package/packages/pi-coding-agent/dist/core/resolve-config-value.test.js +89 -2
  432. package/packages/pi-coding-agent/dist/core/resolve-config-value.test.js.map +1 -1
  433. package/packages/pi-coding-agent/dist/core/resource-loader.d.ts +10 -0
  434. package/packages/pi-coding-agent/dist/core/resource-loader.d.ts.map +1 -1
  435. package/packages/pi-coding-agent/dist/core/resource-loader.js +12 -1
  436. package/packages/pi-coding-agent/dist/core/resource-loader.js.map +1 -1
  437. package/packages/pi-coding-agent/dist/core/retry-handler.d.ts +6 -0
  438. package/packages/pi-coding-agent/dist/core/retry-handler.d.ts.map +1 -1
  439. package/packages/pi-coding-agent/dist/core/retry-handler.js +48 -1
  440. package/packages/pi-coding-agent/dist/core/retry-handler.js.map +1 -1
  441. package/packages/pi-coding-agent/dist/core/retry-handler.test.d.ts +9 -0
  442. package/packages/pi-coding-agent/dist/core/retry-handler.test.d.ts.map +1 -0
  443. package/packages/pi-coding-agent/dist/core/retry-handler.test.js +193 -0
  444. package/packages/pi-coding-agent/dist/core/retry-handler.test.js.map +1 -0
  445. package/packages/pi-coding-agent/dist/core/settings-manager-security.test.d.ts +2 -0
  446. package/packages/pi-coding-agent/dist/core/settings-manager-security.test.d.ts.map +1 -0
  447. package/packages/pi-coding-agent/dist/core/settings-manager-security.test.js +83 -0
  448. package/packages/pi-coding-agent/dist/core/settings-manager-security.test.js.map +1 -0
  449. package/packages/pi-coding-agent/dist/core/settings-manager.d.ts +14 -0
  450. package/packages/pi-coding-agent/dist/core/settings-manager.d.ts.map +1 -1
  451. package/packages/pi-coding-agent/dist/core/settings-manager.js +36 -3
  452. package/packages/pi-coding-agent/dist/core/settings-manager.js.map +1 -1
  453. package/packages/pi-coding-agent/dist/core/tools/hashline-read.d.ts.map +1 -1
  454. package/packages/pi-coding-agent/dist/core/tools/hashline-read.js +10 -3
  455. package/packages/pi-coding-agent/dist/core/tools/hashline-read.js.map +1 -1
  456. package/packages/pi-coding-agent/dist/core/tools/read.d.ts.map +1 -1
  457. package/packages/pi-coding-agent/dist/core/tools/read.js +13 -4
  458. package/packages/pi-coding-agent/dist/core/tools/read.js.map +1 -1
  459. package/packages/pi-coding-agent/dist/core/tools/spawn-shell-windows.test.d.ts +16 -0
  460. package/packages/pi-coding-agent/dist/core/tools/spawn-shell-windows.test.d.ts.map +1 -0
  461. package/packages/pi-coding-agent/dist/core/tools/spawn-shell-windows.test.js +80 -0
  462. package/packages/pi-coding-agent/dist/core/tools/spawn-shell-windows.test.js.map +1 -0
  463. package/packages/pi-coding-agent/dist/index.d.ts +3 -2
  464. package/packages/pi-coding-agent/dist/index.d.ts.map +1 -1
  465. package/packages/pi-coding-agent/dist/index.js +2 -1
  466. package/packages/pi-coding-agent/dist/index.js.map +1 -1
  467. package/packages/pi-coding-agent/dist/modes/interactive/components/armin.d.ts +1 -1
  468. package/packages/pi-coding-agent/dist/modes/interactive/components/armin.d.ts.map +1 -1
  469. package/packages/pi-coding-agent/dist/modes/interactive/components/armin.js +9 -8
  470. package/packages/pi-coding-agent/dist/modes/interactive/components/armin.js.map +1 -1
  471. package/packages/pi-coding-agent/dist/modes/interactive/components/assistant-message.d.ts.map +1 -1
  472. package/packages/pi-coding-agent/dist/modes/interactive/components/assistant-message.js +0 -3
  473. package/packages/pi-coding-agent/dist/modes/interactive/components/assistant-message.js.map +1 -1
  474. package/packages/pi-coding-agent/dist/modes/interactive/components/bash-execution.d.ts +1 -0
  475. package/packages/pi-coding-agent/dist/modes/interactive/components/bash-execution.d.ts.map +1 -1
  476. package/packages/pi-coding-agent/dist/modes/interactive/components/bash-execution.js +2 -1
  477. package/packages/pi-coding-agent/dist/modes/interactive/components/bash-execution.js.map +1 -1
  478. package/packages/pi-coding-agent/dist/modes/interactive/components/bordered-loader.js +1 -1
  479. package/packages/pi-coding-agent/dist/modes/interactive/components/bordered-loader.js.map +1 -1
  480. package/packages/pi-coding-agent/dist/modes/interactive/components/branch-summary-message.js +1 -1
  481. package/packages/pi-coding-agent/dist/modes/interactive/components/branch-summary-message.js.map +1 -1
  482. package/packages/pi-coding-agent/dist/modes/interactive/components/compaction-summary-message.js +1 -1
  483. package/packages/pi-coding-agent/dist/modes/interactive/components/compaction-summary-message.js.map +1 -1
  484. package/packages/pi-coding-agent/dist/modes/interactive/components/config-selector.d.ts.map +1 -1
  485. package/packages/pi-coding-agent/dist/modes/interactive/components/config-selector.js +5 -2
  486. package/packages/pi-coding-agent/dist/modes/interactive/components/config-selector.js.map +1 -1
  487. package/packages/pi-coding-agent/dist/modes/interactive/components/countdown-timer.d.ts +1 -0
  488. package/packages/pi-coding-agent/dist/modes/interactive/components/countdown-timer.d.ts.map +1 -1
  489. package/packages/pi-coding-agent/dist/modes/interactive/components/countdown-timer.js +4 -0
  490. package/packages/pi-coding-agent/dist/modes/interactive/components/countdown-timer.js.map +1 -1
  491. package/packages/pi-coding-agent/dist/modes/interactive/components/custom-message.js +1 -1
  492. package/packages/pi-coding-agent/dist/modes/interactive/components/custom-message.js.map +1 -1
  493. package/packages/pi-coding-agent/dist/modes/interactive/components/daxnuts.d.ts +1 -1
  494. package/packages/pi-coding-agent/dist/modes/interactive/components/daxnuts.d.ts.map +1 -1
  495. package/packages/pi-coding-agent/dist/modes/interactive/components/daxnuts.js +4 -2
  496. package/packages/pi-coding-agent/dist/modes/interactive/components/daxnuts.js.map +1 -1
  497. package/packages/pi-coding-agent/dist/modes/interactive/components/diff.js +2 -2
  498. package/packages/pi-coding-agent/dist/modes/interactive/components/diff.js.map +1 -1
  499. package/packages/pi-coding-agent/dist/modes/interactive/components/dynamic-border.d.ts.map +1 -1
  500. package/packages/pi-coding-agent/dist/modes/interactive/components/dynamic-border.js +8 -1
  501. package/packages/pi-coding-agent/dist/modes/interactive/components/dynamic-border.js.map +1 -1
  502. package/packages/pi-coding-agent/dist/modes/interactive/components/extension-input.d.ts.map +1 -1
  503. package/packages/pi-coding-agent/dist/modes/interactive/components/extension-input.js +2 -0
  504. package/packages/pi-coding-agent/dist/modes/interactive/components/extension-input.js.map +1 -1
  505. package/packages/pi-coding-agent/dist/modes/interactive/components/extension-selector.d.ts.map +1 -1
  506. package/packages/pi-coding-agent/dist/modes/interactive/components/extension-selector.js +4 -0
  507. package/packages/pi-coding-agent/dist/modes/interactive/components/extension-selector.js.map +1 -1
  508. package/packages/pi-coding-agent/dist/modes/interactive/components/footer.d.ts.map +1 -1
  509. package/packages/pi-coding-agent/dist/modes/interactive/components/footer.js +26 -12
  510. package/packages/pi-coding-agent/dist/modes/interactive/components/footer.js.map +1 -1
  511. package/packages/pi-coding-agent/dist/modes/interactive/components/oauth-selector.js +4 -4
  512. package/packages/pi-coding-agent/dist/modes/interactive/components/oauth-selector.js.map +1 -1
  513. package/packages/pi-coding-agent/dist/modes/interactive/components/provider-manager.d.ts +3 -0
  514. package/packages/pi-coding-agent/dist/modes/interactive/components/provider-manager.d.ts.map +1 -1
  515. package/packages/pi-coding-agent/dist/modes/interactive/components/provider-manager.js +46 -14
  516. package/packages/pi-coding-agent/dist/modes/interactive/components/provider-manager.js.map +1 -1
  517. package/packages/pi-coding-agent/dist/modes/interactive/components/scoped-models-selector.d.ts.map +1 -1
  518. package/packages/pi-coding-agent/dist/modes/interactive/components/scoped-models-selector.js +2 -8
  519. package/packages/pi-coding-agent/dist/modes/interactive/components/scoped-models-selector.js.map +1 -1
  520. package/packages/pi-coding-agent/dist/modes/interactive/components/session-selector.js +4 -4
  521. package/packages/pi-coding-agent/dist/modes/interactive/components/session-selector.js.map +1 -1
  522. package/packages/pi-coding-agent/dist/modes/interactive/components/skill-invocation-message.js +2 -2
  523. package/packages/pi-coding-agent/dist/modes/interactive/components/skill-invocation-message.js.map +1 -1
  524. package/packages/pi-coding-agent/dist/modes/interactive/components/tool-execution.d.ts.map +1 -1
  525. package/packages/pi-coding-agent/dist/modes/interactive/components/tool-execution.js +8 -3
  526. package/packages/pi-coding-agent/dist/modes/interactive/components/tool-execution.js.map +1 -1
  527. package/packages/pi-coding-agent/dist/modes/interactive/components/user-message-selector.d.ts.map +1 -1
  528. package/packages/pi-coding-agent/dist/modes/interactive/components/user-message-selector.js +3 -2
  529. package/packages/pi-coding-agent/dist/modes/interactive/components/user-message-selector.js.map +1 -1
  530. package/packages/pi-coding-agent/dist/modes/interactive/controllers/chat-controller.d.ts.map +1 -1
  531. package/packages/pi-coding-agent/dist/modes/interactive/controllers/chat-controller.js +19 -1
  532. package/packages/pi-coding-agent/dist/modes/interactive/controllers/chat-controller.js.map +1 -1
  533. package/packages/pi-coding-agent/dist/modes/interactive/controllers/input-controller.d.ts +1 -0
  534. package/packages/pi-coding-agent/dist/modes/interactive/controllers/input-controller.d.ts.map +1 -1
  535. package/packages/pi-coding-agent/dist/modes/interactive/controllers/input-controller.js +22 -1
  536. package/packages/pi-coding-agent/dist/modes/interactive/controllers/input-controller.js.map +1 -1
  537. package/packages/pi-coding-agent/dist/modes/interactive/controllers/input-controller.test.d.ts +2 -0
  538. package/packages/pi-coding-agent/dist/modes/interactive/controllers/input-controller.test.d.ts.map +1 -0
  539. package/packages/pi-coding-agent/dist/modes/interactive/controllers/input-controller.test.js +122 -0
  540. package/packages/pi-coding-agent/dist/modes/interactive/controllers/input-controller.test.js.map +1 -0
  541. package/packages/pi-coding-agent/dist/modes/interactive/interactive-mode.d.ts +2 -0
  542. package/packages/pi-coding-agent/dist/modes/interactive/interactive-mode.d.ts.map +1 -1
  543. package/packages/pi-coding-agent/dist/modes/interactive/interactive-mode.js +57 -4
  544. package/packages/pi-coding-agent/dist/modes/interactive/interactive-mode.js.map +1 -1
  545. package/packages/pi-coding-agent/dist/modes/interactive/slash-command-handlers.js +1 -1
  546. package/packages/pi-coding-agent/dist/modes/interactive/slash-command-handlers.js.map +1 -1
  547. package/packages/pi-coding-agent/dist/modes/interactive/theme/themes.js +1 -1
  548. package/packages/pi-coding-agent/dist/modes/interactive/theme/themes.js.map +1 -1
  549. package/packages/pi-coding-agent/dist/modes/rpc/remote-terminal.d.ts +1 -0
  550. package/packages/pi-coding-agent/dist/modes/rpc/remote-terminal.d.ts.map +1 -1
  551. package/packages/pi-coding-agent/dist/modes/rpc/remote-terminal.js +5 -0
  552. package/packages/pi-coding-agent/dist/modes/rpc/remote-terminal.js.map +1 -1
  553. package/packages/pi-coding-agent/package.json +1 -1
  554. package/packages/pi-coding-agent/src/core/agent-session.ts +38 -1
  555. package/packages/pi-coding-agent/src/core/compaction/compaction.test.ts +236 -0
  556. package/packages/pi-coding-agent/src/core/compaction/compaction.ts +94 -1
  557. package/packages/pi-coding-agent/src/core/exec.ts +3 -1
  558. package/packages/pi-coding-agent/src/core/extensions/extension-manifest.test.ts +77 -0
  559. package/packages/pi-coding-agent/src/core/extensions/extension-manifest.ts +62 -0
  560. package/packages/pi-coding-agent/src/core/extensions/extension-sort.test.ts +134 -0
  561. package/packages/pi-coding-agent/src/core/extensions/extension-sort.ts +137 -0
  562. package/packages/pi-coding-agent/src/core/extensions/index.ts +4 -0
  563. package/packages/pi-coding-agent/src/core/extensions/loader.ts +5 -0
  564. package/packages/pi-coding-agent/src/core/image-overflow-recovery.test.ts +228 -0
  565. package/packages/pi-coding-agent/src/core/image-overflow-recovery.ts +118 -0
  566. package/packages/pi-coding-agent/src/core/index.ts +6 -0
  567. package/packages/pi-coding-agent/src/core/lsp/index.ts +3 -0
  568. package/packages/pi-coding-agent/src/core/lsp/lspmux.ts +3 -0
  569. package/packages/pi-coding-agent/src/core/messages.test.ts +114 -0
  570. package/packages/pi-coding-agent/src/core/messages.ts +29 -2
  571. package/packages/pi-coding-agent/src/core/model-resolver.ts +1 -0
  572. package/packages/pi-coding-agent/src/core/resolve-config-value.test.ts +111 -1
  573. package/packages/pi-coding-agent/src/core/resolve-config-value.ts +26 -2
  574. package/packages/pi-coding-agent/src/core/resource-loader.ts +20 -1
  575. package/packages/pi-coding-agent/src/core/retry-handler.test.ts +255 -0
  576. package/packages/pi-coding-agent/src/core/retry-handler.ts +52 -1
  577. package/packages/pi-coding-agent/src/core/settings-manager-security.test.ts +102 -0
  578. package/packages/pi-coding-agent/src/core/settings-manager.ts +44 -3
  579. package/packages/pi-coding-agent/src/core/tools/hashline-read.ts +11 -3
  580. package/packages/pi-coding-agent/src/core/tools/read.ts +14 -4
  581. package/packages/pi-coding-agent/src/core/tools/spawn-shell-windows.test.ts +92 -0
  582. package/packages/pi-coding-agent/src/index.ts +11 -0
  583. package/packages/pi-coding-agent/src/modes/interactive/components/armin.ts +9 -9
  584. package/packages/pi-coding-agent/src/modes/interactive/components/assistant-message.ts +0 -2
  585. package/packages/pi-coding-agent/src/modes/interactive/components/bash-execution.ts +3 -1
  586. package/packages/pi-coding-agent/src/modes/interactive/components/bordered-loader.ts +1 -1
  587. package/packages/pi-coding-agent/src/modes/interactive/components/branch-summary-message.ts +1 -1
  588. package/packages/pi-coding-agent/src/modes/interactive/components/compaction-summary-message.ts +1 -1
  589. package/packages/pi-coding-agent/src/modes/interactive/components/config-selector.ts +7 -2
  590. package/packages/pi-coding-agent/src/modes/interactive/components/countdown-timer.ts +3 -0
  591. package/packages/pi-coding-agent/src/modes/interactive/components/custom-message.ts +1 -1
  592. package/packages/pi-coding-agent/src/modes/interactive/components/daxnuts.ts +4 -3
  593. package/packages/pi-coding-agent/src/modes/interactive/components/diff.ts +2 -2
  594. package/packages/pi-coding-agent/src/modes/interactive/components/dynamic-border.ts +3 -1
  595. package/packages/pi-coding-agent/src/modes/interactive/components/extension-input.ts +1 -0
  596. package/packages/pi-coding-agent/src/modes/interactive/components/extension-selector.ts +4 -0
  597. package/packages/pi-coding-agent/src/modes/interactive/components/footer.ts +27 -13
  598. package/packages/pi-coding-agent/src/modes/interactive/components/oauth-selector.ts +4 -4
  599. package/packages/pi-coding-agent/src/modes/interactive/components/provider-manager.ts +45 -14
  600. package/packages/pi-coding-agent/src/modes/interactive/components/scoped-models-selector.ts +2 -7
  601. package/packages/pi-coding-agent/src/modes/interactive/components/session-selector.ts +4 -4
  602. package/packages/pi-coding-agent/src/modes/interactive/components/skill-invocation-message.ts +2 -2
  603. package/packages/pi-coding-agent/src/modes/interactive/components/tool-execution.ts +8 -3
  604. package/packages/pi-coding-agent/src/modes/interactive/components/user-message-selector.ts +3 -2
  605. package/packages/pi-coding-agent/src/modes/interactive/controllers/chat-controller.ts +24 -1
  606. package/packages/pi-coding-agent/src/modes/interactive/controllers/input-controller.test.ts +156 -0
  607. package/packages/pi-coding-agent/src/modes/interactive/controllers/input-controller.ts +21 -1
  608. package/packages/pi-coding-agent/src/modes/interactive/interactive-mode.ts +73 -3
  609. package/packages/pi-coding-agent/src/modes/interactive/slash-command-handlers.ts +1 -1
  610. package/packages/pi-coding-agent/src/modes/interactive/theme/themes.ts +1 -1
  611. package/packages/pi-coding-agent/src/modes/rpc/remote-terminal.ts +6 -0
  612. package/packages/pi-tui/dist/terminal.d.ts +2 -0
  613. package/packages/pi-tui/dist/terminal.d.ts.map +1 -1
  614. package/packages/pi-tui/dist/terminal.js +9 -0
  615. package/packages/pi-tui/dist/terminal.js.map +1 -1
  616. package/packages/pi-tui/dist/tui.d.ts.map +1 -1
  617. package/packages/pi-tui/dist/tui.js +9 -0
  618. package/packages/pi-tui/dist/tui.js.map +1 -1
  619. package/packages/pi-tui/src/terminal.ts +14 -0
  620. package/packages/pi-tui/src/tui.ts +8 -0
  621. package/pkg/dist/modes/interactive/theme/themes.js +1 -1
  622. package/pkg/dist/modes/interactive/theme/themes.js.map +1 -1
  623. package/pkg/package.json +1 -1
  624. package/scripts/ensure-workspace-builds.cjs +45 -14
  625. package/src/resources/agents/researcher.md +1 -1
  626. package/src/resources/extensions/ask-user-questions.ts +21 -3
  627. package/src/resources/extensions/async-jobs/extension-manifest.json +1 -1
  628. package/src/resources/extensions/bg-shell/extension-manifest.json +1 -1
  629. package/src/resources/extensions/browser-tools/extension-manifest.json +1 -1
  630. package/src/resources/extensions/claude-code-cli/partial-builder.ts +13 -6
  631. package/src/resources/extensions/claude-code-cli/stream-adapter.ts +63 -35
  632. package/src/resources/extensions/claude-code-cli/tests/partial-builder.test.ts +28 -0
  633. package/src/resources/extensions/claude-code-cli/tests/stream-adapter.test.ts +108 -1
  634. package/src/resources/extensions/context7/extension-manifest.json +1 -1
  635. package/src/resources/extensions/get-secrets-from-user.ts +8 -5
  636. package/src/resources/extensions/google-search/extension-manifest.json +1 -1
  637. package/src/resources/extensions/google-search/index.ts +2 -1
  638. package/src/resources/extensions/gsd/auto/loop-deps.ts +1 -0
  639. package/src/resources/extensions/gsd/auto/phases.ts +43 -34
  640. package/src/resources/extensions/gsd/auto-artifact-paths.ts +2 -2
  641. package/src/resources/extensions/gsd/auto-dashboard.ts +37 -19
  642. package/src/resources/extensions/gsd/auto-dispatch.ts +18 -2
  643. package/src/resources/extensions/gsd/auto-model-selection.ts +26 -5
  644. package/src/resources/extensions/gsd/auto-post-unit.ts +18 -4
  645. package/src/resources/extensions/gsd/auto-prompts.ts +1 -1
  646. package/src/resources/extensions/gsd/auto-recovery.ts +12 -5
  647. package/src/resources/extensions/gsd/auto-start.ts +35 -26
  648. package/src/resources/extensions/gsd/auto-worktree.ts +193 -9
  649. package/src/resources/extensions/gsd/bootstrap/agent-end-recovery.ts +31 -0
  650. package/src/resources/extensions/gsd/bootstrap/db-tools.ts +85 -8
  651. package/src/resources/extensions/gsd/bootstrap/dynamic-tools.ts +38 -1
  652. package/src/resources/extensions/gsd/bootstrap/register-hooks.ts +41 -35
  653. package/src/resources/extensions/gsd/bootstrap/system-context.ts +72 -12
  654. package/src/resources/extensions/gsd/bootstrap/write-gate.ts +75 -0
  655. package/src/resources/extensions/gsd/captures.ts +63 -3
  656. package/src/resources/extensions/gsd/codebase-generator.ts +351 -0
  657. package/src/resources/extensions/gsd/commands/catalog.ts +10 -1
  658. package/src/resources/extensions/gsd/commands/handlers/ops.ts +5 -0
  659. package/src/resources/extensions/gsd/commands-codebase.ts +164 -0
  660. package/src/resources/extensions/gsd/commands-prefs-wizard.ts +46 -4
  661. package/src/resources/extensions/gsd/complexity-classifier.ts +8 -6
  662. package/src/resources/extensions/gsd/db-writer.ts +140 -7
  663. package/src/resources/extensions/gsd/doctor-git-checks.ts +75 -1
  664. package/src/resources/extensions/gsd/doctor-proactive.ts +35 -1
  665. package/src/resources/extensions/gsd/doctor-providers.ts +2 -1
  666. package/src/resources/extensions/gsd/doctor-runtime-checks.ts +5 -4
  667. package/src/resources/extensions/gsd/doctor-types.ts +2 -0
  668. package/src/resources/extensions/gsd/doctor.ts +3 -1
  669. package/src/resources/extensions/gsd/error-classifier.ts +13 -11
  670. package/src/resources/extensions/gsd/extension-manifest.json +16 -1
  671. package/src/resources/extensions/gsd/forensics.ts +144 -20
  672. package/src/resources/extensions/gsd/git-service.ts +119 -3
  673. package/src/resources/extensions/gsd/gitignore.ts +33 -0
  674. package/src/resources/extensions/gsd/gsd-db.ts +43 -7
  675. package/src/resources/extensions/gsd/guided-flow.ts +114 -45
  676. package/src/resources/extensions/gsd/health-widget-core.ts +34 -0
  677. package/src/resources/extensions/gsd/health-widget.ts +17 -0
  678. package/src/resources/extensions/gsd/index.ts +1 -0
  679. package/src/resources/extensions/gsd/memory-extractor.ts +8 -0
  680. package/src/resources/extensions/gsd/migrate-external.ts +9 -1
  681. package/src/resources/extensions/gsd/milestone-validation-gates.ts +56 -0
  682. package/src/resources/extensions/gsd/model-cost-table.ts +19 -0
  683. package/src/resources/extensions/gsd/model-router.ts +35 -1
  684. package/src/resources/extensions/gsd/native-git-bridge.ts +41 -0
  685. package/src/resources/extensions/gsd/notifications.ts +16 -0
  686. package/src/resources/extensions/gsd/parallel-eligibility.ts +15 -2
  687. package/src/resources/extensions/gsd/parallel-merge.ts +87 -4
  688. package/src/resources/extensions/gsd/parsers-legacy.ts +22 -3
  689. package/src/resources/extensions/gsd/paths.ts +44 -0
  690. package/src/resources/extensions/gsd/preferences-models.ts +14 -1
  691. package/src/resources/extensions/gsd/preferences-types.ts +10 -1
  692. package/src/resources/extensions/gsd/preferences.ts +13 -15
  693. package/src/resources/extensions/gsd/prompt-loader.ts +4 -1
  694. package/src/resources/extensions/gsd/prompts/complete-milestone.md +1 -1
  695. package/src/resources/extensions/gsd/prompts/complete-slice.md +4 -2
  696. package/src/resources/extensions/gsd/prompts/discuss-headless.md +1 -1
  697. package/src/resources/extensions/gsd/prompts/discuss.md +1 -1
  698. package/src/resources/extensions/gsd/prompts/execute-task.md +3 -1
  699. package/src/resources/extensions/gsd/prompts/forensics.md +2 -2
  700. package/src/resources/extensions/gsd/prompts/guided-discuss-milestone.md +1 -1
  701. package/src/resources/extensions/gsd/prompts/guided-discuss-slice.md +1 -1
  702. package/src/resources/extensions/gsd/prompts/plan-slice.md +2 -0
  703. package/src/resources/extensions/gsd/prompts/rethink.md +1 -1
  704. package/src/resources/extensions/gsd/prompts/triage-captures.md +1 -0
  705. package/src/resources/extensions/gsd/repo-identity.ts +186 -11
  706. package/src/resources/extensions/gsd/rethink.ts +6 -0
  707. package/src/resources/extensions/gsd/roadmap-slices.ts +5 -4
  708. package/src/resources/extensions/gsd/state.ts +84 -32
  709. package/src/resources/extensions/gsd/tests/auto-loop.test.ts +29 -0
  710. package/src/resources/extensions/gsd/tests/auto-mode-interactive-guard.test.ts +71 -0
  711. package/src/resources/extensions/gsd/tests/auto-model-selection.test.ts +71 -1
  712. package/src/resources/extensions/gsd/tests/captures.test.ts +103 -0
  713. package/src/resources/extensions/gsd/tests/cli-provider-rate-limit.test.ts +47 -0
  714. package/src/resources/extensions/gsd/tests/codebase-generator.test.ts +488 -0
  715. package/src/resources/extensions/gsd/tests/complete-milestone.test.ts +27 -0
  716. package/src/resources/extensions/gsd/tests/complete-slice.test.ts +21 -0
  717. package/src/resources/extensions/gsd/tests/completion-hierarchy-guards.test.ts +192 -0
  718. package/src/resources/extensions/gsd/tests/complexity-classifier.test.ts +4 -4
  719. package/src/resources/extensions/gsd/tests/db-path-worktree-symlink.test.ts +131 -0
  720. package/src/resources/extensions/gsd/tests/db-writer.test.ts +7 -12
  721. package/src/resources/extensions/gsd/tests/derive-state-db.test.ts +78 -5
  722. package/src/resources/extensions/gsd/tests/derive-state.test.ts +29 -0
  723. package/src/resources/extensions/gsd/tests/discord-invite-links.test.ts +47 -0
  724. package/src/resources/extensions/gsd/tests/discuss-empty-db-fallback.test.ts +127 -0
  725. package/src/resources/extensions/gsd/tests/discuss-queued-milestones.test.ts +40 -0
  726. package/src/resources/extensions/gsd/tests/dist-redirect.mjs +20 -1
  727. package/src/resources/extensions/gsd/tests/doctor-providers.test.ts +117 -0
  728. package/src/resources/extensions/gsd/tests/dynamic-routing-default.test.ts +20 -0
  729. package/src/resources/extensions/gsd/tests/empty-content-abort-loop.test.ts +74 -0
  730. package/src/resources/extensions/gsd/tests/event-replay-idempotency.test.ts +140 -0
  731. package/src/resources/extensions/gsd/tests/forensics-context-persist.test.ts +129 -0
  732. package/src/resources/extensions/gsd/tests/forensics-db-completion.test.ts +96 -0
  733. package/src/resources/extensions/gsd/tests/forensics-dedup.test.ts +31 -0
  734. package/src/resources/extensions/gsd/tests/gsd-tools.test.ts +125 -12
  735. package/src/resources/extensions/gsd/tests/gsdroot-worktree-detection.test.ts +164 -0
  736. package/src/resources/extensions/gsd/tests/guided-flow-dynamic-routing.test.ts +135 -0
  737. package/src/resources/extensions/gsd/tests/guided-flow-session-isolation.test.ts +97 -0
  738. package/src/resources/extensions/gsd/tests/health-widget.test.ts +67 -0
  739. package/src/resources/extensions/gsd/tests/hook-key-parsing.test.ts +107 -0
  740. package/src/resources/extensions/gsd/tests/integration/auto-recovery.test.ts +111 -1
  741. package/src/resources/extensions/gsd/tests/integration/auto-worktree-milestone-merge.test.ts +134 -0
  742. package/src/resources/extensions/gsd/tests/integration/auto-worktree.test.ts +59 -0
  743. package/src/resources/extensions/gsd/tests/integration/doctor-false-positives.test.ts +243 -0
  744. package/src/resources/extensions/gsd/tests/integration/doctor-git.test.ts +72 -0
  745. package/src/resources/extensions/gsd/tests/integration/git-service.test.ts +68 -0
  746. package/src/resources/extensions/gsd/tests/integration/gitignore-staging-2570.test.ts +150 -0
  747. package/src/resources/extensions/gsd/tests/integration/parallel-merge.test.ts +110 -0
  748. package/src/resources/extensions/gsd/tests/integration/run-uat.test.ts +1 -1
  749. package/src/resources/extensions/gsd/tests/integration/state-machine-live-validation.test.ts +959 -0
  750. package/src/resources/extensions/gsd/tests/memory-extractor.test.ts +85 -2
  751. package/src/resources/extensions/gsd/tests/migrate-external-worktree.test.ts +105 -0
  752. package/src/resources/extensions/gsd/tests/milestone-status-authoritative.test.ts +116 -0
  753. package/src/resources/extensions/gsd/tests/model-cost-table.test.ts +34 -0
  754. package/src/resources/extensions/gsd/tests/model-router.test.ts +68 -3
  755. package/src/resources/extensions/gsd/tests/model-unittype-mapping.test.ts +28 -0
  756. package/src/resources/extensions/gsd/tests/notifications.test.ts +45 -0
  757. package/src/resources/extensions/gsd/tests/parallel-commit-scope.test.ts +159 -0
  758. package/src/resources/extensions/gsd/tests/parallel-eligibility-ghost.test.ts +150 -0
  759. package/src/resources/extensions/gsd/tests/plan-milestone-title.test.ts +70 -0
  760. package/src/resources/extensions/gsd/tests/plan-milestone.test.ts +33 -1
  761. package/src/resources/extensions/gsd/tests/project-relocation-recovery.test.ts +297 -0
  762. package/src/resources/extensions/gsd/tests/prompt-contracts.test.ts +29 -0
  763. package/src/resources/extensions/gsd/tests/prompt-loader-replacement.test.ts +178 -0
  764. package/src/resources/extensions/gsd/tests/prompt-tool-names.test.ts +69 -0
  765. package/src/resources/extensions/gsd/tests/provider-errors.test.ts +38 -0
  766. package/src/resources/extensions/gsd/tests/queue-execution-guard.test.ts +157 -0
  767. package/src/resources/extensions/gsd/tests/quick-turn-end-cleanup.test.ts +90 -0
  768. package/src/resources/extensions/gsd/tests/reassess-handler.test.ts +117 -0
  769. package/src/resources/extensions/gsd/tests/reconciliation-edge-cases.test.ts +162 -0
  770. package/src/resources/extensions/gsd/tests/roadmap-slices.test.ts +97 -0
  771. package/src/resources/extensions/gsd/tests/secure-env-collect.test.ts +134 -0
  772. package/src/resources/extensions/gsd/tests/slice-disk-reconcile.test.ts +233 -0
  773. package/src/resources/extensions/gsd/tests/stash-queued-context-files.test.ts +305 -0
  774. package/src/resources/extensions/gsd/tests/state-corruption-2945.test.ts +405 -0
  775. package/src/resources/extensions/gsd/tests/state-derivation-parity.test.ts +257 -0
  776. package/src/resources/extensions/gsd/tests/state-machine-full-walkthrough.test.ts +1628 -0
  777. package/src/resources/extensions/gsd/tests/stop-auto-race-null-unit.test.ts +106 -0
  778. package/src/resources/extensions/gsd/tests/stuck-detection-coverage.test.ts +174 -0
  779. package/src/resources/extensions/gsd/tests/summary-render-parity.test.ts +221 -0
  780. package/src/resources/extensions/gsd/tests/terminated-transient.test.ts +44 -0
  781. package/src/resources/extensions/gsd/tests/tool-naming.test.ts +2 -1
  782. package/src/resources/extensions/gsd/tests/triage-resolution.test.ts +8 -0
  783. package/src/resources/extensions/gsd/tests/uat-stuck-loop-orphaned-worktree.test.ts +289 -0
  784. package/src/resources/extensions/gsd/tests/unit-ownership.test.ts +100 -17
  785. package/src/resources/extensions/gsd/tests/vacuum-recovery.test.ts +154 -0
  786. package/src/resources/extensions/gsd/tests/validate-milestone-write-order.test.ts +4 -1
  787. package/src/resources/extensions/gsd/tests/verdict-parser.test.ts +156 -0
  788. package/src/resources/extensions/gsd/tests/verification-operational-gate.test.ts +82 -0
  789. package/src/resources/extensions/gsd/tests/workflow-logger.test.ts +48 -0
  790. package/src/resources/extensions/gsd/tests/workflow-manifest.test.ts +92 -0
  791. package/src/resources/extensions/gsd/tests/workflow-projections.test.ts +4 -2
  792. package/src/resources/extensions/gsd/tests/worktree-db-respawn-truncation.test.ts +140 -0
  793. package/src/resources/extensions/gsd/tests/worktree-nested-git-safety.test.ts +101 -0
  794. package/src/resources/extensions/gsd/tests/worktree-resolver.test.ts +48 -1
  795. package/src/resources/extensions/gsd/tests/worktree-sync-milestones.test.ts +29 -5
  796. package/src/resources/extensions/gsd/tests/zombie-gsd-state.test.ts +95 -0
  797. package/src/resources/extensions/gsd/tools/complete-task.ts +36 -74
  798. package/src/resources/extensions/gsd/tools/plan-milestone.ts +13 -1
  799. package/src/resources/extensions/gsd/tools/reassess-roadmap.ts +36 -0
  800. package/src/resources/extensions/gsd/tools/validate-milestone.ts +20 -2
  801. package/src/resources/extensions/gsd/triage-resolution.ts +23 -6
  802. package/src/resources/extensions/gsd/types.ts +4 -2
  803. package/src/resources/extensions/gsd/undo.ts +2 -2
  804. package/src/resources/extensions/gsd/unit-ownership.ts +206 -35
  805. package/src/resources/extensions/gsd/verdict-parser.ts +21 -6
  806. package/src/resources/extensions/gsd/watch/header-renderer.ts +275 -0
  807. package/src/resources/extensions/gsd/workflow-logger.ts +3 -1
  808. package/src/resources/extensions/gsd/workflow-manifest.ts +22 -5
  809. package/src/resources/extensions/gsd/workflow-projections.ts +97 -64
  810. package/src/resources/extensions/gsd/workflow-reconcile.ts +39 -10
  811. package/src/resources/extensions/gsd/workspace-index.ts +30 -0
  812. package/src/resources/extensions/gsd/worktree-manager.ts +120 -1
  813. package/src/resources/extensions/gsd/worktree-resolver.ts +22 -3
  814. package/src/resources/extensions/mcp-client/index.ts +13 -7
  815. package/src/resources/extensions/mcp-client/tests/server-name-spaces.test.ts +55 -0
  816. package/src/resources/extensions/ollama/index.ts +130 -0
  817. package/src/resources/extensions/ollama/model-capabilities.ts +145 -0
  818. package/src/resources/extensions/ollama/ollama-client.ts +196 -0
  819. package/src/resources/extensions/ollama/ollama-commands.ts +248 -0
  820. package/src/resources/extensions/ollama/ollama-discovery.ts +106 -0
  821. package/src/resources/extensions/ollama/ollama-tool.ts +218 -0
  822. package/src/resources/extensions/ollama/tests/model-capabilities.test.ts +162 -0
  823. package/src/resources/extensions/ollama/tests/ollama-client.test.ts +38 -0
  824. package/src/resources/extensions/ollama/tests/ollama-discovery.test.ts +28 -0
  825. package/src/resources/extensions/ollama/types.ts +130 -0
  826. package/src/resources/extensions/search-the-web/extension-manifest.json +1 -1
  827. package/src/resources/extensions/search-the-web/url-utils.ts +19 -0
  828. package/src/resources/extensions/shared/interview-ui.ts +12 -1
  829. package/src/resources/extensions/shared/tests/ask-user-freetext.test.ts +156 -0
  830. package/src/resources/skills/btw/SKILL.md +42 -0
  831. package/src/resources/skills/create-gsd-extension/SKILL.md +5 -3
  832. package/src/resources/skills/create-gsd-extension/references/key-rules-gotchas.md +5 -4
  833. package/src/resources/skills/create-gsd-extension/workflows/add-capability.md +2 -2
  834. package/src/resources/skills/create-gsd-extension/workflows/create-extension.md +4 -4
  835. package/src/resources/skills/create-gsd-extension/workflows/debug-extension.md +5 -3
  836. package/dist/web/standalone/.next/static/chunks/6502.8b732f67a11b11b4.js +0 -9
  837. package/dist/web/standalone/.next/static/chunks/app/page-62be3b5fa91e4c8f.js +0 -1
  838. package/dist/web/standalone/.next/static/chunks/main-app-d3d4c336195465f9.js +0 -1
  839. package/dist/web/standalone/.next/static/chunks/next/dist/client/components/builtin/global-error-ab5a8926e07ec673.js +0 -1
  840. package/dist/web/standalone/.next/static/css/a58ef8a151aa0493.css +0 -1
  841. package/src/resources/extensions/gsd/tests/empty-db-reconciliation.test.ts +0 -79
  842. /package/dist/web/standalone/.next/static/{IoheXIe-5DH7ieX8AUo8U → QlWL-8CXgQpzV3ehkNMzh}/_buildManifest.js +0 -0
  843. /package/dist/web/standalone/.next/static/{IoheXIe-5DH7ieX8AUo8U → QlWL-8CXgQpzV3ehkNMzh}/_ssgManifest.js +0 -0
@@ -0,0 +1,959 @@
1
+ /**
2
+ * state-machine-live-validation.test.ts — Live operational validation of the
3
+ * GSD state machine with real handlers, real DB, and real filesystem.
4
+ *
5
+ * Exercises every phase transition, completion guard, edge case, and reopen
6
+ * path end-to-end. This is NOT a unit test — it drives the actual tool handlers
7
+ * against a real temp directory with a real SQLite database.
8
+ *
9
+ * Findings reference: #3161 (state machine validation report)
10
+ */
11
+
12
+ // GSD State Machine Live Validation (#3161)
13
+
14
+ import { describe, test, beforeEach, afterEach } from "node:test";
15
+ import assert from "node:assert/strict";
16
+ import {
17
+ mkdtempSync,
18
+ mkdirSync,
19
+ writeFileSync,
20
+ readFileSync,
21
+ rmSync,
22
+ existsSync,
23
+ } from "node:fs";
24
+ import { tmpdir } from "node:os";
25
+ import { join } from "node:path";
26
+
27
+ // ── DB layer ──────────────────────────────────────────────────────────────
28
+ import {
29
+ openDatabase,
30
+ closeDatabase,
31
+ insertMilestone,
32
+ insertSlice,
33
+ insertTask,
34
+ getTask,
35
+ getSlice,
36
+ getMilestone,
37
+ getSliceTasks,
38
+ getMilestoneSlices,
39
+ updateTaskStatus,
40
+ updateSliceStatus,
41
+ updateMilestoneStatus,
42
+ } from "../../gsd-db.ts";
43
+
44
+ // ── Tool handlers ─────────────────────────────────────────────────────────
45
+ import { handleCompleteTask } from "../../tools/complete-task.ts";
46
+ import { handleCompleteSlice } from "../../tools/complete-slice.ts";
47
+ import { handleCompleteMilestone } from "../../tools/complete-milestone.ts";
48
+ import { handleReopenTask } from "../../tools/reopen-task.ts";
49
+ import { handleReopenSlice } from "../../tools/reopen-slice.ts";
50
+
51
+ // ── State derivation ──────────────────────────────────────────────────────
52
+ import {
53
+ deriveState,
54
+ deriveStateFromDb,
55
+ invalidateStateCache,
56
+ isGhostMilestone,
57
+ } from "../../state.ts";
58
+
59
+ // ── Status guards ─────────────────────────────────────────────────────────
60
+ import { isClosedStatus } from "../../status-guards.ts";
61
+
62
+ // ── Events ────────────────────────────────────────────────────────────────
63
+ import { readEvents } from "../../workflow-events.ts";
64
+
65
+ // ── Cache invalidation ───────────────────────────────────────────────────
66
+ import { invalidateAllCaches } from "../../cache.ts";
67
+
68
+ // ═══════════════════════════════════════════════════════════════════════════
69
+ // Fixture Helpers
70
+ // ═══════════════════════════════════════════════════════════════════════════
71
+
72
+ function makeTempDir(): string {
73
+ return mkdtempSync(join(tmpdir(), "gsd-live-validation-"));
74
+ }
75
+
76
+ /**
77
+ * Create a realistic .gsd/ fixture with:
78
+ * - M001 milestone with ROADMAP, CONTEXT
79
+ * - S01 slice with PLAN (2 tasks T01, T02)
80
+ * - S02 slice with PLAN (1 task T01)
81
+ * - Task PLAN stubs for each task
82
+ * - REQUIREMENTS.md and DECISIONS.md
83
+ */
84
+ function createFullFixture(): string {
85
+ const base = makeTempDir();
86
+ const gsdDir = join(base, ".gsd");
87
+ const m001Dir = join(gsdDir, "milestones", "M001");
88
+ const s01Dir = join(m001Dir, "slices", "S01");
89
+ const s01Tasks = join(s01Dir, "tasks");
90
+ const s02Dir = join(m001Dir, "slices", "S02");
91
+ const s02Tasks = join(s02Dir, "tasks");
92
+
93
+ mkdirSync(s01Tasks, { recursive: true });
94
+ mkdirSync(s02Tasks, { recursive: true });
95
+
96
+ // CONTEXT.md — needed to get past needs-discussion
97
+ writeFileSync(
98
+ join(m001Dir, "M001-CONTEXT.md"),
99
+ [
100
+ "# M001: Live Validation Milestone",
101
+ "",
102
+ "## Purpose",
103
+ "Validate the state machine end-to-end.",
104
+ ].join("\n"),
105
+ );
106
+
107
+ // ROADMAP.md
108
+ writeFileSync(
109
+ join(m001Dir, "M001-ROADMAP.md"),
110
+ [
111
+ "# M001: Live Validation Milestone",
112
+ "",
113
+ "## Vision",
114
+ "Prove state machine correctness.",
115
+ "",
116
+ "## Success Criteria",
117
+ "- All operations succeed",
118
+ "",
119
+ "## Slices",
120
+ "",
121
+ "- [ ] **S01: First Feature** `risk:low` `depends:[]`",
122
+ " - After this: First feature proven.",
123
+ "",
124
+ "- [ ] **S02: Second Feature** `risk:low` `depends:[]`",
125
+ " - After this: Second feature proven.",
126
+ "",
127
+ "## Boundary Map",
128
+ "",
129
+ "| From | To | Produces | Consumes |",
130
+ "|------|----|----------|----------|",
131
+ "| S01 | terminal | feature-a | nothing |",
132
+ "| S02 | terminal | feature-b | nothing |",
133
+ ].join("\n"),
134
+ );
135
+
136
+ // S01 PLAN
137
+ writeFileSync(
138
+ join(s01Dir, "S01-PLAN.md"),
139
+ [
140
+ "# S01: First Feature",
141
+ "",
142
+ "**Goal:** Implement first feature.",
143
+ "",
144
+ "## Tasks",
145
+ "",
146
+ "- [ ] **T01: Implementation** `est:30m`",
147
+ " - Do: Build it",
148
+ " - Verify: Run tests",
149
+ "",
150
+ "- [ ] **T02: Testing** `est:30m`",
151
+ " - Do: Write tests",
152
+ " - Verify: Run tests",
153
+ ].join("\n"),
154
+ );
155
+
156
+ // S01 task plan stubs
157
+ writeFileSync(join(s01Tasks, "T01-PLAN.md"), "# T01 Plan\nImplement.\n");
158
+ writeFileSync(join(s01Tasks, "T02-PLAN.md"), "# T02 Plan\nTest.\n");
159
+
160
+ // S02 PLAN
161
+ writeFileSync(
162
+ join(s02Dir, "S02-PLAN.md"),
163
+ [
164
+ "# S02: Second Feature",
165
+ "",
166
+ "**Goal:** Implement second feature.",
167
+ "",
168
+ "## Tasks",
169
+ "",
170
+ "- [ ] **T01: Implementation** `est:30m`",
171
+ " - Do: Build it",
172
+ " - Verify: Run tests",
173
+ ].join("\n"),
174
+ );
175
+
176
+ // S02 task plan stub
177
+ writeFileSync(join(s02Tasks, "T01-PLAN.md"), "# T01 Plan\nBuild.\n");
178
+
179
+ // REQUIREMENTS.md
180
+ writeFileSync(
181
+ join(gsdDir, "REQUIREMENTS.md"),
182
+ [
183
+ "# Requirements",
184
+ "",
185
+ "## Active",
186
+ "",
187
+ "| ID | Description | Owner |",
188
+ "|----|-------------|-------|",
189
+ "| R001 | Feature works | S01 |",
190
+ ].join("\n"),
191
+ );
192
+
193
+ // DECISIONS.md
194
+ writeFileSync(
195
+ join(gsdDir, "DECISIONS.md"),
196
+ [
197
+ "# Decisions",
198
+ "",
199
+ "| ID | Decision | Choice | Rationale |",
200
+ "|----|----------|--------|-----------|",
201
+ ].join("\n"),
202
+ );
203
+
204
+ return base;
205
+ }
206
+
207
+ function makeTaskParams(
208
+ taskId: string,
209
+ sliceId: string,
210
+ milestoneId: string,
211
+ overrides?: Partial<Record<string, unknown>>,
212
+ ): Record<string, unknown> {
213
+ return {
214
+ taskId,
215
+ sliceId,
216
+ milestoneId,
217
+ oneLiner: `Completed ${taskId}`,
218
+ narrative: `Implemented ${taskId} with full coverage.`,
219
+ verification: "All tests pass.",
220
+ keyFiles: ["src/feature.ts"],
221
+ keyDecisions: [],
222
+ deviations: "None.",
223
+ knownIssues: "None.",
224
+ blockerDiscovered: false,
225
+ verificationEvidence: [
226
+ { command: "npm test", exitCode: 0, verdict: "pass", durationMs: 1000 },
227
+ ],
228
+ ...overrides,
229
+ };
230
+ }
231
+
232
+ function makeSliceParams(
233
+ sliceId: string,
234
+ milestoneId: string,
235
+ ): Record<string, unknown> {
236
+ return {
237
+ sliceId,
238
+ milestoneId,
239
+ sliceTitle: `${sliceId} Feature`,
240
+ oneLiner: `${sliceId} proven`,
241
+ narrative: "All tasks completed.",
242
+ verification: "Tests pass.",
243
+ keyFiles: ["src/feature.ts"],
244
+ keyDecisions: [],
245
+ patternsEstablished: [],
246
+ observabilitySurfaces: [],
247
+ deviations: "None.",
248
+ knownLimitations: "None.",
249
+ followUps: "None.",
250
+ requirementsAdvanced: [],
251
+ requirementsValidated: [],
252
+ requirementsSurfaced: [],
253
+ requirementsInvalidated: [],
254
+ filesModified: [{ path: "src/feature.ts", description: "Feature" }],
255
+ uatContent: "Acceptance criteria met.",
256
+ provides: ["feature"],
257
+ requires: [],
258
+ affects: [],
259
+ drillDownPaths: [],
260
+ };
261
+ }
262
+
263
+ function makeMilestoneParams(milestoneId: string): Record<string, unknown> {
264
+ return {
265
+ milestoneId,
266
+ title: "Live Validation Milestone",
267
+ oneLiner: "Milestone proven end-to-end",
268
+ narrative: "All slices completed and verified.",
269
+ successCriteriaResults: "All criteria met.",
270
+ definitionOfDoneResults: "All items checked.",
271
+ requirementOutcomes: "All requirements satisfied.",
272
+ keyDecisions: ["Chose approach A"],
273
+ keyFiles: ["src/feature.ts"],
274
+ lessonsLearned: ["Integration testing is valuable"],
275
+ followUps: "None.",
276
+ deviations: "None.",
277
+ verificationPassed: true,
278
+ };
279
+ }
280
+
281
+ // ═══════════════════════════════════════════════════════════════════════════
282
+ // Test Suite
283
+ // ═══════════════════════════════════════════════════════════════════════════
284
+
285
+ describe("state-machine-live-validation", () => {
286
+ let base: string;
287
+
288
+ afterEach(() => {
289
+ closeDatabase();
290
+ if (base) rmSync(base, { recursive: true, force: true });
291
+ });
292
+
293
+ // ─────────────────────────────────────────────────────────────────────────
294
+ // PHASE 1: Full happy-path lifecycle
295
+ // ─────────────────────────────────────────────────────────────────────────
296
+
297
+ describe("happy path: full lifecycle M001 → complete", () => {
298
+ test("step 1: empty project derives pre-planning", async () => {
299
+ base = makeTempDir();
300
+ mkdirSync(join(base, ".gsd", "milestones"), { recursive: true });
301
+ const state = await deriveState(base);
302
+ assert.equal(state.phase, "pre-planning");
303
+ assert.equal(state.activeMilestone, null);
304
+ });
305
+
306
+ test("step 2: milestone with CONTEXT-DRAFT derives needs-discussion", async () => {
307
+ base = makeTempDir();
308
+ const mDir = join(base, ".gsd", "milestones", "M001");
309
+ mkdirSync(mDir, { recursive: true });
310
+ writeFileSync(join(mDir, "M001-CONTEXT-DRAFT.md"), "# Draft\nDraft context.\n");
311
+ invalidateStateCache();
312
+ const state = await deriveState(base);
313
+ assert.equal(state.phase, "needs-discussion");
314
+ assert.equal(state.activeMilestone?.id, "M001");
315
+ });
316
+
317
+ test("step 3: full fixture with ROADMAP+PLAN derives planning or executing", async () => {
318
+ base = createFullFixture();
319
+ openDatabase(join(base, ".gsd", "gsd.db"));
320
+ invalidateStateCache();
321
+ const state = await deriveState(base);
322
+ // Without DB migration, filesystem path is used — should be planning or executing
323
+ assert.ok(
324
+ ["planning", "executing", "pre-planning"].includes(state.phase),
325
+ `expected planning/executing/pre-planning, got: ${state.phase}`,
326
+ );
327
+ });
328
+
329
+ test("step 4: complete T01 in S01 — handler succeeds, DB reflects completion", async () => {
330
+ base = createFullFixture();
331
+ openDatabase(join(base, ".gsd", "gsd.db"));
332
+ // Seed DB with hierarchy
333
+ insertMilestone({ id: "M001", title: "Live Validation", status: "active" });
334
+ insertSlice({ id: "S01", milestoneId: "M001", title: "First Feature", status: "in_progress" });
335
+ insertTask({ id: "T01", sliceId: "S01", milestoneId: "M001", title: "Implementation", status: "pending" });
336
+ insertTask({ id: "T02", sliceId: "S01", milestoneId: "M001", title: "Testing", status: "pending" });
337
+
338
+ const result = await handleCompleteTask(makeTaskParams("T01", "S01", "M001") as any, base);
339
+ assert.ok(!("error" in result), `expected success, got: ${JSON.stringify(result)}`);
340
+
341
+ // Verify DB state
342
+ const task = getTask("M001", "S01", "T01");
343
+ assert.ok(task, "T01 should exist in DB");
344
+ assert.ok(isClosedStatus(task!.status), `T01 status should be closed, got: ${task!.status}`);
345
+
346
+ // Verify SUMMARY.md written to disk
347
+ const summaryPath = join(base, ".gsd", "milestones", "M001", "slices", "S01", "tasks", "T01-SUMMARY.md");
348
+ assert.ok(existsSync(summaryPath), "T01-SUMMARY.md should exist on disk");
349
+
350
+ // Verify event log entry
351
+ const events = readEvents(join(base, ".gsd", "event-log.jsonl"));
352
+ const taskEvent = events.find(e => e.cmd === "complete-task" && (e.params as any).taskId === "T01");
353
+ assert.ok(taskEvent, "event log should contain complete-task for T01");
354
+ });
355
+
356
+ test("step 5: complete T02 in S01 — both tasks now done", async () => {
357
+ base = createFullFixture();
358
+ openDatabase(join(base, ".gsd", "gsd.db"));
359
+ insertMilestone({ id: "M001", title: "Live Validation", status: "active" });
360
+ insertSlice({ id: "S01", milestoneId: "M001", title: "First Feature", status: "in_progress" });
361
+ insertTask({ id: "T01", sliceId: "S01", milestoneId: "M001", title: "Implementation", status: "complete" });
362
+ insertTask({ id: "T02", sliceId: "S01", milestoneId: "M001", title: "Testing", status: "pending" });
363
+
364
+ const result = await handleCompleteTask(makeTaskParams("T02", "S01", "M001") as any, base);
365
+ assert.ok(!("error" in result), `expected success, got: ${JSON.stringify(result)}`);
366
+
367
+ // Both tasks complete
368
+ const tasks = getSliceTasks("M001", "S01");
369
+ assert.equal(tasks.length, 2);
370
+ assert.ok(tasks.every(t => isClosedStatus(t.status)), "all tasks should be closed");
371
+ });
372
+
373
+ test("step 6: complete slice S01 — all tasks done, slice closes", async () => {
374
+ base = createFullFixture();
375
+ openDatabase(join(base, ".gsd", "gsd.db"));
376
+ insertMilestone({ id: "M001", title: "Live Validation", status: "active" });
377
+ insertSlice({ id: "S01", milestoneId: "M001", title: "First Feature", status: "in_progress" });
378
+ insertTask({ id: "T01", sliceId: "S01", milestoneId: "M001", title: "Impl", status: "complete" });
379
+ insertTask({ id: "T02", sliceId: "S01", milestoneId: "M001", title: "Test", status: "complete" });
380
+
381
+ const result = await handleCompleteSlice(makeSliceParams("S01", "M001") as any, base);
382
+ assert.ok(!("error" in result), `expected success, got: ${JSON.stringify(result)}`);
383
+
384
+ const slice = getSlice("M001", "S01");
385
+ assert.ok(slice, "S01 should exist");
386
+ assert.ok(isClosedStatus(slice!.status), `S01 should be closed, got: ${slice!.status}`);
387
+
388
+ // SUMMARY.md on disk
389
+ const summaryPath = join(base, ".gsd", "milestones", "M001", "slices", "S01", "S01-SUMMARY.md");
390
+ assert.ok(existsSync(summaryPath), "S01-SUMMARY.md should exist");
391
+ });
392
+
393
+ test("step 7: complete S02 task + slice — both slices done", async () => {
394
+ base = createFullFixture();
395
+ openDatabase(join(base, ".gsd", "gsd.db"));
396
+ insertMilestone({ id: "M001", title: "Live Validation", status: "active" });
397
+ insertSlice({ id: "S01", milestoneId: "M001", title: "First", status: "complete" });
398
+ insertSlice({ id: "S02", milestoneId: "M001", title: "Second", status: "in_progress" });
399
+ insertTask({ id: "T01", sliceId: "S01", milestoneId: "M001", title: "Impl", status: "complete" });
400
+ insertTask({ id: "T01", sliceId: "S02", milestoneId: "M001", title: "Impl", status: "pending" });
401
+
402
+ // Complete task
403
+ const taskResult = await handleCompleteTask(makeTaskParams("T01", "S02", "M001") as any, base);
404
+ assert.ok(!("error" in taskResult), `task: ${JSON.stringify(taskResult)}`);
405
+
406
+ // Complete slice
407
+ const sliceResult = await handleCompleteSlice(makeSliceParams("S02", "M001") as any, base);
408
+ assert.ok(!("error" in sliceResult), `slice: ${JSON.stringify(sliceResult)}`);
409
+
410
+ // Both slices complete
411
+ const slices = getMilestoneSlices("M001");
412
+ assert.ok(slices.length >= 2, "should have 2+ slices");
413
+ assert.ok(slices.every(s => isClosedStatus(s.status)), "all slices should be closed");
414
+ });
415
+
416
+ test("step 8: complete milestone M001 — full lifecycle done", async () => {
417
+ base = createFullFixture();
418
+ openDatabase(join(base, ".gsd", "gsd.db"));
419
+ insertMilestone({ id: "M001", title: "Live Validation", status: "active" });
420
+ insertSlice({ id: "S01", milestoneId: "M001", title: "First", status: "complete" });
421
+ insertSlice({ id: "S02", milestoneId: "M001", title: "Second", status: "complete" });
422
+ insertTask({ id: "T01", sliceId: "S01", milestoneId: "M001", title: "Impl", status: "complete" });
423
+ insertTask({ id: "T02", sliceId: "S01", milestoneId: "M001", title: "Test", status: "complete" });
424
+ insertTask({ id: "T01", sliceId: "S02", milestoneId: "M001", title: "Impl", status: "complete" });
425
+
426
+ const result = await handleCompleteMilestone(makeMilestoneParams("M001") as any, base);
427
+ assert.ok(!("error" in result), `expected success, got: ${JSON.stringify(result)}`);
428
+
429
+ const milestone = getMilestone("M001");
430
+ assert.ok(milestone, "M001 should exist");
431
+ assert.ok(isClosedStatus(milestone!.status), `M001 should be closed, got: ${milestone!.status}`);
432
+
433
+ // SUMMARY.md on disk
434
+ const summaryPath = join(base, ".gsd", "milestones", "M001", "M001-SUMMARY.md");
435
+ assert.ok(existsSync(summaryPath), "M001-SUMMARY.md should exist");
436
+ });
437
+ });
438
+
439
+ // ─────────────────────────────────────────────────────────────────────────
440
+ // PHASE 2: Completion guard edge cases
441
+ // ─────────────────────────────────────────────────────────────────────────
442
+
443
+ describe("completion guards — edge cases", () => {
444
+ test("cannot complete task with empty taskId", async () => {
445
+ base = createFullFixture();
446
+ openDatabase(join(base, ".gsd", "gsd.db"));
447
+ const result = await handleCompleteTask(makeTaskParams("", "S01", "M001") as any, base);
448
+ assert.ok("error" in result);
449
+ assert.match((result as any).error, /taskId is required/);
450
+ });
451
+
452
+ test("cannot complete task in closed milestone", async () => {
453
+ base = createFullFixture();
454
+ openDatabase(join(base, ".gsd", "gsd.db"));
455
+ insertMilestone({ id: "M001", title: "Done", status: "complete" });
456
+ insertSlice({ id: "S01", milestoneId: "M001" });
457
+ insertTask({ id: "T01", sliceId: "S01", milestoneId: "M001", status: "pending" });
458
+
459
+ const result = await handleCompleteTask(makeTaskParams("T01", "S01", "M001") as any, base);
460
+ assert.ok("error" in result);
461
+ assert.match((result as any).error, /closed milestone/);
462
+ });
463
+
464
+ test("cannot complete task in closed slice", async () => {
465
+ base = createFullFixture();
466
+ openDatabase(join(base, ".gsd", "gsd.db"));
467
+ insertMilestone({ id: "M001", title: "Active", status: "active" });
468
+ insertSlice({ id: "S01", milestoneId: "M001", status: "complete" });
469
+ insertTask({ id: "T01", sliceId: "S01", milestoneId: "M001", status: "pending" });
470
+
471
+ const result = await handleCompleteTask(makeTaskParams("T01", "S01", "M001") as any, base);
472
+ assert.ok("error" in result);
473
+ assert.match((result as any).error, /closed slice/);
474
+ });
475
+
476
+ test("double task completion returns error (H5-related)", async () => {
477
+ base = createFullFixture();
478
+ openDatabase(join(base, ".gsd", "gsd.db"));
479
+ insertMilestone({ id: "M001", title: "Active", status: "active" });
480
+ insertSlice({ id: "S01", milestoneId: "M001", status: "in_progress" });
481
+ insertTask({ id: "T01", sliceId: "S01", milestoneId: "M001", status: "complete" });
482
+
483
+ const result = await handleCompleteTask(makeTaskParams("T01", "S01", "M001") as any, base);
484
+ assert.ok("error" in result);
485
+ assert.match((result as any).error, /already complete/);
486
+ });
487
+
488
+ test("cannot complete slice with zero tasks — vacuous truth guard", async () => {
489
+ base = createFullFixture();
490
+ openDatabase(join(base, ".gsd", "gsd.db"));
491
+ insertMilestone({ id: "M001", title: "Active", status: "active" });
492
+ insertSlice({ id: "S01", milestoneId: "M001", status: "in_progress" });
493
+ // No tasks inserted
494
+
495
+ const result = await handleCompleteSlice(makeSliceParams("S01", "M001") as any, base);
496
+ assert.ok("error" in result);
497
+ assert.match((result as any).error, /no tasks found/);
498
+ });
499
+
500
+ test("cannot complete slice with incomplete tasks", async () => {
501
+ base = createFullFixture();
502
+ openDatabase(join(base, ".gsd", "gsd.db"));
503
+ insertMilestone({ id: "M001", title: "Active", status: "active" });
504
+ insertSlice({ id: "S01", milestoneId: "M001", status: "in_progress" });
505
+ insertTask({ id: "T01", sliceId: "S01", milestoneId: "M001", status: "complete" });
506
+ insertTask({ id: "T02", sliceId: "S01", milestoneId: "M001", status: "pending" });
507
+
508
+ const result = await handleCompleteSlice(makeSliceParams("S01", "M001") as any, base);
509
+ assert.ok("error" in result);
510
+ assert.match((result as any).error, /incomplete tasks/);
511
+ });
512
+
513
+ test("double slice completion returns error", async () => {
514
+ base = createFullFixture();
515
+ openDatabase(join(base, ".gsd", "gsd.db"));
516
+ insertMilestone({ id: "M001", title: "Active", status: "active" });
517
+ insertSlice({ id: "S01", milestoneId: "M001", status: "complete" });
518
+ insertTask({ id: "T01", sliceId: "S01", milestoneId: "M001", status: "complete" });
519
+
520
+ const result = await handleCompleteSlice(makeSliceParams("S01", "M001") as any, base);
521
+ assert.ok("error" in result);
522
+ assert.match((result as any).error, /already complete/);
523
+ });
524
+
525
+ test("cannot complete milestone with zero slices", async () => {
526
+ base = createFullFixture();
527
+ openDatabase(join(base, ".gsd", "gsd.db"));
528
+ insertMilestone({ id: "M001", title: "Active", status: "active" });
529
+
530
+ const result = await handleCompleteMilestone(makeMilestoneParams("M001") as any, base);
531
+ assert.ok("error" in result);
532
+ assert.match((result as any).error, /no slices found/);
533
+ });
534
+
535
+ test("cannot complete milestone with incomplete slices", async () => {
536
+ base = createFullFixture();
537
+ openDatabase(join(base, ".gsd", "gsd.db"));
538
+ insertMilestone({ id: "M001", title: "Active", status: "active" });
539
+ insertSlice({ id: "S01", milestoneId: "M001", status: "complete" });
540
+ insertSlice({ id: "S02", milestoneId: "M001", status: "in_progress" });
541
+ insertTask({ id: "T01", sliceId: "S01", milestoneId: "M001", status: "complete" });
542
+ insertTask({ id: "T01", sliceId: "S02", milestoneId: "M001", status: "pending" });
543
+
544
+ const result = await handleCompleteMilestone(makeMilestoneParams("M001") as any, base);
545
+ assert.ok("error" in result);
546
+ assert.match((result as any).error, /incomplete slices/);
547
+ });
548
+
549
+ test("cannot complete milestone with incomplete tasks in complete slice (deep check)", async () => {
550
+ base = createFullFixture();
551
+ openDatabase(join(base, ".gsd", "gsd.db"));
552
+ insertMilestone({ id: "M001", title: "Active", status: "active" });
553
+ // Slice marked complete but task is still pending — simulates inconsistent state
554
+ insertSlice({ id: "S01", milestoneId: "M001", status: "complete" });
555
+ insertTask({ id: "T01", sliceId: "S01", milestoneId: "M001", status: "pending" });
556
+
557
+ const result = await handleCompleteMilestone(makeMilestoneParams("M001") as any, base);
558
+ assert.ok("error" in result);
559
+ assert.match((result as any).error, /incomplete tasks/);
560
+ });
561
+
562
+ test("cannot complete milestone without verificationPassed=true", async () => {
563
+ base = createFullFixture();
564
+ openDatabase(join(base, ".gsd", "gsd.db"));
565
+ insertMilestone({ id: "M001", title: "Active", status: "active" });
566
+ insertSlice({ id: "S01", milestoneId: "M001", status: "complete" });
567
+ insertTask({ id: "T01", sliceId: "S01", milestoneId: "M001", status: "complete" });
568
+
569
+ const params = makeMilestoneParams("M001");
570
+ params.verificationPassed = false;
571
+ const result = await handleCompleteMilestone(params as any, base);
572
+ assert.ok("error" in result);
573
+ assert.match((result as any).error, /verification did not pass/);
574
+ });
575
+
576
+ test("double milestone completion returns error", async () => {
577
+ base = createFullFixture();
578
+ openDatabase(join(base, ".gsd", "gsd.db"));
579
+ insertMilestone({ id: "M001", title: "Done", status: "complete" });
580
+ insertSlice({ id: "S01", milestoneId: "M001", status: "complete" });
581
+ insertTask({ id: "T01", sliceId: "S01", milestoneId: "M001", status: "complete" });
582
+
583
+ const result = await handleCompleteMilestone(makeMilestoneParams("M001") as any, base);
584
+ assert.ok("error" in result);
585
+ assert.match((result as any).error, /already complete/);
586
+ });
587
+ });
588
+
589
+ // ─────────────────────────────────────────────────────────────────────────
590
+ // PHASE 3: Reopen operations
591
+ // ─────────────────────────────────────────────────────────────────────────
592
+
593
+ describe("reopen operations", () => {
594
+ test("reopen task: resets completed task to pending", async () => {
595
+ base = createFullFixture();
596
+ openDatabase(join(base, ".gsd", "gsd.db"));
597
+ insertMilestone({ id: "M001", title: "Active", status: "active" });
598
+ insertSlice({ id: "S01", milestoneId: "M001", status: "in_progress" });
599
+ insertTask({ id: "T01", sliceId: "S01", milestoneId: "M001", status: "complete" });
600
+
601
+ const result = await handleReopenTask(
602
+ { milestoneId: "M001", sliceId: "S01", taskId: "T01", reason: "Need to redo" },
603
+ base,
604
+ );
605
+ assert.ok(!("error" in result), `expected success: ${JSON.stringify(result)}`);
606
+
607
+ const task = getTask("M001", "S01", "T01");
608
+ assert.equal(task!.status, "pending");
609
+ });
610
+
611
+ test("cannot reopen task that is not complete", async () => {
612
+ base = createFullFixture();
613
+ openDatabase(join(base, ".gsd", "gsd.db"));
614
+ insertMilestone({ id: "M001", title: "Active", status: "active" });
615
+ insertSlice({ id: "S01", milestoneId: "M001", status: "in_progress" });
616
+ insertTask({ id: "T01", sliceId: "S01", milestoneId: "M001", status: "pending" });
617
+
618
+ const result = await handleReopenTask(
619
+ { milestoneId: "M001", sliceId: "S01", taskId: "T01" },
620
+ base,
621
+ );
622
+ assert.ok("error" in result);
623
+ assert.match((result as any).error, /not complete/);
624
+ });
625
+
626
+ test("cannot reopen task in closed slice — must reopen slice first", async () => {
627
+ base = createFullFixture();
628
+ openDatabase(join(base, ".gsd", "gsd.db"));
629
+ insertMilestone({ id: "M001", title: "Active", status: "active" });
630
+ insertSlice({ id: "S01", milestoneId: "M001", status: "complete" });
631
+ insertTask({ id: "T01", sliceId: "S01", milestoneId: "M001", status: "complete" });
632
+
633
+ const result = await handleReopenTask(
634
+ { milestoneId: "M001", sliceId: "S01", taskId: "T01" },
635
+ base,
636
+ );
637
+ assert.ok("error" in result);
638
+ assert.match((result as any).error, /closed slice/);
639
+ });
640
+
641
+ test("cannot reopen task in closed milestone", async () => {
642
+ base = createFullFixture();
643
+ openDatabase(join(base, ".gsd", "gsd.db"));
644
+ insertMilestone({ id: "M001", title: "Done", status: "complete" });
645
+ insertSlice({ id: "S01", milestoneId: "M001", status: "complete" });
646
+ insertTask({ id: "T01", sliceId: "S01", milestoneId: "M001", status: "complete" });
647
+
648
+ const result = await handleReopenTask(
649
+ { milestoneId: "M001", sliceId: "S01", taskId: "T01" },
650
+ base,
651
+ );
652
+ assert.ok("error" in result);
653
+ assert.match((result as any).error, /closed milestone/);
654
+ });
655
+
656
+ test("reopen slice: resets slice to in_progress and all tasks to pending", async () => {
657
+ base = createFullFixture();
658
+ openDatabase(join(base, ".gsd", "gsd.db"));
659
+ insertMilestone({ id: "M001", title: "Active", status: "active" });
660
+ insertSlice({ id: "S01", milestoneId: "M001", status: "complete" });
661
+ insertTask({ id: "T01", sliceId: "S01", milestoneId: "M001", status: "complete" });
662
+ insertTask({ id: "T02", sliceId: "S01", milestoneId: "M001", status: "complete" });
663
+
664
+ const result = await handleReopenSlice(
665
+ { milestoneId: "M001", sliceId: "S01", reason: "Need rework" },
666
+ base,
667
+ );
668
+ assert.ok(!("error" in result), `expected success: ${JSON.stringify(result)}`);
669
+ assert.equal((result as any).tasksReset, 2);
670
+
671
+ // Verify slice state
672
+ const slice = getSlice("M001", "S01");
673
+ assert.equal(slice!.status, "in_progress");
674
+
675
+ // Verify all tasks reset to pending
676
+ const tasks = getSliceTasks("M001", "S01");
677
+ assert.ok(tasks.every(t => t.status === "pending"), "all tasks should be pending after slice reopen");
678
+ });
679
+
680
+ test("cannot reopen slice in closed milestone", async () => {
681
+ base = createFullFixture();
682
+ openDatabase(join(base, ".gsd", "gsd.db"));
683
+ insertMilestone({ id: "M001", title: "Done", status: "complete" });
684
+ insertSlice({ id: "S01", milestoneId: "M001", status: "complete" });
685
+
686
+ const result = await handleReopenSlice(
687
+ { milestoneId: "M001", sliceId: "S01" },
688
+ base,
689
+ );
690
+ assert.ok("error" in result);
691
+ assert.match((result as any).error, /closed milestone/);
692
+ });
693
+
694
+ test("no reopen-milestone tool exists — milestone completion is irrevocable (H5)", async () => {
695
+ // This test documents the H5 finding: there is no handleReopenMilestone function.
696
+ // A completed milestone can only be undone via direct DB manipulation.
697
+ base = createFullFixture();
698
+ openDatabase(join(base, ".gsd", "gsd.db"));
699
+ insertMilestone({ id: "M001", title: "Done", status: "complete" });
700
+
701
+ const milestone = getMilestone("M001");
702
+ assert.ok(isClosedStatus(milestone!.status), "milestone is closed");
703
+
704
+ // The only escape is direct DB manipulation — no handler exists
705
+ updateMilestoneStatus("M001", "active", null);
706
+ const reopened = getMilestone("M001");
707
+ assert.equal(reopened!.status, "active", "direct DB manipulation can reopen, but no tool exposes this");
708
+ });
709
+ });
710
+
711
+ // ─────────────────────────────────────────────────────────────────────────
712
+ // PHASE 4: Phantom parents and auto-creation (H6)
713
+ // ─────────────────────────────────────────────────────────────────────────
714
+
715
+ describe("phantom parent auto-creation (H6)", () => {
716
+ test("completing task for non-existent milestone/slice auto-creates them", async () => {
717
+ base = createFullFixture();
718
+ openDatabase(join(base, ".gsd", "gsd.db"));
719
+ // No milestone or slice pre-inserted — handler will auto-create
720
+
721
+ const result = await handleCompleteTask(makeTaskParams("T01", "S99", "M099") as any, base);
722
+ assert.ok(!("error" in result), `expected success: ${JSON.stringify(result)}`);
723
+
724
+ // Phantom milestone created
725
+ const milestone = getMilestone("M099");
726
+ assert.ok(milestone, "phantom milestone M099 should exist");
727
+ assert.equal(milestone!.title, "", "phantom milestone has empty title");
728
+
729
+ // Phantom slice created
730
+ const slice = getSlice("M099", "S99");
731
+ assert.ok(slice, "phantom slice S99 should exist");
732
+ });
733
+
734
+ test("completing slice for non-existent milestone auto-creates it", async () => {
735
+ base = createFullFixture();
736
+ openDatabase(join(base, ".gsd", "gsd.db"));
737
+ // Insert task to satisfy completion guard
738
+ insertMilestone({ id: "M099" });
739
+ insertSlice({ id: "S99", milestoneId: "M099" });
740
+ insertTask({ id: "T01", sliceId: "S99", milestoneId: "M099", status: "complete" });
741
+
742
+ const result = await handleCompleteSlice(makeSliceParams("S99", "M099") as any, base);
743
+ assert.ok(!("error" in result), `expected success: ${JSON.stringify(result)}`);
744
+ });
745
+ });
746
+
747
+ // ─────────────────────────────────────────────────────────────────────────
748
+ // PHASE 5: State derivation consistency
749
+ // ─────────────────────────────────────────────────────────────────────────
750
+
751
+ describe("state derivation with live DB", () => {
752
+ test("deriveStateFromDb reflects task completion immediately", async () => {
753
+ base = createFullFixture();
754
+ openDatabase(join(base, ".gsd", "gsd.db"));
755
+ insertMilestone({ id: "M001", title: "Active", status: "active" });
756
+ insertSlice({ id: "S01", milestoneId: "M001", title: "First", status: "in_progress" });
757
+ insertTask({ id: "T01", sliceId: "S01", milestoneId: "M001", status: "pending" });
758
+ insertTask({ id: "T02", sliceId: "S01", milestoneId: "M001", status: "pending" });
759
+
760
+ invalidateStateCache();
761
+ const stateBefore = await deriveStateFromDb(base);
762
+ assert.equal(stateBefore.phase, "executing", `before: expected executing, got ${stateBefore.phase}`);
763
+
764
+ // Complete T01
765
+ updateTaskStatus("M001", "S01", "T01", "complete", new Date().toISOString());
766
+ invalidateStateCache();
767
+ const stateAfterT01 = await deriveStateFromDb(base);
768
+ // Still executing — T02 is pending
769
+ assert.equal(stateAfterT01.phase, "executing", `after T01: expected executing, got ${stateAfterT01.phase}`);
770
+
771
+ // Complete T02
772
+ updateTaskStatus("M001", "S01", "T02", "complete", new Date().toISOString());
773
+ invalidateStateCache();
774
+ const stateAfterT02 = await deriveStateFromDb(base);
775
+ // All tasks done → summarizing
776
+ assert.equal(stateAfterT02.phase, "summarizing", `after T02: expected summarizing, got ${stateAfterT02.phase}`);
777
+ });
778
+
779
+ test("deriveStateFromDb reflects slice completion → next slice or validating", async () => {
780
+ base = createFullFixture();
781
+ openDatabase(join(base, ".gsd", "gsd.db"));
782
+ insertMilestone({ id: "M001", title: "Active", status: "active" });
783
+ insertSlice({ id: "S01", milestoneId: "M001", title: "First", status: "complete" });
784
+ insertSlice({ id: "S02", milestoneId: "M001", title: "Second", status: "in_progress" });
785
+ insertTask({ id: "T01", sliceId: "S01", milestoneId: "M001", status: "complete" });
786
+ insertTask({ id: "T01", sliceId: "S02", milestoneId: "M001", status: "pending" });
787
+
788
+ invalidateStateCache();
789
+ const state = await deriveStateFromDb(base);
790
+ // S01 done, S02 has pending task → executing
791
+ assert.equal(state.phase, "executing", `expected executing for S02, got ${state.phase}`);
792
+ assert.equal(state.activeSlice?.id, "S02", "active slice should be S02");
793
+ });
794
+
795
+ test("deriveStateFromDb with all slices done → validating-milestone", async () => {
796
+ base = createFullFixture();
797
+ openDatabase(join(base, ".gsd", "gsd.db"));
798
+ insertMilestone({ id: "M001", title: "Active", status: "active" });
799
+ insertSlice({ id: "S01", milestoneId: "M001", title: "First", status: "complete" });
800
+ insertSlice({ id: "S02", milestoneId: "M001", title: "Second", status: "complete" });
801
+ insertTask({ id: "T01", sliceId: "S01", milestoneId: "M001", status: "complete" });
802
+ insertTask({ id: "T01", sliceId: "S02", milestoneId: "M001", status: "complete" });
803
+
804
+ invalidateStateCache();
805
+ const state = await deriveStateFromDb(base);
806
+ assert.equal(state.phase, "validating-milestone", `expected validating-milestone, got ${state.phase}`);
807
+ });
808
+
809
+ test("ghost milestone is skipped by deriveState", async () => {
810
+ base = makeTempDir();
811
+ const gsdDir = join(base, ".gsd", "milestones");
812
+ // M001 is ghost — empty dir
813
+ mkdirSync(join(gsdDir, "M001"), { recursive: true });
814
+ // M002 has content
815
+ mkdirSync(join(gsdDir, "M002"), { recursive: true });
816
+ writeFileSync(join(gsdDir, "M002", "M002-CONTEXT-DRAFT.md"), "# Draft\nContent.\n");
817
+
818
+ assert.ok(isGhostMilestone(base, "M001"), "M001 should be ghost");
819
+ assert.ok(!isGhostMilestone(base, "M002"), "M002 should not be ghost");
820
+
821
+ invalidateStateCache();
822
+ const state = await deriveState(base);
823
+ assert.equal(state.activeMilestone?.id, "M002", "should skip ghost M001 and use M002");
824
+ });
825
+ });
826
+
827
+ // ─────────────────────────────────────────────────────────────────────────
828
+ // PHASE 6: Event log integrity
829
+ // ─────────────────────────────────────────────────────────────────────────
830
+
831
+ describe("event log integrity across operations", () => {
832
+ test("full operation sequence produces correct event log", async () => {
833
+ base = createFullFixture();
834
+ openDatabase(join(base, ".gsd", "gsd.db"));
835
+ insertMilestone({ id: "M001", title: "Active", status: "active" });
836
+ insertSlice({ id: "S01", milestoneId: "M001", title: "First", status: "in_progress" });
837
+ insertTask({ id: "T01", sliceId: "S01", milestoneId: "M001", status: "pending" });
838
+ insertTask({ id: "T02", sliceId: "S01", milestoneId: "M001", status: "pending" });
839
+
840
+ // Complete T01
841
+ await handleCompleteTask(makeTaskParams("T01", "S01", "M001") as any, base);
842
+ // Complete T02
843
+ await handleCompleteTask(makeTaskParams("T02", "S01", "M001") as any, base);
844
+ // Complete S01
845
+ await handleCompleteSlice(makeSliceParams("S01", "M001") as any, base);
846
+
847
+ const events = readEvents(join(base, ".gsd", "event-log.jsonl"));
848
+
849
+ // Should have 3 events: 2 task completions + 1 slice completion
850
+ assert.ok(events.length >= 3, `expected ≥3 events, got ${events.length}`);
851
+
852
+ const taskEvents = events.filter(e => e.cmd === "complete-task");
853
+ assert.equal(taskEvents.length, 2, "2 task completion events");
854
+
855
+ const sliceEvents = events.filter(e => e.cmd === "complete-slice");
856
+ assert.equal(sliceEvents.length, 1, "1 slice completion event");
857
+
858
+ // Events are ordered chronologically
859
+ for (let i = 1; i < events.length; i++) {
860
+ assert.ok(
861
+ events[i]!.ts >= events[i - 1]!.ts,
862
+ `events should be chronologically ordered: ${events[i - 1]!.ts} <= ${events[i]!.ts}`,
863
+ );
864
+ }
865
+
866
+ // All events have hashes and session IDs
867
+ for (const event of events) {
868
+ assert.ok(event.hash, "event should have hash");
869
+ assert.ok(event.session_id, "event should have session_id");
870
+ }
871
+ });
872
+
873
+ test("reopen operations produce events", async () => {
874
+ base = createFullFixture();
875
+ openDatabase(join(base, ".gsd", "gsd.db"));
876
+ insertMilestone({ id: "M001", title: "Active", status: "active" });
877
+ insertSlice({ id: "S01", milestoneId: "M001", status: "in_progress" });
878
+ insertTask({ id: "T01", sliceId: "S01", milestoneId: "M001", status: "complete" });
879
+
880
+ await handleReopenTask(
881
+ { milestoneId: "M001", sliceId: "S01", taskId: "T01", reason: "redo" },
882
+ base,
883
+ );
884
+
885
+ const events = readEvents(join(base, ".gsd", "event-log.jsonl"));
886
+ const reopenEvent = events.find(e => e.cmd === "reopen-task");
887
+ assert.ok(reopenEvent, "should have reopen-task event");
888
+ assert.equal((reopenEvent!.params as any).taskId, "T01");
889
+ assert.equal((reopenEvent!.params as any).reason, "redo");
890
+ });
891
+ });
892
+
893
+ // ─────────────────────────────────────────────────────────────────────────
894
+ // PHASE 7: Reopen-then-redo cycle
895
+ // ─────────────────────────────────────────────────────────────────────────
896
+
897
+ describe("reopen-then-redo cycle", () => {
898
+ test("complete → reopen → M12: stale SUMMARY causes immediate auto-reconcile", async () => {
899
+ // Finding M12: reopen-task does NOT delete the SUMMARY.md from disk.
900
+ // The reopen handler's own post-mutation hook calls renderAllProjections
901
+ // which triggers deriveStateFromDb, which sees the stale SUMMARY.md and
902
+ // auto-reconciles the task BACK to "complete" (#2514) within the same call.
903
+ //
904
+ // Result: the reopen is effectively a no-op when filesystem artifacts exist.
905
+ base = createFullFixture();
906
+ openDatabase(join(base, ".gsd", "gsd.db"));
907
+ insertMilestone({ id: "M001", title: "Active", status: "active" });
908
+ insertSlice({ id: "S01", milestoneId: "M001", title: "First", status: "in_progress" });
909
+ insertTask({ id: "T01", sliceId: "S01", milestoneId: "M001", status: "pending" });
910
+
911
+ // Complete — writes T01-SUMMARY.md to disk
912
+ const r1 = await handleCompleteTask(makeTaskParams("T01", "S01", "M001") as any, base);
913
+ assert.ok(!("error" in r1), `first complete: ${JSON.stringify(r1)}`);
914
+
915
+ const summaryPath = join(base, ".gsd", "milestones", "M001", "slices", "S01", "tasks", "T01-SUMMARY.md");
916
+ assert.ok(existsSync(summaryPath), "SUMMARY.md exists after completion");
917
+
918
+ // Reopen — handler sets DB to "pending" in transaction, but post-mutation
919
+ // hook triggers reconciler which immediately sets it back to "complete"
920
+ const r2 = await handleReopenTask({ milestoneId: "M001", sliceId: "S01", taskId: "T01" }, base);
921
+ assert.ok(!("error" in r2), `reopen handler succeeded: ${JSON.stringify(r2)}`);
922
+
923
+ // M12: After reopen completes, DB shows "complete" not "pending" because
924
+ // the reconciler auto-corrected it from the stale SUMMARY.md
925
+ const task = getTask("M001", "S01", "T01");
926
+ assert.equal(task!.status, "complete", "M12: reconciler overrides reopen — task is back to complete");
927
+ assert.ok(existsSync(summaryPath), "M12: SUMMARY.md was never cleaned up");
928
+ });
929
+
930
+ test("complete slice → reopen → M12: reconciler overrides task reset via stale SUMMARY", async () => {
931
+ // Same M12 pattern at the slice level: reopen-slice resets all tasks to
932
+ // "pending" in DB, but task SUMMARY.md artifacts remain on disk. The
933
+ // reopen handler's post-mutation hook triggers reconciler which sees the
934
+ // stale artifacts and auto-corrects tasks back to "complete".
935
+ base = createFullFixture();
936
+ openDatabase(join(base, ".gsd", "gsd.db"));
937
+ insertMilestone({ id: "M001", title: "Active", status: "active" });
938
+ insertSlice({ id: "S01", milestoneId: "M001", title: "First", status: "in_progress" });
939
+ insertTask({ id: "T01", sliceId: "S01", milestoneId: "M001", status: "pending" });
940
+
941
+ // Complete task + slice
942
+ await handleCompleteTask(makeTaskParams("T01", "S01", "M001") as any, base);
943
+ await handleCompleteSlice(makeSliceParams("S01", "M001") as any, base);
944
+ assert.ok(isClosedStatus(getSlice("M001", "S01")!.status));
945
+
946
+ // Reopen slice — transaction resets slice to in_progress and task to pending,
947
+ // but post-mutation hook triggers reconciler which sees stale SUMMARY.md
948
+ await handleReopenSlice({ milestoneId: "M001", sliceId: "S01" }, base);
949
+
950
+ // Slice status is correctly in_progress (no slice SUMMARY reconciliation)
951
+ assert.equal(getSlice("M001", "S01")!.status, "in_progress");
952
+
953
+ // M12: Task was reset to "pending" in the transaction, but reconciler
954
+ // already corrected it back to "complete" from the stale SUMMARY.md
955
+ const task = getTask("M001", "S01", "T01");
956
+ assert.equal(task!.status, "complete", "M12: reconciler overrides reopen — task back to complete");
957
+ });
958
+ });
959
+ });