gsd-pi 2.76.0 → 2.77.0-dev.1594b263e

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 (1227) hide show
  1. package/README.md +33 -31
  2. package/dist/claude-cli-check.js +36 -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/headless.js +49 -4
  14. package/dist/loader.js +35 -7
  15. package/dist/mcp-server.d.ts +7 -0
  16. package/dist/mcp-server.js +35 -1
  17. package/dist/onboarding.js +45 -0
  18. package/dist/provider-migrations.d.ts +18 -0
  19. package/dist/provider-migrations.js +14 -0
  20. package/dist/resource-loader.d.ts +41 -1
  21. package/dist/resource-loader.js +34 -21
  22. package/dist/resources/agents/researcher.md +1 -1
  23. package/dist/resources/extensions/browser-tools/capture.js +9 -0
  24. package/dist/resources/extensions/browser-tools/tests/browser-tools-integration.test.mjs +8 -59
  25. package/dist/resources/extensions/browser-tools/tests/browser-tools-unit.test.cjs +36 -24
  26. package/dist/resources/extensions/browser-tools/tests/capture-sharp-optional.test.cjs +69 -71
  27. package/dist/resources/extensions/browser-tools/tools/forms.js +5 -1
  28. package/dist/resources/extensions/browser-tools/tools/intent.js +5 -1
  29. package/dist/resources/extensions/claude-code-cli/readiness.js +35 -8
  30. package/dist/resources/extensions/claude-code-cli/stream-adapter.js +625 -80
  31. package/dist/resources/extensions/cmux/index.js +20 -0
  32. package/dist/resources/extensions/github-sync/templates.js +103 -0
  33. package/dist/resources/extensions/google-search/extension-manifest.json +5 -4
  34. package/dist/resources/extensions/google-search/index.js +3 -375
  35. package/dist/resources/extensions/gsd/abandon-detect.js +44 -0
  36. package/dist/resources/extensions/gsd/auto/loop.js +133 -2
  37. package/dist/resources/extensions/gsd/auto/phases.js +160 -49
  38. package/dist/resources/extensions/gsd/auto/resolve.js +24 -0
  39. package/dist/resources/extensions/gsd/auto/run-unit.js +48 -4
  40. package/dist/resources/extensions/gsd/auto/session.js +28 -3
  41. package/dist/resources/extensions/gsd/auto/turn-epoch.js +95 -0
  42. package/dist/resources/extensions/gsd/auto-dispatch.js +216 -40
  43. package/dist/resources/extensions/gsd/auto-loop.js +1 -1
  44. package/dist/resources/extensions/gsd/auto-model-selection.js +177 -20
  45. package/dist/resources/extensions/gsd/auto-post-unit.js +240 -66
  46. package/dist/resources/extensions/gsd/auto-prompts.js +386 -104
  47. package/dist/resources/extensions/gsd/auto-recovery.js +124 -4
  48. package/dist/resources/extensions/gsd/auto-start.js +180 -87
  49. package/dist/resources/extensions/gsd/auto-timeout-recovery.js +11 -5
  50. package/dist/resources/extensions/gsd/auto-tool-tracking.js +47 -7
  51. package/dist/resources/extensions/gsd/auto-unit-closeout.js +11 -2
  52. package/dist/resources/extensions/gsd/auto-verification.js +33 -0
  53. package/dist/resources/extensions/gsd/auto-worktree.js +230 -86
  54. package/dist/resources/extensions/gsd/auto.js +169 -55
  55. package/dist/resources/extensions/gsd/blocked-models.js +68 -0
  56. package/dist/resources/extensions/gsd/bootstrap/agent-end-recovery.js +112 -2
  57. package/dist/resources/extensions/gsd/bootstrap/db-tools.js +248 -9
  58. package/dist/resources/extensions/gsd/bootstrap/exec-tools.js +93 -0
  59. package/dist/resources/extensions/gsd/bootstrap/memory-tools.js +3 -0
  60. package/dist/resources/extensions/gsd/bootstrap/provider-error-resume.js +5 -6
  61. package/dist/resources/extensions/gsd/bootstrap/register-extension.js +23 -0
  62. package/dist/resources/extensions/gsd/bootstrap/register-hooks.js +59 -9
  63. package/dist/resources/extensions/gsd/bootstrap/system-context.js +95 -29
  64. package/dist/resources/extensions/gsd/bootstrap/write-gate.js +161 -11
  65. package/dist/resources/extensions/gsd/clean-root-preflight.js +93 -0
  66. package/dist/resources/extensions/gsd/commands/handlers/workflow.js +31 -4
  67. package/dist/resources/extensions/gsd/commands-cmux.js +9 -6
  68. package/dist/resources/extensions/gsd/commands-extensions.js +634 -43
  69. package/dist/resources/extensions/gsd/commands-extract-learnings.js +54 -89
  70. package/dist/resources/extensions/gsd/commands-prefs-wizard.js +968 -23
  71. package/dist/resources/extensions/gsd/compaction-snapshot.js +121 -0
  72. package/dist/resources/extensions/gsd/complexity-classifier.js +5 -3
  73. package/dist/resources/extensions/gsd/component-loader.js +447 -0
  74. package/dist/resources/extensions/gsd/component-types.js +69 -0
  75. package/dist/resources/extensions/gsd/context-store.js +23 -7
  76. package/dist/resources/extensions/gsd/db-writer.js +88 -16
  77. package/dist/resources/extensions/gsd/detection.js +49 -1
  78. package/dist/resources/extensions/gsd/dispatch-guard.js +29 -3
  79. package/dist/resources/extensions/gsd/docs/preferences-reference.md +1 -1
  80. package/dist/resources/extensions/gsd/doctor-git-checks.js +23 -29
  81. package/dist/resources/extensions/gsd/doctor-providers.js +51 -5
  82. package/dist/resources/extensions/gsd/ecosystem/gsd-extension-api.js +1 -0
  83. package/dist/resources/extensions/gsd/error-classifier.js +31 -3
  84. package/dist/resources/extensions/gsd/exec-history.js +120 -0
  85. package/dist/resources/extensions/gsd/exec-sandbox.js +258 -0
  86. package/dist/resources/extensions/gsd/file-lock.js +49 -9
  87. package/dist/resources/extensions/gsd/forensics.js +106 -0
  88. package/dist/resources/extensions/gsd/gate-registry.js +2 -2
  89. package/dist/resources/extensions/gsd/git-constants.js +28 -1
  90. package/dist/resources/extensions/gsd/git-self-heal.js +27 -0
  91. package/dist/resources/extensions/gsd/git-service.js +127 -2
  92. package/dist/resources/extensions/gsd/gitignore.js +2 -0
  93. package/dist/resources/extensions/gsd/gsd-db.js +173 -25
  94. package/dist/resources/extensions/gsd/guided-flow-queue.js +4 -1
  95. package/dist/resources/extensions/gsd/guided-flow.js +214 -13
  96. package/dist/resources/extensions/gsd/health-widget.js +4 -1
  97. package/dist/resources/extensions/gsd/hook-emitter.js +108 -0
  98. package/dist/resources/extensions/gsd/init-wizard.js +15 -1
  99. package/dist/resources/extensions/gsd/journal.js +17 -2
  100. package/dist/resources/extensions/gsd/key-manager.js +28 -0
  101. package/dist/resources/extensions/gsd/memory-backfill.js +126 -0
  102. package/dist/resources/extensions/gsd/memory-extractor.js +7 -1
  103. package/dist/resources/extensions/gsd/memory-store.js +19 -0
  104. package/dist/resources/extensions/gsd/milestone-actions.js +15 -0
  105. package/dist/resources/extensions/gsd/milestone-scope-classifier.js +299 -0
  106. package/dist/resources/extensions/gsd/milestone-summary-classifier.js +37 -0
  107. package/dist/resources/extensions/gsd/model-cost-table.js +3 -0
  108. package/dist/resources/extensions/gsd/model-router.js +42 -3
  109. package/dist/resources/extensions/gsd/native-git-bridge.js +34 -4
  110. package/dist/resources/extensions/gsd/notifications.js +30 -16
  111. package/dist/resources/extensions/gsd/pre-execution-checks.js +44 -9
  112. package/dist/resources/extensions/gsd/preferences-types.js +9 -0
  113. package/dist/resources/extensions/gsd/preferences-validation.js +106 -0
  114. package/dist/resources/extensions/gsd/preferences.js +17 -17
  115. package/dist/resources/extensions/gsd/prompt-cache-optimizer.js +4 -0
  116. package/dist/resources/extensions/gsd/prompt-loader.js +22 -7
  117. package/dist/resources/extensions/gsd/prompts/complete-milestone.md +6 -2
  118. package/dist/resources/extensions/gsd/prompts/complete-slice.md +2 -2
  119. package/dist/resources/extensions/gsd/prompts/debug-diagnose.md +2 -0
  120. package/dist/resources/extensions/gsd/prompts/discuss-headless.md +29 -2
  121. package/dist/resources/extensions/gsd/prompts/discuss.md +29 -2
  122. package/dist/resources/extensions/gsd/prompts/doctor-heal.md +5 -4
  123. package/dist/resources/extensions/gsd/prompts/execute-task.md +3 -2
  124. package/dist/resources/extensions/gsd/prompts/parallel-research-slices.md +5 -2
  125. package/dist/resources/extensions/gsd/prompts/plan-slice.md +16 -2
  126. package/dist/resources/extensions/gsd/prompts/research-slice.md +1 -0
  127. package/dist/resources/extensions/gsd/prompts/system.md +1 -0
  128. package/dist/resources/extensions/gsd/reports.js +5 -4
  129. package/dist/resources/extensions/gsd/safety/evidence-collector.js +96 -0
  130. package/dist/resources/extensions/gsd/safety/file-change-validator.js +13 -5
  131. package/dist/resources/extensions/gsd/safety/git-checkpoint.js +11 -0
  132. package/dist/resources/extensions/gsd/safety/safety-harness.js +5 -1
  133. package/dist/resources/extensions/gsd/service-tier.js +5 -2
  134. package/dist/resources/extensions/gsd/session-lock.js +19 -10
  135. package/dist/resources/extensions/gsd/skill-manifest.js +168 -0
  136. package/dist/resources/extensions/gsd/slice-cadence.js +238 -0
  137. package/dist/resources/extensions/gsd/slice-parallel-orchestrator.js +278 -8
  138. package/dist/resources/extensions/gsd/state-transition-matrix.js +118 -0
  139. package/dist/resources/extensions/gsd/state.js +112 -62
  140. package/dist/resources/extensions/gsd/sync-lock.js +98 -42
  141. package/dist/resources/extensions/gsd/token-counter.js +22 -5
  142. package/dist/resources/extensions/gsd/tools/complete-milestone.js +16 -10
  143. package/dist/resources/extensions/gsd/tools/complete-slice.js +21 -0
  144. package/dist/resources/extensions/gsd/tools/complete-task.js +31 -0
  145. package/dist/resources/extensions/gsd/tools/exec-search-tool.js +59 -0
  146. package/dist/resources/extensions/gsd/tools/exec-tool.js +126 -0
  147. package/dist/resources/extensions/gsd/tools/memory-tools.js +26 -1
  148. package/dist/resources/extensions/gsd/tools/resume-tool.js +23 -0
  149. package/dist/resources/extensions/gsd/tools/validate-milestone.js +7 -2
  150. package/dist/resources/extensions/gsd/unit-context-composer.js +147 -0
  151. package/dist/resources/extensions/gsd/unit-context-manifest.js +370 -0
  152. package/dist/resources/extensions/gsd/uok/audit.js +18 -2
  153. package/dist/resources/extensions/gsd/uok/dispatch-envelope.js +33 -0
  154. package/dist/resources/extensions/gsd/uok/execution-graph.js +10 -0
  155. package/dist/resources/extensions/gsd/uok/gate-runner.js +53 -5
  156. package/dist/resources/extensions/gsd/uok/gitops.js +2 -1
  157. package/dist/resources/extensions/gsd/uok/loop-adapter.js +37 -10
  158. package/dist/resources/extensions/gsd/uok/parity-report.js +58 -0
  159. package/dist/resources/extensions/gsd/uok/plan-v2.js +30 -7
  160. package/dist/resources/extensions/gsd/uok/writer.js +82 -0
  161. package/dist/resources/extensions/gsd/workflow-logger.js +10 -2
  162. package/dist/resources/extensions/gsd/workflow-mcp.js +9 -0
  163. package/dist/resources/extensions/gsd/workflow-templates/spike.md +6 -0
  164. package/dist/resources/extensions/gsd/worktree-manager.js +86 -8
  165. package/dist/resources/extensions/gsd/worktree-resolver.js +136 -17
  166. package/dist/resources/extensions/gsd/worktree-telemetry.js +198 -0
  167. package/dist/resources/extensions/mcp-client/auth.js +10 -1
  168. package/dist/resources/extensions/mcp-client/index.js +121 -10
  169. package/dist/resources/extensions/ollama/index.js +5 -1
  170. package/dist/resources/extensions/remote-questions/manager.js +11 -5
  171. package/dist/resources/extensions/search-the-web/command-search-provider.js +5 -4
  172. package/dist/resources/extensions/search-the-web/native-search.js +45 -13
  173. package/dist/resources/extensions/shared/cmux-events.js +12 -0
  174. package/dist/resources/extensions/shared/rtk-session-stats.js +1 -2
  175. package/dist/resources/skills/api-design/SKILL.md +190 -0
  176. package/dist/resources/skills/create-mcp-server/SKILL.md +121 -0
  177. package/dist/resources/skills/create-skill/SKILL.md +2 -2
  178. package/dist/resources/skills/create-skill/references/gsd-skill-ecosystem.md +4 -4
  179. package/dist/resources/skills/create-skill/workflows/audit-skill.md +4 -4
  180. package/dist/resources/skills/create-skill/workflows/create-new-skill.md +5 -5
  181. package/dist/resources/skills/decompose-into-slices/SKILL.md +139 -0
  182. package/dist/resources/skills/dependency-upgrade/SKILL.md +158 -0
  183. package/dist/resources/skills/design-an-interface/SKILL.md +102 -0
  184. package/dist/resources/skills/forensics/SKILL.md +153 -0
  185. package/dist/resources/skills/grill-me/SKILL.md +93 -0
  186. package/dist/resources/skills/handoff/SKILL.md +121 -0
  187. package/dist/resources/skills/observability/SKILL.md +174 -0
  188. package/dist/resources/skills/security-review/SKILL.md +181 -0
  189. package/dist/resources/skills/spike-wrap-up/SKILL.md +138 -0
  190. package/dist/resources/skills/tdd/SKILL.md +112 -0
  191. package/dist/resources/skills/verify-before-complete/SKILL.md +98 -0
  192. package/dist/resources/skills/write-docs/SKILL.md +82 -0
  193. package/dist/resources/skills/write-milestone-brief/SKILL.md +135 -0
  194. package/dist/tsconfig.extensions.tsbuildinfo +1 -1
  195. package/dist/web/standalone/.next/BUILD_ID +1 -1
  196. package/dist/web/standalone/.next/app-path-routes-manifest.json +12 -12
  197. package/dist/web/standalone/.next/build-manifest.json +4 -4
  198. package/dist/web/standalone/.next/prerender-manifest.json +3 -3
  199. package/dist/web/standalone/.next/react-loadable-manifest.json +1 -1
  200. package/dist/web/standalone/.next/required-server-files.json +4 -4
  201. package/dist/web/standalone/.next/server/app/_global-error/page.js +3 -3
  202. package/dist/web/standalone/.next/server/app/_global-error/page_client-reference-manifest.js +1 -1
  203. package/dist/web/standalone/.next/server/app/_global-error.html +1 -1
  204. package/dist/web/standalone/.next/server/app/_global-error.rsc +1 -1
  205. package/dist/web/standalone/.next/server/app/_global-error.segments/_full.segment.rsc +1 -1
  206. package/dist/web/standalone/.next/server/app/_global-error.segments/_global-error/__PAGE__.segment.rsc +1 -1
  207. package/dist/web/standalone/.next/server/app/_global-error.segments/_global-error.segment.rsc +1 -1
  208. package/dist/web/standalone/.next/server/app/_global-error.segments/_head.segment.rsc +1 -1
  209. package/dist/web/standalone/.next/server/app/_global-error.segments/_index.segment.rsc +1 -1
  210. package/dist/web/standalone/.next/server/app/_global-error.segments/_tree.segment.rsc +1 -1
  211. package/dist/web/standalone/.next/server/app/_not-found/page.js +2 -2
  212. package/dist/web/standalone/.next/server/app/_not-found/page_client-reference-manifest.js +1 -1
  213. package/dist/web/standalone/.next/server/app/_not-found.html +1 -1
  214. package/dist/web/standalone/.next/server/app/_not-found.rsc +3 -3
  215. package/dist/web/standalone/.next/server/app/_not-found.segments/_full.segment.rsc +3 -3
  216. package/dist/web/standalone/.next/server/app/_not-found.segments/_head.segment.rsc +1 -1
  217. package/dist/web/standalone/.next/server/app/_not-found.segments/_index.segment.rsc +3 -3
  218. package/dist/web/standalone/.next/server/app/_not-found.segments/_not-found/__PAGE__.segment.rsc +1 -1
  219. package/dist/web/standalone/.next/server/app/_not-found.segments/_not-found.segment.rsc +1 -1
  220. package/dist/web/standalone/.next/server/app/_not-found.segments/_tree.segment.rsc +1 -1
  221. package/dist/web/standalone/.next/server/app/api/boot/route.js +1 -1
  222. package/dist/web/standalone/.next/server/app/api/boot/route.js.nft.json +1 -1
  223. package/dist/web/standalone/.next/server/app/api/boot/route_client-reference-manifest.js +1 -1
  224. package/dist/web/standalone/.next/server/app/api/bridge-terminal/input/route.js +1 -1
  225. package/dist/web/standalone/.next/server/app/api/bridge-terminal/input/route.js.nft.json +1 -1
  226. package/dist/web/standalone/.next/server/app/api/bridge-terminal/input/route_client-reference-manifest.js +1 -1
  227. package/dist/web/standalone/.next/server/app/api/bridge-terminal/resize/route.js +1 -1
  228. package/dist/web/standalone/.next/server/app/api/bridge-terminal/resize/route.js.nft.json +1 -1
  229. package/dist/web/standalone/.next/server/app/api/bridge-terminal/resize/route_client-reference-manifest.js +1 -1
  230. package/dist/web/standalone/.next/server/app/api/bridge-terminal/stream/route.js +2 -2
  231. package/dist/web/standalone/.next/server/app/api/bridge-terminal/stream/route.js.nft.json +1 -1
  232. package/dist/web/standalone/.next/server/app/api/bridge-terminal/stream/route_client-reference-manifest.js +1 -1
  233. package/dist/web/standalone/.next/server/app/api/browse-directories/route.js +1 -1
  234. package/dist/web/standalone/.next/server/app/api/browse-directories/route_client-reference-manifest.js +1 -1
  235. package/dist/web/standalone/.next/server/app/api/captures/route.js +1 -1
  236. package/dist/web/standalone/.next/server/app/api/captures/route.js.nft.json +1 -1
  237. package/dist/web/standalone/.next/server/app/api/captures/route_client-reference-manifest.js +1 -1
  238. package/dist/web/standalone/.next/server/app/api/cleanup/route.js +1 -1
  239. package/dist/web/standalone/.next/server/app/api/cleanup/route.js.nft.json +1 -1
  240. package/dist/web/standalone/.next/server/app/api/cleanup/route_client-reference-manifest.js +1 -1
  241. package/dist/web/standalone/.next/server/app/api/dev-mode/route.js +1 -1
  242. package/dist/web/standalone/.next/server/app/api/dev-mode/route_client-reference-manifest.js +1 -1
  243. package/dist/web/standalone/.next/server/app/api/doctor/route.js +1 -1
  244. package/dist/web/standalone/.next/server/app/api/doctor/route.js.nft.json +1 -1
  245. package/dist/web/standalone/.next/server/app/api/doctor/route_client-reference-manifest.js +1 -1
  246. package/dist/web/standalone/.next/server/app/api/experimental/route.js +2 -2
  247. package/dist/web/standalone/.next/server/app/api/experimental/route_client-reference-manifest.js +1 -1
  248. package/dist/web/standalone/.next/server/app/api/export-data/route.js +1 -1
  249. package/dist/web/standalone/.next/server/app/api/export-data/route.js.nft.json +1 -1
  250. package/dist/web/standalone/.next/server/app/api/export-data/route_client-reference-manifest.js +1 -1
  251. package/dist/web/standalone/.next/server/app/api/files/route.js +1 -1
  252. package/dist/web/standalone/.next/server/app/api/files/route.js.nft.json +1 -1
  253. package/dist/web/standalone/.next/server/app/api/files/route_client-reference-manifest.js +1 -1
  254. package/dist/web/standalone/.next/server/app/api/forensics/route.js +1 -1
  255. package/dist/web/standalone/.next/server/app/api/forensics/route.js.nft.json +1 -1
  256. package/dist/web/standalone/.next/server/app/api/forensics/route_client-reference-manifest.js +1 -1
  257. package/dist/web/standalone/.next/server/app/api/git/route.js +1 -1
  258. package/dist/web/standalone/.next/server/app/api/git/route.js.nft.json +1 -1
  259. package/dist/web/standalone/.next/server/app/api/git/route_client-reference-manifest.js +1 -1
  260. package/dist/web/standalone/.next/server/app/api/history/route.js +1 -1
  261. package/dist/web/standalone/.next/server/app/api/history/route.js.nft.json +1 -1
  262. package/dist/web/standalone/.next/server/app/api/history/route_client-reference-manifest.js +1 -1
  263. package/dist/web/standalone/.next/server/app/api/hooks/route.js +1 -1
  264. package/dist/web/standalone/.next/server/app/api/hooks/route.js.nft.json +1 -1
  265. package/dist/web/standalone/.next/server/app/api/hooks/route_client-reference-manifest.js +1 -1
  266. package/dist/web/standalone/.next/server/app/api/inspect/route.js +1 -1
  267. package/dist/web/standalone/.next/server/app/api/inspect/route.js.nft.json +1 -1
  268. package/dist/web/standalone/.next/server/app/api/inspect/route_client-reference-manifest.js +1 -1
  269. package/dist/web/standalone/.next/server/app/api/knowledge/route.js +1 -1
  270. package/dist/web/standalone/.next/server/app/api/knowledge/route.js.nft.json +1 -1
  271. package/dist/web/standalone/.next/server/app/api/knowledge/route_client-reference-manifest.js +1 -1
  272. package/dist/web/standalone/.next/server/app/api/live-state/route.js +1 -1
  273. package/dist/web/standalone/.next/server/app/api/live-state/route.js.nft.json +1 -1
  274. package/dist/web/standalone/.next/server/app/api/live-state/route_client-reference-manifest.js +1 -1
  275. package/dist/web/standalone/.next/server/app/api/notifications/route.js +2 -2
  276. package/dist/web/standalone/.next/server/app/api/notifications/route.js.nft.json +1 -1
  277. package/dist/web/standalone/.next/server/app/api/notifications/route_client-reference-manifest.js +1 -1
  278. package/dist/web/standalone/.next/server/app/api/onboarding/route.js +1 -1
  279. package/dist/web/standalone/.next/server/app/api/onboarding/route.js.nft.json +1 -1
  280. package/dist/web/standalone/.next/server/app/api/onboarding/route_client-reference-manifest.js +1 -1
  281. package/dist/web/standalone/.next/server/app/api/preferences/route.js +1 -1
  282. package/dist/web/standalone/.next/server/app/api/preferences/route_client-reference-manifest.js +1 -1
  283. package/dist/web/standalone/.next/server/app/api/projects/route.js +1 -1
  284. package/dist/web/standalone/.next/server/app/api/projects/route.js.nft.json +1 -1
  285. package/dist/web/standalone/.next/server/app/api/projects/route_client-reference-manifest.js +1 -1
  286. package/dist/web/standalone/.next/server/app/api/recovery/route.js +1 -1
  287. package/dist/web/standalone/.next/server/app/api/recovery/route.js.nft.json +1 -1
  288. package/dist/web/standalone/.next/server/app/api/recovery/route_client-reference-manifest.js +1 -1
  289. package/dist/web/standalone/.next/server/app/api/remote-questions/route.js +2 -2
  290. package/dist/web/standalone/.next/server/app/api/remote-questions/route_client-reference-manifest.js +1 -1
  291. package/dist/web/standalone/.next/server/app/api/session/browser/route.js +1 -1
  292. package/dist/web/standalone/.next/server/app/api/session/browser/route.js.nft.json +1 -1
  293. package/dist/web/standalone/.next/server/app/api/session/browser/route_client-reference-manifest.js +1 -1
  294. package/dist/web/standalone/.next/server/app/api/session/command/route.js +1 -1
  295. package/dist/web/standalone/.next/server/app/api/session/command/route.js.nft.json +1 -1
  296. package/dist/web/standalone/.next/server/app/api/session/command/route_client-reference-manifest.js +1 -1
  297. package/dist/web/standalone/.next/server/app/api/session/events/route.js +2 -2
  298. package/dist/web/standalone/.next/server/app/api/session/events/route.js.nft.json +1 -1
  299. package/dist/web/standalone/.next/server/app/api/session/events/route_client-reference-manifest.js +1 -1
  300. package/dist/web/standalone/.next/server/app/api/session/manage/route.js +1 -1
  301. package/dist/web/standalone/.next/server/app/api/session/manage/route.js.nft.json +1 -1
  302. package/dist/web/standalone/.next/server/app/api/session/manage/route_client-reference-manifest.js +1 -1
  303. package/dist/web/standalone/.next/server/app/api/settings-data/route.js +1 -1
  304. package/dist/web/standalone/.next/server/app/api/settings-data/route.js.nft.json +1 -1
  305. package/dist/web/standalone/.next/server/app/api/settings-data/route_client-reference-manifest.js +1 -1
  306. package/dist/web/standalone/.next/server/app/api/shutdown/route.js +1 -1
  307. package/dist/web/standalone/.next/server/app/api/shutdown/route_client-reference-manifest.js +1 -1
  308. package/dist/web/standalone/.next/server/app/api/skill-health/route.js +1 -1
  309. package/dist/web/standalone/.next/server/app/api/skill-health/route.js.nft.json +1 -1
  310. package/dist/web/standalone/.next/server/app/api/skill-health/route_client-reference-manifest.js +1 -1
  311. package/dist/web/standalone/.next/server/app/api/steer/route.js +1 -1
  312. package/dist/web/standalone/.next/server/app/api/steer/route.js.nft.json +1 -1
  313. package/dist/web/standalone/.next/server/app/api/steer/route_client-reference-manifest.js +1 -1
  314. package/dist/web/standalone/.next/server/app/api/switch-root/route.js +1 -1
  315. package/dist/web/standalone/.next/server/app/api/switch-root/route.js.nft.json +1 -1
  316. package/dist/web/standalone/.next/server/app/api/switch-root/route_client-reference-manifest.js +1 -1
  317. package/dist/web/standalone/.next/server/app/api/terminal/input/route.js +2 -2
  318. package/dist/web/standalone/.next/server/app/api/terminal/input/route_client-reference-manifest.js +1 -1
  319. package/dist/web/standalone/.next/server/app/api/terminal/resize/route.js +2 -2
  320. package/dist/web/standalone/.next/server/app/api/terminal/resize/route_client-reference-manifest.js +1 -1
  321. package/dist/web/standalone/.next/server/app/api/terminal/sessions/route.js +2 -2
  322. package/dist/web/standalone/.next/server/app/api/terminal/sessions/route.js.nft.json +1 -1
  323. package/dist/web/standalone/.next/server/app/api/terminal/sessions/route_client-reference-manifest.js +1 -1
  324. package/dist/web/standalone/.next/server/app/api/terminal/stream/route.js +4 -4
  325. package/dist/web/standalone/.next/server/app/api/terminal/stream/route.js.nft.json +1 -1
  326. package/dist/web/standalone/.next/server/app/api/terminal/stream/route_client-reference-manifest.js +1 -1
  327. package/dist/web/standalone/.next/server/app/api/terminal/upload/route.js +1 -1
  328. package/dist/web/standalone/.next/server/app/api/terminal/upload/route_client-reference-manifest.js +1 -1
  329. package/dist/web/standalone/.next/server/app/api/undo/route.js +1 -1
  330. package/dist/web/standalone/.next/server/app/api/undo/route.js.nft.json +1 -1
  331. package/dist/web/standalone/.next/server/app/api/undo/route_client-reference-manifest.js +1 -1
  332. package/dist/web/standalone/.next/server/app/api/update/route.js +1 -1
  333. package/dist/web/standalone/.next/server/app/api/update/route_client-reference-manifest.js +1 -1
  334. package/dist/web/standalone/.next/server/app/api/visualizer/route.js +1 -1
  335. package/dist/web/standalone/.next/server/app/api/visualizer/route.js.nft.json +1 -1
  336. package/dist/web/standalone/.next/server/app/api/visualizer/route_client-reference-manifest.js +1 -1
  337. package/dist/web/standalone/.next/server/app/index.html +1 -1
  338. package/dist/web/standalone/.next/server/app/index.rsc +4 -4
  339. package/dist/web/standalone/.next/server/app/index.segments/__PAGE__.segment.rsc +2 -2
  340. package/dist/web/standalone/.next/server/app/index.segments/_full.segment.rsc +4 -4
  341. package/dist/web/standalone/.next/server/app/index.segments/_head.segment.rsc +1 -1
  342. package/dist/web/standalone/.next/server/app/index.segments/_index.segment.rsc +3 -3
  343. package/dist/web/standalone/.next/server/app/index.segments/_tree.segment.rsc +1 -1
  344. package/dist/web/standalone/.next/server/app/page.js +2 -2
  345. package/dist/web/standalone/.next/server/app/page_client-reference-manifest.js +1 -1
  346. package/dist/web/standalone/.next/server/app-paths-manifest.json +12 -12
  347. package/dist/web/standalone/.next/server/chunks/1926.js +1 -0
  348. package/dist/web/standalone/.next/server/chunks/63.js +3 -3
  349. package/dist/web/standalone/.next/server/chunks/6897.js +3 -3
  350. package/dist/web/standalone/.next/server/middleware-build-manifest.js +1 -1
  351. package/dist/web/standalone/.next/server/middleware-manifest.json +5 -5
  352. package/dist/web/standalone/.next/server/middleware-react-loadable-manifest.js +1 -1
  353. package/dist/web/standalone/.next/server/middleware.js +2 -2
  354. package/dist/web/standalone/.next/server/next-font-manifest.js +1 -1
  355. package/dist/web/standalone/.next/server/next-font-manifest.json +1 -1
  356. package/dist/web/standalone/.next/server/pages/404.html +1 -1
  357. package/dist/web/standalone/.next/server/pages/500.html +1 -1
  358. package/dist/web/standalone/.next/server/server-reference-manifest.json +1 -1
  359. package/dist/web/standalone/.next/static/chunks/2826.e9f5195e91f9cad2.js +11 -0
  360. package/dist/web/standalone/.next/static/chunks/app/_not-found/{page-2f24283c162b6ab3.js → page-f2a7482d42a5614b.js} +1 -1
  361. package/dist/web/standalone/.next/static/chunks/app/{layout-9ecfd95f343793f0.js → layout-a16c7a7ecdf0c2cf.js} +1 -1
  362. package/dist/web/standalone/.next/static/chunks/app/page-5b113fd32bc2a1c3.js +1 -0
  363. package/dist/web/standalone/.next/static/chunks/main-app-fdab67f7802d7832.js +1 -0
  364. package/dist/web/standalone/.next/static/chunks/next/dist/client/components/builtin/global-error-459824ffb8c323dd.js +1 -0
  365. package/dist/web/standalone/.next/static/chunks/{webpack-5fc74f13a25fa1bb.js → webpack-2e68521d7c82f7c2.js} +1 -1
  366. package/dist/web/standalone/node_modules/node-pty/build/Makefile +2 -2
  367. package/dist/web/standalone/node_modules/node-pty/build/Release/pty.node +0 -0
  368. package/dist/web/standalone/node_modules/node-pty/build/pty.target.mk +14 -14
  369. package/dist/web/standalone/node_modules/node-pty/node-addon-api/node_addon_api.target.mk +14 -14
  370. package/dist/web/standalone/node_modules/node-pty/node-addon-api/node_addon_api_except.target.mk +14 -14
  371. package/dist/web/standalone/node_modules/node-pty/node-addon-api/node_addon_api_maybe.target.mk +14 -14
  372. package/dist/web/standalone/server.js +1 -1
  373. package/dist/welcome-screen.js +6 -1
  374. package/dist/wizard.js +2 -0
  375. package/package.json +17 -16
  376. package/packages/daemon/package.json +2 -2
  377. package/packages/daemon/src/logger.ts +4 -3
  378. package/packages/mcp-server/README.md +3 -3
  379. package/packages/mcp-server/dist/env-writer.d.ts +1 -0
  380. package/packages/mcp-server/dist/env-writer.d.ts.map +1 -1
  381. package/packages/mcp-server/dist/env-writer.js +74 -6
  382. package/packages/mcp-server/dist/env-writer.js.map +1 -1
  383. package/packages/mcp-server/dist/remote-questions.d.ts +45 -0
  384. package/packages/mcp-server/dist/remote-questions.d.ts.map +1 -0
  385. package/packages/mcp-server/dist/remote-questions.js +732 -0
  386. package/packages/mcp-server/dist/remote-questions.js.map +1 -0
  387. package/packages/mcp-server/dist/server.d.ts +31 -0
  388. package/packages/mcp-server/dist/server.d.ts.map +1 -1
  389. package/packages/mcp-server/dist/server.js +179 -93
  390. package/packages/mcp-server/dist/server.js.map +1 -1
  391. package/packages/mcp-server/dist/session-manager.d.ts +14 -0
  392. package/packages/mcp-server/dist/session-manager.d.ts.map +1 -1
  393. package/packages/mcp-server/dist/session-manager.js +49 -1
  394. package/packages/mcp-server/dist/session-manager.js.map +1 -1
  395. package/packages/mcp-server/dist/workflow-tools.d.ts +1 -1
  396. package/packages/mcp-server/dist/workflow-tools.d.ts.map +1 -1
  397. package/packages/mcp-server/dist/workflow-tools.js +178 -31
  398. package/packages/mcp-server/dist/workflow-tools.js.map +1 -1
  399. package/packages/mcp-server/package.json +9 -3
  400. package/packages/mcp-server/src/env-writer.test.ts +79 -1
  401. package/packages/mcp-server/src/env-writer.ts +76 -6
  402. package/packages/mcp-server/src/mcp-server.test.ts +89 -0
  403. package/packages/mcp-server/src/readers/graph.test.ts +87 -15
  404. package/packages/mcp-server/src/readers/readers.test.ts +5 -1
  405. package/packages/mcp-server/src/remote-questions.test.ts +294 -0
  406. package/packages/mcp-server/src/remote-questions.ts +916 -0
  407. package/packages/mcp-server/src/secure-env-collect.test.ts +232 -237
  408. package/packages/mcp-server/src/server.ts +236 -108
  409. package/packages/mcp-server/src/session-manager.ts +43 -1
  410. package/packages/mcp-server/src/workflow-tools.test.ts +231 -1
  411. package/packages/mcp-server/src/workflow-tools.ts +234 -49
  412. package/packages/mcp-server/tsconfig.test.json +19 -0
  413. package/packages/mcp-server/tsconfig.tsbuildinfo +1 -1
  414. package/packages/native/package.json +7 -2
  415. package/packages/native/src/__tests__/_test-coverage-guard.test.mjs +98 -0
  416. package/packages/native/src/__tests__/clipboard.test.mjs +69 -23
  417. package/packages/native/src/__tests__/module-compat.test.mjs +59 -27
  418. package/packages/native/src/__tests__/ps.test.mjs +14 -8
  419. package/packages/native/src/__tests__/stream-process.test.mjs +23 -2
  420. package/packages/native/src/__tests__/truncate.test.mjs +17 -2
  421. package/packages/native/tsconfig.tsbuildinfo +1 -1
  422. package/packages/pi-agent-core/dist/agent-loop.js +12 -0
  423. package/packages/pi-agent-core/dist/agent-loop.js.map +1 -1
  424. package/packages/pi-agent-core/dist/types.d.ts +30 -0
  425. package/packages/pi-agent-core/dist/types.d.ts.map +1 -1
  426. package/packages/pi-agent-core/dist/types.js.map +1 -1
  427. package/packages/pi-agent-core/package.json +6 -1
  428. package/packages/pi-agent-core/src/agent-loop.test.ts +226 -31
  429. package/packages/pi-agent-core/src/agent-loop.ts +14 -0
  430. package/packages/pi-agent-core/src/agent.test.ts +96 -102
  431. package/packages/pi-agent-core/src/types.ts +34 -0
  432. package/packages/pi-agent-core/tsconfig.tsbuildinfo +1 -1
  433. package/packages/pi-ai/dist/models/capability-patches.d.ts.map +1 -1
  434. package/packages/pi-ai/dist/models/capability-patches.js +9 -2
  435. package/packages/pi-ai/dist/models/capability-patches.js.map +1 -1
  436. package/packages/pi-ai/dist/models/custom.d.ts +38 -0
  437. package/packages/pi-ai/dist/models/custom.d.ts.map +1 -1
  438. package/packages/pi-ai/dist/models/custom.js +41 -0
  439. package/packages/pi-ai/dist/models/custom.js.map +1 -1
  440. package/packages/pi-ai/dist/models/generated/index.d.ts +34 -0
  441. package/packages/pi-ai/dist/models/generated/index.d.ts.map +1 -1
  442. package/packages/pi-ai/dist/models/generated/openai-codex.d.ts +17 -0
  443. package/packages/pi-ai/dist/models/generated/openai-codex.d.ts.map +1 -1
  444. package/packages/pi-ai/dist/models/generated/openai-codex.js +17 -0
  445. package/packages/pi-ai/dist/models/generated/openai-codex.js.map +1 -1
  446. package/packages/pi-ai/dist/models/generated/openai.d.ts +17 -0
  447. package/packages/pi-ai/dist/models/generated/openai.d.ts.map +1 -1
  448. package/packages/pi-ai/dist/models/generated/openai.js +17 -0
  449. package/packages/pi-ai/dist/models/generated/openai.js.map +1 -1
  450. package/packages/pi-ai/dist/models.generated.test.js +43 -70
  451. package/packages/pi-ai/dist/models.generated.test.js.map +1 -1
  452. package/packages/pi-ai/dist/models.test.js +36 -11
  453. package/packages/pi-ai/dist/models.test.js.map +1 -1
  454. package/packages/pi-ai/dist/providers/anthropic-auth.test.js +1 -1
  455. package/packages/pi-ai/dist/providers/anthropic-auth.test.js.map +1 -1
  456. package/packages/pi-ai/dist/providers/anthropic-bearer-auth.test.d.ts +2 -0
  457. package/packages/pi-ai/dist/providers/anthropic-bearer-auth.test.d.ts.map +1 -0
  458. package/packages/pi-ai/dist/providers/anthropic-bearer-auth.test.js +13 -0
  459. package/packages/pi-ai/dist/providers/anthropic-bearer-auth.test.js.map +1 -0
  460. package/packages/pi-ai/dist/providers/anthropic-shared.d.ts.map +1 -1
  461. package/packages/pi-ai/dist/providers/anthropic-shared.js +27 -4
  462. package/packages/pi-ai/dist/providers/anthropic-shared.js.map +1 -1
  463. package/packages/pi-ai/dist/providers/anthropic.d.ts.map +1 -1
  464. package/packages/pi-ai/dist/providers/anthropic.js +13 -4
  465. package/packages/pi-ai/dist/providers/anthropic.js.map +1 -1
  466. package/packages/pi-ai/dist/providers/minimax-tool-name.test.d.ts +2 -0
  467. package/packages/pi-ai/dist/providers/minimax-tool-name.test.d.ts.map +1 -0
  468. package/packages/pi-ai/dist/providers/minimax-tool-name.test.js +80 -0
  469. package/packages/pi-ai/dist/providers/minimax-tool-name.test.js.map +1 -0
  470. package/packages/pi-ai/dist/providers/openai-completions.d.ts.map +1 -1
  471. package/packages/pi-ai/dist/providers/openai-completions.js +60 -15
  472. package/packages/pi-ai/dist/providers/openai-completions.js.map +1 -1
  473. package/packages/pi-ai/dist/providers/simple-options.d.ts +10 -0
  474. package/packages/pi-ai/dist/providers/simple-options.d.ts.map +1 -1
  475. package/packages/pi-ai/dist/providers/simple-options.js +16 -1
  476. package/packages/pi-ai/dist/providers/simple-options.js.map +1 -1
  477. package/packages/pi-ai/dist/providers/think-tag-parser.d.ts +17 -0
  478. package/packages/pi-ai/dist/providers/think-tag-parser.d.ts.map +1 -0
  479. package/packages/pi-ai/dist/providers/think-tag-parser.js +75 -0
  480. package/packages/pi-ai/dist/providers/think-tag-parser.js.map +1 -0
  481. package/packages/pi-ai/dist/providers/think-tag-parser.test.d.ts +2 -0
  482. package/packages/pi-ai/dist/providers/think-tag-parser.test.d.ts.map +1 -0
  483. package/packages/pi-ai/dist/providers/think-tag-parser.test.js +41 -0
  484. package/packages/pi-ai/dist/providers/think-tag-parser.test.js.map +1 -0
  485. package/packages/pi-ai/dist/utils/oauth/github-copilot.d.ts.map +1 -1
  486. package/packages/pi-ai/dist/utils/oauth/github-copilot.js +12 -2
  487. package/packages/pi-ai/dist/utils/oauth/github-copilot.js.map +1 -1
  488. package/packages/pi-ai/dist/utils/oauth/github-copilot.test.js +164 -14
  489. package/packages/pi-ai/dist/utils/oauth/github-copilot.test.js.map +1 -1
  490. package/packages/pi-ai/dist/utils/oauth/google-antigravity.d.ts.map +1 -1
  491. package/packages/pi-ai/dist/utils/oauth/google-antigravity.js +15 -3
  492. package/packages/pi-ai/dist/utils/oauth/google-antigravity.js.map +1 -1
  493. package/packages/pi-ai/dist/utils/oauth/google-antigravity.test.d.ts +2 -0
  494. package/packages/pi-ai/dist/utils/oauth/google-antigravity.test.d.ts.map +1 -0
  495. package/packages/pi-ai/dist/utils/oauth/google-antigravity.test.js +67 -0
  496. package/packages/pi-ai/dist/utils/oauth/google-antigravity.test.js.map +1 -0
  497. package/packages/pi-ai/dist/utils/oauth/google-gemini-cli.d.ts.map +1 -1
  498. package/packages/pi-ai/dist/utils/oauth/google-gemini-cli.js +16 -3
  499. package/packages/pi-ai/dist/utils/oauth/google-gemini-cli.js.map +1 -1
  500. package/packages/pi-ai/dist/utils/oauth/google-gemini-cli.test.d.ts +2 -0
  501. package/packages/pi-ai/dist/utils/oauth/google-gemini-cli.test.d.ts.map +1 -0
  502. package/packages/pi-ai/dist/utils/oauth/google-gemini-cli.test.js +67 -0
  503. package/packages/pi-ai/dist/utils/oauth/google-gemini-cli.test.js.map +1 -0
  504. package/packages/pi-ai/package.json +6 -1
  505. package/packages/pi-ai/scripts/generate-models.ts +44 -0
  506. package/packages/pi-ai/src/models/capability-patches.ts +10 -2
  507. package/packages/pi-ai/src/models/custom.ts +42 -0
  508. package/packages/pi-ai/src/models/generated/openai-codex.ts +17 -0
  509. package/packages/pi-ai/src/models/generated/openai.ts +17 -0
  510. package/packages/pi-ai/src/models.generated.test.ts +46 -73
  511. package/packages/pi-ai/src/models.test.ts +48 -11
  512. package/packages/pi-ai/src/providers/anthropic-auth.test.ts +1 -1
  513. package/packages/pi-ai/src/providers/anthropic-bearer-auth.test.ts +26 -0
  514. package/packages/pi-ai/src/providers/anthropic-shared.ts +26 -5
  515. package/packages/pi-ai/src/providers/anthropic.ts +15 -4
  516. package/packages/pi-ai/src/providers/minimax-tool-name.test.ts +98 -0
  517. package/packages/pi-ai/src/providers/openai-completions.ts +57 -16
  518. package/packages/pi-ai/src/providers/simple-options.ts +17 -1
  519. package/packages/pi-ai/src/providers/think-tag-parser.test.ts +44 -0
  520. package/packages/pi-ai/src/providers/think-tag-parser.ts +94 -0
  521. package/packages/pi-ai/src/utils/oauth/github-copilot.test.ts +200 -23
  522. package/packages/pi-ai/src/utils/oauth/github-copilot.ts +12 -2
  523. package/packages/pi-ai/src/utils/oauth/google-antigravity.test.ts +84 -0
  524. package/packages/pi-ai/src/utils/oauth/google-antigravity.ts +15 -5
  525. package/packages/pi-ai/src/utils/oauth/google-gemini-cli.test.ts +84 -0
  526. package/packages/pi-ai/src/utils/oauth/google-gemini-cli.ts +16 -5
  527. package/packages/pi-ai/tsconfig.tsbuildinfo +1 -1
  528. package/packages/pi-coding-agent/dist/core/agent-session-abort-order.test.js +96 -31
  529. package/packages/pi-coding-agent/dist/core/agent-session-abort-order.test.js.map +1 -1
  530. package/packages/pi-coding-agent/dist/core/agent-session-model-switch.test.js +75 -12
  531. package/packages/pi-coding-agent/dist/core/agent-session-model-switch.test.js.map +1 -1
  532. package/packages/pi-coding-agent/dist/core/agent-session-tool-refresh.test.js +99 -31
  533. package/packages/pi-coding-agent/dist/core/agent-session-tool-refresh.test.js.map +1 -1
  534. package/packages/pi-coding-agent/dist/core/agent-session.d.ts +2 -0
  535. package/packages/pi-coding-agent/dist/core/agent-session.d.ts.map +1 -1
  536. package/packages/pi-coding-agent/dist/core/agent-session.js +32 -2
  537. package/packages/pi-coding-agent/dist/core/agent-session.js.map +1 -1
  538. package/packages/pi-coding-agent/dist/core/compaction/compaction.d.ts +25 -0
  539. package/packages/pi-coding-agent/dist/core/compaction/compaction.d.ts.map +1 -1
  540. package/packages/pi-coding-agent/dist/core/compaction/compaction.js +105 -6
  541. package/packages/pi-coding-agent/dist/core/compaction/compaction.js.map +1 -1
  542. package/packages/pi-coding-agent/dist/core/compaction/compaction.test.js +230 -28
  543. package/packages/pi-coding-agent/dist/core/compaction/compaction.test.js.map +1 -1
  544. package/packages/pi-coding-agent/dist/core/compaction/utils.d.ts +30 -2
  545. package/packages/pi-coding-agent/dist/core/compaction/utils.d.ts.map +1 -1
  546. package/packages/pi-coding-agent/dist/core/compaction/utils.js +113 -12
  547. package/packages/pi-coding-agent/dist/core/compaction/utils.js.map +1 -1
  548. package/packages/pi-coding-agent/dist/core/compaction-orchestrator.d.ts +1 -0
  549. package/packages/pi-coding-agent/dist/core/compaction-orchestrator.d.ts.map +1 -1
  550. package/packages/pi-coding-agent/dist/core/compaction-orchestrator.js +29 -18
  551. package/packages/pi-coding-agent/dist/core/compaction-orchestrator.js.map +1 -1
  552. package/packages/pi-coding-agent/dist/core/compaction-orchestrator.test.d.ts +2 -0
  553. package/packages/pi-coding-agent/dist/core/compaction-orchestrator.test.d.ts.map +1 -0
  554. package/packages/pi-coding-agent/dist/core/compaction-orchestrator.test.js +130 -0
  555. package/packages/pi-coding-agent/dist/core/compaction-orchestrator.test.js.map +1 -0
  556. package/packages/pi-coding-agent/dist/core/compaction-utils.test.js +56 -1
  557. package/packages/pi-coding-agent/dist/core/compaction-utils.test.js.map +1 -1
  558. package/packages/pi-coding-agent/dist/core/discovery-cache.test.js +8 -15
  559. package/packages/pi-coding-agent/dist/core/discovery-cache.test.js.map +1 -1
  560. package/packages/pi-coding-agent/dist/core/extensions/extension-discovery.d.ts +25 -0
  561. package/packages/pi-coding-agent/dist/core/extensions/extension-discovery.d.ts.map +1 -0
  562. package/packages/pi-coding-agent/dist/core/extensions/extension-discovery.js +109 -0
  563. package/packages/pi-coding-agent/dist/core/extensions/extension-discovery.js.map +1 -0
  564. package/packages/pi-coding-agent/dist/core/extensions/extension-registry.d.ts +67 -0
  565. package/packages/pi-coding-agent/dist/core/extensions/extension-registry.d.ts.map +1 -0
  566. package/packages/pi-coding-agent/dist/core/extensions/extension-registry.js +167 -0
  567. package/packages/pi-coding-agent/dist/core/extensions/extension-registry.js.map +1 -0
  568. package/packages/pi-coding-agent/dist/core/extensions/index.d.ts +1 -1
  569. package/packages/pi-coding-agent/dist/core/extensions/index.d.ts.map +1 -1
  570. package/packages/pi-coding-agent/dist/core/extensions/index.js.map +1 -1
  571. package/packages/pi-coding-agent/dist/core/extensions/loader.d.ts +8 -2
  572. package/packages/pi-coding-agent/dist/core/extensions/loader.d.ts.map +1 -1
  573. package/packages/pi-coding-agent/dist/core/extensions/loader.js +89 -8
  574. package/packages/pi-coding-agent/dist/core/extensions/loader.js.map +1 -1
  575. package/packages/pi-coding-agent/dist/core/extensions/runner.d.ts +35 -2
  576. package/packages/pi-coding-agent/dist/core/extensions/runner.d.ts.map +1 -1
  577. package/packages/pi-coding-agent/dist/core/extensions/runner.js +233 -0
  578. package/packages/pi-coding-agent/dist/core/extensions/runner.js.map +1 -1
  579. package/packages/pi-coding-agent/dist/core/extensions/types.d.ts +212 -2
  580. package/packages/pi-coding-agent/dist/core/extensions/types.d.ts.map +1 -1
  581. package/packages/pi-coding-agent/dist/core/extensions/types.js.map +1 -1
  582. package/packages/pi-coding-agent/dist/core/hooks-runner.d.ts +53 -0
  583. package/packages/pi-coding-agent/dist/core/hooks-runner.d.ts.map +1 -0
  584. package/packages/pi-coding-agent/dist/core/hooks-runner.js +337 -0
  585. package/packages/pi-coding-agent/dist/core/hooks-runner.js.map +1 -0
  586. package/packages/pi-coding-agent/dist/core/hooks-runner.test.d.ts +2 -0
  587. package/packages/pi-coding-agent/dist/core/hooks-runner.test.d.ts.map +1 -0
  588. package/packages/pi-coding-agent/dist/core/hooks-runner.test.js +234 -0
  589. package/packages/pi-coding-agent/dist/core/hooks-runner.test.js.map +1 -0
  590. package/packages/pi-coding-agent/dist/core/index.d.ts +1 -0
  591. package/packages/pi-coding-agent/dist/core/index.d.ts.map +1 -1
  592. package/packages/pi-coding-agent/dist/core/index.js +1 -0
  593. package/packages/pi-coding-agent/dist/core/index.js.map +1 -1
  594. package/packages/pi-coding-agent/dist/core/lsp/lsp-integration.test.js +41 -4
  595. package/packages/pi-coding-agent/dist/core/lsp/lsp-integration.test.js.map +1 -1
  596. package/packages/pi-coding-agent/dist/core/model-discovery.d.ts +3 -1
  597. package/packages/pi-coding-agent/dist/core/model-discovery.d.ts.map +1 -1
  598. package/packages/pi-coding-agent/dist/core/model-discovery.js +92 -12
  599. package/packages/pi-coding-agent/dist/core/model-discovery.js.map +1 -1
  600. package/packages/pi-coding-agent/dist/core/model-discovery.test.js +16 -1
  601. package/packages/pi-coding-agent/dist/core/model-discovery.test.js.map +1 -1
  602. package/packages/pi-coding-agent/dist/core/model-registry-auth-header.test.d.ts +2 -0
  603. package/packages/pi-coding-agent/dist/core/model-registry-auth-header.test.d.ts.map +1 -0
  604. package/packages/pi-coding-agent/dist/core/model-registry-auth-header.test.js +40 -0
  605. package/packages/pi-coding-agent/dist/core/model-registry-auth-header.test.js.map +1 -0
  606. package/packages/pi-coding-agent/dist/core/model-registry-auth-mode.test.js +19 -2
  607. package/packages/pi-coding-agent/dist/core/model-registry-auth-mode.test.js.map +1 -1
  608. package/packages/pi-coding-agent/dist/core/model-registry-custom-caps.test.d.ts +2 -0
  609. package/packages/pi-coding-agent/dist/core/model-registry-custom-caps.test.d.ts.map +1 -0
  610. package/packages/pi-coding-agent/dist/core/model-registry-custom-caps.test.js +203 -0
  611. package/packages/pi-coding-agent/dist/core/model-registry-custom-caps.test.js.map +1 -0
  612. package/packages/pi-coding-agent/dist/core/model-registry-discovery.test.js +61 -1
  613. package/packages/pi-coding-agent/dist/core/model-registry-discovery.test.js.map +1 -1
  614. package/packages/pi-coding-agent/dist/core/model-registry.d.ts +5 -0
  615. package/packages/pi-coding-agent/dist/core/model-registry.d.ts.map +1 -1
  616. package/packages/pi-coding-agent/dist/core/model-registry.js +90 -10
  617. package/packages/pi-coding-agent/dist/core/model-registry.js.map +1 -1
  618. package/packages/pi-coding-agent/dist/core/redact-secrets.d.ts +2 -0
  619. package/packages/pi-coding-agent/dist/core/redact-secrets.d.ts.map +1 -0
  620. package/packages/pi-coding-agent/dist/core/redact-secrets.js +49 -0
  621. package/packages/pi-coding-agent/dist/core/redact-secrets.js.map +1 -0
  622. package/packages/pi-coding-agent/dist/core/redact-secrets.test.d.ts +2 -0
  623. package/packages/pi-coding-agent/dist/core/redact-secrets.test.d.ts.map +1 -0
  624. package/packages/pi-coding-agent/dist/core/redact-secrets.test.js +67 -0
  625. package/packages/pi-coding-agent/dist/core/redact-secrets.test.js.map +1 -0
  626. package/packages/pi-coding-agent/dist/core/resource-loader-cache-reset.test.js +76 -18
  627. package/packages/pi-coding-agent/dist/core/resource-loader-cache-reset.test.js.map +1 -1
  628. package/packages/pi-coding-agent/dist/core/resource-loader.js +1 -1
  629. package/packages/pi-coding-agent/dist/core/resource-loader.js.map +1 -1
  630. package/packages/pi-coding-agent/dist/core/retry-handler.d.ts.map +1 -1
  631. package/packages/pi-coding-agent/dist/core/retry-handler.js +2 -6
  632. package/packages/pi-coding-agent/dist/core/retry-handler.js.map +1 -1
  633. package/packages/pi-coding-agent/dist/core/retry-handler.test.js +5 -1
  634. package/packages/pi-coding-agent/dist/core/retry-handler.test.js.map +1 -1
  635. package/packages/pi-coding-agent/dist/core/retryable-error-regex.d.ts +18 -0
  636. package/packages/pi-coding-agent/dist/core/retryable-error-regex.d.ts.map +1 -0
  637. package/packages/pi-coding-agent/dist/core/retryable-error-regex.js +18 -0
  638. package/packages/pi-coding-agent/dist/core/retryable-error-regex.js.map +1 -0
  639. package/packages/pi-coding-agent/dist/core/sdk.d.ts +1 -0
  640. package/packages/pi-coding-agent/dist/core/sdk.d.ts.map +1 -1
  641. package/packages/pi-coding-agent/dist/core/sdk.js +4 -1
  642. package/packages/pi-coding-agent/dist/core/sdk.js.map +1 -1
  643. package/packages/pi-coding-agent/dist/core/sdk.test.js +19 -1
  644. package/packages/pi-coding-agent/dist/core/sdk.test.js.map +1 -1
  645. package/packages/pi-coding-agent/dist/core/session-manager.d.ts.map +1 -1
  646. package/packages/pi-coding-agent/dist/core/session-manager.js +10 -6
  647. package/packages/pi-coding-agent/dist/core/session-manager.js.map +1 -1
  648. package/packages/pi-coding-agent/dist/core/session-manager.test.js +45 -1
  649. package/packages/pi-coding-agent/dist/core/session-manager.test.js.map +1 -1
  650. package/packages/pi-coding-agent/dist/core/settings-manager.d.ts +55 -0
  651. package/packages/pi-coding-agent/dist/core/settings-manager.d.ts.map +1 -1
  652. package/packages/pi-coding-agent/dist/core/settings-manager.js.map +1 -1
  653. package/packages/pi-coding-agent/dist/core/system-prompt.d.ts +20 -0
  654. package/packages/pi-coding-agent/dist/core/system-prompt.d.ts.map +1 -1
  655. package/packages/pi-coding-agent/dist/core/system-prompt.js +19 -5
  656. package/packages/pi-coding-agent/dist/core/system-prompt.js.map +1 -1
  657. package/packages/pi-coding-agent/dist/core/tools/path-utils.test.js +2 -1
  658. package/packages/pi-coding-agent/dist/core/tools/path-utils.test.js.map +1 -1
  659. package/packages/pi-coding-agent/dist/index.d.ts +2 -1
  660. package/packages/pi-coding-agent/dist/index.d.ts.map +1 -1
  661. package/packages/pi-coding-agent/dist/index.js +1 -0
  662. package/packages/pi-coding-agent/dist/index.js.map +1 -1
  663. package/packages/pi-coding-agent/dist/modes/interactive/components/__tests__/provider-display-name.test.js +15 -6
  664. package/packages/pi-coding-agent/dist/modes/interactive/components/__tests__/provider-display-name.test.js.map +1 -1
  665. package/packages/pi-coding-agent/dist/modes/interactive/components/__tests__/tool-execution.test.js +36 -5
  666. package/packages/pi-coding-agent/dist/modes/interactive/components/__tests__/tool-execution.test.js.map +1 -1
  667. package/packages/pi-coding-agent/dist/modes/interactive/components/chat-frame.d.ts +1 -1
  668. package/packages/pi-coding-agent/dist/modes/interactive/components/chat-frame.d.ts.map +1 -1
  669. package/packages/pi-coding-agent/dist/modes/interactive/components/chat-frame.js +5 -4
  670. package/packages/pi-coding-agent/dist/modes/interactive/components/chat-frame.js.map +1 -1
  671. package/packages/pi-coding-agent/dist/modes/interactive/components/dynamic-border.test.js +20 -13
  672. package/packages/pi-coding-agent/dist/modes/interactive/components/dynamic-border.test.js.map +1 -1
  673. package/packages/pi-coding-agent/dist/modes/interactive/components/footer.d.ts.map +1 -1
  674. package/packages/pi-coding-agent/dist/modes/interactive/components/footer.js +14 -5
  675. package/packages/pi-coding-agent/dist/modes/interactive/components/footer.js.map +1 -1
  676. package/packages/pi-coding-agent/dist/modes/interactive/components/model-selector.d.ts +7 -1
  677. package/packages/pi-coding-agent/dist/modes/interactive/components/model-selector.d.ts.map +1 -1
  678. package/packages/pi-coding-agent/dist/modes/interactive/components/model-selector.js +31 -9
  679. package/packages/pi-coding-agent/dist/modes/interactive/components/model-selector.js.map +1 -1
  680. package/packages/pi-coding-agent/dist/modes/interactive/components/provider-manager.d.ts.map +1 -1
  681. package/packages/pi-coding-agent/dist/modes/interactive/components/provider-manager.js +13 -7
  682. package/packages/pi-coding-agent/dist/modes/interactive/components/provider-manager.js.map +1 -1
  683. package/packages/pi-coding-agent/dist/modes/interactive/components/skill-invocation-message.d.ts +7 -6
  684. package/packages/pi-coding-agent/dist/modes/interactive/components/skill-invocation-message.d.ts.map +1 -1
  685. package/packages/pi-coding-agent/dist/modes/interactive/components/skill-invocation-message.js +29 -21
  686. package/packages/pi-coding-agent/dist/modes/interactive/components/skill-invocation-message.js.map +1 -1
  687. package/packages/pi-coding-agent/dist/modes/interactive/components/tool-execution.d.ts.map +1 -1
  688. package/packages/pi-coding-agent/dist/modes/interactive/components/tool-execution.js +30 -12
  689. package/packages/pi-coding-agent/dist/modes/interactive/components/tool-execution.js.map +1 -1
  690. package/packages/pi-coding-agent/dist/modes/interactive/controllers/input-controller.d.ts.map +1 -1
  691. package/packages/pi-coding-agent/dist/modes/interactive/controllers/input-controller.js +18 -3
  692. package/packages/pi-coding-agent/dist/modes/interactive/controllers/input-controller.js.map +1 -1
  693. package/packages/pi-coding-agent/dist/modes/interactive/controllers/input-controller.test.js +139 -0
  694. package/packages/pi-coding-agent/dist/modes/interactive/controllers/input-controller.test.js.map +1 -1
  695. package/packages/pi-coding-agent/dist/modes/interactive/interactive-mode-state.d.ts +2 -0
  696. package/packages/pi-coding-agent/dist/modes/interactive/interactive-mode-state.d.ts.map +1 -1
  697. package/packages/pi-coding-agent/dist/modes/interactive/interactive-mode-state.js.map +1 -1
  698. package/packages/pi-coding-agent/dist/modes/interactive/interactive-mode.d.ts +4 -0
  699. package/packages/pi-coding-agent/dist/modes/interactive/interactive-mode.d.ts.map +1 -1
  700. package/packages/pi-coding-agent/dist/modes/interactive/interactive-mode.js +118 -14
  701. package/packages/pi-coding-agent/dist/modes/interactive/interactive-mode.js.map +1 -1
  702. package/packages/pi-coding-agent/dist/tests/system-prompt-skill-filter.test.d.ts +2 -0
  703. package/packages/pi-coding-agent/dist/tests/system-prompt-skill-filter.test.d.ts.map +1 -0
  704. package/packages/pi-coding-agent/dist/tests/system-prompt-skill-filter.test.js +130 -0
  705. package/packages/pi-coding-agent/dist/tests/system-prompt-skill-filter.test.js.map +1 -0
  706. package/packages/pi-coding-agent/package.json +6 -1
  707. package/packages/pi-coding-agent/src/core/agent-session-abort-order.test.ts +113 -36
  708. package/packages/pi-coding-agent/src/core/agent-session-model-switch.test.ts +89 -17
  709. package/packages/pi-coding-agent/src/core/agent-session-tool-refresh.test.ts +112 -43
  710. package/packages/pi-coding-agent/src/core/agent-session.ts +38 -2
  711. package/packages/pi-coding-agent/src/core/compaction/compaction.test.ts +368 -28
  712. package/packages/pi-coding-agent/src/core/compaction/compaction.ts +122 -6
  713. package/packages/pi-coding-agent/src/core/compaction/utils.ts +111 -13
  714. package/packages/pi-coding-agent/src/core/compaction-orchestrator.test.ts +154 -0
  715. package/packages/pi-coding-agent/src/core/compaction-orchestrator.ts +32 -18
  716. package/packages/pi-coding-agent/src/core/compaction-utils.test.ts +68 -1
  717. package/packages/pi-coding-agent/src/core/discovery-cache.test.ts +9 -18
  718. package/packages/pi-coding-agent/src/core/extensions/extension-discovery.ts +119 -0
  719. package/packages/pi-coding-agent/src/core/extensions/extension-registry.ts +222 -0
  720. package/packages/pi-coding-agent/src/core/extensions/index.ts +16 -0
  721. package/packages/pi-coding-agent/src/core/extensions/loader.ts +87 -11
  722. package/packages/pi-coding-agent/src/core/extensions/runner.ts +351 -0
  723. package/packages/pi-coding-agent/src/core/extensions/types.ts +266 -0
  724. package/packages/pi-coding-agent/src/core/hooks-runner.test.ts +269 -0
  725. package/packages/pi-coding-agent/src/core/hooks-runner.ts +460 -0
  726. package/packages/pi-coding-agent/src/core/index.ts +10 -0
  727. package/packages/pi-coding-agent/src/core/lsp/lsp-integration.test.ts +48 -4
  728. package/packages/pi-coding-agent/src/core/model-discovery.test.ts +19 -0
  729. package/packages/pi-coding-agent/src/core/model-discovery.ts +99 -12
  730. package/packages/pi-coding-agent/src/core/model-registry-auth-header.test.ts +44 -0
  731. package/packages/pi-coding-agent/src/core/model-registry-auth-mode.test.ts +22 -2
  732. package/packages/pi-coding-agent/src/core/model-registry-custom-caps.test.ts +245 -0
  733. package/packages/pi-coding-agent/src/core/model-registry-discovery.test.ts +75 -0
  734. package/packages/pi-coding-agent/src/core/model-registry.ts +102 -10
  735. package/packages/pi-coding-agent/src/core/redact-secrets.test.ts +86 -0
  736. package/packages/pi-coding-agent/src/core/redact-secrets.ts +58 -0
  737. package/packages/pi-coding-agent/src/core/resource-loader-cache-reset.test.ts +93 -28
  738. package/packages/pi-coding-agent/src/core/resource-loader.ts +1 -1
  739. package/packages/pi-coding-agent/src/core/retry-handler.test.ts +5 -1
  740. package/packages/pi-coding-agent/src/core/retry-handler.ts +2 -8
  741. package/packages/pi-coding-agent/src/core/retryable-error-regex.ts +18 -0
  742. package/packages/pi-coding-agent/src/core/sdk.test.ts +25 -1
  743. package/packages/pi-coding-agent/src/core/sdk.ts +10 -3
  744. package/packages/pi-coding-agent/src/core/session-manager.test.ts +65 -1
  745. package/packages/pi-coding-agent/src/core/session-manager.ts +10 -6
  746. package/packages/pi-coding-agent/src/core/settings-manager.ts +57 -0
  747. package/packages/pi-coding-agent/src/core/system-prompt.ts +38 -4
  748. package/packages/pi-coding-agent/src/core/tools/path-utils.test.ts +2 -1
  749. package/packages/pi-coding-agent/src/index.ts +17 -0
  750. package/packages/pi-coding-agent/src/modes/interactive/components/__tests__/provider-display-name.test.ts +17 -7
  751. package/packages/pi-coding-agent/src/modes/interactive/components/__tests__/tool-execution.test.ts +49 -3
  752. package/packages/pi-coding-agent/src/modes/interactive/components/chat-frame.ts +6 -6
  753. package/packages/pi-coding-agent/src/modes/interactive/components/dynamic-border.test.ts +26 -20
  754. package/packages/pi-coding-agent/src/modes/interactive/components/footer.ts +14 -5
  755. package/packages/pi-coding-agent/src/modes/interactive/components/model-selector.ts +45 -11
  756. package/packages/pi-coding-agent/src/modes/interactive/components/provider-manager.ts +16 -7
  757. package/packages/pi-coding-agent/src/modes/interactive/components/skill-invocation-message.ts +36 -22
  758. package/packages/pi-coding-agent/src/modes/interactive/components/tool-execution.ts +48 -9
  759. package/packages/pi-coding-agent/src/modes/interactive/controllers/input-controller.test.ts +160 -1
  760. package/packages/pi-coding-agent/src/modes/interactive/controllers/input-controller.ts +20 -3
  761. package/packages/pi-coding-agent/src/modes/interactive/interactive-mode-state.ts +2 -0
  762. package/packages/pi-coding-agent/src/modes/interactive/interactive-mode.ts +132 -14
  763. package/packages/pi-coding-agent/src/tests/system-prompt-skill-filter.test.ts +157 -0
  764. package/packages/pi-coding-agent/tsconfig.tsbuildinfo +1 -1
  765. package/packages/pi-tui/dist/__tests__/autocomplete.test.js +31 -14
  766. package/packages/pi-tui/dist/__tests__/autocomplete.test.js.map +1 -1
  767. package/packages/pi-tui/dist/__tests__/overlay-layout.test.js +128 -17
  768. package/packages/pi-tui/dist/__tests__/overlay-layout.test.js.map +1 -1
  769. package/packages/pi-tui/dist/__tests__/stdin-buffer.test.js +51 -6
  770. package/packages/pi-tui/dist/__tests__/stdin-buffer.test.js.map +1 -1
  771. package/packages/pi-tui/dist/__tests__/tui.test.js +18 -30
  772. package/packages/pi-tui/dist/__tests__/tui.test.js.map +1 -1
  773. package/packages/pi-tui/dist/components/__tests__/input.test.js +10 -3
  774. package/packages/pi-tui/dist/components/__tests__/input.test.js.map +1 -1
  775. package/packages/pi-tui/dist/components/__tests__/loader.test.js +53 -9
  776. package/packages/pi-tui/dist/components/__tests__/loader.test.js.map +1 -1
  777. package/packages/pi-tui/dist/components/__tests__/markdown-maxlines.test.js +6 -2
  778. package/packages/pi-tui/dist/components/__tests__/markdown-maxlines.test.js.map +1 -1
  779. package/packages/pi-tui/dist/components/editor.d.ts +14 -0
  780. package/packages/pi-tui/dist/components/editor.d.ts.map +1 -1
  781. package/packages/pi-tui/dist/components/editor.js +19 -0
  782. package/packages/pi-tui/dist/components/editor.js.map +1 -1
  783. package/packages/pi-tui/dist/components/image.test.js +6 -5
  784. package/packages/pi-tui/dist/components/image.test.js.map +1 -1
  785. package/packages/pi-tui/dist/editor-component.d.ts +2 -0
  786. package/packages/pi-tui/dist/editor-component.d.ts.map +1 -1
  787. package/packages/pi-tui/dist/editor-component.js.map +1 -1
  788. package/packages/pi-tui/dist/stdin-buffer.d.ts +7 -0
  789. package/packages/pi-tui/dist/stdin-buffer.d.ts.map +1 -1
  790. package/packages/pi-tui/dist/stdin-buffer.js +20 -0
  791. package/packages/pi-tui/dist/stdin-buffer.js.map +1 -1
  792. package/packages/pi-tui/package.json +6 -1
  793. package/packages/pi-tui/src/__tests__/autocomplete.test.ts +46 -15
  794. package/packages/pi-tui/src/__tests__/overlay-layout.test.ts +140 -17
  795. package/packages/pi-tui/src/__tests__/stdin-buffer.test.ts +62 -6
  796. package/packages/pi-tui/src/__tests__/tui.test.ts +18 -37
  797. package/packages/pi-tui/src/components/__tests__/input.test.ts +19 -3
  798. package/packages/pi-tui/src/components/__tests__/loader.test.ts +112 -35
  799. package/packages/pi-tui/src/components/__tests__/markdown-maxlines.test.ts +9 -2
  800. package/packages/pi-tui/src/components/editor.ts +22 -0
  801. package/packages/pi-tui/src/components/image.test.ts +10 -5
  802. package/packages/pi-tui/src/editor-component.ts +3 -0
  803. package/packages/pi-tui/src/stdin-buffer.ts +26 -0
  804. package/packages/pi-tui/tsconfig.tsbuildinfo +1 -1
  805. package/packages/rpc-client/dist/rpc-client.test.js +101 -51
  806. package/packages/rpc-client/dist/rpc-client.test.js.map +1 -1
  807. package/packages/rpc-client/package.json +6 -1
  808. package/packages/rpc-client/src/rpc-client.test.ts +109 -52
  809. package/packages/rpc-client/tsconfig.tsbuildinfo +1 -1
  810. package/pkg/package.json +1 -1
  811. package/scripts/install.js +526 -0
  812. package/scripts/lib/workspace-manifest.cjs +86 -0
  813. package/scripts/link-workspace-packages.cjs +5 -16
  814. package/scripts/postinstall.js +9 -178
  815. package/src/resources/agents/researcher.md +1 -1
  816. package/src/resources/extensions/browser-tools/capture.ts +12 -0
  817. package/src/resources/extensions/browser-tools/tests/browser-tools-integration.test.mjs +8 -59
  818. package/src/resources/extensions/browser-tools/tests/browser-tools-unit.test.cjs +36 -24
  819. package/src/resources/extensions/browser-tools/tests/capture-sharp-optional.test.cjs +69 -71
  820. package/src/resources/extensions/browser-tools/tools/forms.ts +5 -1
  821. package/src/resources/extensions/browser-tools/tools/intent.ts +5 -1
  822. package/src/resources/extensions/claude-code-cli/readiness.ts +36 -8
  823. package/src/resources/extensions/claude-code-cli/stream-adapter.ts +676 -86
  824. package/src/resources/extensions/claude-code-cli/tests/stream-adapter.test.ts +1170 -89
  825. package/src/resources/extensions/cmux/index.ts +35 -10
  826. package/src/resources/extensions/github-sync/templates.ts +151 -0
  827. package/src/resources/extensions/github-sync/tests/cli.test.ts +76 -7
  828. package/src/resources/extensions/github-sync/tests/templates.test.ts +92 -1
  829. package/src/resources/extensions/google-search/extension-manifest.json +5 -4
  830. package/src/resources/extensions/google-search/index.ts +9 -470
  831. package/src/resources/extensions/gsd/abandon-detect.ts +62 -0
  832. package/src/resources/extensions/gsd/auto/loop-deps.ts +15 -1
  833. package/src/resources/extensions/gsd/auto/loop.ts +151 -2
  834. package/src/resources/extensions/gsd/auto/phases.ts +192 -47
  835. package/src/resources/extensions/gsd/auto/resolve.ts +29 -0
  836. package/src/resources/extensions/gsd/auto/run-unit.ts +56 -4
  837. package/src/resources/extensions/gsd/auto/session.ts +42 -4
  838. package/src/resources/extensions/gsd/auto/turn-epoch.ts +108 -0
  839. package/src/resources/extensions/gsd/auto/types.ts +1 -1
  840. package/src/resources/extensions/gsd/auto-dispatch.ts +229 -39
  841. package/src/resources/extensions/gsd/auto-loop.ts +1 -1
  842. package/src/resources/extensions/gsd/auto-model-selection.ts +202 -19
  843. package/src/resources/extensions/gsd/auto-post-unit.ts +255 -76
  844. package/src/resources/extensions/gsd/auto-prompts.ts +413 -94
  845. package/src/resources/extensions/gsd/auto-recovery.ts +125 -2
  846. package/src/resources/extensions/gsd/auto-start.ts +206 -82
  847. package/src/resources/extensions/gsd/auto-timeout-recovery.ts +12 -5
  848. package/src/resources/extensions/gsd/auto-tool-tracking.ts +51 -7
  849. package/src/resources/extensions/gsd/auto-unit-closeout.ts +14 -3
  850. package/src/resources/extensions/gsd/auto-verification.ts +33 -0
  851. package/src/resources/extensions/gsd/auto-worktree.ts +251 -93
  852. package/src/resources/extensions/gsd/auto.ts +192 -61
  853. package/src/resources/extensions/gsd/blocked-models.ts +98 -0
  854. package/src/resources/extensions/gsd/bootstrap/agent-end-recovery.ts +140 -2
  855. package/src/resources/extensions/gsd/bootstrap/db-tools.ts +261 -9
  856. package/src/resources/extensions/gsd/bootstrap/exec-tools.ts +109 -0
  857. package/src/resources/extensions/gsd/bootstrap/memory-tools.ts +5 -0
  858. package/src/resources/extensions/gsd/bootstrap/provider-error-resume.ts +6 -6
  859. package/src/resources/extensions/gsd/bootstrap/register-extension.ts +26 -0
  860. package/src/resources/extensions/gsd/bootstrap/register-hooks.ts +61 -9
  861. package/src/resources/extensions/gsd/bootstrap/system-context.ts +102 -35
  862. package/src/resources/extensions/gsd/bootstrap/write-gate.ts +193 -11
  863. package/src/resources/extensions/gsd/clean-root-preflight.ts +111 -0
  864. package/src/resources/extensions/gsd/commands/handlers/workflow.ts +27 -8
  865. package/src/resources/extensions/gsd/commands-cmux.ts +10 -6
  866. package/src/resources/extensions/gsd/commands-extensions.ts +747 -41
  867. package/src/resources/extensions/gsd/commands-extract-learnings.ts +55 -90
  868. package/src/resources/extensions/gsd/commands-prefs-wizard.ts +898 -32
  869. package/src/resources/extensions/gsd/compaction-snapshot.ts +165 -0
  870. package/src/resources/extensions/gsd/complexity-classifier.ts +5 -3
  871. package/src/resources/extensions/gsd/component-loader.ts +598 -0
  872. package/src/resources/extensions/gsd/component-types.ts +362 -0
  873. package/src/resources/extensions/gsd/context-store.ts +25 -8
  874. package/src/resources/extensions/gsd/db-writer.ts +88 -17
  875. package/src/resources/extensions/gsd/detection.ts +58 -1
  876. package/src/resources/extensions/gsd/dispatch-guard.ts +26 -2
  877. package/src/resources/extensions/gsd/docs/preferences-reference.md +1 -1
  878. package/src/resources/extensions/gsd/doctor-git-checks.ts +23 -27
  879. package/src/resources/extensions/gsd/doctor-providers.ts +59 -6
  880. package/src/resources/extensions/gsd/ecosystem/gsd-extension-api.ts +2 -0
  881. package/src/resources/extensions/gsd/error-classifier.ts +36 -3
  882. package/src/resources/extensions/gsd/exec-history.ts +153 -0
  883. package/src/resources/extensions/gsd/exec-sandbox.ts +326 -0
  884. package/src/resources/extensions/gsd/file-lock.ts +84 -11
  885. package/src/resources/extensions/gsd/forensics.ts +118 -1
  886. package/src/resources/extensions/gsd/gate-registry.ts +2 -2
  887. package/src/resources/extensions/gsd/git-constants.ts +30 -1
  888. package/src/resources/extensions/gsd/git-self-heal.ts +31 -0
  889. package/src/resources/extensions/gsd/git-service.ts +150 -2
  890. package/src/resources/extensions/gsd/gitignore.ts +2 -1
  891. package/src/resources/extensions/gsd/gsd-db.ts +191 -25
  892. package/src/resources/extensions/gsd/guided-flow-queue.ts +4 -1
  893. package/src/resources/extensions/gsd/guided-flow.ts +261 -14
  894. package/src/resources/extensions/gsd/health-widget.ts +3 -1
  895. package/src/resources/extensions/gsd/hook-emitter.ts +188 -0
  896. package/src/resources/extensions/gsd/init-wizard.ts +15 -1
  897. package/src/resources/extensions/gsd/journal.ts +39 -3
  898. package/src/resources/extensions/gsd/key-manager.ts +28 -0
  899. package/src/resources/extensions/gsd/memory-backfill.ts +140 -0
  900. package/src/resources/extensions/gsd/memory-extractor.ts +11 -3
  901. package/src/resources/extensions/gsd/memory-store.ts +26 -0
  902. package/src/resources/extensions/gsd/milestone-actions.ts +18 -0
  903. package/src/resources/extensions/gsd/milestone-scope-classifier.ts +366 -0
  904. package/src/resources/extensions/gsd/milestone-summary-classifier.ts +42 -0
  905. package/src/resources/extensions/gsd/model-cost-table.ts +3 -0
  906. package/src/resources/extensions/gsd/model-router.ts +48 -1
  907. package/src/resources/extensions/gsd/native-git-bridge.ts +34 -4
  908. package/src/resources/extensions/gsd/notifications.ts +27 -15
  909. package/src/resources/extensions/gsd/pre-execution-checks.ts +46 -10
  910. package/src/resources/extensions/gsd/preferences-types.ts +46 -0
  911. package/src/resources/extensions/gsd/preferences-validation.ts +100 -0
  912. package/src/resources/extensions/gsd/preferences.ts +17 -17
  913. package/src/resources/extensions/gsd/prompt-cache-optimizer.ts +4 -0
  914. package/src/resources/extensions/gsd/prompt-loader.ts +30 -7
  915. package/src/resources/extensions/gsd/prompts/complete-milestone.md +6 -2
  916. package/src/resources/extensions/gsd/prompts/complete-slice.md +2 -2
  917. package/src/resources/extensions/gsd/prompts/debug-diagnose.md +2 -0
  918. package/src/resources/extensions/gsd/prompts/discuss-headless.md +29 -2
  919. package/src/resources/extensions/gsd/prompts/discuss.md +29 -2
  920. package/src/resources/extensions/gsd/prompts/doctor-heal.md +5 -4
  921. package/src/resources/extensions/gsd/prompts/execute-task.md +3 -2
  922. package/src/resources/extensions/gsd/prompts/parallel-research-slices.md +5 -2
  923. package/src/resources/extensions/gsd/prompts/plan-slice.md +16 -2
  924. package/src/resources/extensions/gsd/prompts/research-slice.md +1 -0
  925. package/src/resources/extensions/gsd/prompts/system.md +1 -0
  926. package/src/resources/extensions/gsd/reports.ts +5 -4
  927. package/src/resources/extensions/gsd/safety/evidence-collector.ts +119 -0
  928. package/src/resources/extensions/gsd/safety/file-change-validator.ts +17 -4
  929. package/src/resources/extensions/gsd/safety/git-checkpoint.ts +15 -0
  930. package/src/resources/extensions/gsd/safety/safety-harness.ts +9 -0
  931. package/src/resources/extensions/gsd/service-tier.ts +5 -2
  932. package/src/resources/extensions/gsd/session-lock.ts +20 -10
  933. package/src/resources/extensions/gsd/skill-manifest.ts +175 -0
  934. package/src/resources/extensions/gsd/slice-cadence.ts +299 -0
  935. package/src/resources/extensions/gsd/slice-parallel-orchestrator.ts +309 -8
  936. package/src/resources/extensions/gsd/state-transition-matrix.ts +152 -0
  937. package/src/resources/extensions/gsd/state.ts +121 -70
  938. package/src/resources/extensions/gsd/sync-lock.ts +97 -39
  939. package/src/resources/extensions/gsd/tests/artifact-retry-cap.test.ts +270 -0
  940. package/src/resources/extensions/gsd/tests/artifacts-table-preserved-on-cache-invalidate.test.ts +2 -1
  941. package/src/resources/extensions/gsd/tests/auto-deterministic-error-classification-4973.test.ts +341 -0
  942. package/src/resources/extensions/gsd/tests/auto-discuss-milestone-deadlock-4973.test.ts +264 -0
  943. package/src/resources/extensions/gsd/tests/auto-loop.test.ts +322 -286
  944. package/src/resources/extensions/gsd/tests/auto-mode-guards.test.ts +79 -0
  945. package/src/resources/extensions/gsd/tests/auto-model-selection-tool-poisoning.test.ts +742 -0
  946. package/src/resources/extensions/gsd/tests/auto-model-selection.test.ts +173 -1
  947. package/src/resources/extensions/gsd/tests/auto-paused-session-validation.test.ts +12 -0
  948. package/src/resources/extensions/gsd/tests/auto-phases-lifecycle.test.ts +61 -0
  949. package/src/resources/extensions/gsd/tests/auto-recovery.test.ts +122 -0
  950. package/src/resources/extensions/gsd/tests/auto-remediate-slice-status.test.ts +4 -1
  951. package/src/resources/extensions/gsd/tests/auto-retry-mcp-churn-fixes.test.ts +8 -194
  952. package/src/resources/extensions/gsd/tests/auto-start-bootstrap-await-3420.test.ts +141 -0
  953. package/src/resources/extensions/gsd/tests/auto-start-clean-runtime-db-gated.test.ts +64 -0
  954. package/src/resources/extensions/gsd/tests/auto-start-cold-db-bootstrap.test.ts +2 -2
  955. package/src/resources/extensions/gsd/tests/auto-start-needs-discussion.test.ts +15 -58
  956. package/src/resources/extensions/gsd/tests/auto-start-worktree-db-path.test.ts +2 -2
  957. package/src/resources/extensions/gsd/tests/auto-thinking-restore.test.ts +39 -0
  958. package/src/resources/extensions/gsd/tests/auto-warning-noise-regression.test.ts +3 -2
  959. package/src/resources/extensions/gsd/tests/auto-wrapup-inflight-guard.test.ts +23 -0
  960. package/src/resources/extensions/gsd/tests/blocked-models.test.ts +98 -0
  961. package/src/resources/extensions/gsd/tests/bootstrap-derive-state-db-open.test.ts +2 -1
  962. package/src/resources/extensions/gsd/tests/bundled-skill-triggers.test.ts +54 -0
  963. package/src/resources/extensions/gsd/tests/cache-staleness-regression.test.ts +17 -21
  964. package/src/resources/extensions/gsd/tests/canonical-milestone-root.test.ts +108 -0
  965. package/src/resources/extensions/gsd/tests/clean-root-preflight.test.ts +186 -0
  966. package/src/resources/extensions/gsd/tests/cmux.test.ts +5 -9
  967. package/src/resources/extensions/gsd/tests/commands-extract-learnings.test.ts +68 -66
  968. package/src/resources/extensions/gsd/tests/compaction-snapshot.test.ts +123 -0
  969. package/src/resources/extensions/gsd/tests/complete-milestone-excerpt.test.ts +263 -0
  970. package/src/resources/extensions/gsd/tests/complete-milestone.test.ts +61 -1
  971. package/src/resources/extensions/gsd/tests/complete-slice-composer.test.ts +192 -0
  972. package/src/resources/extensions/gsd/tests/complete-slice-verification-gate.test.ts +2 -1
  973. package/src/resources/extensions/gsd/tests/complete-slice.test.ts +2 -2
  974. package/src/resources/extensions/gsd/tests/complete-task.test.ts +16 -8
  975. package/src/resources/extensions/gsd/tests/complexity-classifier.test.ts +3 -3
  976. package/src/resources/extensions/gsd/tests/component-loader.test.ts +589 -0
  977. package/src/resources/extensions/gsd/tests/component-types.test.ts +127 -0
  978. package/src/resources/extensions/gsd/tests/context-store.test.ts +79 -0
  979. package/src/resources/extensions/gsd/tests/copy-planning-artifacts-samepath.test.ts +2 -1
  980. package/src/resources/extensions/gsd/tests/crash-recovery.test.ts +50 -1
  981. package/src/resources/extensions/gsd/tests/custom-engine-loop-integration.test.ts +161 -0
  982. package/src/resources/extensions/gsd/tests/db-access-guardrails.test.ts +1 -0
  983. package/src/resources/extensions/gsd/tests/derive-state-crossval.test.ts +3 -3
  984. package/src/resources/extensions/gsd/tests/derive-state-db-disk-reconcile.test.ts +40 -0
  985. package/src/resources/extensions/gsd/tests/derive-state-db.test.ts +133 -3
  986. package/src/resources/extensions/gsd/tests/derive-state-helpers.test.ts +8 -4
  987. package/src/resources/extensions/gsd/tests/derive-state.test.ts +4 -4
  988. package/src/resources/extensions/gsd/tests/discuss-slice-structured-questions.test.ts +2 -1
  989. package/src/resources/extensions/gsd/tests/discuss-tool-scope-leak.test.ts +2 -1
  990. package/src/resources/extensions/gsd/tests/dispatch-complete-milestone-guard.test.ts +14 -9
  991. package/src/resources/extensions/gsd/tests/dispatch-guard-summary-db-mismatch.test.ts +77 -0
  992. package/src/resources/extensions/gsd/tests/dispatch-guard.test.ts +25 -0
  993. package/src/resources/extensions/gsd/tests/dispatch-missing-task-plans.test.ts +14 -0
  994. package/src/resources/extensions/gsd/tests/dispatcher-stuck-planning.test.ts +3 -2
  995. package/src/resources/extensions/gsd/tests/doctor-providers.test.ts +148 -3
  996. package/src/resources/extensions/gsd/tests/double-merge-guard.test.ts +4 -3
  997. package/src/resources/extensions/gsd/tests/empty-content-abort-loop.test.ts +4 -3
  998. package/src/resources/extensions/gsd/tests/ensure-db-open.test.ts +306 -1
  999. package/src/resources/extensions/gsd/tests/escalation.test.ts +1 -1
  1000. package/src/resources/extensions/gsd/tests/exec-history.test.ts +237 -0
  1001. package/src/resources/extensions/gsd/tests/exec-sandbox.test.ts +210 -0
  1002. package/src/resources/extensions/gsd/tests/execution-entry-missing-context-4671.test.ts +173 -0
  1003. package/src/resources/extensions/gsd/tests/extension-bootstrap-isolation.test.ts +139 -129
  1004. package/src/resources/extensions/gsd/tests/file-change-validator.test.ts +58 -0
  1005. package/src/resources/extensions/gsd/tests/file-lock.test.ts +86 -12
  1006. package/src/resources/extensions/gsd/tests/finalize-timeout-guard.test.ts +8 -104
  1007. package/src/resources/extensions/gsd/tests/flat-rate-routing-guard.test.ts +40 -9
  1008. package/src/resources/extensions/gsd/tests/freeform-decisions.test.ts +62 -0
  1009. package/src/resources/extensions/gsd/tests/gate-state-canonicalization.test.ts +102 -0
  1010. package/src/resources/extensions/gsd/tests/gate-storage.test.ts +1 -1
  1011. package/src/resources/extensions/gsd/tests/google-search-stub.test.ts +131 -0
  1012. package/src/resources/extensions/gsd/tests/gsd-db.test.ts +447 -1
  1013. package/src/resources/extensions/gsd/tests/headless-milestone-parity.test.ts +117 -0
  1014. package/src/resources/extensions/gsd/tests/hook-key-parsing.test.ts +4 -55
  1015. package/src/resources/extensions/gsd/tests/init-wizard.test.ts +27 -0
  1016. package/src/resources/extensions/gsd/tests/integration/all-milestones-complete-merge.test.ts +7 -56
  1017. package/src/resources/extensions/gsd/tests/integration/auto-worktree-milestone-merge.test.ts +30 -0
  1018. package/src/resources/extensions/gsd/tests/integration/doctor-git-symlink-cwd.test.ts +11 -0
  1019. package/src/resources/extensions/gsd/tests/integration/doctor-git.test.ts +78 -0
  1020. package/src/resources/extensions/gsd/tests/integration/doctor-proactive.test.ts +18 -2
  1021. package/src/resources/extensions/gsd/tests/integration/git-service.test.ts +4 -2
  1022. package/src/resources/extensions/gsd/tests/integration/gitignore-tracked-gsd.test.ts +1 -0
  1023. package/src/resources/extensions/gsd/tests/integration/idle-recovery.test.ts +30 -0
  1024. package/src/resources/extensions/gsd/tests/integration/queue-completed-milestone-perf.test.ts +10 -4
  1025. package/src/resources/extensions/gsd/tests/integration/state-machine-edge-cases.test.ts +144 -7
  1026. package/src/resources/extensions/gsd/tests/integration/state-machine-live-validation.test.ts +4 -0
  1027. package/src/resources/extensions/gsd/tests/integration/state-machine-runtime-failures.test.ts +2 -16
  1028. package/src/resources/extensions/gsd/tests/integration/worktree-e2e.test.ts +11 -0
  1029. package/src/resources/extensions/gsd/tests/interactive-routing-bypass.test.ts +9 -3
  1030. package/src/resources/extensions/gsd/tests/interrupted-session-ui.test.ts +6 -9
  1031. package/src/resources/extensions/gsd/tests/isolation-none-branch-guard.test.ts +1 -1
  1032. package/src/resources/extensions/gsd/tests/issue-4540-regressions.test.ts +288 -0
  1033. package/src/resources/extensions/gsd/tests/journal-integration.test.ts +101 -0
  1034. package/src/resources/extensions/gsd/tests/key-manager.test.ts +9 -0
  1035. package/src/resources/extensions/gsd/tests/knowledge.test.ts +93 -1
  1036. package/src/resources/extensions/gsd/tests/load-memory-block.test.ts +36 -0
  1037. package/src/resources/extensions/gsd/tests/mcp-client-security.test.ts +47 -0
  1038. package/src/resources/extensions/gsd/tests/md-importer.test.ts +1 -1
  1039. package/src/resources/extensions/gsd/tests/memory-extractor.test.ts +5 -15
  1040. package/src/resources/extensions/gsd/tests/memory-pressure-stuck-state.test.ts +12 -0
  1041. package/src/resources/extensions/gsd/tests/memory-store.test.ts +2 -2
  1042. package/src/resources/extensions/gsd/tests/merge-conflict-stops-loop.test.ts +227 -55
  1043. package/src/resources/extensions/gsd/tests/milestone-scope-classifier.test.ts +187 -0
  1044. package/src/resources/extensions/gsd/tests/milestone-status-authoritative.test.ts +3 -3
  1045. package/src/resources/extensions/gsd/tests/milestone-summary-classifier.test.ts +30 -0
  1046. package/src/resources/extensions/gsd/tests/milestone-transition-state-rebuild.test.ts +4 -2
  1047. package/src/resources/extensions/gsd/tests/model-cost-table.test.ts +9 -1
  1048. package/src/resources/extensions/gsd/tests/model-router.test.ts +1 -1
  1049. package/src/resources/extensions/gsd/tests/native-git-bridge-exec-fallback.test.ts +6 -48
  1050. package/src/resources/extensions/gsd/tests/notification-widget.test.ts +6 -3
  1051. package/src/resources/extensions/gsd/tests/orphaned-worktree-audit.test.ts +59 -2
  1052. package/src/resources/extensions/gsd/tests/parallel-commit-scope.test.ts +5 -0
  1053. package/src/resources/extensions/gsd/tests/parallel-research-dispatch.test.ts +274 -112
  1054. package/src/resources/extensions/gsd/tests/parallel-skill-prompt-integration.test.ts +150 -0
  1055. package/src/resources/extensions/gsd/tests/pipeline-variant-dispatch.test.ts +301 -0
  1056. package/src/resources/extensions/gsd/tests/plan-gate-failed-doctor-heal-hint.test.ts +37 -0
  1057. package/src/resources/extensions/gsd/tests/pre-exec-backtick-strip.test.ts +14 -0
  1058. package/src/resources/extensions/gsd/tests/pre-exec-gate-loop.test.ts +272 -0
  1059. package/src/resources/extensions/gsd/tests/pre-execution-checks.test.ts +356 -0
  1060. package/src/resources/extensions/gsd/tests/pre-execution-pause-wiring.test.ts +32 -1
  1061. package/src/resources/extensions/gsd/tests/preferences-worktree-sync.test.ts +2 -1
  1062. package/src/resources/extensions/gsd/tests/preferences.test.ts +110 -0
  1063. package/src/resources/extensions/gsd/tests/prefs-wizard-coverage.test.ts +44 -0
  1064. package/src/resources/extensions/gsd/tests/prompt-cache-optimizer.test.ts +12 -0
  1065. package/src/resources/extensions/gsd/tests/prompt-loader-extension-dir.test.ts +49 -0
  1066. package/src/resources/extensions/gsd/tests/prompt-step-ordering.test.ts +15 -4
  1067. package/src/resources/extensions/gsd/tests/provider-errors.test.ts +157 -45
  1068. package/src/resources/extensions/gsd/tests/queue-auto-guard.test.ts +213 -0
  1069. package/src/resources/extensions/gsd/tests/queue-draft-detection.test.ts +3 -2
  1070. package/src/resources/extensions/gsd/tests/queued-discuss-fast-path.test.ts +4 -5
  1071. package/src/resources/extensions/gsd/tests/quick-auto-guard.test.ts +13 -7
  1072. package/src/resources/extensions/gsd/tests/ready-phrase-no-files-4573.test.ts +388 -0
  1073. package/src/resources/extensions/gsd/tests/reassess-default-optin.test.ts +132 -0
  1074. package/src/resources/extensions/gsd/tests/recovery-attempts-reset.test.ts +8 -40
  1075. package/src/resources/extensions/gsd/tests/regex-hardening.test.ts +136 -256
  1076. package/src/resources/extensions/gsd/tests/require-slice-discussion-dispatch.test.ts +170 -0
  1077. package/src/resources/extensions/gsd/tests/research-milestone-composer.test.ts +114 -0
  1078. package/src/resources/extensions/gsd/tests/restore-tools-after-discuss.test.ts +15 -6
  1079. package/src/resources/extensions/gsd/tests/resume-dispatch-worktree.test.ts +230 -0
  1080. package/src/resources/extensions/gsd/tests/rewrite-docs-abandon-detect.test.ts +195 -0
  1081. package/src/resources/extensions/gsd/tests/run-uat-composer.test.ts +148 -0
  1082. package/src/resources/extensions/gsd/tests/safety-harness-false-positives.test.ts +205 -0
  1083. package/src/resources/extensions/gsd/tests/save-gate-result-render.test.ts +95 -0
  1084. package/src/resources/extensions/gsd/tests/schema-v21-sequence.test.ts +413 -0
  1085. package/src/resources/extensions/gsd/tests/service-tier.test.ts +4 -0
  1086. package/src/resources/extensions/gsd/tests/session-lock-regression.test.ts +29 -0
  1087. package/src/resources/extensions/gsd/tests/session-start-footer.test.ts +32 -40
  1088. package/src/resources/extensions/gsd/tests/sidecar-queue.test.ts +3 -2
  1089. package/src/resources/extensions/gsd/tests/silent-catch-diagnostics.test.ts +55 -95
  1090. package/src/resources/extensions/gsd/tests/single-writer-v3-tool-surface.test.ts +158 -0
  1091. package/src/resources/extensions/gsd/tests/skill-activation.test.ts +120 -1
  1092. package/src/resources/extensions/gsd/tests/skill-manifest.test.ts +112 -0
  1093. package/src/resources/extensions/gsd/tests/slice-cadence.test.ts +242 -0
  1094. package/src/resources/extensions/gsd/tests/slice-context-injection.test.ts +3 -2
  1095. package/src/resources/extensions/gsd/tests/slice-parallel-orchestrator.test.ts +164 -1
  1096. package/src/resources/extensions/gsd/tests/smart-entry-draft.test.ts +2 -1
  1097. package/src/resources/extensions/gsd/tests/stale-dirlistcache-4648.test.ts +112 -0
  1098. package/src/resources/extensions/gsd/tests/stash-queued-context-files.test.ts +56 -0
  1099. package/src/resources/extensions/gsd/tests/state-machine-full-walkthrough.test.ts +29 -5
  1100. package/src/resources/extensions/gsd/tests/state-transition-matrix.test.ts +44 -0
  1101. package/src/resources/extensions/gsd/tests/stop-auto-race-null-unit.test.ts +3 -3
  1102. package/src/resources/extensions/gsd/tests/structured-data-formatter.test.ts +11 -92
  1103. package/src/resources/extensions/gsd/tests/stuck-detection-coverage.test.ts +2 -2
  1104. package/src/resources/extensions/gsd/tests/subagent-model-dispatch.test.ts +7 -6
  1105. package/src/resources/extensions/gsd/tests/survivor-branch-complete.test.ts +102 -101
  1106. package/src/resources/extensions/gsd/tests/sync-lock.test.ts +31 -0
  1107. package/src/resources/extensions/gsd/tests/sync-worktree-skip-current.test.ts +4 -3
  1108. package/src/resources/extensions/gsd/tests/test-helpers.test.ts +98 -0
  1109. package/src/resources/extensions/gsd/tests/test-helpers.ts +153 -0
  1110. package/src/resources/extensions/gsd/tests/token-counter.test.ts +105 -1
  1111. package/src/resources/extensions/gsd/tests/token-profile.test.ts +8 -1
  1112. package/src/resources/extensions/gsd/tests/tool-compatibility.test.ts +107 -0
  1113. package/src/resources/extensions/gsd/tests/tool-invocation-error-loop-break.test.ts +61 -1
  1114. package/src/resources/extensions/gsd/tests/tool-naming.test.ts +8 -1
  1115. package/src/resources/extensions/gsd/tests/triage-resolution.test.ts +50 -2
  1116. package/src/resources/extensions/gsd/tests/turn-epoch.test.ts +162 -0
  1117. package/src/resources/extensions/gsd/tests/unit-context-composer.test.ts +355 -0
  1118. package/src/resources/extensions/gsd/tests/unit-context-manifest.test.ts +258 -0
  1119. package/src/resources/extensions/gsd/tests/uok-contracts.test.ts +51 -0
  1120. package/src/resources/extensions/gsd/tests/uok-execution-graph.test.ts +16 -0
  1121. package/src/resources/extensions/gsd/tests/uok-gate-runner.test.ts +75 -0
  1122. package/src/resources/extensions/gsd/tests/uok-gitops-wiring.test.ts +49 -26
  1123. package/src/resources/extensions/gsd/tests/uok-loop-adapter-writer.test.ts +65 -0
  1124. package/src/resources/extensions/gsd/tests/uok-parity-report.test.ts +42 -0
  1125. package/src/resources/extensions/gsd/tests/uok-plan-v2-wiring.test.ts +42 -2
  1126. package/src/resources/extensions/gsd/tests/uok-writer.test.ts +75 -0
  1127. package/src/resources/extensions/gsd/tests/validate-extension-package.test.ts +168 -0
  1128. package/src/resources/extensions/gsd/tests/validate-milestone.test.ts +148 -8
  1129. package/src/resources/extensions/gsd/tests/verify-artifact-tightened.test.ts +144 -80
  1130. package/src/resources/extensions/gsd/tests/visualizer-critical-path.test.ts +20 -54
  1131. package/src/resources/extensions/gsd/tests/visualizer-overlay.test.ts +342 -277
  1132. package/src/resources/extensions/gsd/tests/worker-model-override.test.ts +37 -29
  1133. package/src/resources/extensions/gsd/tests/workflow-mcp.test.ts +25 -2
  1134. package/src/resources/extensions/gsd/tests/workflow-tool-executors.test.ts +65 -2
  1135. package/src/resources/extensions/gsd/tests/worktree-db.test.ts +242 -247
  1136. package/src/resources/extensions/gsd/tests/worktree-health-monorepo.test.ts +103 -67
  1137. package/src/resources/extensions/gsd/tests/worktree-journal-events.test.ts +6 -1
  1138. package/src/resources/extensions/gsd/tests/worktree-nested-git-safety.test.ts +92 -90
  1139. package/src/resources/extensions/gsd/tests/worktree-resolver.test.ts +78 -5
  1140. package/src/resources/extensions/gsd/tests/worktree-submodule-safety.test.ts +238 -59
  1141. package/src/resources/extensions/gsd/tests/worktree-sync-overwrite-loop.test.ts +113 -161
  1142. package/src/resources/extensions/gsd/tests/worktree-telemetry.test.ts +210 -0
  1143. package/src/resources/extensions/gsd/tests/write-gate-planning-unit.test.ts +262 -0
  1144. package/src/resources/extensions/gsd/tests/write-gate-predicates.test.ts +186 -0
  1145. package/src/resources/extensions/gsd/tests/write-gate.test.ts +71 -5
  1146. package/src/resources/extensions/gsd/tests/zombie-gsd-state.test.ts +80 -94
  1147. package/src/resources/extensions/gsd/token-counter.ts +22 -5
  1148. package/src/resources/extensions/gsd/tools/complete-milestone.ts +15 -9
  1149. package/src/resources/extensions/gsd/tools/complete-slice.ts +38 -0
  1150. package/src/resources/extensions/gsd/tools/complete-task.ts +49 -0
  1151. package/src/resources/extensions/gsd/tools/exec-search-tool.ts +81 -0
  1152. package/src/resources/extensions/gsd/tools/exec-tool.ts +183 -0
  1153. package/src/resources/extensions/gsd/tools/memory-tools.ts +31 -1
  1154. package/src/resources/extensions/gsd/tools/resume-tool.ts +40 -0
  1155. package/src/resources/extensions/gsd/tools/validate-milestone.ts +8 -2
  1156. package/src/resources/extensions/gsd/types.ts +3 -3
  1157. package/src/resources/extensions/gsd/unit-context-composer.ts +218 -0
  1158. package/src/resources/extensions/gsd/unit-context-manifest.ts +574 -0
  1159. package/src/resources/extensions/gsd/uok/audit.ts +20 -2
  1160. package/src/resources/extensions/gsd/uok/contracts.ts +65 -0
  1161. package/src/resources/extensions/gsd/uok/dispatch-envelope.ts +56 -0
  1162. package/src/resources/extensions/gsd/uok/execution-graph.ts +22 -0
  1163. package/src/resources/extensions/gsd/uok/gate-runner.ts +65 -5
  1164. package/src/resources/extensions/gsd/uok/gitops.ts +6 -1
  1165. package/src/resources/extensions/gsd/uok/loop-adapter.ts +45 -10
  1166. package/src/resources/extensions/gsd/uok/parity-report.ts +84 -0
  1167. package/src/resources/extensions/gsd/uok/plan-v2.ts +39 -8
  1168. package/src/resources/extensions/gsd/uok/writer.ts +113 -0
  1169. package/src/resources/extensions/gsd/workflow-logger.ts +25 -3
  1170. package/src/resources/extensions/gsd/workflow-mcp.ts +9 -0
  1171. package/src/resources/extensions/gsd/workflow-templates/spike.md +6 -0
  1172. package/src/resources/extensions/gsd/worktree-manager.ts +109 -7
  1173. package/src/resources/extensions/gsd/worktree-resolver.ts +150 -18
  1174. package/src/resources/extensions/gsd/worktree-telemetry.ts +322 -0
  1175. package/src/resources/extensions/mcp-client/auth.ts +12 -1
  1176. package/src/resources/extensions/mcp-client/index.ts +132 -11
  1177. package/src/resources/extensions/mcp-client/tests/server-name-spaces.test.ts +70 -36
  1178. package/src/resources/extensions/ollama/index.ts +5 -1
  1179. package/src/resources/extensions/ollama/ollama-auth-mode.test.ts +123 -15
  1180. package/src/resources/extensions/ollama/ollama-status-indicator.test.ts +206 -19
  1181. package/src/resources/extensions/remote-questions/manager.ts +36 -4
  1182. package/src/resources/extensions/remote-questions/tests/command-polling.test.ts +200 -190
  1183. package/src/resources/extensions/search-the-web/command-search-provider.ts +5 -4
  1184. package/src/resources/extensions/search-the-web/native-search.ts +48 -12
  1185. package/src/resources/extensions/shared/cmux-events.ts +59 -0
  1186. package/src/resources/extensions/shared/rtk-session-stats.ts +1 -2
  1187. package/src/resources/extensions/shared/tests/interview-preview.test.ts +11 -3
  1188. package/src/resources/extensions/voice/tests/linux-ready.test.ts +129 -113
  1189. package/src/resources/skills/api-design/SKILL.md +190 -0
  1190. package/src/resources/skills/create-mcp-server/SKILL.md +121 -0
  1191. package/src/resources/skills/create-skill/SKILL.md +2 -2
  1192. package/src/resources/skills/create-skill/references/gsd-skill-ecosystem.md +4 -4
  1193. package/src/resources/skills/create-skill/workflows/audit-skill.md +4 -4
  1194. package/src/resources/skills/create-skill/workflows/create-new-skill.md +5 -5
  1195. package/src/resources/skills/decompose-into-slices/SKILL.md +139 -0
  1196. package/src/resources/skills/dependency-upgrade/SKILL.md +158 -0
  1197. package/src/resources/skills/design-an-interface/SKILL.md +102 -0
  1198. package/src/resources/skills/forensics/SKILL.md +153 -0
  1199. package/src/resources/skills/grill-me/SKILL.md +93 -0
  1200. package/src/resources/skills/handoff/SKILL.md +121 -0
  1201. package/src/resources/skills/observability/SKILL.md +174 -0
  1202. package/src/resources/skills/security-review/SKILL.md +181 -0
  1203. package/src/resources/skills/spike-wrap-up/SKILL.md +138 -0
  1204. package/src/resources/skills/tdd/SKILL.md +112 -0
  1205. package/src/resources/skills/verify-before-complete/SKILL.md +98 -0
  1206. package/src/resources/skills/write-docs/SKILL.md +82 -0
  1207. package/src/resources/skills/write-milestone-brief/SKILL.md +135 -0
  1208. package/dist/web/standalone/.next/server/chunks/7461.js +0 -1
  1209. package/dist/web/standalone/.next/static/chunks/2826.e59e8578e2e28639.js +0 -9
  1210. package/dist/web/standalone/.next/static/chunks/app/page-151349214571e2b6.js +0 -1
  1211. package/dist/web/standalone/.next/static/chunks/main-app-d3d4c336195465f9.js +0 -1
  1212. package/dist/web/standalone/.next/static/chunks/next/dist/client/components/builtin/global-error-ab5a8926e07ec673.js +0 -1
  1213. package/src/resources/extensions/gsd/tests/auto-start-model-capture.test.ts +0 -113
  1214. package/src/resources/extensions/gsd/tests/complete-milestone-false-merge.test.ts +0 -142
  1215. package/src/resources/extensions/gsd/tests/dashboard-model-label-ordering.test.ts +0 -107
  1216. package/src/resources/extensions/gsd/tests/find-missing-summaries-closed.test.ts +0 -48
  1217. package/src/resources/extensions/gsd/tests/forensics-context-persist.test.ts +0 -159
  1218. package/src/resources/extensions/gsd/tests/forensics-db-completion.test.ts +0 -96
  1219. package/src/resources/extensions/gsd/tests/forensics-dedup.test.ts +0 -79
  1220. package/src/resources/extensions/gsd/tests/forensics-hook-key-parse.test.ts +0 -74
  1221. package/src/resources/extensions/gsd/tests/forensics-journal.test.ts +0 -162
  1222. package/src/resources/extensions/gsd/tests/gitignore-bg-shell.test.ts +0 -38
  1223. package/src/resources/extensions/gsd/tests/gsd-no-project-error.test.ts +0 -73
  1224. package/src/resources/extensions/gsd/tests/idle-watchdog-stall-override.test.ts +0 -125
  1225. package/src/resources/extensions/gsd/tests/import-done-milestones.test.ts +0 -42
  1226. /package/dist/web/standalone/.next/static/{ssX7BLv3Dw9Fb4CtrCGeR → MdwvuQQLlBY6wwiSO1Tgv}/_buildManifest.js +0 -0
  1227. /package/dist/web/standalone/.next/static/{ssX7BLv3Dw9Fb4CtrCGeR → MdwvuQQLlBY6wwiSO1Tgv}/_ssgManifest.js +0 -0
