gsd-pi 2.76.0-dev.fe143342a → 2.77.0-dev.1d17f366c

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 (597) hide show
  1. package/README.md +17 -35
  2. package/dist/claude-cli-check.js +32 -3
  3. package/dist/cli-web-branch.d.ts +1 -0
  4. package/dist/cli-web-branch.js +3 -0
  5. package/dist/cli.js +38 -2
  6. package/dist/extension-discovery.d.ts +6 -0
  7. package/dist/extension-discovery.js +37 -0
  8. package/dist/extension-registry.d.ts +3 -0
  9. package/dist/extension-sort.d.ts +18 -0
  10. package/dist/extension-sort.js +114 -0
  11. package/dist/extension-validator.d.ts +47 -0
  12. package/dist/extension-validator.js +127 -0
  13. package/dist/loader.js +35 -7
  14. package/dist/onboarding.js +45 -0
  15. package/dist/provider-migrations.d.ts +18 -0
  16. package/dist/provider-migrations.js +14 -0
  17. package/dist/resources/extensions/claude-code-cli/readiness.js +4 -3
  18. package/dist/resources/extensions/claude-code-cli/stream-adapter.js +78 -59
  19. package/dist/resources/extensions/cmux/index.js +20 -0
  20. package/dist/resources/extensions/github-sync/templates.js +103 -0
  21. package/dist/resources/extensions/google-search/extension-manifest.json +5 -4
  22. package/dist/resources/extensions/google-search/index.js +3 -375
  23. package/dist/resources/extensions/gsd/abandon-detect.js +44 -0
  24. package/dist/resources/extensions/gsd/auto/loop.js +90 -2
  25. package/dist/resources/extensions/gsd/auto/phases.js +95 -21
  26. package/dist/resources/extensions/gsd/auto/resolve.js +24 -0
  27. package/dist/resources/extensions/gsd/auto/run-unit.js +48 -4
  28. package/dist/resources/extensions/gsd/auto/session.js +18 -1
  29. package/dist/resources/extensions/gsd/auto/turn-epoch.js +95 -0
  30. package/dist/resources/extensions/gsd/auto-dispatch.js +115 -17
  31. package/dist/resources/extensions/gsd/auto-loop.js +1 -1
  32. package/dist/resources/extensions/gsd/auto-model-selection.js +1 -1
  33. package/dist/resources/extensions/gsd/auto-post-unit.js +90 -2
  34. package/dist/resources/extensions/gsd/auto-prompts.js +14 -0
  35. package/dist/resources/extensions/gsd/auto-recovery.js +46 -1
  36. package/dist/resources/extensions/gsd/auto-start.js +45 -39
  37. package/dist/resources/extensions/gsd/auto-timeout-recovery.js +11 -5
  38. package/dist/resources/extensions/gsd/auto-unit-closeout.js +11 -2
  39. package/dist/resources/extensions/gsd/auto-worktree.js +109 -61
  40. package/dist/resources/extensions/gsd/auto.js +97 -31
  41. package/dist/resources/extensions/gsd/bootstrap/agent-end-recovery.js +27 -1
  42. package/dist/resources/extensions/gsd/bootstrap/provider-error-resume.js +4 -2
  43. package/dist/resources/extensions/gsd/bootstrap/register-extension.js +11 -0
  44. package/dist/resources/extensions/gsd/bootstrap/register-hooks.js +17 -6
  45. package/dist/resources/extensions/gsd/bootstrap/system-context.js +11 -6
  46. package/dist/resources/extensions/gsd/bootstrap/write-gate.js +34 -2
  47. package/dist/resources/extensions/gsd/clean-root-preflight.js +93 -0
  48. package/dist/resources/extensions/gsd/commands/handlers/workflow.js +31 -4
  49. package/dist/resources/extensions/gsd/commands-cmux.js +9 -6
  50. package/dist/resources/extensions/gsd/commands-extensions.js +634 -43
  51. package/dist/resources/extensions/gsd/commands-prefs-wizard.js +968 -23
  52. package/dist/resources/extensions/gsd/dispatch-guard.js +29 -3
  53. package/dist/resources/extensions/gsd/file-lock.js +49 -9
  54. package/dist/resources/extensions/gsd/git-service.js +1 -0
  55. package/dist/resources/extensions/gsd/gitignore.js +2 -0
  56. package/dist/resources/extensions/gsd/gsd-db.js +90 -30
  57. package/dist/resources/extensions/gsd/guided-flow-queue.js +4 -1
  58. package/dist/resources/extensions/gsd/guided-flow.js +212 -9
  59. package/dist/resources/extensions/gsd/health-widget.js +4 -1
  60. package/dist/resources/extensions/gsd/journal.js +17 -2
  61. package/dist/resources/extensions/gsd/key-manager.js +22 -0
  62. package/dist/resources/extensions/gsd/milestone-actions.js +15 -0
  63. package/dist/resources/extensions/gsd/milestone-summary-classifier.js +37 -0
  64. package/dist/resources/extensions/gsd/model-router.js +36 -3
  65. package/dist/resources/extensions/gsd/notifications.js +30 -16
  66. package/dist/resources/extensions/gsd/pre-execution-checks.js +31 -6
  67. package/dist/resources/extensions/gsd/prompts/discuss-headless.md +29 -2
  68. package/dist/resources/extensions/gsd/prompts/discuss.md +29 -2
  69. package/dist/resources/extensions/gsd/prompts/doctor-heal.md +5 -4
  70. package/dist/resources/extensions/gsd/prompts/parallel-research-slices.md +5 -2
  71. package/dist/resources/extensions/gsd/prompts/system.md +1 -0
  72. package/dist/resources/extensions/gsd/reports.js +5 -4
  73. package/dist/resources/extensions/gsd/safety/evidence-collector.js +96 -0
  74. package/dist/resources/extensions/gsd/safety/file-change-validator.js +12 -4
  75. package/dist/resources/extensions/gsd/safety/safety-harness.js +5 -1
  76. package/dist/resources/extensions/gsd/state-transition-matrix.js +118 -0
  77. package/dist/resources/extensions/gsd/state.js +25 -25
  78. package/dist/resources/extensions/gsd/token-counter.js +22 -5
  79. package/dist/resources/extensions/gsd/tools/complete-milestone.js +16 -10
  80. package/dist/resources/extensions/gsd/tools/complete-slice.js +21 -0
  81. package/dist/resources/extensions/gsd/tools/complete-task.js +31 -0
  82. package/dist/resources/extensions/gsd/uok/audit.js +18 -2
  83. package/dist/resources/extensions/gsd/uok/dispatch-envelope.js +33 -0
  84. package/dist/resources/extensions/gsd/uok/execution-graph.js +10 -0
  85. package/dist/resources/extensions/gsd/uok/gitops.js +2 -1
  86. package/dist/resources/extensions/gsd/uok/loop-adapter.js +37 -10
  87. package/dist/resources/extensions/gsd/uok/parity-report.js +58 -0
  88. package/dist/resources/extensions/gsd/uok/plan-v2.js +30 -7
  89. package/dist/resources/extensions/gsd/uok/writer.js +82 -0
  90. package/dist/resources/extensions/gsd/workflow-logger.js +10 -2
  91. package/dist/resources/extensions/gsd/worktree-manager.js +1 -0
  92. package/dist/resources/extensions/gsd/worktree-resolver.js +50 -10
  93. package/dist/resources/extensions/mcp-client/auth.js +10 -1
  94. package/dist/resources/extensions/mcp-client/index.js +118 -9
  95. package/dist/resources/extensions/shared/cmux-events.js +12 -0
  96. package/dist/resources/extensions/shared/rtk-session-stats.js +1 -2
  97. package/dist/resources/skills/create-skill/SKILL.md +2 -2
  98. package/dist/resources/skills/create-skill/references/gsd-skill-ecosystem.md +4 -4
  99. package/dist/resources/skills/create-skill/workflows/audit-skill.md +4 -4
  100. package/dist/resources/skills/create-skill/workflows/create-new-skill.md +5 -5
  101. package/dist/resources/skills/verify-before-complete/SKILL.md +2 -1
  102. package/dist/resources/skills/write-docs/SKILL.md +2 -1
  103. package/dist/tsconfig.extensions.tsbuildinfo +1 -1
  104. package/dist/web/standalone/.next/BUILD_ID +1 -1
  105. package/dist/web/standalone/.next/app-path-routes-manifest.json +9 -9
  106. package/dist/web/standalone/.next/build-manifest.json +3 -3
  107. package/dist/web/standalone/.next/prerender-manifest.json +3 -3
  108. package/dist/web/standalone/.next/react-loadable-manifest.json +1 -1
  109. package/dist/web/standalone/.next/server/app/_global-error.html +1 -1
  110. package/dist/web/standalone/.next/server/app/_global-error.rsc +1 -1
  111. package/dist/web/standalone/.next/server/app/_global-error.segments/_full.segment.rsc +1 -1
  112. package/dist/web/standalone/.next/server/app/_global-error.segments/_global-error/__PAGE__.segment.rsc +1 -1
  113. package/dist/web/standalone/.next/server/app/_global-error.segments/_global-error.segment.rsc +1 -1
  114. package/dist/web/standalone/.next/server/app/_global-error.segments/_head.segment.rsc +1 -1
  115. package/dist/web/standalone/.next/server/app/_global-error.segments/_index.segment.rsc +1 -1
  116. package/dist/web/standalone/.next/server/app/_global-error.segments/_tree.segment.rsc +1 -1
  117. package/dist/web/standalone/.next/server/app/_not-found.html +1 -1
  118. package/dist/web/standalone/.next/server/app/_not-found.rsc +1 -1
  119. package/dist/web/standalone/.next/server/app/_not-found.segments/_full.segment.rsc +1 -1
  120. package/dist/web/standalone/.next/server/app/_not-found.segments/_head.segment.rsc +1 -1
  121. package/dist/web/standalone/.next/server/app/_not-found.segments/_index.segment.rsc +1 -1
  122. package/dist/web/standalone/.next/server/app/_not-found.segments/_not-found/__PAGE__.segment.rsc +1 -1
  123. package/dist/web/standalone/.next/server/app/_not-found.segments/_not-found.segment.rsc +1 -1
  124. package/dist/web/standalone/.next/server/app/_not-found.segments/_tree.segment.rsc +1 -1
  125. package/dist/web/standalone/.next/server/app/api/boot/route.js +1 -1
  126. package/dist/web/standalone/.next/server/app/api/boot/route.js.nft.json +1 -1
  127. package/dist/web/standalone/.next/server/app/api/bridge-terminal/input/route.js +1 -1
  128. package/dist/web/standalone/.next/server/app/api/bridge-terminal/input/route.js.nft.json +1 -1
  129. package/dist/web/standalone/.next/server/app/api/bridge-terminal/resize/route.js +1 -1
  130. package/dist/web/standalone/.next/server/app/api/bridge-terminal/resize/route.js.nft.json +1 -1
  131. package/dist/web/standalone/.next/server/app/api/bridge-terminal/stream/route.js +1 -1
  132. package/dist/web/standalone/.next/server/app/api/bridge-terminal/stream/route.js.nft.json +1 -1
  133. package/dist/web/standalone/.next/server/app/api/captures/route.js +1 -1
  134. package/dist/web/standalone/.next/server/app/api/captures/route.js.nft.json +1 -1
  135. package/dist/web/standalone/.next/server/app/api/cleanup/route.js +1 -1
  136. package/dist/web/standalone/.next/server/app/api/cleanup/route.js.nft.json +1 -1
  137. package/dist/web/standalone/.next/server/app/api/doctor/route.js +1 -1
  138. package/dist/web/standalone/.next/server/app/api/doctor/route.js.nft.json +1 -1
  139. package/dist/web/standalone/.next/server/app/api/export-data/route.js +1 -1
  140. package/dist/web/standalone/.next/server/app/api/export-data/route.js.nft.json +1 -1
  141. package/dist/web/standalone/.next/server/app/api/files/route.js +1 -1
  142. package/dist/web/standalone/.next/server/app/api/files/route.js.nft.json +1 -1
  143. package/dist/web/standalone/.next/server/app/api/forensics/route.js +1 -1
  144. package/dist/web/standalone/.next/server/app/api/forensics/route.js.nft.json +1 -1
  145. package/dist/web/standalone/.next/server/app/api/git/route.js +1 -1
  146. package/dist/web/standalone/.next/server/app/api/git/route.js.nft.json +1 -1
  147. package/dist/web/standalone/.next/server/app/api/history/route.js +1 -1
  148. package/dist/web/standalone/.next/server/app/api/history/route.js.nft.json +1 -1
  149. package/dist/web/standalone/.next/server/app/api/hooks/route.js +1 -1
  150. package/dist/web/standalone/.next/server/app/api/hooks/route.js.nft.json +1 -1
  151. package/dist/web/standalone/.next/server/app/api/inspect/route.js +1 -1
  152. package/dist/web/standalone/.next/server/app/api/inspect/route.js.nft.json +1 -1
  153. package/dist/web/standalone/.next/server/app/api/knowledge/route.js +1 -1
  154. package/dist/web/standalone/.next/server/app/api/knowledge/route.js.nft.json +1 -1
  155. package/dist/web/standalone/.next/server/app/api/live-state/route.js +1 -1
  156. package/dist/web/standalone/.next/server/app/api/live-state/route.js.nft.json +1 -1
  157. package/dist/web/standalone/.next/server/app/api/notifications/route.js +1 -1
  158. package/dist/web/standalone/.next/server/app/api/notifications/route.js.nft.json +1 -1
  159. package/dist/web/standalone/.next/server/app/api/onboarding/route.js +1 -1
  160. package/dist/web/standalone/.next/server/app/api/onboarding/route.js.nft.json +1 -1
  161. package/dist/web/standalone/.next/server/app/api/projects/route.js +1 -1
  162. package/dist/web/standalone/.next/server/app/api/projects/route.js.nft.json +1 -1
  163. package/dist/web/standalone/.next/server/app/api/recovery/route.js +1 -1
  164. package/dist/web/standalone/.next/server/app/api/recovery/route.js.nft.json +1 -1
  165. package/dist/web/standalone/.next/server/app/api/session/browser/route.js +1 -1
  166. package/dist/web/standalone/.next/server/app/api/session/browser/route.js.nft.json +1 -1
  167. package/dist/web/standalone/.next/server/app/api/session/command/route.js +1 -1
  168. package/dist/web/standalone/.next/server/app/api/session/command/route.js.nft.json +1 -1
  169. package/dist/web/standalone/.next/server/app/api/session/events/route.js +1 -1
  170. package/dist/web/standalone/.next/server/app/api/session/events/route.js.nft.json +1 -1
  171. package/dist/web/standalone/.next/server/app/api/session/manage/route.js +1 -1
  172. package/dist/web/standalone/.next/server/app/api/session/manage/route.js.nft.json +1 -1
  173. package/dist/web/standalone/.next/server/app/api/settings-data/route.js +1 -1
  174. package/dist/web/standalone/.next/server/app/api/settings-data/route.js.nft.json +1 -1
  175. package/dist/web/standalone/.next/server/app/api/skill-health/route.js +1 -1
  176. package/dist/web/standalone/.next/server/app/api/skill-health/route.js.nft.json +1 -1
  177. package/dist/web/standalone/.next/server/app/api/steer/route.js +1 -1
  178. package/dist/web/standalone/.next/server/app/api/steer/route.js.nft.json +1 -1
  179. package/dist/web/standalone/.next/server/app/api/switch-root/route.js +1 -1
  180. package/dist/web/standalone/.next/server/app/api/switch-root/route.js.nft.json +1 -1
  181. package/dist/web/standalone/.next/server/app/api/terminal/sessions/route.js +1 -1
  182. package/dist/web/standalone/.next/server/app/api/terminal/sessions/route.js.nft.json +1 -1
  183. package/dist/web/standalone/.next/server/app/api/terminal/stream/route.js +1 -1
  184. package/dist/web/standalone/.next/server/app/api/terminal/stream/route.js.nft.json +1 -1
  185. package/dist/web/standalone/.next/server/app/api/undo/route.js +1 -1
  186. package/dist/web/standalone/.next/server/app/api/undo/route.js.nft.json +1 -1
  187. package/dist/web/standalone/.next/server/app/api/visualizer/route.js +1 -1
  188. package/dist/web/standalone/.next/server/app/api/visualizer/route.js.nft.json +1 -1
  189. package/dist/web/standalone/.next/server/app/index.html +1 -1
  190. package/dist/web/standalone/.next/server/app/index.rsc +1 -1
  191. package/dist/web/standalone/.next/server/app/index.segments/__PAGE__.segment.rsc +1 -1
  192. package/dist/web/standalone/.next/server/app/index.segments/_full.segment.rsc +1 -1
  193. package/dist/web/standalone/.next/server/app/index.segments/_head.segment.rsc +1 -1
  194. package/dist/web/standalone/.next/server/app/index.segments/_index.segment.rsc +1 -1
  195. package/dist/web/standalone/.next/server/app/index.segments/_tree.segment.rsc +1 -1
  196. package/dist/web/standalone/.next/server/app-paths-manifest.json +9 -9
  197. package/dist/web/standalone/.next/server/chunks/1926.js +1 -0
  198. package/dist/web/standalone/.next/server/chunks/6897.js +2 -2
  199. package/dist/web/standalone/.next/server/middleware-build-manifest.js +1 -1
  200. package/dist/web/standalone/.next/server/middleware-manifest.json +5 -5
  201. package/dist/web/standalone/.next/server/middleware-react-loadable-manifest.js +1 -1
  202. package/dist/web/standalone/.next/server/pages/404.html +1 -1
  203. package/dist/web/standalone/.next/server/pages/500.html +1 -1
  204. package/dist/web/standalone/.next/server/server-reference-manifest.json +1 -1
  205. package/dist/web/standalone/.next/static/chunks/2826.e9f5195e91f9cad2.js +11 -0
  206. package/dist/web/standalone/.next/static/chunks/{webpack-5fc74f13a25fa1bb.js → webpack-2e68521d7c82f7c2.js} +1 -1
  207. package/dist/welcome-screen.js +6 -1
  208. package/dist/wizard.js +2 -0
  209. package/package.json +16 -14
  210. package/packages/daemon/package.json +2 -2
  211. package/packages/mcp-server/README.md +3 -3
  212. package/packages/mcp-server/dist/env-writer.d.ts +1 -0
  213. package/packages/mcp-server/dist/env-writer.d.ts.map +1 -1
  214. package/packages/mcp-server/dist/env-writer.js +74 -6
  215. package/packages/mcp-server/dist/env-writer.js.map +1 -1
  216. package/packages/mcp-server/dist/remote-questions.d.ts +45 -0
  217. package/packages/mcp-server/dist/remote-questions.d.ts.map +1 -0
  218. package/packages/mcp-server/dist/remote-questions.js +732 -0
  219. package/packages/mcp-server/dist/remote-questions.js.map +1 -0
  220. package/packages/mcp-server/dist/server.d.ts +7 -0
  221. package/packages/mcp-server/dist/server.d.ts.map +1 -1
  222. package/packages/mcp-server/dist/server.js +95 -10
  223. package/packages/mcp-server/dist/server.js.map +1 -1
  224. package/packages/mcp-server/dist/session-manager.d.ts +14 -0
  225. package/packages/mcp-server/dist/session-manager.d.ts.map +1 -1
  226. package/packages/mcp-server/dist/session-manager.js +49 -1
  227. package/packages/mcp-server/dist/session-manager.js.map +1 -1
  228. package/packages/mcp-server/dist/workflow-tools.d.ts.map +1 -1
  229. package/packages/mcp-server/dist/workflow-tools.js +15 -6
  230. package/packages/mcp-server/dist/workflow-tools.js.map +1 -1
  231. package/packages/mcp-server/package.json +9 -3
  232. package/packages/mcp-server/src/env-writer.test.ts +79 -1
  233. package/packages/mcp-server/src/env-writer.ts +76 -6
  234. package/packages/mcp-server/src/mcp-server.test.ts +67 -0
  235. package/packages/mcp-server/src/readers/readers.test.ts +5 -1
  236. package/packages/mcp-server/src/remote-questions.test.ts +294 -0
  237. package/packages/mcp-server/src/remote-questions.ts +916 -0
  238. package/packages/mcp-server/src/server.ts +118 -16
  239. package/packages/mcp-server/src/session-manager.ts +43 -1
  240. package/packages/mcp-server/src/workflow-tools.test.ts +44 -0
  241. package/packages/mcp-server/src/workflow-tools.ts +19 -6
  242. package/packages/mcp-server/tsconfig.test.json +19 -0
  243. package/packages/mcp-server/tsconfig.tsbuildinfo +1 -1
  244. package/packages/native/package.json +6 -1
  245. package/packages/native/src/__tests__/clipboard.test.mjs +69 -23
  246. package/packages/native/tsconfig.tsbuildinfo +1 -1
  247. package/packages/pi-agent-core/package.json +6 -1
  248. package/packages/pi-agent-core/src/agent-loop.test.ts +220 -15
  249. package/packages/pi-ai/dist/models/custom.d.ts +38 -0
  250. package/packages/pi-ai/dist/models/custom.d.ts.map +1 -1
  251. package/packages/pi-ai/dist/models/custom.js +41 -0
  252. package/packages/pi-ai/dist/models/custom.js.map +1 -1
  253. package/packages/pi-ai/dist/providers/anthropic-auth.test.js +1 -1
  254. package/packages/pi-ai/dist/providers/anthropic-auth.test.js.map +1 -1
  255. package/packages/pi-ai/dist/providers/anthropic-shared.d.ts.map +1 -1
  256. package/packages/pi-ai/dist/providers/anthropic-shared.js +27 -4
  257. package/packages/pi-ai/dist/providers/anthropic-shared.js.map +1 -1
  258. package/packages/pi-ai/dist/providers/anthropic.d.ts.map +1 -1
  259. package/packages/pi-ai/dist/providers/anthropic.js +8 -3
  260. package/packages/pi-ai/dist/providers/anthropic.js.map +1 -1
  261. package/packages/pi-ai/dist/providers/minimax-tool-name.test.d.ts +2 -0
  262. package/packages/pi-ai/dist/providers/minimax-tool-name.test.d.ts.map +1 -0
  263. package/packages/pi-ai/dist/providers/minimax-tool-name.test.js +80 -0
  264. package/packages/pi-ai/dist/providers/minimax-tool-name.test.js.map +1 -0
  265. package/packages/pi-ai/dist/providers/simple-options.d.ts +10 -0
  266. package/packages/pi-ai/dist/providers/simple-options.d.ts.map +1 -1
  267. package/packages/pi-ai/dist/providers/simple-options.js +16 -1
  268. package/packages/pi-ai/dist/providers/simple-options.js.map +1 -1
  269. package/packages/pi-ai/package.json +6 -1
  270. package/packages/pi-ai/src/models/custom.ts +42 -0
  271. package/packages/pi-ai/src/providers/anthropic-auth.test.ts +1 -1
  272. package/packages/pi-ai/src/providers/anthropic-shared.ts +26 -5
  273. package/packages/pi-ai/src/providers/anthropic.ts +9 -3
  274. package/packages/pi-ai/src/providers/minimax-tool-name.test.ts +98 -0
  275. package/packages/pi-ai/src/providers/simple-options.ts +17 -1
  276. package/packages/pi-ai/tsconfig.tsbuildinfo +1 -1
  277. package/packages/pi-coding-agent/dist/core/agent-session-abort-order.test.js +3 -2
  278. package/packages/pi-coding-agent/dist/core/agent-session-abort-order.test.js.map +1 -1
  279. package/packages/pi-coding-agent/dist/core/agent-session.d.ts +2 -0
  280. package/packages/pi-coding-agent/dist/core/agent-session.d.ts.map +1 -1
  281. package/packages/pi-coding-agent/dist/core/agent-session.js +7 -0
  282. package/packages/pi-coding-agent/dist/core/agent-session.js.map +1 -1
  283. package/packages/pi-coding-agent/dist/core/compaction/compaction.d.ts +25 -0
  284. package/packages/pi-coding-agent/dist/core/compaction/compaction.d.ts.map +1 -1
  285. package/packages/pi-coding-agent/dist/core/compaction/compaction.js +105 -6
  286. package/packages/pi-coding-agent/dist/core/compaction/compaction.js.map +1 -1
  287. package/packages/pi-coding-agent/dist/core/compaction/compaction.test.js +230 -28
  288. package/packages/pi-coding-agent/dist/core/compaction/compaction.test.js.map +1 -1
  289. package/packages/pi-coding-agent/dist/core/compaction/utils.d.ts +30 -2
  290. package/packages/pi-coding-agent/dist/core/compaction/utils.d.ts.map +1 -1
  291. package/packages/pi-coding-agent/dist/core/compaction/utils.js +113 -12
  292. package/packages/pi-coding-agent/dist/core/compaction/utils.js.map +1 -1
  293. package/packages/pi-coding-agent/dist/core/compaction-orchestrator.d.ts +1 -0
  294. package/packages/pi-coding-agent/dist/core/compaction-orchestrator.d.ts.map +1 -1
  295. package/packages/pi-coding-agent/dist/core/compaction-orchestrator.js +29 -18
  296. package/packages/pi-coding-agent/dist/core/compaction-orchestrator.js.map +1 -1
  297. package/packages/pi-coding-agent/dist/core/compaction-orchestrator.test.d.ts +2 -0
  298. package/packages/pi-coding-agent/dist/core/compaction-orchestrator.test.d.ts.map +1 -0
  299. package/packages/pi-coding-agent/dist/core/compaction-orchestrator.test.js +130 -0
  300. package/packages/pi-coding-agent/dist/core/compaction-orchestrator.test.js.map +1 -0
  301. package/packages/pi-coding-agent/dist/core/compaction-utils.test.js +56 -1
  302. package/packages/pi-coding-agent/dist/core/compaction-utils.test.js.map +1 -1
  303. package/packages/pi-coding-agent/dist/core/discovery-cache.test.js +8 -15
  304. package/packages/pi-coding-agent/dist/core/discovery-cache.test.js.map +1 -1
  305. package/packages/pi-coding-agent/dist/core/extensions/extension-discovery.d.ts +25 -0
  306. package/packages/pi-coding-agent/dist/core/extensions/extension-discovery.d.ts.map +1 -0
  307. package/packages/pi-coding-agent/dist/core/extensions/extension-discovery.js +109 -0
  308. package/packages/pi-coding-agent/dist/core/extensions/extension-discovery.js.map +1 -0
  309. package/packages/pi-coding-agent/dist/core/extensions/extension-registry.d.ts +67 -0
  310. package/packages/pi-coding-agent/dist/core/extensions/extension-registry.d.ts.map +1 -0
  311. package/packages/pi-coding-agent/dist/core/extensions/extension-registry.js +167 -0
  312. package/packages/pi-coding-agent/dist/core/extensions/extension-registry.js.map +1 -0
  313. package/packages/pi-coding-agent/dist/core/extensions/loader.d.ts +3 -2
  314. package/packages/pi-coding-agent/dist/core/extensions/loader.d.ts.map +1 -1
  315. package/packages/pi-coding-agent/dist/core/extensions/loader.js +24 -8
  316. package/packages/pi-coding-agent/dist/core/extensions/loader.js.map +1 -1
  317. package/packages/pi-coding-agent/dist/core/extensions/runner.d.ts +2 -0
  318. package/packages/pi-coding-agent/dist/core/extensions/runner.d.ts.map +1 -1
  319. package/packages/pi-coding-agent/dist/core/extensions/runner.js.map +1 -1
  320. package/packages/pi-coding-agent/dist/core/extensions/types.d.ts +14 -0
  321. package/packages/pi-coding-agent/dist/core/extensions/types.d.ts.map +1 -1
  322. package/packages/pi-coding-agent/dist/core/extensions/types.js.map +1 -1
  323. package/packages/pi-coding-agent/dist/core/lsp/lsp-integration.test.js +11 -0
  324. package/packages/pi-coding-agent/dist/core/lsp/lsp-integration.test.js.map +1 -1
  325. package/packages/pi-coding-agent/dist/core/model-registry-auth-mode.test.js +2 -2
  326. package/packages/pi-coding-agent/dist/core/model-registry-auth-mode.test.js.map +1 -1
  327. package/packages/pi-coding-agent/dist/core/model-registry-custom-caps.test.d.ts +2 -0
  328. package/packages/pi-coding-agent/dist/core/model-registry-custom-caps.test.d.ts.map +1 -0
  329. package/packages/pi-coding-agent/dist/core/model-registry-custom-caps.test.js +203 -0
  330. package/packages/pi-coding-agent/dist/core/model-registry-custom-caps.test.js.map +1 -0
  331. package/packages/pi-coding-agent/dist/core/model-registry.d.ts.map +1 -1
  332. package/packages/pi-coding-agent/dist/core/model-registry.js +14 -0
  333. package/packages/pi-coding-agent/dist/core/model-registry.js.map +1 -1
  334. package/packages/pi-coding-agent/dist/core/resource-loader.js +1 -1
  335. package/packages/pi-coding-agent/dist/core/resource-loader.js.map +1 -1
  336. package/packages/pi-coding-agent/dist/core/sdk.d.ts +1 -0
  337. package/packages/pi-coding-agent/dist/core/sdk.d.ts.map +1 -1
  338. package/packages/pi-coding-agent/dist/core/sdk.js +4 -1
  339. package/packages/pi-coding-agent/dist/core/sdk.js.map +1 -1
  340. package/packages/pi-coding-agent/dist/core/sdk.test.js +19 -1
  341. package/packages/pi-coding-agent/dist/core/sdk.test.js.map +1 -1
  342. package/packages/pi-coding-agent/dist/core/session-manager.js +1 -1
  343. package/packages/pi-coding-agent/dist/core/session-manager.js.map +1 -1
  344. package/packages/pi-coding-agent/dist/core/session-manager.test.js +21 -1
  345. package/packages/pi-coding-agent/dist/core/session-manager.test.js.map +1 -1
  346. package/packages/pi-coding-agent/dist/core/system-prompt.js +3 -3
  347. package/packages/pi-coding-agent/dist/core/system-prompt.js.map +1 -1
  348. package/packages/pi-coding-agent/dist/core/tools/path-utils.test.js +2 -1
  349. package/packages/pi-coding-agent/dist/core/tools/path-utils.test.js.map +1 -1
  350. package/packages/pi-coding-agent/dist/modes/interactive/components/__tests__/provider-display-name.test.js +15 -6
  351. package/packages/pi-coding-agent/dist/modes/interactive/components/__tests__/provider-display-name.test.js.map +1 -1
  352. package/packages/pi-coding-agent/dist/modes/interactive/components/footer.d.ts.map +1 -1
  353. package/packages/pi-coding-agent/dist/modes/interactive/components/footer.js +14 -5
  354. package/packages/pi-coding-agent/dist/modes/interactive/components/footer.js.map +1 -1
  355. package/packages/pi-coding-agent/dist/modes/interactive/components/model-selector.d.ts +7 -1
  356. package/packages/pi-coding-agent/dist/modes/interactive/components/model-selector.d.ts.map +1 -1
  357. package/packages/pi-coding-agent/dist/modes/interactive/components/model-selector.js +31 -9
  358. package/packages/pi-coding-agent/dist/modes/interactive/components/model-selector.js.map +1 -1
  359. package/packages/pi-coding-agent/dist/modes/interactive/controllers/input-controller.test.js +14 -0
  360. package/packages/pi-coding-agent/dist/modes/interactive/controllers/input-controller.test.js.map +1 -1
  361. package/packages/pi-coding-agent/dist/modes/interactive/interactive-mode.d.ts.map +1 -1
  362. package/packages/pi-coding-agent/dist/modes/interactive/interactive-mode.js +13 -1
  363. package/packages/pi-coding-agent/dist/modes/interactive/interactive-mode.js.map +1 -1
  364. package/packages/pi-coding-agent/package.json +6 -1
  365. package/packages/pi-coding-agent/src/core/agent-session-abort-order.test.ts +3 -2
  366. package/packages/pi-coding-agent/src/core/agent-session.ts +11 -0
  367. package/packages/pi-coding-agent/src/core/compaction/compaction.test.ts +368 -28
  368. package/packages/pi-coding-agent/src/core/compaction/compaction.ts +122 -6
  369. package/packages/pi-coding-agent/src/core/compaction/utils.ts +111 -13
  370. package/packages/pi-coding-agent/src/core/compaction-orchestrator.test.ts +154 -0
  371. package/packages/pi-coding-agent/src/core/compaction-orchestrator.ts +32 -18
  372. package/packages/pi-coding-agent/src/core/compaction-utils.test.ts +68 -1
  373. package/packages/pi-coding-agent/src/core/discovery-cache.test.ts +9 -18
  374. package/packages/pi-coding-agent/src/core/extensions/extension-discovery.ts +119 -0
  375. package/packages/pi-coding-agent/src/core/extensions/extension-registry.ts +222 -0
  376. package/packages/pi-coding-agent/src/core/extensions/loader.ts +24 -11
  377. package/packages/pi-coding-agent/src/core/extensions/runner.ts +2 -0
  378. package/packages/pi-coding-agent/src/core/extensions/types.ts +15 -0
  379. package/packages/pi-coding-agent/src/core/lsp/lsp-integration.test.ts +13 -0
  380. package/packages/pi-coding-agent/src/core/model-registry-auth-mode.test.ts +2 -2
  381. package/packages/pi-coding-agent/src/core/model-registry-custom-caps.test.ts +245 -0
  382. package/packages/pi-coding-agent/src/core/model-registry.ts +16 -0
  383. package/packages/pi-coding-agent/src/core/resource-loader.ts +1 -1
  384. package/packages/pi-coding-agent/src/core/sdk.test.ts +25 -1
  385. package/packages/pi-coding-agent/src/core/sdk.ts +10 -3
  386. package/packages/pi-coding-agent/src/core/session-manager.test.ts +30 -1
  387. package/packages/pi-coding-agent/src/core/session-manager.ts +1 -1
  388. package/packages/pi-coding-agent/src/core/system-prompt.ts +3 -3
  389. package/packages/pi-coding-agent/src/core/tools/path-utils.test.ts +2 -1
  390. package/packages/pi-coding-agent/src/modes/interactive/components/__tests__/provider-display-name.test.ts +17 -7
  391. package/packages/pi-coding-agent/src/modes/interactive/components/footer.ts +14 -5
  392. package/packages/pi-coding-agent/src/modes/interactive/components/model-selector.ts +45 -11
  393. package/packages/pi-coding-agent/src/modes/interactive/controllers/input-controller.test.ts +14 -0
  394. package/packages/pi-coding-agent/src/modes/interactive/interactive-mode.ts +13 -1
  395. package/packages/pi-coding-agent/tsconfig.tsbuildinfo +1 -1
  396. package/packages/pi-tui/dist/__tests__/autocomplete.test.js +12 -5
  397. package/packages/pi-tui/dist/__tests__/autocomplete.test.js.map +1 -1
  398. package/packages/pi-tui/dist/__tests__/stdin-buffer.test.js +21 -0
  399. package/packages/pi-tui/dist/__tests__/stdin-buffer.test.js.map +1 -1
  400. package/packages/pi-tui/dist/stdin-buffer.d.ts +7 -0
  401. package/packages/pi-tui/dist/stdin-buffer.d.ts.map +1 -1
  402. package/packages/pi-tui/dist/stdin-buffer.js +20 -0
  403. package/packages/pi-tui/dist/stdin-buffer.js.map +1 -1
  404. package/packages/pi-tui/package.json +6 -1
  405. package/packages/pi-tui/src/__tests__/autocomplete.test.ts +20 -5
  406. package/packages/pi-tui/src/__tests__/stdin-buffer.test.ts +27 -0
  407. package/packages/pi-tui/src/stdin-buffer.ts +26 -0
  408. package/packages/pi-tui/tsconfig.tsbuildinfo +1 -1
  409. package/packages/rpc-client/package.json +6 -1
  410. package/pkg/package.json +1 -1
  411. package/scripts/install.js +512 -0
  412. package/scripts/lib/workspace-manifest.cjs +86 -0
  413. package/scripts/link-workspace-packages.cjs +5 -17
  414. package/scripts/postinstall.js +9 -178
  415. package/src/resources/extensions/claude-code-cli/readiness.ts +4 -3
  416. package/src/resources/extensions/claude-code-cli/stream-adapter.ts +91 -63
  417. package/src/resources/extensions/claude-code-cli/tests/stream-adapter.test.ts +114 -12
  418. package/src/resources/extensions/cmux/index.ts +35 -10
  419. package/src/resources/extensions/github-sync/templates.ts +151 -0
  420. package/src/resources/extensions/github-sync/tests/templates.test.ts +59 -0
  421. package/src/resources/extensions/google-search/extension-manifest.json +5 -4
  422. package/src/resources/extensions/google-search/index.ts +9 -470
  423. package/src/resources/extensions/gsd/abandon-detect.ts +62 -0
  424. package/src/resources/extensions/gsd/auto/loop-deps.ts +14 -1
  425. package/src/resources/extensions/gsd/auto/loop.ts +104 -2
  426. package/src/resources/extensions/gsd/auto/phases.ts +123 -21
  427. package/src/resources/extensions/gsd/auto/resolve.ts +29 -0
  428. package/src/resources/extensions/gsd/auto/run-unit.ts +56 -4
  429. package/src/resources/extensions/gsd/auto/session.ts +28 -1
  430. package/src/resources/extensions/gsd/auto/turn-epoch.ts +108 -0
  431. package/src/resources/extensions/gsd/auto/types.ts +1 -1
  432. package/src/resources/extensions/gsd/auto-dispatch.ts +117 -16
  433. package/src/resources/extensions/gsd/auto-loop.ts +1 -1
  434. package/src/resources/extensions/gsd/auto-model-selection.ts +1 -1
  435. package/src/resources/extensions/gsd/auto-post-unit.ts +92 -3
  436. package/src/resources/extensions/gsd/auto-prompts.ts +28 -1
  437. package/src/resources/extensions/gsd/auto-recovery.ts +40 -1
  438. package/src/resources/extensions/gsd/auto-start.ts +48 -52
  439. package/src/resources/extensions/gsd/auto-timeout-recovery.ts +12 -5
  440. package/src/resources/extensions/gsd/auto-unit-closeout.ts +14 -3
  441. package/src/resources/extensions/gsd/auto-worktree.ts +122 -68
  442. package/src/resources/extensions/gsd/auto.ts +105 -35
  443. package/src/resources/extensions/gsd/bootstrap/agent-end-recovery.ts +34 -1
  444. package/src/resources/extensions/gsd/bootstrap/provider-error-resume.ts +6 -2
  445. package/src/resources/extensions/gsd/bootstrap/register-extension.ts +11 -0
  446. package/src/resources/extensions/gsd/bootstrap/register-hooks.ts +18 -6
  447. package/src/resources/extensions/gsd/bootstrap/system-context.ts +13 -9
  448. package/src/resources/extensions/gsd/bootstrap/write-gate.ts +35 -2
  449. package/src/resources/extensions/gsd/clean-root-preflight.ts +111 -0
  450. package/src/resources/extensions/gsd/commands/handlers/workflow.ts +27 -8
  451. package/src/resources/extensions/gsd/commands-cmux.ts +10 -6
  452. package/src/resources/extensions/gsd/commands-extensions.ts +747 -41
  453. package/src/resources/extensions/gsd/commands-prefs-wizard.ts +898 -32
  454. package/src/resources/extensions/gsd/dispatch-guard.ts +26 -2
  455. package/src/resources/extensions/gsd/file-lock.ts +84 -11
  456. package/src/resources/extensions/gsd/git-service.ts +1 -0
  457. package/src/resources/extensions/gsd/gitignore.ts +2 -1
  458. package/src/resources/extensions/gsd/gsd-db.ts +92 -32
  459. package/src/resources/extensions/gsd/guided-flow-queue.ts +4 -1
  460. package/src/resources/extensions/gsd/guided-flow.ts +259 -10
  461. package/src/resources/extensions/gsd/health-widget.ts +3 -1
  462. package/src/resources/extensions/gsd/journal.ts +29 -3
  463. package/src/resources/extensions/gsd/key-manager.ts +22 -0
  464. package/src/resources/extensions/gsd/milestone-actions.ts +18 -0
  465. package/src/resources/extensions/gsd/milestone-summary-classifier.ts +42 -0
  466. package/src/resources/extensions/gsd/model-router.ts +42 -1
  467. package/src/resources/extensions/gsd/notifications.ts +27 -15
  468. package/src/resources/extensions/gsd/pre-execution-checks.ts +33 -7
  469. package/src/resources/extensions/gsd/preferences-types.ts +8 -0
  470. package/src/resources/extensions/gsd/prompts/discuss-headless.md +29 -2
  471. package/src/resources/extensions/gsd/prompts/discuss.md +29 -2
  472. package/src/resources/extensions/gsd/prompts/doctor-heal.md +5 -4
  473. package/src/resources/extensions/gsd/prompts/parallel-research-slices.md +5 -2
  474. package/src/resources/extensions/gsd/prompts/system.md +1 -0
  475. package/src/resources/extensions/gsd/reports.ts +5 -4
  476. package/src/resources/extensions/gsd/safety/evidence-collector.ts +119 -0
  477. package/src/resources/extensions/gsd/safety/file-change-validator.ts +16 -3
  478. package/src/resources/extensions/gsd/safety/safety-harness.ts +9 -0
  479. package/src/resources/extensions/gsd/state-transition-matrix.ts +152 -0
  480. package/src/resources/extensions/gsd/state.ts +35 -30
  481. package/src/resources/extensions/gsd/tests/auto-loop.test.ts +238 -4
  482. package/src/resources/extensions/gsd/tests/auto-mode-guards.test.ts +79 -0
  483. package/src/resources/extensions/gsd/tests/auto-paused-session-validation.test.ts +12 -0
  484. package/src/resources/extensions/gsd/tests/auto-recovery.test.ts +122 -0
  485. package/src/resources/extensions/gsd/tests/auto-start-bootstrap-await-3420.test.ts +141 -0
  486. package/src/resources/extensions/gsd/tests/auto-start-clean-runtime-db-gated.test.ts +63 -0
  487. package/src/resources/extensions/gsd/tests/auto-wrapup-inflight-guard.test.ts +23 -0
  488. package/src/resources/extensions/gsd/tests/clean-root-preflight.test.ts +186 -0
  489. package/src/resources/extensions/gsd/tests/cmux.test.ts +5 -9
  490. package/src/resources/extensions/gsd/tests/complete-milestone-false-merge.test.ts +15 -0
  491. package/src/resources/extensions/gsd/tests/complete-milestone.test.ts +61 -1
  492. package/src/resources/extensions/gsd/tests/complete-slice.test.ts +2 -2
  493. package/src/resources/extensions/gsd/tests/complete-task.test.ts +2 -2
  494. package/src/resources/extensions/gsd/tests/custom-engine-loop-integration.test.ts +161 -0
  495. package/src/resources/extensions/gsd/tests/db-access-guardrails.test.ts +1 -0
  496. package/src/resources/extensions/gsd/tests/derive-state.test.ts +1 -2
  497. package/src/resources/extensions/gsd/tests/dispatch-complete-milestone-guard.test.ts +14 -9
  498. package/src/resources/extensions/gsd/tests/dispatch-guard-summary-db-mismatch.test.ts +77 -0
  499. package/src/resources/extensions/gsd/tests/dispatch-guard.test.ts +25 -0
  500. package/src/resources/extensions/gsd/tests/dispatch-missing-task-plans.test.ts +14 -0
  501. package/src/resources/extensions/gsd/tests/doctor-providers.test.ts +31 -0
  502. package/src/resources/extensions/gsd/tests/double-merge-guard.test.ts +1 -1
  503. package/src/resources/extensions/gsd/tests/ensure-db-open.test.ts +1 -1
  504. package/src/resources/extensions/gsd/tests/escalation.test.ts +1 -1
  505. package/src/resources/extensions/gsd/tests/exec-history.test.ts +113 -0
  506. package/src/resources/extensions/gsd/tests/execution-entry-missing-context-4671.test.ts +173 -0
  507. package/src/resources/extensions/gsd/tests/file-change-validator.test.ts +38 -0
  508. package/src/resources/extensions/gsd/tests/file-lock.test.ts +86 -12
  509. package/src/resources/extensions/gsd/tests/google-search-stub.test.ts +131 -0
  510. package/src/resources/extensions/gsd/tests/gsd-db.test.ts +296 -1
  511. package/src/resources/extensions/gsd/tests/headless-milestone-parity.test.ts +117 -0
  512. package/src/resources/extensions/gsd/tests/integration/auto-worktree-milestone-merge.test.ts +30 -0
  513. package/src/resources/extensions/gsd/tests/integration/git-service.test.ts +4 -2
  514. package/src/resources/extensions/gsd/tests/integration/gitignore-tracked-gsd.test.ts +1 -0
  515. package/src/resources/extensions/gsd/tests/integration/idle-recovery.test.ts +30 -0
  516. package/src/resources/extensions/gsd/tests/integration/worktree-e2e.test.ts +11 -0
  517. package/src/resources/extensions/gsd/tests/issue-4540-regressions.test.ts +288 -0
  518. package/src/resources/extensions/gsd/tests/journal-integration.test.ts +66 -0
  519. package/src/resources/extensions/gsd/tests/key-manager.test.ts +2 -0
  520. package/src/resources/extensions/gsd/tests/mcp-client-security.test.ts +76 -0
  521. package/src/resources/extensions/gsd/tests/md-importer.test.ts +1 -1
  522. package/src/resources/extensions/gsd/tests/memory-pressure-stuck-state.test.ts +12 -0
  523. package/src/resources/extensions/gsd/tests/memory-store.test.ts +2 -2
  524. package/src/resources/extensions/gsd/tests/milestone-status-authoritative.test.ts +3 -3
  525. package/src/resources/extensions/gsd/tests/milestone-summary-classifier.test.ts +30 -0
  526. package/src/resources/extensions/gsd/tests/milestone-transition-state-rebuild.test.ts +4 -2
  527. package/src/resources/extensions/gsd/tests/parallel-commit-scope.test.ts +5 -0
  528. package/src/resources/extensions/gsd/tests/parallel-research-dispatch.test.ts +19 -0
  529. package/src/resources/extensions/gsd/tests/parallel-skill-prompt-integration.test.ts +150 -0
  530. package/src/resources/extensions/gsd/tests/plan-gate-failed-doctor-heal-hint.test.ts +37 -0
  531. package/src/resources/extensions/gsd/tests/pre-exec-gate-loop.test.ts +272 -0
  532. package/src/resources/extensions/gsd/tests/pre-execution-checks.test.ts +337 -0
  533. package/src/resources/extensions/gsd/tests/prefs-wizard-coverage.test.ts +44 -0
  534. package/src/resources/extensions/gsd/tests/provider-errors.test.ts +39 -25
  535. package/src/resources/extensions/gsd/tests/queue-auto-guard.test.ts +181 -0
  536. package/src/resources/extensions/gsd/tests/quick-auto-guard.test.ts +13 -7
  537. package/src/resources/extensions/gsd/tests/ready-phrase-no-files-4573.test.ts +388 -0
  538. package/src/resources/extensions/gsd/tests/require-slice-discussion-dispatch.test.ts +170 -0
  539. package/src/resources/extensions/gsd/tests/restore-tools-after-discuss.test.ts +9 -3
  540. package/src/resources/extensions/gsd/tests/resume-dispatch-worktree.test.ts +230 -0
  541. package/src/resources/extensions/gsd/tests/rewrite-docs-abandon-detect.test.ts +195 -0
  542. package/src/resources/extensions/gsd/tests/safety-harness-false-positives.test.ts +205 -0
  543. package/src/resources/extensions/gsd/tests/schema-v21-sequence.test.ts +413 -0
  544. package/src/resources/extensions/gsd/tests/session-start-footer.test.ts +32 -40
  545. package/src/resources/extensions/gsd/tests/stale-dirlistcache-4648.test.ts +112 -0
  546. package/src/resources/extensions/gsd/tests/stash-queued-context-files.test.ts +56 -0
  547. package/src/resources/extensions/gsd/tests/state-machine-full-walkthrough.test.ts +24 -0
  548. package/src/resources/extensions/gsd/tests/state-transition-matrix.test.ts +44 -0
  549. package/src/resources/extensions/gsd/tests/stuck-detection-coverage.test.ts +2 -2
  550. package/src/resources/extensions/gsd/tests/token-counter.test.ts +105 -1
  551. package/src/resources/extensions/gsd/tests/tool-compatibility.test.ts +107 -0
  552. package/src/resources/extensions/gsd/tests/triage-resolution.test.ts +50 -2
  553. package/src/resources/extensions/gsd/tests/turn-epoch.test.ts +162 -0
  554. package/src/resources/extensions/gsd/tests/uok-contracts.test.ts +51 -0
  555. package/src/resources/extensions/gsd/tests/uok-execution-graph.test.ts +16 -0
  556. package/src/resources/extensions/gsd/tests/uok-loop-adapter-writer.test.ts +65 -0
  557. package/src/resources/extensions/gsd/tests/uok-parity-report.test.ts +42 -0
  558. package/src/resources/extensions/gsd/tests/uok-plan-v2-wiring.test.ts +42 -2
  559. package/src/resources/extensions/gsd/tests/uok-writer.test.ts +75 -0
  560. package/src/resources/extensions/gsd/tests/validate-extension-package.test.ts +168 -0
  561. package/src/resources/extensions/gsd/tests/validate-milestone.test.ts +138 -5
  562. package/src/resources/extensions/gsd/tests/workflow-mcp.test.ts +25 -2
  563. package/src/resources/extensions/gsd/tests/workflow-tool-executors.test.ts +65 -2
  564. package/src/resources/extensions/gsd/tests/worktree-db.test.ts +35 -0
  565. package/src/resources/extensions/gsd/tests/worktree-journal-events.test.ts +6 -1
  566. package/src/resources/extensions/gsd/tests/worktree-resolver.test.ts +78 -5
  567. package/src/resources/extensions/gsd/tests/write-gate.test.ts +64 -0
  568. package/src/resources/extensions/gsd/token-counter.ts +22 -5
  569. package/src/resources/extensions/gsd/tools/complete-milestone.ts +15 -9
  570. package/src/resources/extensions/gsd/tools/complete-slice.ts +38 -0
  571. package/src/resources/extensions/gsd/tools/complete-task.ts +49 -0
  572. package/src/resources/extensions/gsd/uok/audit.ts +20 -2
  573. package/src/resources/extensions/gsd/uok/contracts.ts +65 -0
  574. package/src/resources/extensions/gsd/uok/dispatch-envelope.ts +56 -0
  575. package/src/resources/extensions/gsd/uok/execution-graph.ts +22 -0
  576. package/src/resources/extensions/gsd/uok/gitops.ts +6 -1
  577. package/src/resources/extensions/gsd/uok/loop-adapter.ts +45 -10
  578. package/src/resources/extensions/gsd/uok/parity-report.ts +84 -0
  579. package/src/resources/extensions/gsd/uok/plan-v2.ts +39 -8
  580. package/src/resources/extensions/gsd/uok/writer.ts +113 -0
  581. package/src/resources/extensions/gsd/workflow-logger.ts +23 -3
  582. package/src/resources/extensions/gsd/worktree-manager.ts +1 -0
  583. package/src/resources/extensions/gsd/worktree-resolver.ts +54 -9
  584. package/src/resources/extensions/mcp-client/auth.ts +12 -1
  585. package/src/resources/extensions/mcp-client/index.ts +129 -10
  586. package/src/resources/extensions/shared/cmux-events.ts +59 -0
  587. package/src/resources/extensions/shared/rtk-session-stats.ts +1 -2
  588. package/src/resources/skills/create-skill/SKILL.md +2 -2
  589. package/src/resources/skills/create-skill/references/gsd-skill-ecosystem.md +4 -4
  590. package/src/resources/skills/create-skill/workflows/audit-skill.md +4 -4
  591. package/src/resources/skills/create-skill/workflows/create-new-skill.md +5 -5
  592. package/src/resources/skills/verify-before-complete/SKILL.md +2 -1
  593. package/src/resources/skills/write-docs/SKILL.md +2 -1
  594. package/dist/web/standalone/.next/server/chunks/7461.js +0 -1
  595. package/dist/web/standalone/.next/static/chunks/2826.e59e8578e2e28639.js +0 -9
  596. /package/dist/web/standalone/.next/static/{n21VtX2hZlkpdEUO_nU4z → vidAVJkURvTJ0_V2-64ro}/_buildManifest.js +0 -0
  597. /package/dist/web/standalone/.next/static/{n21VtX2hZlkpdEUO_nU4z → vidAVJkURvTJ0_V2-64ro}/_ssgManifest.js +0 -0
