gsd-pi 2.44.0 → 2.45.0-dev.1afbdaa

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 (608) hide show
  1. package/README.md +30 -12
  2. package/dist/help-text.js +1 -1
  3. package/dist/loader.js +34 -0
  4. package/dist/resources/extensions/gsd/activity-log.js +7 -0
  5. package/dist/resources/extensions/gsd/auto/infra-errors.js +3 -0
  6. package/dist/resources/extensions/gsd/auto/phases.js +63 -77
  7. package/dist/resources/extensions/gsd/auto/run-unit.js +6 -3
  8. package/dist/resources/extensions/gsd/auto/session.js +0 -11
  9. package/dist/resources/extensions/gsd/auto-artifact-paths.js +112 -0
  10. package/dist/resources/extensions/gsd/auto-post-unit.js +25 -96
  11. package/dist/resources/extensions/gsd/auto-prompts.js +24 -1
  12. package/dist/resources/extensions/gsd/auto-start.js +33 -5
  13. package/dist/resources/extensions/gsd/auto-timers.js +57 -3
  14. package/dist/resources/extensions/gsd/auto-worktree-sync.js +4 -0
  15. package/dist/resources/extensions/gsd/auto-worktree.js +14 -10
  16. package/dist/resources/extensions/gsd/auto.js +42 -60
  17. package/dist/resources/extensions/gsd/bootstrap/db-tools.js +170 -11
  18. package/dist/resources/extensions/gsd/bootstrap/register-hooks.js +18 -0
  19. package/dist/resources/extensions/gsd/bootstrap/system-context.js +46 -12
  20. package/dist/resources/extensions/gsd/commands/catalog.js +7 -1
  21. package/dist/resources/extensions/gsd/commands/context.js +0 -4
  22. package/dist/resources/extensions/gsd/commands/handlers/core.js +2 -0
  23. package/dist/resources/extensions/gsd/commands/handlers/ops.js +10 -0
  24. package/dist/resources/extensions/gsd/commands/handlers/parallel.js +1 -1
  25. package/dist/resources/extensions/gsd/commands/handlers/workflow.js +5 -0
  26. package/dist/resources/extensions/gsd/commands-mcp-status.js +187 -0
  27. package/dist/resources/extensions/gsd/crash-recovery.js +2 -4
  28. package/dist/resources/extensions/gsd/dashboard-overlay.js +0 -44
  29. package/dist/resources/extensions/gsd/db-writer.js +40 -22
  30. package/dist/resources/extensions/gsd/doctor-checks.js +167 -2
  31. package/dist/resources/extensions/gsd/doctor.js +13 -3
  32. package/dist/resources/extensions/gsd/git-service.js +8 -3
  33. package/dist/resources/extensions/gsd/gsd-db.js +28 -4
  34. package/dist/resources/extensions/gsd/guided-flow.js +1 -2
  35. package/dist/resources/extensions/gsd/markdown-renderer.js +1 -1
  36. package/dist/resources/extensions/gsd/parallel-merge.js +1 -1
  37. package/dist/resources/extensions/gsd/parallel-orchestrator.js +5 -18
  38. package/dist/resources/extensions/gsd/preferences-types.js +2 -2
  39. package/dist/resources/extensions/gsd/preferences.js +17 -5
  40. package/dist/resources/extensions/gsd/prompts/complete-milestone.md +21 -10
  41. package/dist/resources/extensions/gsd/prompts/complete-slice.md +10 -23
  42. package/dist/resources/extensions/gsd/prompts/discuss.md +2 -2
  43. package/dist/resources/extensions/gsd/prompts/execute-task.md +5 -15
  44. package/dist/resources/extensions/gsd/prompts/guided-discuss-milestone.md +1 -1
  45. package/dist/resources/extensions/gsd/prompts/guided-discuss-slice.md +1 -1
  46. package/dist/resources/extensions/gsd/prompts/guided-plan-slice.md +1 -1
  47. package/dist/resources/extensions/gsd/prompts/guided-research-slice.md +1 -1
  48. package/dist/resources/extensions/gsd/prompts/plan-milestone.md +1 -1
  49. package/dist/resources/extensions/gsd/prompts/plan-slice.md +5 -3
  50. package/dist/resources/extensions/gsd/prompts/queue.md +2 -2
  51. package/dist/resources/extensions/gsd/prompts/quick-task.md +2 -0
  52. package/dist/resources/extensions/gsd/prompts/reactive-execute.md +1 -1
  53. package/dist/resources/extensions/gsd/prompts/reassess-roadmap.md +6 -6
  54. package/dist/resources/extensions/gsd/prompts/replan-slice.md +3 -14
  55. package/dist/resources/extensions/gsd/prompts/research-slice.md +3 -3
  56. package/dist/resources/extensions/gsd/prompts/rethink.md +83 -0
  57. package/dist/resources/extensions/gsd/prompts/system.md +1 -1
  58. package/dist/resources/extensions/gsd/prompts/validate-milestone.md +7 -37
  59. package/dist/resources/extensions/gsd/provider-error-pause.js +7 -0
  60. package/dist/resources/extensions/gsd/repo-identity.js +45 -7
  61. package/dist/resources/extensions/gsd/rethink.js +115 -0
  62. package/dist/resources/extensions/gsd/session-lock.js +1 -3
  63. package/dist/resources/extensions/gsd/state.js +48 -3
  64. package/dist/resources/extensions/gsd/sync-lock.js +89 -0
  65. package/dist/resources/extensions/gsd/tools/complete-milestone.js +61 -11
  66. package/dist/resources/extensions/gsd/tools/complete-slice.js +56 -11
  67. package/dist/resources/extensions/gsd/tools/complete-task.js +50 -2
  68. package/dist/resources/extensions/gsd/tools/plan-milestone.js +37 -1
  69. package/dist/resources/extensions/gsd/tools/plan-slice.js +31 -1
  70. package/dist/resources/extensions/gsd/tools/plan-task.js +28 -1
  71. package/dist/resources/extensions/gsd/tools/reassess-roadmap.js +32 -2
  72. package/dist/resources/extensions/gsd/tools/reopen-slice.js +86 -0
  73. package/dist/resources/extensions/gsd/tools/reopen-task.js +90 -0
  74. package/dist/resources/extensions/gsd/tools/replan-slice.js +34 -2
  75. package/dist/resources/extensions/gsd/tools/validate-milestone.js +88 -0
  76. package/dist/resources/extensions/gsd/unit-ownership.js +85 -0
  77. package/dist/resources/extensions/gsd/workflow-events.js +102 -0
  78. package/dist/resources/extensions/gsd/workflow-logger.js +193 -0
  79. package/dist/resources/extensions/gsd/workflow-manifest.js +244 -0
  80. package/dist/resources/extensions/gsd/workflow-migration.js +280 -0
  81. package/dist/resources/extensions/gsd/workflow-projections.js +373 -0
  82. package/dist/resources/extensions/gsd/workflow-reconcile.js +411 -0
  83. package/dist/resources/extensions/gsd/worktree-manager.js +34 -3
  84. package/dist/resources/extensions/gsd/worktree-resolver.js +43 -0
  85. package/dist/resources/extensions/gsd/write-intercept.js +84 -0
  86. package/dist/resources/extensions/mcp-client/index.js +14 -0
  87. package/dist/resources/extensions/voice/index.js +11 -16
  88. package/dist/resources/extensions/voice/linux-ready.js +67 -0
  89. package/dist/web/standalone/.next/BUILD_ID +1 -1
  90. package/dist/web/standalone/.next/app-path-routes-manifest.json +12 -12
  91. package/dist/web/standalone/.next/build-manifest.json +4 -4
  92. package/dist/web/standalone/.next/prerender-manifest.json +3 -3
  93. package/dist/web/standalone/.next/react-loadable-manifest.json +2 -2
  94. package/dist/web/standalone/.next/required-server-files.json +3 -3
  95. package/dist/web/standalone/.next/server/app/_global-error/page.js +3 -3
  96. package/dist/web/standalone/.next/server/app/_global-error/page_client-reference-manifest.js +1 -1
  97. package/dist/web/standalone/.next/server/app/_global-error.html +2 -2
  98. package/dist/web/standalone/.next/server/app/_global-error.rsc +1 -1
  99. package/dist/web/standalone/.next/server/app/_global-error.segments/_full.segment.rsc +1 -1
  100. package/dist/web/standalone/.next/server/app/_global-error.segments/_global-error/__PAGE__.segment.rsc +1 -1
  101. package/dist/web/standalone/.next/server/app/_global-error.segments/_global-error.segment.rsc +1 -1
  102. package/dist/web/standalone/.next/server/app/_global-error.segments/_head.segment.rsc +1 -1
  103. package/dist/web/standalone/.next/server/app/_global-error.segments/_index.segment.rsc +1 -1
  104. package/dist/web/standalone/.next/server/app/_global-error.segments/_tree.segment.rsc +1 -1
  105. package/dist/web/standalone/.next/server/app/_not-found/page.js +2 -2
  106. package/dist/web/standalone/.next/server/app/_not-found/page_client-reference-manifest.js +1 -1
  107. package/dist/web/standalone/.next/server/app/_not-found.html +1 -1
  108. package/dist/web/standalone/.next/server/app/_not-found.rsc +5 -5
  109. package/dist/web/standalone/.next/server/app/_not-found.segments/_full.segment.rsc +5 -5
  110. package/dist/web/standalone/.next/server/app/_not-found.segments/_head.segment.rsc +1 -1
  111. package/dist/web/standalone/.next/server/app/_not-found.segments/_index.segment.rsc +4 -4
  112. package/dist/web/standalone/.next/server/app/_not-found.segments/_not-found/__PAGE__.segment.rsc +1 -1
  113. package/dist/web/standalone/.next/server/app/_not-found.segments/_not-found.segment.rsc +1 -1
  114. package/dist/web/standalone/.next/server/app/_not-found.segments/_tree.segment.rsc +2 -2
  115. package/dist/web/standalone/.next/server/app/api/boot/route.js +1 -1
  116. package/dist/web/standalone/.next/server/app/api/boot/route_client-reference-manifest.js +1 -1
  117. package/dist/web/standalone/.next/server/app/api/bridge-terminal/input/route.js +1 -1
  118. package/dist/web/standalone/.next/server/app/api/bridge-terminal/input/route_client-reference-manifest.js +1 -1
  119. package/dist/web/standalone/.next/server/app/api/bridge-terminal/resize/route.js +1 -1
  120. package/dist/web/standalone/.next/server/app/api/bridge-terminal/resize/route_client-reference-manifest.js +1 -1
  121. package/dist/web/standalone/.next/server/app/api/bridge-terminal/stream/route.js +2 -2
  122. package/dist/web/standalone/.next/server/app/api/bridge-terminal/stream/route_client-reference-manifest.js +1 -1
  123. package/dist/web/standalone/.next/server/app/api/browse-directories/route.js +1 -1
  124. package/dist/web/standalone/.next/server/app/api/browse-directories/route_client-reference-manifest.js +1 -1
  125. package/dist/web/standalone/.next/server/app/api/captures/route.js +1 -1
  126. package/dist/web/standalone/.next/server/app/api/captures/route_client-reference-manifest.js +1 -1
  127. package/dist/web/standalone/.next/server/app/api/cleanup/route.js +1 -1
  128. package/dist/web/standalone/.next/server/app/api/cleanup/route_client-reference-manifest.js +1 -1
  129. package/dist/web/standalone/.next/server/app/api/dev-mode/route.js +1 -1
  130. package/dist/web/standalone/.next/server/app/api/dev-mode/route_client-reference-manifest.js +1 -1
  131. package/dist/web/standalone/.next/server/app/api/doctor/route.js +1 -1
  132. package/dist/web/standalone/.next/server/app/api/doctor/route_client-reference-manifest.js +1 -1
  133. package/dist/web/standalone/.next/server/app/api/export-data/route.js +1 -1
  134. package/dist/web/standalone/.next/server/app/api/export-data/route_client-reference-manifest.js +1 -1
  135. package/dist/web/standalone/.next/server/app/api/files/route.js +1 -1
  136. package/dist/web/standalone/.next/server/app/api/files/route_client-reference-manifest.js +1 -1
  137. package/dist/web/standalone/.next/server/app/api/forensics/route.js +1 -1
  138. package/dist/web/standalone/.next/server/app/api/forensics/route_client-reference-manifest.js +1 -1
  139. package/dist/web/standalone/.next/server/app/api/git/route.js +1 -1
  140. package/dist/web/standalone/.next/server/app/api/git/route_client-reference-manifest.js +1 -1
  141. package/dist/web/standalone/.next/server/app/api/history/route.js +1 -1
  142. package/dist/web/standalone/.next/server/app/api/history/route_client-reference-manifest.js +1 -1
  143. package/dist/web/standalone/.next/server/app/api/hooks/route.js +1 -1
  144. package/dist/web/standalone/.next/server/app/api/hooks/route_client-reference-manifest.js +1 -1
  145. package/dist/web/standalone/.next/server/app/api/inspect/route.js +1 -1
  146. package/dist/web/standalone/.next/server/app/api/inspect/route_client-reference-manifest.js +1 -1
  147. package/dist/web/standalone/.next/server/app/api/knowledge/route.js +1 -1
  148. package/dist/web/standalone/.next/server/app/api/knowledge/route_client-reference-manifest.js +1 -1
  149. package/dist/web/standalone/.next/server/app/api/live-state/route.js +1 -1
  150. package/dist/web/standalone/.next/server/app/api/live-state/route_client-reference-manifest.js +1 -1
  151. package/dist/web/standalone/.next/server/app/api/onboarding/route.js +1 -1
  152. package/dist/web/standalone/.next/server/app/api/onboarding/route_client-reference-manifest.js +1 -1
  153. package/dist/web/standalone/.next/server/app/api/preferences/route.js +1 -1
  154. package/dist/web/standalone/.next/server/app/api/preferences/route_client-reference-manifest.js +1 -1
  155. package/dist/web/standalone/.next/server/app/api/projects/route.js +1 -1
  156. package/dist/web/standalone/.next/server/app/api/projects/route_client-reference-manifest.js +1 -1
  157. package/dist/web/standalone/.next/server/app/api/recovery/route.js +1 -1
  158. package/dist/web/standalone/.next/server/app/api/recovery/route_client-reference-manifest.js +1 -1
  159. package/dist/web/standalone/.next/server/app/api/remote-questions/route.js +5 -5
  160. package/dist/web/standalone/.next/server/app/api/remote-questions/route_client-reference-manifest.js +1 -1
  161. package/dist/web/standalone/.next/server/app/api/session/browser/route.js +1 -1
  162. package/dist/web/standalone/.next/server/app/api/session/browser/route_client-reference-manifest.js +1 -1
  163. package/dist/web/standalone/.next/server/app/api/session/command/route.js +1 -1
  164. package/dist/web/standalone/.next/server/app/api/session/command/route_client-reference-manifest.js +1 -1
  165. package/dist/web/standalone/.next/server/app/api/session/events/route.js +2 -2
  166. package/dist/web/standalone/.next/server/app/api/session/events/route_client-reference-manifest.js +1 -1
  167. package/dist/web/standalone/.next/server/app/api/session/manage/route.js +1 -1
  168. package/dist/web/standalone/.next/server/app/api/session/manage/route_client-reference-manifest.js +1 -1
  169. package/dist/web/standalone/.next/server/app/api/settings-data/route.js +1 -1
  170. package/dist/web/standalone/.next/server/app/api/settings-data/route_client-reference-manifest.js +1 -1
  171. package/dist/web/standalone/.next/server/app/api/shutdown/route.js +1 -1
  172. package/dist/web/standalone/.next/server/app/api/shutdown/route_client-reference-manifest.js +1 -1
  173. package/dist/web/standalone/.next/server/app/api/skill-health/route.js +1 -1
  174. package/dist/web/standalone/.next/server/app/api/skill-health/route_client-reference-manifest.js +1 -1
  175. package/dist/web/standalone/.next/server/app/api/steer/route.js +1 -1
  176. package/dist/web/standalone/.next/server/app/api/steer/route_client-reference-manifest.js +1 -1
  177. package/dist/web/standalone/.next/server/app/api/switch-root/route.js +1 -1
  178. package/dist/web/standalone/.next/server/app/api/switch-root/route_client-reference-manifest.js +1 -1
  179. package/dist/web/standalone/.next/server/app/api/terminal/input/route.js +2 -2
  180. package/dist/web/standalone/.next/server/app/api/terminal/input/route_client-reference-manifest.js +1 -1
  181. package/dist/web/standalone/.next/server/app/api/terminal/resize/route.js +2 -2
  182. package/dist/web/standalone/.next/server/app/api/terminal/resize/route_client-reference-manifest.js +1 -1
  183. package/dist/web/standalone/.next/server/app/api/terminal/sessions/route.js +2 -2
  184. package/dist/web/standalone/.next/server/app/api/terminal/sessions/route_client-reference-manifest.js +1 -1
  185. package/dist/web/standalone/.next/server/app/api/terminal/stream/route.js +4 -4
  186. package/dist/web/standalone/.next/server/app/api/terminal/stream/route_client-reference-manifest.js +1 -1
  187. package/dist/web/standalone/.next/server/app/api/terminal/upload/route.js +1 -1
  188. package/dist/web/standalone/.next/server/app/api/terminal/upload/route_client-reference-manifest.js +1 -1
  189. package/dist/web/standalone/.next/server/app/api/undo/route.js +1 -1
  190. package/dist/web/standalone/.next/server/app/api/undo/route_client-reference-manifest.js +1 -1
  191. package/dist/web/standalone/.next/server/app/api/update/route.js +1 -1
  192. package/dist/web/standalone/.next/server/app/api/update/route_client-reference-manifest.js +1 -1
  193. package/dist/web/standalone/.next/server/app/api/visualizer/route.js +1 -1
  194. package/dist/web/standalone/.next/server/app/api/visualizer/route_client-reference-manifest.js +1 -1
  195. package/dist/web/standalone/.next/server/app/index.html +1 -1
  196. package/dist/web/standalone/.next/server/app/index.rsc +6 -6
  197. package/dist/web/standalone/.next/server/app/index.segments/__PAGE__.segment.rsc +2 -2
  198. package/dist/web/standalone/.next/server/app/index.segments/_full.segment.rsc +6 -6
  199. package/dist/web/standalone/.next/server/app/index.segments/_head.segment.rsc +1 -1
  200. package/dist/web/standalone/.next/server/app/index.segments/_index.segment.rsc +4 -4
  201. package/dist/web/standalone/.next/server/app/index.segments/_tree.segment.rsc +2 -2
  202. package/dist/web/standalone/.next/server/app/page.js +2 -2
  203. package/dist/web/standalone/.next/server/app/page_client-reference-manifest.js +1 -1
  204. package/dist/web/standalone/.next/server/app-paths-manifest.json +12 -12
  205. package/dist/web/standalone/.next/server/chunks/229.js +1 -1
  206. package/dist/web/standalone/.next/server/chunks/471.js +3 -3
  207. package/dist/web/standalone/.next/server/middleware-build-manifest.js +1 -1
  208. package/dist/web/standalone/.next/server/middleware-react-loadable-manifest.js +1 -1
  209. package/dist/web/standalone/.next/server/middleware.js +2 -2
  210. package/dist/web/standalone/.next/server/next-font-manifest.js +1 -1
  211. package/dist/web/standalone/.next/server/next-font-manifest.json +1 -1
  212. package/dist/web/standalone/.next/server/pages/404.html +1 -1
  213. package/dist/web/standalone/.next/server/pages/500.html +2 -2
  214. package/dist/web/standalone/.next/server/server-reference-manifest.json +1 -1
  215. package/dist/web/standalone/.next/static/chunks/4024.11ca5c01938e5948.js +9 -0
  216. package/dist/web/standalone/.next/static/chunks/{3721.bf31263de6d5fa46.js → 485.243af25f0cdf50d6.js} +2 -2
  217. package/dist/web/standalone/.next/static/chunks/app/_not-found/{page-2f24283c162b6ab3.js → page-f2a7482d42a5614b.js} +1 -1
  218. package/dist/web/standalone/.next/static/chunks/app/{layout-9ecfd95f343793f0.js → layout-a16c7a7ecdf0c2cf.js} +1 -1
  219. package/dist/web/standalone/.next/static/chunks/app/page-6654a8cca61a3d1c.js +1 -0
  220. package/dist/web/standalone/.next/static/chunks/main-app-fdab67f7802d7832.js +1 -0
  221. package/dist/web/standalone/.next/static/chunks/next/dist/client/components/builtin/global-error-459824ffb8c323dd.js +1 -0
  222. package/dist/web/standalone/.next/static/chunks/webpack-0a4cd455ec4197d2.js +1 -0
  223. package/dist/web/standalone/.next/static/css/dd4ae3f58ac9b600.css +1 -0
  224. package/dist/web/standalone/node_modules/node-pty/build/Makefile +2 -2
  225. package/dist/web/standalone/node_modules/node-pty/build/Release/pty.node +0 -0
  226. package/dist/web/standalone/node_modules/node-pty/build/pty.target.mk +14 -14
  227. package/dist/web/standalone/node_modules/node-pty/node-addon-api/node_addon_api.target.mk +14 -14
  228. package/dist/web/standalone/node_modules/node-pty/node-addon-api/node_addon_api_except.target.mk +14 -14
  229. package/dist/web/standalone/node_modules/node-pty/node-addon-api/node_addon_api_maybe.target.mk +14 -14
  230. package/dist/web/standalone/server.js +1 -1
  231. package/package.json +2 -1
  232. package/packages/native/dist/stream-process/index.js +2 -2
  233. package/packages/native/src/__tests__/stream-process.test.mjs +34 -0
  234. package/packages/native/src/stream-process/index.ts +2 -2
  235. package/packages/pi-coding-agent/dist/core/auth-storage.d.ts +3 -1
  236. package/packages/pi-coding-agent/dist/core/auth-storage.d.ts.map +1 -1
  237. package/packages/pi-coding-agent/dist/core/auth-storage.js +15 -1
  238. package/packages/pi-coding-agent/dist/core/auth-storage.js.map +1 -1
  239. package/packages/pi-coding-agent/dist/core/auth-storage.test.js +6 -8
  240. package/packages/pi-coding-agent/dist/core/auth-storage.test.js.map +1 -1
  241. package/packages/pi-coding-agent/dist/core/compaction-orchestrator.d.ts.map +1 -1
  242. package/packages/pi-coding-agent/dist/core/compaction-orchestrator.js +2 -0
  243. package/packages/pi-coding-agent/dist/core/compaction-orchestrator.js.map +1 -1
  244. package/packages/pi-coding-agent/dist/core/extensions/runner.test.js +24 -26
  245. package/packages/pi-coding-agent/dist/core/extensions/runner.test.js.map +1 -1
  246. package/packages/pi-coding-agent/dist/core/extensions/types.d.ts +2 -1
  247. package/packages/pi-coding-agent/dist/core/extensions/types.d.ts.map +1 -1
  248. package/packages/pi-coding-agent/dist/core/extensions/types.js.map +1 -1
  249. package/packages/pi-coding-agent/dist/core/fs-utils.test.js +29 -48
  250. package/packages/pi-coding-agent/dist/core/fs-utils.test.js.map +1 -1
  251. package/packages/pi-coding-agent/dist/core/lifecycle-hooks.d.ts +4 -0
  252. package/packages/pi-coding-agent/dist/core/lifecycle-hooks.d.ts.map +1 -1
  253. package/packages/pi-coding-agent/dist/core/lifecycle-hooks.js +10 -5
  254. package/packages/pi-coding-agent/dist/core/lifecycle-hooks.js.map +1 -1
  255. package/packages/pi-coding-agent/dist/core/lifecycle-hooks.test.d.ts +2 -0
  256. package/packages/pi-coding-agent/dist/core/lifecycle-hooks.test.d.ts.map +1 -0
  257. package/packages/pi-coding-agent/dist/core/lifecycle-hooks.test.js +185 -0
  258. package/packages/pi-coding-agent/dist/core/lifecycle-hooks.test.js.map +1 -0
  259. package/packages/pi-coding-agent/dist/core/local-model-check.d.ts +15 -0
  260. package/packages/pi-coding-agent/dist/core/local-model-check.d.ts.map +1 -0
  261. package/packages/pi-coding-agent/dist/core/local-model-check.js +41 -0
  262. package/packages/pi-coding-agent/dist/core/local-model-check.js.map +1 -0
  263. package/packages/pi-coding-agent/dist/core/model-registry-auth-mode.test.js +239 -10
  264. package/packages/pi-coding-agent/dist/core/model-registry-auth-mode.test.js.map +1 -1
  265. package/packages/pi-coding-agent/dist/core/model-registry.d.ts +13 -1
  266. package/packages/pi-coding-agent/dist/core/model-registry.d.ts.map +1 -1
  267. package/packages/pi-coding-agent/dist/core/model-registry.js +40 -3
  268. package/packages/pi-coding-agent/dist/core/model-registry.js.map +1 -1
  269. package/packages/pi-coding-agent/dist/core/package-commands.test.js +206 -195
  270. package/packages/pi-coding-agent/dist/core/package-commands.test.js.map +1 -1
  271. package/packages/pi-coding-agent/dist/core/resolve-config-value.test.js +34 -44
  272. package/packages/pi-coding-agent/dist/core/resolve-config-value.test.js.map +1 -1
  273. package/packages/pi-coding-agent/dist/core/session-manager.test.js +30 -34
  274. package/packages/pi-coding-agent/dist/core/session-manager.test.js.map +1 -1
  275. package/packages/pi-coding-agent/dist/core/settings-manager.d.ts +3 -0
  276. package/packages/pi-coding-agent/dist/core/settings-manager.d.ts.map +1 -1
  277. package/packages/pi-coding-agent/dist/core/settings-manager.js +6 -0
  278. package/packages/pi-coding-agent/dist/core/settings-manager.js.map +1 -1
  279. package/packages/pi-coding-agent/dist/core/tools/edit-diff.test.js +10 -12
  280. package/packages/pi-coding-agent/dist/core/tools/edit-diff.test.js.map +1 -1
  281. package/packages/pi-coding-agent/dist/main.d.ts.map +1 -1
  282. package/packages/pi-coding-agent/dist/main.js +17 -0
  283. package/packages/pi-coding-agent/dist/main.js.map +1 -1
  284. package/packages/pi-coding-agent/dist/modes/interactive/components/__tests__/timestamp.test.d.ts +2 -0
  285. package/packages/pi-coding-agent/dist/modes/interactive/components/__tests__/timestamp.test.d.ts.map +1 -0
  286. package/packages/pi-coding-agent/dist/modes/interactive/components/__tests__/timestamp.test.js +32 -0
  287. package/packages/pi-coding-agent/dist/modes/interactive/components/__tests__/timestamp.test.js.map +1 -0
  288. package/packages/pi-coding-agent/dist/modes/interactive/components/assistant-message.d.ts +3 -1
  289. package/packages/pi-coding-agent/dist/modes/interactive/components/assistant-message.d.ts.map +1 -1
  290. package/packages/pi-coding-agent/dist/modes/interactive/components/assistant-message.js +8 -1
  291. package/packages/pi-coding-agent/dist/modes/interactive/components/assistant-message.js.map +1 -1
  292. package/packages/pi-coding-agent/dist/modes/interactive/components/settings-selector.d.ts +2 -0
  293. package/packages/pi-coding-agent/dist/modes/interactive/components/settings-selector.d.ts.map +1 -1
  294. package/packages/pi-coding-agent/dist/modes/interactive/components/settings-selector.js +12 -0
  295. package/packages/pi-coding-agent/dist/modes/interactive/components/settings-selector.js.map +1 -1
  296. package/packages/pi-coding-agent/dist/modes/interactive/components/timestamp.d.ts +15 -0
  297. package/packages/pi-coding-agent/dist/modes/interactive/components/timestamp.d.ts.map +1 -0
  298. package/packages/pi-coding-agent/dist/modes/interactive/components/timestamp.js +40 -0
  299. package/packages/pi-coding-agent/dist/modes/interactive/components/timestamp.js.map +1 -0
  300. package/packages/pi-coding-agent/dist/modes/interactive/components/tool-execution.d.ts.map +1 -1
  301. package/packages/pi-coding-agent/dist/modes/interactive/components/tool-execution.js +4 -1
  302. package/packages/pi-coding-agent/dist/modes/interactive/components/tool-execution.js.map +1 -1
  303. package/packages/pi-coding-agent/dist/modes/interactive/components/user-message.d.ts +5 -2
  304. package/packages/pi-coding-agent/dist/modes/interactive/components/user-message.d.ts.map +1 -1
  305. package/packages/pi-coding-agent/dist/modes/interactive/components/user-message.js +13 -2
  306. package/packages/pi-coding-agent/dist/modes/interactive/components/user-message.js.map +1 -1
  307. package/packages/pi-coding-agent/dist/modes/interactive/controllers/chat-controller.d.ts.map +1 -1
  308. package/packages/pi-coding-agent/dist/modes/interactive/controllers/chat-controller.js +17 -8
  309. package/packages/pi-coding-agent/dist/modes/interactive/controllers/chat-controller.js.map +1 -1
  310. package/packages/pi-coding-agent/dist/modes/interactive/interactive-mode.d.ts.map +1 -1
  311. package/packages/pi-coding-agent/dist/modes/interactive/interactive-mode.js +7 -3
  312. package/packages/pi-coding-agent/dist/modes/interactive/interactive-mode.js.map +1 -1
  313. package/packages/pi-coding-agent/dist/resources/extensions/memory/storage.test.js +43 -47
  314. package/packages/pi-coding-agent/dist/resources/extensions/memory/storage.test.js.map +1 -1
  315. package/packages/pi-coding-agent/package.json +1 -1
  316. package/packages/pi-coding-agent/src/core/auth-storage.test.ts +7 -7
  317. package/packages/pi-coding-agent/src/core/auth-storage.ts +15 -1
  318. package/packages/pi-coding-agent/src/core/compaction-orchestrator.ts +2 -0
  319. package/packages/pi-coding-agent/src/core/extensions/runner.test.ts +26 -26
  320. package/packages/pi-coding-agent/src/core/extensions/types.ts +2 -1
  321. package/packages/pi-coding-agent/src/core/fs-utils.test.ts +31 -43
  322. package/packages/pi-coding-agent/src/core/lifecycle-hooks.test.ts +227 -0
  323. package/packages/pi-coding-agent/src/core/lifecycle-hooks.ts +11 -5
  324. package/packages/pi-coding-agent/src/core/local-model-check.ts +45 -0
  325. package/packages/pi-coding-agent/src/core/model-registry-auth-mode.test.ts +297 -11
  326. package/packages/pi-coding-agent/src/core/model-registry.ts +51 -4
  327. package/packages/pi-coding-agent/src/core/package-commands.test.ts +227 -205
  328. package/packages/pi-coding-agent/src/core/resolve-config-value.test.ts +40 -45
  329. package/packages/pi-coding-agent/src/core/session-manager.test.ts +33 -33
  330. package/packages/pi-coding-agent/src/core/settings-manager.ts +9 -0
  331. package/packages/pi-coding-agent/src/core/tools/edit-diff.test.ts +17 -17
  332. package/packages/pi-coding-agent/src/main.ts +19 -0
  333. package/packages/pi-coding-agent/src/modes/interactive/components/__tests__/timestamp.test.ts +38 -0
  334. package/packages/pi-coding-agent/src/modes/interactive/components/assistant-message.ts +10 -0
  335. package/packages/pi-coding-agent/src/modes/interactive/components/settings-selector.ts +15 -0
  336. package/packages/pi-coding-agent/src/modes/interactive/components/timestamp.ts +48 -0
  337. package/packages/pi-coding-agent/src/modes/interactive/components/tool-execution.ts +3 -1
  338. package/packages/pi-coding-agent/src/modes/interactive/components/user-message.ts +18 -3
  339. package/packages/pi-coding-agent/src/modes/interactive/controllers/chat-controller.ts +16 -7
  340. package/packages/pi-coding-agent/src/modes/interactive/interactive-mode.ts +8 -1
  341. package/packages/pi-coding-agent/src/resources/extensions/memory/storage.test.ts +74 -74
  342. package/pkg/package.json +1 -1
  343. package/src/resources/extensions/gsd/activity-log.ts +1 -0
  344. package/src/resources/extensions/gsd/auto/infra-errors.ts +3 -0
  345. package/src/resources/extensions/gsd/auto/loop-deps.ts +0 -19
  346. package/src/resources/extensions/gsd/auto/phases.ts +69 -91
  347. package/src/resources/extensions/gsd/auto/run-unit.ts +6 -3
  348. package/src/resources/extensions/gsd/auto/session.ts +0 -18
  349. package/src/resources/extensions/gsd/auto-artifact-paths.ts +131 -0
  350. package/src/resources/extensions/gsd/auto-dashboard.ts +0 -1
  351. package/src/resources/extensions/gsd/auto-post-unit.ts +25 -106
  352. package/src/resources/extensions/gsd/auto-prompts.ts +24 -1
  353. package/src/resources/extensions/gsd/auto-start.ts +40 -5
  354. package/src/resources/extensions/gsd/auto-timers.ts +64 -3
  355. package/src/resources/extensions/gsd/auto-worktree-sync.ts +5 -0
  356. package/src/resources/extensions/gsd/auto-worktree.ts +17 -11
  357. package/src/resources/extensions/gsd/auto.ts +44 -86
  358. package/src/resources/extensions/gsd/bootstrap/db-tools.ts +162 -11
  359. package/src/resources/extensions/gsd/bootstrap/register-hooks.ts +22 -0
  360. package/src/resources/extensions/gsd/bootstrap/system-context.ts +48 -11
  361. package/src/resources/extensions/gsd/commands/catalog.ts +7 -1
  362. package/src/resources/extensions/gsd/commands/context.ts +0 -5
  363. package/src/resources/extensions/gsd/commands/handlers/core.ts +2 -0
  364. package/src/resources/extensions/gsd/commands/handlers/ops.ts +10 -0
  365. package/src/resources/extensions/gsd/commands/handlers/parallel.ts +1 -1
  366. package/src/resources/extensions/gsd/commands/handlers/workflow.ts +8 -0
  367. package/src/resources/extensions/gsd/commands-mcp-status.ts +247 -0
  368. package/src/resources/extensions/gsd/crash-recovery.ts +1 -5
  369. package/src/resources/extensions/gsd/dashboard-overlay.ts +0 -50
  370. package/src/resources/extensions/gsd/db-writer.ts +41 -27
  371. package/src/resources/extensions/gsd/doctor-checks.ts +180 -2
  372. package/src/resources/extensions/gsd/doctor-types.ts +7 -1
  373. package/src/resources/extensions/gsd/doctor.ts +13 -4
  374. package/src/resources/extensions/gsd/git-service.ts +6 -2
  375. package/src/resources/extensions/gsd/gsd-db.ts +32 -4
  376. package/src/resources/extensions/gsd/guided-flow.ts +1 -2
  377. package/src/resources/extensions/gsd/journal.ts +6 -1
  378. package/src/resources/extensions/gsd/markdown-renderer.ts +1 -1
  379. package/src/resources/extensions/gsd/parallel-merge.ts +1 -1
  380. package/src/resources/extensions/gsd/parallel-orchestrator.ts +5 -21
  381. package/src/resources/extensions/gsd/preferences-types.ts +2 -2
  382. package/src/resources/extensions/gsd/preferences.ts +18 -4
  383. package/src/resources/extensions/gsd/prompts/complete-milestone.md +21 -10
  384. package/src/resources/extensions/gsd/prompts/complete-slice.md +10 -23
  385. package/src/resources/extensions/gsd/prompts/discuss.md +2 -2
  386. package/src/resources/extensions/gsd/prompts/execute-task.md +5 -15
  387. package/src/resources/extensions/gsd/prompts/guided-discuss-milestone.md +1 -1
  388. package/src/resources/extensions/gsd/prompts/guided-discuss-slice.md +1 -1
  389. package/src/resources/extensions/gsd/prompts/guided-plan-slice.md +1 -1
  390. package/src/resources/extensions/gsd/prompts/guided-research-slice.md +1 -1
  391. package/src/resources/extensions/gsd/prompts/plan-milestone.md +1 -1
  392. package/src/resources/extensions/gsd/prompts/plan-slice.md +5 -3
  393. package/src/resources/extensions/gsd/prompts/queue.md +2 -2
  394. package/src/resources/extensions/gsd/prompts/quick-task.md +2 -0
  395. package/src/resources/extensions/gsd/prompts/reactive-execute.md +1 -1
  396. package/src/resources/extensions/gsd/prompts/reassess-roadmap.md +6 -6
  397. package/src/resources/extensions/gsd/prompts/replan-slice.md +3 -14
  398. package/src/resources/extensions/gsd/prompts/research-slice.md +3 -3
  399. package/src/resources/extensions/gsd/prompts/rethink.md +83 -0
  400. package/src/resources/extensions/gsd/prompts/system.md +1 -1
  401. package/src/resources/extensions/gsd/prompts/validate-milestone.md +7 -37
  402. package/src/resources/extensions/gsd/provider-error-pause.ts +9 -0
  403. package/src/resources/extensions/gsd/repo-identity.ts +46 -7
  404. package/src/resources/extensions/gsd/rethink.ts +154 -0
  405. package/src/resources/extensions/gsd/session-lock.ts +0 -4
  406. package/src/resources/extensions/gsd/state.ts +49 -1
  407. package/src/resources/extensions/gsd/sync-lock.ts +94 -0
  408. package/src/resources/extensions/gsd/tests/all-milestones-complete-merge.test.ts +99 -99
  409. package/src/resources/extensions/gsd/tests/auto-lock-creation.test.ts +19 -29
  410. package/src/resources/extensions/gsd/tests/auto-loop.test.ts +6 -10
  411. package/src/resources/extensions/gsd/tests/auto-paused-session-validation.test.ts +43 -57
  412. package/src/resources/extensions/gsd/tests/auto-pr-bugs.test.ts +88 -0
  413. package/src/resources/extensions/gsd/tests/auto-preflight.test.ts +11 -13
  414. package/src/resources/extensions/gsd/tests/auto-recovery.test.ts +465 -523
  415. package/src/resources/extensions/gsd/tests/auto-secrets-gate.test.ts +73 -75
  416. package/src/resources/extensions/gsd/tests/auto-start-needs-discussion.test.ts +34 -56
  417. package/src/resources/extensions/gsd/tests/auto-worktree-milestone-merge.test.ts +533 -656
  418. package/src/resources/extensions/gsd/tests/auto-worktree.test.ts +165 -143
  419. package/src/resources/extensions/gsd/tests/cache-staleness-regression.test.ts +29 -52
  420. package/src/resources/extensions/gsd/tests/captures.test.ts +148 -176
  421. package/src/resources/extensions/gsd/tests/claude-import-tui.test.ts +32 -33
  422. package/src/resources/extensions/gsd/tests/collect-from-manifest.test.ts +141 -143
  423. package/src/resources/extensions/gsd/tests/commands-inspect-open-db.test.ts +25 -25
  424. package/src/resources/extensions/gsd/tests/commands-logs.test.ts +81 -81
  425. package/src/resources/extensions/gsd/tests/complete-milestone.test.ts +134 -59
  426. package/src/resources/extensions/gsd/tests/complete-slice.test.ts +15 -14
  427. package/src/resources/extensions/gsd/tests/complete-task.test.ts +27 -12
  428. package/src/resources/extensions/gsd/tests/completed-units-metrics-sync.test.ts +114 -0
  429. package/src/resources/extensions/gsd/tests/context-store.test.ts +354 -367
  430. package/src/resources/extensions/gsd/tests/continue-here.test.ts +68 -72
  431. package/src/resources/extensions/gsd/tests/cost-projection.test.ts +92 -106
  432. package/src/resources/extensions/gsd/tests/crash-recovery.test.ts +26 -40
  433. package/src/resources/extensions/gsd/tests/custom-engine-loop-integration.test.ts +0 -3
  434. package/src/resources/extensions/gsd/tests/dashboard-budget.test.ts +220 -237
  435. package/src/resources/extensions/gsd/tests/db-writer.test.ts +465 -416
  436. package/src/resources/extensions/gsd/tests/definition-loader.test.ts +76 -92
  437. package/src/resources/extensions/gsd/tests/derive-state-crossval.test.ts +68 -83
  438. package/src/resources/extensions/gsd/tests/derive-state-db-disk-reconcile.test.ts +121 -0
  439. package/src/resources/extensions/gsd/tests/derive-state-db.test.ts +210 -181
  440. package/src/resources/extensions/gsd/tests/derive-state-deps.test.ts +78 -101
  441. package/src/resources/extensions/gsd/tests/derive-state.test.ts +192 -227
  442. package/src/resources/extensions/gsd/tests/detection.test.ts +232 -278
  443. package/src/resources/extensions/gsd/tests/dev-engine-wrapper.test.ts +30 -34
  444. package/src/resources/extensions/gsd/tests/dispatch-guard.test.ts +164 -180
  445. package/src/resources/extensions/gsd/tests/dispatch-missing-task-plans.test.ts +43 -49
  446. package/src/resources/extensions/gsd/tests/dispatch-uat-last-completed.test.ts +28 -32
  447. package/src/resources/extensions/gsd/tests/doctor-completion-deferral.test.ts +27 -29
  448. package/src/resources/extensions/gsd/tests/doctor-delimiter-fix.test.ts +34 -38
  449. package/src/resources/extensions/gsd/tests/doctor-enhancements.test.ts +54 -75
  450. package/src/resources/extensions/gsd/tests/doctor-environment-worktree.test.ts +21 -32
  451. package/src/resources/extensions/gsd/tests/doctor-environment.test.ts +72 -97
  452. package/src/resources/extensions/gsd/tests/doctor-fixlevel.test.ts +38 -44
  453. package/src/resources/extensions/gsd/tests/doctor-git.test.ts +104 -145
  454. package/src/resources/extensions/gsd/tests/doctor-proactive.test.ts +84 -106
  455. package/src/resources/extensions/gsd/tests/doctor-roadmap-summary-atomicity.test.ts +54 -60
  456. package/src/resources/extensions/gsd/tests/doctor-runtime.test.ts +72 -93
  457. package/src/resources/extensions/gsd/tests/doctor.test.ts +104 -134
  458. package/src/resources/extensions/gsd/tests/ensure-db-open.test.ts +123 -131
  459. package/src/resources/extensions/gsd/tests/est-annotation-timeout.test.ts +120 -0
  460. package/src/resources/extensions/gsd/tests/exit-command.test.ts +20 -24
  461. package/src/resources/extensions/gsd/tests/feature-branch-lifecycle-integration.test.ts +48 -57
  462. package/src/resources/extensions/gsd/tests/files-loadfile-eisdir.test.ts +5 -7
  463. package/src/resources/extensions/gsd/tests/flag-file-db.test.ts +30 -42
  464. package/src/resources/extensions/gsd/tests/freeform-decisions.test.ts +198 -206
  465. package/src/resources/extensions/gsd/tests/git-locale.test.ts +13 -27
  466. package/src/resources/extensions/gsd/tests/git-service.test.ts +285 -388
  467. package/src/resources/extensions/gsd/tests/gitignore-tracked-gsd.test.ts +31 -39
  468. package/src/resources/extensions/gsd/tests/graph-operations.test.ts +63 -69
  469. package/src/resources/extensions/gsd/tests/gsd-db.test.ts +255 -264
  470. package/src/resources/extensions/gsd/tests/gsd-inspect.test.ts +108 -119
  471. package/src/resources/extensions/gsd/tests/gsd-recover.test.ts +81 -103
  472. package/src/resources/extensions/gsd/tests/gsd-tools.test.ts +229 -262
  473. package/src/resources/extensions/gsd/tests/headless-answers.test.ts +13 -13
  474. package/src/resources/extensions/gsd/tests/health-widget.test.ts +29 -37
  475. package/src/resources/extensions/gsd/tests/idle-recovery.test.ts +82 -103
  476. package/src/resources/extensions/gsd/tests/infra-error.test.ts +20 -2
  477. package/src/resources/extensions/gsd/tests/inherited-repo-home-dir.test.ts +121 -0
  478. package/src/resources/extensions/gsd/tests/init-wizard.test.ts +16 -18
  479. package/src/resources/extensions/gsd/tests/integration-edge.test.ts +41 -46
  480. package/src/resources/extensions/gsd/tests/integration-lifecycle.test.ts +42 -53
  481. package/src/resources/extensions/gsd/tests/integration-mixed-milestones.test.ts +75 -91
  482. package/src/resources/extensions/gsd/tests/integration-proof.test.ts +33 -42
  483. package/src/resources/extensions/gsd/tests/journal-integration.test.ts +0 -3
  484. package/src/resources/extensions/gsd/tests/knowledge.test.ts +89 -0
  485. package/src/resources/extensions/gsd/tests/markdown-renderer.test.ts +150 -194
  486. package/src/resources/extensions/gsd/tests/mcp-status.test.ts +103 -0
  487. package/src/resources/extensions/gsd/tests/md-importer.test.ts +101 -125
  488. package/src/resources/extensions/gsd/tests/memory-extractor.test.ts +45 -54
  489. package/src/resources/extensions/gsd/tests/memory-store.test.ts +81 -94
  490. package/src/resources/extensions/gsd/tests/merge-conflict-stops-loop.test.ts +66 -0
  491. package/src/resources/extensions/gsd/tests/migrate-command.test.ts +57 -66
  492. package/src/resources/extensions/gsd/tests/migrate-hierarchy.test.ts +83 -93
  493. package/src/resources/extensions/gsd/tests/migrate-parser.test.ts +161 -170
  494. package/src/resources/extensions/gsd/tests/migrate-transformer.test.ts +125 -141
  495. package/src/resources/extensions/gsd/tests/migrate-validator-parsers.test.ts +107 -131
  496. package/src/resources/extensions/gsd/tests/migrate-writer-integration.test.ts +87 -96
  497. package/src/resources/extensions/gsd/tests/migrate-writer.test.ts +125 -164
  498. package/src/resources/extensions/gsd/tests/milestone-transition-state-rebuild.test.ts +8 -9
  499. package/src/resources/extensions/gsd/tests/must-have-parser.test.ts +81 -94
  500. package/src/resources/extensions/gsd/tests/none-mode-gates.test.ts +75 -37
  501. package/src/resources/extensions/gsd/tests/overrides.test.ts +99 -106
  502. package/src/resources/extensions/gsd/tests/parallel-budget-atomicity.test.ts +0 -1
  503. package/src/resources/extensions/gsd/tests/parallel-crash-recovery.test.ts +39 -53
  504. package/src/resources/extensions/gsd/tests/parallel-merge.test.ts +7 -8
  505. package/src/resources/extensions/gsd/tests/parallel-orchestration.test.ts +20 -24
  506. package/src/resources/extensions/gsd/tests/parallel-worker-monitoring.test.ts +24 -29
  507. package/src/resources/extensions/gsd/tests/parallel-workers-multi-milestone-e2e.test.ts +66 -83
  508. package/src/resources/extensions/gsd/tests/park-edge-cases.test.ts +54 -77
  509. package/src/resources/extensions/gsd/tests/park-milestone.test.ts +68 -115
  510. package/src/resources/extensions/gsd/tests/parsers.test.ts +546 -611
  511. package/src/resources/extensions/gsd/tests/paths.test.ts +72 -87
  512. package/src/resources/extensions/gsd/tests/plan-milestone.test.ts +9 -6
  513. package/src/resources/extensions/gsd/tests/post-mutation-hook.test.ts +171 -0
  514. package/src/resources/extensions/gsd/tests/post-unit-hooks.test.ts +77 -117
  515. package/src/resources/extensions/gsd/tests/preferences.test.ts +34 -9
  516. package/src/resources/extensions/gsd/tests/projection-regression.test.ts +174 -0
  517. package/src/resources/extensions/gsd/tests/prompt-contracts.test.ts +26 -21
  518. package/src/resources/extensions/gsd/tests/prompt-db.test.ts +56 -56
  519. package/src/resources/extensions/gsd/tests/queue-draft-detection.test.ts +93 -119
  520. package/src/resources/extensions/gsd/tests/queue-order.test.ts +70 -82
  521. package/src/resources/extensions/gsd/tests/queue-reorder-e2e.test.ts +42 -55
  522. package/src/resources/extensions/gsd/tests/quick-auto-guard.test.ts +100 -0
  523. package/src/resources/extensions/gsd/tests/quick-branch-lifecycle.test.ts +45 -73
  524. package/src/resources/extensions/gsd/tests/reassess-prompt.test.ts +28 -38
  525. package/src/resources/extensions/gsd/tests/recovery-attempts-reset.test.ts +176 -0
  526. package/src/resources/extensions/gsd/tests/reopen-slice.test.ts +155 -0
  527. package/src/resources/extensions/gsd/tests/reopen-task.test.ts +165 -0
  528. package/src/resources/extensions/gsd/tests/replan-slice.test.ts +73 -80
  529. package/src/resources/extensions/gsd/tests/repo-identity-worktree.test.ts +71 -74
  530. package/src/resources/extensions/gsd/tests/requirements.test.ts +70 -75
  531. package/src/resources/extensions/gsd/tests/retry-state-reset.test.ts +44 -66
  532. package/src/resources/extensions/gsd/tests/roadmap-parse-regression.test.ts +114 -181
  533. package/src/resources/extensions/gsd/tests/rule-registry.test.ts +63 -65
  534. package/src/resources/extensions/gsd/tests/run-uat.test.ts +66 -128
  535. package/src/resources/extensions/gsd/tests/session-lock-multipath.test.ts +18 -25
  536. package/src/resources/extensions/gsd/tests/session-lock-regression.test.ts +37 -47
  537. package/src/resources/extensions/gsd/tests/shared-wal.test.ts +19 -26
  538. package/src/resources/extensions/gsd/tests/sqlite-unavailable-gate.test.ts +63 -0
  539. package/src/resources/extensions/gsd/tests/stalled-tool-recovery.test.ts +6 -8
  540. package/src/resources/extensions/gsd/tests/stop-auto-merge-back.test.ts +67 -0
  541. package/src/resources/extensions/gsd/tests/stop-auto-remote.test.ts +2 -3
  542. package/src/resources/extensions/gsd/tests/survivor-branch-complete.test.ts +108 -0
  543. package/src/resources/extensions/gsd/tests/symlink-numbered-variants.test.ts +22 -28
  544. package/src/resources/extensions/gsd/tests/sync-lock.test.ts +122 -0
  545. package/src/resources/extensions/gsd/tests/terminated-transient.test.ts +49 -0
  546. package/src/resources/extensions/gsd/tests/token-savings.test.ts +54 -56
  547. package/src/resources/extensions/gsd/tests/tool-call-loop-guard.test.ts +23 -25
  548. package/src/resources/extensions/gsd/tests/tool-naming.test.ts +10 -11
  549. package/src/resources/extensions/gsd/tests/unique-milestone-ids.test.ts +66 -82
  550. package/src/resources/extensions/gsd/tests/unit-ownership.test.ts +175 -0
  551. package/src/resources/extensions/gsd/tests/unit-runtime.test.ts +46 -47
  552. package/src/resources/extensions/gsd/tests/visualizer-critical-path.test.ts +20 -22
  553. package/src/resources/extensions/gsd/tests/visualizer-data.test.ts +84 -86
  554. package/src/resources/extensions/gsd/tests/visualizer-overlay.test.ts +41 -43
  555. package/src/resources/extensions/gsd/tests/visualizer-views.test.ts +94 -96
  556. package/src/resources/extensions/gsd/tests/windows-path-normalization.test.ts +11 -13
  557. package/src/resources/extensions/gsd/tests/worker-registry.test.ts +27 -29
  558. package/src/resources/extensions/gsd/tests/workflow-events.test.ts +205 -0
  559. package/src/resources/extensions/gsd/tests/workflow-logger.test.ts +275 -0
  560. package/src/resources/extensions/gsd/tests/workflow-manifest.test.ts +186 -0
  561. package/src/resources/extensions/gsd/tests/workflow-projections.test.ts +171 -0
  562. package/src/resources/extensions/gsd/tests/workflow-templates.test.ts +50 -52
  563. package/src/resources/extensions/gsd/tests/worktree-bugfix.test.ts +10 -13
  564. package/src/resources/extensions/gsd/tests/worktree-db-integration.test.ts +14 -18
  565. package/src/resources/extensions/gsd/tests/worktree-db.test.ts +38 -39
  566. package/src/resources/extensions/gsd/tests/worktree-e2e.test.ts +17 -21
  567. package/src/resources/extensions/gsd/tests/worktree-health.test.ts +25 -30
  568. package/src/resources/extensions/gsd/tests/worktree-integration.test.ts +30 -37
  569. package/src/resources/extensions/gsd/tests/worktree-journal-events.test.ts +220 -0
  570. package/src/resources/extensions/gsd/tests/worktree-submodule-safety.test.ts +65 -0
  571. package/src/resources/extensions/gsd/tests/worktree-symlink-removal.test.ts +15 -22
  572. package/src/resources/extensions/gsd/tests/worktree-sync-milestones.test.ts +59 -66
  573. package/src/resources/extensions/gsd/tests/worktree.test.ts +44 -50
  574. package/src/resources/extensions/gsd/tests/write-intercept.test.ts +76 -0
  575. package/src/resources/extensions/gsd/tools/complete-milestone.ts +74 -11
  576. package/src/resources/extensions/gsd/tools/complete-slice.ts +68 -11
  577. package/src/resources/extensions/gsd/tools/complete-task.ts +63 -1
  578. package/src/resources/extensions/gsd/tools/plan-milestone.ts +45 -0
  579. package/src/resources/extensions/gsd/tools/plan-slice.ts +40 -0
  580. package/src/resources/extensions/gsd/tools/plan-task.ts +37 -1
  581. package/src/resources/extensions/gsd/tools/reassess-roadmap.ts +39 -1
  582. package/src/resources/extensions/gsd/tools/reopen-slice.ts +125 -0
  583. package/src/resources/extensions/gsd/tools/reopen-task.ts +129 -0
  584. package/src/resources/extensions/gsd/tools/replan-slice.ts +41 -1
  585. package/src/resources/extensions/gsd/tools/validate-milestone.ts +127 -0
  586. package/src/resources/extensions/gsd/types.ts +8 -0
  587. package/src/resources/extensions/gsd/unit-ownership.ts +104 -0
  588. package/src/resources/extensions/gsd/workflow-events.ts +154 -0
  589. package/src/resources/extensions/gsd/workflow-logger.ts +243 -0
  590. package/src/resources/extensions/gsd/workflow-manifest.ts +334 -0
  591. package/src/resources/extensions/gsd/workflow-migration.ts +345 -0
  592. package/src/resources/extensions/gsd/workflow-projections.ts +425 -0
  593. package/src/resources/extensions/gsd/workflow-reconcile.ts +503 -0
  594. package/src/resources/extensions/gsd/worktree-manager.ts +41 -5
  595. package/src/resources/extensions/gsd/worktree-resolver.ts +44 -0
  596. package/src/resources/extensions/gsd/write-intercept.ts +90 -0
  597. package/src/resources/extensions/mcp-client/index.ts +20 -0
  598. package/src/resources/extensions/voice/index.ts +11 -21
  599. package/src/resources/extensions/voice/linux-ready.ts +87 -0
  600. package/src/resources/extensions/voice/tests/linux-ready.test.ts +124 -0
  601. package/dist/web/standalone/.next/static/chunks/4024.0de81b543b28b9fe.js +0 -9
  602. package/dist/web/standalone/.next/static/chunks/app/page-7e9530a7122506c5.js +0 -1
  603. package/dist/web/standalone/.next/static/chunks/main-app-d3d4c336195465f9.js +0 -1
  604. package/dist/web/standalone/.next/static/chunks/next/dist/client/components/builtin/global-error-ab5a8926e07ec673.js +0 -1
  605. package/dist/web/standalone/.next/static/chunks/webpack-9014b5adb127a98a.js +0 -1
  606. package/dist/web/standalone/.next/static/css/8a727f372cf53002.css +0 -1
  607. /package/dist/web/standalone/.next/static/{mgkxN0mGP6gSUmGPEzbk_ → j-BskPs0nxxPeYY-bSrab}/_buildManifest.js +0 -0
  608. /package/dist/web/standalone/.next/static/{mgkxN0mGP6gSUmGPEzbk_ → j-BskPs0nxxPeYY-bSrab}/_ssgManifest.js +0 -0
