gsd-pi 2.45.0 → 2.46.0-dev.cc9d310

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 (347) hide show
  1. package/dist/help-text.js +1 -1
  2. package/dist/loader.js +34 -0
  3. package/dist/resources/extensions/gsd/auto/phases.js +27 -42
  4. package/dist/resources/extensions/gsd/auto/run-unit.js +6 -3
  5. package/dist/resources/extensions/gsd/auto/session.js +0 -11
  6. package/dist/resources/extensions/gsd/auto-artifact-paths.js +112 -0
  7. package/dist/resources/extensions/gsd/auto-post-unit.js +25 -96
  8. package/dist/resources/extensions/gsd/auto-start.js +2 -3
  9. package/dist/resources/extensions/gsd/auto-worktree.js +5 -4
  10. package/dist/resources/extensions/gsd/auto.js +12 -57
  11. package/dist/resources/extensions/gsd/bootstrap/db-tools.js +15 -12
  12. package/dist/resources/extensions/gsd/bootstrap/register-hooks.js +18 -0
  13. package/dist/resources/extensions/gsd/commands/context.js +0 -4
  14. package/dist/resources/extensions/gsd/commands/handlers/parallel.js +1 -1
  15. package/dist/resources/extensions/gsd/crash-recovery.js +2 -4
  16. package/dist/resources/extensions/gsd/dashboard-overlay.js +0 -44
  17. package/dist/resources/extensions/gsd/db-writer.js +9 -9
  18. package/dist/resources/extensions/gsd/doctor-checks.js +167 -2
  19. package/dist/resources/extensions/gsd/doctor.js +5 -3
  20. package/dist/resources/extensions/gsd/gsd-db.js +16 -3
  21. package/dist/resources/extensions/gsd/guided-flow.js +1 -2
  22. package/dist/resources/extensions/gsd/parallel-merge.js +1 -1
  23. package/dist/resources/extensions/gsd/parallel-orchestrator.js +5 -18
  24. package/dist/resources/extensions/gsd/preferences-types.js +2 -2
  25. package/dist/resources/extensions/gsd/preferences.js +8 -4
  26. package/dist/resources/extensions/gsd/prompts/complete-milestone.md +21 -8
  27. package/dist/resources/extensions/gsd/prompts/complete-slice.md +10 -23
  28. package/dist/resources/extensions/gsd/prompts/discuss.md +2 -2
  29. package/dist/resources/extensions/gsd/prompts/execute-task.md +5 -15
  30. package/dist/resources/extensions/gsd/prompts/guided-discuss-milestone.md +1 -1
  31. package/dist/resources/extensions/gsd/prompts/guided-discuss-slice.md +1 -1
  32. package/dist/resources/extensions/gsd/prompts/guided-plan-slice.md +1 -1
  33. package/dist/resources/extensions/gsd/prompts/guided-research-slice.md +1 -1
  34. package/dist/resources/extensions/gsd/prompts/plan-milestone.md +1 -1
  35. package/dist/resources/extensions/gsd/prompts/plan-slice.md +4 -2
  36. package/dist/resources/extensions/gsd/prompts/queue.md +2 -2
  37. package/dist/resources/extensions/gsd/prompts/quick-task.md +2 -0
  38. package/dist/resources/extensions/gsd/prompts/reactive-execute.md +1 -1
  39. package/dist/resources/extensions/gsd/prompts/research-slice.md +3 -3
  40. package/dist/resources/extensions/gsd/prompts/rethink.md +7 -2
  41. package/dist/resources/extensions/gsd/prompts/system.md +1 -1
  42. package/dist/resources/extensions/gsd/session-lock.js +1 -3
  43. package/dist/resources/extensions/gsd/state.js +7 -0
  44. package/dist/resources/extensions/gsd/sync-lock.js +89 -0
  45. package/dist/resources/extensions/gsd/tools/complete-milestone.js +61 -11
  46. package/dist/resources/extensions/gsd/tools/complete-slice.js +56 -11
  47. package/dist/resources/extensions/gsd/tools/complete-task.js +50 -2
  48. package/dist/resources/extensions/gsd/tools/plan-milestone.js +37 -1
  49. package/dist/resources/extensions/gsd/tools/plan-slice.js +30 -1
  50. package/dist/resources/extensions/gsd/tools/plan-task.js +27 -1
  51. package/dist/resources/extensions/gsd/tools/reassess-roadmap.js +32 -2
  52. package/dist/resources/extensions/gsd/tools/reopen-slice.js +86 -0
  53. package/dist/resources/extensions/gsd/tools/reopen-task.js +90 -0
  54. package/dist/resources/extensions/gsd/tools/replan-slice.js +32 -2
  55. package/dist/resources/extensions/gsd/unit-ownership.js +85 -0
  56. package/dist/resources/extensions/gsd/workflow-events.js +102 -0
  57. package/dist/resources/extensions/gsd/workflow-logger.js +193 -0
  58. package/dist/resources/extensions/gsd/workflow-manifest.js +244 -0
  59. package/dist/resources/extensions/gsd/workflow-migration.js +280 -0
  60. package/dist/resources/extensions/gsd/workflow-projections.js +373 -0
  61. package/dist/resources/extensions/gsd/workflow-reconcile.js +411 -0
  62. package/dist/resources/extensions/gsd/worktree-manager.js +4 -3
  63. package/dist/resources/extensions/gsd/worktree-resolver.js +37 -0
  64. package/dist/resources/extensions/gsd/write-intercept.js +84 -0
  65. package/dist/resources/extensions/voice/index.js +11 -16
  66. package/dist/resources/extensions/voice/linux-ready.js +67 -0
  67. package/dist/web/standalone/.next/BUILD_ID +1 -1
  68. package/dist/web/standalone/.next/app-path-routes-manifest.json +17 -17
  69. package/dist/web/standalone/.next/build-manifest.json +3 -3
  70. package/dist/web/standalone/.next/prerender-manifest.json +3 -3
  71. package/dist/web/standalone/.next/required-server-files.json +3 -3
  72. package/dist/web/standalone/.next/server/app/_global-error/page.js +3 -3
  73. package/dist/web/standalone/.next/server/app/_global-error/page_client-reference-manifest.js +1 -1
  74. package/dist/web/standalone/.next/server/app/_global-error.html +2 -2
  75. package/dist/web/standalone/.next/server/app/_global-error.rsc +1 -1
  76. package/dist/web/standalone/.next/server/app/_global-error.segments/_full.segment.rsc +1 -1
  77. package/dist/web/standalone/.next/server/app/_global-error.segments/_global-error/__PAGE__.segment.rsc +1 -1
  78. package/dist/web/standalone/.next/server/app/_global-error.segments/_global-error.segment.rsc +1 -1
  79. package/dist/web/standalone/.next/server/app/_global-error.segments/_head.segment.rsc +1 -1
  80. package/dist/web/standalone/.next/server/app/_global-error.segments/_index.segment.rsc +1 -1
  81. package/dist/web/standalone/.next/server/app/_global-error.segments/_tree.segment.rsc +1 -1
  82. package/dist/web/standalone/.next/server/app/_not-found/page.js +2 -2
  83. package/dist/web/standalone/.next/server/app/_not-found/page_client-reference-manifest.js +1 -1
  84. package/dist/web/standalone/.next/server/app/_not-found.html +1 -1
  85. package/dist/web/standalone/.next/server/app/_not-found.rsc +3 -3
  86. package/dist/web/standalone/.next/server/app/_not-found.segments/_full.segment.rsc +3 -3
  87. package/dist/web/standalone/.next/server/app/_not-found.segments/_head.segment.rsc +1 -1
  88. package/dist/web/standalone/.next/server/app/_not-found.segments/_index.segment.rsc +3 -3
  89. package/dist/web/standalone/.next/server/app/_not-found.segments/_not-found/__PAGE__.segment.rsc +1 -1
  90. package/dist/web/standalone/.next/server/app/_not-found.segments/_not-found.segment.rsc +1 -1
  91. package/dist/web/standalone/.next/server/app/_not-found.segments/_tree.segment.rsc +1 -1
  92. package/dist/web/standalone/.next/server/app/api/boot/route.js +1 -1
  93. package/dist/web/standalone/.next/server/app/api/boot/route_client-reference-manifest.js +1 -1
  94. package/dist/web/standalone/.next/server/app/api/bridge-terminal/input/route.js +1 -1
  95. package/dist/web/standalone/.next/server/app/api/bridge-terminal/input/route_client-reference-manifest.js +1 -1
  96. package/dist/web/standalone/.next/server/app/api/bridge-terminal/resize/route.js +1 -1
  97. package/dist/web/standalone/.next/server/app/api/bridge-terminal/resize/route_client-reference-manifest.js +1 -1
  98. package/dist/web/standalone/.next/server/app/api/bridge-terminal/stream/route.js +2 -2
  99. package/dist/web/standalone/.next/server/app/api/bridge-terminal/stream/route_client-reference-manifest.js +1 -1
  100. package/dist/web/standalone/.next/server/app/api/browse-directories/route.js +1 -1
  101. package/dist/web/standalone/.next/server/app/api/browse-directories/route_client-reference-manifest.js +1 -1
  102. package/dist/web/standalone/.next/server/app/api/captures/route.js +1 -1
  103. package/dist/web/standalone/.next/server/app/api/captures/route_client-reference-manifest.js +1 -1
  104. package/dist/web/standalone/.next/server/app/api/cleanup/route.js +1 -1
  105. package/dist/web/standalone/.next/server/app/api/cleanup/route_client-reference-manifest.js +1 -1
  106. package/dist/web/standalone/.next/server/app/api/dev-mode/route.js +1 -1
  107. package/dist/web/standalone/.next/server/app/api/dev-mode/route_client-reference-manifest.js +1 -1
  108. package/dist/web/standalone/.next/server/app/api/doctor/route.js +1 -1
  109. package/dist/web/standalone/.next/server/app/api/doctor/route_client-reference-manifest.js +1 -1
  110. package/dist/web/standalone/.next/server/app/api/export-data/route.js +1 -1
  111. package/dist/web/standalone/.next/server/app/api/export-data/route_client-reference-manifest.js +1 -1
  112. package/dist/web/standalone/.next/server/app/api/files/route.js +1 -1
  113. package/dist/web/standalone/.next/server/app/api/files/route_client-reference-manifest.js +1 -1
  114. package/dist/web/standalone/.next/server/app/api/forensics/route.js +1 -1
  115. package/dist/web/standalone/.next/server/app/api/forensics/route_client-reference-manifest.js +1 -1
  116. package/dist/web/standalone/.next/server/app/api/git/route.js +1 -1
  117. package/dist/web/standalone/.next/server/app/api/git/route_client-reference-manifest.js +1 -1
  118. package/dist/web/standalone/.next/server/app/api/history/route.js +1 -1
  119. package/dist/web/standalone/.next/server/app/api/history/route_client-reference-manifest.js +1 -1
  120. package/dist/web/standalone/.next/server/app/api/hooks/route.js +1 -1
  121. package/dist/web/standalone/.next/server/app/api/hooks/route_client-reference-manifest.js +1 -1
  122. package/dist/web/standalone/.next/server/app/api/inspect/route.js +1 -1
  123. package/dist/web/standalone/.next/server/app/api/inspect/route_client-reference-manifest.js +1 -1
  124. package/dist/web/standalone/.next/server/app/api/knowledge/route.js +1 -1
  125. package/dist/web/standalone/.next/server/app/api/knowledge/route_client-reference-manifest.js +1 -1
  126. package/dist/web/standalone/.next/server/app/api/live-state/route.js +1 -1
  127. package/dist/web/standalone/.next/server/app/api/live-state/route_client-reference-manifest.js +1 -1
  128. package/dist/web/standalone/.next/server/app/api/onboarding/route.js +1 -1
  129. package/dist/web/standalone/.next/server/app/api/onboarding/route_client-reference-manifest.js +1 -1
  130. package/dist/web/standalone/.next/server/app/api/preferences/route.js +1 -1
  131. package/dist/web/standalone/.next/server/app/api/preferences/route_client-reference-manifest.js +1 -1
  132. package/dist/web/standalone/.next/server/app/api/projects/route.js +1 -1
  133. package/dist/web/standalone/.next/server/app/api/projects/route_client-reference-manifest.js +1 -1
  134. package/dist/web/standalone/.next/server/app/api/recovery/route.js +1 -1
  135. package/dist/web/standalone/.next/server/app/api/recovery/route_client-reference-manifest.js +1 -1
  136. package/dist/web/standalone/.next/server/app/api/remote-questions/route.js +5 -5
  137. package/dist/web/standalone/.next/server/app/api/remote-questions/route_client-reference-manifest.js +1 -1
  138. package/dist/web/standalone/.next/server/app/api/session/browser/route.js +1 -1
  139. package/dist/web/standalone/.next/server/app/api/session/browser/route_client-reference-manifest.js +1 -1
  140. package/dist/web/standalone/.next/server/app/api/session/command/route.js +1 -1
  141. package/dist/web/standalone/.next/server/app/api/session/command/route_client-reference-manifest.js +1 -1
  142. package/dist/web/standalone/.next/server/app/api/session/events/route.js +2 -2
  143. package/dist/web/standalone/.next/server/app/api/session/events/route_client-reference-manifest.js +1 -1
  144. package/dist/web/standalone/.next/server/app/api/session/manage/route.js +1 -1
  145. package/dist/web/standalone/.next/server/app/api/session/manage/route_client-reference-manifest.js +1 -1
  146. package/dist/web/standalone/.next/server/app/api/settings-data/route.js +1 -1
  147. package/dist/web/standalone/.next/server/app/api/settings-data/route_client-reference-manifest.js +1 -1
  148. package/dist/web/standalone/.next/server/app/api/shutdown/route.js +1 -1
  149. package/dist/web/standalone/.next/server/app/api/shutdown/route_client-reference-manifest.js +1 -1
  150. package/dist/web/standalone/.next/server/app/api/skill-health/route.js +1 -1
  151. package/dist/web/standalone/.next/server/app/api/skill-health/route_client-reference-manifest.js +1 -1
  152. package/dist/web/standalone/.next/server/app/api/steer/route.js +1 -1
  153. package/dist/web/standalone/.next/server/app/api/steer/route_client-reference-manifest.js +1 -1
  154. package/dist/web/standalone/.next/server/app/api/switch-root/route.js +1 -1
  155. package/dist/web/standalone/.next/server/app/api/switch-root/route_client-reference-manifest.js +1 -1
  156. package/dist/web/standalone/.next/server/app/api/terminal/input/route.js +2 -2
  157. package/dist/web/standalone/.next/server/app/api/terminal/input/route_client-reference-manifest.js +1 -1
  158. package/dist/web/standalone/.next/server/app/api/terminal/resize/route.js +2 -2
  159. package/dist/web/standalone/.next/server/app/api/terminal/resize/route_client-reference-manifest.js +1 -1
  160. package/dist/web/standalone/.next/server/app/api/terminal/sessions/route.js +2 -2
  161. package/dist/web/standalone/.next/server/app/api/terminal/sessions/route_client-reference-manifest.js +1 -1
  162. package/dist/web/standalone/.next/server/app/api/terminal/stream/route.js +4 -4
  163. package/dist/web/standalone/.next/server/app/api/terminal/stream/route_client-reference-manifest.js +1 -1
  164. package/dist/web/standalone/.next/server/app/api/terminal/upload/route.js +1 -1
  165. package/dist/web/standalone/.next/server/app/api/terminal/upload/route_client-reference-manifest.js +1 -1
  166. package/dist/web/standalone/.next/server/app/api/undo/route.js +1 -1
  167. package/dist/web/standalone/.next/server/app/api/undo/route_client-reference-manifest.js +1 -1
  168. package/dist/web/standalone/.next/server/app/api/update/route.js +1 -1
  169. package/dist/web/standalone/.next/server/app/api/update/route_client-reference-manifest.js +1 -1
  170. package/dist/web/standalone/.next/server/app/api/visualizer/route.js +1 -1
  171. package/dist/web/standalone/.next/server/app/api/visualizer/route_client-reference-manifest.js +1 -1
  172. package/dist/web/standalone/.next/server/app/index.html +1 -1
  173. package/dist/web/standalone/.next/server/app/index.rsc +4 -4
  174. package/dist/web/standalone/.next/server/app/index.segments/__PAGE__.segment.rsc +2 -2
  175. package/dist/web/standalone/.next/server/app/index.segments/_full.segment.rsc +4 -4
  176. package/dist/web/standalone/.next/server/app/index.segments/_head.segment.rsc +1 -1
  177. package/dist/web/standalone/.next/server/app/index.segments/_index.segment.rsc +3 -3
  178. package/dist/web/standalone/.next/server/app/index.segments/_tree.segment.rsc +1 -1
  179. package/dist/web/standalone/.next/server/app/page.js +2 -2
  180. package/dist/web/standalone/.next/server/app/page_client-reference-manifest.js +1 -1
  181. package/dist/web/standalone/.next/server/app-paths-manifest.json +17 -17
  182. package/dist/web/standalone/.next/server/chunks/229.js +1 -1
  183. package/dist/web/standalone/.next/server/chunks/471.js +3 -3
  184. package/dist/web/standalone/.next/server/middleware-build-manifest.js +1 -1
  185. package/dist/web/standalone/.next/server/middleware.js +2 -2
  186. package/dist/web/standalone/.next/server/next-font-manifest.js +1 -1
  187. package/dist/web/standalone/.next/server/next-font-manifest.json +1 -1
  188. package/dist/web/standalone/.next/server/pages/404.html +1 -1
  189. package/dist/web/standalone/.next/server/pages/500.html +2 -2
  190. package/dist/web/standalone/.next/server/server-reference-manifest.json +1 -1
  191. package/dist/web/standalone/.next/static/chunks/app/_not-found/{page-2f24283c162b6ab3.js → page-f2a7482d42a5614b.js} +1 -1
  192. package/dist/web/standalone/.next/static/chunks/app/{layout-9ecfd95f343793f0.js → layout-a16c7a7ecdf0c2cf.js} +1 -1
  193. package/dist/web/standalone/.next/static/chunks/app/page-6654a8cca61a3d1c.js +1 -0
  194. package/dist/web/standalone/.next/static/chunks/main-app-fdab67f7802d7832.js +1 -0
  195. package/dist/web/standalone/.next/static/chunks/next/dist/client/components/builtin/global-error-459824ffb8c323dd.js +1 -0
  196. package/dist/web/standalone/node_modules/node-pty/build/Makefile +2 -2
  197. package/dist/web/standalone/node_modules/node-pty/build/Release/pty.node +0 -0
  198. package/dist/web/standalone/node_modules/node-pty/build/pty.target.mk +14 -14
  199. package/dist/web/standalone/node_modules/node-pty/node-addon-api/node_addon_api.target.mk +14 -14
  200. package/dist/web/standalone/node_modules/node-pty/node-addon-api/node_addon_api_except.target.mk +14 -14
  201. package/dist/web/standalone/node_modules/node-pty/node-addon-api/node_addon_api_maybe.target.mk +14 -14
  202. package/dist/web/standalone/server.js +1 -1
  203. package/package.json +2 -1
  204. package/packages/pi-coding-agent/dist/core/compaction-orchestrator.d.ts.map +1 -1
  205. package/packages/pi-coding-agent/dist/core/compaction-orchestrator.js +2 -0
  206. package/packages/pi-coding-agent/dist/core/compaction-orchestrator.js.map +1 -1
  207. package/packages/pi-coding-agent/dist/core/extensions/types.d.ts +2 -1
  208. package/packages/pi-coding-agent/dist/core/extensions/types.d.ts.map +1 -1
  209. package/packages/pi-coding-agent/dist/core/extensions/types.js.map +1 -1
  210. package/packages/pi-coding-agent/dist/core/lifecycle-hooks.d.ts +4 -0
  211. package/packages/pi-coding-agent/dist/core/lifecycle-hooks.d.ts.map +1 -1
  212. package/packages/pi-coding-agent/dist/core/lifecycle-hooks.js +10 -5
  213. package/packages/pi-coding-agent/dist/core/lifecycle-hooks.js.map +1 -1
  214. package/packages/pi-coding-agent/dist/core/lifecycle-hooks.test.d.ts +2 -0
  215. package/packages/pi-coding-agent/dist/core/lifecycle-hooks.test.d.ts.map +1 -0
  216. package/packages/pi-coding-agent/dist/core/lifecycle-hooks.test.js +185 -0
  217. package/packages/pi-coding-agent/dist/core/lifecycle-hooks.test.js.map +1 -0
  218. package/packages/pi-coding-agent/dist/core/model-registry-auth-mode.test.js +239 -10
  219. package/packages/pi-coding-agent/dist/core/model-registry-auth-mode.test.js.map +1 -1
  220. package/packages/pi-coding-agent/dist/core/model-registry.d.ts +2 -1
  221. package/packages/pi-coding-agent/dist/core/model-registry.d.ts.map +1 -1
  222. package/packages/pi-coding-agent/dist/core/model-registry.js +20 -2
  223. package/packages/pi-coding-agent/dist/core/model-registry.js.map +1 -1
  224. package/packages/pi-coding-agent/dist/core/package-commands.test.js +206 -195
  225. package/packages/pi-coding-agent/dist/core/package-commands.test.js.map +1 -1
  226. package/packages/pi-coding-agent/package.json +1 -1
  227. package/packages/pi-coding-agent/src/core/compaction-orchestrator.ts +2 -0
  228. package/packages/pi-coding-agent/src/core/extensions/types.ts +2 -1
  229. package/packages/pi-coding-agent/src/core/lifecycle-hooks.test.ts +227 -0
  230. package/packages/pi-coding-agent/src/core/lifecycle-hooks.ts +11 -5
  231. package/packages/pi-coding-agent/src/core/model-registry-auth-mode.test.ts +297 -11
  232. package/packages/pi-coding-agent/src/core/model-registry.ts +30 -3
  233. package/packages/pi-coding-agent/src/core/package-commands.test.ts +227 -205
  234. package/pkg/package.json +1 -1
  235. package/src/resources/extensions/gsd/auto/loop-deps.ts +0 -19
  236. package/src/resources/extensions/gsd/auto/phases.ts +24 -44
  237. package/src/resources/extensions/gsd/auto/run-unit.ts +6 -3
  238. package/src/resources/extensions/gsd/auto/session.ts +0 -18
  239. package/src/resources/extensions/gsd/auto-artifact-paths.ts +131 -0
  240. package/src/resources/extensions/gsd/auto-dashboard.ts +0 -1
  241. package/src/resources/extensions/gsd/auto-post-unit.ts +25 -106
  242. package/src/resources/extensions/gsd/auto-start.ts +1 -3
  243. package/src/resources/extensions/gsd/auto-worktree.ts +8 -5
  244. package/src/resources/extensions/gsd/auto.ts +7 -83
  245. package/src/resources/extensions/gsd/bootstrap/db-tools.ts +15 -12
  246. package/src/resources/extensions/gsd/bootstrap/register-hooks.ts +22 -0
  247. package/src/resources/extensions/gsd/commands/context.ts +0 -5
  248. package/src/resources/extensions/gsd/commands/handlers/parallel.ts +1 -1
  249. package/src/resources/extensions/gsd/crash-recovery.ts +1 -5
  250. package/src/resources/extensions/gsd/dashboard-overlay.ts +0 -50
  251. package/src/resources/extensions/gsd/db-writer.ts +9 -17
  252. package/src/resources/extensions/gsd/doctor-checks.ts +180 -2
  253. package/src/resources/extensions/gsd/doctor-types.ts +7 -1
  254. package/src/resources/extensions/gsd/doctor.ts +6 -3
  255. package/src/resources/extensions/gsd/gsd-db.ts +16 -3
  256. package/src/resources/extensions/gsd/guided-flow.ts +1 -2
  257. package/src/resources/extensions/gsd/journal.ts +6 -1
  258. package/src/resources/extensions/gsd/parallel-merge.ts +1 -1
  259. package/src/resources/extensions/gsd/parallel-orchestrator.ts +5 -21
  260. package/src/resources/extensions/gsd/preferences-types.ts +2 -2
  261. package/src/resources/extensions/gsd/preferences.ts +7 -3
  262. package/src/resources/extensions/gsd/prompts/complete-milestone.md +21 -8
  263. package/src/resources/extensions/gsd/prompts/complete-slice.md +10 -23
  264. package/src/resources/extensions/gsd/prompts/discuss.md +2 -2
  265. package/src/resources/extensions/gsd/prompts/execute-task.md +5 -15
  266. package/src/resources/extensions/gsd/prompts/guided-discuss-milestone.md +1 -1
  267. package/src/resources/extensions/gsd/prompts/guided-discuss-slice.md +1 -1
  268. package/src/resources/extensions/gsd/prompts/guided-plan-slice.md +1 -1
  269. package/src/resources/extensions/gsd/prompts/guided-research-slice.md +1 -1
  270. package/src/resources/extensions/gsd/prompts/plan-milestone.md +1 -1
  271. package/src/resources/extensions/gsd/prompts/plan-slice.md +4 -2
  272. package/src/resources/extensions/gsd/prompts/queue.md +2 -2
  273. package/src/resources/extensions/gsd/prompts/quick-task.md +2 -0
  274. package/src/resources/extensions/gsd/prompts/reactive-execute.md +1 -1
  275. package/src/resources/extensions/gsd/prompts/research-slice.md +3 -3
  276. package/src/resources/extensions/gsd/prompts/rethink.md +7 -2
  277. package/src/resources/extensions/gsd/prompts/system.md +1 -1
  278. package/src/resources/extensions/gsd/session-lock.ts +0 -4
  279. package/src/resources/extensions/gsd/state.ts +8 -0
  280. package/src/resources/extensions/gsd/sync-lock.ts +94 -0
  281. package/src/resources/extensions/gsd/tests/auto-lock-creation.test.ts +5 -13
  282. package/src/resources/extensions/gsd/tests/auto-loop.test.ts +6 -10
  283. package/src/resources/extensions/gsd/tests/complete-milestone.test.ts +96 -0
  284. package/src/resources/extensions/gsd/tests/complete-slice.test.ts +264 -228
  285. package/src/resources/extensions/gsd/tests/complete-task.test.ts +317 -250
  286. package/src/resources/extensions/gsd/tests/crash-recovery.test.ts +2 -8
  287. package/src/resources/extensions/gsd/tests/custom-engine-loop-integration.test.ts +0 -3
  288. package/src/resources/extensions/gsd/tests/gsd-db.test.ts +1 -1
  289. package/src/resources/extensions/gsd/tests/idle-recovery.test.ts +1 -1
  290. package/src/resources/extensions/gsd/tests/integration-proof.test.ts +15 -24
  291. package/src/resources/extensions/gsd/tests/journal-integration.test.ts +0 -3
  292. package/src/resources/extensions/gsd/tests/md-importer.test.ts +1 -1
  293. package/src/resources/extensions/gsd/tests/memory-store.test.ts +2 -2
  294. package/src/resources/extensions/gsd/tests/merge-conflict-stops-loop.test.ts +1 -1
  295. package/src/resources/extensions/gsd/tests/milestone-transition-state-rebuild.test.ts +8 -9
  296. package/src/resources/extensions/gsd/tests/none-mode-gates.test.ts +42 -3
  297. package/src/resources/extensions/gsd/tests/parallel-budget-atomicity.test.ts +0 -1
  298. package/src/resources/extensions/gsd/tests/parallel-crash-recovery.test.ts +0 -7
  299. package/src/resources/extensions/gsd/tests/parallel-merge.test.ts +7 -8
  300. package/src/resources/extensions/gsd/tests/parallel-orchestration.test.ts +20 -24
  301. package/src/resources/extensions/gsd/tests/parallel-worker-monitoring.test.ts +0 -2
  302. package/src/resources/extensions/gsd/tests/plan-milestone.test.ts +9 -6
  303. package/src/resources/extensions/gsd/tests/post-mutation-hook.test.ts +171 -0
  304. package/src/resources/extensions/gsd/tests/preferences.test.ts +7 -9
  305. package/src/resources/extensions/gsd/tests/projection-regression.test.ts +174 -0
  306. package/src/resources/extensions/gsd/tests/prompt-contracts.test.ts +15 -14
  307. package/src/resources/extensions/gsd/tests/reopen-slice.test.ts +155 -0
  308. package/src/resources/extensions/gsd/tests/reopen-task.test.ts +165 -0
  309. package/src/resources/extensions/gsd/tests/session-lock-regression.test.ts +1 -4
  310. package/src/resources/extensions/gsd/tests/stop-auto-remote.test.ts +2 -3
  311. package/src/resources/extensions/gsd/tests/sync-lock.test.ts +122 -0
  312. package/src/resources/extensions/gsd/tests/unit-ownership.test.ts +175 -0
  313. package/src/resources/extensions/gsd/tests/workflow-events.test.ts +205 -0
  314. package/src/resources/extensions/gsd/tests/workflow-logger.test.ts +275 -0
  315. package/src/resources/extensions/gsd/tests/workflow-manifest.test.ts +186 -0
  316. package/src/resources/extensions/gsd/tests/workflow-projections.test.ts +171 -0
  317. package/src/resources/extensions/gsd/tests/worktree-journal-events.test.ts +220 -0
  318. package/src/resources/extensions/gsd/tests/write-intercept.test.ts +76 -0
  319. package/src/resources/extensions/gsd/tools/complete-milestone.ts +74 -11
  320. package/src/resources/extensions/gsd/tools/complete-slice.ts +68 -11
  321. package/src/resources/extensions/gsd/tools/complete-task.ts +63 -1
  322. package/src/resources/extensions/gsd/tools/plan-milestone.ts +45 -0
  323. package/src/resources/extensions/gsd/tools/plan-slice.ts +38 -0
  324. package/src/resources/extensions/gsd/tools/plan-task.ts +35 -1
  325. package/src/resources/extensions/gsd/tools/reassess-roadmap.ts +39 -1
  326. package/src/resources/extensions/gsd/tools/reopen-slice.ts +125 -0
  327. package/src/resources/extensions/gsd/tools/reopen-task.ts +129 -0
  328. package/src/resources/extensions/gsd/tools/replan-slice.ts +38 -1
  329. package/src/resources/extensions/gsd/types.ts +8 -0
  330. package/src/resources/extensions/gsd/unit-ownership.ts +104 -0
  331. package/src/resources/extensions/gsd/workflow-events.ts +154 -0
  332. package/src/resources/extensions/gsd/workflow-logger.ts +243 -0
  333. package/src/resources/extensions/gsd/workflow-manifest.ts +334 -0
  334. package/src/resources/extensions/gsd/workflow-migration.ts +345 -0
  335. package/src/resources/extensions/gsd/workflow-projections.ts +425 -0
  336. package/src/resources/extensions/gsd/workflow-reconcile.ts +503 -0
  337. package/src/resources/extensions/gsd/worktree-manager.ts +4 -9
  338. package/src/resources/extensions/gsd/worktree-resolver.ts +37 -0
  339. package/src/resources/extensions/gsd/write-intercept.ts +90 -0
  340. package/src/resources/extensions/voice/index.ts +11 -21
  341. package/src/resources/extensions/voice/linux-ready.ts +87 -0
  342. package/src/resources/extensions/voice/tests/linux-ready.test.ts +124 -0
  343. package/dist/web/standalone/.next/static/chunks/app/page-12dd5ece0df4badc.js +0 -1
  344. package/dist/web/standalone/.next/static/chunks/main-app-d3d4c336195465f9.js +0 -1
  345. package/dist/web/standalone/.next/static/chunks/next/dist/client/components/builtin/global-error-ab5a8926e07ec673.js +0 -1
  346. /package/dist/web/standalone/.next/static/{wUzEX1U3CmFcMry2SUDJn → ZIDqryyYDroh_8AnaAOSG}/_buildManifest.js +0 -0
  347. /package/dist/web/standalone/.next/static/{wUzEX1U3CmFcMry2SUDJn → ZIDqryyYDroh_8AnaAOSG}/_ssgManifest.js +0 -0