@@ -122,3 +122,116 @@ test('executeExecSearch: includes stdout_path and preview in details', () => {
122
122
  cleanup(base);
123
123
  }
124
124
  });
125
+
126
+ // ── Path traversal security tests (issue #4590) ───────────────────────────
127
+
128
+ test('safeReadMeta: ignores malicious stdout_path in JSON, derives path from meta file location', () => {
129
+ // Arrange: write a .meta.json whose JSON content has a path-traversal value
130
+ // in stdout_path / stderr_path. The read-side must silently discard these
131
+ // and derive sibling paths from the actual .meta.json location instead.
132
+ const base = freshBase();
133
+ try {
134
+ const dir = join(base, '.gsd', 'exec');
135
+ mkdirSync(dir, { recursive: true });
136
+ const id = 'traversal-test-run';
137
+ const metaPath = join(dir, `${id}.meta.json`);
138
+ const stdoutPath = join(dir, `${id}.stdout`);
139
+ const stderrPath = join(dir, `${id}.stderr`);
140
+ // Write real sibling files so digest_preview can succeed.
141
+ writeFileSync(stdoutPath, 'legitimate stdout content\n');
142
+ writeFileSync(stderrPath, '');
143
+ // Write a meta.json that tries to point stdout_path outside the exec dir.
144
+ writeFileSync(
145
+ metaPath,
146
+ JSON.stringify({
147
+ id,
148
+ runtime: 'bash',
149
+ purpose: 'test run',
150
+ started_at: '2026-04-20T12:00:00.000Z',
151
+ finished_at: '2026-04-20T12:00:00.100Z',
152
+ duration_ms: 100,
153
+ exit_code: 0,
154
+ signal: null,
155
+ timed_out: false,
156
+ stdout_bytes: 24,
157
+ stderr_bytes: 0,
158
+ stdout_truncated: false,
159
+ stderr_truncated: false,
160
+ // These malicious values must NEVER be used as filesystem paths.
161
+ stdout_path: '../../etc/passwd',
162
+ stderr_path: '../../etc/shadow',
163
+ }),
164
+ );
165
+
166
+ const entries = listExecHistory(base);
167
+ assert.equal(entries.length, 1);
168
+ const entry = entries[0]!;
169
+
170
+ // stdout_path must be derived from the meta file location, not from JSON.
171
+ assert.equal(entry.stdout_path, stdoutPath,
172
+ `stdout_path must be a sibling of the meta file; got: ${entry.stdout_path}`);
173
+ assert.equal(entry.stderr_path, stderrPath,
174
+ `stderr_path must be a sibling of the meta file; got: ${entry.stderr_path}`);
175
+
176
+ // Verify neither traversal string leaked into the returned entry.
177
+ assert.ok(!entry.stdout_path.includes('..'),
178
+ `stdout_path must not contain path traversal sequences: ${entry.stdout_path}`);
179
+ assert.ok(!entry.stderr_path.includes('..'),
180
+ `stderr_path must not contain path traversal sequences: ${entry.stderr_path}`);
181
+ assert.ok(!entry.stdout_path.includes('etc/passwd'),
182
+ `stdout_path must not point to /etc/passwd: ${entry.stdout_path}`);
183
+ } finally {
184
+ cleanup(base);
185
+ }
186
+ });
187
+
188
+ test('searchExecHistory: digest_preview is read from derived sibling path, not JSON stdout_path', () => {
189
+ // Arrange: a .meta.json with a malicious stdout_path pointing to /etc/passwd.
190
+ // The digest_preview should be read from the real sibling .stdout file,
191
+ // not from the JSON-supplied path.
192
+ const base = freshBase();
193
+ try {
194
+ const dir = join(base, '.gsd', 'exec');
195
+ mkdirSync(dir, { recursive: true });
196
+ const id = 'preview-traversal-run';
197
+ const metaPath = join(dir, `${id}.meta.json`);
198
+ const stdoutPath = join(dir, `${id}.stdout`);
199
+ writeFileSync(stdoutPath, 'safe-sentinel-content\n');
200
+ writeFileSync(join(dir, `${id}.stderr`), '');
201
+ writeFileSync(
202
+ metaPath,
203
+ JSON.stringify({
204
+ id,
205
+ runtime: 'bash',
206
+ purpose: null,
207
+ started_at: '2026-04-20T12:00:00.000Z',
208
+ finished_at: '2026-04-20T12:00:00.100Z',
209
+ duration_ms: 50,
210
+ exit_code: 0,
211
+ signal: null,
212
+ timed_out: false,
213
+ stdout_bytes: 21,
214
+ stderr_bytes: 0,
215
+ stdout_truncated: false,
216
+ stderr_truncated: false,
217
+ // Attacker-controlled path — must be ignored.
218
+ stdout_path: '/etc/passwd',
219
+ stderr_path: '/etc/shadow',
220
+ }),
221
+ );
222
+
223
+ const hits = searchExecHistory(base, {});
224
+ assert.equal(hits.length, 1);
225
+ const hit = hits[0]!;
226
+
227
+ // The preview must come from the safe sibling, not /etc/passwd.
228
+ assert.ok(
229
+ hit.digest_preview?.includes('safe-sentinel-content'),
230
+ `digest_preview should contain safe-sentinel-content; got: ${hit.digest_preview}`,
231
+ );
232
+ // Ensure the entry paths are the derived ones.
233
+ assert.equal(hit.entry.stdout_path, stdoutPath);
234
+ } finally {
235
+ cleanup(base);
236
+ }
237
+ });
@@ -0,0 +1,173 @@
1
+ /**
2
+ * Regression tests for #4671 — execution-entry phase + missing CONTEXT.md.
3
+ *
4
+ * When a milestone advances to an execution-entry phase (executing /
5
+ * summarizing / validating-milestone / completing-milestone) without
6
+ * `CONTEXT.md` on disk, the `pre-planning (no context) → discuss-milestone`
7
+ * rule no longer fires and the plan-v2 gate only blocks. This rule provides
8
+ * the recovery by redispatching to discuss-milestone.
9
+ *
10
+ * Exercises the dispatch rule from DISPATCH_RULES directly with a
11
+ * DispatchContext built against a real temp directory.
12
+ */
13
+ import { test, describe } from "node:test";
14
+ import assert from "node:assert/strict";
15
+ import { mkdtempSync, mkdirSync, writeFileSync, rmSync } from "node:fs";
16
+ import { join } from "node:path";
17
+ import { tmpdir } from "node:os";
18
+ import { DISPATCH_RULES, type DispatchContext } from "../auto-dispatch.ts";
19
+ import type { GSDState, Phase } from "../types.ts";
20
+
21
+ const RULE_NAME_TOKEN = "execution-entry phase (no context)";
22
+
23
+ function findRule() {
24
+ const matches = DISPATCH_RULES.filter((r) => r.name.includes(RULE_NAME_TOKEN));
25
+ if (matches.length !== 1) {
26
+ throw new Error(
27
+ `expected exactly one dispatch rule containing "${RULE_NAME_TOKEN}", found ${matches.length}`,
28
+ );
29
+ }
30
+ return matches[0];
31
+ }
32
+
33
+ function buildState(phase: Phase): GSDState {
34
+ return {
35
+ activeMilestone: { id: "M001", title: "Test milestone" },
36
+ activeSlice: null,
37
+ activeTask: null,
38
+ phase,
39
+ recentDecisions: [],
40
+ blockers: [],
41
+ nextAction: "",
42
+ registry: [],
43
+ };
44
+ }
45
+
46
+ function makeBasePath(prefix: string): string {
47
+ const dir = mkdtempSync(join(tmpdir(), `gsd-4671-${prefix}-`));
48
+ mkdirSync(join(dir, ".gsd", "milestones", "M001"), { recursive: true });
49
+ return dir;
50
+ }
51
+
52
+ function buildCtx(basePath: string, state: GSDState): DispatchContext {
53
+ return {
54
+ basePath,
55
+ mid: "M001",
56
+ midTitle: "Test milestone",
57
+ state,
58
+ prefs: undefined,
59
+ };
60
+ }
61
+
62
+ describe("#4671 execution-entry phase missing-context recovery", () => {
63
+ const executionEntryPhases: Phase[] = [
64
+ "executing",
65
+ "summarizing",
66
+ "validating-milestone",
67
+ "completing-milestone",
68
+ ];
69
+
70
+ for (const phase of executionEntryPhases) {
71
+ test(`phase=${phase} with missing CONTEXT.md → dispatches discuss-milestone`, async () => {
72
+ const basePath = makeBasePath(`missing-${phase}`);
73
+ try {
74
+ const action = await findRule().match(buildCtx(basePath, buildState(phase)));
75
+ assert.ok(action, "rule must return an action when CONTEXT.md is missing");
76
+ assert.strictEqual(action!.action, "dispatch");
77
+ if (action!.action === "dispatch") {
78
+ assert.strictEqual(action!.unitType, "discuss-milestone");
79
+ assert.strictEqual(action!.unitId, "M001");
80
+ assert.ok(typeof action!.prompt === "string" && action!.prompt.length > 0);
81
+ }
82
+ } finally {
83
+ rmSync(basePath, { recursive: true, force: true });
84
+ }
85
+ });
86
+ }
87
+
88
+ test("phase=executing with CONTEXT.md present → falls through", async () => {
89
+ const basePath = makeBasePath("has-context");
90
+ try {
91
+ writeFileSync(
92
+ join(basePath, ".gsd", "milestones", "M001", "M001-CONTEXT.md"),
93
+ "# M001 Context\n\nSome real context.\n",
94
+ );
95
+ const action = await findRule().match(buildCtx(basePath, buildState("executing")));
96
+ assert.strictEqual(action, null, "rule must fall through when CONTEXT.md exists");
97
+ } finally {
98
+ rmSync(basePath, { recursive: true, force: true });
99
+ }
100
+ });
101
+
102
+ test("phase=executing accepts finalized CONTEXT.md from GSD_PROJECT_ROOT fallback", async () => {
103
+ const projectRoot = makeBasePath("project-root-context");
104
+ const worktreeBase = makeBasePath("worktree-context");
105
+ const prevProjectRoot = process.env.GSD_PROJECT_ROOT;
106
+ try {
107
+ writeFileSync(
108
+ join(projectRoot, ".gsd", "milestones", "M001", "M001-CONTEXT.md"),
109
+ "# M001 Context\n\nFinalized context at project root.\n",
110
+ );
111
+ process.env.GSD_PROJECT_ROOT = projectRoot;
112
+
113
+ const action = await findRule().match(buildCtx(worktreeBase, buildState("executing")));
114
+ assert.strictEqual(
115
+ action,
116
+ null,
117
+ "rule must align with plan-v2 project-root fallback before redispatching",
118
+ );
119
+ } finally {
120
+ if (prevProjectRoot === undefined) {
121
+ delete process.env.GSD_PROJECT_ROOT;
122
+ } else {
123
+ process.env.GSD_PROJECT_ROOT = prevProjectRoot;
124
+ }
125
+ rmSync(projectRoot, { recursive: true, force: true });
126
+ rmSync(worktreeBase, { recursive: true, force: true });
127
+ }
128
+ });
129
+
130
+ test("phase=pre-planning does not trigger this rule (handled by upstream rule)", async () => {
131
+ const basePath = makeBasePath("pre-planning");
132
+ try {
133
+ const action = await findRule().match(buildCtx(basePath, buildState("pre-planning")));
134
+ assert.strictEqual(
135
+ action,
136
+ null,
137
+ "rule must only target execution-entry phases; pre-planning is handled elsewhere",
138
+ );
139
+ } finally {
140
+ rmSync(basePath, { recursive: true, force: true });
141
+ }
142
+ });
143
+
144
+ test("empty CONTEXT.md (whitespace only) → rule still fires", async () => {
145
+ const basePath = makeBasePath("empty-context");
146
+ try {
147
+ writeFileSync(
148
+ join(basePath, ".gsd", "milestones", "M001", "M001-CONTEXT.md"),
149
+ " \n\t\n",
150
+ );
151
+ const action = await findRule().match(buildCtx(basePath, buildState("summarizing")));
152
+ assert.ok(action, "rule must fire when CONTEXT.md is empty/whitespace-only");
153
+ if (action?.action === "dispatch") {
154
+ assert.strictEqual(action.unitType, "discuss-milestone");
155
+ }
156
+ } finally {
157
+ rmSync(basePath, { recursive: true, force: true });
158
+ }
159
+ });
160
+
161
+ test("rule ordering: fires BEFORE execution-entry phase handlers", () => {
162
+ const recoveryIdx = DISPATCH_RULES.findIndex((r) => r.name.includes(RULE_NAME_TOKEN));
163
+ const summarizingIdx = DISPATCH_RULES.findIndex((r) =>
164
+ r.name.startsWith("summarizing → complete-slice"),
165
+ );
166
+ assert.ok(recoveryIdx > -1, "recovery rule must exist");
167
+ assert.ok(summarizingIdx > -1, "summarizing rule must exist");
168
+ assert.ok(
169
+ recoveryIdx < summarizingIdx,
170
+ `recovery rule (idx ${recoveryIdx}) must come before summarizing rule (idx ${summarizingIdx}) so it can redispatch before the plan-v2 gate blocks`,
171
+ );
172
+ });
173
+ });
@@ -35,6 +35,44 @@ test("validateFileChanges works on repos with a single commit (no HEAD~1)", (t)
35
35
  assert.deepEqual(audit.missingFiles, []);
36
36
  });
