gsd-pi 2.77.0-dev.eaa4973bc → 2.78.0-dev.aeeb2ca00

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 (545) hide show
  1. package/README.md +53 -17
  2. package/dist/claude-cli-check.js +46 -10
  3. package/dist/headless.js +49 -4
  4. package/dist/resource-loader.d.ts +40 -0
  5. package/dist/resource-loader.js +32 -13
  6. package/dist/resources/extensions/browser-tools/capture.js +9 -0
  7. package/dist/resources/extensions/browser-tools/tests/browser-tools-integration.test.mjs +8 -59
  8. package/dist/resources/extensions/browser-tools/tests/browser-tools-unit.test.cjs +36 -24
  9. package/dist/resources/extensions/browser-tools/tests/capture-sharp-optional.test.cjs +69 -71
  10. package/dist/resources/extensions/browser-tools/tools/forms.js +5 -1
  11. package/dist/resources/extensions/browser-tools/tools/intent.js +5 -1
  12. package/dist/resources/extensions/claude-code-cli/readiness.js +72 -16
  13. package/dist/resources/extensions/claude-code-cli/stream-adapter.js +481 -17
  14. package/dist/resources/extensions/github-sync/templates.js +103 -0
  15. package/dist/resources/extensions/google-search/index.js +3 -2
  16. package/dist/resources/extensions/gsd/auto/loop.js +124 -2
  17. package/dist/resources/extensions/gsd/auto/phases.js +57 -39
  18. package/dist/resources/extensions/gsd/auto/session.js +6 -2
  19. package/dist/resources/extensions/gsd/auto-dispatch.js +142 -29
  20. package/dist/resources/extensions/gsd/auto-model-selection.js +124 -4
  21. package/dist/resources/extensions/gsd/auto-post-unit.js +150 -64
  22. package/dist/resources/extensions/gsd/auto-prompts.js +372 -104
  23. package/dist/resources/extensions/gsd/auto-recovery.js +197 -48
  24. package/dist/resources/extensions/gsd/auto-start.js +107 -29
  25. package/dist/resources/extensions/gsd/auto-tool-tracking.js +47 -7
  26. package/dist/resources/extensions/gsd/auto-worktree.js +122 -26
  27. package/dist/resources/extensions/gsd/auto.js +76 -21
  28. package/dist/resources/extensions/gsd/bootstrap/agent-end-recovery.js +19 -1
  29. package/dist/resources/extensions/gsd/bootstrap/db-tools.js +209 -0
  30. package/dist/resources/extensions/gsd/bootstrap/provider-error-resume.js +3 -6
  31. package/dist/resources/extensions/gsd/bootstrap/register-hooks.js +7 -3
  32. package/dist/resources/extensions/gsd/bootstrap/write-gate.js +127 -9
  33. package/dist/resources/extensions/gsd/component-loader.js +447 -0
  34. package/dist/resources/extensions/gsd/component-types.js +69 -0
  35. package/dist/resources/extensions/gsd/context-store.js +23 -7
  36. package/dist/resources/extensions/gsd/detection.js +49 -1
  37. package/dist/resources/extensions/gsd/dispatch-guard.js +2 -17
  38. package/dist/resources/extensions/gsd/docs/preferences-reference.md +1 -1
  39. package/dist/resources/extensions/gsd/forensics.js +106 -0
  40. package/dist/resources/extensions/gsd/gate-registry.js +2 -2
  41. package/dist/resources/extensions/gsd/git-constants.js +28 -1
  42. package/dist/resources/extensions/gsd/git-self-heal.js +27 -0
  43. package/dist/resources/extensions/gsd/git-service.js +126 -2
  44. package/dist/resources/extensions/gsd/gsd-db.js +6 -3
  45. package/dist/resources/extensions/gsd/guided-flow.js +39 -13
  46. package/dist/resources/extensions/gsd/memory-extractor.js +7 -1
  47. package/dist/resources/extensions/gsd/milestone-scope-classifier.js +299 -0
  48. package/dist/resources/extensions/gsd/milestone-summary-classifier.js +37 -0
  49. package/dist/resources/extensions/gsd/model-cost-table.js +3 -0
  50. package/dist/resources/extensions/gsd/model-router.js +6 -0
  51. package/dist/resources/extensions/gsd/native-git-bridge.js +34 -4
  52. package/dist/resources/extensions/gsd/preferences-validation.js +23 -0
  53. package/dist/resources/extensions/gsd/prompt-cache-optimizer.js +4 -0
  54. package/dist/resources/extensions/gsd/prompts/complete-milestone.md +6 -2
  55. package/dist/resources/extensions/gsd/prompts/discuss-headless.md +23 -4
  56. package/dist/resources/extensions/gsd/prompts/doctor-heal.md +5 -4
  57. package/dist/resources/extensions/gsd/prompts/plan-slice.md +15 -2
  58. package/dist/resources/extensions/gsd/safety/git-checkpoint.js +11 -0
  59. package/dist/resources/extensions/gsd/service-tier.js +5 -2
  60. package/dist/resources/extensions/gsd/session-lock.js +19 -10
  61. package/dist/resources/extensions/gsd/skill-manifest.js +168 -0
  62. package/dist/resources/extensions/gsd/slice-cadence.js +238 -0
  63. package/dist/resources/extensions/gsd/slice-parallel-orchestrator.js +278 -8
  64. package/dist/resources/extensions/gsd/state-transition-matrix.js +118 -0
  65. package/dist/resources/extensions/gsd/state.js +69 -58
  66. package/dist/resources/extensions/gsd/sync-lock.js +98 -42
  67. package/dist/resources/extensions/gsd/tools/validate-milestone.js +7 -2
  68. package/dist/resources/extensions/gsd/unit-context-composer.js +147 -0
  69. package/dist/resources/extensions/gsd/unit-context-manifest.js +370 -0
  70. package/dist/resources/extensions/gsd/uok/dispatch-envelope.js +33 -0
  71. package/dist/resources/extensions/gsd/uok/execution-graph.js +10 -0
  72. package/dist/resources/extensions/gsd/uok/gate-runner.js +53 -5
  73. package/dist/resources/extensions/gsd/uok/gitops.js +2 -1
  74. package/dist/resources/extensions/gsd/uok/loop-adapter.js +37 -10
  75. package/dist/resources/extensions/gsd/uok/parity-report.js +58 -0
  76. package/dist/resources/extensions/gsd/uok/plan-v2.js +10 -4
  77. package/dist/resources/extensions/gsd/uok/writer.js +82 -0
  78. package/dist/resources/extensions/gsd/workflow-mcp.js +6 -0
  79. package/dist/resources/extensions/gsd/worktree-manager.js +85 -8
  80. package/dist/resources/extensions/gsd/worktree-resolver.js +86 -7
  81. package/dist/resources/extensions/gsd/worktree-telemetry.js +198 -0
  82. package/dist/resources/extensions/mcp-client/index.js +3 -1
  83. package/dist/resources/extensions/ollama/index.js +5 -1
  84. package/dist/resources/extensions/remote-questions/manager.js +11 -5
  85. package/dist/tsconfig.extensions.tsbuildinfo +1 -1
  86. package/dist/web/standalone/.next/BUILD_ID +1 -1
  87. package/dist/web/standalone/.next/app-path-routes-manifest.json +11 -11
  88. package/dist/web/standalone/.next/build-manifest.json +2 -2
  89. package/dist/web/standalone/.next/prerender-manifest.json +3 -3
  90. package/dist/web/standalone/.next/server/app/_global-error.html +1 -1
  91. package/dist/web/standalone/.next/server/app/_global-error.rsc +1 -1
  92. package/dist/web/standalone/.next/server/app/_global-error.segments/_full.segment.rsc +1 -1
  93. package/dist/web/standalone/.next/server/app/_global-error.segments/_global-error/__PAGE__.segment.rsc +1 -1
  94. package/dist/web/standalone/.next/server/app/_global-error.segments/_global-error.segment.rsc +1 -1
  95. package/dist/web/standalone/.next/server/app/_global-error.segments/_head.segment.rsc +1 -1
  96. package/dist/web/standalone/.next/server/app/_global-error.segments/_index.segment.rsc +1 -1
  97. package/dist/web/standalone/.next/server/app/_global-error.segments/_tree.segment.rsc +1 -1
  98. package/dist/web/standalone/.next/server/app/_not-found.html +1 -1
  99. package/dist/web/standalone/.next/server/app/_not-found.rsc +1 -1
  100. package/dist/web/standalone/.next/server/app/_not-found.segments/_full.segment.rsc +1 -1
  101. package/dist/web/standalone/.next/server/app/_not-found.segments/_head.segment.rsc +1 -1
  102. package/dist/web/standalone/.next/server/app/_not-found.segments/_index.segment.rsc +1 -1
  103. package/dist/web/standalone/.next/server/app/_not-found.segments/_not-found/__PAGE__.segment.rsc +1 -1
  104. package/dist/web/standalone/.next/server/app/_not-found.segments/_not-found.segment.rsc +1 -1
  105. package/dist/web/standalone/.next/server/app/_not-found.segments/_tree.segment.rsc +1 -1
  106. package/dist/web/standalone/.next/server/app/api/git/route.js +1 -1
  107. package/dist/web/standalone/.next/server/app/index.html +1 -1
  108. package/dist/web/standalone/.next/server/app/index.rsc +1 -1
  109. package/dist/web/standalone/.next/server/app/index.segments/__PAGE__.segment.rsc +1 -1
  110. package/dist/web/standalone/.next/server/app/index.segments/_full.segment.rsc +1 -1
  111. package/dist/web/standalone/.next/server/app/index.segments/_head.segment.rsc +1 -1
  112. package/dist/web/standalone/.next/server/app/index.segments/_index.segment.rsc +1 -1
  113. package/dist/web/standalone/.next/server/app/index.segments/_tree.segment.rsc +1 -1
  114. package/dist/web/standalone/.next/server/app-paths-manifest.json +11 -11
  115. package/dist/web/standalone/.next/server/chunks/1926.js +1 -1
  116. package/dist/web/standalone/.next/server/chunks/6897.js +1 -1
  117. package/dist/web/standalone/.next/server/middleware-build-manifest.js +1 -1
  118. package/dist/web/standalone/.next/server/middleware-manifest.json +5 -5
  119. package/dist/web/standalone/.next/server/pages/404.html +1 -1
  120. package/dist/web/standalone/.next/server/pages/500.html +1 -1
  121. package/dist/web/standalone/.next/server/server-reference-manifest.json +1 -1
  122. package/package.json +2 -3
  123. package/packages/daemon/package.json +2 -2
  124. package/packages/daemon/src/logger.ts +4 -3
  125. package/packages/mcp-server/dist/server.d.ts +24 -0
  126. package/packages/mcp-server/dist/server.d.ts.map +1 -1
  127. package/packages/mcp-server/dist/server.js +88 -87
  128. package/packages/mcp-server/dist/server.js.map +1 -1
  129. package/packages/mcp-server/dist/workflow-tools.d.ts.map +1 -1
  130. package/packages/mcp-server/dist/workflow-tools.js +15 -6
  131. package/packages/mcp-server/dist/workflow-tools.js.map +1 -1
  132. package/packages/mcp-server/package.json +2 -2
  133. package/packages/mcp-server/src/mcp-server.test.ts +25 -3
  134. package/packages/mcp-server/src/readers/graph.test.ts +87 -15
  135. package/packages/mcp-server/src/secure-env-collect.test.ts +232 -237
  136. package/packages/mcp-server/src/server.ts +131 -105
  137. package/packages/mcp-server/src/workflow-tools.test.ts +85 -0
  138. package/packages/mcp-server/src/workflow-tools.ts +19 -6
  139. package/packages/mcp-server/tsconfig.tsbuildinfo +1 -1
  140. package/packages/native/package.json +2 -2
  141. package/packages/native/src/__tests__/_test-coverage-guard.test.mjs +98 -0
  142. package/packages/native/src/__tests__/module-compat.test.mjs +59 -27
  143. package/packages/native/src/__tests__/ps.test.mjs +14 -8
  144. package/packages/native/src/__tests__/stream-process.test.mjs +23 -2
  145. package/packages/native/src/__tests__/truncate.test.mjs +17 -2
  146. package/packages/pi-agent-core/package.json +1 -1
  147. package/packages/pi-agent-core/src/agent-loop.test.ts +5 -15
  148. package/packages/pi-agent-core/src/agent.test.ts +96 -102
  149. package/packages/pi-agent-core/tsconfig.tsbuildinfo +1 -1
  150. package/packages/pi-ai/dist/models/capability-patches.d.ts.map +1 -1
  151. package/packages/pi-ai/dist/models/capability-patches.js +9 -2
  152. package/packages/pi-ai/dist/models/capability-patches.js.map +1 -1
  153. package/packages/pi-ai/dist/models/generated/index.d.ts +34 -0
  154. package/packages/pi-ai/dist/models/generated/index.d.ts.map +1 -1
  155. package/packages/pi-ai/dist/models/generated/openai-codex.d.ts +17 -0
  156. package/packages/pi-ai/dist/models/generated/openai-codex.d.ts.map +1 -1
  157. package/packages/pi-ai/dist/models/generated/openai-codex.js +17 -0
  158. package/packages/pi-ai/dist/models/generated/openai-codex.js.map +1 -1
  159. package/packages/pi-ai/dist/models/generated/openai.d.ts +17 -0
  160. package/packages/pi-ai/dist/models/generated/openai.d.ts.map +1 -1
  161. package/packages/pi-ai/dist/models/generated/openai.js +17 -0
  162. package/packages/pi-ai/dist/models/generated/openai.js.map +1 -1
  163. package/packages/pi-ai/dist/models.generated.test.js +43 -70
  164. package/packages/pi-ai/dist/models.generated.test.js.map +1 -1
  165. package/packages/pi-ai/dist/models.test.js +36 -11
  166. package/packages/pi-ai/dist/models.test.js.map +1 -1
  167. package/packages/pi-ai/package.json +1 -1
  168. package/packages/pi-ai/scripts/generate-models.ts +44 -0
  169. package/packages/pi-ai/src/models/capability-patches.ts +10 -2
  170. package/packages/pi-ai/src/models/generated/openai-codex.ts +17 -0
  171. package/packages/pi-ai/src/models/generated/openai.ts +17 -0
  172. package/packages/pi-ai/src/models.generated.test.ts +46 -73
  173. package/packages/pi-ai/src/models.test.ts +48 -11
  174. package/packages/pi-ai/tsconfig.tsbuildinfo +1 -1
  175. package/packages/pi-coding-agent/dist/core/agent-session-abort-order.test.js +96 -32
  176. package/packages/pi-coding-agent/dist/core/agent-session-abort-order.test.js.map +1 -1
  177. package/packages/pi-coding-agent/dist/core/agent-session-model-switch.test.js +75 -12
  178. package/packages/pi-coding-agent/dist/core/agent-session-model-switch.test.js.map +1 -1
  179. package/packages/pi-coding-agent/dist/core/agent-session-tool-refresh.test.js +99 -31
  180. package/packages/pi-coding-agent/dist/core/agent-session-tool-refresh.test.js.map +1 -1
  181. package/packages/pi-coding-agent/dist/core/extensions/loader.d.ts +5 -0
  182. package/packages/pi-coding-agent/dist/core/extensions/loader.d.ts.map +1 -1
  183. package/packages/pi-coding-agent/dist/core/extensions/loader.js +61 -0
  184. package/packages/pi-coding-agent/dist/core/extensions/loader.js.map +1 -1
  185. package/packages/pi-coding-agent/dist/core/lsp/lsp-integration.test.js +30 -4
  186. package/packages/pi-coding-agent/dist/core/lsp/lsp-integration.test.js.map +1 -1
  187. package/packages/pi-coding-agent/dist/core/model-registry-auth-mode.test.js +17 -0
  188. package/packages/pi-coding-agent/dist/core/model-registry-auth-mode.test.js.map +1 -1
  189. package/packages/pi-coding-agent/dist/core/resource-loader-cache-reset.test.js +76 -18
  190. package/packages/pi-coding-agent/dist/core/resource-loader-cache-reset.test.js.map +1 -1
  191. package/packages/pi-coding-agent/dist/core/retry-handler.d.ts.map +1 -1
  192. package/packages/pi-coding-agent/dist/core/retry-handler.js +2 -6
  193. package/packages/pi-coding-agent/dist/core/retry-handler.js.map +1 -1
  194. package/packages/pi-coding-agent/dist/core/retry-handler.test.js +5 -1
  195. package/packages/pi-coding-agent/dist/core/retry-handler.test.js.map +1 -1
  196. package/packages/pi-coding-agent/dist/core/retryable-error-regex.d.ts +18 -0
  197. package/packages/pi-coding-agent/dist/core/retryable-error-regex.d.ts.map +1 -0
  198. package/packages/pi-coding-agent/dist/core/retryable-error-regex.js +18 -0
  199. package/packages/pi-coding-agent/dist/core/retryable-error-regex.js.map +1 -0
  200. package/packages/pi-coding-agent/dist/core/system-prompt.d.ts +20 -0
  201. package/packages/pi-coding-agent/dist/core/system-prompt.d.ts.map +1 -1
  202. package/packages/pi-coding-agent/dist/core/system-prompt.js +16 -2
  203. package/packages/pi-coding-agent/dist/core/system-prompt.js.map +1 -1
  204. package/packages/pi-coding-agent/dist/index.d.ts +1 -0
  205. package/packages/pi-coding-agent/dist/index.d.ts.map +1 -1
  206. package/packages/pi-coding-agent/dist/index.js +1 -0
  207. package/packages/pi-coding-agent/dist/index.js.map +1 -1
  208. package/packages/pi-coding-agent/dist/modes/interactive/components/__tests__/tool-execution.test.js +36 -5
  209. package/packages/pi-coding-agent/dist/modes/interactive/components/__tests__/tool-execution.test.js.map +1 -1
  210. package/packages/pi-coding-agent/dist/modes/interactive/components/dynamic-border.test.js +20 -13
  211. package/packages/pi-coding-agent/dist/modes/interactive/components/dynamic-border.test.js.map +1 -1
  212. package/packages/pi-coding-agent/dist/modes/interactive/components/tool-execution.d.ts.map +1 -1
  213. package/packages/pi-coding-agent/dist/modes/interactive/components/tool-execution.js +30 -12
  214. package/packages/pi-coding-agent/dist/modes/interactive/components/tool-execution.js.map +1 -1
  215. package/packages/pi-coding-agent/dist/modes/interactive/controllers/input-controller.d.ts.map +1 -1
  216. package/packages/pi-coding-agent/dist/modes/interactive/controllers/input-controller.js +18 -3
  217. package/packages/pi-coding-agent/dist/modes/interactive/controllers/input-controller.js.map +1 -1
  218. package/packages/pi-coding-agent/dist/modes/interactive/controllers/input-controller.test.js +125 -0
  219. package/packages/pi-coding-agent/dist/modes/interactive/controllers/input-controller.test.js.map +1 -1
  220. package/packages/pi-coding-agent/dist/modes/interactive/interactive-mode-state.d.ts +2 -0
  221. package/packages/pi-coding-agent/dist/modes/interactive/interactive-mode-state.d.ts.map +1 -1
  222. package/packages/pi-coding-agent/dist/modes/interactive/interactive-mode-state.js.map +1 -1
  223. package/packages/pi-coding-agent/dist/modes/interactive/interactive-mode.d.ts +4 -0
  224. package/packages/pi-coding-agent/dist/modes/interactive/interactive-mode.d.ts.map +1 -1
  225. package/packages/pi-coding-agent/dist/modes/interactive/interactive-mode.js +105 -13
  226. package/packages/pi-coding-agent/dist/modes/interactive/interactive-mode.js.map +1 -1
  227. package/packages/pi-coding-agent/dist/tests/system-prompt-skill-filter.test.d.ts +2 -0
  228. package/packages/pi-coding-agent/dist/tests/system-prompt-skill-filter.test.d.ts.map +1 -0
  229. package/packages/pi-coding-agent/dist/tests/system-prompt-skill-filter.test.js +130 -0
  230. package/packages/pi-coding-agent/dist/tests/system-prompt-skill-filter.test.js.map +1 -0
  231. package/packages/pi-coding-agent/package.json +1 -1
  232. package/packages/pi-coding-agent/src/core/agent-session-abort-order.test.ts +113 -37
  233. package/packages/pi-coding-agent/src/core/agent-session-model-switch.test.ts +89 -17
  234. package/packages/pi-coding-agent/src/core/agent-session-tool-refresh.test.ts +112 -43
  235. package/packages/pi-coding-agent/src/core/extensions/loader.ts +58 -0
  236. package/packages/pi-coding-agent/src/core/lsp/lsp-integration.test.ts +35 -4
  237. package/packages/pi-coding-agent/src/core/model-registry-auth-mode.test.ts +20 -0
  238. package/packages/pi-coding-agent/src/core/resource-loader-cache-reset.test.ts +93 -28
  239. package/packages/pi-coding-agent/src/core/retry-handler.test.ts +5 -1
  240. package/packages/pi-coding-agent/src/core/retry-handler.ts +2 -8
  241. package/packages/pi-coding-agent/src/core/retryable-error-regex.ts +18 -0
  242. package/packages/pi-coding-agent/src/core/system-prompt.ts +35 -1
  243. package/packages/pi-coding-agent/src/index.ts +1 -0
  244. package/packages/pi-coding-agent/src/modes/interactive/components/__tests__/tool-execution.test.ts +49 -3
  245. package/packages/pi-coding-agent/src/modes/interactive/components/dynamic-border.test.ts +26 -20
  246. package/packages/pi-coding-agent/src/modes/interactive/components/tool-execution.ts +48 -9
  247. package/packages/pi-coding-agent/src/modes/interactive/controllers/input-controller.test.ts +146 -1
  248. package/packages/pi-coding-agent/src/modes/interactive/controllers/input-controller.ts +20 -3
  249. package/packages/pi-coding-agent/src/modes/interactive/interactive-mode-state.ts +2 -0
  250. package/packages/pi-coding-agent/src/modes/interactive/interactive-mode.ts +119 -13
  251. package/packages/pi-coding-agent/src/tests/system-prompt-skill-filter.test.ts +157 -0
  252. package/packages/pi-coding-agent/tsconfig.tsbuildinfo +1 -1
  253. package/packages/pi-tui/dist/__tests__/autocomplete.test.js +18 -8
  254. package/packages/pi-tui/dist/__tests__/autocomplete.test.js.map +1 -1
  255. package/packages/pi-tui/dist/__tests__/overlay-layout.test.js +128 -17
  256. package/packages/pi-tui/dist/__tests__/overlay-layout.test.js.map +1 -1
  257. package/packages/pi-tui/dist/__tests__/stdin-buffer.test.js +37 -11
  258. package/packages/pi-tui/dist/__tests__/stdin-buffer.test.js.map +1 -1
  259. package/packages/pi-tui/dist/__tests__/tui.test.js +18 -30
  260. package/packages/pi-tui/dist/__tests__/tui.test.js.map +1 -1
  261. package/packages/pi-tui/dist/components/__tests__/input.test.js +10 -3
  262. package/packages/pi-tui/dist/components/__tests__/input.test.js.map +1 -1
  263. package/packages/pi-tui/dist/components/__tests__/loader.test.js +53 -9
  264. package/packages/pi-tui/dist/components/__tests__/loader.test.js.map +1 -1
  265. package/packages/pi-tui/dist/components/__tests__/markdown-maxlines.test.js +6 -2
  266. package/packages/pi-tui/dist/components/__tests__/markdown-maxlines.test.js.map +1 -1
  267. package/packages/pi-tui/dist/components/editor.d.ts +14 -0
  268. package/packages/pi-tui/dist/components/editor.d.ts.map +1 -1
  269. package/packages/pi-tui/dist/components/editor.js +19 -0
  270. package/packages/pi-tui/dist/components/editor.js.map +1 -1
  271. package/packages/pi-tui/dist/components/image.test.js +6 -5
  272. package/packages/pi-tui/dist/components/image.test.js.map +1 -1
  273. package/packages/pi-tui/dist/editor-component.d.ts +2 -0
  274. package/packages/pi-tui/dist/editor-component.d.ts.map +1 -1
  275. package/packages/pi-tui/dist/editor-component.js.map +1 -1
  276. package/packages/pi-tui/package.json +1 -1
  277. package/packages/pi-tui/src/__tests__/autocomplete.test.ts +24 -8
  278. package/packages/pi-tui/src/__tests__/overlay-layout.test.ts +140 -17
  279. package/packages/pi-tui/src/__tests__/stdin-buffer.test.ts +42 -11
  280. package/packages/pi-tui/src/__tests__/tui.test.ts +18 -37
  281. package/packages/pi-tui/src/components/__tests__/input.test.ts +19 -3
  282. package/packages/pi-tui/src/components/__tests__/loader.test.ts +112 -35
  283. package/packages/pi-tui/src/components/__tests__/markdown-maxlines.test.ts +9 -2
  284. package/packages/pi-tui/src/components/editor.ts +22 -0
  285. package/packages/pi-tui/src/components/image.test.ts +10 -5
  286. package/packages/pi-tui/src/editor-component.ts +3 -0
  287. package/packages/pi-tui/tsconfig.tsbuildinfo +1 -1
  288. package/packages/rpc-client/dist/rpc-client.test.js +101 -51
  289. package/packages/rpc-client/dist/rpc-client.test.js.map +1 -1
  290. package/packages/rpc-client/package.json +1 -1
  291. package/packages/rpc-client/src/rpc-client.test.ts +109 -52
  292. package/packages/rpc-client/tsconfig.tsbuildinfo +1 -1
  293. package/pkg/package.json +1 -1
  294. package/scripts/install.js +15 -1
  295. package/src/resources/extensions/browser-tools/capture.ts +12 -0
  296. package/src/resources/extensions/browser-tools/tests/browser-tools-integration.test.mjs +8 -59
  297. package/src/resources/extensions/browser-tools/tests/browser-tools-unit.test.cjs +36 -24
  298. package/src/resources/extensions/browser-tools/tests/capture-sharp-optional.test.cjs +69 -71
  299. package/src/resources/extensions/browser-tools/tools/forms.ts +5 -1
  300. package/src/resources/extensions/browser-tools/tools/intent.ts +5 -1
  301. package/src/resources/extensions/claude-code-cli/readiness.ts +75 -16
  302. package/src/resources/extensions/claude-code-cli/stream-adapter.ts +518 -19
  303. package/src/resources/extensions/claude-code-cli/tests/stream-adapter.test.ts +919 -75
  304. package/src/resources/extensions/github-sync/templates.ts +151 -0
  305. package/src/resources/extensions/github-sync/tests/cli.test.ts +76 -7
  306. package/src/resources/extensions/github-sync/tests/templates.test.ts +92 -1
  307. package/src/resources/extensions/google-search/index.ts +3 -2
  308. package/src/resources/extensions/gsd/auto/loop.ts +142 -2
  309. package/src/resources/extensions/gsd/auto/phases.ts +62 -38
  310. package/src/resources/extensions/gsd/auto/session.ts +7 -2
  311. package/src/resources/extensions/gsd/auto-dispatch.ts +156 -29
  312. package/src/resources/extensions/gsd/auto-model-selection.ts +131 -4
  313. package/src/resources/extensions/gsd/auto-post-unit.ts +163 -73
  314. package/src/resources/extensions/gsd/auto-prompts.ts +385 -93
  315. package/src/resources/extensions/gsd/auto-recovery.ts +230 -51
  316. package/src/resources/extensions/gsd/auto-start.ts +127 -9
  317. package/src/resources/extensions/gsd/auto-tool-tracking.ts +51 -7
  318. package/src/resources/extensions/gsd/auto-worktree.ts +130 -26
  319. package/src/resources/extensions/gsd/auto.ts +90 -23
  320. package/src/resources/extensions/gsd/bootstrap/agent-end-recovery.ts +20 -1
  321. package/src/resources/extensions/gsd/bootstrap/db-tools.ts +221 -0
  322. package/src/resources/extensions/gsd/bootstrap/provider-error-resume.ts +3 -7
  323. package/src/resources/extensions/gsd/bootstrap/register-hooks.ts +7 -3
  324. package/src/resources/extensions/gsd/bootstrap/write-gate.ts +158 -9
  325. package/src/resources/extensions/gsd/component-loader.ts +598 -0
  326. package/src/resources/extensions/gsd/component-types.ts +362 -0
  327. package/src/resources/extensions/gsd/context-store.ts +25 -8
  328. package/src/resources/extensions/gsd/detection.ts +58 -1
  329. package/src/resources/extensions/gsd/dispatch-guard.ts +2 -20
  330. package/src/resources/extensions/gsd/docs/preferences-reference.md +1 -1
  331. package/src/resources/extensions/gsd/forensics.ts +118 -1
  332. package/src/resources/extensions/gsd/gate-registry.ts +2 -2
  333. package/src/resources/extensions/gsd/git-constants.ts +30 -1
  334. package/src/resources/extensions/gsd/git-self-heal.ts +31 -0
  335. package/src/resources/extensions/gsd/git-service.ts +149 -2
  336. package/src/resources/extensions/gsd/gsd-db.ts +6 -3
  337. package/src/resources/extensions/gsd/guided-flow.ts +57 -14
  338. package/src/resources/extensions/gsd/journal.ts +11 -1
  339. package/src/resources/extensions/gsd/memory-extractor.ts +11 -3
  340. package/src/resources/extensions/gsd/milestone-scope-classifier.ts +366 -0
  341. package/src/resources/extensions/gsd/milestone-summary-classifier.ts +42 -0
  342. package/src/resources/extensions/gsd/model-cost-table.ts +3 -0
  343. package/src/resources/extensions/gsd/model-router.ts +6 -0
  344. package/src/resources/extensions/gsd/native-git-bridge.ts +34 -4
  345. package/src/resources/extensions/gsd/preferences-validation.ts +21 -0
  346. package/src/resources/extensions/gsd/prompt-cache-optimizer.ts +4 -0
  347. package/src/resources/extensions/gsd/prompts/complete-milestone.md +6 -2
  348. package/src/resources/extensions/gsd/prompts/discuss-headless.md +23 -4
  349. package/src/resources/extensions/gsd/prompts/doctor-heal.md +5 -4
  350. package/src/resources/extensions/gsd/prompts/plan-slice.md +15 -2
  351. package/src/resources/extensions/gsd/safety/git-checkpoint.ts +15 -0
  352. package/src/resources/extensions/gsd/service-tier.ts +5 -2
  353. package/src/resources/extensions/gsd/session-lock.ts +20 -10
  354. package/src/resources/extensions/gsd/skill-manifest.ts +175 -0
  355. package/src/resources/extensions/gsd/slice-cadence.ts +299 -0
  356. package/src/resources/extensions/gsd/slice-parallel-orchestrator.ts +309 -8
  357. package/src/resources/extensions/gsd/state-transition-matrix.ts +152 -0
  358. package/src/resources/extensions/gsd/state.ts +76 -66
  359. package/src/resources/extensions/gsd/sync-lock.ts +97 -39
  360. package/src/resources/extensions/gsd/tests/artifact-retry-cap.test.ts +270 -0
  361. package/src/resources/extensions/gsd/tests/artifacts-table-preserved-on-cache-invalidate.test.ts +2 -1
  362. package/src/resources/extensions/gsd/tests/auto-deterministic-error-classification-4973.test.ts +341 -0
  363. package/src/resources/extensions/gsd/tests/auto-discuss-milestone-deadlock-4973.test.ts +264 -0
  364. package/src/resources/extensions/gsd/tests/auto-loop.test.ts +133 -292
  365. package/src/resources/extensions/gsd/tests/auto-model-selection-tool-poisoning.test.ts +742 -0
  366. package/src/resources/extensions/gsd/tests/auto-model-selection.test.ts +78 -0
  367. package/src/resources/extensions/gsd/tests/auto-phases-lifecycle.test.ts +61 -0
  368. package/src/resources/extensions/gsd/tests/auto-recovery.test.ts +93 -0
  369. package/src/resources/extensions/gsd/tests/auto-remediate-slice-status.test.ts +4 -1
  370. package/src/resources/extensions/gsd/tests/auto-retry-mcp-churn-fixes.test.ts +8 -194
  371. package/src/resources/extensions/gsd/tests/auto-start-clean-runtime-db-gated.test.ts +3 -2
  372. package/src/resources/extensions/gsd/tests/auto-start-cold-db-bootstrap.test.ts +2 -2
  373. package/src/resources/extensions/gsd/tests/auto-start-needs-discussion.test.ts +15 -58
  374. package/src/resources/extensions/gsd/tests/auto-start-worktree-db-path.test.ts +2 -2
  375. package/src/resources/extensions/gsd/tests/auto-thinking-restore.test.ts +3 -2
  376. package/src/resources/extensions/gsd/tests/auto-warning-noise-regression.test.ts +3 -2
  377. package/src/resources/extensions/gsd/tests/bootstrap-derive-state-db-open.test.ts +2 -1
  378. package/src/resources/extensions/gsd/tests/cache-staleness-regression.test.ts +17 -21
  379. package/src/resources/extensions/gsd/tests/canonical-milestone-root.test.ts +108 -0
  380. package/src/resources/extensions/gsd/tests/complete-milestone-excerpt.test.ts +263 -0
  381. package/src/resources/extensions/gsd/tests/complete-milestone.test.ts +25 -0
  382. package/src/resources/extensions/gsd/tests/complete-slice-composer.test.ts +192 -0
  383. package/src/resources/extensions/gsd/tests/complete-slice-verification-gate.test.ts +2 -1
  384. package/src/resources/extensions/gsd/tests/complete-task.test.ts +16 -8
  385. package/src/resources/extensions/gsd/tests/component-loader.test.ts +589 -0
  386. package/src/resources/extensions/gsd/tests/component-types.test.ts +127 -0
  387. package/src/resources/extensions/gsd/tests/context-store.test.ts +79 -0
  388. package/src/resources/extensions/gsd/tests/copy-planning-artifacts-samepath.test.ts +2 -1
  389. package/src/resources/extensions/gsd/tests/crash-recovery.test.ts +50 -1
  390. package/src/resources/extensions/gsd/tests/custom-engine-loop-integration.test.ts +159 -0
  391. package/src/resources/extensions/gsd/tests/db-access-guardrails.test.ts +1 -0
  392. package/src/resources/extensions/gsd/tests/derive-state-crossval.test.ts +3 -3
  393. package/src/resources/extensions/gsd/tests/derive-state-db-disk-reconcile.test.ts +40 -0
  394. package/src/resources/extensions/gsd/tests/derive-state-db.test.ts +91 -3
  395. package/src/resources/extensions/gsd/tests/derive-state.test.ts +4 -4
  396. package/src/resources/extensions/gsd/tests/discuss-slice-structured-questions.test.ts +2 -1
  397. package/src/resources/extensions/gsd/tests/discuss-tool-scope-leak.test.ts +2 -1
  398. package/src/resources/extensions/gsd/tests/dispatch-complete-milestone-guard.test.ts +5 -0
  399. package/src/resources/extensions/gsd/tests/dispatch-guard.test.ts +25 -0
  400. package/src/resources/extensions/gsd/tests/dispatch-missing-task-plans.test.ts +14 -0
  401. package/src/resources/extensions/gsd/tests/dispatcher-stuck-planning.test.ts +3 -2
  402. package/src/resources/extensions/gsd/tests/double-merge-guard.test.ts +4 -3
  403. package/src/resources/extensions/gsd/tests/empty-content-abort-loop.test.ts +4 -3
  404. package/src/resources/extensions/gsd/tests/execution-entry-missing-context-4671.test.ts +173 -0
  405. package/src/resources/extensions/gsd/tests/extension-bootstrap-isolation.test.ts +139 -129
  406. package/src/resources/extensions/gsd/tests/finalize-timeout-guard.test.ts +8 -104
  407. package/src/resources/extensions/gsd/tests/gate-state-canonicalization.test.ts +102 -0
  408. package/src/resources/extensions/gsd/tests/gate-storage.test.ts +1 -1
  409. package/src/resources/extensions/gsd/tests/google-search-stub.test.ts +14 -4
  410. package/src/resources/extensions/gsd/tests/headless-milestone-parity.test.ts +117 -0
  411. package/src/resources/extensions/gsd/tests/hook-key-parsing.test.ts +4 -55
  412. package/src/resources/extensions/gsd/tests/integration/all-milestones-complete-merge.test.ts +7 -56
  413. package/src/resources/extensions/gsd/tests/integration/auto-recovery.test.ts +20 -0
  414. package/src/resources/extensions/gsd/tests/integration/doctor-proactive.test.ts +18 -2
  415. package/src/resources/extensions/gsd/tests/integration/queue-completed-milestone-perf.test.ts +10 -4
  416. package/src/resources/extensions/gsd/tests/integration/state-machine-edge-cases.test.ts +144 -7
  417. package/src/resources/extensions/gsd/tests/integration/state-machine-live-validation.test.ts +4 -0
  418. package/src/resources/extensions/gsd/tests/integration/state-machine-runtime-failures.test.ts +2 -16
  419. package/src/resources/extensions/gsd/tests/interactive-routing-bypass.test.ts +9 -3
  420. package/src/resources/extensions/gsd/tests/interrupted-session-ui.test.ts +6 -9
  421. package/src/resources/extensions/gsd/tests/journal-integration.test.ts +64 -0
  422. package/src/resources/extensions/gsd/tests/knowledge.test.ts +93 -1
  423. package/src/resources/extensions/gsd/tests/mcp-client-security.test.ts +8 -37
  424. package/src/resources/extensions/gsd/tests/memory-extractor.test.ts +5 -15
  425. package/src/resources/extensions/gsd/tests/merge-conflict-stops-loop.test.ts +227 -55
  426. package/src/resources/extensions/gsd/tests/milestone-scope-classifier.test.ts +187 -0
  427. package/src/resources/extensions/gsd/tests/milestone-summary-classifier.test.ts +30 -0
  428. package/src/resources/extensions/gsd/tests/model-cost-table.test.ts +9 -1
  429. package/src/resources/extensions/gsd/tests/model-router.test.ts +1 -1
  430. package/src/resources/extensions/gsd/tests/native-git-bridge-exec-fallback.test.ts +6 -48
  431. package/src/resources/extensions/gsd/tests/notification-widget.test.ts +6 -3
  432. package/src/resources/extensions/gsd/tests/orphaned-worktree-audit.test.ts +59 -2
  433. package/src/resources/extensions/gsd/tests/parallel-research-dispatch.test.ts +273 -130
  434. package/src/resources/extensions/gsd/tests/pipeline-variant-dispatch.test.ts +301 -0
  435. package/src/resources/extensions/gsd/tests/pre-execution-pause-wiring.test.ts +32 -1
  436. package/src/resources/extensions/gsd/tests/preferences-worktree-sync.test.ts +2 -1
  437. package/src/resources/extensions/gsd/tests/prompt-cache-optimizer.test.ts +12 -0
  438. package/src/resources/extensions/gsd/tests/prompt-step-ordering.test.ts +15 -4
  439. package/src/resources/extensions/gsd/tests/provider-errors.test.ts +23 -24
  440. package/src/resources/extensions/gsd/tests/queue-auto-guard.test.ts +32 -0
  441. package/src/resources/extensions/gsd/tests/queue-draft-detection.test.ts +3 -2
  442. package/src/resources/extensions/gsd/tests/queued-discuss-fast-path.test.ts +4 -5
  443. package/src/resources/extensions/gsd/tests/ready-phrase-no-files-4573.test.ts +75 -2
  444. package/src/resources/extensions/gsd/tests/reassess-default-optin.test.ts +132 -0
  445. package/src/resources/extensions/gsd/tests/recovery-attempts-reset.test.ts +8 -40
  446. package/src/resources/extensions/gsd/tests/regex-hardening.test.ts +136 -256
  447. package/src/resources/extensions/gsd/tests/research-milestone-composer.test.ts +114 -0
  448. package/src/resources/extensions/gsd/tests/restore-tools-after-discuss.test.ts +6 -3
  449. package/src/resources/extensions/gsd/tests/run-uat-composer.test.ts +148 -0
  450. package/src/resources/extensions/gsd/tests/service-tier.test.ts +4 -0
  451. package/src/resources/extensions/gsd/tests/session-lock-regression.test.ts +29 -0
  452. package/src/resources/extensions/gsd/tests/sidecar-queue.test.ts +3 -2
  453. package/src/resources/extensions/gsd/tests/silent-catch-diagnostics.test.ts +55 -95
  454. package/src/resources/extensions/gsd/tests/single-writer-v3-tool-surface.test.ts +158 -0
  455. package/src/resources/extensions/gsd/tests/skill-activation.test.ts +120 -1
  456. package/src/resources/extensions/gsd/tests/skill-manifest.test.ts +112 -0
  457. package/src/resources/extensions/gsd/tests/slice-cadence.test.ts +242 -0
  458. package/src/resources/extensions/gsd/tests/slice-context-injection.test.ts +3 -2
  459. package/src/resources/extensions/gsd/tests/slice-parallel-orchestrator.test.ts +164 -1
  460. package/src/resources/extensions/gsd/tests/smart-entry-draft.test.ts +2 -1
  461. package/src/resources/extensions/gsd/tests/stale-dirlistcache-4648.test.ts +112 -0
  462. package/src/resources/extensions/gsd/tests/state-machine-full-walkthrough.test.ts +29 -5
  463. package/src/resources/extensions/gsd/tests/state-transition-matrix.test.ts +44 -0
  464. package/src/resources/extensions/gsd/tests/stop-auto-race-null-unit.test.ts +3 -3
  465. package/src/resources/extensions/gsd/tests/structured-data-formatter.test.ts +11 -92
  466. package/src/resources/extensions/gsd/tests/subagent-model-dispatch.test.ts +7 -6
  467. package/src/resources/extensions/gsd/tests/survivor-branch-complete.test.ts +102 -101
  468. package/src/resources/extensions/gsd/tests/sync-lock.test.ts +31 -0
  469. package/src/resources/extensions/gsd/tests/sync-worktree-skip-current.test.ts +4 -3
  470. package/src/resources/extensions/gsd/tests/test-helpers.test.ts +98 -0
  471. package/src/resources/extensions/gsd/tests/test-helpers.ts +153 -0
  472. package/src/resources/extensions/gsd/tests/token-profile.test.ts +8 -1
  473. package/src/resources/extensions/gsd/tests/tool-invocation-error-loop-break.test.ts +61 -1
  474. package/src/resources/extensions/gsd/tests/tool-naming.test.ts +8 -1
  475. package/src/resources/extensions/gsd/tests/unit-context-composer.test.ts +355 -0
  476. package/src/resources/extensions/gsd/tests/unit-context-manifest.test.ts +258 -0
  477. package/src/resources/extensions/gsd/tests/uok-contracts.test.ts +51 -0
  478. package/src/resources/extensions/gsd/tests/uok-execution-graph.test.ts +16 -0
  479. package/src/resources/extensions/gsd/tests/uok-gate-runner.test.ts +75 -0
  480. package/src/resources/extensions/gsd/tests/uok-gitops-wiring.test.ts +49 -26
  481. package/src/resources/extensions/gsd/tests/uok-loop-adapter-writer.test.ts +65 -0
  482. package/src/resources/extensions/gsd/tests/uok-parity-report.test.ts +42 -0
  483. package/src/resources/extensions/gsd/tests/uok-plan-v2-wiring.test.ts +19 -2
  484. package/src/resources/extensions/gsd/tests/uok-writer.test.ts +75 -0
  485. package/src/resources/extensions/gsd/tests/validate-milestone.test.ts +12 -0
  486. package/src/resources/extensions/gsd/tests/verify-artifact-tightened.test.ts +144 -80
  487. package/src/resources/extensions/gsd/tests/visualizer-critical-path.test.ts +20 -54
  488. package/src/resources/extensions/gsd/tests/visualizer-overlay.test.ts +342 -277
  489. package/src/resources/extensions/gsd/tests/worker-model-override.test.ts +37 -29
  490. package/src/resources/extensions/gsd/tests/worktree-db.test.ts +226 -266
  491. package/src/resources/extensions/gsd/tests/worktree-health-monorepo.test.ts +103 -67
  492. package/src/resources/extensions/gsd/tests/worktree-nested-git-safety.test.ts +92 -90
  493. package/src/resources/extensions/gsd/tests/worktree-submodule-safety.test.ts +238 -59
  494. package/src/resources/extensions/gsd/tests/worktree-sync-overwrite-loop.test.ts +113 -161
  495. package/src/resources/extensions/gsd/tests/worktree-telemetry.test.ts +210 -0
  496. package/src/resources/extensions/gsd/tests/write-gate-planning-unit.test.ts +262 -0
  497. package/src/resources/extensions/gsd/tests/write-gate-predicates.test.ts +186 -0
  498. package/src/resources/extensions/gsd/tests/write-gate.test.ts +7 -5
  499. package/src/resources/extensions/gsd/tests/zombie-gsd-state.test.ts +80 -96
  500. package/src/resources/extensions/gsd/tools/validate-milestone.ts +8 -2
  501. package/src/resources/extensions/gsd/types.ts +3 -3
  502. package/src/resources/extensions/gsd/unit-context-composer.ts +218 -0
  503. package/src/resources/extensions/gsd/unit-context-manifest.ts +574 -0
  504. package/src/resources/extensions/gsd/uok/contracts.ts +65 -0
  505. package/src/resources/extensions/gsd/uok/dispatch-envelope.ts +56 -0
  506. package/src/resources/extensions/gsd/uok/execution-graph.ts +22 -0
  507. package/src/resources/extensions/gsd/uok/gate-runner.ts +65 -5
  508. package/src/resources/extensions/gsd/uok/gitops.ts +6 -1
  509. package/src/resources/extensions/gsd/uok/loop-adapter.ts +45 -10
  510. package/src/resources/extensions/gsd/uok/parity-report.ts +84 -0
  511. package/src/resources/extensions/gsd/uok/plan-v2.ts +13 -5
  512. package/src/resources/extensions/gsd/uok/writer.ts +113 -0
  513. package/src/resources/extensions/gsd/workflow-mcp.ts +6 -0
  514. package/src/resources/extensions/gsd/worktree-manager.ts +108 -7
  515. package/src/resources/extensions/gsd/worktree-resolver.ts +96 -9
  516. package/src/resources/extensions/gsd/worktree-telemetry.ts +322 -0
  517. package/src/resources/extensions/mcp-client/index.ts +3 -1
  518. package/src/resources/extensions/mcp-client/tests/server-name-spaces.test.ts +70 -36
  519. package/src/resources/extensions/ollama/index.ts +5 -1
  520. package/src/resources/extensions/ollama/ollama-auth-mode.test.ts +123 -15
  521. package/src/resources/extensions/ollama/ollama-status-indicator.test.ts +206 -19
  522. package/src/resources/extensions/remote-questions/manager.ts +36 -4
  523. package/src/resources/extensions/remote-questions/tests/command-polling.test.ts +200 -190
  524. package/src/resources/extensions/shared/tests/interview-preview.test.ts +11 -3
  525. package/src/resources/extensions/voice/tests/linux-ready.test.ts +129 -113
  526. package/packages/pi-ai/dist/utils/oauth/oauth-providers.test.d.ts +0 -2
  527. package/packages/pi-ai/dist/utils/oauth/oauth-providers.test.d.ts.map +0 -1
  528. package/packages/pi-ai/dist/utils/oauth/oauth-providers.test.js +0 -289
  529. package/packages/pi-ai/dist/utils/oauth/oauth-providers.test.js.map +0 -1
  530. package/packages/pi-ai/src/utils/oauth/oauth-providers.test.ts +0 -363
  531. package/src/resources/extensions/gsd/tests/auto-start-model-capture.test.ts +0 -143
  532. package/src/resources/extensions/gsd/tests/complete-milestone-false-merge.test.ts +0 -157
  533. package/src/resources/extensions/gsd/tests/dashboard-model-label-ordering.test.ts +0 -107
  534. package/src/resources/extensions/gsd/tests/find-missing-summaries-closed.test.ts +0 -48
  535. package/src/resources/extensions/gsd/tests/forensics-context-persist.test.ts +0 -159
  536. package/src/resources/extensions/gsd/tests/forensics-db-completion.test.ts +0 -96
  537. package/src/resources/extensions/gsd/tests/forensics-dedup.test.ts +0 -79
  538. package/src/resources/extensions/gsd/tests/forensics-hook-key-parse.test.ts +0 -74
  539. package/src/resources/extensions/gsd/tests/forensics-journal.test.ts +0 -162
  540. package/src/resources/extensions/gsd/tests/gitignore-bg-shell.test.ts +0 -38
  541. package/src/resources/extensions/gsd/tests/gsd-no-project-error.test.ts +0 -73
  542. package/src/resources/extensions/gsd/tests/idle-watchdog-stall-override.test.ts +0 -125
  543. package/src/resources/extensions/gsd/tests/import-done-milestones.test.ts +0 -42
  544. /package/dist/web/standalone/.next/static/{5wbu35_C2_MQ3Jj1lEVDx → cAJH99yNS1UPbeSEiNRrV}/_buildManifest.js +0 -0
  545. /package/dist/web/standalone/.next/static/{5wbu35_C2_MQ3Jj1lEVDx → cAJH99yNS1UPbeSEiNRrV}/_ssgManifest.js +0 -0