@@ -8,10 +8,15 @@ import {
8
8
  getResultErrorMessage,
9
9
  makeAbortedMessage,
10
10
  mergePendingToolCalls,
11
+ buildFinalAssistantContent,
11
12
  resolveClaudePermissionMode,
12
13
  buildPromptFromContext,
13
14
  buildSdkQueryPrompt,
14
15
  buildSdkOptions,
16
+ createClaudeCodeCanUseToolHandler,
17
+ buildBashPermissionPattern,
18
+ buildBashPermissionPatternOptions,
19
+ bashCommandMatchesSavedRules,
15
20
  createClaudeCodeElicitationHandler,
16
21
  extractImageBlocksFromContext,
17
22
  extractToolResultsFromSdkUserMessage,
@@ -19,11 +24,58 @@ import {
19
24
  parseAskUserQuestionsElicitation,
20
25
  parseTextInputElicitation,
21
26
  parseClaudeLookupOutput,
27
+ resolveBundledClaudeCliPath,
28
+ normalizeClaudePathForSdk,
22
29
  roundResultToElicitationContent,
23
30
  } from "../stream-adapter.ts";
24
31
  import type { AssistantMessage, Context, Message } from "@gsd/pi-ai";
25
32
  import type { SDKUserMessage } from "../sdk-types.ts";
26
33
 
34
+ // ---------------------------------------------------------------------------
35
+ // Env helpers — `GSD_WORKFLOW_MCP_*` save/restore
36
+ //
37
+ // The naive pattern `process.env.X = prev.X` breaks when `prev.X` is
38
+ // undefined: Node coerces the assignment to the literal string
39
+ // "undefined", which then pollutes subsequent tests that read the var
40
+ // and assume it's absent. Issue #4808 documents the resulting bleed.
41
+ //
42
+ // `setWorkflowMcpEnv` returns a `restore()` closure that either
43
+ // re-assigns the previous string value OR `delete`s the key when the
44
+ // original was absent. Call in a try/finally; restore in the finally.
45
+ // ---------------------------------------------------------------------------
46
+
47
+ const WORKFLOW_MCP_ENV_KEYS = [
48
+ "GSD_WORKFLOW_MCP_COMMAND",
49
+ "GSD_WORKFLOW_MCP_NAME",
50
+ "GSD_WORKFLOW_MCP_ARGS",
51
+ "GSD_WORKFLOW_MCP_ENV",
52
+ "GSD_WORKFLOW_MCP_CWD",
53
+ ] as const;
54
+
55
+ type WorkflowMcpEnvKey = (typeof WORKFLOW_MCP_ENV_KEYS)[number];
56
+
57
+ function setWorkflowMcpEnv(
58
+ values: Partial<Record<WorkflowMcpEnvKey, string>>,
59
+ ): () => void {
60
+ const prev: Partial<Record<WorkflowMcpEnvKey, string | undefined>> = {};
61
+ for (const key of WORKFLOW_MCP_ENV_KEYS) {
62
+ prev[key] = process.env[key];
63
+ }
64
+ for (const [key, value] of Object.entries(values)) {
65
+ process.env[key] = value;
66
+ }
67
+ return function restore() {
68
+ for (const key of WORKFLOW_MCP_ENV_KEYS) {
69
+ const previous = prev[key];
70
+ if (previous === undefined) {
71
+ delete process.env[key];
72
+ } else {
73
+ process.env[key] = previous;
74
+ }
75
+ }
76
+ };
77
+ }
78
+
27
79
  // ---------------------------------------------------------------------------
28
80
  // Existing tests — exhausted stream fallback (#2575)
29
81
  // ---------------------------------------------------------------------------
@@ -372,13 +424,146 @@ describe("stream-adapter — Claude Code external tool results", () => {
372
424
  toolUseId: "tool-bash-1",
373
425
  result: {
374
426
  content: [{ type: "text", text: "line 1\nline 2" }],
375
- details: {},
427
+ // extractStructuredDetailsFromBlock returns undefined when no
428
+ // structured payload exists, restoring the pre-#4477 nullable
429
+ // contract (#4477 review feedback).
430
+ details: undefined,
376
431
  isError: false,
377
432
  },
378
433
  },
379
434
  ]);
