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
@@ -1,55 +1,89 @@
1
1
  /**
2
2
  * Regression test for #3029 — mcp_discover fails for server names with spaces.
3
3
  *
4
- * The getServerConfig lookup must handle:
5
- * 1. Exact match (already works)
4
+ * getServerConfig must handle:
5
+ * 1. Exact match
6
6
  * 2. Names with leading/trailing whitespace (trimming)
7
7
  * 3. Case-insensitive matching (e.g. "Langgraph code" vs "langgraph Code")
8
8
  *
9
- * We test at the source level since getServerConfig is not exported.
9
+ * getOrConnect must use the canonical (config.name) as the cache key so that
10
+ * subsequent lookups with variant casing/whitespace hit the same connection.
11
+ *
12
+ * These are behaviour tests against the real exported getServerConfig — no
13
+ * source grep.
10
14
  */
11
15
 
12
- import test from "node:test";
16
+ import test, { before, after } from "node:test";
13
17
  import assert from "node:assert/strict";
14
- import { readFileSync } from "node:fs";
15
- import { dirname, join } from "node:path";
16
- import { fileURLToPath } from "node:url";
18
+ import { writeFileSync, unlinkSync, existsSync, mkdirSync, rmSync } from "node:fs";
19
+ import { join } from "node:path";
20
+ import { mkdtempSync } from "node:fs";
21
+ import { tmpdir } from "node:os";
22
+
23
+ import { getServerConfig } from "../index.js";
24
+
25
+ // readConfigs() anchors to process.cwd() — run each test in a sandbox dir
26
+ // with a purpose-built .mcp.json so the extension reads our fixture, not
27
+ // whatever .mcp.json happens to live in the current working directory.
28
+ let sandboxDir: string;
29
+ let originalCwd: string;
30
+
31
+ before(() => {
32
+ originalCwd = process.cwd();
33
+ sandboxDir = mkdtempSync(join(tmpdir(), "mcp-name-spaces-"));
34
+ const mcpConfig = {
35
+ mcpServers: {
36
+ "Langgraph Code": {
37
+ command: "echo",
38
+ args: ["test"],
39
+ },
40
+ "other-server": {
41
+ url: "https://example.com",
42
+ },
43
+ },
44
+ };
45
+ writeFileSync(join(sandboxDir, ".mcp.json"), JSON.stringify(mcpConfig), "utf-8");
46
+ process.chdir(sandboxDir);
47
+ });
17
48
 
18
- const __filename = fileURLToPath(import.meta.url);
19
- const __dirname = dirname(__filename);
49
+ after(() => {
50
+ process.chdir(originalCwd);
51
+ try {
52
+ rmSync(sandboxDir, { recursive: true, force: true });
53
+ } catch {
54
+ // Best-effort cleanup
55
+ }
56
+ });
20
57
 
21
- const source = readFileSync(join(__dirname, "..", "index.ts"), "utf-8");
58
+ test("#3029: getServerConfig finds exact match", () => {
59
+ const cfg = getServerConfig("Langgraph Code");
60
+ assert.ok(cfg, "exact name must resolve");
61
+ assert.equal(cfg?.name, "Langgraph Code");
62
+ });
22
63
 
23
64
  test("#3029: getServerConfig trims whitespace from input name", () => {
24
- assert.ok(
25
- source.includes(".trim()"),
26
- "getServerConfig should trim the input name before comparison",
27
- );
65
+ const cfg = getServerConfig(" Langgraph Code ");
66
+ assert.ok(cfg, "whitespace-padded name must resolve to the same server");
67
+ assert.equal(cfg?.name, "Langgraph Code");
28
68
  });
29
69
 
30
70
  test("#3029: getServerConfig performs case-insensitive matching", () => {
31
- assert.ok(
32
- source.includes(".toLowerCase()"),
33
- "getServerConfig should compare names case-insensitively",
34
- );
71
+ const cfg = getServerConfig("langgraph code");
72
+ assert.ok(cfg, "lower-cased name must resolve");
73
+ assert.equal(cfg?.name, "Langgraph Code");
74
+
75
+ const mixed = getServerConfig("LANGGRAPH CODE");
76
+ assert.ok(mixed, "upper-cased name must resolve");
77
+ assert.equal(mixed?.name, "Langgraph Code");
78
+ });
79
+
80
+ test("#3029: getServerConfig combines trim + case-insensitive", () => {
81
+ const cfg = getServerConfig(" LANGGRAPH code ");
82
+ assert.ok(cfg, "padded + mixed-case must resolve");
83
+ assert.equal(cfg?.name, "Langgraph Code");
35
84
  });
