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
@@ -7,13 +7,17 @@ import { isDbAvailable, getMilestoneSlices, getSliceTasks, type SliceRow } from
7
7
  import type { UokGraphNode } from "./contracts.js";
8
8
 
9
9
  const PLAN_V2_CLARIFY_ROUND_LIMIT = 3;
10
- const EXECUTION_ENTRY_PHASES: ReadonlySet<Phase> = new Set([
10
+ export const EXECUTION_ENTRY_PHASES: ReadonlySet<Phase> = new Set([
11
11
  "executing",
12
12
  "summarizing",
13
13
  "validating-milestone",
14
14
  "completing-milestone",
15
15
  ]);
16
16
 
17
+ export function isExecutionEntryPhase(phase: Phase): boolean {
18
+ return EXECUTION_ENTRY_PHASES.has(phase);
19
+ }
20
+
17
21
  export interface PlanV2CompileResult {
18
22
  ok: boolean;
19
23
  reason?: string;
@@ -38,6 +42,37 @@ function hasFileContent(path: string | null): boolean {
38
42
  }
39
43
  }
40
44
 
45
+ function getArtifactLookupBases(basePath: string): string[] {
46
+ const bases = [basePath];
47
+ const projectRoot = process.env.GSD_PROJECT_ROOT;
48
+ if (projectRoot && projectRoot.trim().length > 0 && projectRoot !== basePath) {
49
+ bases.push(projectRoot);
50
+ }
51
+ return bases;
52
+ }
53
+
54
+ function hasMilestoneFileContent(
55
+ basePath: string,
56
+ milestoneId: string,
57
+ suffix: string,
58
+ ): boolean {
59
+ const bases = getArtifactLookupBases(basePath);
60
+ for (const candidateBase of bases) {
61
+ if (hasFileContent(resolveMilestoneFile(candidateBase, milestoneId, suffix))) {
62
+ return true;
63
+ }
64
+ }
65
+ return false;
66
+ }
67
+
68
+ export function hasFinalizedMilestoneContext(basePath: string, milestoneId: string): boolean {
69
+ return hasMilestoneFileContent(basePath, milestoneId, "CONTEXT");
70
+ }
71
+
72
+ export function isMissingFinalizedContextResult(result: PlanV2CompileResult): boolean {
73
+ return !result.ok && result.finalizedContextIncluded === false;
74
+ }
75
+
41
76
  function countSliceResearchArtifacts(basePath: string, milestoneId: string, slices: SliceRow[]): number {
42
77
  let count = 0;
43
78
  for (const slice of slices) {
@@ -48,10 +83,6 @@ function countSliceResearchArtifacts(basePath: string, milestoneId: string, slic
48
83
  return count;
49
84
  }
50
85
 
51
- function isExecutionEntryPhase(phase: Phase): boolean {
52
- return EXECUTION_ENTRY_PHASES.has(phase);
53
- }
54
-
55
86
  export function compileUnitGraphFromState(basePath: string, state: GSDState): PlanV2CompileResult {
56
87
  const mid = state.activeMilestone?.id;
57
88
  if (!mid) return { ok: false, reason: "no active milestone" };
@@ -60,9 +91,9 @@ export function compileUnitGraphFromState(basePath: string, state: GSDState): Pl
60
91
  const slices = getMilestoneSlices(mid).sort((a, b) => Number(a.sequence ?? 0) - Number(b.sequence ?? 0));
61
92
  const nodes: UokGraphNode[] = [];
62
93
  const clarifyRoundLimit = PLAN_V2_CLARIFY_ROUND_LIMIT;
63
- const draftContextIncluded = hasFileContent(resolveMilestoneFile(basePath, mid, "CONTEXT-DRAFT"));
64
- const finalizedContextIncluded = hasFileContent(resolveMilestoneFile(basePath, mid, "CONTEXT"));
65
- const researchSynthesized = hasFileContent(resolveMilestoneFile(basePath, mid, "RESEARCH"))
94
+ const draftContextIncluded = hasMilestoneFileContent(basePath, mid, "CONTEXT-DRAFT");
95
+ const finalizedContextIncluded = hasMilestoneFileContent(basePath, mid, "CONTEXT");
96
+ const researchSynthesized = hasMilestoneFileContent(basePath, mid, "RESEARCH")
66
97
  || countSliceResearchArtifacts(basePath, mid, slices) > 0;
67
98
 
68
99
  if (isExecutionEntryPhase(state.phase) && !finalizedContextIncluded) {
@@ -0,0 +1,113 @@
1
+ import { existsSync, readFileSync } from "node:fs";
2
+ import { join } from "node:path";
3
+ import { randomUUID } from "node:crypto";
4
+
5
+ import { atomicWriteSync } from "../atomic-write.js";
6
+ import { gsdRoot } from "../paths.js";
7
+ import type { WriteRecord, WriterToken } from "./contracts.js";
8
+
9
+ interface SequenceState {
10
+ lastSequence: number;
11
+ updatedAt: string;
12
+ }
13
+
14
+ const activeTokens = new Map<string, WriterToken>();
15
+
16
+ function tokenKey(basePath: string, turnId: string): string {
17
+ return `${basePath}:${turnId}`;
18
+ }
19
+
20
+ function sequencePath(basePath: string): string {
21
+ return join(gsdRoot(basePath), "runtime", "uok-writer-sequence.json");
22
+ }
23
+
24
+ function readSequenceState(basePath: string): SequenceState {
25
+ const path = sequencePath(basePath);
26
+ if (!existsSync(path)) {
27
+ return { lastSequence: 0, updatedAt: new Date(0).toISOString() };
28
+ }
29
+ try {
30
+ const parsed = JSON.parse(readFileSync(path, "utf-8")) as Partial<SequenceState>;
31
+ return {
32
+ lastSequence: Number.isInteger(parsed.lastSequence) ? Number(parsed.lastSequence) : 0,
33
+ updatedAt: typeof parsed.updatedAt === "string" ? parsed.updatedAt : new Date(0).toISOString(),
34
+ };
35
+ } catch {
36
+ return { lastSequence: 0, updatedAt: new Date(0).toISOString() };
37
+ }
38
+ }
39
+
40
+ function writeSequenceState(basePath: string, state: SequenceState): void {
41
+ atomicWriteSync(sequencePath(basePath), JSON.stringify(state, null, 2) + "\n", "utf-8");
42
+ }
43
+
44
+ export function acquireWriterToken(args: {
45
+ basePath: string;
46
+ traceId: string;
47
+ turnId: string;
48
+ owner?: WriterToken["owner"];
49
+ }): WriterToken {
50
+ const key = tokenKey(args.basePath, args.turnId);
51
+ const existing = activeTokens.get(key);
52
+ if (existing) {
53
+ throw new Error(`Writer token already active for turn ${args.turnId}`);
54
+ }
55
+
56
+ const token: WriterToken = {
57
+ tokenId: randomUUID(),
58
+ traceId: args.traceId,
59
+ turnId: args.turnId,
60
+ acquiredAt: new Date().toISOString(),
61
+ owner: args.owner ?? "uok",
62
+ };
63
+ activeTokens.set(key, token);
64
+ return token;
65
+ }
66
+
67
+ export function releaseWriterToken(basePath: string, token: WriterToken): void {
68
+ const key = tokenKey(basePath, token.turnId);
69
+ const current = activeTokens.get(key);
70
+ if (current?.tokenId === token.tokenId) {
71
+ activeTokens.delete(key);
72
+ }
73
+ }
74
+
75
+ export function hasActiveWriterToken(basePath: string, turnId: string): boolean {
76
+ return activeTokens.has(tokenKey(basePath, turnId));
77
+ }
78
+
79
+ export function nextWriteRecord(args: {
80
+ basePath: string;
81
+ token: WriterToken;
82
+ category: WriteRecord["category"];
83
+ operation: WriteRecord["operation"];
84
+ path?: string;
85
+ metadata?: Record<string, unknown>;
86
+ }): WriteRecord {
87
+ if (!hasActiveWriterToken(args.basePath, args.token.turnId)) {
88
+ throw new Error(`Writer token is not active for turn ${args.token.turnId}`);
89
+ }
90
+
91
+ const state = readSequenceState(args.basePath);
92
+ const sequence = state.lastSequence + 1;
93
+ const updatedAt = new Date().toISOString();
94
+ writeSequenceState(args.basePath, { lastSequence: sequence, updatedAt });
95
+
96
+ return {
97
+ writerToken: args.token,
98
+ sequence: {
99
+ traceId: args.token.traceId,
100
+ turnId: args.token.turnId,
101
+ sequence,
102
+ },
103
+ category: args.category,
104
+ operation: args.operation,
105
+ path: args.path,
106
+ ts: updatedAt,
107
+ metadata: args.metadata,
108
+ };
109
+ }
110
+
111
+ export function resetWriterTokensForTests(): void {
112
+ activeTokens.clear();
113
+ }
@@ -16,9 +16,17 @@
16
16
  // the start of each unit to prevent log bleed between units running in the same
17
17
  // Node process.
18
18
 
19
- import { appendFileSync, readFileSync, existsSync, mkdirSync } from "node:fs";
19
+ import {
20
+ appendFileSync,
21
+ closeSync,
22
+ existsSync,
23
+ mkdirSync,
24
+ openSync,
25
+ readFileSync,
26
+ } from "node:fs";
20
27
  import { join } from "node:path";
21
28
 
29
+ import { withFileLockSync } from "./file-lock.js";
22
30
  import { appendNotification } from "./notification-store.js";
23
31
  import { buildAuditEnvelope, emitUokAuditEvent } from "./uok/audit.js";
24
32
  import { isUnifiedAuditEnabled } from "./uok/audit-toggle.js";
@@ -58,7 +66,9 @@ export type LogComponent =
58
66
  | "memory-embeddings" // Memory layer embedding generation
59
67
  | "memory-ingest" // Memory layer ingestion pipeline
60
68
  | "memory-backfill" // ADR-013: decisions->memories backfill
61
- | "context-mode"; // Context-mode exec sandbox and compaction snapshot
69
+ | "context-mode" // Context-mode exec sandbox and compaction snapshot
70
+ | "preflight" // Clean-root preflight gate at milestone completion
71
+ | "postUnit"; // Post-unit processing (abandon detection, overrides)
62
72
 
63
73
  export interface LogEntry {
64
74
  ts: string;
@@ -312,8 +322,18 @@ function _push(
312
322
  try {
313
323
  const auditDir = join(_auditBasePath, ".gsd");
314
324
  mkdirSync(auditDir, { recursive: true });
325
+ const auditPath = join(auditDir, "audit-log.jsonl");
315
326
  const sanitized = _sanitizeForAudit(entry);
316
- appendFileSync(join(auditDir, "audit-log.jsonl"), JSON.stringify(sanitized) + "\n", "utf-8");
327
+ // Ensure file exists so proper-lockfile can acquire a lock against it.
328
+ if (!existsSync(auditPath)) closeSync(openSync(auditPath, "a"));
329
+ // onLocked: "skip" — never block error logging on lock contention.
330
+ withFileLockSync(
331
+ auditPath,
332
+ () => {
333
+ appendFileSync(auditPath, JSON.stringify(sanitized) + "\n", "utf-8");
334
+ },
335
+ { onLocked: "skip" },
336
+ );
317
337
  } catch (auditErr) {
318
338
  // Best-effort — never let audit write failures bubble up
319
339
  _writeStderr(`[gsd:audit] failed to persist log entry: ${(auditErr as Error).message}\n`);
@@ -559,6 +559,7 @@ const SKIP_PATHS = [
559
559
  ".gsd/worktrees/",
560
560
  ".gsd/runtime/",
561
561
  ".gsd/activity/",
562
+ ".gsd/audit/",
562
563
  ".gsd/forensics/",
563
564
  ".gsd/parallel/",
564
565
  ".gsd/journal/",
@@ -79,6 +79,35 @@ export interface NotifyCtx {
79
79
  ) => void;
80
80
  }
81
81
 
82
+ // ─── Path Helpers ──────────────────────────────────────────────────────────
83
+
84
+ /**
85
+ * Worktree marker segment — present in any path produced by worktreePath().
86
+ * Used to strip the worktree suffix and recover the project root (#3729).
87
+ */
88
+ const WORKTREE_MARKER = "/.gsd/worktrees/";
89
+
90
+ /**
91
+ * Resolve the project root from session path state.
92
+ *
93
+ * Prefers `originalBasePath` (always the project root when set), but falls
94
+ * back to `basePath` when `originalBasePath` is falsy (e.g. fresh AutoSession
95
+ * with default empty string). If `basePath` itself is inside a worktree
96
+ * directory (contains `/.gsd/worktrees/`), strip that suffix to recover the
97
+ * actual project root — preventing double-nested worktree paths (#3729).
98
+ */
99
+ export function resolveProjectRoot(
100
+ originalBasePath: string,
101
+ basePath: string,
102
+ ): string {
103
+ let resolved = originalBasePath || basePath;
104
+ const markerIdx = resolved.indexOf(WORKTREE_MARKER);
105
+ if (markerIdx !== -1) {
106
+ resolved = resolved.slice(0, markerIdx);
107
+ }
108
+ return resolved;
109
+ }
110
+
82
111
  // ─── WorktreeResolver ──────────────────────────────────────────────────────
83
112
 
84
113
  export class WorktreeResolver {
@@ -99,12 +128,12 @@ export class WorktreeResolver {
99
128
 
100
129
  /** Original project root — always the non-worktree path. */
101
130
  get projectRoot(): string {
102
- return this.s.originalBasePath || this.s.basePath;
131
+ return resolveProjectRoot(this.s.originalBasePath, this.s.basePath);
103
132
  }
104
133
 
105
134
  /** Path for auto.lock file — same as the old lockBase(). */
106
135
  get lockPath(): string {
107
- return this.s.originalBasePath || this.s.basePath;
136
+ return resolveProjectRoot(this.s.originalBasePath, this.s.basePath);
108
137
  }
109
138
 
110
139
  // ── Private Helpers ────────────────────────────────────────────────────
@@ -182,7 +211,10 @@ export class WorktreeResolver {
182
211
  return;
183
212
  }
184
213
 
185
- const basePath = this.s.originalBasePath || this.s.basePath;
214
+ // Resolve the project root for worktree operations via shared helper.
215
+ // Handles the case where originalBasePath is falsy and basePath is itself
216
+ // a worktree path — prevents double-nested worktree paths (#3729).
217
+ const basePath = resolveProjectRoot(this.s.originalBasePath, this.s.basePath);
186
218
  debugLog("WorktreeResolver", {
187
219
  action: "enterMilestone",
188
220
  milestoneId,
@@ -569,11 +601,13 @@ export class WorktreeResolver {
569
601
  }
570
602
  }
571
603
 
572
- // Re-throw MergeConflictError so the auto loop can detect real code
573
- // conflicts and stop instead of retrying forever (#2330).
574
- if (err instanceof MergeConflictError) {
575
- throw err;
576
- }
604
+ // Restore state before re-throwing so callers always get a consistent
605
+ // session (#4380).
606
+ this.restoreToProjectRoot();
607
+ // Re-throw: MergeConflictError stops the auto loop (#2330); non-conflict
608
+ // errors (permission denied, filesystem failures) must also propagate so
609
+ // broken states are diagnosable (#4380).
610
+ throw err;
577
611
  }
578
612
 
579
613
  // Always restore basePath and rebuild — whether merge succeeded or failed
@@ -659,6 +693,8 @@ export class WorktreeResolver {
659
693
  error: msg,
660
694
  });
661
695
  ctx.notify(`Milestone merge failed (branch mode): ${msg}`, "warning");
696
+ // Re-throw all errors so callers can apply their own recovery logic (#4380).
697
+ throw err;
662
698
  }
663
699
  }
664
700
 
@@ -681,7 +717,16 @@ export class WorktreeResolver {
681
717
  currentMilestoneId,
682
718
  nextMilestoneId,
683
719
  });
684
- this.mergeAndExit(currentMilestoneId, ctx);
720
+ try {
721
+ this.mergeAndExit(currentMilestoneId, ctx);
722
+ } catch (err) {
723
+ // mergeAndExit emits a warning and restores state when it fails during
724
+ // merge/cleanup. But if it throws before recovery runs (e.g., in
725
+ // validateMilestoneId or emitJournalEvent), basePath won't be restored
726
+ // to projectRoot — re-throw so we don't enter the next milestone with
727
+ // the current one unmerged.
728
+ if (this.s.basePath !== this.projectRoot) throw err;
729
+ }
685
730
  this.enterMilestone(nextMilestoneId, ctx);
686
731
  }
687
732
  }
@@ -37,7 +37,18 @@ export type McpHttpAuthConfig = McpHttpAuthHeaders & McpHttpOAuthConfig;
37
37
  function resolveEnvValue(value: string): string {
38
38
  return value.replace(
39
39
  /\$\{([^}]+)\}/g,
40
- (_match, varName) => process.env[varName] ?? "",
40
+ (_match, varName) => {
41
+ const resolved = process.env[varName];
42
+ if (resolved === undefined || resolved === "") {
43
+ // eslint-disable-next-line no-console
44
+ console.warn(
45
+ `[mcp-client auth] Environment variable "${varName}" referenced in MCP server config is unset. ` +
46
+ `Requests will go out with a malformed header and the remote server will likely reject them with 401.`,
47
+ );
48
+ return "";
49
+ }
50
+ return resolved;
51
+ },
41
52
  );
42
53
  }
43
54
 
@@ -11,7 +11,7 @@
11
11
  * mcp_call — Call a tool on an MCP server (lazy connect)
12
12
  */
13
13
 
14
- import type { ExtensionAPI } from "@gsd/pi-coding-agent";
14
+ import type { ExtensionAPI, ExtensionContext } from "@gsd/pi-coding-agent";
15
15
  import {
16
16
  truncateHead,
17
17
  DEFAULT_MAX_BYTES,
@@ -33,6 +33,7 @@ import type { McpHttpAuthConfig } from "./auth.js";
33
33
  interface McpServerConfig {
34
34
  name: string;
35
35
  transport: "stdio" | "http" | "unknown";
36
+ sourcePath: string;
36
37
  command?: string;
37
38
  args?: string[];
38
39
  env?: Record<string, string>;
@@ -58,8 +59,40 @@ interface ManagedConnection {
58
59
  // ─── Connection Manager ───────────────────────────────────────────────────────
59
60
 
60
61
  const connections = new Map<string, ManagedConnection>();
62
+ const pendingConnections = new Map<string, Promise<Client>>();
61
63
  let configCache: McpServerConfig[] | null = null;
62
64
  const toolCache = new Map<string, McpToolSchema[]>();
65
+ const trustedStdioServers = new Set<string>();
66
+
67
+ const CHILD_ENV_ALLOWLIST = new Set([
68
+ "PATH",
69
+ "Path",
70
+ "HOME",
71
+ "USER",
72
+ "USERNAME",
73
+ "USERPROFILE",
74
+ "SHELL",
75
+ "TMPDIR",
76
+ "TEMP",
77
+ "TMP",
78
+ "SystemRoot",
79
+ "WINDIR",
80
+ "APPDATA",
81
+ "LOCALAPPDATA",
82
+ "XDG_CONFIG_HOME",
83
+ "XDG_CACHE_HOME",
84
+ ]);
85
+
86
+ function stdioTrustKey(config: McpServerConfig): string {
87
+ return JSON.stringify({
88
+ name: config.name,
89
+ sourcePath: config.sourcePath,
90
+ command: config.command,
91
+ args: config.args ?? [],
92
+ cwd: config.cwd,
93
+ env: config.env ?? {},
94
+ });
95
+ }
63
96
 
64
97
  function readConfigs(): McpServerConfig[] {
65
98
  if (configCache) return configCache;
@@ -99,6 +132,7 @@ function readConfigs(): McpServerConfig[] {
99
132
  servers.push({
100
133
  name,
101
134
  transport,
135
+ sourcePath: configPath,
102
136
  ...(hasCommand && {
103
137
  command: config.command as string,
104
138
  args: Array.isArray(config.args) ? (config.args as string[]) : undefined,
@@ -121,6 +155,54 @@ function readConfigs(): McpServerConfig[] {
121
155
  return servers;
122
156
  }
123
157
 
158
+ export function _buildMcpChildEnvForTest(configEnv: Record<string, string> | undefined): Record<string, string> {
159
+ const childEnv: Record<string, string> = {};
160
+ for (const key of CHILD_ENV_ALLOWLIST) {
161
+ const value = process.env[key];
162
+ if (typeof value === "string") childEnv[key] = value;
163
+ }
164
+ return {
165
+ ...childEnv,
166
+ ...(configEnv ? resolveEnv(configEnv) : {}),
167
+ };
168
+ }
169
+
170
+ export function _buildMcpTrustConfirmOptionsForTest(signal?: AbortSignal): { timeout: number; signal?: AbortSignal } {
171
+ return signal ? { timeout: 120_000, signal } : { timeout: 120_000 };
172
+ }
173
+
174
+ async function assertTrustedStdioServer(
175
+ config: McpServerConfig,
176
+ ctx?: ExtensionContext,
177
+ signal?: AbortSignal,
178
+ ): Promise<string | undefined> {
179
+ if (config.transport !== "stdio") return undefined;
180
+ const trustKey = stdioTrustKey(config);
181
+ if (trustedStdioServers.has(trustKey)) return undefined;
182
+
183
+ if (!ctx?.hasUI) {
184
+ throw new Error(
185
+ `MCP server "${config.name}" is a project-local stdio command from ${config.sourcePath}. ` +
186
+ "Run this from an interactive GSD session and approve the server before use.",
187
+ );
188
+ }
189
+
190
+ const commandLine = [config.command, ...(config.args ?? [])].filter(Boolean).join(" ");
191
+ const envKeys = Object.keys(config.env ?? {});
192
+ const envSummary = envKeys.length > 0
193
+ ? `\n\nConfigured environment keys: ${envKeys.join(", ")}`
194
+ : "\n\nNo explicit environment keys configured.";
195
+ const approved = await ctx.ui.confirm(
196
+ `Trust MCP server "${config.name}"?`,
197
+ `Project config ${config.sourcePath} wants to start:\n\n${commandLine}${envSummary}\n\nOnly approve MCP servers you trust.`,
198
+ _buildMcpTrustConfirmOptionsForTest(signal),
199
+ );
200
+ if (!approved) {
201
+ throw new Error(`MCP server "${config.name}" was not approved by the user.`);
202
+ }
203
+ return trustKey;
204
+ }
205
+
124
206
  function getServerConfig(name: string): McpServerConfig | undefined {
125
207
  const trimmed = name.trim();
126
208
  return readConfigs().find((s) =>
@@ -145,7 +227,7 @@ function resolveEnv(env: Record<string, string>): Record<string, string> {
145
227
  return resolved;
146
228
  }
147
229
 
148
- async function getOrConnect(name: string, signal?: AbortSignal): Promise<Client> {
230
+ async function getOrConnect(name: string, signal?: AbortSignal, ctx?: ExtensionContext): Promise<Client> {
149
231
  const config = getServerConfig(name);
150
232
  if (!config) throw new Error(`Unknown MCP server: "${name}". Use mcp_servers to list available servers.`);
151
233
 
@@ -154,14 +236,29 @@ async function getOrConnect(name: string, signal?: AbortSignal): Promise<Client>
154
236
  const existing = connections.get(config.name);
155
237
  if (existing) return existing.client;
156
238
 
239
+ const pending = pendingConnections.get(config.name);
240
+ if (pending) return pending;
241
+
242
+ const connectionPromise = connectServer(config, signal, ctx);
243
+ pendingConnections.set(config.name, connectionPromise);
244
+ try {
245
+ return await connectionPromise;
246
+ } finally {
247
+ pendingConnections.delete(config.name);
248
+ }
249
+ }
250
+
251
+ async function connectServer(config: McpServerConfig, signal?: AbortSignal, ctx?: ExtensionContext): Promise<Client> {
157
252
  const client = new Client({ name: "gsd", version: "1.0.0" });
158
253
  let transport: StdioClientTransport | StreamableHTTPClientTransport;
254
+ let approvedTrustKey: string | undefined;
159
255
 
160
256
  if (config.transport === "stdio" && config.command) {
257
+ approvedTrustKey = await assertTrustedStdioServer(config, ctx, signal);
161
258
  transport = new StdioClientTransport({
162
259
  command: config.command,
163
260
  args: config.args,
164
- env: config.env ? { ...process.env, ...resolveEnv(config.env) } as Record<string, string> : undefined,
261
+ env: _buildMcpChildEnvForTest(config.env),
165
262
  cwd: config.cwd,
166
263
  stderr: "pipe",
167
264
  });
@@ -179,9 +276,24 @@ async function getOrConnect(name: string, signal?: AbortSignal): Promise<Client>
179
276
  throw new Error(`Server "${config.name}" has unsupported transport: ${config.transport}`);
180
277
  }
181
278
 
182
- await client.connect(transport, { signal, timeout: 30000 });
183
- connections.set(config.name, { client, transport });
184
- return client;
279
+ try {
280
+ await client.connect(transport, { signal, timeout: 30000 });
281
+ if (approvedTrustKey) trustedStdioServers.add(approvedTrustKey);
282
+ connections.set(config.name, { client, transport });
283
+ return client;
284
+ } catch (err) {
285
+ try {
286
+ await transport.close();
287
+ } catch {
288
+ // Best-effort cleanup after a failed or aborted connection attempt.
289
+ }
290
+ try {
291
+ await client.close();
292
+ } catch {
293
+ // Best-effort cleanup after a failed or aborted connection attempt.
294
+ }
295
+ throw err;
296
+ }
185
297
  }
186
298
 
187
299
  async function closeAll(): Promise<void> {
@@ -191,9 +303,16 @@ async function closeAll(): Promise<void> {
191
303
  } catch {
192
304
  // Best-effort cleanup
193
305
  }
306
+ try {
307
+ await conn.transport.close();
308
+ } catch {
309
+ // Best-effort cleanup
310
+ }
194
311
  connections.delete(name);
195
312
  });
196
313
  await Promise.allSettled(closing);
314
+ pendingConnections.clear();
315
+ trustedStdioServers.clear();
197
316
  toolCache.clear();
198
317
  }
199
318
 
@@ -331,7 +450,7 @@ export default function (pi: ExtensionAPI) {
331
450
  }),
332
451
  }),
333
452
 
334
- async execute(_id, params, signal) {
453
+ async execute(_id, params, signal, _onUpdate, ctx) {
335
454
  try {
336
455
  // Return cached tools if available
337
456
  const cached = toolCache.get(params.server);
@@ -348,7 +467,7 @@ export default function (pi: ExtensionAPI) {
348
467
  };
349
468
  }
350
469
 
351
- const client = await getOrConnect(params.server, signal);
470
+ const client = await getOrConnect(params.server, signal, ctx);
352
471
  const result = await client.listTools(undefined, { signal, timeout: 30000 });
353
472
  const tools: McpToolSchema[] = (result.tools ?? []).map((t) => ({
354
473
  name: t.name,
@@ -423,9 +542,9 @@ export default function (pi: ExtensionAPI) {
423
542
  ),
424
543
  }),
425
544
 
426
- async execute(_id, params, signal) {
545
+ async execute(_id, params, signal, _onUpdate, ctx) {
427
546
  try {
428
- const client = await getOrConnect(params.server, signal);
547
+ const client = await getOrConnect(params.server, signal, ctx);
429
548
  const result = await client.callTool(
430
549
  { name: params.tool, arguments: params.args ?? {} },
431
550
  undefined,
@@ -0,0 +1,59 @@
1
+ // GSD-2 — Shared cmux event channel contracts
2
+ // Copyright (c) 2026 Jeremy McSpadden <jeremy@fluxlabs.net>
3
+
4
+ /**
5
+ * Neutral event channel module for gsd<->cmux IPC.
6
+ * Both gsd and cmux import from here — neither imports the other directly.
7
+ * Per ADR-006 Phase 0: event-based decoupling.
8
+ */
9
+
10
+ export const CMUX_CHANNELS = {
11
+ SIDEBAR: "cmux:sidebar",
12
+ LOG: "cmux:log",
13
+ LIFECYCLE: "cmux:lifecycle",
14
+ } as const;
15
+
16
+ /** Migrated from cmux/index.ts (D-07) — shared by both gsd and cmux. */
17
+ export type CmuxLogLevel = "info" | "progress" | "success" | "warning" | "error";
18
+
19
+ // ── Structural types (D-05): cmux defines only what it needs ──
20
+
21
+ export interface CmuxPreferencesInput {
22
+ cmux?: {
23
+ enabled?: boolean;
24
+ notifications?: boolean;
25
+ sidebar?: boolean;
26
+ splits?: boolean;
27
+ browser?: boolean;
28
+ };
29
+ }
30
+
31
+ export interface CmuxStateInput {
32
+ phase: string;
33
+ activeMilestone?: { id: string };
34
+ activeSlice?: { id: string };
35
+ activeTask?: { id: string };
36
+ progress?: {
37
+ milestones: { done: number; total: number };
38
+ slices?: { done: number; total: number };
39
+ tasks?: { done: number; total: number };
40
+ };
41
+ }
42
+
43
+ // ── Event payloads ──
44
+
45
+ export interface CmuxSidebarEvent {
46
+ action: "sync" | "clear";
47
+ preferences?: CmuxPreferencesInput;
48
+ state?: CmuxStateInput;
49
+ }
50
+
51
+ export interface CmuxLogEvent {
52
+ preferences?: CmuxPreferencesInput;
53
+ message: string;
54
+ level: CmuxLogLevel;
55
+ }
56
+
57
+ export interface CmuxLifecycleEvent {
58
+ action: "markPromptShown";
59
+ }
@@ -2,7 +2,6 @@ import { spawnSync } from "node:child_process";
2
2
  import { existsSync, mkdirSync, readFileSync, writeFileSync } from "node:fs";
3
3
  import { join } from "node:path";
4
4
 
5
- import { gsdRoot } from "../gsd/paths.js";
6
5
  import { formatTokenCount } from "./format-utils.js";
7
6
  import { buildRtkEnv, isRtkEnabled, resolveRtkBinaryPath } from "./rtk.js";
8
7
 
@@ -46,7 +45,7 @@ interface BaselineStore {
46
45
  let cachedSummary: { at: number; binaryPath: string; summary: RtkGainSummary | null } | null = null;
47
46
 
48
47
  function getRuntimeDir(basePath: string): string {
49
- return join(gsdRoot(basePath), "runtime");
48
+ return join(basePath, ".gsd", "runtime");
50
49
  }
51
50
 
52
51
  function getBaselinesPath(basePath: string): string {