37
37
 
38
+ test("validateFileChanges excludes allowlisted files from unexpected-change warnings", (t) => {
39
+ const base = mkdtempSync(join(tmpdir(), "gsd-file-change-validator-"));
40
+ t.after(() => rmSync(base, { recursive: true, force: true }));
41
+
42
+ mkdirSync(join(base, "tracking", "history"), { recursive: true });
43
+ git(base, "init");
44
+ git(base, "config", "user.email", "test@example.com");
45
+ git(base, "config", "user.name", "Test User");
46
+
47
+ writeFileSync(join(base, "src.ts"), "initial\n");
48
+ writeFileSync(join(base, "tracking", "history", "2026-04-20-snapshot.md"), "initial\n");
49
+ git(base, "add", ".");
50
+ git(base, "commit", "-m", "initial");
51
+
52
+ writeFileSync(join(base, "src.ts"), "updated\n");
53
+ writeFileSync(join(base, "tracking", "history", "2026-04-20-snapshot.md"), "updated\n");
54
+ git(base, "add", ".");
55
+ git(base, "commit", "-m", "update");
56
+
57
+ // Without allowlist: tracking/history snapshot is unexpected
58
+ const auditWithout = validateFileChanges(base, ["src.ts"], []);
59
+ assert.ok(auditWithout, "audit should be produced");
60
+ assert.ok(
61
+ auditWithout.unexpectedFiles.includes("tracking/history/2026-04-20-snapshot.md"),
62
+ "snapshot should be unexpected without allowlist",
63
+ );
64
+
65
+ // With glob allowlist: snapshot is excluded
66
+ const auditWith = validateFileChanges(base, ["src.ts"], [], ["tracking/history/**"]);
67
+ assert.ok(auditWith, "audit should be produced with allowlist");
68
+ assert.deepEqual(auditWith.unexpectedFiles, [], "no unexpected files when snapshot is allowlisted");
69
+ assert.equal(
70
+ auditWith.violations.filter(v => v.severity === "warning").length,
71
+ 0,
72
+ "no warnings when all unexpected files are allowlisted",
73
+ );
74
+ });
75
+
38
76
  test("validateFileChanges ignores inline descriptions in expected output paths", (t) => {
39
77
  const base = mkdtempSync(join(tmpdir(), "gsd-file-change-validator-"));
40
78
  t.after(() => rmSync(base, { recursive: true, force: true }));
@@ -52,7 +52,7 @@ test("withFileLock: executes callback when file does not exist", async () => {
52
52
  }
53
53
  });
54
54
 
55
- test("withFileLockSync: falls back to unlocked callback on ELOCKED", () => {
55
+ test("withFileLockSync: throws ELOCKED by default (no silent fallback)", () => {
56
56
  if (!hasProperLockfile() || process.platform === "win32") {
57
57
  return;
58
58
  }
@@ -65,19 +65,56 @@ test("withFileLockSync: falls back to unlocked callback on ELOCKED", () => {
65
65
  const release = lockfile.lockSync(filePath, { retries: 0, stale: 10000 });
66
66
  try {
67
67
  let called = 0;
68
- const result = withFileLockSync(filePath, () => {
69
- called++;
70
- return "fallback-ok";
71
- });
68
+ assert.throws(
69
+ () => {
70
+ withFileLockSync(
71
+ filePath,
72
+ () => {
73
+ called++;
74
+ return "should-not-return";
75
+ },
76
+ { retries: 0 },
77
+ );
78
+ },
79
+ (err: any) => err?.code === "ELOCKED",
80
+ );
81
+ assert.equal(called, 0, "callback must not run when lock cannot be acquired");
82
+ } finally {
83
+ release();
84
+ rmSync(dir, { recursive: true, force: true });
85
+ }
86
+ });
87
+
88
+ test("withFileLockSync: onLocked=\"skip\" runs callback unlocked on ELOCKED", () => {
89
+ if (!hasProperLockfile() || process.platform === "win32") {
90
+ return;
91
+ }
92
+
93
+ const lockfile = require("proper-lockfile");
94
+ const dir = mkdtempSync(join(tmpdir(), "gsd-file-lock-test-"));
95
+ const filePath = join(dir, "locked.jsonl");
96
+ writeFileSync(filePath, "{}\n", "utf-8");
97
+
98
+ const release = lockfile.lockSync(filePath, { retries: 0, stale: 10000 });
99
+ try {
100
+ let called = 0;
101
+ const result = withFileLockSync(
102
+ filePath,
103
+ () => {
104
+ called++;
105
+ return "fallback-ok";
106
+ },
107
+ { retries: 0, onLocked: "skip" },
108
+ );
72
109
  assert.equal(result, "fallback-ok");
73
- assert.equal(called, 1, "callback should run even when lock acquisition fails");
110
+ assert.equal(called, 1, "callback should run when onLocked is skip");
74
111
  } finally {
75
112
  release();
76
113
  rmSync(dir, { recursive: true, force: true });
77
114
  }
78
115
  });
79
116
 
80
- test("withFileLock: falls back to unlocked callback on ELOCKED", async () => {
117
+ test("withFileLock: throws ELOCKED by default (no silent fallback)", async () => {
81
118
  if (!hasProperLockfile() || process.platform === "win32") {
82
119
  return;
83
120
  }
@@ -90,12 +127,49 @@ test("withFileLock: falls back to unlocked callback on ELOCKED", async () => {
90
127
  const release = await lockfile.lock(filePath, { retries: 0, stale: 10000 });
91
128
  try {
92
129
  let called = 0;
93
- const result = await withFileLock(filePath, async () => {
94
- called++;
95
- return "fallback-ok";
96
- });
130
+ await assert.rejects(
131
+ async () => {
132
+ await withFileLock(
133
+ filePath,
134
+ async () => {
135
+ called++;
136
+ return "should-not-return";
137
+ },
138
+ { retries: 0 },
139
+ );
140
+ },
141
+ (err: any) => err?.code === "ELOCKED",
142
+ );
143
+ assert.equal(called, 0, "callback must not run when lock cannot be acquired");
144
+ } finally {
145
+ await release();
146
+ rmSync(dir, { recursive: true, force: true });
147
+ }
148
+ });
149
+
150
+ test("withFileLock: onLocked=\"skip\" runs callback unlocked on ELOCKED", async () => {
151
+ if (!hasProperLockfile() || process.platform === "win32") {
152
+ return;
153
+ }
154
+
155
+ const lockfile = require("proper-lockfile");
156
+ const dir = mkdtempSync(join(tmpdir(), "gsd-file-lock-test-"));
157
+ const filePath = join(dir, "locked.jsonl");
158
+ writeFileSync(filePath, "{}\n", "utf-8");
159
+
160
+ const release = await lockfile.lock(filePath, { retries: 0, stale: 10000 });
161
+ try {
162
+ let called = 0;
163
+ const result = await withFileLock(
164
+ filePath,
165
+ async () => {
166
+ called++;
167
+ return "fallback-ok";
168
+ },
169
+ { retries: 0, onLocked: "skip" },
170
+ );
97
171
  assert.equal(result, "fallback-ok");
98
- assert.equal(called, 1, "callback should run even when lock acquisition fails");
172
+ assert.equal(called, 1, "callback should run when onLocked is skip");
99
173
  } finally {
100
174
  await release();
101
175
  rmSync(dir, { recursive: true, force: true });
@@ -0,0 +1,131 @@
1
+ // GSD-2 — Tests for google-search deprecation stub (STUB-01, STUB-02)
2
+ import test from "node:test";
3
+ import assert from "node:assert/strict";
4
+
5
+ // ─── Tests ────────────────────────────────────────────────────────────────────
6
+
7
+ test("google-search stub: default export is a function", async (_t) => {
8
+ // STUB-01: stub has a default export function accepting ExtensionAPI
9
+ const mod = await import("../../google-search/index.ts");
10
+ const stubFn = mod.default;
11
+ assert.equal(typeof stubFn, "function");
12
+ });
13
+
14
+ test("google-search stub: registers session_start handler", async (_t) => {
15
+ // STUB-01: stub calls pi.on("session_start", ...)
16
+ const mod = await import("../../google-search/index.ts");
17
+ const stubFn = mod.default;
18
+
19
+ let capturedEvent: string | undefined;
20
+ let capturedHandler: unknown;
21
+
22
+ const mockPi = {
23
+ on(event: string, handler: unknown) {
24
+ capturedEvent = event;
25
+ capturedHandler = handler;
26
+ },
27
+ registerTool: () => {},
28
+ };
29
+
30
+ stubFn(mockPi as never);
31
+
32
+ assert.equal(capturedEvent, "session_start");
33
+ assert.equal(typeof capturedHandler, "function");
34
+ });
35
+
36
+ test("google-search stub: does NOT call registerTool", async (_t) => {
37
+ // STUB-02: stub is a no-op for tools
38
+ const mod = await import("../../google-search/index.ts");
39
+ const stubFn = mod.default;
40
+
41
+ let registerToolCalled = false;
42
+
43
+ const mockPi = {
44
+ on: (_event: string, _handler: unknown) => {},
45
+ registerTool: () => { registerToolCalled = true; },
46
+ };
47
+
48
+ stubFn(mockPi as never);
49
+
50
+ assert.equal(registerToolCalled, false);
51
+ });
52
+
53
+ test("google-search stub: session_start warning contains package name", async (_t) => {
54
+ // STUB-01: warning includes @gsd-extensions/google-search
55
+ const mod = await import("../../google-search/index.ts");
56
+ const stubFn = mod.default;
57
+
58
+ let capturedHandler: ((event: unknown, ctx: unknown) => Promise<void>) | undefined;
59
+
60
+ const mockPi = {
61
+ on(_event: string, handler: (event: unknown, ctx: unknown) => Promise<void>) {
62
+ capturedHandler = handler;
63
+ },
64
+ registerTool: () => {},
65
+ };
66
+
67
+ stubFn(mockPi as never);
68
+
69
+ assert.ok(capturedHandler, "session_start handler should have been registered");
70
+
71
+ let capturedMessage: string | undefined;
72
+ const mockCtx = {
73
+ ui: {
74
+ notify(message: string, _level: string) {
75
+ capturedMessage = message;
76
+ },
77
+ },
78
+ };
79
+
80
+ await capturedHandler!({}, mockCtx);
81
+
82
+ assert.ok(
83
+ capturedMessage?.includes("@gsd-extensions/google-search"),
84
+ `Expected message to include "@gsd-extensions/google-search", got: "${capturedMessage}"`,
85
+ );
86
+ });
87
+
88
+ test("google-search stub: session_start warning explains package is not yet published", async (_t) => {
89
+ // STUB-01: stub must NOT advise `gsd extensions install` — the replacement
90
+ // package is not yet on npm, so that command would 404. The message must
91
+ // explain the extraction is in progress and no user action is required.
92
+ const mod = await import("../../google-search/index.ts");
93
+ const stubFn = mod.default;
94
+
95
+ let capturedHandler: ((event: unknown, ctx: unknown) => Promise<void>) | undefined;
96
+
97
+ const mockPi = {
98
+ on(_event: string, handler: (event: unknown, ctx: unknown) => Promise<void>) {
99
+ capturedHandler = handler;
100
+ },
101
+ registerTool: () => {},
102
+ };
103
+
104
+ stubFn(mockPi as never);
105
+
106
+ assert.ok(capturedHandler, "session_start handler should have been registered");
107
+
108
+ let capturedMessage: string | undefined;
109
+ const mockCtx = {
110
+ ui: {
111
+ notify(message: string, _level: string) {
112
+ capturedMessage = message;
113
+ },
114
+ },
115
+ };
116
+
117
+ await capturedHandler!({}, mockCtx);
118
+
119
+ assert.ok(
120
+ !capturedMessage?.includes("gsd extensions install"),
121
+ `Expected message NOT to include unpublished install command, got: "${capturedMessage}"`,
122
+ );
123
+ assert.ok(
124
+ capturedMessage?.includes("not yet published"),
125
+ `Expected message to include "not yet published", got: "${capturedMessage}"`,
126
+ );
127
+ assert.ok(
128
+ capturedMessage?.includes("No action needed"),
129
+ `Expected message to include "No action needed", got: "${capturedMessage}"`,
130
+ );
131
+ });