380
435
  });
381
436
 
437
+ test("extractToolResultsFromSdkUserMessage reads structuredContent as a sibling field (#4472)", () => {
438
+ const message: SDKUserMessage = {
439
+ type: "user",
440
+ session_id: "sess-1",
441
+ parent_tool_use_id: "tool-mcp-1",
442
+ message: {
443
+ role: "user",
444
+ content: [
445
+ {
446
+ type: "mcp_tool_result",
447
+ tool_use_id: "tool-mcp-1",
448
+ content: [{ type: "text", text: "Gate Q3 result saved: verdict=pass" }],
449
+ is_error: false,
450
+ structuredContent: { gateId: "Q3", verdict: "pass" },
451
+ } as unknown as Record<string, unknown>,
452
+ ],
453
+ },
454
+ };
455
+
456
+ const results = extractToolResultsFromSdkUserMessage(message);
457
+ assert.deepEqual(results[0].result.details, { gateId: "Q3", verdict: "pass" });
458
+ });
459
+
460
+ test("extractToolResultsFromSdkUserMessage reads structuredContent from a content sub-block (#4472)", () => {
461
+ const message: SDKUserMessage = {
462
+ type: "user",
463
+ session_id: "sess-1",
464
+ parent_tool_use_id: "tool-mcp-2",
465
+ message: {
466
+ role: "user",
467
+ content: [
468
+ {
469
+ type: "mcp_tool_result",
470
+ tool_use_id: "tool-mcp-2",
471
+ content: [
472
+ { type: "text", text: "Gate Q4 result saved: verdict=flag" },
473
+ { type: "structuredContent", structuredContent: { gateId: "Q4", verdict: "flag" } },
474
+ ],
475
+ is_error: false,
476
+ } as unknown as Record<string, unknown>,
477
+ ],
478
+ },
479
+ };
480
+
481
+ const results = extractToolResultsFromSdkUserMessage(message);
482
+ assert.deepEqual(results[0].result.details, { gateId: "Q4", verdict: "flag" });
483
+ });
484
+
485
+ test("#4477 extractToolResultsFromSdkUserMessage does NOT leak structuredContent pseudo-blocks into visible content", () => {
486
+ // Regression: when a content sub-block carries `type: "structuredContent"`,
487
+ // it carries the structured payload (extracted separately into `details`)
488
+ // and must NOT appear in the visible `content` array — otherwise the
489
+ // renderer stringifies the JSON pseudo-block and shows it next to the
490
+ // actual tool output. See PR #4477 review (CodeRabbit, post-fix-round).
491
+ const message: SDKUserMessage = {
492
+ type: "user",
493
+ session_id: "sess-1",
494
+ parent_tool_use_id: "tool-mcp-strip",
495
+ message: {
496
+ role: "user",
497
+ content: [
498
+ {
499
+ type: "mcp_tool_result",
500
+ tool_use_id: "tool-mcp-strip",
501
+ content: [
502
+ { type: "text", text: "Gate Q5 result saved: verdict=pass" },
503
+ { type: "structuredContent", structuredContent: { gateId: "Q5", verdict: "pass" } },
504
+ { type: "text", text: "second visible line" },
505
+ // snake_case variant — also a pseudo-block; also must be stripped
506
+ { type: "structured_content", structured_content: { extra: "data" } },
507
+ ],
508
+ is_error: false,
509
+ } as unknown as Record<string, unknown>,
510
+ ],
511
+ },
512
+ };
513
+
514
+ const results = extractToolResultsFromSdkUserMessage(message);
515
+ assert.equal(results.length, 1, "should extract one result");
516
+ const result = results[0].result;
517
+
518
+ // The structured payload IS extracted to `details`.
519
+ assert.deepEqual(result.details, { gateId: "Q5", verdict: "pass" });
520
+
521
+ // The visible content has the two text blocks but NEITHER pseudo-block.
522
+ const visibleTexts = result.content.map((c: any) => c.text);
523
+ assert.deepEqual(
524
+ visibleTexts,
525
+ ["Gate Q5 result saved: verdict=pass", "second visible line"],
526
+ "visible content must include only the two text blocks; both structuredContent variants must be stripped",
527
+ );
528
+
529
+ // Belt-and-suspenders: assert no rendered text shows the JSON serialization
530
+ // of a pseudo-block. We don't check for bare keys like "gateId" or "verdict"
531
+ // because those are legitimate words in the gate-result message text. The
532
+ // regression signature would be a JSON-shaped substring that could only
533
+ // appear via stringification.
534
+ const allText = visibleTexts.join("\n");
535
+ assert.ok(
536
+ !allText.includes('"structuredContent"'),
537
+ "rendered content must not include the pseudo-block type marker as JSON text",
538
+ );
539
+ assert.ok(
540
+ !allText.includes('"structured_content"'),
541
+ "rendered content must not include the snake_case pseudo-block type marker as JSON text",
542
+ );
543
+ });
544
+
545
+ test("extractToolResultsFromSdkUserMessage accepts snake_case structured_content defensively (#4472)", () => {
546
+ const message: SDKUserMessage = {
547
+ type: "user",
548
+ session_id: "sess-1",
549
+ parent_tool_use_id: "tool-mcp-3",
550
+ message: {
551
+ role: "user",
552
+ content: [
553
+ {
554
+ type: "mcp_tool_result",
555
+ tool_use_id: "tool-mcp-3",
556
+ content: [{ type: "text", text: "ok" }],
557
+ structured_content: { operation: "save_gate_result" },
558
+ } as unknown as Record<string, unknown>,
559
+ ],
560
+ },
561
+ };
562
+
563
+ const results = extractToolResultsFromSdkUserMessage(message);
564
+ assert.deepEqual(results[0].result.details, { operation: "save_gate_result" });
565
+ });
566
+
382
567
  test("extractToolResultsFromSdkUserMessage falls back to tool_use_result", () => {
383
568
  const message: SDKUserMessage = {
384
569
  type: "user",
@@ -398,12 +583,79 @@ describe("stream-adapter — Claude Code external tool results", () => {
398
583
  toolUseId: "tool-read-1",
399
584
  result: {
400
585
  content: [{ type: "text", text: "file contents" }],
401
- details: {},
586
+ // undefined (not {}) per the restored nullable contract — see
587
+ // the analogous assertion in the tool_result test above.
588
+ details: undefined,
402
589
  isError: true,
403
590
  },
404
591
  },
405
592
  ]);
406
593
  });