@@ -653,15 +653,72 @@ export function containsTypeScriptSyntax(source: string): boolean {
653
653
  * are compiled once and reused across all extensions.
654
654
  */
655
655
  let _extensionLoaderJiti: ReturnType<typeof createJiti> | null = null;
656
+ // Tracks every extension-module path that jiti has compiled through the shared
657
+ // singleton so resetExtensionLoaderCache() can also evict Node's global
658
+ // require.cache entries for those modules. jiti stores compiled modules under
659
+ // `nativeRequire.cache[filename]` when `moduleCache: true`, so a new singleton
660
+ // still returns the stale cached module on re-import without this eviction.
661
+ const _loadedExtensionPaths = new Set<string>();
662
+ const _extensionRequire = createRequire(import.meta.url);
656
663
 
657
664
  /**
658
665
  * Reset the shared jiti singleton so the next call to getExtensionLoaderJiti()
659
666
  * creates a fresh instance. This prevents memory leaks in long-running daemon
660
667
  * processes (every loaded module stays cached forever) and ensures stale modules
661
668
  * are not returned when extension source changes on disk.
669
+ *
670
+ * #3616: resetting the singleton alone is insufficient — jiti stores compiled
671
+ * modules in Node's global require.cache when `moduleCache: true`, which is
672
+ * shared across singletons. We also evict cached entries for every extension
673
+ * path we've previously loaded so the next import recompiles from disk.
662
674
  */
663
675
  export function resetExtensionLoaderCache(): void {
664
676
  _extensionLoaderJiti = null;
677
+ // Build a set of exact cache keys we expect (raw path, resolved path,
678
+ // realpath) AND a set of (basename, containing-directory) pairs so we
679
+ // can also catch entries that jiti/Node wrote under a canonicalized
680
+ // form (Windows drive-letter case, separator swap, UNC prefix, symlink
681
+ // resolution). require.cache is shared across all createRequire
682
+ // instances for CJS, so iterating any instance's cache covers jiti's
683
+ // internal `nativeRequire.cache` writes.
684
+ const exact = new Set<string>();
685
+ const signatures = new Set<string>();
686
+ const makeSignature = (p: string): string => {
687
+ const normalized = p.replace(/\\/g, "/").toLowerCase();
688
+ const slash = normalized.lastIndexOf("/");
689
+ const base = slash >= 0 ? normalized.slice(slash + 1) : normalized;
690
+ // Use the trailing two path segments as the signature — unique
691
+ // enough to avoid collisions in typical filesystems while tolerating
692
+ // drive-letter / separator variations that differ in the prefix.
693
+ const parent = slash >= 0 ? normalized.slice(0, slash) : "";
694
+ const parentSlash = parent.lastIndexOf("/");
695
+ const parentSeg = parentSlash >= 0 ? parent.slice(parentSlash + 1) : parent;
696
+ return `${parentSeg}/${base}`;
697
+ };
698
+ for (const raw of _loadedExtensionPaths) {
699
+ exact.add(raw);
700
+ try {
701
+ exact.add(_extensionRequire.resolve(raw));
702
+ } catch {
703
+ // unresolvable — fall through; signature scan may still hit it
704
+ }
705
+ try {
706
+ exact.add(fs.realpathSync(raw));
707
+ } catch {
708
+ // file may have been deleted already; ignore
709
+ }
710
+ signatures.add(makeSignature(raw));
711
+ }
712
+ for (const key of Object.keys(_extensionRequire.cache)) {
713
+ if (exact.has(key) || signatures.has(makeSignature(key))) {
714
+ try {
715
+ delete _extensionRequire.cache[key];
716
+ } catch {
717
+ // require.cache is best-effort; ignore failures (e.g. frozen cache).
718
+ }
719
+ }
720
+ }
721
+ _loadedExtensionPaths.clear();
665
722
  }
666
723
 
667
724
  function getExtensionLoaderJiti() {
@@ -696,6 +753,7 @@ async function loadExtensionModule(extensionPath: string) {
696
753
  const jiti = getExtensionLoaderJiti();
697
754
 
698
755
  const module = await jiti.import(extensionPath, { default: true });
756
+ _loadedExtensionPaths.add(extensionPath);
699
757
  const factory = module as ExtensionFactory;
700
758
  return typeof factory !== "function" ? undefined : factory;
701
759
  }
@@ -315,8 +315,19 @@ test("LSP integration: typescript-language-server", async (t) => {
315
315
  textDocument: { uri: mathUri, languageId: "typescript", version: 1, text: mathContent },
316
316
  });
317
317
 
318
- // Give the server time to index
319
- await new Promise((r) => setTimeout(r, 3000));
318
+ // Poll for a published diagnostics notification on main.ts, which
319
+ // is the observable signal that TypeScript has finished indexing
320
+ // the opened file. Previous magic-sleep (3000ms) was too short on
321
+ // slow CI machines and wasteful on fast ones (#4798).
322
+ const INDEX_DEADLINE_MS = 15_000;
323
+ const indexDeadline = Date.now() + INDEX_DEADLINE_MS;
324
+ while (Date.now() < indexDeadline) {
325
+ const diags = lsp
326
+ .getNotifications("textDocument/publishDiagnostics")
327
+ .filter((n) => (n.params as { uri: string }).uri === mainUri);
328
+ if (diags.length > 0) break;
329
+ await new Promise((r) => setTimeout(r, 50));
330
+ }
320
331
 
321
332
  // ---- Hover ----
322
333
  await t.test("hover on 'add' call", async () => {
@@ -381,8 +392,28 @@ test("LSP integration: typescript-language-server", async (t) => {
381
392
 
382
393
  // ---- Diagnostics (published via notification) ----
383
394
  await t.test("diagnostics for type error", async () => {
384
- // Wait a bit more for diagnostics to arrive
385
- await new Promise((r) => setTimeout(r, 2000));
395
+ // Poll for the specific type-error diagnostic on main.ts
396
+ // instead of sleeping a fixed 2s. tsserver pushes diagnostics
397
+ // incrementally — we need to wait until at least one diag
398
+ // contains a type-error signal, not just any diag.
399
+ const DIAG_DEADLINE_MS = 10_000;
400
+ const diagDeadline = Date.now() + DIAG_DEADLINE_MS;
401
+ while (Date.now() < diagDeadline) {
402
+ const candidates = lsp
403
+ .getNotifications("textDocument/publishDiagnostics")
404
+ .filter((n) => (n.params as { uri: string }).uri === mainUri)
405
+ .flatMap(
406
+ (n) => (n.params as { diagnostics: Array<{ message: string }> }).diagnostics,
407
+ );
408
+ if (
409
+ candidates.some(
410
+ (d) => d.message.includes("not assignable") || d.message.includes("Type"),
411
+ )
412
+ ) {
413
+ break;
414
+ }
415
+ await new Promise((r) => setTimeout(r, 50));
416
+ }
386
417
 
387
418
  const diagNotifications = lsp.getNotifications("textDocument/publishDiagnostics");
388
419
  const mainDiags = diagNotifications.filter(
@@ -39,6 +39,10 @@ function findModel(registry: ModelRegistry, provider: string, id: string): Model
39
39
  return registry.getAvailable().find((m) => m.provider === provider && m.id === id);
40
40
  }
41
41
 
42
+ function availableModelIds(registry: ModelRegistry): Set<string> {
43
+ return new Set(registry.getAvailable().map((model) => `${model.provider}/${model.id}`));
44
+ }
45
+
42
46
  function makeModel(provider: string, id: string, api: string): Model<Api> {
43
47
  return {
44
48
  id,
@@ -93,6 +97,22 @@ function createStreamSpy(): {
93
97
  // ─── Registration ─────────────────────────────────────────────────────────────
94
98
 
95
99
  describe("ModelRegistry authMode — registration", () => {
100
+ it("includes GPT-5.5 in the authenticated all-models menu backing list", () => {
101
+ const registry = createInMemoryRegistry({
102
+ openai: { type: "api_key", key: "sk-test" },
103
+ "openai-codex": {
104
+ type: "oauth",
105
+ access: "codex-access",
106
+ refresh: "codex-refresh",
107
+ expires: Date.now() + 60_000,
108
+ },
109
+ });
110
+
111
+ const ids = availableModelIds(registry);
112
+ assert.ok(ids.has("openai/gpt-5.5"), "all-models menu backing list should include openai/gpt-5.5");
113
+ assert.ok(ids.has("openai-codex/gpt-5.5"), "all-models menu backing list should include openai-codex/gpt-5.5");
114
+ });
115
+
96
116
  it("registers externalCli provider with streamSimple and without apiKey/oauth", () => {
97
117
  const registry = createRegistry();
98
118
  const spy = createStreamSpy();
@@ -1,42 +1,107 @@
1
- // GSD-2 — Regression test for #3616: reload() must reset jiti extension loader cache
2
- // Copyright (c) 2026 Jeremy McSpadden <jeremy@fluxlabs.net>
1
+ // Regression test for #3616: DefaultResourceLoader.reload() must invalidate
2
+ // the jiti module cache before loading extensions, so that edits to
3
+ // extension source on disk are picked up on the next reload (not served
4
+ // stale from memory).
5
+ //
6
+ // Verified end-to-end behaviourally: we write a .ts extension that
7
+ // registers a tool whose NAME is a module-scope constant, load it,
8
+ // rewrite the source with a new constant value, reload(), and assert
9
+ // the observable tool name reflects the NEW source. Without jiti cache
10
+ // invalidation, the second reload would re-register the stale name.
3
11
 
4
- import test, { describe } from "node:test";
5
12
  import assert from "node:assert/strict";
6
- import { readFileSync } from "node:fs";
13
+ import { mkdtempSync, rmSync, utimesSync, writeFileSync } from "node:fs";
14
+ import { tmpdir } from "node:os";
7
15
  import { join } from "node:path";
16
+ import { afterEach, beforeEach, describe, it } from "node:test";
8
17
 
9
- const source = readFileSync(
10
- join(process.cwd(), "packages/pi-coding-agent/src/core/resource-loader.ts"),
11
- "utf-8",
12
- );
18
+ import { DefaultResourceLoader } from "./resource-loader.js";
19
+ import { SettingsManager } from "./settings-manager.js";
20
+ import { resetExtensionLoaderCache } from "./extensions/loader.js";
13
21
 
14
- describe("#3616 reload() must invalidate jiti module cache", () => {
15
- test("resource-loader imports resetExtensionLoaderCache from loader.js", () => {
16
- assert.ok(
17
- source.includes("resetExtensionLoaderCache"),
18
- "resource-loader.ts should import resetExtensionLoaderCache",
19
- );
20
- assert.ok(
21
- source.includes('from "./extensions/loader.js"'),
22
- "resetExtensionLoaderCache should be imported from extensions/loader.js",
23
- );
22
+ let testDir: string;
23
+
24
+ function writeExtensionWithToolName(extPath: string, toolName: string): void {
25
+ // Extension factory signature expected by the loader. Uses `any` so the
26
+ // test stays decoupled from the ExtensionAPI type shape.
27
+ writeFileSync(
28
+ extPath,
29
+ [
30
+ `const TOOL_NAME = "${toolName}";`,
31
+ `export default function activate(api: any) {`,
32
+ ` api.registerTool({`,
33
+ ` name: TOOL_NAME,`,
34
+ ` label: TOOL_NAME,`,
35
+ ` description: "test tool — source-generated name",`,
36
+ ` parameters: { type: "object", properties: {}, additionalProperties: false },`,
37
+ ` execute: async () => ({ content: [], details: undefined }),`,
38
+ ` });`,
39
+ `}`,
40
+ "",
41
+ ].join("\n"),
42
+ );
43
+ }
44
+
45
+ describe("#3616 — DefaultResourceLoader.reload() invalidates extension module cache", () => {
46
+ beforeEach(() => {
47
+ testDir = mkdtempSync(join(tmpdir(), "resource-loader-cache-reset-"));
48
+ // Ensure a clean jiti singleton — prior tests in this process may
49
+ // have populated it with unrelated entries.
50
+ resetExtensionLoaderCache();
51
+ });
52
+
53
+ afterEach(() => {
54
+ resetExtensionLoaderCache();
55
+ rmSync(testDir, { recursive: true, force: true });
24
56
  });
25
57
 
26
- test("reload() calls resetExtensionLoaderCache before loadExtensions", () => {
27
- const reloadStart = source.indexOf("async reload(): Promise<void>");
28
- assert.ok(reloadStart >= 0, "should find reload() method");
29
- const reloadBody = source.slice(reloadStart, reloadStart + 4000);
58
+ it("reload() picks up source edits after the extension has been loaded once", async () => {
59
+ const agentDir = join(testDir, "agent-home");
60
+ const extPath = join(testDir, "reload-probe.ts");
30
61
 
31
- const resetIdx = reloadBody.indexOf("resetExtensionLoaderCache()");
32
- assert.ok(resetIdx >= 0, "reload() should call resetExtensionLoaderCache()");
62
+ // v1 initial content
63
+ writeExtensionWithToolName(extPath, "probe_v1");
33
64
 
34
- const loadIdx = reloadBody.indexOf("loadExtensions(");
35
- assert.ok(loadIdx >= 0, "reload() should call loadExtensions");
65
+ const loader = new DefaultResourceLoader({
66
+ cwd: testDir,
67
+ agentDir,
68
+ settingsManager: SettingsManager.inMemory(),
69
+ noExtensions: true,
70
+ noPromptTemplates: true,
71
+ noThemes: true,
72
+ additionalExtensionPaths: [extPath],
73
+ });
36
74
 
75
+ await loader.reload();
76
+
77
+ const toolsV1 = [...loader.getExtensions().extensions.flatMap((e) => [...e.tools.keys()])];
78
+ assert.ok(
79
+ toolsV1.includes("probe_v1"),
80
+ `first reload should register probe_v1; got=${JSON.stringify(toolsV1)}`,
81
+ );
82
+
83
+ // v2 — overwrite the source on disk with a different tool name.
84
+ writeExtensionWithToolName(extPath, "probe_v2");
85
+ // Bump mtime explicitly so file-stat–based cache strategies (jiti's
86
+ // moduleCache consults Node's require.cache, which some runtimes
87
+ // tiebreak on mtime) always see "newer than last seen". On Windows
88
+ // NTFS + node the default fs mtime resolution can silently collapse
89
+ // two writes in the same tick to an identical mtime — that fooled
90
+ // the Windows CI run on #3616.
91
+ const futureTime = new Date(Date.now() + 5000);
92
+ utimesSync(extPath, futureTime, futureTime);
93
+
94
+ await loader.reload();
95
+
96
+ const toolsV2 = [...loader.getExtensions().extensions.flatMap((e) => [...e.tools.keys()])];
97
+ assert.ok(
98
+ toolsV2.includes("probe_v2"),
99
+ `second reload must observe the edited source (probe_v2) — if reload() ` +
100
+ `fails to reset the jiti cache, the stale module returns probe_v1. got=${JSON.stringify(toolsV2)}`,
101
+ );
37
102
  assert.ok(
38
- resetIdx < loadIdx,
39
- "resetExtensionLoaderCache() must be called BEFORE loadExtensions to ensure fresh modules",
103
+ !toolsV2.includes("probe_v1"),
104
+ `second reload must NOT still expose the stale probe_v1 name; got=${JSON.stringify(toolsV2)}`,
40
105
  );
41
106
  });
42
107
  });
@@ -281,7 +281,11 @@ describe("RetryHandler — long-context entitlement 429 (#2803)", () => {
281
281
  assert.equal(result, true, "retry should be initiated");
282
282
 
283
283
  handler.abortRetry();
284
- await new Promise((resolve) => setTimeout(resolve, 10));
284
+ // Yield the microtask queue so any synchronous continuation
285
+ // scheduled by abortRetry() settles before we assert. This is
286
+ // deterministic — no magic-sleep dependency (#4798 / #4784).
287
+ await Promise.resolve();
288
+ await Promise.resolve();
285
289
 
286
290
  assert.equal(continueFn.mock.calls.length, 0, "cancelled retry must not continue after explicit abort");
287
291
  const endEvents = emittedEvents.filter((e) => e.type === "auto_retry_end");
@@ -18,6 +18,7 @@ import type { ModelRegistry } from "./model-registry.js";
18
18
  import type { SettingsManager } from "./settings-manager.js";
19
19
  import { sleep } from "../utils/sleep.js";
20
20
  import type { AgentSessionEvent } from "./agent-session.js";
21
+ import { RETRYABLE_ERROR_RE } from "./retryable-error-regex.js";
21
22
 
22
23
  /** Dependencies injected from AgentSession into RetryHandler */
23
24
  export interface RetryHandlerDeps {
@@ -111,14 +112,7 @@ export class RetryHandler {
111
112
  const contextWindow = this._deps.getModel()?.contextWindow ?? 0;
112
113
  if (isContextOverflow(message, contextWindow)) return false;
113
114
 
114
- const err = message.errorMessage;
115
- // "temporarily backed off" is intentionally excluded: it is an internally-
116
- // generated error from getApiKey() when credentials are in a backoff window.
117
- // Re-entering the retry handler for that message creates a cascade of empty
118
- // error entries in the session file, breaking resume (#3429).
119
- return /overloaded|rate.?limit|too many requests|402|429|500|502|503|504|service.?unavailable|server.?error|internal.?error|connection.?error|connection.?refused|other side closed|fetch failed|upstream.?connect|reset before headers|terminated|retry delay|network.?(?:is\s+)?unavailable|credentials.*expired|requires more credits|can only afford|insufficient credits|not enough credits|extra usage is required|(?:out of|no) extra usage|third.party.*draw from extra|third.party.*not.*available/i.test(
120
- err,
121
- );
115
+ return RETRYABLE_ERROR_RE.test(message.errorMessage);
122
116
  }
123
117
 
124
118
  /**
@@ -0,0 +1,18 @@
1
+ /**
2
+ * Regex matching retryable provider errors — overloaded, rate limits, transient
3
+ * server/connection failures, credential-backoff, quota/credit issues.
4
+ *
5
+ * Kept in its own zero-import module so tests can consume the live pattern
6
+ * without pulling in the full RetryHandler dependency graph (Agent /
7
+ * FallbackResolver / ModelRegistry / @gsd/pi-ai …). The test in
8
+ * `src/resources/extensions/gsd/tests/provider-errors.test.ts` previously
9
+ * redefined this regex inline, which meant runtime and test could drift
10
+ * silently on every edit (see #4837).
11
+ *
12
+ * "temporarily backed off" is intentionally excluded: it is an internally-
13
+ * generated error from getApiKey() when credentials are in a backoff window.
14
+ * Re-entering the retry handler for that message creates a cascade of empty
15
+ * error entries in the session file, breaking resume (#3429).
16
+ */
17
+ export const RETRYABLE_ERROR_RE =
18
+ /overloaded|rate.?limit|too many requests|402|429|500|502|503|504|service.?unavailable|server.?error|internal.?error|connection.?error|connection.?refused|other side closed|fetch failed|upstream.?connect|reset before headers|terminated|retry delay|network.?(?:is\s+)?unavailable|credentials.*expired|requires more credits|can only afford|insufficient credits|not enough credits|extra usage is required|(?:out of|no) extra usage|third.party.*draw from extra|third.party.*not.*available/i;
@@ -35,6 +35,26 @@ export interface BuildSystemPromptOptions {
35
35
  contextFiles?: Array<{ path: string; content: string }>;
36
36
  /** Pre-loaded skills. */
37
37
  skills?: Skill[];
38
+ /**
39
+ * Optional predicate applied to the `skills` list before rendering the
40
+ * <available_skills> catalog. Returning `false` omits a skill from the
41
+ * prompt (the skill remains loaded and invocable by name — only the
42
+ * catalog listing is suppressed).
43
+ *
44
+ * Intended for consumers that can narrow the relevant skill surface
45
+ * (e.g. per-unit-type manifests) to reduce cached system-prompt bloat.
46
+ * When omitted, all non-`disableModelInvocation` skills render — i.e.
47
+ * behavior is unchanged from before this option existed.
48
+ *
49
+ * Contract: the predicate must be **pure and synchronous**. It may be
50
+ * invoked on every system-prompt rebuild (tool-set changes and
51
+ * runtime resource-loader extensions both trigger one), so any state
52
+ * the closure captures should be stable across the rebuild window.
53
+ * If the predicate throws, `buildSystemPrompt` logs a warning and
54
+ * falls back to the unfiltered skill list — callers never see the
55
+ * exception and the session stays consistent.
56
+ */
57
+ skillFilter?: (skill: Skill) => boolean;
38
58
  }
39
59
 
40
60
  /** Build the system prompt with tools, guidelines, and context */
@@ -48,6 +68,7 @@ export function buildSystemPrompt(options: BuildSystemPromptOptions = {}): strin
48
68
  cwd,
49
69
  contextFiles: providedContextFiles,
50
70
  skills: providedSkills,
71
+ skillFilter,
51
72
  } = options;
52
73
  const resolvedCwd = toPosixPath(cwd ?? process.cwd());
53
74
 
@@ -66,7 +87,20 @@ export function buildSystemPrompt(options: BuildSystemPromptOptions = {}): strin
66
87
  const appendSection = appendSystemPrompt ? `\n\n${appendSystemPrompt}` : "";
67
88
 
68
89
  const contextFiles = providedContextFiles ?? [];
69
- const skills = providedSkills ?? [];
90
+ const skillsBase = providedSkills ?? [];
91
+ let skills = skillsBase;
92
+ if (skillFilter) {
93
+ try {
94
+ skills = skillsBase.filter(skillFilter);
95
+ } catch (error) {
96
+ // A consumer's predicate threw. Fall back to the unfiltered list so
97
+ // the session stays consistent — callers (e.g. AgentSession.setTools)
98
+ // must not be left with updated tools but a stale system prompt.
99
+ const message = error instanceof Error ? error.message : String(error);
100
+ console.warn(`buildSystemPrompt: skillFilter threw; falling back to unfiltered skills. Error: ${message}`);
101
+ skills = skillsBase;
102
+ }
103
+ }
70
104
 
71
105
  if (customPrompt) {
72
106
  let prompt = customPrompt;
@@ -188,6 +188,7 @@ export type { PackageCommand, PackageCommandOptions, PackageCommandRunnerOptions
188
188
  export { getPackageCommandUsage, parsePackageCommand, runPackageCommand } from "./core/package-commands.js";
189
189
  export type { ResourceCollision, ResourceDiagnostic, ResourceLoader } from "./core/resource-loader.js";
190
190
  export { DefaultResourceLoader } from "./core/resource-loader.js";
191
+ export { RETRYABLE_ERROR_RE } from "./core/retryable-error-regex.js";
191
192
  // SDK for programmatic usage
192
193
  export {
193
194
  type CreateAgentSessionOptions,
@@ -14,12 +14,13 @@ function renderTool(
14
14
  isError: boolean;
15
15
  details?: Record<string, unknown>;
16
16
  },
17
+ toolDefinition?: { label?: string },
17
18
  ): string {
18
19
  const component = new ToolExecutionComponent(
19
20
  toolName,
20
21
  args,
21
22
  {},
22
- undefined,
23
+ toolDefinition as any,
23
24
  { requestRender() {} } as any,
24
25
  );
25
26
  component.setExpanded(true);
@@ -35,12 +36,13 @@ function renderToolCollapsed(
35
36
  isError: boolean;
36
37
  details?: Record<string, unknown>;
37
38
  },
39
+ toolDefinition?: { label?: string },
38
40
  ): string {
39
41
  const component = new ToolExecutionComponent(
40
42
  toolName,
41
43
  args,
42
44
  {},
43
- undefined,
45
+ toolDefinition as any,
44
46
  { requestRender() {} } as any,
45
47
  );
46
48
  if (result) component.updateResult(result);
@@ -110,13 +112,57 @@ describe("ToolExecutionComponent", () => {
110
112
  { count: 3, enabled: true, label: "hello" },
111
113
  );
112
114
 
113
- assert.match(rendered, /some_unknown_tool/);
115
+ assert.match(rendered, /Some Unknown Tool/);
114
116
  assert.match(rendered, /count=3/);
115
117
  assert.match(rendered, /enabled=true/);
116
118
  assert.match(rendered, /label="hello"/);
117
119
  assert.doesNotMatch(rendered, /^\{$/m);
118
120
  });
119
121
 
122
+ test("frame header prefers toolDefinition.label over raw tool name", () => {
123
+ const rendered = renderToolCollapsed(
124
+ "gsd_slice_complete",
125
+ { sliceId: "S03" },
126
+ undefined,
127
+ { label: "Complete Slice" },
128
+ );
129
+
130
+ assert.match(rendered, /Tool Complete Slice/);
131
+ assert.doesNotMatch(rendered, /gsd_slice_complete/);
132
+ });
133
+
134
+ test("frame header strips gsd_ prefix and title-cases when no label is registered", () => {
135
+ const rendered = renderToolCollapsed("gsd_requirement_update", { id: "R005" });
136
+
137
+ assert.match(rendered, /Tool Requirement Update/);
138
+ assert.doesNotMatch(rendered, /gsd_requirement_update/);
139
+ });
140
+
141
+ test("formatCompactArgs truncates long string values inline instead of dumping JSON", () => {
142
+ const longPath = "/Users/alice/.gsd/projects/4dce7b775013/worktrees/slice-S03-some-long-path-that-exceeds-limit";
143
+ const rendered = renderToolCollapsed("gsd_slice_complete", {
144
+ sliceId: "S03",
145
+ milestoneId: "M001",
146
+ worktree: longPath,
147
+ });
148
+
149
+ assert.match(rendered, /sliceId="S03"/);
150
+ assert.match(rendered, /milestoneId="M001"/);
151
+ assert.match(rendered, /worktree=".*…"/);
152
+ assert.doesNotMatch(rendered, /"sliceId":\s*"S03"/);
153
+ });
154
+
155
+ test("formatCompactArgs shows full string values when expanded", () => {
156
+ const longPath = "/Users/alice/.gsd/projects/4dce7b775013/worktrees/slice-S03-some-long-path-that-exceeds-limit";
157
+ const rendered = renderTool("gsd_slice_complete", {
158
+ sliceId: "S03",
159
+ worktree: longPath,
160
+ });
161
+
162
+ assert.match(rendered, new RegExp(longPath.replace(/\//g, "\\/")));
163
+ assert.doesNotMatch(rendered, /…/);
164
+ });
165
+
120
166
  test("generic fallback truncates long output when collapsed", () => {
121
167
  const longOutput = Array.from({ length: 25 }, (_, i) => `line ${i + 1}`).join("\n");
122
168
  const rendered = renderToolCollapsed(
@@ -37,26 +37,32 @@ describe("DynamicBorder spinner", () => {
37
37
  border.stopSpinner();
38
38
  });
39
39
 
40
- it("triggers standalone render when no external render occurred recently", async () => {
41
- const border = new DynamicBorder((s) => s);
42
- const tui = makeTUI();
43
-
44
- // Set lastExternalRender to a time well in the past
45
- const anyBorder = border as any;
46
- anyBorder.lastExternalRender = 0;
47
-
48
- border.startSpinner(tui as any, (s) => s);
49
- const initialCount = tui.renderCount;
50
-
51
- // Wait for one spinner tick (200ms interval + buffer)
52
- await new Promise((r) => setTimeout(r, 250));
53
-
54
- assert.ok(
55
- tui.renderCount > initialCount,
56
- "spinner should trigger requestRender when no recent external render",
57
- );
58
-
59
- border.stopSpinner();
40
+ it("triggers standalone render when no external render occurred recently", () => {
41
+ mock.timers.enable({ apis: ["setInterval"], now: 0 });
42
+ try {
43
+ const border = new DynamicBorder((s) => s);
44
+ const tui = makeTUI();
45
+
46
+ // Set lastExternalRender to a time well in the past
47
+ const anyBorder = border as any;
48
+ anyBorder.lastExternalRender = 0;
49
+
50
+ border.startSpinner(tui as any, (s) => s);
51
+ const initialCount = tui.renderCount;
52
+
53
+ // Advance exactly one spinner interval (200ms). With mocked timers
54
+ // this is deterministic — no flake under CI load.
55
+ mock.timers.tick(200);
56
+
57
+ assert.ok(
58
+ tui.renderCount > initialCount,
59
+ "spinner should trigger requestRender after one 200ms interval when no recent external render",
60
+ );
61
+
62
+ border.stopSpinner();
63
+ } finally {
64
+ mock.timers.reset();
65
+ }
60
66
  });
61
67
 
62
68
  it("updates lastExternalRender on each render() call", () => {