36
85
 
37
- test("#3029: getOrConnect normalizes name for connection cache lookup", () => {
38
- // The connections Map key must use the canonical (config) name, not the
39
- // raw user input, so that subsequent lookups hit the cache even when the
40
- // user's casing differs.
41
- const getOrConnectMatch = source.match(
42
- /async function getOrConnect\(name: string[\s\S]*?const existing = connections\.get\(/,
43
- );
44
- assert.ok(
45
- getOrConnectMatch,
46
- "getOrConnect function should exist",
47
- );
48
- // After the fix, getOrConnect should normalize the name via getServerConfig
49
- // or use config.name as the canonical cache key.
50
- assert.ok(
51
- source.includes("connections.get(config.name") ||
52
- source.includes("connections.set(config.name"),
53
- "getOrConnect should use config.name (canonical) as the connections cache key",
54
- );
86
+ test("#3029: getServerConfig returns undefined for unknown name", () => {
87
+ const cfg = getServerConfig("does-not-exist");
88
+ assert.equal(cfg, undefined);
55
89
  });
@@ -45,8 +45,12 @@ let providerRegistered = false;
45
45
  /**
46
46
  * Probe Ollama and register discovered models.
47
47
  * Safe to call multiple times — re-discovers and re-registers.
48
+ *
49
+ * Exported for tests (see ollama-auth-mode.test.ts, ollama-status-indicator.test.ts)
50
+ * so a fake HTTP endpoint can drive the registration/unregistration paths.
51
+ * Production callers always go through the session_start handler below.
48
52
  */
49
- async function probeAndRegister(pi: ExtensionAPI): Promise<boolean> {
53
+ export async function probeAndRegister(pi: ExtensionAPI): Promise<boolean> {
50
54
  const running = await client.isRunning();
51
55
  if (!running) {
52
56
  if (providerRegistered) {
@@ -1,20 +1,128 @@
1
1
  /**
2
2
  * Regression test for #3440: Ollama extension must register with
3
- * authMode "apiKey" (not "none") to avoid streamSimple requirement.
3
+ * authMode "apiKey" (not "none"), otherwise the core bails out because
4
+ * the provider has no streamSimple.
5
+ *
6
+ * Behaviour test: spin up a fake Ollama endpoint, point OLLAMA_HOST at
7
+ * it, and invoke probeAndRegister with a mock pi. Assert that
8
+ * registerProvider was called with authMode "apiKey".
4
9
  */
5
- import { test } from "node:test";
10
+ import { test, before, after, beforeEach } from "node:test";
6
11
  import assert from "node:assert/strict";
7
- import { readFileSync } from "node:fs";
8
- import { join, dirname } from "node:path";
9
- import { fileURLToPath } from "node:url";
10
-
11
- const __dirname = dirname(fileURLToPath(import.meta.url));
12
-
13
- test("Ollama registers with authMode apiKey, not none (#3440)", () => {
14
- const src = readFileSync(join(__dirname, "index.ts"), "utf-8");
15
- // Find the registerProvider call
16
- const registerBlock = src.slice(src.indexOf("pi.registerProvider(\"ollama\""));
17
- const authLine = registerBlock.match(/authMode:\s*"(\w+)"/);
18
- assert.ok(authLine, "registerProvider must specify authMode");
19
- assert.equal(authLine![1], "apiKey", "authMode must be apiKey, not none");
12
+ import { createServer, type Server } from "node:http";
13
+ import type { AddressInfo } from "node:net";
14
+
15
+ import { probeAndRegister } from "./index.js";
16
+
17
+ type RegisterCall = [string, Record<string, unknown>];
18
+
19
+ function makeMockPi() {
20
+ const calls: { registerProvider: RegisterCall[]; unregisterProvider: string[] } = {
21
+ registerProvider: [],
22
+ unregisterProvider: [],
23
+ };
24
+ const pi = {
25
+ registerProvider(id: string, spec: Record<string, unknown>) {
26
+ calls.registerProvider.push([id, spec]);
27
+ },
28
+ unregisterProvider(id: string) {
29
+ calls.unregisterProvider.push(id);
30
+ },
31
+ } as unknown as Parameters<typeof probeAndRegister>[0];
32
+ return { pi, calls };
33
+ }
34
+
35
+ let server: Server;
36
+ let savedHost: string | undefined;
37
+
38
+ before(async () => {
39
+ // Fake Ollama endpoint that:
40
+ // GET / → 200 (isRunning probe)
41
+ // GET /api/tags → one model
42
+ // POST /api/show → minimal capability info
43
+ server = createServer((req, res) => {
44
+ if (req.method === "GET" && req.url === "/") {
45
+ res.writeHead(200, { "Content-Type": "text/plain" });
46
+ res.end("Ollama is running");
47
+ return;
48
+ }
49
+ if (req.method === "GET" && req.url === "/api/tags") {
50
+ res.writeHead(200, { "Content-Type": "application/json" });
51
+ res.end(
52
+ JSON.stringify({
53
+ models: [
54
+ {
55
+ name: "llama3:latest",
56
+ modified_at: new Date().toISOString(),
57
+ size: 1_000_000,
58
+ digest: "abc",
59
+ details: {
60
+ parent_model: "",
61
+ format: "gguf",
62
+ family: "llama",
63
+ families: ["llama"],
64
+ parameter_size: "8B",
65
+ quantization_level: "Q4_0",
66
+ },
67
+ },
68
+ ],
69
+ }),
70
+ );
71
+ return;
72
+ }
73
+ if (req.method === "POST" && req.url === "/api/show") {
74
+ res.writeHead(200, { "Content-Type": "application/json" });
75
+ res.end(
76
+ JSON.stringify({
77
+ modelfile: "",
78
+ parameters: "",
79
+ template: "",
80
+ details: {
81
+ parent_model: "",
82
+ format: "gguf",
83
+ family: "llama",
84
+ families: ["llama"],
85
+ parameter_size: "8B",
86
+ quantization_level: "Q4_0",
87
+ },
88
+ model_info: { "llama.context_length": 8192 },
89
+ capabilities: [],
90
+ }),
91
+ );
92
+ return;
93
+ }
94
+ res.writeHead(404);
95
+ res.end();
96
+ });
97
+ await new Promise<void>((resolve) => server.listen(0, "127.0.0.1", resolve));
98
+ const { port } = server.address() as AddressInfo;
99
+ savedHost = process.env.OLLAMA_HOST;
100
+ process.env.OLLAMA_HOST = `http://127.0.0.1:${port}`;
101
+ });
102
+
103
+ after(async () => {
104
+ await new Promise<void>((resolve) => server.close(() => resolve()));
105
+ if (savedHost === undefined) delete process.env.OLLAMA_HOST;
106
+ else process.env.OLLAMA_HOST = savedHost;
107
+ });
108
+
109
+ beforeEach(() => {
110
+ // Each test starts from a clean providerRegistered state in the module.
111
+ // probeAndRegister is idempotent — calling it is safe regardless.
112
+ });
113
+
114
+ test("Ollama registers with authMode apiKey, not none (#3440)", async () => {
115
+ const { pi, calls } = makeMockPi();
116
+
117
+ const found = await probeAndRegister(pi);
118
+ assert.equal(found, true, "probeAndRegister should return true when models are discovered");
119
+
120
+ assert.equal(calls.registerProvider.length, 1, "registerProvider should be called exactly once");
121
+ const [providerId, spec] = calls.registerProvider[0];
122
+ assert.equal(providerId, "ollama");
123
+ assert.equal(
124
+ spec.authMode,
125
+ "apiKey",
126
+ "authMode must be apiKey so the core doesn't require streamSimple for every model",
127
+ );
20
128
  });
@@ -1,28 +1,215 @@
1
1
  /**
2
2
  * Regression test: don't show an Ollama footer status unless Ollama is
3
3
  * actually usable (running with at least one discovered model).
4
+ *
5
+ * Behaviour tests:
6
+ * 1. probeAndRegister returns false when /api/tags returns no models
7
+ * (running-without-models should not be treated as available).
8
+ * 2. The session_start handler calls ctx.ui.setStatus("ollama", "Ollama")
9
+ * when probeAndRegister reports true, and setStatus("ollama", undefined)
10
+ * when it reports false — keeping the footer clean on unavailable Ollama.
4
11
  */
5
- import { test } from "node:test";
12
+ import { test, before, after } from "node:test";
6
13
  import assert from "node:assert/strict";
7
- import { readFileSync } from "node:fs";
8
- import { join, dirname } from "node:path";
9
- import { fileURLToPath } from "node:url";
10
-
11
- const __dirname = dirname(fileURLToPath(import.meta.url));
12
- const src = readFileSync(join(__dirname, "index.ts"), "utf-8");
13
-
14
- test("probeAndRegister returns false when no Ollama models are discovered", () => {
15
- assert.match(
16
- src,
17
- /if \(models\.length === 0\)[\s\S]*return false;/,
18
- "running-without-models should not be treated as available",
19
- );
14
+ import { createServer, type Server } from "node:http";
15
+ import type { AddressInfo } from "node:net";
16
+
17
+ import ollamaExtension, { probeAndRegister } from "./index.js";
18
+
19
+ type RegisterCall = [string, Record<string, unknown>];
20
+
21
+ function makeMockPi() {
22
+ const calls: {
23
+ registerProvider: RegisterCall[];
24
+ unregisterProvider: string[];
25
+ registerTool: unknown[];
26
+ onHandlers: Map<string, Array<(...args: unknown[]) => unknown>>;
27
+ } = {
28
+ registerProvider: [],
29
+ unregisterProvider: [],
30
+ registerTool: [],
31
+ onHandlers: new Map(),
32
+ };
33
+ const pi = {
34
+ registerProvider(id: string, spec: Record<string, unknown>) {
35
+ calls.registerProvider.push([id, spec]);
36
+ },
37
+ unregisterProvider(id: string) {
38
+ calls.unregisterProvider.push(id);
39
+ },
40
+ registerTool(tool: unknown) {
41
+ calls.registerTool.push(tool);
42
+ },
43
+ registerCommand() {
44
+ /* no-op */
45
+ },
46
+ on(event: string, handler: (...args: unknown[]) => unknown) {
47
+ if (!calls.onHandlers.has(event)) calls.onHandlers.set(event, []);
48
+ calls.onHandlers.get(event)!.push(handler);
49
+ },
50
+ } as unknown as Parameters<typeof probeAndRegister>[0];
51
+ return { pi, calls };
52
+ }
53
+
54
+ // Server mode:
55
+ // "empty" → /api/tags returns { models: [] }
56
+ // "loaded" → /api/tags returns one model + /api/show with 8k context
57
+ let server: Server;
58
+ let serverMode: "empty" | "loaded" = "empty";
59
+ let savedHost: string | undefined;
60
+
61
+ before(async () => {
62
+ server = createServer((req, res) => {
63
+ if (req.method === "GET" && req.url === "/") {
64
+ res.writeHead(200);
65
+ res.end("Ollama is running");
66
+ return;
67
+ }
68
+ if (req.method === "GET" && req.url === "/api/tags") {
69
+ res.writeHead(200, { "Content-Type": "application/json" });
70
+ if (serverMode === "empty") {
71
+ res.end(JSON.stringify({ models: [] }));
72
+ } else {
73
+ res.end(
74
+ JSON.stringify({
75
+ models: [
76
+ {
77
+ name: "llama3:latest",
78
+ modified_at: new Date().toISOString(),
79
+ size: 1_000_000,
80
+ digest: "abc",
81
+ details: {
82
+ parent_model: "",
83
+ format: "gguf",
84
+ family: "llama",
85
+ families: ["llama"],
86
+ parameter_size: "8B",
87
+ quantization_level: "Q4_0",
88
+ },
89
+ },
90
+ ],
91
+ }),
92
+ );
93
+ }
94
+ return;
95
+ }
96
+ if (req.method === "POST" && req.url === "/api/show") {
97
+ res.writeHead(200, { "Content-Type": "application/json" });
98
+ res.end(
99
+ JSON.stringify({
100
+ modelfile: "",
101
+ parameters: "",
102
+ template: "",
103
+ details: {
104
+ parent_model: "",
105
+ format: "gguf",
106
+ family: "llama",
107
+ families: ["llama"],
108
+ parameter_size: "8B",
109
+ quantization_level: "Q4_0",
110
+ },
111
+ model_info: { "llama.context_length": 8192 },
112
+ capabilities: [],
113
+ }),
114
+ );
115
+ return;
116
+ }
117
+ res.writeHead(404);
118
+ res.end();
119
+ });
120
+ await new Promise<void>((resolve) => server.listen(0, "127.0.0.1", resolve));
121
+ const { port } = server.address() as AddressInfo;
122
+ savedHost = process.env.OLLAMA_HOST;
123
+ process.env.OLLAMA_HOST = `http://127.0.0.1:${port}`;
124
+ });
125
+
126
+ after(async () => {
127
+ await new Promise<void>((resolve) => server.close(() => resolve()));
128
+ if (savedHost === undefined) delete process.env.OLLAMA_HOST;
129
+ else process.env.OLLAMA_HOST = savedHost;
20
130
  });
21
131
 
22
- test("interactive session clears ollama footer status when unavailable", () => {
23
- assert.match(
24
- src,
25
- /ctx\.ui\.setStatus\("ollama", found \? "Ollama" : undefined\)/,
26
- "status should be cleared when probeAndRegister reports unavailable",
132
+ test("probeAndRegister returns false when no Ollama models are discovered", async () => {
133
+ serverMode = "empty";
134
+ const { pi, calls } = makeMockPi();
135
+ const found = await probeAndRegister(pi);
136
+ assert.equal(found, false, "no models should be reported as unavailable");
137
+ assert.equal(
138
+ calls.registerProvider.length,
139
+ 0,
140
+ "provider must not be registered when no models are discoverable",
27
141
  );
28
142
  });
143
+
144
+ test("probeAndRegister returns true when Ollama has at least one model", async () => {
145
+ serverMode = "loaded";
146
+ const { pi, calls } = makeMockPi();
147
+ const found = await probeAndRegister(pi);
148
+ assert.equal(found, true);
149
+ assert.equal(calls.registerProvider.length, 1);
150
+ });
151
+
152
+ test("interactive session sets ollama status based on probeAndRegister result", async () => {
153
+ // Load case: status should be set to "Ollama".
154
+ {
155
+ serverMode = "loaded";
156
+ const { pi, calls } = makeMockPi();
157
+ ollamaExtension(pi);
158
+ const handlers = calls.onHandlers.get("session_start") ?? [];
159
+ assert.equal(handlers.length, 1, "extension registers one session_start handler");
160
+
161
+ const statusCalls: Array<[string, string | undefined]> = [];
162
+ const ctx = {
163
+ hasUI: true,
164
+ ui: {
165
+ setStatus: (slot: string, value: string | undefined) => {
166
+ statusCalls.push([slot, value]);
167
+ },
168
+ notify: () => {},
169
+ },
170
+ };
171
+
172
+ // Fire session_start; wait a tick for the internal promise chain to resolve.
173
+ await handlers[0]({}, ctx);
174
+ // Give probeAndRegister + .then(setStatus) time to complete.
175
+ for (let i = 0; i < 50; i++) {
176
+ if (statusCalls.length > 0) break;
177
+ await new Promise((r) => setTimeout(r, 20));
178
+ }
179
+ assert.deepEqual(
180
+ statusCalls,
181
+ [["ollama", "Ollama"]],
182
+ "status should be set to 'Ollama' when probe reports available",
183
+ );
184
+ }
185
+
186
+ // Unavailable case: status should be cleared (undefined).
187
+ {
188
+ serverMode = "empty";
189
+ const { pi, calls } = makeMockPi();
190
+ ollamaExtension(pi);
191
+ const handlers = calls.onHandlers.get("session_start") ?? [];
192
+
193
+ const statusCalls: Array<[string, string | undefined]> = [];
194
+ const ctx = {
195
+ hasUI: true,
196
+ ui: {
197
+ setStatus: (slot: string, value: string | undefined) => {
198
+ statusCalls.push([slot, value]);
199
+ },
200
+ notify: () => {},
201
+ },
202
+ };
203
+
204
+ await handlers[0]({}, ctx);
205
+ for (let i = 0; i < 50; i++) {
206
+ if (statusCalls.length > 0) break;
207
+ await new Promise((r) => setTimeout(r, 20));
208
+ }
209
+ assert.deepEqual(
210
+ statusCalls,
211
+ [["ollama", undefined]],
212
+ "status must be cleared (undefined) when probe reports unavailable",
213
+ );
214
+ }
215
+ });
@@ -14,6 +14,28 @@ import { sanitizeError } from "../shared/sanitize.js";
14
14
 
15
15
  const COMMAND_POLLING_INTERVAL_MS = 5000;
16
16
 
17
+ /**
18
+ * Minimal adapter surface used by startCommandPolling. Just enough for
19
+ * the polling loop to invoke without pulling in the full
20
+ * TelegramAdapter in tests.
21
+ */
22
+ export interface PollingAdapter {
23
+ pollAndHandleCommands: (basePath: string) => Promise<number>;
24
+ }
25
+
26
+ /**
27
+ * Optional dependency-injection seam for `startCommandPolling`. Production
28
+ * callers pass nothing; tests stub the config resolver, adapter
29
+ * constructor, and timer functions to exercise the real function
30
+ * without hitting the filesystem / env / real intervals. See #4806.
31
+ */
32
+ export interface CommandPollingDeps {
33
+ resolveConfig?: () => ResolvedConfig | null;
34
+ createAdapter?: (config: ResolvedConfig, basePath: string) => PollingAdapter;
35
+ setIntervalFn?: typeof setInterval;
36
+ clearIntervalFn?: typeof clearInterval;
37
+ }
38
+
17
39
  /**
18
40
  * Start background polling for incoming slash commands on the configured
19
41
  * remote channel. Only Telegram supports command polling — other channels
@@ -21,27 +43,37 @@ const COMMAND_POLLING_INTERVAL_MS = 5000;
21
43
  *
22
44
  * @param basePath - Project root, forwarded to command handlers (e.g. /status).
23
45
  * @param intervalMs - Polling interval in milliseconds (default 5 s).
46
+ * @param deps - Test-only overrides. Omit in production.
24
47
  * @returns A cleanup function that stops the polling interval.
25
48
  */
26
49
  export function startCommandPolling(
27
50
  basePath: string,
28
51
  intervalMs = COMMAND_POLLING_INTERVAL_MS,
52
+ deps: CommandPollingDeps = {},
29
53
  ): () => void {
30
- const config = resolveRemoteConfig();
54
+ const resolveConfig = deps.resolveConfig ?? resolveRemoteConfig;
55
+ const createAdapter =
56
+ deps.createAdapter ??
57
+ ((c: ResolvedConfig, b: string): PollingAdapter =>
58
+ new TelegramAdapter(c.token, c.channelId, b));
59
+ const setIntervalFn = deps.setIntervalFn ?? setInterval;
60
+ const clearIntervalFn = deps.clearIntervalFn ?? clearInterval;
61
+
62
+ const config = resolveConfig();
31
63
  if (!config || config.channel !== "telegram") {
32
64
  // Non-Telegram channels have no command polling support — return a no-op cleanup.
33
65
  return () => {};
34
66
  }
35
67
 
36
- const adapter = new TelegramAdapter(config.token, config.channelId, basePath);
68
+ const adapter = createAdapter(config, basePath);
37
69
 
38
- const timer = setInterval(() => {
70
+ const timer = setIntervalFn(() => {
39
71
  void adapter.pollAndHandleCommands(basePath).catch(() => {
40
72
  // Non-fatal: network hiccup or rate-limit — best-effort polling
41
73
  });
42
74
  }, intervalMs);
43
75
 
44
- return () => clearInterval(timer);
76
+ return () => clearIntervalFn(timer);
45
77
  }
46
78
 
47
79
  interface ToolResult {