594
+
595
+ test("buildFinalAssistantContent preserves intermediate tool calls with attached external results", () => {
596
+ const finalContent = buildFinalAssistantContent({
597
+ intermediateToolBlocks: [
598
+ {
599
+ type: "toolCall",
600
+ id: "tool-bash-1",
601
+ name: "bash",
602
+ arguments: { command: "echo hi" },
603
+ } as any,
604
+ ],
605
+ pendingContent: [{ type: "text", text: "All done." }],
606
+ toolResultsById: new Map([
607
+ [
608
+ "tool-bash-1",
609
+ {
610
+ content: [{ type: "text", text: "hi\n" }],
611
+ details: { source: "claude-code" },
612
+ isError: false,
613
+ },
614
+ ],
615
+ ]),
616
+ });
617
+
618
+ assert.equal(finalContent[0]?.type, "toolCall");
619
+ assert.deepEqual((finalContent[0] as any).externalResult, {
620
+ content: [{ type: "text", text: "hi\n" }],
621
+ details: { source: "claude-code" },
622
+ isError: false,
623
+ });
624
+ assert.deepEqual(finalContent[1], { type: "text", text: "All done." });
625
+ });
626
+
627
+ test("buildFinalAssistantContent keeps final-turn tool calls when result arrives without a synthetic user boundary", () => {
628
+ const finalContent = buildFinalAssistantContent({
629
+ intermediateToolBlocks: [],
630
+ pendingContent: [
631
+ {
632
+ type: "toolCall",
633
+ id: "tool-read-1",
634
+ name: "read",
635
+ arguments: { path: "README.md" },
636
+ } as any,
637
+ { type: "text", text: "Read complete." },
638
+ ],
639
+ toolResultsById: new Map([
640
+ [
641
+ "tool-read-1",
642
+ {
643
+ content: [{ type: "text", text: "file contents" }],
644
+ details: { path: "README.md" },
645
+ isError: false,
646
+ },
647
+ ],
648
+ ]),
649
+ });
650
+
651
+ assert.equal(finalContent[0]?.type, "toolCall");
652
+ assert.deepEqual((finalContent[0] as any).externalResult, {
653
+ content: [{ type: "text", text: "file contents" }],
654
+ details: { path: "README.md" },
655
+ isError: false,
656
+ });
657
+ assert.deepEqual(finalContent[1], { type: "text", text: "Read complete." });
658
+ });
407
659
  });