@@ -8,7 +8,7 @@ import { importExtensionModule, loadExtensions, } from "./extensions/index.js";
8
8
  function toScope(local) {
9
9
  return local ? "project" : "user";
10
10
  }
11
- function readManifestRuntimeDeps(dir) {
11
+ export function readManifestRuntimeDeps(dir) {
12
12
  const manifestPath = join(dir, "extension-manifest.json");
13
13
  if (!existsSync(manifestPath))
14
14
  return [];
@@ -20,7 +20,7 @@ function readManifestRuntimeDeps(dir) {
20
20
  return [];
21
21
  }
22
22
  }
23
- function collectRuntimeDependencies(installedPath, entryPaths) {
23
+ export function collectRuntimeDependencies(installedPath, entryPaths) {
24
24
  const deps = new Set();
25
25
  const candidateDirs = new Set([installedPath, ...entryPaths.map((entryPath) => dirname(entryPath))]);
26
26
  for (const dir of candidateDirs) {
@@ -30,7 +30,7 @@ function collectRuntimeDependencies(installedPath, entryPaths) {
30
30
  }
31
31
  return Array.from(deps);
32
32
  }
33
- function verifyRuntimeDependencies(runtimeDeps, source, appName) {
33
+ export function verifyRuntimeDependencies(runtimeDeps, source, appName) {
34
34
  const missing = [];
35
35
  for (const dep of runtimeDeps) {
36
36
  const result = spawnSync(dep, ["--version"], { encoding: "utf-8", timeout: 5000 });
@@ -43,7 +43,7 @@ function verifyRuntimeDependencies(runtimeDeps, source, appName) {
43
43
  throw new Error(`Missing runtime dependencies: ${missing.join(", ")}.\n` +
44
44
  `Install them and retry: ${appName} install ${source}`);
45
45
  }
46
- function resolveLocalSourcePath(source, cwd) {
46
+ export function resolveLocalSourcePath(source, cwd) {
47
47
  const trimmed = source.trim();
48
48
  if (!trimmed)
49
49
  return undefined;
@@ -120,9 +120,14 @@ async function runHookSafe(hook, context, stderr) {
120
120
  function getLegacyExportCandidates(phase) {
121
121
  return [phase];
122
122
  }
123
+ const _legacyModuleCache = new Map();
123
124
  async function runLegacyExportHook(entryPath, phase, context) {
124
125
  try {
125
- const module = await importExtensionModule(import.meta.url, pathToFileURL(entryPath).href);
126
+ let module = _legacyModuleCache.get(entryPath);
127
+ if (!module) {
128
+ module = await importExtensionModule(import.meta.url, pathToFileURL(entryPath).href);
129
+ _legacyModuleCache.set(entryPath, module);
130
+ }
126
131
  for (const exportName of getLegacyExportCandidates(phase)) {
127
132
  const candidate = module[exportName];
128
133
  if (typeof candidate === "function") {
@@ -1 +1 @@
1
- {"version":3,"file":"lifecycle-hooks.js","sourceRoot":"","sources":["../../src/core/lifecycle-hooks.ts"],"names":[],"mappings":"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","sourcesContent":["import { spawnSync } from \"node:child_process\";\nimport { existsSync, readFileSync } from \"node:fs\";\nimport { homedir } from \"node:os\";\nimport { dirname, join, resolve } from \"node:path\";\nimport { pathToFileURL } from \"node:url\";\nimport { parseGitUrl } from \"../utils/git.js\";\nimport {\n\timportExtensionModule,\n\tloadExtensions,\n\ttype LifecycleHookContext,\n\ttype LifecycleHookMap,\n\ttype LifecycleHookHandler,\n\ttype LifecycleHookPhase,\n\ttype LifecycleHookScope,\n} from \"./extensions/index.js\";\nimport type { DefaultPackageManager } from \"./package-manager.js\";\n\ninterface ExtensionManifest {\n\tdependencies?: {\n\t\truntime?: string[];\n\t};\n}\n\nexport interface PackageLifecycleHooksOptions {\n\tsource: string;\n\tlocal: boolean;\n\tcwd: string;\n\tagentDir: string;\n\tappName: string;\n\tpackageManager: DefaultPackageManager;\n\tstdout: NodeJS.WriteStream;\n\tstderr: NodeJS.WriteStream;\n}\n\nexport type LifecycleHooksTarget = \"source\" | \"installed\";\n\nexport interface PrepareLifecycleHooksOptions {\n\tverifyRuntimeDependencies?: boolean;\n}\n\nexport interface LifecycleHooksRunResult {\n\tphase: LifecycleHookPhase;\n\thooksRun: number;\n\thookErrors: number;\n\tlegacyHooksRun: number;\n\tentryPathCount: number;\n\tskipped: boolean;\n}\n\ninterface LoadedLifecycleHooks {\n\tsource: string;\n\tscope: LifecycleHookScope;\n\tinstalledPath?: string;\n\tcwd: string;\n\tstdout: NodeJS.WriteStream;\n\tstderr: NodeJS.WriteStream;\n\tentryPaths: string[];\n\thooksByPath: Map<string, LifecycleHookMap>;\n}\n\nfunction toScope(local: boolean): LifecycleHookScope {\n\treturn local ? \"project\" : \"user\";\n}\n\nfunction readManifestRuntimeDeps(dir: string): string[] {\n\tconst manifestPath = join(dir, \"extension-manifest.json\");\n\tif (!existsSync(manifestPath)) return [];\n\ttry {\n\t\tconst manifest = JSON.parse(readFileSync(manifestPath, \"utf-8\")) as ExtensionManifest;\n\t\treturn manifest.dependencies?.runtime?.filter((dep): dep is string => typeof dep === \"string\") ?? [];\n\t} catch {\n\t\treturn [];\n\t}\n}\n\nfunction collectRuntimeDependencies(installedPath: string, entryPaths: string[]): string[] {\n\tconst deps = new Set<string>();\n\tconst candidateDirs = new Set<string>([installedPath, ...entryPaths.map((entryPath) => dirname(entryPath))]);\n\tfor (const dir of candidateDirs) {\n\t\tfor (const dep of readManifestRuntimeDeps(dir)) {\n\t\t\tdeps.add(dep);\n\t\t}\n\t}\n\treturn Array.from(deps);\n}\n\nfunction verifyRuntimeDependencies(runtimeDeps: string[], source: string, appName: string): void {\n\tconst missing: string[] = [];\n\tfor (const dep of runtimeDeps) {\n\t\tconst result = spawnSync(dep, [\"--version\"], { encoding: \"utf-8\", timeout: 5000 });\n\t\tif (result.error || result.status !== 0) {\n\t\t\tmissing.push(dep);\n\t\t}\n\t}\n\tif (missing.length === 0) return;\n\tthrow new Error(\n\t\t`Missing runtime dependencies: ${missing.join(\", \")}.\\n` +\n\t\t\t`Install them and retry: ${appName} install ${source}`,\n\t);\n}\n\nfunction resolveLocalSourcePath(source: string, cwd: string): string | undefined {\n\tconst trimmed = source.trim();\n\tif (!trimmed) return undefined;\n\tif (trimmed.startsWith(\"npm:\")) return undefined;\n\tif (parseGitUrl(trimmed)) return undefined;\n\n\tlet normalized = trimmed;\n\tif (normalized === \"~\") {\n\t\tnormalized = homedir();\n\t} else if (normalized.startsWith(\"~/\")) {\n\t\tnormalized = join(homedir(), normalized.slice(2));\n\t}\n\n\tconst absolutePath = resolve(cwd, normalized);\n\treturn existsSync(absolutePath) ? absolutePath : undefined;\n}\n\nasync function resolveEntryPathsFromTarget(\n\toptions: PackageLifecycleHooksOptions,\n\ttarget: LifecycleHooksTarget,\n\tscope: LifecycleHookScope,\n): Promise<{ entryPaths: string[]; installedPath?: string }> {\n\tif (target === \"source\") {\n\t\tconst localSourcePath = resolveLocalSourcePath(options.source, options.cwd);\n\t\tif (!localSourcePath) return { entryPaths: [] };\n\t\tconst resolved = await options.packageManager.resolveExtensionSources([localSourcePath], { local: true });\n\t\tconst entryPaths = resolved.extensions.filter((resource) => resource.enabled).map((resource) => resource.path);\n\t\treturn { entryPaths, installedPath: localSourcePath };\n\t}\n\n\tconst installedPath = options.packageManager.getInstalledPath(options.source, scope);\n\tif (!installedPath) return { entryPaths: [] };\n\tconst resolved = await options.packageManager.resolveExtensionSources([installedPath], { local: true });\n\tconst entryPaths = resolved.extensions.filter((resource) => resource.enabled).map((resource) => resource.path);\n\treturn { entryPaths, installedPath };\n}\n\nexport async function prepareLifecycleHooks(\n\toptions: PackageLifecycleHooksOptions,\n\ttarget: LifecycleHooksTarget,\n\tprepareOptions?: PrepareLifecycleHooksOptions,\n): Promise<LoadedLifecycleHooks | null> {\n\tconst scope = toScope(options.local);\n\tconst { entryPaths, installedPath } = await resolveEntryPathsFromTarget(options, target, scope);\n\tif (entryPaths.length === 0) {\n\t\treturn null;\n\t}\n\n\tif (prepareOptions?.verifyRuntimeDependencies && installedPath) {\n\t\tconst runtimeDeps = collectRuntimeDependencies(installedPath, entryPaths);\n\t\tverifyRuntimeDependencies(runtimeDeps, options.source, options.appName);\n\t}\n\n\tconst loaded = await loadExtensions(entryPaths, options.cwd);\n\tfor (const { path, error } of loaded.errors) {\n\t\toptions.stderr.write(`[lifecycle-hooks] Failed to load extension \"${path}\": ${error}\\n`);\n\t}\n\n\tconst hooksByPath = new Map<string, LifecycleHookMap>();\n\tfor (const extension of loaded.extensions) {\n\t\thooksByPath.set(extension.path, extension.lifecycleHooks);\n\t}\n\n\treturn {\n\t\tsource: options.source,\n\t\tscope,\n\t\tinstalledPath,\n\t\tcwd: options.cwd,\n\t\tstdout: options.stdout,\n\t\tstderr: options.stderr,\n\t\tentryPaths,\n\t\thooksByPath,\n\t};\n}\n\nasync function runHookSafe(\n\thook: LifecycleHookHandler,\n\tcontext: LifecycleHookContext,\n\tstderr: NodeJS.WriteStream,\n): Promise<boolean> {\n\ttry {\n\t\tawait hook(context);\n\t\treturn true;\n\t} catch (error) {\n\t\tconst message = error instanceof Error ? error.message : String(error);\n\t\tstderr.write(`[lifecycle-hooks:${context.phase}] Hook failed: ${message}\\n`);\n\t\treturn false;\n\t}\n}\n\nfunction getLegacyExportCandidates(phase: LifecycleHookPhase): string[] {\n\treturn [phase];\n}\n\nasync function runLegacyExportHook(\n\tentryPath: string,\n\tphase: LifecycleHookPhase,\n\tcontext: LifecycleHookContext,\n): Promise<LifecycleHookHandler | null> {\n\ttry {\n\t\tconst module = await importExtensionModule<Record<string, unknown>>(import.meta.url, pathToFileURL(entryPath).href);\n\t\tfor (const exportName of getLegacyExportCandidates(phase)) {\n\t\t\tconst candidate = module[exportName];\n\t\t\tif (typeof candidate === \"function\") {\n\t\t\t\treturn candidate as LifecycleHookHandler;\n\t\t\t}\n\t\t}\n\t\treturn null;\n\t} catch {\n\t\treturn null;\n\t}\n}\n\nexport async function runLifecycleHooks(\n\tloaded: LoadedLifecycleHooks | null,\n\tphase: LifecycleHookPhase,\n): Promise<LifecycleHooksRunResult> {\n\tif (!loaded) {\n\t\treturn {\n\t\t\tphase,\n\t\t\thooksRun: 0,\n\t\t\thookErrors: 0,\n\t\t\tlegacyHooksRun: 0,\n\t\t\tentryPathCount: 0,\n\t\t\tskipped: true,\n\t\t};\n\t}\n\n\tconst context: LifecycleHookContext = {\n\t\tphase,\n\t\tsource: loaded.source,\n\t\tinstalledPath: loaded.installedPath,\n\t\tscope: loaded.scope,\n\t\tcwd: loaded.cwd,\n\t\tinteractive: Boolean(process.stdin.isTTY && process.stdout.isTTY),\n\t\tlog: (message) => loaded.stdout.write(`${message}\\n`),\n\t\twarn: (message) => loaded.stderr.write(`${message}\\n`),\n\t\terror: (message) => loaded.stderr.write(`${message}\\n`),\n\t};\n\n\tlet hooksRun = 0;\n\tlet hookErrors = 0;\n\tlet legacyHooksRun = 0;\n\n\tfor (const entryPath of loaded.entryPaths) {\n\t\tconst hookMap = loaded.hooksByPath.get(entryPath);\n\t\tconst registeredHooks = hookMap?.[phase] ?? [];\n\t\tif (registeredHooks.length > 0) {\n\t\t\tfor (const hook of registeredHooks) {\n\t\t\t\thooksRun += 1;\n\t\t\t\tconst ok = await runHookSafe(hook, context, loaded.stderr);\n\t\t\t\tif (!ok) hookErrors += 1;\n\t\t\t}\n\t\t\tcontinue;\n\t\t}\n\n\t\tconst legacyHook = await runLegacyExportHook(entryPath, phase, context);\n\t\tif (!legacyHook) continue;\n\n\t\tlegacyHooksRun += 1;\n\t\tconst ok = await runHookSafe(legacyHook, context, loaded.stderr);\n\t\tif (!ok) hookErrors += 1;\n\t}\n\n\treturn {\n\t\tphase,\n\t\thooksRun,\n\t\thookErrors,\n\t\tlegacyHooksRun,\n\t\tentryPathCount: loaded.entryPaths.length,\n\t\tskipped: false,\n\t};\n}\n"]}
1
+ {"version":3,"file":"lifecycle-hooks.js","sourceRoot":"","sources":["../../src/core/lifecycle-hooks.ts"],"names":[],"mappings":"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","sourcesContent":["import { spawnSync } from \"node:child_process\";\nimport { existsSync, readFileSync } from \"node:fs\";\nimport { homedir } from \"node:os\";\nimport { dirname, join, resolve } from \"node:path\";\nimport { pathToFileURL } from \"node:url\";\nimport { parseGitUrl } from \"../utils/git.js\";\nimport {\n\timportExtensionModule,\n\tloadExtensions,\n\ttype LifecycleHookContext,\n\ttype LifecycleHookMap,\n\ttype LifecycleHookHandler,\n\ttype LifecycleHookPhase,\n\ttype LifecycleHookScope,\n} from \"./extensions/index.js\";\nimport type { DefaultPackageManager } from \"./package-manager.js\";\n\ninterface ExtensionManifest {\n\tdependencies?: {\n\t\truntime?: string[];\n\t};\n}\n\nexport interface PackageLifecycleHooksOptions {\n\tsource: string;\n\tlocal: boolean;\n\tcwd: string;\n\tagentDir: string;\n\tappName: string;\n\tpackageManager: DefaultPackageManager;\n\tstdout: NodeJS.WriteStream;\n\tstderr: NodeJS.WriteStream;\n}\n\nexport type LifecycleHooksTarget = \"source\" | \"installed\";\n\nexport interface PrepareLifecycleHooksOptions {\n\tverifyRuntimeDependencies?: boolean;\n}\n\nexport interface LifecycleHooksRunResult {\n\tphase: LifecycleHookPhase;\n\thooksRun: number;\n\thookErrors: number;\n\tlegacyHooksRun: number;\n\tentryPathCount: number;\n\tskipped: boolean;\n}\n\ninterface LoadedLifecycleHooks {\n\tsource: string;\n\tscope: LifecycleHookScope;\n\tinstalledPath?: string;\n\tcwd: string;\n\tstdout: NodeJS.WriteStream;\n\tstderr: NodeJS.WriteStream;\n\tentryPaths: string[];\n\thooksByPath: Map<string, LifecycleHookMap>;\n}\n\nfunction toScope(local: boolean): LifecycleHookScope {\n\treturn local ? \"project\" : \"user\";\n}\n\nexport function readManifestRuntimeDeps(dir: string): string[] {\n\tconst manifestPath = join(dir, \"extension-manifest.json\");\n\tif (!existsSync(manifestPath)) return [];\n\ttry {\n\t\tconst manifest = JSON.parse(readFileSync(manifestPath, \"utf-8\")) as ExtensionManifest;\n\t\treturn manifest.dependencies?.runtime?.filter((dep): dep is string => typeof dep === \"string\") ?? [];\n\t} catch {\n\t\treturn [];\n\t}\n}\n\nexport function collectRuntimeDependencies(installedPath: string, entryPaths: string[]): string[] {\n\tconst deps = new Set<string>();\n\tconst candidateDirs = new Set<string>([installedPath, ...entryPaths.map((entryPath) => dirname(entryPath))]);\n\tfor (const dir of candidateDirs) {\n\t\tfor (const dep of readManifestRuntimeDeps(dir)) {\n\t\t\tdeps.add(dep);\n\t\t}\n\t}\n\treturn Array.from(deps);\n}\n\nexport function verifyRuntimeDependencies(runtimeDeps: string[], source: string, appName: string): void {\n\tconst missing: string[] = [];\n\tfor (const dep of runtimeDeps) {\n\t\tconst result = spawnSync(dep, [\"--version\"], { encoding: \"utf-8\", timeout: 5000 });\n\t\tif (result.error || result.status !== 0) {\n\t\t\tmissing.push(dep);\n\t\t}\n\t}\n\tif (missing.length === 0) return;\n\tthrow new Error(\n\t\t`Missing runtime dependencies: ${missing.join(\", \")}.\\n` +\n\t\t\t`Install them and retry: ${appName} install ${source}`,\n\t);\n}\n\nexport function resolveLocalSourcePath(source: string, cwd: string): string | undefined {\n\tconst trimmed = source.trim();\n\tif (!trimmed) return undefined;\n\tif (trimmed.startsWith(\"npm:\")) return undefined;\n\tif (parseGitUrl(trimmed)) return undefined;\n\n\tlet normalized = trimmed;\n\tif (normalized === \"~\") {\n\t\tnormalized = homedir();\n\t} else if (normalized.startsWith(\"~/\")) {\n\t\tnormalized = join(homedir(), normalized.slice(2));\n\t}\n\n\tconst absolutePath = resolve(cwd, normalized);\n\treturn existsSync(absolutePath) ? absolutePath : undefined;\n}\n\nasync function resolveEntryPathsFromTarget(\n\toptions: PackageLifecycleHooksOptions,\n\ttarget: LifecycleHooksTarget,\n\tscope: LifecycleHookScope,\n): Promise<{ entryPaths: string[]; installedPath?: string }> {\n\tif (target === \"source\") {\n\t\tconst localSourcePath = resolveLocalSourcePath(options.source, options.cwd);\n\t\tif (!localSourcePath) return { entryPaths: [] };\n\t\tconst resolved = await options.packageManager.resolveExtensionSources([localSourcePath], { local: true });\n\t\tconst entryPaths = resolved.extensions.filter((resource) => resource.enabled).map((resource) => resource.path);\n\t\treturn { entryPaths, installedPath: localSourcePath };\n\t}\n\n\tconst installedPath = options.packageManager.getInstalledPath(options.source, scope);\n\tif (!installedPath) return { entryPaths: [] };\n\tconst resolved = await options.packageManager.resolveExtensionSources([installedPath], { local: true });\n\tconst entryPaths = resolved.extensions.filter((resource) => resource.enabled).map((resource) => resource.path);\n\treturn { entryPaths, installedPath };\n}\n\nexport async function prepareLifecycleHooks(\n\toptions: PackageLifecycleHooksOptions,\n\ttarget: LifecycleHooksTarget,\n\tprepareOptions?: PrepareLifecycleHooksOptions,\n): Promise<LoadedLifecycleHooks | null> {\n\tconst scope = toScope(options.local);\n\tconst { entryPaths, installedPath } = await resolveEntryPathsFromTarget(options, target, scope);\n\tif (entryPaths.length === 0) {\n\t\treturn null;\n\t}\n\n\tif (prepareOptions?.verifyRuntimeDependencies && installedPath) {\n\t\tconst runtimeDeps = collectRuntimeDependencies(installedPath, entryPaths);\n\t\tverifyRuntimeDependencies(runtimeDeps, options.source, options.appName);\n\t}\n\n\tconst loaded = await loadExtensions(entryPaths, options.cwd);\n\tfor (const { path, error } of loaded.errors) {\n\t\toptions.stderr.write(`[lifecycle-hooks] Failed to load extension \"${path}\": ${error}\\n`);\n\t}\n\n\tconst hooksByPath = new Map<string, LifecycleHookMap>();\n\tfor (const extension of loaded.extensions) {\n\t\thooksByPath.set(extension.path, extension.lifecycleHooks);\n\t}\n\n\treturn {\n\t\tsource: options.source,\n\t\tscope,\n\t\tinstalledPath,\n\t\tcwd: options.cwd,\n\t\tstdout: options.stdout,\n\t\tstderr: options.stderr,\n\t\tentryPaths,\n\t\thooksByPath,\n\t};\n}\n\nasync function runHookSafe(\n\thook: LifecycleHookHandler,\n\tcontext: LifecycleHookContext,\n\tstderr: NodeJS.WriteStream,\n): Promise<boolean> {\n\ttry {\n\t\tawait hook(context);\n\t\treturn true;\n\t} catch (error) {\n\t\tconst message = error instanceof Error ? error.message : String(error);\n\t\tstderr.write(`[lifecycle-hooks:${context.phase}] Hook failed: ${message}\\n`);\n\t\treturn false;\n\t}\n}\n\nfunction getLegacyExportCandidates(phase: LifecycleHookPhase): string[] {\n\treturn [phase];\n}\n\nconst _legacyModuleCache = new Map<string, Record<string, unknown>>();\n\nasync function runLegacyExportHook(\n\tentryPath: string,\n\tphase: LifecycleHookPhase,\n\tcontext: LifecycleHookContext,\n): Promise<LifecycleHookHandler | null> {\n\ttry {\n\t\tlet module = _legacyModuleCache.get(entryPath);\n\t\tif (!module) {\n\t\t\tmodule = await importExtensionModule<Record<string, unknown>>(import.meta.url, pathToFileURL(entryPath).href);\n\t\t\t_legacyModuleCache.set(entryPath, module);\n\t\t}\n\t\tfor (const exportName of getLegacyExportCandidates(phase)) {\n\t\t\tconst candidate = module[exportName];\n\t\t\tif (typeof candidate === \"function\") {\n\t\t\t\treturn candidate as LifecycleHookHandler;\n\t\t\t}\n\t\t}\n\t\treturn null;\n\t} catch {\n\t\treturn null;\n\t}\n}\n\nexport async function runLifecycleHooks(\n\tloaded: LoadedLifecycleHooks | null,\n\tphase: LifecycleHookPhase,\n): Promise<LifecycleHooksRunResult> {\n\tif (!loaded) {\n\t\treturn {\n\t\t\tphase,\n\t\t\thooksRun: 0,\n\t\t\thookErrors: 0,\n\t\t\tlegacyHooksRun: 0,\n\t\t\tentryPathCount: 0,\n\t\t\tskipped: true,\n\t\t};\n\t}\n\n\tconst context: LifecycleHookContext = {\n\t\tphase,\n\t\tsource: loaded.source,\n\t\tinstalledPath: loaded.installedPath,\n\t\tscope: loaded.scope,\n\t\tcwd: loaded.cwd,\n\t\tinteractive: Boolean(process.stdin.isTTY && process.stdout.isTTY),\n\t\tlog: (message) => loaded.stdout.write(`${message}\\n`),\n\t\twarn: (message) => loaded.stderr.write(`${message}\\n`),\n\t\terror: (message) => loaded.stderr.write(`${message}\\n`),\n\t};\n\n\tlet hooksRun = 0;\n\tlet hookErrors = 0;\n\tlet legacyHooksRun = 0;\n\n\tfor (const entryPath of loaded.entryPaths) {\n\t\tconst hookMap = loaded.hooksByPath.get(entryPath);\n\t\tconst registeredHooks = hookMap?.[phase] ?? [];\n\t\tif (registeredHooks.length > 0) {\n\t\t\tfor (const hook of registeredHooks) {\n\t\t\t\thooksRun += 1;\n\t\t\t\tconst ok = await runHookSafe(hook, context, loaded.stderr);\n\t\t\t\tif (!ok) hookErrors += 1;\n\t\t\t}\n\t\t\tcontinue;\n\t\t}\n\n\t\tconst legacyHook = await runLegacyExportHook(entryPath, phase, context);\n\t\tif (!legacyHook) continue;\n\n\t\tlegacyHooksRun += 1;\n\t\tconst ok = await runHookSafe(legacyHook, context, loaded.stderr);\n\t\tif (!ok) hookErrors += 1;\n\t}\n\n\treturn {\n\t\tphase,\n\t\thooksRun,\n\t\thookErrors,\n\t\tlegacyHooksRun,\n\t\tentryPathCount: loaded.entryPaths.length,\n\t\tskipped: false,\n\t};\n}\n"]}
@@ -0,0 +1,2 @@
1
+ export {};
2
+ //# sourceMappingURL=lifecycle-hooks.test.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"lifecycle-hooks.test.d.ts","sourceRoot":"","sources":["../../src/core/lifecycle-hooks.test.ts"],"names":[],"mappings":""}
@@ -0,0 +1,185 @@
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 { readManifestRuntimeDeps, collectRuntimeDependencies, verifyRuntimeDependencies, resolveLocalSourcePath, } from "./lifecycle-hooks.js";
7
+ function tmpDir(prefix, t) {
8
+ const dir = mkdtempSync(join(tmpdir(), `pi-lh-${prefix}-`));
9
+ t.after(() => rmSync(dir, { recursive: true, force: true }));
10
+ return dir;
11
+ }
12
+ // ─── readManifestRuntimeDeps ──────────────────────────────────────────────────
13
+ describe("readManifestRuntimeDeps", () => {
14
+ it("returns empty array when manifest file is missing", (t) => {
15
+ const dir = tmpDir("no-manifest", t);
16
+ assert.deepEqual(readManifestRuntimeDeps(dir), []);
17
+ });
18
+ it("returns empty array for malformed JSON", (t) => {
19
+ const dir = tmpDir("bad-json", t);
20
+ writeFileSync(join(dir, "extension-manifest.json"), "not json{{{", "utf-8");
21
+ assert.deepEqual(readManifestRuntimeDeps(dir), []);
22
+ });
23
+ it("returns runtime deps from valid manifest", (t) => {
24
+ const dir = tmpDir("valid", t);
25
+ writeFileSync(join(dir, "extension-manifest.json"), JSON.stringify({
26
+ dependencies: { runtime: ["claude", "node"] },
27
+ }), "utf-8");
28
+ assert.deepEqual(readManifestRuntimeDeps(dir), ["claude", "node"]);
29
+ });
30
+ it("returns empty array when dependencies exists but runtime is missing", (t) => {
31
+ const dir = tmpDir("no-runtime", t);
32
+ writeFileSync(join(dir, "extension-manifest.json"), JSON.stringify({
33
+ dependencies: {},
34
+ }), "utf-8");
35
+ assert.deepEqual(readManifestRuntimeDeps(dir), []);
36
+ });
37
+ it("returns empty array when runtime is empty", (t) => {
38
+ const dir = tmpDir("empty-runtime", t);
39
+ writeFileSync(join(dir, "extension-manifest.json"), JSON.stringify({
40
+ dependencies: { runtime: [] },
41
+ }), "utf-8");
42
+ assert.deepEqual(readManifestRuntimeDeps(dir), []);
43
+ });
44
+ it("filters out non-string entries in runtime array", (t) => {
45
+ const dir = tmpDir("mixed-types", t);
46
+ writeFileSync(join(dir, "extension-manifest.json"), JSON.stringify({
47
+ dependencies: { runtime: [123, null, "node", false, "python"] },
48
+ }), "utf-8");
49
+ assert.deepEqual(readManifestRuntimeDeps(dir), ["node", "python"]);
50
+ });
51
+ it("returns empty array when no dependencies field at all", (t) => {
52
+ const dir = tmpDir("no-deps-field", t);
53
+ writeFileSync(join(dir, "extension-manifest.json"), JSON.stringify({
54
+ id: "test",
55
+ name: "Test",
56
+ }), "utf-8");
57
+ assert.deepEqual(readManifestRuntimeDeps(dir), []);
58
+ });
59
+ });
60
+ // ─── collectRuntimeDependencies ───────────────────────────────────────────────
61
+ describe("collectRuntimeDependencies", () => {
62
+ it("aggregates deps from installedPath manifest", (t) => {
63
+ const dir = tmpDir("collect-installed", t);
64
+ writeFileSync(join(dir, "extension-manifest.json"), JSON.stringify({
65
+ dependencies: { runtime: ["claude"] },
66
+ }), "utf-8");
67
+ assert.deepEqual(collectRuntimeDependencies(dir, []), ["claude"]);
68
+ });
69
+ it("aggregates deps from entry path directory manifests", (t) => {
70
+ const root = tmpDir("collect-entry", t);
71
+ const installedDir = join(root, "installed");
72
+ const entryDir = join(root, "entry");
73
+ mkdirSync(installedDir, { recursive: true });
74
+ mkdirSync(entryDir, { recursive: true });
75
+ writeFileSync(join(entryDir, "extension-manifest.json"), JSON.stringify({
76
+ dependencies: { runtime: ["python"] },
77
+ }), "utf-8");
78
+ const deps = collectRuntimeDependencies(installedDir, [join(entryDir, "index.ts")]);
79
+ assert.deepEqual(deps, ["python"]);
80
+ });
81
+ it("deduplicates across multiple directories", (t) => {
82
+ const root = tmpDir("collect-dedup", t);
83
+ const dir1 = join(root, "dir1");
84
+ const dir2 = join(root, "dir2");
85
+ mkdirSync(dir1, { recursive: true });
86
+ mkdirSync(dir2, { recursive: true });
87
+ writeFileSync(join(dir1, "extension-manifest.json"), JSON.stringify({
88
+ dependencies: { runtime: ["node", "python"] },
89
+ }), "utf-8");
90
+ writeFileSync(join(dir2, "extension-manifest.json"), JSON.stringify({
91
+ dependencies: { runtime: ["python", "claude"] },
92
+ }), "utf-8");
93
+ const deps = collectRuntimeDependencies(dir1, [join(dir2, "index.ts")]);
94
+ assert.equal(deps.length, 3);
95
+ assert.ok(deps.includes("node"));
96
+ assert.ok(deps.includes("python"));
97
+ assert.ok(deps.includes("claude"));
98
+ });
99
+ it("returns empty when no directories have manifests", (t) => {
100
+ const dir = tmpDir("collect-empty", t);
101
+ assert.deepEqual(collectRuntimeDependencies(dir, []), []);
102
+ });
103
+ });
104
+ // ─── verifyRuntimeDependencies ────────────────────────────────────────────────
105
+ describe("verifyRuntimeDependencies", () => {
106
+ it("does not throw for empty deps array", () => {
107
+ assert.doesNotThrow(() => verifyRuntimeDependencies([], "test-source", "pi"));
108
+ });
109
+ it("does not throw when all deps are present", () => {
110
+ assert.doesNotThrow(() => verifyRuntimeDependencies(["node"], "test-source", "pi"));
111
+ });
112
+ it("throws for missing dep with 'Missing runtime dependencies' message", () => {
113
+ assert.throws(() => verifyRuntimeDependencies(["__nonexistent_dep_for_test__"], "test-source", "pi"), (err) => {
114
+ assert.ok(err.message.includes("Missing runtime dependencies"));
115
+ assert.ok(err.message.includes("__nonexistent_dep_for_test__"));
116
+ return true;
117
+ });
118
+ });
119
+ it("lists all missing deps in error message", () => {
120
+ assert.throws(() => verifyRuntimeDependencies(["__missing_1__", "__missing_2__"], "test-source", "pi"), (err) => {
121
+ assert.ok(err.message.includes("__missing_1__"));
122
+ assert.ok(err.message.includes("__missing_2__"));
123
+ return true;
124
+ });
125
+ });
126
+ it("includes appName and source in error for retry hint", () => {
127
+ assert.throws(() => verifyRuntimeDependencies(["__missing__"], "github:user/repo", "gsd"), (err) => {
128
+ assert.ok(err.message.includes("gsd"));
129
+ assert.ok(err.message.includes("github:user/repo"));
130
+ return true;
131
+ });
132
+ });
133
+ });
134
+ // ─── resolveLocalSourcePath ───────────────────────────────────────────────────
135
+ describe("resolveLocalSourcePath", () => {
136
+ it("returns undefined for empty string", () => {
137
+ assert.equal(resolveLocalSourcePath("", "/tmp"), undefined);
138
+ });
139
+ it("returns undefined for npm: source", () => {
140
+ assert.equal(resolveLocalSourcePath("npm:@foo/bar", "/tmp"), undefined);
141
+ });
142
+ it("returns undefined for git URL", () => {
143
+ assert.equal(resolveLocalSourcePath("git:github.com/user/repo", "/tmp"), undefined);
144
+ });
145
+ it("returns undefined for https git URL", () => {
146
+ assert.equal(resolveLocalSourcePath("https://github.com/user/repo", "/tmp"), undefined);
147
+ });
148
+ it("resolves ~ to homedir", () => {
149
+ const result = resolveLocalSourcePath("~", "/tmp");
150
+ if (existsSync(homedir())) {
151
+ assert.equal(result, homedir());
152
+ }
153
+ else {
154
+ assert.equal(result, undefined);
155
+ }
156
+ });
157
+ it("resolves ~/path relative to homedir", () => {
158
+ const result = resolveLocalSourcePath("~/", "/tmp");
159
+ if (existsSync(homedir())) {
160
+ assert.equal(result, homedir());
161
+ }
162
+ else {
163
+ assert.equal(result, undefined);
164
+ }
165
+ });
166
+ it("resolves relative path that exists", (t) => {
167
+ const dir = tmpDir("resolve-rel", t);
168
+ const sub = join(dir, "myext");
169
+ mkdirSync(sub, { recursive: true });
170
+ const result = resolveLocalSourcePath("myext", dir);
171
+ assert.equal(result, resolve(dir, "myext"));
172
+ });
173
+ it("returns undefined for relative path that does not exist", (t) => {
174
+ const dir = tmpDir("resolve-noexist", t);
175
+ assert.equal(resolveLocalSourcePath("nonexistent", dir), undefined);
176
+ });
177
+ it("resolves absolute path that exists", (t) => {
178
+ const dir = tmpDir("resolve-abs", t);
179
+ assert.equal(resolveLocalSourcePath(dir, "/irrelevant"), dir);
180
+ });
181
+ it("returns undefined for absolute path that does not exist", () => {
182
+ assert.equal(resolveLocalSourcePath("/tmp/__nonexistent_path_for_test__", "/tmp"), undefined);
183
+ });
184
+ });
185
+ //# sourceMappingURL=lifecycle-hooks.test.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"lifecycle-hooks.test.js","sourceRoot":"","sources":["../../src/core/lifecycle-hooks.test.ts"],"names":[],"mappings":"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","sourcesContent":["import assert from \"node:assert/strict\";\nimport { mkdtempSync, mkdirSync, rmSync, writeFileSync, existsSync } from \"node:fs\";\nimport { homedir, tmpdir } from \"node:os\";\nimport { join, resolve } from \"node:path\";\nimport { describe, it } from \"node:test\";\nimport {\n\treadManifestRuntimeDeps,\n\tcollectRuntimeDependencies,\n\tverifyRuntimeDependencies,\n\tresolveLocalSourcePath,\n} from \"./lifecycle-hooks.js\";\n\nfunction tmpDir(prefix: string, t: { after: (fn: () => void) => void }): string {\n\tconst dir = mkdtempSync(join(tmpdir(), `pi-lh-${prefix}-`));\n\tt.after(() => rmSync(dir, { recursive: true, force: true }));\n\treturn dir;\n}\n\n// ─── readManifestRuntimeDeps ──────────────────────────────────────────────────\n\ndescribe(\"readManifestRuntimeDeps\", () => {\n\tit(\"returns empty array when manifest file is missing\", (t) => {\n\t\tconst dir = tmpDir(\"no-manifest\", t);\n\t\tassert.deepEqual(readManifestRuntimeDeps(dir), []);\n\t});\n\n\tit(\"returns empty array for malformed JSON\", (t) => {\n\t\tconst dir = tmpDir(\"bad-json\", t);\n\t\twriteFileSync(join(dir, \"extension-manifest.json\"), \"not json{{{\", \"utf-8\");\n\t\tassert.deepEqual(readManifestRuntimeDeps(dir), []);\n\t});\n\n\tit(\"returns runtime deps from valid manifest\", (t) => {\n\t\tconst dir = tmpDir(\"valid\", t);\n\t\twriteFileSync(join(dir, \"extension-manifest.json\"), JSON.stringify({\n\t\t\tdependencies: { runtime: [\"claude\", \"node\"] },\n\t\t}), \"utf-8\");\n\t\tassert.deepEqual(readManifestRuntimeDeps(dir), [\"claude\", \"node\"]);\n\t});\n\n\tit(\"returns empty array when dependencies exists but runtime is missing\", (t) => {\n\t\tconst dir = tmpDir(\"no-runtime\", t);\n\t\twriteFileSync(join(dir, \"extension-manifest.json\"), JSON.stringify({\n\t\t\tdependencies: {},\n\t\t}), \"utf-8\");\n\t\tassert.deepEqual(readManifestRuntimeDeps(dir), []);\n\t});\n\n\tit(\"returns empty array when runtime is empty\", (t) => {\n\t\tconst dir = tmpDir(\"empty-runtime\", t);\n\t\twriteFileSync(join(dir, \"extension-manifest.json\"), JSON.stringify({\n\t\t\tdependencies: { runtime: [] },\n\t\t}), \"utf-8\");\n\t\tassert.deepEqual(readManifestRuntimeDeps(dir), []);\n\t});\n\n\tit(\"filters out non-string entries in runtime array\", (t) => {\n\t\tconst dir = tmpDir(\"mixed-types\", t);\n\t\twriteFileSync(join(dir, \"extension-manifest.json\"), JSON.stringify({\n\t\t\tdependencies: { runtime: [123, null, \"node\", false, \"python\"] },\n\t\t}), \"utf-8\");\n\t\tassert.deepEqual(readManifestRuntimeDeps(dir), [\"node\", \"python\"]);\n\t});\n\n\tit(\"returns empty array when no dependencies field at all\", (t) => {\n\t\tconst dir = tmpDir(\"no-deps-field\", t);\n\t\twriteFileSync(join(dir, \"extension-manifest.json\"), JSON.stringify({\n\t\t\tid: \"test\",\n\t\t\tname: \"Test\",\n\t\t}), \"utf-8\");\n\t\tassert.deepEqual(readManifestRuntimeDeps(dir), []);\n\t});\n});\n\n// ─── collectRuntimeDependencies ───────────────────────────────────────────────\n\ndescribe(\"collectRuntimeDependencies\", () => {\n\tit(\"aggregates deps from installedPath manifest\", (t) => {\n\t\tconst dir = tmpDir(\"collect-installed\", t);\n\t\twriteFileSync(join(dir, \"extension-manifest.json\"), JSON.stringify({\n\t\t\tdependencies: { runtime: [\"claude\"] },\n\t\t}), \"utf-8\");\n\t\tassert.deepEqual(collectRuntimeDependencies(dir, []), [\"claude\"]);\n\t});\n\n\tit(\"aggregates deps from entry path directory manifests\", (t) => {\n\t\tconst root = tmpDir(\"collect-entry\", t);\n\t\tconst installedDir = join(root, \"installed\");\n\t\tconst entryDir = join(root, \"entry\");\n\t\tmkdirSync(installedDir, { recursive: true });\n\t\tmkdirSync(entryDir, { recursive: true });\n\t\twriteFileSync(join(entryDir, \"extension-manifest.json\"), JSON.stringify({\n\t\t\tdependencies: { runtime: [\"python\"] },\n\t\t}), \"utf-8\");\n\t\tconst deps = collectRuntimeDependencies(installedDir, [join(entryDir, \"index.ts\")]);\n\t\tassert.deepEqual(deps, [\"python\"]);\n\t});\n\n\tit(\"deduplicates across multiple directories\", (t) => {\n\t\tconst root = tmpDir(\"collect-dedup\", t);\n\t\tconst dir1 = join(root, \"dir1\");\n\t\tconst dir2 = join(root, \"dir2\");\n\t\tmkdirSync(dir1, { recursive: true });\n\t\tmkdirSync(dir2, { recursive: true });\n\t\twriteFileSync(join(dir1, \"extension-manifest.json\"), JSON.stringify({\n\t\t\tdependencies: { runtime: [\"node\", \"python\"] },\n\t\t}), \"utf-8\");\n\t\twriteFileSync(join(dir2, \"extension-manifest.json\"), JSON.stringify({\n\t\t\tdependencies: { runtime: [\"python\", \"claude\"] },\n\t\t}), \"utf-8\");\n\t\tconst deps = collectRuntimeDependencies(dir1, [join(dir2, \"index.ts\")]);\n\t\tassert.equal(deps.length, 3);\n\t\tassert.ok(deps.includes(\"node\"));\n\t\tassert.ok(deps.includes(\"python\"));\n\t\tassert.ok(deps.includes(\"claude\"));\n\t});\n\n\tit(\"returns empty when no directories have manifests\", (t) => {\n\t\tconst dir = tmpDir(\"collect-empty\", t);\n\t\tassert.deepEqual(collectRuntimeDependencies(dir, []), []);\n\t});\n});\n\n// ─── verifyRuntimeDependencies ────────────────────────────────────────────────\n\ndescribe(\"verifyRuntimeDependencies\", () => {\n\tit(\"does not throw for empty deps array\", () => {\n\t\tassert.doesNotThrow(() => verifyRuntimeDependencies([], \"test-source\", \"pi\"));\n\t});\n\n\tit(\"does not throw when all deps are present\", () => {\n\t\tassert.doesNotThrow(() => verifyRuntimeDependencies([\"node\"], \"test-source\", \"pi\"));\n\t});\n\n\tit(\"throws for missing dep with 'Missing runtime dependencies' message\", () => {\n\t\tassert.throws(\n\t\t\t() => verifyRuntimeDependencies([\"__nonexistent_dep_for_test__\"], \"test-source\", \"pi\"),\n\t\t\t(err: Error) => {\n\t\t\t\tassert.ok(err.message.includes(\"Missing runtime dependencies\"));\n\t\t\t\tassert.ok(err.message.includes(\"__nonexistent_dep_for_test__\"));\n\t\t\t\treturn true;\n\t\t\t},\n\t\t);\n\t});\n\n\tit(\"lists all missing deps in error message\", () => {\n\t\tassert.throws(\n\t\t\t() => verifyRuntimeDependencies([\"__missing_1__\", \"__missing_2__\"], \"test-source\", \"pi\"),\n\t\t\t(err: Error) => {\n\t\t\t\tassert.ok(err.message.includes(\"__missing_1__\"));\n\t\t\t\tassert.ok(err.message.includes(\"__missing_2__\"));\n\t\t\t\treturn true;\n\t\t\t},\n\t\t);\n\t});\n\n\tit(\"includes appName and source in error for retry hint\", () => {\n\t\tassert.throws(\n\t\t\t() => verifyRuntimeDependencies([\"__missing__\"], \"github:user/repo\", \"gsd\"),\n\t\t\t(err: Error) => {\n\t\t\t\tassert.ok(err.message.includes(\"gsd\"));\n\t\t\t\tassert.ok(err.message.includes(\"github:user/repo\"));\n\t\t\t\treturn true;\n\t\t\t},\n\t\t);\n\t});\n});\n\n// ─── resolveLocalSourcePath ───────────────────────────────────────────────────\n\ndescribe(\"resolveLocalSourcePath\", () => {\n\tit(\"returns undefined for empty string\", () => {\n\t\tassert.equal(resolveLocalSourcePath(\"\", \"/tmp\"), undefined);\n\t});\n\n\tit(\"returns undefined for npm: source\", () => {\n\t\tassert.equal(resolveLocalSourcePath(\"npm:@foo/bar\", \"/tmp\"), undefined);\n\t});\n\n\tit(\"returns undefined for git URL\", () => {\n\t\tassert.equal(resolveLocalSourcePath(\"git:github.com/user/repo\", \"/tmp\"), undefined);\n\t});\n\n\tit(\"returns undefined for https git URL\", () => {\n\t\tassert.equal(resolveLocalSourcePath(\"https://github.com/user/repo\", \"/tmp\"), undefined);\n\t});\n\n\tit(\"resolves ~ to homedir\", () => {\n\t\tconst result = resolveLocalSourcePath(\"~\", \"/tmp\");\n\t\tif (existsSync(homedir())) {\n\t\t\tassert.equal(result, homedir());\n\t\t} else {\n\t\t\tassert.equal(result, undefined);\n\t\t}\n\t});\n\n\tit(\"resolves ~/path relative to homedir\", () => {\n\t\tconst result = resolveLocalSourcePath(\"~/\", \"/tmp\");\n\t\tif (existsSync(homedir())) {\n\t\t\tassert.equal(result, homedir());\n\t\t} else {\n\t\t\tassert.equal(result, undefined);\n\t\t}\n\t});\n\n\tit(\"resolves relative path that exists\", (t) => {\n\t\tconst dir = tmpDir(\"resolve-rel\", t);\n\t\tconst sub = join(dir, \"myext\");\n\t\tmkdirSync(sub, { recursive: true });\n\t\tconst result = resolveLocalSourcePath(\"myext\", dir);\n\t\tassert.equal(result, resolve(dir, \"myext\"));\n\t});\n\n\tit(\"returns undefined for relative path that does not exist\", (t) => {\n\t\tconst dir = tmpDir(\"resolve-noexist\", t);\n\t\tassert.equal(resolveLocalSourcePath(\"nonexistent\", dir), undefined);\n\t});\n\n\tit(\"resolves absolute path that exists\", (t) => {\n\t\tconst dir = tmpDir(\"resolve-abs\", t);\n\t\tassert.equal(resolveLocalSourcePath(dir, \"/irrelevant\"), dir);\n\t});\n\n\tit(\"returns undefined for absolute path that does not exist\", () => {\n\t\tassert.equal(resolveLocalSourcePath(\"/tmp/__nonexistent_path_for_test__\", \"/tmp\"), undefined);\n\t});\n});\n"]}