@@ -1,5 +1,5 @@
1
1
  import assert from "node:assert/strict";
2
- import { describe, it } from "node:test";
2
+ import { describe, it, afterEach } from "node:test";
3
3
  import { mkdtempSync, rmSync, readFileSync } from "node:fs";
4
4
  import { join } from "node:path";
5
5
  import { tmpdir } from "node:os";
@@ -11,57 +11,53 @@ function wait(ms) {
11
11
  return new Promise((resolve) => setTimeout(resolve, ms));
12
12
  }
13
13
  describe("MemoryStorage debounced persistence", () => {
14
- it("multiple rapid mutations only trigger one persist write", async () => {
15
- const dir = makeTmpDir();
16
- const dbPath = join(dir, "test.db");
17
- try {
18
- const storage = await MemoryStorage.create(dbPath);
19
- const initialStat = readFileSync(dbPath);
20
- const initialMtime = initialStat.length;
21
- storage.upsertThreads([
22
- { threadId: "t1", filePath: "/a.txt", fileSize: 100, fileMtime: 1000, cwd: "/proj" },
23
- ]);
24
- storage.upsertThreads([
25
- { threadId: "t2", filePath: "/b.txt", fileSize: 200, fileMtime: 2000, cwd: "/proj" },
26
- ]);
27
- storage.upsertThreads([
28
- { threadId: "t3", filePath: "/c.txt", fileSize: 300, fileMtime: 3000, cwd: "/proj" },
29
- ]);
30
- const afterMutationsBuf = readFileSync(dbPath);
31
- assert.deepEqual(afterMutationsBuf, initialStat, "File should not have been written yet (debounce window has not elapsed)");
32
- await wait(700);
33
- const afterDebounceBuf = readFileSync(dbPath);
34
- assert.notDeepEqual(afterDebounceBuf, initialStat, "File should have been written after debounce window elapsed");
35
- const stats = storage.getStats();
36
- assert.equal(stats.totalThreads, 3);
37
- storage.close();
38
- }
39
- finally {
14
+ let dir;
15
+ afterEach(() => {
16
+ if (dir) {
40
17
  rmSync(dir, { recursive: true, force: true });
41
18
  }
42
19
  });
20
+ it("multiple rapid mutations only trigger one persist write", async () => {
21
+ dir = makeTmpDir();
22
+ const dbPath = join(dir, "test.db");
23
+ const storage = await MemoryStorage.create(dbPath);
24
+ const initialStat = readFileSync(dbPath);
25
+ const initialMtime = initialStat.length;
26
+ storage.upsertThreads([
27
+ { threadId: "t1", filePath: "/a.txt", fileSize: 100, fileMtime: 1000, cwd: "/proj" },
28
+ ]);
29
+ storage.upsertThreads([
30
+ { threadId: "t2", filePath: "/b.txt", fileSize: 200, fileMtime: 2000, cwd: "/proj" },
31
+ ]);
32
+ storage.upsertThreads([
33
+ { threadId: "t3", filePath: "/c.txt", fileSize: 300, fileMtime: 3000, cwd: "/proj" },
34
+ ]);
35
+ const afterMutationsBuf = readFileSync(dbPath);
36
+ assert.deepEqual(afterMutationsBuf, initialStat, "File should not have been written yet (debounce window has not elapsed)");
37
+ await wait(700);
38
+ const afterDebounceBuf = readFileSync(dbPath);
39
+ assert.notDeepEqual(afterDebounceBuf, initialStat, "File should have been written after debounce window elapsed");
40
+ const stats = storage.getStats();
41
+ assert.equal(stats.totalThreads, 3);
42
+ storage.close();
43
+ });
43
44
  it("close() flushes pending changes immediately without waiting for debounce", async () => {
44
- const dir = makeTmpDir();
45
+ dir = makeTmpDir();
45
46
  const dbPath = join(dir, "test.db");
46
- try {
47
- const storage = await MemoryStorage.create(dbPath);
48
- const initialBuf = readFileSync(dbPath);
49
- storage.upsertThreads([
50
- { threadId: "t1", filePath: "/a.txt", fileSize: 100, fileMtime: 1000, cwd: "/proj" },
51
- ]);
52
- const beforeCloseBuf = readFileSync(dbPath);
53
- assert.deepEqual(beforeCloseBuf, initialBuf, "File should not have been written yet (debounce window has not elapsed)");
54
- storage.close();
55
- const afterCloseBuf = readFileSync(dbPath);
56
- assert.notDeepEqual(afterCloseBuf, initialBuf, "File should have been written immediately on close()");
57
- const reopened = await MemoryStorage.create(dbPath);
58
- const stats = reopened.getStats();
59
- assert.equal(stats.totalThreads, 1, "Data should be persisted and readable after close");
60
- reopened.close();
61
- }
62
- finally {
63
- rmSync(dir, { recursive: true, force: true });
64
- }
47
+ const storage = await MemoryStorage.create(dbPath);
48
+ const initialBuf = readFileSync(dbPath);
49
+ storage.upsertThreads([
50
+ { threadId: "t1", filePath: "/a.txt", fileSize: 100, fileMtime: 1000, cwd: "/proj" },
51
+ ]);
52
+ const beforeCloseBuf = readFileSync(dbPath);
53
+ assert.deepEqual(beforeCloseBuf, initialBuf, "File should not have been written yet (debounce window has not elapsed)");
54
+ storage.close();
55
+ const afterCloseBuf = readFileSync(dbPath);
56
+ assert.notDeepEqual(afterCloseBuf, initialBuf, "File should have been written immediately on close()");
57
+ const reopened = await MemoryStorage.create(dbPath);
58
+ const stats = reopened.getStats();
59
+ assert.equal(stats.totalThreads, 1, "Data should be persisted and readable after close");
60
+ reopened.close();
65
61
  });
66
62
  });
67
63
  //# sourceMappingURL=storage.test.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"storage.test.js","sourceRoot":"","sources":["../../../../src/resources/extensions/memory/storage.test.ts"],"names":[],"mappings":"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","sourcesContent":["import assert from \"node:assert/strict\";\nimport { describe, it, mock } from \"node:test\";\nimport { mkdtempSync, rmSync, readFileSync, existsSync } from \"node:fs\";\nimport { join } from \"node:path\";\nimport { tmpdir } from \"node:os\";\n\nimport { MemoryStorage } from \"./storage.js\";\n\nfunction makeTmpDir(): string {\n\treturn mkdtempSync(join(tmpdir(), \"gsd-memory-storage-test-\"));\n}\n\nfunction wait(ms: number): Promise<void> {\n\treturn new Promise((resolve) => setTimeout(resolve, ms));\n}\n\ndescribe(\"MemoryStorage debounced persistence\", () => {\n\tit(\"multiple rapid mutations only trigger one persist write\", async () => {\n\t\tconst dir = makeTmpDir();\n\t\tconst dbPath = join(dir, \"test.db\");\n\t\ttry {\n\t\t\tconst storage = await MemoryStorage.create(dbPath);\n\n\t\t\tconst initialStat = readFileSync(dbPath);\n\t\t\tconst initialMtime = initialStat.length;\n\n\t\t\tstorage.upsertThreads([\n\t\t\t\t{ threadId: \"t1\", filePath: \"/a.txt\", fileSize: 100, fileMtime: 1000, cwd: \"/proj\" },\n\t\t\t]);\n\t\t\tstorage.upsertThreads([\n\t\t\t\t{ threadId: \"t2\", filePath: \"/b.txt\", fileSize: 200, fileMtime: 2000, cwd: \"/proj\" },\n\t\t\t]);\n\t\t\tstorage.upsertThreads([\n\t\t\t\t{ threadId: \"t3\", filePath: \"/c.txt\", fileSize: 300, fileMtime: 3000, cwd: \"/proj\" },\n\t\t\t]);\n\n\t\t\tconst afterMutationsBuf = readFileSync(dbPath);\n\t\t\tassert.deepEqual(\n\t\t\t\tafterMutationsBuf,\n\t\t\t\tinitialStat,\n\t\t\t\t\"File should not have been written yet (debounce window has not elapsed)\",\n\t\t\t);\n\n\t\t\tawait wait(700);\n\n\t\t\tconst afterDebounceBuf = readFileSync(dbPath);\n\t\t\tassert.notDeepEqual(\n\t\t\t\tafterDebounceBuf,\n\t\t\t\tinitialStat,\n\t\t\t\t\"File should have been written after debounce window elapsed\",\n\t\t\t);\n\n\t\t\tconst stats = storage.getStats();\n\t\t\tassert.equal(stats.totalThreads, 3);\n\n\t\t\tstorage.close();\n\t\t} finally {\n\t\t\trmSync(dir, { recursive: true, force: true });\n\t\t}\n\t});\n\n\tit(\"close() flushes pending changes immediately without waiting for debounce\", async () => {\n\t\tconst dir = makeTmpDir();\n\t\tconst dbPath = join(dir, \"test.db\");\n\t\ttry {\n\t\t\tconst storage = await MemoryStorage.create(dbPath);\n\n\t\t\tconst initialBuf = readFileSync(dbPath);\n\n\t\t\tstorage.upsertThreads([\n\t\t\t\t{ threadId: \"t1\", filePath: \"/a.txt\", fileSize: 100, fileMtime: 1000, cwd: \"/proj\" },\n\t\t\t]);\n\n\t\t\tconst beforeCloseBuf = readFileSync(dbPath);\n\t\t\tassert.deepEqual(\n\t\t\t\tbeforeCloseBuf,\n\t\t\t\tinitialBuf,\n\t\t\t\t\"File should not have been written yet (debounce window has not elapsed)\",\n\t\t\t);\n\n\t\t\tstorage.close();\n\n\t\t\tconst afterCloseBuf = readFileSync(dbPath);\n\t\t\tassert.notDeepEqual(\n\t\t\t\tafterCloseBuf,\n\t\t\t\tinitialBuf,\n\t\t\t\t\"File should have been written immediately on close()\",\n\t\t\t);\n\n\t\t\tconst reopened = await MemoryStorage.create(dbPath);\n\t\t\tconst stats = reopened.getStats();\n\t\t\tassert.equal(stats.totalThreads, 1, \"Data should be persisted and readable after close\");\n\t\t\treopened.close();\n\t\t} finally {\n\t\t\trmSync(dir, { recursive: true, force: true });\n\t\t}\n\t});\n});\n"]}
1
+ {"version":3,"file":"storage.test.js","sourceRoot":"","sources":["../../../../src/resources/extensions/memory/storage.test.ts"],"names":[],"mappings":"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","sourcesContent":["import assert from \"node:assert/strict\";\nimport { describe, it, afterEach } from \"node:test\";\nimport { mkdtempSync, rmSync, readFileSync, existsSync } from \"node:fs\";\nimport { join } from \"node:path\";\nimport { tmpdir } from \"node:os\";\n\nimport { MemoryStorage } from \"./storage.js\";\n\nfunction makeTmpDir(): string {\n\treturn mkdtempSync(join(tmpdir(), \"gsd-memory-storage-test-\"));\n}\n\nfunction wait(ms: number): Promise<void> {\n\treturn new Promise((resolve) => setTimeout(resolve, ms));\n}\n\ndescribe(\"MemoryStorage debounced persistence\", () => {\n\tlet dir: string;\n\n\tafterEach(() => {\n\t\tif (dir) {\n\t\t\trmSync(dir, { recursive: true, force: true });\n\t\t}\n\t});\n\n\tit(\"multiple rapid mutations only trigger one persist write\", async () => {\n\t\tdir = makeTmpDir();\n\t\tconst dbPath = join(dir, \"test.db\");\n\t\tconst storage = await MemoryStorage.create(dbPath);\n\n\t\tconst initialStat = readFileSync(dbPath);\n\t\tconst initialMtime = initialStat.length;\n\n\t\tstorage.upsertThreads([\n\t\t\t{ threadId: \"t1\", filePath: \"/a.txt\", fileSize: 100, fileMtime: 1000, cwd: \"/proj\" },\n\t\t]);\n\t\tstorage.upsertThreads([\n\t\t\t{ threadId: \"t2\", filePath: \"/b.txt\", fileSize: 200, fileMtime: 2000, cwd: \"/proj\" },\n\t\t]);\n\t\tstorage.upsertThreads([\n\t\t\t{ threadId: \"t3\", filePath: \"/c.txt\", fileSize: 300, fileMtime: 3000, cwd: \"/proj\" },\n\t\t]);\n\n\t\tconst afterMutationsBuf = readFileSync(dbPath);\n\t\tassert.deepEqual(\n\t\t\tafterMutationsBuf,\n\t\t\tinitialStat,\n\t\t\t\"File should not have been written yet (debounce window has not elapsed)\",\n\t\t);\n\n\t\tawait wait(700);\n\n\t\tconst afterDebounceBuf = readFileSync(dbPath);\n\t\tassert.notDeepEqual(\n\t\t\tafterDebounceBuf,\n\t\t\tinitialStat,\n\t\t\t\"File should have been written after debounce window elapsed\",\n\t\t);\n\n\t\tconst stats = storage.getStats();\n\t\tassert.equal(stats.totalThreads, 3);\n\n\t\tstorage.close();\n\t});\n\n\tit(\"close() flushes pending changes immediately without waiting for debounce\", async () => {\n\t\tdir = makeTmpDir();\n\t\tconst dbPath = join(dir, \"test.db\");\n\t\tconst storage = await MemoryStorage.create(dbPath);\n\n\t\tconst initialBuf = readFileSync(dbPath);\n\n\t\tstorage.upsertThreads([\n\t\t\t{ threadId: \"t1\", filePath: \"/a.txt\", fileSize: 100, fileMtime: 1000, cwd: \"/proj\" },\n\t\t]);\n\n\t\tconst beforeCloseBuf = readFileSync(dbPath);\n\t\tassert.deepEqual(\n\t\t\tbeforeCloseBuf,\n\t\t\tinitialBuf,\n\t\t\t\"File should not have been written yet (debounce window has not elapsed)\",\n\t\t);\n\n\t\tstorage.close();\n\n\t\tconst afterCloseBuf = readFileSync(dbPath);\n\t\tassert.notDeepEqual(\n\t\t\tafterCloseBuf,\n\t\t\tinitialBuf,\n\t\t\t\"File should have been written immediately on close()\",\n\t\t);\n\n\t\tconst reopened = await MemoryStorage.create(dbPath);\n\t\tconst stats = reopened.getStats();\n\t\tassert.equal(stats.totalThreads, 1, \"Data should be persisted and readable after close\");\n\t\treopened.close();\n\t});\n});\n"]}
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@gsd/pi-coding-agent",
3
- "version": "2.44.0",
3
+ "version": "2.45.0",
4
4
  "description": "Coding agent CLI (vendored from pi-mono)",
5
5
  "type": "module",
6
6
  "piConfig": {
@@ -287,7 +287,7 @@ describe("AuthStorage — oauth credential for non-OAuth provider (#2083)", () =
287
287
  assert.equal(key, undefined);
288
288
  });
289
289
 
290
- it("falls through to env var when openrouter has type:oauth credential", async () => {
290
+ it("falls through to env var when openrouter has type:oauth credential", async (t) => {
291
291
  const storage = inMemory({
292
292
  openrouter: {
293
293
  type: "oauth",
@@ -299,17 +299,17 @@ describe("AuthStorage — oauth credential for non-OAuth provider (#2083)", () =
299
299
 
300
300
  // Simulate OPENROUTER_API_KEY being set via env
301
301
  const origEnv = process.env.OPENROUTER_API_KEY;
302
- try {
303
- process.env.OPENROUTER_API_KEY = "sk-or-v1-env-key";
304
- const key = await storage.getApiKey("openrouter");
305
- assert.equal(key, "sk-or-v1-env-key");
306
- } finally {
302
+ t.after(() => {
307
303
  if (origEnv === undefined) {
308
304
  delete process.env.OPENROUTER_API_KEY;
309
305
  } else {
310
306
  process.env.OPENROUTER_API_KEY = origEnv;
311
307
  }
312
- }
308
+ });
309
+
310
+ process.env.OPENROUTER_API_KEY = "sk-or-v1-env-key";
311
+ const key = await storage.getApiKey("openrouter");
312
+ assert.equal(key, "sk-or-v1-env-key");
313
313
  });
314
314
 
315
315
  it("falls through to fallback resolver when openrouter has type:oauth credential", async () => {
@@ -744,7 +744,21 @@ export class AuthStorage {
744
744
  * @param providerId - The provider to get an API key for
745
745
  * @param sessionId - Optional session ID for sticky credential selection
746
746
  */
747
- async getApiKey(providerId: string, sessionId?: string): Promise<string | undefined> {
747
+ async getApiKey(providerId: string, sessionId?: string, options?: { baseUrl?: string }): Promise<string | undefined> {
748
+ // If the model has a local baseUrl, return a dummy key to avoid auth blocking
749
+ if (options?.baseUrl) {
750
+ try {
751
+ const hostname = new URL(options.baseUrl).hostname;
752
+ if (hostname === "localhost" || hostname === "127.0.0.1" || hostname === "0.0.0.0" || hostname === "::1") {
753
+ return "local-no-key-needed";
754
+ }
755
+ } catch {
756
+ if (options.baseUrl.startsWith("unix:")) {
757
+ return "local-no-key-needed";
758
+ }
759
+ }
760
+ }
761
+
748
762
  // Runtime override takes highest priority
749
763
  const runtimeKey = this.runtimeOverrides.get(providerId);
750
764
  if (runtimeKey) {
@@ -97,6 +97,7 @@ export class CompactionOrchestrator {
97
97
  if (!this._deps.modelRegistry.isProviderRequestReady(model.provider)) {
98
98
  throw new Error(`No API key for ${model.provider}`);
99
99
  }
100
+ // undefined for externalCli/none providers — stripped at the streamSimple boundary (model-registry.ts)
100
101
  const apiKey = await this._deps.modelRegistry.getApiKey(model, this._deps.getSessionId());
101
102
 
102
103
  const pathEntries = this._deps.sessionManager.getBranch();
@@ -303,6 +304,7 @@ export class CompactionOrchestrator {
303
304
  this._deps.emit({ type: "auto_compaction_end", result: undefined, aborted: false, willRetry: false });
304
305
  return;
305
306
  }
307
+ // undefined for externalCli/none providers — stripped at the streamSimple boundary (model-registry.ts)
306
308
  const apiKey = await this._deps.modelRegistry.getApiKey(model, this._deps.getSessionId());
307
309
 
308
310
  const pathEntries = this._deps.sessionManager.getBranch();
@@ -48,37 +48,37 @@ function makeThrowingExtension(eventType: string, error: Error): Extension {
48
48
  }
49
49
 
50
50
  describe("ExtensionRunner.emitToolCall", () => {
51
- it("catches throwing extension handler and routes to emitError", async () => {
51
+ it("catches throwing extension handler and routes to emitError", async (t) => {
52
52
  const dir = mkdtempSync(join(tmpdir(), "runner-test-"));
53
- try {
54
- const sessionManager = SessionManager.create(dir, dir);
55
- const authStorage = AuthStorage.create();
56
- const modelRegistry = new ModelRegistry(authStorage, join(dir, "models.json"));
53
+ t.after(() => {
54
+ rmSync(dir, { recursive: true, force: true });
55
+ });
57
56
 
58
- const throwingExt = makeThrowingExtension("tool_call", new Error("handler crashed"));
59
- const runtime = makeMinimalRuntime();
60
- const runner = new ExtensionRunner([throwingExt], runtime, dir, sessionManager, modelRegistry);
57
+ const sessionManager = SessionManager.create(dir, dir);
58
+ const authStorage = AuthStorage.create();
59
+ const modelRegistry = new ModelRegistry(authStorage, join(dir, "models.json"));
61
60
 
62
- const errors: any[] = [];
63
- runner.onError((err) => errors.push(err));
61
+ const throwingExt = makeThrowingExtension("tool_call", new Error("handler crashed"));
62
+ const runtime = makeMinimalRuntime();
63
+ const runner = new ExtensionRunner([throwingExt], runtime, dir, sessionManager, modelRegistry);
64
64
 
65
- const event: ToolCallEvent = {
66
- type: "tool_call",
67
- toolCallId: "test-123",
68
- toolName: "test_tool",
69
- input: {},
70
- } as ToolCallEvent;
65
+ const errors: any[] = [];
66
+ runner.onError((err) => errors.push(err));
71
67
 
72
- const result = await runner.emitToolCall(event);
68
+ const event: ToolCallEvent = {
69
+ type: "tool_call",
70
+ toolCallId: "test-123",
71
+ toolName: "test_tool",
72
+ input: {},
73
+ } as ToolCallEvent;
73
74
 
74
- // Should not throw — error is caught and routed to emitError
75
- assert.equal(result, undefined);
76
- assert.equal(errors.length, 1);
77
- assert.equal(errors[0].error, "handler crashed");
78
- assert.equal(errors[0].event, "tool_call");
79
- assert.equal(errors[0].extensionPath, "/test/throwing-ext");
80
- } finally {
81
- rmSync(dir, { recursive: true, force: true });
82
- }
75
+ const result = await runner.emitToolCall(event);
76
+
77
+ // Should not throw — error is caught and routed to emitError
78
+ assert.equal(result, undefined);
79
+ assert.equal(errors.length, 1);
80
+ assert.equal(errors[0].error, "handler crashed");
81
+ assert.equal(errors[0].event, "tool_call");
82
+ assert.equal(errors[0].extensionPath, "/test/throwing-ext");
83
83
  });
84
84
  });
@@ -1242,7 +1242,8 @@ export interface ExtensionAPI {
1242
1242
  export interface ProviderConfig {
1243
1243
  /** Auth behavior for provider availability and request key handling. Defaults to "apiKey". */
1244
1244
  authMode?: "apiKey" | "oauth" | "externalCli" | "none";
1245
- /** Optional readiness check. Return false if the provider cannot accept requests (e.g., CLI not authenticated, API key invalid). Called before default auth checks. */
1245
+ /** Optional readiness check. Return false if the provider cannot accept requests (e.g., CLI not authenticated, API key invalid).
1246
+ * Called before default auth checks. Trusted at the same level as extension code — extensions already have arbitrary code execution. */
1246
1247
  isReady?: () => boolean;
1247
1248
  /** Base URL for the API endpoint. Required when defining models. */
1248
1249
  baseUrl?: string;
@@ -1,66 +1,54 @@
1
1
  import assert from "node:assert/strict";
2
- import { describe, it } from "node:test";
2
+ import { describe, it, afterEach } from "node:test";
3
3
  import { mkdtempSync, readFileSync, rmSync, existsSync } from "node:fs";
4
4
  import { join } from "node:path";
5
5
  import { tmpdir } from "node:os";
6
6
  import { atomicWriteFileSync } from "./fs-utils.js";
7
7
 
8
8
  describe("atomicWriteFileSync", () => {
9
- it("writes file content atomically", () => {
10
- const dir = mkdtempSync(join(tmpdir(), "fs-utils-test-"));
11
- try {
12
- const filePath = join(dir, "test.txt");
13
- atomicWriteFileSync(filePath, "hello world");
14
- assert.equal(readFileSync(filePath, "utf-8"), "hello world");
15
- } finally {
9
+ let dir: string;
10
+
11
+ afterEach(() => {
12
+ if (dir) {
16
13
  rmSync(dir, { recursive: true, force: true });
17
14
  }
18
15
  });
19
16
 
17
+ it("writes file content atomically", () => {
18
+ dir = mkdtempSync(join(tmpdir(), "fs-utils-test-"));
19
+ const filePath = join(dir, "test.txt");
20
+ atomicWriteFileSync(filePath, "hello world");
21
+ assert.equal(readFileSync(filePath, "utf-8"), "hello world");
22
+ });
23
+
20
24
  it("overwrites existing file atomically", () => {
21
- const dir = mkdtempSync(join(tmpdir(), "fs-utils-test-"));
22
- try {
23
- const filePath = join(dir, "test.txt");
24
- atomicWriteFileSync(filePath, "first");
25
- atomicWriteFileSync(filePath, "second");
26
- assert.equal(readFileSync(filePath, "utf-8"), "second");
27
- } finally {
28
- rmSync(dir, { recursive: true, force: true });
29
- }
25
+ dir = mkdtempSync(join(tmpdir(), "fs-utils-test-"));
26
+ const filePath = join(dir, "test.txt");
27
+ atomicWriteFileSync(filePath, "first");
28
+ atomicWriteFileSync(filePath, "second");
29
+ assert.equal(readFileSync(filePath, "utf-8"), "second");
30
30
  });
31
31
 
32
32
  it("does not leave .tmp file after successful write", () => {
33
- const dir = mkdtempSync(join(tmpdir(), "fs-utils-test-"));
34
- try {
35
- const filePath = join(dir, "test.txt");
36
- atomicWriteFileSync(filePath, "content");
37
- assert.equal(existsSync(filePath + ".tmp"), false);
38
- } finally {
39
- rmSync(dir, { recursive: true, force: true });
40
- }
33
+ dir = mkdtempSync(join(tmpdir(), "fs-utils-test-"));
34
+ const filePath = join(dir, "test.txt");
35
+ atomicWriteFileSync(filePath, "content");
36
+ assert.equal(existsSync(filePath + ".tmp"), false);
41
37
  });
42
38
 
43
39
  it("supports Buffer content", () => {
44
- const dir = mkdtempSync(join(tmpdir(), "fs-utils-test-"));
45
- try {
46
- const filePath = join(dir, "test.bin");
47
- const buf = Buffer.from([0x00, 0x01, 0x02, 0xff]);
48
- atomicWriteFileSync(filePath, buf);
49
- const result = readFileSync(filePath);
50
- assert.deepEqual(result, buf);
51
- } finally {
52
- rmSync(dir, { recursive: true, force: true });
53
- }
40
+ dir = mkdtempSync(join(tmpdir(), "fs-utils-test-"));
41
+ const filePath = join(dir, "test.bin");
42
+ const buf = Buffer.from([0x00, 0x01, 0x02, 0xff]);
43
+ atomicWriteFileSync(filePath, buf);
44
+ const result = readFileSync(filePath);
45
+ assert.deepEqual(result, buf);
54
46
  });
55
47
 
56
48
  it("supports encoding parameter", () => {
57
- const dir = mkdtempSync(join(tmpdir(), "fs-utils-test-"));
58
- try {
59
- const filePath = join(dir, "test.txt");
60
- atomicWriteFileSync(filePath, "utf8 content", "utf-8");
61
- assert.equal(readFileSync(filePath, "utf-8"), "utf8 content");
62
- } finally {
63
- rmSync(dir, { recursive: true, force: true });
64
- }
49
+ dir = mkdtempSync(join(tmpdir(), "fs-utils-test-"));
50
+ const filePath = join(dir, "test.txt");
51
+ atomicWriteFileSync(filePath, "utf8 content", "utf-8");
52
+ assert.equal(readFileSync(filePath, "utf-8"), "utf8 content");
65
53
  });
66
54
  });
@@ -0,0 +1,227 @@
1
+ import assert from "node:assert/strict";
2
+ import { mkdtempSync, mkdirSync, rmSync, writeFileSync, existsSync } from "node:fs";
3
+ import { homedir, tmpdir } from "node:os";
4
+ import { join, resolve } from "node:path";
5
+ import { describe, it } from "node:test";
6
+ import {
7
+ readManifestRuntimeDeps,
8
+ collectRuntimeDependencies,
9
+ verifyRuntimeDependencies,
10
+ resolveLocalSourcePath,
11
+ } from "./lifecycle-hooks.js";
12
+
13
+ function tmpDir(prefix: string, t: { after: (fn: () => void) => void }): string {
14
+ const dir = mkdtempSync(join(tmpdir(), `pi-lh-${prefix}-`));
15
+ t.after(() => rmSync(dir, { recursive: true, force: true }));
16
+ return dir;
17
+ }
18
+
19
+ // ─── readManifestRuntimeDeps ──────────────────────────────────────────────────
20
+
21
+ describe("readManifestRuntimeDeps", () => {
22
+ it("returns empty array when manifest file is missing", (t) => {
23
+ const dir = tmpDir("no-manifest", t);
24
+ assert.deepEqual(readManifestRuntimeDeps(dir), []);
25
+ });
26
+
27
+ it("returns empty array for malformed JSON", (t) => {
28
+ const dir = tmpDir("bad-json", t);
29
+ writeFileSync(join(dir, "extension-manifest.json"), "not json{{{", "utf-8");
30
+ assert.deepEqual(readManifestRuntimeDeps(dir), []);
31
+ });
32
+
33
+ it("returns runtime deps from valid manifest", (t) => {
34
+ const dir = tmpDir("valid", t);
35
+ writeFileSync(join(dir, "extension-manifest.json"), JSON.stringify({
36
+ dependencies: { runtime: ["claude", "node"] },
37
+ }), "utf-8");
38
+ assert.deepEqual(readManifestRuntimeDeps(dir), ["claude", "node"]);
39
+ });
40
+
41
+ it("returns empty array when dependencies exists but runtime is missing", (t) => {
42
+ const dir = tmpDir("no-runtime", t);
43
+ writeFileSync(join(dir, "extension-manifest.json"), JSON.stringify({
44
+ dependencies: {},
45
+ }), "utf-8");
46
+ assert.deepEqual(readManifestRuntimeDeps(dir), []);
47
+ });
48
+
49
+ it("returns empty array when runtime is empty", (t) => {
50
+ const dir = tmpDir("empty-runtime", t);
51
+ writeFileSync(join(dir, "extension-manifest.json"), JSON.stringify({
52
+ dependencies: { runtime: [] },
53
+ }), "utf-8");
54
+ assert.deepEqual(readManifestRuntimeDeps(dir), []);
55
+ });
56
+
57
+ it("filters out non-string entries in runtime array", (t) => {
58
+ const dir = tmpDir("mixed-types", t);
59
+ writeFileSync(join(dir, "extension-manifest.json"), JSON.stringify({
60
+ dependencies: { runtime: [123, null, "node", false, "python"] },
61
+ }), "utf-8");
62
+ assert.deepEqual(readManifestRuntimeDeps(dir), ["node", "python"]);
63
+ });
64
+
65
+ it("returns empty array when no dependencies field at all", (t) => {
66
+ const dir = tmpDir("no-deps-field", t);
67
+ writeFileSync(join(dir, "extension-manifest.json"), JSON.stringify({
68
+ id: "test",
69
+ name: "Test",
70
+ }), "utf-8");
71
+ assert.deepEqual(readManifestRuntimeDeps(dir), []);
72
+ });
73
+ });
74
+
75
+ // ─── collectRuntimeDependencies ───────────────────────────────────────────────
76
+
77
+ describe("collectRuntimeDependencies", () => {
78
+ it("aggregates deps from installedPath manifest", (t) => {
79
+ const dir = tmpDir("collect-installed", t);
80
+ writeFileSync(join(dir, "extension-manifest.json"), JSON.stringify({
81
+ dependencies: { runtime: ["claude"] },
82
+ }), "utf-8");
83
+ assert.deepEqual(collectRuntimeDependencies(dir, []), ["claude"]);
84
+ });
85
+
86
+ it("aggregates deps from entry path directory manifests", (t) => {
87
+ const root = tmpDir("collect-entry", t);
88
+ const installedDir = join(root, "installed");
89
+ const entryDir = join(root, "entry");
90
+ mkdirSync(installedDir, { recursive: true });
91
+ mkdirSync(entryDir, { recursive: true });
92
+ writeFileSync(join(entryDir, "extension-manifest.json"), JSON.stringify({
93
+ dependencies: { runtime: ["python"] },
94
+ }), "utf-8");
95
+ const deps = collectRuntimeDependencies(installedDir, [join(entryDir, "index.ts")]);
96
+ assert.deepEqual(deps, ["python"]);
97
+ });
98
+
99
+ it("deduplicates across multiple directories", (t) => {
100
+ const root = tmpDir("collect-dedup", t);
101
+ const dir1 = join(root, "dir1");
102
+ const dir2 = join(root, "dir2");
103
+ mkdirSync(dir1, { recursive: true });
104
+ mkdirSync(dir2, { recursive: true });
105
+ writeFileSync(join(dir1, "extension-manifest.json"), JSON.stringify({
106
+ dependencies: { runtime: ["node", "python"] },
107
+ }), "utf-8");
108
+ writeFileSync(join(dir2, "extension-manifest.json"), JSON.stringify({
109
+ dependencies: { runtime: ["python", "claude"] },
110
+ }), "utf-8");
111
+ const deps = collectRuntimeDependencies(dir1, [join(dir2, "index.ts")]);
112
+ assert.equal(deps.length, 3);
113
+ assert.ok(deps.includes("node"));
114
+ assert.ok(deps.includes("python"));
115
+ assert.ok(deps.includes("claude"));
116
+ });
117
+
118
+ it("returns empty when no directories have manifests", (t) => {
119
+ const dir = tmpDir("collect-empty", t);
120
+ assert.deepEqual(collectRuntimeDependencies(dir, []), []);
121
+ });
122
+ });
123
+
124
+ // ─── verifyRuntimeDependencies ────────────────────────────────────────────────
125
+
126
+ describe("verifyRuntimeDependencies", () => {
127
+ it("does not throw for empty deps array", () => {
128
+ assert.doesNotThrow(() => verifyRuntimeDependencies([], "test-source", "pi"));
129
+ });
130
+
131
+ it("does not throw when all deps are present", () => {
132
+ assert.doesNotThrow(() => verifyRuntimeDependencies(["node"], "test-source", "pi"));
133
+ });
134
+
135
+ it("throws for missing dep with 'Missing runtime dependencies' message", () => {
136
+ assert.throws(
137
+ () => verifyRuntimeDependencies(["__nonexistent_dep_for_test__"], "test-source", "pi"),
138
+ (err: Error) => {
139
+ assert.ok(err.message.includes("Missing runtime dependencies"));
140
+ assert.ok(err.message.includes("__nonexistent_dep_for_test__"));
141
+ return true;
142
+ },
143
+ );
144
+ });
145
+
146
+ it("lists all missing deps in error message", () => {
147
+ assert.throws(
148
+ () => verifyRuntimeDependencies(["__missing_1__", "__missing_2__"], "test-source", "pi"),
149
+ (err: Error) => {
150
+ assert.ok(err.message.includes("__missing_1__"));
151
+ assert.ok(err.message.includes("__missing_2__"));
152
+ return true;
153
+ },
154
+ );
155
+ });
156
+
157
+ it("includes appName and source in error for retry hint", () => {
158
+ assert.throws(
159
+ () => verifyRuntimeDependencies(["__missing__"], "github:user/repo", "gsd"),
160
+ (err: Error) => {
161
+ assert.ok(err.message.includes("gsd"));
162
+ assert.ok(err.message.includes("github:user/repo"));
163
+ return true;
164
+ },
165
+ );
166
+ });
167
+ });
168
+
169
+ // ─── resolveLocalSourcePath ───────────────────────────────────────────────────
170
+
171
+ describe("resolveLocalSourcePath", () => {
172
+ it("returns undefined for empty string", () => {
173
+ assert.equal(resolveLocalSourcePath("", "/tmp"), undefined);
174
+ });
175
+
176
+ it("returns undefined for npm: source", () => {
177
+ assert.equal(resolveLocalSourcePath("npm:@foo/bar", "/tmp"), undefined);
178
+ });
179
+
180
+ it("returns undefined for git URL", () => {
181
+ assert.equal(resolveLocalSourcePath("git:github.com/user/repo", "/tmp"), undefined);
182
+ });
183
+
184
+ it("returns undefined for https git URL", () => {
185
+ assert.equal(resolveLocalSourcePath("https://github.com/user/repo", "/tmp"), undefined);
186
+ });
187
+
188
+ it("resolves ~ to homedir", () => {
189
+ const result = resolveLocalSourcePath("~", "/tmp");
190
+ if (existsSync(homedir())) {
191
+ assert.equal(result, homedir());
192
+ } else {
193
+ assert.equal(result, undefined);
194
+ }
195
+ });
196
+
197
+ it("resolves ~/path relative to homedir", () => {
198
+ const result = resolveLocalSourcePath("~/", "/tmp");
199
+ if (existsSync(homedir())) {
200
+ assert.equal(result, homedir());
201
+ } else {
202
+ assert.equal(result, undefined);
203
+ }
204
+ });
205
+
206
+ it("resolves relative path that exists", (t) => {
207
+ const dir = tmpDir("resolve-rel", t);
208
+ const sub = join(dir, "myext");
209
+ mkdirSync(sub, { recursive: true });
210
+ const result = resolveLocalSourcePath("myext", dir);
211
+ assert.equal(result, resolve(dir, "myext"));
212
+ });
213
+
214
+ it("returns undefined for relative path that does not exist", (t) => {
215
+ const dir = tmpDir("resolve-noexist", t);
216
+ assert.equal(resolveLocalSourcePath("nonexistent", dir), undefined);
217
+ });
218
+
219
+ it("resolves absolute path that exists", (t) => {
220
+ const dir = tmpDir("resolve-abs", t);
221
+ assert.equal(resolveLocalSourcePath(dir, "/irrelevant"), dir);
222
+ });
223
+
224
+ it("returns undefined for absolute path that does not exist", () => {
225
+ assert.equal(resolveLocalSourcePath("/tmp/__nonexistent_path_for_test__", "/tmp"), undefined);
226
+ });
227
+ });