408
660
 
409
661
  describe("stream-adapter — session persistence (#2859)", () => {
@@ -536,19 +788,14 @@ describe("stream-adapter — session persistence (#2859)", () => {
536
788
  });
537
789
 
538
790
  test("buildSdkOptions includes workflow MCP server config when env is set", () => {
539
- const prev = {
540
- GSD_WORKFLOW_MCP_COMMAND: process.env.GSD_WORKFLOW_MCP_COMMAND,
541
- GSD_WORKFLOW_MCP_NAME: process.env.GSD_WORKFLOW_MCP_NAME,
542
- GSD_WORKFLOW_MCP_ARGS: process.env.GSD_WORKFLOW_MCP_ARGS,
543
- GSD_WORKFLOW_MCP_ENV: process.env.GSD_WORKFLOW_MCP_ENV,
544
- GSD_WORKFLOW_MCP_CWD: process.env.GSD_WORKFLOW_MCP_CWD,
545
- };
791
+ const restore = setWorkflowMcpEnv({
792
+ GSD_WORKFLOW_MCP_COMMAND: "node",
793
+ GSD_WORKFLOW_MCP_NAME: "gsd-workflow",
794
+ GSD_WORKFLOW_MCP_ARGS: JSON.stringify(["packages/mcp-server/dist/cli.js"]),
795
+ GSD_WORKFLOW_MCP_ENV: JSON.stringify({ GSD_CLI_PATH: "/tmp/gsd" }),
796
+ GSD_WORKFLOW_MCP_CWD: "/tmp/project",
797
+ });
546
798
  try {
547
- process.env.GSD_WORKFLOW_MCP_COMMAND = "node";
548
- process.env.GSD_WORKFLOW_MCP_NAME = "gsd-workflow";
549
- process.env.GSD_WORKFLOW_MCP_ARGS = JSON.stringify(["packages/mcp-server/dist/cli.js"]);
550
- process.env.GSD_WORKFLOW_MCP_ENV = JSON.stringify({ GSD_CLI_PATH: "/tmp/gsd" });
551
- process.env.GSD_WORKFLOW_MCP_CWD = "/tmp/project";
552
799
 
553
800
  const options = buildSdkOptions("claude-sonnet-4-20250514", "test");
554
801
  const mcpServers = options.mcpServers as Record<string, any>;
@@ -560,72 +807,63 @@ describe("stream-adapter — session persistence (#2859)", () => {
560
807
  assert.equal(srv.env.GSD_CLI_PATH, "/tmp/gsd");
561
808
  assert.equal(srv.env.GSD_PERSIST_WRITE_GATE_STATE, "1");
562
809
  assert.equal(srv.env.GSD_WORKFLOW_PROJECT_ROOT, "/tmp/project");
563
- assert.deepEqual(options.disallowedTools, ["AskUserQuestion"]);
810
+ assert.deepEqual(options.disallowedTools, []);
564
811
  assert.deepEqual(options.allowedTools, [
565
812
  "Read",
566
813
  "Write",
567
814
  "Edit",
568
815
  "Glob",
569
816
  "Grep",
570
- "Bash(ls:*)",
571
- "Bash(pwd)",
817
+ "Bash",
818
+ "Agent",
819
+ "WebFetch",
820
+ "WebSearch",
821
+ "AskUserQuestion",
572
822
  "mcp__gsd-workflow__*",
573
823
  ]);
574
824
  } finally {
575
- process.env.GSD_WORKFLOW_MCP_COMMAND = prev.GSD_WORKFLOW_MCP_COMMAND;
576
- process.env.GSD_WORKFLOW_MCP_NAME = prev.GSD_WORKFLOW_MCP_NAME;
577
- process.env.GSD_WORKFLOW_MCP_ARGS = prev.GSD_WORKFLOW_MCP_ARGS;
578
- process.env.GSD_WORKFLOW_MCP_ENV = prev.GSD_WORKFLOW_MCP_ENV;
579
- process.env.GSD_WORKFLOW_MCP_CWD = prev.GSD_WORKFLOW_MCP_CWD;
825
+ restore();
580
826
  }
581
827
  });
582
828
 
583
- test("buildSdkOptions disables AskUserQuestion for custom workflow MCP server names", () => {
584
- const prev = {
585
- GSD_WORKFLOW_MCP_COMMAND: process.env.GSD_WORKFLOW_MCP_COMMAND,
586
- GSD_WORKFLOW_MCP_NAME: process.env.GSD_WORKFLOW_MCP_NAME,
587
- GSD_WORKFLOW_MCP_ARGS: process.env.GSD_WORKFLOW_MCP_ARGS,
588
- GSD_WORKFLOW_MCP_ENV: process.env.GSD_WORKFLOW_MCP_ENV,
589
- GSD_WORKFLOW_MCP_CWD: process.env.GSD_WORKFLOW_MCP_CWD,
590
- };
829
+ test("buildSdkOptions auto-approves every tool for custom workflow MCP server names", () => {
830
+ const restore = setWorkflowMcpEnv({
831
+ GSD_WORKFLOW_MCP_COMMAND: "node",
832
+ GSD_WORKFLOW_MCP_NAME: "custom-workflow",
833
+ GSD_WORKFLOW_MCP_ARGS: JSON.stringify(["packages/mcp-server/dist/cli.js"]),
834
+ GSD_WORKFLOW_MCP_ENV: JSON.stringify({ GSD_CLI_PATH: "/tmp/gsd" }),
835
+ GSD_WORKFLOW_MCP_CWD: "/tmp/project",
836
+ });
591
837
  try {
592
- process.env.GSD_WORKFLOW_MCP_COMMAND = "node";
593
- process.env.GSD_WORKFLOW_MCP_NAME = "custom-workflow";
594
- process.env.GSD_WORKFLOW_MCP_ARGS = JSON.stringify(["packages/mcp-server/dist/cli.js"]);
595
- process.env.GSD_WORKFLOW_MCP_ENV = JSON.stringify({ GSD_CLI_PATH: "/tmp/gsd" });
596
- process.env.GSD_WORKFLOW_MCP_CWD = "/tmp/project";
597
838
 
598
839
  const options = buildSdkOptions("claude-sonnet-4-20250514", "test");
599
840
  const mcpServers = options.mcpServers as Record<string, any>;
600
841
  assert.ok(mcpServers?.["custom-workflow"], "expected custom workflow server config");
601
- assert.deepEqual(options.disallowedTools, ["AskUserQuestion"]);
842
+ assert.deepEqual(options.disallowedTools, []);
602
843
  assert.deepEqual(options.allowedTools, [
603
844
  "Read",
604
845
  "Write",
605
846
  "Edit",
606
847
  "Glob",
607
848
  "Grep",
608
- "Bash(ls:*)",
609
- "Bash(pwd)",
849
+ "Bash",
850
+ "Agent",
851
+ "WebFetch",
852
+ "WebSearch",
853
+ "AskUserQuestion",
610
854
  "mcp__custom-workflow__*",
611
855
  ]);
612
856
  } finally {
613
- process.env.GSD_WORKFLOW_MCP_COMMAND = prev.GSD_WORKFLOW_MCP_COMMAND;
614
- process.env.GSD_WORKFLOW_MCP_NAME = prev.GSD_WORKFLOW_MCP_NAME;
615
- process.env.GSD_WORKFLOW_MCP_ARGS = prev.GSD_WORKFLOW_MCP_ARGS;
616
- process.env.GSD_WORKFLOW_MCP_ENV = prev.GSD_WORKFLOW_MCP_ENV;
617
- process.env.GSD_WORKFLOW_MCP_CWD = prev.GSD_WORKFLOW_MCP_CWD;
857
+ restore();
618
858
  }
619
859
  });
620
860
 
621
861
  test("buildSdkOptions auto-discovers bundled MCP server even without env hints", () => {
622
- const prev = {
623
- GSD_WORKFLOW_MCP_COMMAND: process.env.GSD_WORKFLOW_MCP_COMMAND,
624
- GSD_WORKFLOW_MCP_NAME: process.env.GSD_WORKFLOW_MCP_NAME,
625
- GSD_WORKFLOW_MCP_ARGS: process.env.GSD_WORKFLOW_MCP_ARGS,
626
- GSD_WORKFLOW_MCP_ENV: process.env.GSD_WORKFLOW_MCP_ENV,
627
- GSD_WORKFLOW_MCP_CWD: process.env.GSD_WORKFLOW_MCP_CWD,
628
- };
862
+ // Use setWorkflowMcpEnv with no values to save current state;
863
+ // restore() in finally will put it back correctly (including
864
+ // deleting any keys that started as undefined — the #4808 bug
865
+ // the naive `process.env.X = prev.X` pattern introduced).
866
+ const restore = setWorkflowMcpEnv({});
629
867
  try {
630
868
  delete process.env.GSD_WORKFLOW_MCP_COMMAND;
631
869
  delete process.env.GSD_WORKFLOW_MCP_NAME;
@@ -644,29 +882,21 @@ describe("stream-adapter — session persistence (#2859)", () => {
644
882
  const mcpServers = (options as any).mcpServers;
645
883
  if (mcpServers) {
646
884
  assert.ok(mcpServers["gsd-workflow"], "if present, must be gsd-workflow");
647
- assert.deepEqual((options as any).disallowedTools, ["AskUserQuestion"]);
885
+ assert.deepEqual((options as any).disallowedTools, []);
648
886
  } else {
649
- assert.deepEqual((options as any).disallowedTools, ["AskUserQuestion"]);
887
+ assert.deepEqual((options as any).disallowedTools, []);
650
888
  }
651
889
  rmSync(emptyDir, { recursive: true, force: true });
652
890
  } finally {
653
- process.env.GSD_WORKFLOW_MCP_COMMAND = prev.GSD_WORKFLOW_MCP_COMMAND;
654
- process.env.GSD_WORKFLOW_MCP_NAME = prev.GSD_WORKFLOW_MCP_NAME;
655
- process.env.GSD_WORKFLOW_MCP_ARGS = prev.GSD_WORKFLOW_MCP_ARGS;
656
- process.env.GSD_WORKFLOW_MCP_ENV = prev.GSD_WORKFLOW_MCP_ENV;
657
- process.env.GSD_WORKFLOW_MCP_CWD = prev.GSD_WORKFLOW_MCP_CWD;
891
+ restore();
658
892
  }
659
893
  });
660
894
 
661
895
  test("buildSdkOptions auto-detects local workflow MCP dist CLI when present", () => {
662
- const prev = {
663
- GSD_WORKFLOW_MCP_COMMAND: process.env.GSD_WORKFLOW_MCP_COMMAND,
664
- GSD_WORKFLOW_MCP_NAME: process.env.GSD_WORKFLOW_MCP_NAME,
665
- GSD_WORKFLOW_MCP_ARGS: process.env.GSD_WORKFLOW_MCP_ARGS,
666
- GSD_WORKFLOW_MCP_ENV: process.env.GSD_WORKFLOW_MCP_ENV,
667
- GSD_WORKFLOW_MCP_CWD: process.env.GSD_WORKFLOW_MCP_CWD,
668
- GSD_CLI_PATH: process.env.GSD_CLI_PATH,
669
- };
896
+ // GSD_CLI_PATH isn't in WORKFLOW_MCP_ENV_KEYS, so save+restore it
897
+ // manually around setWorkflowMcpEnv which handles the MCP keys.
898
+ const prevCliPath = process.env.GSD_CLI_PATH;
899
+ const restore = setWorkflowMcpEnv({});
670
900
  const originalCwd = process.cwd();
671
901
  const repoDir = mkdtempSync(join(tmpdir(), "claude-mcp-detect-"));
672
902
  try {
@@ -693,27 +923,22 @@ describe("stream-adapter — session persistence (#2859)", () => {
693
923
  assert.equal(srv.env.GSD_CLI_PATH, "/tmp/gsd");
694
924
  assert.equal(srv.env.GSD_PERSIST_WRITE_GATE_STATE, "1");
695
925
  assert.equal(srv.env.GSD_WORKFLOW_PROJECT_ROOT, resolvedRepoDir);
696
- assert.deepEqual(options.disallowedTools, ["AskUserQuestion"]);
926
+ assert.deepEqual(options.disallowedTools, []);
697
927
  } finally {
698
928
  process.chdir(originalCwd);
699
929
  rmSync(repoDir, { recursive: true, force: true });
700
- process.env.GSD_WORKFLOW_MCP_COMMAND = prev.GSD_WORKFLOW_MCP_COMMAND;
701
- process.env.GSD_WORKFLOW_MCP_NAME = prev.GSD_WORKFLOW_MCP_NAME;
702
- process.env.GSD_WORKFLOW_MCP_ARGS = prev.GSD_WORKFLOW_MCP_ARGS;
703
- process.env.GSD_WORKFLOW_MCP_ENV = prev.GSD_WORKFLOW_MCP_ENV;
704
- process.env.GSD_WORKFLOW_MCP_CWD = prev.GSD_WORKFLOW_MCP_CWD;
705
- process.env.GSD_CLI_PATH = prev.GSD_CLI_PATH;
930
+ restore();
931
+ // GSD_CLI_PATH isn't in setWorkflowMcpEnv's scope — restore it here.
932
+ if (prevCliPath === undefined) {
933
+ delete process.env.GSD_CLI_PATH;
934
+ } else {
935
+ process.env.GSD_CLI_PATH = prevCliPath;
936
+ }
706
937
  }
707
938
  });
708
939
 
709
940
  test("buildSdkOptions preserves runtime callbacks such as onElicitation", () => {
710
- const prev = {
711
- GSD_WORKFLOW_MCP_COMMAND: process.env.GSD_WORKFLOW_MCP_COMMAND,
712
- GSD_WORKFLOW_MCP_NAME: process.env.GSD_WORKFLOW_MCP_NAME,
713
- GSD_WORKFLOW_MCP_ARGS: process.env.GSD_WORKFLOW_MCP_ARGS,
714
- GSD_WORKFLOW_MCP_ENV: process.env.GSD_WORKFLOW_MCP_ENV,
715
- GSD_WORKFLOW_MCP_CWD: process.env.GSD_WORKFLOW_MCP_CWD,
716
- };
941
+ const restore = setWorkflowMcpEnv({});
717
942
  const onElicitation = async () => ({ action: "decline" as const });
718
943
  try {
719
944
  delete process.env.GSD_WORKFLOW_MCP_COMMAND;
@@ -724,11 +949,7 @@ describe("stream-adapter — session persistence (#2859)", () => {
724
949
  const options = buildSdkOptions("claude-sonnet-4-20250514", "test", undefined, { onElicitation });
725
950
  assert.equal(options.onElicitation, onElicitation);
726
951
  } finally {
727
- process.env.GSD_WORKFLOW_MCP_COMMAND = prev.GSD_WORKFLOW_MCP_COMMAND;
728
- process.env.GSD_WORKFLOW_MCP_NAME = prev.GSD_WORKFLOW_MCP_NAME;
729
- process.env.GSD_WORKFLOW_MCP_ARGS = prev.GSD_WORKFLOW_MCP_ARGS;
730
- process.env.GSD_WORKFLOW_MCP_ENV = prev.GSD_WORKFLOW_MCP_ENV;
731
- process.env.GSD_WORKFLOW_MCP_CWD = prev.GSD_WORKFLOW_MCP_CWD;
952
+ restore();
732
953
  }
733
954
  });
734
955
  });
@@ -1081,11 +1302,15 @@ describe("stream-adapter — permission mode (F10)", () => {
1081
1302
  }
1082
1303
  }
1083
1304
 
1084
- test("buildSdkOptions defaults to bypassPermissions for backwards compatibility", () => {
1305
+ test("buildSdkOptions defaults to bypassPermissions (globally unblocks all tools)", () => {
1085
1306
  clearWorkflowMcpEnv();
1086
1307
  const opts = buildSdkOptions("claude-sonnet-4-6", "test");
1087
1308
  assert.equal(opts.permissionMode, "bypassPermissions");
1088
- assert.equal(opts.allowDangerouslySkipPermissions, true);
1309
+ assert.equal(
1310
+ opts.allowDangerouslySkipPermissions,
1311
+ true,
1312
+ "allowDangerouslySkipPermissions must be true when permissionMode is bypassPermissions",
1313
+ );
1089
1314
  });
1090
1315
 
1091
1316
  test("buildSdkOptions respects explicit acceptEdits override", () => {
@@ -1099,6 +1324,11 @@ describe("stream-adapter — permission mode (F10)", () => {
1099
1324
  );
1100
1325
  });
1101
1326
 
1327
+ test("resolveClaudePermissionMode defaults to bypassPermissions when no env var is set (globally unblocks all tools)", async () => {
1328
+ const mode = await resolveClaudePermissionMode({});
1329
+ assert.equal(mode, "bypassPermissions");
1330
+ });
1331
+
1102
1332
  test("resolveClaudePermissionMode honours the GSD_CLAUDE_CODE_PERMISSION_MODE env override", async () => {
1103
1333
  const env = { GSD_CLAUDE_CODE_PERMISSION_MODE: "acceptEdits" } as NodeJS.ProcessEnv;
1104
1334
  const mode = await resolveClaudePermissionMode(env);
@@ -1114,6 +1344,27 @@ describe("stream-adapter — permission mode (F10)", () => {
1114
1344
  `expected bypass or acceptEdits, got ${mode}`,
1115
1345
  );
1116
1346
  });
1347
+
1348
+ test("resolveClaudePermissionMode flips to bypassPermissions when GSD_HEADLESS=1 (#4657)", async () => {
1349
+ const originalWarn = console.warn;
1350
+ console.warn = () => {};
1351
+ try {
1352
+ const env = { GSD_HEADLESS: "1" } as NodeJS.ProcessEnv;
1353
+ const mode = await resolveClaudePermissionMode(env);
1354
+ assert.equal(mode, "bypassPermissions");
1355
+ } finally {
1356
+ console.warn = originalWarn;
1357
+ }
1358
+ });
1359
+
1360
+ test("resolveClaudePermissionMode: explicit override wins over GSD_HEADLESS=1", async () => {
1361
+ const env = {
1362
+ GSD_HEADLESS: "1",
1363
+ GSD_CLAUDE_CODE_PERMISSION_MODE: "acceptEdits",
1364
+ } as NodeJS.ProcessEnv;
1365
+ const mode = await resolveClaudePermissionMode(env);
1366
+ assert.equal(mode, "acceptEdits");
1367
+ });
1117
1368
  });
1118
1369
 
1119
1370
  describe("stream-adapter — Windows Claude path lookup (#3770)", () => {
@@ -1126,8 +1377,838 @@ describe("stream-adapter — Windows Claude path lookup (#3770)", () => {
1126
1377
  assert.equal(getClaudeLookupCommand("linux"), "which claude");
1127
1378
  });
1128
1379
 
1129
- test("parseClaudeLookupOutput keeps the first native path from multi-line lookup output", () => {
1130
- const output = "C:\\Users\\Binoy\\.local\\bin\\claude.exe\r\nC:\\Program Files\\Claude\\claude.exe\r\n";
1131
- assert.equal(parseClaudeLookupOutput(output), "C:\\Users\\Binoy\\.local\\bin\\claude.exe");
1380
+ test("parseClaudeLookupOutput prefers .exe on win32 when where output includes shims", () => {
1381
+ const output = [
1382
+ "C:\\Users\\djeff\\AppData\\Roaming\\npm\\claude",
1383
+ "C:\\Users\\djeff\\AppData\\Roaming\\npm\\claude.cmd",
1384
+ "C:\\Program Files\\Claude\\claude.exe",
1385
+ ].join("\r\n");
1386
+ assert.equal(parseClaudeLookupOutput(output, "win32"), "C:\\Program Files\\Claude\\claude.exe");
1387
+ });
1388
+
1389
+ test("parseClaudeLookupOutput keeps first line on non-win32 platforms", () => {
1390
+ const output = "/usr/local/bin/claude\n/opt/homebrew/bin/claude\n";
1391
+ assert.equal(parseClaudeLookupOutput(output, "darwin"), "/usr/local/bin/claude");
1392
+ });
1393
+
1394
+ test("normalizeClaudePathForSdk swaps Windows shim paths to bundled cli.js", () => {
1395
+ const shimPath = "C:\\Users\\djeff\\AppData\\Roaming\\npm\\claude";
1396
+ const bundled = "C:\\repo\\node_modules\\@anthropic-ai\\claude-agent-sdk\\cli.js";
1397
+ assert.equal(normalizeClaudePathForSdk(shimPath, "win32", bundled), bundled);
1398
+ assert.equal(normalizeClaudePathForSdk("C:\\Program Files\\Claude\\claude.exe", "win32", bundled), "C:\\Program Files\\Claude\\claude.exe");
1399
+ });
1400
+
1401
+ test("resolveBundledClaudeCliPath returns a .js path when SDK package is present", () => {
1402
+ const resolved = resolveBundledClaudeCliPath();
1403
+ assert.ok(resolved, "expected sdk cli.js to be resolvable in test workspace");
1404
+ assert.match(resolved!, /[\\/]@anthropic-ai[\\/]claude-agent-sdk[\\/]cli\.js$/);
1405
+ });
1406
+ });
1407
+
1408
+ // ---------------------------------------------------------------------------
1409
+ // canUseTool handler (#4383)
1410
+ // ---------------------------------------------------------------------------
1411
+
1412
+ describe("stream-adapter — canUseTool handler", () => {
1413
+ function makeOptions(overrides: Partial<{ signal: AbortSignal; suggestions: Array<Record<string, unknown>>; title: string; description: string; toolUseID: string }> = {}) {
1414
+ return {
1415
+ signal: overrides.signal ?? new AbortController().signal,
1416
+ toolUseID: overrides.toolUseID ?? "toolu_test123",
1417
+ ...(overrides.title !== undefined ? { title: overrides.title } : {}),
1418
+ ...(overrides.description !== undefined ? { description: overrides.description } : {}),
1419
+ ...(overrides.suggestions !== undefined ? { suggestions: overrides.suggestions } : {}),
1420
+ };
1421
+ }
1422
+
1423
+ // Point process.cwd() at an empty temp dir so the real repo's
1424
+ // .claude/settings.local.json (which may already contain rules like
1425
+ // "Bash(gh pr list:*)") does not short-circuit the permission flow.
1426
+ // Returns a cleanup function that restores cwd and removes the temp dir.
1427
+ // biome-ignore lint/suspicious/noExplicitAny: test-only monkey-patch
1428
+ function withIsolatedCwd(): () => void {
1429
+ const dir = realpathSync(mkdtempSync(join(tmpdir(), "gsd-canusetool-")));
1430
+ const orig = process.cwd;
1431
+ process.cwd = () => dir;
1432
+ return () => {
1433
+ process.cwd = orig;
1434
+ rmSync(dir, { recursive: true, force: true });
1435
+ };
1436
+ }
1437
+
1438
+ test("returns undefined when no UI context is provided", () => {
1439
+ const handler = createClaudeCodeCanUseToolHandler(undefined);
1440
+ assert.equal(handler, undefined);
1441
+ });
1442
+
1443
+ test("shows select dialog with Allow/Always Allow/Deny and returns allow", async () => {
1444
+ let selectPrompt = "";
1445
+ let selectOptions: string[] = [];
1446
+ const ui = {
1447
+ select: async (prompt: string, options: string[]) => {
1448
+ selectPrompt = prompt;
1449
+ selectOptions = options;
1450
+ return "Allow";
1451
+ },
1452
+ };
1453
+
1454
+ const handler = createClaudeCodeCanUseToolHandler(ui as any);
1455
+ assert.ok(handler);
1456
+
1457
+ const input = { command: "ls -la" };
1458
+ const result = await handler!("Bash", input, makeOptions({
1459
+ title: "Claude wants to run: ls -la",
1460
+ description: "List directory contents",
1461
+ }));
1462
+
1463
+ assert.equal(result.behavior, "allow");
1464
+ assert.deepEqual((result as any).updatedInput, input);
1465
+ assert.equal((result as any).toolUseID, "toolu_test123");
1466
+ // Allow (one-time) should NOT include updatedPermissions
1467
+ assert.equal((result as any).updatedPermissions, undefined);
1468
+ assert.deepEqual(selectOptions, ["Allow", "Always Allow", "Deny"]);
1469
+ // Prompt includes title and input summary
1470
+ assert.ok(selectPrompt.includes("Claude wants to run: ls -la"));
1471
+ assert.ok(selectPrompt.includes("ls -la"));
1472
+ });
1473
+
1474
+ test("returns deny when user selects Deny", async () => {
1475
+ const ui = {
1476
+ select: async () => "Deny",
1477
+ };
1478
+
1479
+ const handler = createClaudeCodeCanUseToolHandler(ui as any);
1480
+ const result = await handler!("Bash", { command: "rm -rf /" }, makeOptions());
1481
+
1482
+ assert.equal(result.behavior, "deny");
1483
+ assert.equal((result as any).message, "User denied");
1484
+ assert.equal((result as any).toolUseID, "toolu_test123");
1485
+ });
1486
+
1487
+ test("returns deny when user dismisses dialog (undefined)", async () => {
1488
+ const ui = {
1489
+ select: async () => undefined,
1490
+ };
1491
+
1492
+ const handler = createClaudeCodeCanUseToolHandler(ui as any);
1493
+ const result = await handler!("Bash", { command: "echo hi" }, makeOptions());
1494
+
1495
+ assert.equal(result.behavior, "deny");
1496
+ assert.equal((result as any).message, "User denied");
1497
+ });
1498
+
1499
+ test("Always Allow for Bash patches SDK suggestions with smart ruleContent", async () => {
1500
+ const notified: string[] = [];
1501
+ const ui = { select: async (_p: string, opts: string[]) => opts.find((o) => o.startsWith("Always Allow"))!, notify: (msg: string) => notified.push(msg) };
1502
+ const suggestions = [{
1503
+ type: "addRules",
1504
+ rules: [{ toolName: "Bash", ruleContent: "ls -la /tmp" }],
1505
+ behavior: "allow",
1506
+ destination: "localSettings",
1507
+ }];
1508
+
1509
+ const handler = createClaudeCodeCanUseToolHandler(ui as any);
1510
+ const result = await handler!("Bash", { command: "ls -la /tmp" }, makeOptions({ suggestions }));
1511
+
1512
+ assert.equal(result.behavior, "allow");
1513
+ // Should patch ruleContent with our smart pattern, preserving SDK structure
1514
+ assert.deepEqual((result as any).updatedPermissions, [{
1515
+ type: "addRules",
1516
+ rules: [{ toolName: "Bash", ruleContent: "ls:*" }],
1517
+ behavior: "allow",
1518
+ destination: "localSettings",
1519
+ }]);
1520
+ assert.equal(notified.length, 1);
1521
+ assert.ok(notified[0].includes("Saved:") && notified[0].includes("Bash(ls:*)"));
1522
+ });
1523
+
1524
+ test("Always Allow for Bash with subcommand-sensitive CLI captures verb", async () => {
1525
+ const cleanup = withIsolatedCwd();
1526
+ try {
1527
+ const notified: string[] = [];
1528
+ // First select call: pick "Always Allow ..."; second call (level
1529
+ // picker): pick the "git push" granularity explicitly.
1530
+ let selectCall = 0;
1531
+ const ui = {
1532
+ select: async (_p: string, opts: string[]) => {
1533
+ selectCall++;
1534
+ if (selectCall === 1) return opts.find((o) => o.startsWith("Always Allow"))!;
1535
+ return "Bash(git push:*)";
1536
+ },
1537
+ notify: (msg: string) => notified.push(msg),
1538
+ };
1539
+ const suggestions = [{
1540
+ type: "addRules",
1541
+ rules: [{ toolName: "Bash", ruleContent: "git push origin main" }],
1542
+ behavior: "allow",
1543
+ destination: "localSettings",
1544
+ }];
1545
+
1546
+ const handler = createClaudeCodeCanUseToolHandler(ui as any);
1547
+ const result = await handler!("Bash", { command: "git push origin main" }, makeOptions({ suggestions }));
1548
+
1549
+ assert.equal(result.behavior, "allow");
1550
+ assert.deepEqual((result as any).updatedPermissions, [{
1551
+ type: "addRules",
1552
+ rules: [{ toolName: "Bash", ruleContent: "git push:*" }],
1553
+ behavior: "allow",
1554
+ destination: "localSettings",
1555
+ }]);
1556
+ assert.ok(notified[0].includes("Saved:") && notified[0].includes("Bash(git push:*)"));
1557
+ } finally {
1558
+ cleanup();
1559
+ }
1560
+ });
1561
+
1562
+ test("Always Allow for Bash without suggestions builds proper PermissionUpdate", async () => {
1563
+ const cleanup = withIsolatedCwd();
1564
+ try {
1565
+ const notified: string[] = [];
1566
+ let selectCall = 0;
1567
+ const ui = {
1568
+ select: async (_p: string, opts: string[]) => {
1569
+ selectCall++;
1570
+ if (selectCall === 1) return opts.find((o) => o.startsWith("Always Allow"))!;
1571
+ return "Bash(gh pr list:*)";
1572
+ },
1573
+ notify: (msg: string) => notified.push(msg),
1574
+ };
1575
+
1576
+ const handler = createClaudeCodeCanUseToolHandler(ui as any);
1577
+ const result = await handler!("Bash", { command: "gh pr list" }, makeOptions());
1578
+
1579
+ assert.equal(result.behavior, "allow");
1580
+ // No SDK suggestions → builds PermissionUpdate from scratch
1581
+ assert.deepEqual((result as any).updatedPermissions, [{
1582
+ type: "addRules",
1583
+ rules: [{ toolName: "Bash", ruleContent: "gh pr list:*" }],
1584
+ behavior: "allow",
1585
+ destination: "localSettings",
1586
+ }]);
1587
+ assert.ok(notified[0].includes("Saved:") && notified[0].includes("Bash(gh pr list:*)"));
1588
+ } finally {
1589
+ cleanup();
1590
+ }
1591
+ });
1592
+
1593
+ test("Always Allow for non-Bash tools passes SDK suggestions through", async () => {
1594
+ const notified: string[] = [];
1595
+ const ui = { select: async (_p: string, opts: string[]) => opts.find((o) => o.startsWith("Always Allow"))!, notify: (msg: string) => notified.push(msg) };
1596
+ const suggestions = [{
1597
+ type: "addRules",
1598
+ rules: [{ toolName: "Write" }],
1599
+ behavior: "allow",
1600
+ destination: "localSettings",
1601
+ }];
1602
+
1603
+ const handler = createClaudeCodeCanUseToolHandler(ui as any);
1604
+ const result = await handler!("Write", { file_path: "/tmp/test.txt" }, makeOptions({ suggestions }));
1605
+
1606
+ assert.equal(result.behavior, "allow");
1607
+ assert.deepEqual((result as any).updatedPermissions, suggestions);
1608
+ // Non-Bash tools don't emit a post-selection notification (only Bash runs the level picker)
1609
+ assert.equal(notified.length, 0);
1610
+ });
1611
+
1612
+ test("Always Allow for non-Bash without suggestions omits updatedPermissions", async () => {
1613
+ const notified: string[] = [];
1614
+ const ui = { select: async (_p: string, opts: string[]) => opts.find((o) => o.startsWith("Always Allow"))!, notify: (msg: string) => notified.push(msg) };
1615
+
1616
+ const handler = createClaudeCodeCanUseToolHandler(ui as any);
1617
+ const result = await handler!("Write", { file_path: "/tmp/test.txt" }, makeOptions());
1618
+
1619
+ assert.equal(result.behavior, "allow");
1620
+ assert.equal((result as any).updatedPermissions, undefined);
1621
+ // No suggestions → no notification
1622
+ assert.equal(notified.length, 0);
1623
+ });
1624
+
1625
+ test("prompt includes command text for Bash tools", async () => {
1626
+ let selectPrompt = "";
1627
+ const ui = {
1628
+ select: async (prompt: string) => {
1629
+ selectPrompt = prompt;
1630
+ return "Allow";
1631
+ },
1632
+ };
1633
+
1634
+ const handler = createClaudeCodeCanUseToolHandler(ui as any);
1635
+ await handler!("Bash", { command: "git status" }, makeOptions());
1636
+ assert.ok(selectPrompt.includes("git status"), `prompt should include command: ${selectPrompt}`);
1637
+ });
1638
+
1639
+ test("prompt includes file_path for file tools", async () => {
1640
+ let selectPrompt = "";
1641
+ const ui = {
1642
+ select: async (prompt: string) => {
1643
+ selectPrompt = prompt;
1644
+ return "Allow";
1645
+ },
1646
+ };
1647
+
1648
+ const handler = createClaudeCodeCanUseToolHandler(ui as any);
1649
+ await handler!("Write", { file_path: "/tmp/test.txt", content: "hello" }, makeOptions());
1650
+ assert.ok(selectPrompt.includes("/tmp/test.txt"), `prompt should include file path: ${selectPrompt}`);
1651
+ });
1652
+
1653
+ test("uses title from options when available", async () => {
1654
+ let selectPrompt = "";
1655
+ const ui = {
1656
+ select: async (prompt: string) => {
1657
+ selectPrompt = prompt;
1658
+ return "Allow";
1659
+ },
1660
+ };
1661
+
1662
+ const handler = createClaudeCodeCanUseToolHandler(ui as any);
1663
+ await handler!("WebFetch", {}, makeOptions({ title: "Claude wants to fetch: https://example.com" }));
1664
+ assert.ok(selectPrompt.includes("Claude wants to fetch: https://example.com"));
1665
+ });
1666
+
1667
+ test("falls back to default title when options.title is missing", async () => {
1668
+ let selectPrompt = "";
1669
+ const ui = {
1670
+ select: async (prompt: string) => {
1671
+ selectPrompt = prompt;
1672
+ return "Allow";
1673
+ },
1674
+ };
1675
+
1676
+ const handler = createClaudeCodeCanUseToolHandler(ui as any);
1677
+ await handler!("WebFetch", { url: "https://example.com" }, makeOptions());
1678
+ assert.ok(selectPrompt.includes("Allow Claude Code to use: WebFetch?"));
1679
+ });
1680
+
1681
+ test("returns deny when signal is already aborted", async () => {
1682
+ const ui = {
1683
+ select: async () => { throw new Error("should not be called"); },
1684
+ };
1685
+
1686
+ const controller = new AbortController();
1687
+ controller.abort();
1688
+
1689
+ const handler = createClaudeCodeCanUseToolHandler(ui as any);
1690
+ const result = await handler!("Bash", {}, makeOptions({ signal: controller.signal }));
1691
+
1692
+ assert.equal(result.behavior, "deny");
1693
+ assert.equal((result as any).message, "Aborted");
1694
+ });
1695
+
1696
+ test("returns deny when ui.select throws", async () => {
1697
+ const ui = {
1698
+ select: async () => { throw new Error("dialog crashed"); },
1699
+ };
1700
+
1701
+ const handler = createClaudeCodeCanUseToolHandler(ui as any);
1702
+ const result = await handler!("Bash", {}, makeOptions());
1703
+
1704
+ assert.equal(result.behavior, "deny");
1705
+ assert.equal((result as any).message, "Aborted");
1706
+ });
1707
+
1708
+ test("buildSdkOptions passes canUseTool through extraOptions", () => {
1709
+ const canUseTool = async () => ({ behavior: "allow" as const, updatedInput: {}, toolUseID: "test" });
1710
+ const opts = buildSdkOptions("claude-sonnet-4-6", "test", undefined, { canUseTool });
1711
+ assert.equal(opts.canUseTool, canUseTool);
1712
+ });
1713
+
1714
+ test("Always Allow shows level picker and user broadens to base command", async () => {
1715
+ const cleanup = withIsolatedCwd();
1716
+ try {
1717
+ const prompts: string[] = [];
1718
+ const levelOpts: string[][] = [];
1719
+ let selectCall = 0;
1720
+ const ui = {
1721
+ select: async (prompt: string, opts: string[]) => {
1722
+ prompts.push(prompt);
1723
+ selectCall++;
1724
+ if (selectCall === 1) return opts.find((o) => o.startsWith("Always Allow"))!;
1725
+ levelOpts.push(opts);
1726
+ return "Bash(gh:*)";
1727
+ },
1728
+ notify: () => {},
1729
+ };
1730
+
1731
+ const handler = createClaudeCodeCanUseToolHandler(ui as any);
1732
+ const result = await handler!("Bash", { command: "gh pr list" }, makeOptions());
1733
+
1734
+ assert.equal(result.behavior, "allow");
1735
+ assert.deepEqual((result as any).updatedPermissions, [{
1736
+ type: "addRules",
1737
+ rules: [{ toolName: "Bash", ruleContent: "gh:*" }],
1738
+ behavior: "allow",
1739
+ destination: "localSettings",
1740
+ }]);
1741
+ // Second dialog offered every granularity level
1742
+ assert.deepEqual(levelOpts[0], [
1743
+ "Bash(gh:*)",
1744
+ "Bash(gh pr:*)",
1745
+ "Bash(gh pr list:*)",
1746
+ ]);
1747
+ assert.ok(prompts[1].includes("Save permission at which level?"));
1748
+ } finally {
1749
+ cleanup();
1750
+ }
1751
+ });
1752
+
1753
+ test("Always Allow narrows to mid-level pattern when user picks Bash(gh pr:*)", async () => {
1754
+ const cleanup = withIsolatedCwd();
1755
+ try {
1756
+ let selectCall = 0;
1757
+ const ui = {
1758
+ select: async (_p: string, opts: string[]) => {
1759
+ selectCall++;
1760
+ if (selectCall === 1) return opts.find((o) => o.startsWith("Always Allow"))!;
1761
+ return "Bash(gh pr:*)";
1762
+ },
1763
+ notify: () => {},
1764
+ };
1765
+
1766
+ const handler = createClaudeCodeCanUseToolHandler(ui as any);
1767
+ const result = await handler!("Bash", { command: "gh pr list --limit 5" }, makeOptions());
1768
+
1769
+ assert.equal(result.behavior, "allow");
1770
+ assert.deepEqual((result as any).updatedPermissions, [{
1771
+ type: "addRules",
1772
+ rules: [{ toolName: "Bash", ruleContent: "gh pr:*" }],
1773
+ behavior: "allow",
1774
+ destination: "localSettings",
1775
+ }]);
1776
+ } finally {
1777
+ cleanup();
1778
+ }
1779
+ });
1780
+
1781
+ test("Always Allow skips level picker when only one pattern is available", async () => {
1782
+ const cleanup = withIsolatedCwd();
1783
+ try {
1784
+ const prompts: string[] = [];
1785
+ const ui = {
1786
+ select: async (prompt: string, opts: string[]) => {
1787
+ prompts.push(prompt);
1788
+ return opts.find((o) => o.startsWith("Always Allow"))!;
1789
+ },
1790
+ notify: () => {},
1791
+ };
1792
+
1793
+ const handler = createClaudeCodeCanUseToolHandler(ui as any);
1794
+ const result = await handler!("Bash", { command: "ls -la /tmp" }, makeOptions());
1795
+
1796
+ assert.equal(result.behavior, "allow");
1797
+ // "ls" has no subcommand tokens before the flag → single-option path
1798
+ assert.equal(prompts.length, 1, "should not show a second dialog");
1799
+ assert.deepEqual((result as any).updatedPermissions, [{
1800
+ type: "addRules",
1801
+ rules: [{ toolName: "Bash", ruleContent: "ls:*" }],
1802
+ behavior: "allow",
1803
+ destination: "localSettings",
1804
+ }]);
1805
+ } finally {
1806
+ cleanup();
1807
+ }
1808
+ });
1809
+
1810
+ test("Always Allow denies the tool when level picker is dismissed", async () => {
1811
+ const cleanup = withIsolatedCwd();
1812
+ try {
1813
+ const notified: string[] = [];
1814
+ let selectCall = 0;
1815
+ const ui = {
1816
+ select: async (_p: string, opts: string[]) => {
1817
+ selectCall++;
1818
+ if (selectCall === 1) return opts.find((o) => o.startsWith("Always Allow"))!;
1819
+ return undefined; // user dismissed level picker
1820
+ },
1821
+ notify: (msg: string) => notified.push(msg),
1822
+ };
1823
+
1824
+ const handler = createClaudeCodeCanUseToolHandler(ui as any);
1825
+ const result = await handler!("Bash", { command: "gh pr list" }, makeOptions());
1826
+
1827
+ // Dismissing the level picker cancels the tool use — a one-time allow
1828
+ // would leave the spawned agent running even though the user bailed.
1829
+ assert.equal(result.behavior, "deny");
1830
+ assert.equal((result as any).updatedPermissions, undefined);
1831
+ assert.equal(notified.length, 0, "no 'Saved:' notification when nothing was saved");
1832
+ } finally {
1833
+ cleanup();
1834
+ }
1835
+ });
1836
+ });
1837
+
1838
+ // ---------------------------------------------------------------------------
1839
+ // buildBashPermissionPattern — smart permission granularity
1840
+ // ---------------------------------------------------------------------------
1841
+
1842
+ describe("buildBashPermissionPattern", () => {
1843
+ test("simple command wildcards all args", () => {
1844
+ assert.equal(buildBashPermissionPattern("ping -n 4 localhost"), "Bash(ping:*)");
1845
+ assert.equal(buildBashPermissionPattern("echo hello world"), "Bash(echo:*)");
1846
+ assert.equal(buildBashPermissionPattern("ls -la /tmp"), "Bash(ls:*)");
1847
+ assert.equal(buildBashPermissionPattern("node server.js"), "Bash(node:*)");
1848
+ });
1849
+
1850
+ test("git captures one subcommand", () => {
1851
+ assert.equal(buildBashPermissionPattern("git push origin main"), "Bash(git push:*)");
1852
+ assert.equal(buildBashPermissionPattern("git log --oneline"), "Bash(git log:*)");
1853
+ assert.equal(buildBashPermissionPattern("git status"), "Bash(git status:*)");
1854
+ });
1855
+
1856
+ test("gh captures two subcommands", () => {
1857
+ assert.equal(buildBashPermissionPattern("gh pr list"), "Bash(gh pr list:*)");
1858
+ assert.equal(buildBashPermissionPattern("gh pr create --title foo"), "Bash(gh pr create:*)");
1859
+ assert.equal(buildBashPermissionPattern("gh issue view 123"), "Bash(gh issue view:*)");
1860
+ });
1861
+
1862
+ test("npm captures one subcommand", () => {
1863
+ assert.equal(buildBashPermissionPattern("npm install lodash"), "Bash(npm install:*)");
1864
+ assert.equal(buildBashPermissionPattern("npm publish"), "Bash(npm publish:*)");
1865
+ assert.equal(buildBashPermissionPattern("npm run test"), "Bash(npm run:*)");
1866
+ });
1867
+
1868
+ test("npx captures package name", () => {
1869
+ assert.equal(buildBashPermissionPattern("npx vitest run"), "Bash(npx vitest:*)");
1870
+ assert.equal(buildBashPermissionPattern("npx --version"), "Bash(npx --version:*)");
1871
+ });
1872
+
1873
+ test("docker captures one subcommand", () => {
1874
+ assert.equal(buildBashPermissionPattern("docker ps -a"), "Bash(docker ps:*)");
1875
+ assert.equal(buildBashPermissionPattern("docker rm container1"), "Bash(docker rm:*)");
1876
+ });
1877
+
1878
+ test("aws captures two subcommands", () => {
1879
+ assert.equal(buildBashPermissionPattern("aws s3 cp file.txt s3://bucket/"), "Bash(aws s3 cp:*)");
1880
+ assert.equal(buildBashPermissionPattern("aws ec2 describe-instances"), "Bash(aws ec2 describe-instances:*)");
1881
+ });
1882
+
1883
+ test("skips sudo wrapper", () => {
1884
+ assert.equal(buildBashPermissionPattern("sudo ping localhost"), "Bash(ping:*)");
1885
+ assert.equal(buildBashPermissionPattern("sudo git push"), "Bash(git push:*)");
1886
+ });
1887
+
1888
+ test("skips env wrapper and VAR=val assignments", () => {
1889
+ assert.equal(buildBashPermissionPattern("env NODE_ENV=prod node server.js"), "Bash(node:*)");
1890
+ assert.equal(buildBashPermissionPattern("NODE_ENV=prod node server.js"), "Bash(node:*)");
1891
+ assert.equal(buildBashPermissionPattern("FOO=bar BAZ=qux git push"), "Bash(git push:*)");
1892
+ });
1893
+
1894
+ test("strips path from executable", () => {
1895
+ assert.equal(buildBashPermissionPattern("/usr/bin/git push"), "Bash(git push:*)");
1896
+ assert.equal(buildBashPermissionPattern("C:\\Windows\\ping.exe localhost"), "Bash(ping:*)");
1897
+ });
1898
+
1899
+ test("empty or whitespace-only command", () => {
1900
+ assert.equal(buildBashPermissionPattern(""), "Bash(*)");
1901
+ assert.equal(buildBashPermissionPattern(" "), "Bash(*)");
1902
+ });
1903
+
1904
+ test("chained commands — extracts pattern from the meaningful segment", () => {
1905
+ assert.equal(buildBashPermissionPattern("cd /foo && gh pr list --limit 5"), "Bash(gh pr list:*)");
1906
+ assert.equal(buildBashPermissionPattern("cd C:/Users/djeff/repos/gsd-2 && gh pr list --limit 5"), "Bash(gh pr list:*)");
1907
+ assert.equal(buildBashPermissionPattern("cd /tmp && git push origin main"), "Bash(git push:*)");
1908
+ assert.equal(buildBashPermissionPattern("export FOO=1 && npm install lodash"), "Bash(npm install:*)");
1909
+ assert.equal(buildBashPermissionPattern("mkdir -p out; docker ps -a"), "Bash(docker ps:*)");
1910
+ assert.equal(buildBashPermissionPattern("echo start || ping localhost"), "Bash(ping:*)");
1911
+ });
1912
+
1913
+ test("skips trailing || true / || : error suppressors", () => {
1914
+ assert.equal(
1915
+ buildBashPermissionPattern("cd C:/Users/djeff/repos/gsd-2 && gh pr create --dry-run --title \"test\" --body \"test\" 2>&1 || true"),
1916
+ "Bash(gh pr create:*)",
1917
+ );
1918
+ assert.equal(buildBashPermissionPattern("gh pr list || true"), "Bash(gh pr list:*)");
1919
+ assert.equal(buildBashPermissionPattern("git push || :"), "Bash(git push:*)");
1920
+ assert.equal(buildBashPermissionPattern("cd /tmp && npm install || echo failed"), "Bash(npm install:*)");
1921
+ });
1922
+
1923
+ test("single command is unaffected by chain extraction", () => {
1924
+ assert.equal(buildBashPermissionPattern("gh pr list"), "Bash(gh pr list:*)");
1925
+ assert.equal(buildBashPermissionPattern("git push origin main"), "Bash(git push:*)");
1926
+ });
1927
+ });
1928
+
1929
+ // ---------------------------------------------------------------------------
1930
+ // buildBashPermissionPatternOptions — granularity level menu
1931
+ // ---------------------------------------------------------------------------
1932
+
1933
+ describe("buildBashPermissionPatternOptions", () => {
1934
+ test("offers every prefix from base to full subcommand chain", () => {
1935
+ assert.deepEqual(buildBashPermissionPatternOptions("gh pr list"), [
1936
+ "Bash(gh:*)",
1937
+ "Bash(gh pr:*)",
1938
+ "Bash(gh pr list:*)",
1939
+ ]);
1940
+ assert.deepEqual(buildBashPermissionPatternOptions("git push origin main"), [
1941
+ "Bash(git:*)",
1942
+ "Bash(git push:*)",
1943
+ "Bash(git push origin:*)",
1944
+ "Bash(git push origin main:*)",
1945
+ ]);
1946
+ });
1947
+
1948
+ test("stops at first flag — flags are args, not verbs", () => {
1949
+ assert.deepEqual(buildBashPermissionPatternOptions("gh pr create --title foo"), [
1950
+ "Bash(gh:*)",
1951
+ "Bash(gh pr:*)",
1952
+ "Bash(gh pr create:*)",
1953
+ ]);
1954
+ assert.deepEqual(buildBashPermissionPatternOptions("git log --oneline"), [
1955
+ "Bash(git:*)",
1956
+ "Bash(git log:*)",
1957
+ ]);
1958
+ });
1959
+
1960
+ test("single-option when there is no subcommand to choose from", () => {
1961
+ assert.deepEqual(buildBashPermissionPatternOptions("ls -la /tmp"), ["Bash(ls:*)"]);
1962
+ assert.deepEqual(buildBashPermissionPatternOptions("ping -n 4 localhost"), ["Bash(ping:*)"]);
1963
+ assert.deepEqual(buildBashPermissionPatternOptions("node"), ["Bash(node:*)"]);
1964
+ });
1965
+
1966
+ test("extracts meaningful segment from compound commands", () => {
1967
+ assert.deepEqual(buildBashPermissionPatternOptions("cd /foo && gh pr list"), [
1968
+ "Bash(gh:*)",
1969
+ "Bash(gh pr:*)",
1970
+ "Bash(gh pr list:*)",
1971
+ ]);
1972
+ assert.deepEqual(buildBashPermissionPatternOptions("gh pr create --dry-run || true"), [
1973
+ "Bash(gh:*)",
1974
+ "Bash(gh pr:*)",
1975
+ "Bash(gh pr create:*)",
1976
+ ]);
1977
+ });
1978
+
1979
+ test("caps at three subcommand tokens to keep the menu short", () => {
1980
+ const result = buildBashPermissionPatternOptions("foo bar baz qux quux corge");
1981
+ // base + 3 sub tokens = 4 patterns max
1982
+ assert.equal(result.length, 4);
1983
+ assert.deepEqual(result, [
1984
+ "Bash(foo:*)",
1985
+ "Bash(foo bar:*)",
1986
+ "Bash(foo bar baz:*)",
1987
+ "Bash(foo bar baz qux:*)",
1988
+ ]);
1989
+ });
1990
+
1991
+ test("skips sudo/env wrappers like the single-pattern variant", () => {
1992
+ assert.deepEqual(buildBashPermissionPatternOptions("sudo git push origin"), [
1993
+ "Bash(git:*)",
1994
+ "Bash(git push:*)",
1995
+ "Bash(git push origin:*)",
1996
+ ]);
1997
+ assert.deepEqual(buildBashPermissionPatternOptions("NODE_ENV=prod node server.js"), [
1998
+ "Bash(node:*)",
1999
+ "Bash(node server.js:*)",
2000
+ ]);
2001
+ });
2002
+
2003
+ test("empty command returns the catch-all pattern", () => {
2004
+ assert.deepEqual(buildBashPermissionPatternOptions(""), ["Bash(*)"]);
2005
+ assert.deepEqual(buildBashPermissionPatternOptions(" "), ["Bash(*)"]);
2006
+ });
2007
+ });
2008
+
2009
+ // ---------------------------------------------------------------------------
2010
+ // bashCommandMatchesSavedRules — compound command bypass for saved rules
2011
+ // ---------------------------------------------------------------------------
2012
+
2013
+ describe("bashCommandMatchesSavedRules — compound command bypass", () => {
2014
+ let tempDir: string;
2015
+ let originalCwd: string;
2016
+
2017
+ // Create a temp project directory with .claude/settings.local.json
2018
+ function setupSettings(allow: string[]): void {
2019
+ const claudeDir = join(tempDir, ".claude");
2020
+ mkdirSync(claudeDir, { recursive: true });
2021
+ writeFileSync(
2022
+ join(claudeDir, "settings.local.json"),
2023
+ JSON.stringify({ permissions: { allow } }),
2024
+ );
2025
+ }
2026
+
2027
+ // biome-ignore lint/suspicious/noExplicitAny: test-only monkey-patch
2028
+ let origCwd: any;
2029
+
2030
+ // Monkey-patch process.cwd() to point at our temp dir
2031
+ function setCwd(dir: string): void {
2032
+ origCwd = process.cwd;
2033
+ process.cwd = () => dir;
2034
+ }
2035
+ function restoreCwd(): void {
2036
+ if (origCwd) process.cwd = origCwd;
2037
+ }
2038
+
2039
+ test("matches cd-prefixed compound command against saved prefix rule", () => {
2040
+ tempDir = realpathSync(mkdtempSync(join(tmpdir(), "gsd-rules-")));
2041
+ try {
2042
+ setupSettings(["Bash(gh pr list:*)"]);
2043
+ setCwd(tempDir);
2044
+ assert.equal(
2045
+ bashCommandMatchesSavedRules("cd /some/path && gh pr list --limit 5"),
2046
+ true,
2047
+ );
2048
+ } finally {
2049
+ restoreCwd();
2050
+ rmSync(tempDir, { recursive: true, force: true });
2051
+ }
2052
+ });
2053
+
2054
+ test("matches cd-prefixed compound command with exact subcommand", () => {
2055
+ tempDir = realpathSync(mkdtempSync(join(tmpdir(), "gsd-rules-")));
2056
+ try {
2057
+ setupSettings(["Bash(gh pr list:*)"]);
2058
+ setCwd(tempDir);
2059
+ assert.equal(
2060
+ bashCommandMatchesSavedRules("cd C:/Users/foo/repos/bar && gh pr list"),
2061
+ true,
2062
+ );
2063
+ } finally {
2064
+ restoreCwd();
2065
+ rmSync(tempDir, { recursive: true, force: true });
2066
+ }
2067
+ });
2068
+
2069
+ test("rejects when leading segment is not cd", () => {
2070
+ tempDir = realpathSync(mkdtempSync(join(tmpdir(), "gsd-rules-")));
2071
+ try {
2072
+ setupSettings(["Bash(gh pr list:*)"]);
2073
+ setCwd(tempDir);
2074
+ // "rm -rf /tmp" is not a cd command — should not auto-approve
2075
+ assert.equal(
2076
+ bashCommandMatchesSavedRules("rm -rf /tmp && gh pr list"),
2077
+ false,
2078
+ );
2079
+ } finally {
2080
+ restoreCwd();
2081
+ rmSync(tempDir, { recursive: true, force: true });
2082
+ }
2083
+ });
2084
+
2085
+ test("rejects when meaningful segment does not match any rule", () => {
2086
+ tempDir = realpathSync(mkdtempSync(join(tmpdir(), "gsd-rules-")));
2087
+ try {
2088
+ setupSettings(["Bash(gh pr list:*)"]);
2089
+ setCwd(tempDir);
2090
+ assert.equal(
2091
+ bashCommandMatchesSavedRules("cd /path && gh issue create --title foo"),
2092
+ false,
2093
+ );
2094
+ } finally {
2095
+ restoreCwd();
2096
+ rmSync(tempDir, { recursive: true, force: true });
2097
+ }
2098
+ });
2099
+
2100
+ test("matches simple (non-compound) commands against on-disk rules", () => {
2101
+ tempDir = realpathSync(mkdtempSync(join(tmpdir(), "gsd-rules-")));
2102
+ try {
2103
+ setupSettings(["Bash(gh pr list:*)"]);
2104
+ setCwd(tempDir);
2105
+ // Simple commands must also be checked — the SDK's in-memory cache
2106
+ // may be stale if the rule was added mid-session via "Always Allow"
2107
+ assert.equal(bashCommandMatchesSavedRules("gh pr list --limit 5"), true);
2108
+ assert.equal(bashCommandMatchesSavedRules("gh pr list"), true);
2109
+ } finally {
2110
+ restoreCwd();
2111
+ rmSync(tempDir, { recursive: true, force: true });
2112
+ }
2113
+ });
2114
+
2115
+ test("returns false for simple commands with no matching rule", () => {
2116
+ tempDir = realpathSync(mkdtempSync(join(tmpdir(), "gsd-rules-")));
2117
+ try {
2118
+ setupSettings(["Bash(gh pr list:*)"]);
2119
+ setCwd(tempDir);
2120
+ assert.equal(bashCommandMatchesSavedRules("gh issue list --limit 5"), false);
2121
+ } finally {
2122
+ restoreCwd();
2123
+ rmSync(tempDir, { recursive: true, force: true });
2124
+ }
2125
+ });
2126
+
2127
+ test("returns false when no settings file exists", () => {
2128
+ tempDir = realpathSync(mkdtempSync(join(tmpdir(), "gsd-rules-")));
2129
+ try {
2130
+ // No .claude/settings.local.json created
2131
+ setCwd(tempDir);
2132
+ assert.equal(
2133
+ bashCommandMatchesSavedRules("cd /path && gh pr list"),
2134
+ false,
2135
+ );
2136
+ } finally {
2137
+ restoreCwd();
2138
+ rmSync(tempDir, { recursive: true, force: true });
2139
+ }
2140
+ });
2141
+
2142
+ test("matches exact rule (non-prefix)", () => {
2143
+ tempDir = realpathSync(mkdtempSync(join(tmpdir(), "gsd-rules-")));
2144
+ try {
2145
+ setupSettings(["Bash(ping -n 4 localhost)"]);
2146
+ setCwd(tempDir);
2147
+ assert.equal(
2148
+ bashCommandMatchesSavedRules("cd /path && ping -n 4 localhost"),
2149
+ true,
2150
+ );
2151
+ } finally {
2152
+ restoreCwd();
2153
+ rmSync(tempDir, { recursive: true, force: true });
2154
+ }
2155
+ });
2156
+
2157
+ test("handles multiple cd segments before the meaningful command", () => {
2158
+ tempDir = realpathSync(mkdtempSync(join(tmpdir(), "gsd-rules-")));
2159
+ try {
2160
+ setupSettings(["Bash(npm install:*)"]);
2161
+ setCwd(tempDir);
2162
+ assert.equal(
2163
+ bashCommandMatchesSavedRules("cd /home && cd project && npm install lodash"),
2164
+ true,
2165
+ );
2166
+ } finally {
2167
+ restoreCwd();
2168
+ rmSync(tempDir, { recursive: true, force: true });
2169
+ }
2170
+ });
2171
+
2172
+ test("matches compound command with trailing || true suppressor", () => {
2173
+ tempDir = realpathSync(mkdtempSync(join(tmpdir(), "gsd-rules-")));
2174
+ try {
2175
+ setupSettings(["Bash(gh pr create:*)"]);
2176
+ setCwd(tempDir);
2177
+ assert.equal(
2178
+ bashCommandMatchesSavedRules('cd C:/Users/djeff/repos/gsd-2 && gh pr create --dry-run --title "test" --body "test" 2>&1 || true'),
2179
+ true,
2180
+ );
2181
+ assert.equal(
2182
+ bashCommandMatchesSavedRules("gh pr create --dry-run || true"),
2183
+ true,
2184
+ );
2185
+ assert.equal(
2186
+ bashCommandMatchesSavedRules("cd /tmp && git push || :"),
2187
+ false, // rule is for gh pr create, not git push
2188
+ );
2189
+ } finally {
2190
+ restoreCwd();
2191
+ rmSync(tempDir, { recursive: true, force: true });
2192
+ }
2193
+ });
2194
+
2195
+ test("reads rules from settings.json as well as settings.local.json", () => {
2196
+ tempDir = realpathSync(mkdtempSync(join(tmpdir(), "gsd-rules-")));
2197
+ try {
2198
+ const claudeDir = join(tempDir, ".claude");
2199
+ mkdirSync(claudeDir, { recursive: true });
2200
+ writeFileSync(
2201
+ join(claudeDir, "settings.json"),
2202
+ JSON.stringify({ permissions: { allow: ["Bash(git push:*)"] } }),
2203
+ );
2204
+ setCwd(tempDir);
2205
+ assert.equal(
2206
+ bashCommandMatchesSavedRules("cd /repo && git push origin main"),
2207
+ true,
2208
+ );
2209
+ } finally {
2210
+ restoreCwd();
2211
+ rmSync(tempDir, { recursive: true, force: true });
2212
+ }
1132
2213
  });
1133
2214
  });