gsd-pi 2.77.0-dev.1d17f366c → 2.77.0-dev.2daa994b6

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 (368) hide show
  1. package/dist/headless.js +25 -4
  2. package/dist/resource-loader.d.ts +40 -0
  3. package/dist/resource-loader.js +32 -13
  4. package/dist/resources/extensions/browser-tools/capture.js +9 -0
  5. package/dist/resources/extensions/browser-tools/tests/browser-tools-integration.test.mjs +8 -59
  6. package/dist/resources/extensions/browser-tools/tests/browser-tools-unit.test.cjs +36 -24
  7. package/dist/resources/extensions/browser-tools/tests/capture-sharp-optional.test.cjs +69 -71
  8. package/dist/resources/extensions/browser-tools/tools/forms.js +5 -1
  9. package/dist/resources/extensions/browser-tools/tools/intent.js +5 -1
  10. package/dist/resources/extensions/gsd/auto/phases.js +5 -18
  11. package/dist/resources/extensions/gsd/auto/session.js +6 -0
  12. package/dist/resources/extensions/gsd/auto-dispatch.js +37 -8
  13. package/dist/resources/extensions/gsd/auto-post-unit.js +79 -0
  14. package/dist/resources/extensions/gsd/auto-prompts.js +372 -104
  15. package/dist/resources/extensions/gsd/auto-start.js +75 -24
  16. package/dist/resources/extensions/gsd/auto.js +34 -0
  17. package/dist/resources/extensions/gsd/bootstrap/agent-end-recovery.js +9 -1
  18. package/dist/resources/extensions/gsd/bootstrap/write-gate.js +7 -1
  19. package/dist/resources/extensions/gsd/component-loader.js +447 -0
  20. package/dist/resources/extensions/gsd/component-types.js +69 -0
  21. package/dist/resources/extensions/gsd/context-store.js +23 -7
  22. package/dist/resources/extensions/gsd/detection.js +49 -1
  23. package/dist/resources/extensions/gsd/docs/preferences-reference.md +1 -1
  24. package/dist/resources/extensions/gsd/forensics.js +106 -0
  25. package/dist/resources/extensions/gsd/gsd-db.js +1 -1
  26. package/dist/resources/extensions/gsd/guided-flow.js +2 -4
  27. package/dist/resources/extensions/gsd/memory-extractor.js +7 -1
  28. package/dist/resources/extensions/gsd/milestone-scope-classifier.js +299 -0
  29. package/dist/resources/extensions/gsd/model-cost-table.js +3 -0
  30. package/dist/resources/extensions/gsd/model-router.js +6 -0
  31. package/dist/resources/extensions/gsd/preferences-validation.js +23 -0
  32. package/dist/resources/extensions/gsd/prompt-cache-optimizer.js +4 -0
  33. package/dist/resources/extensions/gsd/prompts/complete-milestone.md +5 -1
  34. package/dist/resources/extensions/gsd/prompts/plan-slice.md +15 -2
  35. package/dist/resources/extensions/gsd/service-tier.js +5 -2
  36. package/dist/resources/extensions/gsd/skill-manifest.js +168 -0
  37. package/dist/resources/extensions/gsd/slice-cadence.js +238 -0
  38. package/dist/resources/extensions/gsd/tools/validate-milestone.js +7 -2
  39. package/dist/resources/extensions/gsd/unit-context-composer.js +147 -0
  40. package/dist/resources/extensions/gsd/unit-context-manifest.js +334 -0
  41. package/dist/resources/extensions/gsd/worktree-manager.js +51 -0
  42. package/dist/resources/extensions/gsd/worktree-resolver.js +86 -7
  43. package/dist/resources/extensions/gsd/worktree-telemetry.js +198 -0
  44. package/dist/resources/extensions/mcp-client/index.js +3 -1
  45. package/dist/resources/extensions/ollama/index.js +5 -1
  46. package/dist/resources/extensions/remote-questions/manager.js +11 -5
  47. package/dist/tsconfig.extensions.tsbuildinfo +1 -1
  48. package/dist/web/standalone/.next/BUILD_ID +1 -1
  49. package/dist/web/standalone/.next/app-path-routes-manifest.json +17 -17
  50. package/dist/web/standalone/.next/build-manifest.json +2 -2
  51. package/dist/web/standalone/.next/prerender-manifest.json +3 -3
  52. package/dist/web/standalone/.next/server/app/_global-error.html +1 -1
  53. package/dist/web/standalone/.next/server/app/_global-error.rsc +1 -1
  54. package/dist/web/standalone/.next/server/app/_global-error.segments/_full.segment.rsc +1 -1
  55. package/dist/web/standalone/.next/server/app/_global-error.segments/_global-error/__PAGE__.segment.rsc +1 -1
  56. package/dist/web/standalone/.next/server/app/_global-error.segments/_global-error.segment.rsc +1 -1
  57. package/dist/web/standalone/.next/server/app/_global-error.segments/_head.segment.rsc +1 -1
  58. package/dist/web/standalone/.next/server/app/_global-error.segments/_index.segment.rsc +1 -1
  59. package/dist/web/standalone/.next/server/app/_global-error.segments/_tree.segment.rsc +1 -1
  60. package/dist/web/standalone/.next/server/app/_not-found.html +1 -1
  61. package/dist/web/standalone/.next/server/app/_not-found.rsc +1 -1
  62. package/dist/web/standalone/.next/server/app/_not-found.segments/_full.segment.rsc +1 -1
  63. package/dist/web/standalone/.next/server/app/_not-found.segments/_head.segment.rsc +1 -1
  64. package/dist/web/standalone/.next/server/app/_not-found.segments/_index.segment.rsc +1 -1
  65. package/dist/web/standalone/.next/server/app/_not-found.segments/_not-found/__PAGE__.segment.rsc +1 -1
  66. package/dist/web/standalone/.next/server/app/_not-found.segments/_not-found.segment.rsc +1 -1
  67. package/dist/web/standalone/.next/server/app/_not-found.segments/_tree.segment.rsc +1 -1
  68. package/dist/web/standalone/.next/server/app/index.html +1 -1
  69. package/dist/web/standalone/.next/server/app/index.rsc +1 -1
  70. package/dist/web/standalone/.next/server/app/index.segments/__PAGE__.segment.rsc +1 -1
  71. package/dist/web/standalone/.next/server/app/index.segments/_full.segment.rsc +1 -1
  72. package/dist/web/standalone/.next/server/app/index.segments/_head.segment.rsc +1 -1
  73. package/dist/web/standalone/.next/server/app/index.segments/_index.segment.rsc +1 -1
  74. package/dist/web/standalone/.next/server/app/index.segments/_tree.segment.rsc +1 -1
  75. package/dist/web/standalone/.next/server/app-paths-manifest.json +17 -17
  76. package/dist/web/standalone/.next/server/chunks/6897.js +1 -1
  77. package/dist/web/standalone/.next/server/middleware-build-manifest.js +1 -1
  78. package/dist/web/standalone/.next/server/middleware-manifest.json +5 -5
  79. package/dist/web/standalone/.next/server/pages/404.html +1 -1
  80. package/dist/web/standalone/.next/server/pages/500.html +1 -1
  81. package/dist/web/standalone/.next/server/server-reference-manifest.json +1 -1
  82. package/package.json +1 -3
  83. package/packages/mcp-server/src/mcp-server.test.ts +25 -3
  84. package/packages/mcp-server/src/readers/graph.test.ts +87 -15
  85. package/packages/mcp-server/src/workflow-tools.test.ts +80 -39
  86. package/packages/native/package.json +1 -1
  87. package/packages/native/src/__tests__/_test-coverage-guard.test.mjs +98 -0
  88. package/packages/native/src/__tests__/module-compat.test.mjs +59 -27
  89. package/packages/native/src/__tests__/ps.test.mjs +14 -8
  90. package/packages/native/src/__tests__/stream-process.test.mjs +23 -2
  91. package/packages/native/src/__tests__/truncate.test.mjs +17 -2
  92. package/packages/pi-agent-core/src/agent-loop.test.ts +5 -15
  93. package/packages/pi-agent-core/src/agent.test.ts +96 -102
  94. package/packages/pi-agent-core/tsconfig.tsbuildinfo +1 -1
  95. package/packages/pi-ai/dist/models/generated/index.d.ts +34 -0
  96. package/packages/pi-ai/dist/models/generated/index.d.ts.map +1 -1
  97. package/packages/pi-ai/dist/models/generated/openai-codex.d.ts +17 -0
  98. package/packages/pi-ai/dist/models/generated/openai-codex.d.ts.map +1 -1
  99. package/packages/pi-ai/dist/models/generated/openai-codex.js +17 -0
  100. package/packages/pi-ai/dist/models/generated/openai-codex.js.map +1 -1
  101. package/packages/pi-ai/dist/models/generated/openai.d.ts +17 -0
  102. package/packages/pi-ai/dist/models/generated/openai.d.ts.map +1 -1
  103. package/packages/pi-ai/dist/models/generated/openai.js +17 -0
  104. package/packages/pi-ai/dist/models/generated/openai.js.map +1 -1
  105. package/packages/pi-ai/dist/models.generated.test.js +43 -70
  106. package/packages/pi-ai/dist/models.generated.test.js.map +1 -1
  107. package/packages/pi-ai/dist/models.test.js +29 -11
  108. package/packages/pi-ai/dist/models.test.js.map +1 -1
  109. package/packages/pi-ai/scripts/generate-models.ts +44 -0
  110. package/packages/pi-ai/src/models/generated/openai-codex.ts +17 -0
  111. package/packages/pi-ai/src/models/generated/openai.ts +17 -0
  112. package/packages/pi-ai/src/models.generated.test.ts +46 -73
  113. package/packages/pi-ai/src/models.test.ts +39 -11
  114. package/packages/pi-ai/tsconfig.tsbuildinfo +1 -1
  115. package/packages/pi-coding-agent/dist/core/agent-session-abort-order.test.js +96 -32
  116. package/packages/pi-coding-agent/dist/core/agent-session-abort-order.test.js.map +1 -1
  117. package/packages/pi-coding-agent/dist/core/agent-session-model-switch.test.js +75 -12
  118. package/packages/pi-coding-agent/dist/core/agent-session-model-switch.test.js.map +1 -1
  119. package/packages/pi-coding-agent/dist/core/agent-session-tool-refresh.test.js +99 -31
  120. package/packages/pi-coding-agent/dist/core/agent-session-tool-refresh.test.js.map +1 -1
  121. package/packages/pi-coding-agent/dist/core/extensions/loader.d.ts +5 -0
  122. package/packages/pi-coding-agent/dist/core/extensions/loader.d.ts.map +1 -1
  123. package/packages/pi-coding-agent/dist/core/extensions/loader.js +61 -0
  124. package/packages/pi-coding-agent/dist/core/extensions/loader.js.map +1 -1
  125. package/packages/pi-coding-agent/dist/core/lsp/lsp-integration.test.js +30 -4
  126. package/packages/pi-coding-agent/dist/core/lsp/lsp-integration.test.js.map +1 -1
  127. package/packages/pi-coding-agent/dist/core/model-registry-auth-mode.test.js +17 -0
  128. package/packages/pi-coding-agent/dist/core/model-registry-auth-mode.test.js.map +1 -1
  129. package/packages/pi-coding-agent/dist/core/resource-loader-cache-reset.test.js +76 -18
  130. package/packages/pi-coding-agent/dist/core/resource-loader-cache-reset.test.js.map +1 -1
  131. package/packages/pi-coding-agent/dist/core/retry-handler.d.ts.map +1 -1
  132. package/packages/pi-coding-agent/dist/core/retry-handler.js +2 -6
  133. package/packages/pi-coding-agent/dist/core/retry-handler.js.map +1 -1
  134. package/packages/pi-coding-agent/dist/core/retry-handler.test.js +5 -1
  135. package/packages/pi-coding-agent/dist/core/retry-handler.test.js.map +1 -1
  136. package/packages/pi-coding-agent/dist/core/retryable-error-regex.d.ts +18 -0
  137. package/packages/pi-coding-agent/dist/core/retryable-error-regex.d.ts.map +1 -0
  138. package/packages/pi-coding-agent/dist/core/retryable-error-regex.js +18 -0
  139. package/packages/pi-coding-agent/dist/core/retryable-error-regex.js.map +1 -0
  140. package/packages/pi-coding-agent/dist/core/system-prompt.d.ts +20 -0
  141. package/packages/pi-coding-agent/dist/core/system-prompt.d.ts.map +1 -1
  142. package/packages/pi-coding-agent/dist/core/system-prompt.js +16 -2
  143. package/packages/pi-coding-agent/dist/core/system-prompt.js.map +1 -1
  144. package/packages/pi-coding-agent/dist/index.d.ts +1 -0
  145. package/packages/pi-coding-agent/dist/index.d.ts.map +1 -1
  146. package/packages/pi-coding-agent/dist/index.js +1 -0
  147. package/packages/pi-coding-agent/dist/index.js.map +1 -1
  148. package/packages/pi-coding-agent/dist/modes/interactive/components/__tests__/tool-execution.test.js +36 -5
  149. package/packages/pi-coding-agent/dist/modes/interactive/components/__tests__/tool-execution.test.js.map +1 -1
  150. package/packages/pi-coding-agent/dist/modes/interactive/components/dynamic-border.test.js +20 -13
  151. package/packages/pi-coding-agent/dist/modes/interactive/components/dynamic-border.test.js.map +1 -1
  152. package/packages/pi-coding-agent/dist/modes/interactive/components/tool-execution.d.ts.map +1 -1
  153. package/packages/pi-coding-agent/dist/modes/interactive/components/tool-execution.js +30 -12
  154. package/packages/pi-coding-agent/dist/modes/interactive/components/tool-execution.js.map +1 -1
  155. package/packages/pi-coding-agent/dist/tests/system-prompt-skill-filter.test.d.ts +2 -0
  156. package/packages/pi-coding-agent/dist/tests/system-prompt-skill-filter.test.d.ts.map +1 -0
  157. package/packages/pi-coding-agent/dist/tests/system-prompt-skill-filter.test.js +130 -0
  158. package/packages/pi-coding-agent/dist/tests/system-prompt-skill-filter.test.js.map +1 -0
  159. package/packages/pi-coding-agent/src/core/agent-session-abort-order.test.ts +113 -37
  160. package/packages/pi-coding-agent/src/core/agent-session-model-switch.test.ts +89 -17
  161. package/packages/pi-coding-agent/src/core/agent-session-tool-refresh.test.ts +112 -43
  162. package/packages/pi-coding-agent/src/core/extensions/loader.ts +58 -0
  163. package/packages/pi-coding-agent/src/core/lsp/lsp-integration.test.ts +35 -4
  164. package/packages/pi-coding-agent/src/core/model-registry-auth-mode.test.ts +20 -0
  165. package/packages/pi-coding-agent/src/core/resource-loader-cache-reset.test.ts +93 -28
  166. package/packages/pi-coding-agent/src/core/retry-handler.test.ts +5 -1
  167. package/packages/pi-coding-agent/src/core/retry-handler.ts +2 -8
  168. package/packages/pi-coding-agent/src/core/retryable-error-regex.ts +18 -0
  169. package/packages/pi-coding-agent/src/core/system-prompt.ts +35 -1
  170. package/packages/pi-coding-agent/src/index.ts +1 -0
  171. package/packages/pi-coding-agent/src/modes/interactive/components/__tests__/tool-execution.test.ts +49 -3
  172. package/packages/pi-coding-agent/src/modes/interactive/components/dynamic-border.test.ts +26 -20
  173. package/packages/pi-coding-agent/src/modes/interactive/components/tool-execution.ts +48 -9
  174. package/packages/pi-coding-agent/src/tests/system-prompt-skill-filter.test.ts +157 -0
  175. package/packages/pi-coding-agent/tsconfig.tsbuildinfo +1 -1
  176. package/packages/pi-tui/dist/__tests__/autocomplete.test.js +18 -8
  177. package/packages/pi-tui/dist/__tests__/autocomplete.test.js.map +1 -1
  178. package/packages/pi-tui/dist/__tests__/overlay-layout.test.js +128 -17
  179. package/packages/pi-tui/dist/__tests__/overlay-layout.test.js.map +1 -1
  180. package/packages/pi-tui/dist/__tests__/stdin-buffer.test.js +36 -12
  181. package/packages/pi-tui/dist/__tests__/stdin-buffer.test.js.map +1 -1
  182. package/packages/pi-tui/dist/__tests__/tui.test.js +18 -30
  183. package/packages/pi-tui/dist/__tests__/tui.test.js.map +1 -1
  184. package/packages/pi-tui/dist/components/__tests__/input.test.js +10 -3
  185. package/packages/pi-tui/dist/components/__tests__/input.test.js.map +1 -1
  186. package/packages/pi-tui/dist/components/__tests__/loader.test.js +53 -9
  187. package/packages/pi-tui/dist/components/__tests__/loader.test.js.map +1 -1
  188. package/packages/pi-tui/dist/components/__tests__/markdown-maxlines.test.js +6 -2
  189. package/packages/pi-tui/dist/components/__tests__/markdown-maxlines.test.js.map +1 -1
  190. package/packages/pi-tui/dist/components/image.test.js +6 -5
  191. package/packages/pi-tui/dist/components/image.test.js.map +1 -1
  192. package/packages/pi-tui/src/__tests__/autocomplete.test.ts +24 -8
  193. package/packages/pi-tui/src/__tests__/overlay-layout.test.ts +140 -17
  194. package/packages/pi-tui/src/__tests__/stdin-buffer.test.ts +41 -12
  195. package/packages/pi-tui/src/__tests__/tui.test.ts +18 -37
  196. package/packages/pi-tui/src/components/__tests__/input.test.ts +19 -3
  197. package/packages/pi-tui/src/components/__tests__/loader.test.ts +112 -35
  198. package/packages/pi-tui/src/components/__tests__/markdown-maxlines.test.ts +9 -2
  199. package/packages/pi-tui/src/components/image.test.ts +10 -5
  200. package/packages/pi-tui/tsconfig.tsbuildinfo +1 -1
  201. package/packages/rpc-client/dist/rpc-client.test.js +101 -51
  202. package/packages/rpc-client/dist/rpc-client.test.js.map +1 -1
  203. package/packages/rpc-client/src/rpc-client.test.ts +109 -52
  204. package/packages/rpc-client/tsconfig.tsbuildinfo +1 -1
  205. package/scripts/install.js +15 -1
  206. package/src/resources/extensions/browser-tools/capture.ts +12 -0
  207. package/src/resources/extensions/browser-tools/tests/browser-tools-integration.test.mjs +8 -59
  208. package/src/resources/extensions/browser-tools/tests/browser-tools-unit.test.cjs +36 -24
  209. package/src/resources/extensions/browser-tools/tests/capture-sharp-optional.test.cjs +69 -71
  210. package/src/resources/extensions/browser-tools/tools/forms.ts +5 -1
  211. package/src/resources/extensions/browser-tools/tools/intent.ts +5 -1
  212. package/src/resources/extensions/claude-code-cli/tests/stream-adapter.test.ts +80 -72
  213. package/src/resources/extensions/github-sync/tests/cli.test.ts +76 -7
  214. package/src/resources/extensions/github-sync/tests/templates.test.ts +33 -1
  215. package/src/resources/extensions/gsd/auto/phases.ts +6 -17
  216. package/src/resources/extensions/gsd/auto/session.ts +7 -0
  217. package/src/resources/extensions/gsd/auto-dispatch.ts +40 -8
  218. package/src/resources/extensions/gsd/auto-post-unit.ts +81 -0
  219. package/src/resources/extensions/gsd/auto-prompts.ts +385 -93
  220. package/src/resources/extensions/gsd/auto-start.ts +97 -4
  221. package/src/resources/extensions/gsd/auto.ts +37 -0
  222. package/src/resources/extensions/gsd/bootstrap/agent-end-recovery.ts +9 -1
  223. package/src/resources/extensions/gsd/bootstrap/write-gate.ts +7 -1
  224. package/src/resources/extensions/gsd/component-loader.ts +598 -0
  225. package/src/resources/extensions/gsd/component-types.ts +362 -0
  226. package/src/resources/extensions/gsd/context-store.ts +25 -8
  227. package/src/resources/extensions/gsd/detection.ts +58 -1
  228. package/src/resources/extensions/gsd/docs/preferences-reference.md +1 -1
  229. package/src/resources/extensions/gsd/forensics.ts +118 -1
  230. package/src/resources/extensions/gsd/git-service.ts +16 -0
  231. package/src/resources/extensions/gsd/gsd-db.ts +1 -1
  232. package/src/resources/extensions/gsd/guided-flow.ts +2 -4
  233. package/src/resources/extensions/gsd/journal.ts +11 -1
  234. package/src/resources/extensions/gsd/memory-extractor.ts +11 -3
  235. package/src/resources/extensions/gsd/milestone-scope-classifier.ts +366 -0
  236. package/src/resources/extensions/gsd/model-cost-table.ts +3 -0
  237. package/src/resources/extensions/gsd/model-router.ts +6 -0
  238. package/src/resources/extensions/gsd/preferences-validation.ts +21 -0
  239. package/src/resources/extensions/gsd/prompt-cache-optimizer.ts +4 -0
  240. package/src/resources/extensions/gsd/prompts/complete-milestone.md +5 -1
  241. package/src/resources/extensions/gsd/prompts/plan-slice.md +15 -2
  242. package/src/resources/extensions/gsd/service-tier.ts +5 -2
  243. package/src/resources/extensions/gsd/skill-manifest.ts +175 -0
  244. package/src/resources/extensions/gsd/slice-cadence.ts +299 -0
  245. package/src/resources/extensions/gsd/tests/artifacts-table-preserved-on-cache-invalidate.test.ts +2 -1
  246. package/src/resources/extensions/gsd/tests/auto-loop.test.ts +25 -292
  247. package/src/resources/extensions/gsd/tests/auto-remediate-slice-status.test.ts +4 -1
  248. package/src/resources/extensions/gsd/tests/auto-retry-mcp-churn-fixes.test.ts +8 -194
  249. package/src/resources/extensions/gsd/tests/auto-start-clean-runtime-db-gated.test.ts +3 -2
  250. package/src/resources/extensions/gsd/tests/auto-start-cold-db-bootstrap.test.ts +2 -2
  251. package/src/resources/extensions/gsd/tests/auto-start-needs-discussion.test.ts +15 -58
  252. package/src/resources/extensions/gsd/tests/auto-start-worktree-db-path.test.ts +2 -2
  253. package/src/resources/extensions/gsd/tests/auto-thinking-restore.test.ts +3 -2
  254. package/src/resources/extensions/gsd/tests/auto-warning-noise-regression.test.ts +3 -2
  255. package/src/resources/extensions/gsd/tests/bootstrap-derive-state-db-open.test.ts +2 -1
  256. package/src/resources/extensions/gsd/tests/cache-staleness-regression.test.ts +17 -21
  257. package/src/resources/extensions/gsd/tests/canonical-milestone-root.test.ts +108 -0
  258. package/src/resources/extensions/gsd/tests/complete-milestone-excerpt.test.ts +263 -0
  259. package/src/resources/extensions/gsd/tests/complete-slice-composer.test.ts +192 -0
  260. package/src/resources/extensions/gsd/tests/complete-slice-verification-gate.test.ts +2 -1
  261. package/src/resources/extensions/gsd/tests/complete-task.test.ts +8 -4
  262. package/src/resources/extensions/gsd/tests/component-loader.test.ts +589 -0
  263. package/src/resources/extensions/gsd/tests/component-types.test.ts +127 -0
  264. package/src/resources/extensions/gsd/tests/context-store.test.ts +79 -0
  265. package/src/resources/extensions/gsd/tests/copy-planning-artifacts-samepath.test.ts +2 -1
  266. package/src/resources/extensions/gsd/tests/discuss-slice-structured-questions.test.ts +2 -1
  267. package/src/resources/extensions/gsd/tests/discuss-tool-scope-leak.test.ts +2 -1
  268. package/src/resources/extensions/gsd/tests/double-merge-guard.test.ts +4 -3
  269. package/src/resources/extensions/gsd/tests/empty-content-abort-loop.test.ts +4 -3
  270. package/src/resources/extensions/gsd/tests/extension-bootstrap-isolation.test.ts +139 -129
  271. package/src/resources/extensions/gsd/tests/finalize-timeout-guard.test.ts +8 -104
  272. package/src/resources/extensions/gsd/tests/hook-key-parsing.test.ts +4 -55
  273. package/src/resources/extensions/gsd/tests/integration/all-milestones-complete-merge.test.ts +7 -56
  274. package/src/resources/extensions/gsd/tests/integration/doctor-proactive.test.ts +18 -2
  275. package/src/resources/extensions/gsd/tests/integration/queue-completed-milestone-perf.test.ts +10 -4
  276. package/src/resources/extensions/gsd/tests/integration/state-machine-edge-cases.test.ts +1 -1
  277. package/src/resources/extensions/gsd/tests/interactive-routing-bypass.test.ts +9 -3
  278. package/src/resources/extensions/gsd/tests/interrupted-session-ui.test.ts +6 -9
  279. package/src/resources/extensions/gsd/tests/knowledge.test.ts +93 -1
  280. package/src/resources/extensions/gsd/tests/mcp-client-security.test.ts +8 -37
  281. package/src/resources/extensions/gsd/tests/memory-extractor.test.ts +5 -15
  282. package/src/resources/extensions/gsd/tests/merge-conflict-stops-loop.test.ts +227 -55
  283. package/src/resources/extensions/gsd/tests/milestone-scope-classifier.test.ts +187 -0
  284. package/src/resources/extensions/gsd/tests/model-cost-table.test.ts +9 -1
  285. package/src/resources/extensions/gsd/tests/model-router.test.ts +1 -1
  286. package/src/resources/extensions/gsd/tests/native-git-bridge-exec-fallback.test.ts +6 -48
  287. package/src/resources/extensions/gsd/tests/notification-widget.test.ts +6 -3
  288. package/src/resources/extensions/gsd/tests/orphaned-worktree-audit.test.ts +59 -2
  289. package/src/resources/extensions/gsd/tests/parallel-research-dispatch.test.ts +273 -130
  290. package/src/resources/extensions/gsd/tests/pipeline-variant-dispatch.test.ts +301 -0
  291. package/src/resources/extensions/gsd/tests/preferences-worktree-sync.test.ts +2 -1
  292. package/src/resources/extensions/gsd/tests/prompt-cache-optimizer.test.ts +12 -0
  293. package/src/resources/extensions/gsd/tests/prompt-step-ordering.test.ts +15 -4
  294. package/src/resources/extensions/gsd/tests/provider-errors.test.ts +22 -16
  295. package/src/resources/extensions/gsd/tests/queue-draft-detection.test.ts +3 -2
  296. package/src/resources/extensions/gsd/tests/queued-discuss-fast-path.test.ts +4 -5
  297. package/src/resources/extensions/gsd/tests/reassess-default-optin.test.ts +132 -0
  298. package/src/resources/extensions/gsd/tests/recovery-attempts-reset.test.ts +8 -40
  299. package/src/resources/extensions/gsd/tests/regex-hardening.test.ts +136 -256
  300. package/src/resources/extensions/gsd/tests/research-milestone-composer.test.ts +114 -0
  301. package/src/resources/extensions/gsd/tests/restore-tools-after-discuss.test.ts +6 -3
  302. package/src/resources/extensions/gsd/tests/run-uat-composer.test.ts +148 -0
  303. package/src/resources/extensions/gsd/tests/service-tier.test.ts +4 -0
  304. package/src/resources/extensions/gsd/tests/sidecar-queue.test.ts +3 -2
  305. package/src/resources/extensions/gsd/tests/silent-catch-diagnostics.test.ts +55 -95
  306. package/src/resources/extensions/gsd/tests/skill-activation.test.ts +120 -1
  307. package/src/resources/extensions/gsd/tests/skill-manifest.test.ts +112 -0
  308. package/src/resources/extensions/gsd/tests/slice-cadence.test.ts +242 -0
  309. package/src/resources/extensions/gsd/tests/slice-context-injection.test.ts +3 -2
  310. package/src/resources/extensions/gsd/tests/smart-entry-draft.test.ts +2 -1
  311. package/src/resources/extensions/gsd/tests/stop-auto-race-null-unit.test.ts +3 -3
  312. package/src/resources/extensions/gsd/tests/structured-data-formatter.test.ts +11 -92
  313. package/src/resources/extensions/gsd/tests/subagent-model-dispatch.test.ts +7 -6
  314. package/src/resources/extensions/gsd/tests/survivor-branch-complete.test.ts +102 -101
  315. package/src/resources/extensions/gsd/tests/sync-worktree-skip-current.test.ts +4 -3
  316. package/src/resources/extensions/gsd/tests/test-helpers.test.ts +98 -0
  317. package/src/resources/extensions/gsd/tests/test-helpers.ts +153 -0
  318. package/src/resources/extensions/gsd/tests/token-profile.test.ts +8 -1
  319. package/src/resources/extensions/gsd/tests/unit-context-composer.test.ts +355 -0
  320. package/src/resources/extensions/gsd/tests/unit-context-manifest.test.ts +203 -0
  321. package/src/resources/extensions/gsd/tests/uok-gitops-wiring.test.ts +49 -26
  322. package/src/resources/extensions/gsd/tests/validate-milestone.test.ts +1 -0
  323. package/src/resources/extensions/gsd/tests/verify-artifact-tightened.test.ts +144 -80
  324. package/src/resources/extensions/gsd/tests/visualizer-critical-path.test.ts +20 -54
  325. package/src/resources/extensions/gsd/tests/visualizer-overlay.test.ts +342 -277
  326. package/src/resources/extensions/gsd/tests/worker-model-override.test.ts +37 -29
  327. package/src/resources/extensions/gsd/tests/worktree-db.test.ts +226 -266
  328. package/src/resources/extensions/gsd/tests/worktree-health-monorepo.test.ts +103 -67
  329. package/src/resources/extensions/gsd/tests/worktree-nested-git-safety.test.ts +92 -90
  330. package/src/resources/extensions/gsd/tests/worktree-submodule-safety.test.ts +238 -59
  331. package/src/resources/extensions/gsd/tests/worktree-sync-overwrite-loop.test.ts +113 -161
  332. package/src/resources/extensions/gsd/tests/worktree-telemetry.test.ts +210 -0
  333. package/src/resources/extensions/gsd/tests/zombie-gsd-state.test.ts +80 -96
  334. package/src/resources/extensions/gsd/tools/validate-milestone.ts +8 -2
  335. package/src/resources/extensions/gsd/unit-context-composer.ts +218 -0
  336. package/src/resources/extensions/gsd/unit-context-manifest.ts +492 -0
  337. package/src/resources/extensions/gsd/worktree-manager.ts +53 -0
  338. package/src/resources/extensions/gsd/worktree-resolver.ts +96 -9
  339. package/src/resources/extensions/gsd/worktree-telemetry.ts +322 -0
  340. package/src/resources/extensions/mcp-client/index.ts +3 -1
  341. package/src/resources/extensions/mcp-client/tests/server-name-spaces.test.ts +70 -36
  342. package/src/resources/extensions/ollama/index.ts +5 -1
  343. package/src/resources/extensions/ollama/ollama-auth-mode.test.ts +123 -15
  344. package/src/resources/extensions/ollama/ollama-status-indicator.test.ts +206 -19
  345. package/src/resources/extensions/remote-questions/manager.ts +36 -4
  346. package/src/resources/extensions/remote-questions/tests/command-polling.test.ts +200 -190
  347. package/src/resources/extensions/shared/tests/interview-preview.test.ts +11 -3
  348. package/src/resources/extensions/voice/tests/linux-ready.test.ts +129 -113
  349. package/packages/pi-ai/dist/utils/oauth/oauth-providers.test.d.ts +0 -2
  350. package/packages/pi-ai/dist/utils/oauth/oauth-providers.test.d.ts.map +0 -1
  351. package/packages/pi-ai/dist/utils/oauth/oauth-providers.test.js +0 -289
  352. package/packages/pi-ai/dist/utils/oauth/oauth-providers.test.js.map +0 -1
  353. package/packages/pi-ai/src/utils/oauth/oauth-providers.test.ts +0 -363
  354. package/src/resources/extensions/gsd/tests/auto-start-model-capture.test.ts +0 -143
  355. package/src/resources/extensions/gsd/tests/complete-milestone-false-merge.test.ts +0 -157
  356. package/src/resources/extensions/gsd/tests/dashboard-model-label-ordering.test.ts +0 -107
  357. package/src/resources/extensions/gsd/tests/find-missing-summaries-closed.test.ts +0 -48
  358. package/src/resources/extensions/gsd/tests/forensics-context-persist.test.ts +0 -159
  359. package/src/resources/extensions/gsd/tests/forensics-db-completion.test.ts +0 -96
  360. package/src/resources/extensions/gsd/tests/forensics-dedup.test.ts +0 -79
  361. package/src/resources/extensions/gsd/tests/forensics-hook-key-parse.test.ts +0 -74
  362. package/src/resources/extensions/gsd/tests/forensics-journal.test.ts +0 -162
  363. package/src/resources/extensions/gsd/tests/gitignore-bg-shell.test.ts +0 -38
  364. package/src/resources/extensions/gsd/tests/gsd-no-project-error.test.ts +0 -73
  365. package/src/resources/extensions/gsd/tests/idle-watchdog-stall-override.test.ts +0 -125
  366. package/src/resources/extensions/gsd/tests/import-done-milestones.test.ts +0 -42
  367. /package/dist/web/standalone/.next/static/{vidAVJkURvTJ0_V2-64ro → gYYky7yfxW8txb9vU2TrJ}/_buildManifest.js +0 -0
  368. /package/dist/web/standalone/.next/static/{vidAVJkURvTJ0_V2-64ro → gYYky7yfxW8txb9vU2TrJ}/_ssgManifest.js +0 -0
@@ -9,9 +9,11 @@
9
9
 
10
10
  import { test, describe } from "node:test";
11
11
  import assert from "node:assert/strict";
12
- import { readFileSync } from "node:fs";
12
+ import { readFileSync, writeFileSync, mkdtempSync, existsSync } from "node:fs";
13
13
  import * as path from "node:path";
14
+ import * as os from "node:os";
14
15
  import { fileURLToPath } from "node:url";
16
+ import { spawnSync } from "node:child_process";
15
17
 
16
18
  const __dirname = path.dirname(fileURLToPath(import.meta.url));
17
19
  const pkgPath = path.resolve(__dirname, "..", "..", "package.json");
@@ -60,32 +62,62 @@ describe("@gsd/native module compatibility (#2861)", () => {
60
62
  }
61
63
  });
62
64
 
63
- test("native.ts source must not use bare import.meta.url (parse-time error in CJS)", () => {
64
- // When compiled to CJS, import.meta is a *parse-time* syntax error --
65
- // typeof guards don't help because Node rejects the syntax before
66
- // executing any code. The source must wrap import.meta access in
67
- // an indirect eval so the CJS parser never sees the bare syntax.
68
- const nativeSrc = readFileSync(
69
- path.resolve(__dirname, "..", "native.ts"),
70
- "utf8",
71
- );
65
+ test(
66
+ "compiled CJS output loads under a parent package with type: module (regression guard for #2861)",
67
+ () => {
68
+ // Behavioral guard: the real regression #2861 surfaced when the package
69
+ // was consumed from a parent whose `package.json` declared
70
+ // `"type": "module"`, because the CJS output was parse-errored by
71
+ // Node.js v24. Rather than grep the TypeScript source for forbidden
72
+ // strings (which would break on any equivalent refactor), this test
73
+ // actually requires the compiled CJS from a synthesized parent that
74
+ // mimics the failing layout in the original bug report.
75
+ const distPath = path.resolve(__dirname, "..", "..", "dist", "native.js");
76
+ if (!existsSync(distPath)) {
77
+ // The native package's test runner builds `dist/` before this test
78
+ // runs; however, developers may invoke the file in isolation. Skip
79
+ // rather than fail spuriously — the invariant still fails loudly
80
+ // on any regression under the full `npm test` flow.
81
+ return;
82
+ }
72
83
 
73
- // Bare import.meta.url (NOT wrapped) would crash at parse time in CJS.
74
- // These regexes match direct usage like fileURLToPath(import.meta.url)
75
- // and createRequire(import.meta.url), but NOT indirect patterns that
76
- // hide import.meta from the CJS parser.
77
- const hasBareImportMetaDirname = /path\.dirname\(.*fileURLToPath\(import\.meta\.url\)\)/.test(nativeSrc);
78
- const hasBareImportMetaRequire = /createRequire\(import\.meta\.url\)/.test(nativeSrc);
84
+ const parentDir = mkdtempSync(path.join(os.tmpdir(), "gsd-native-modcompat-"));
85
+ // Parent declares "type": "module", reproducing the #2861 layout.
86
+ writeFileSync(
87
+ path.join(parentDir, "package.json"),
88
+ JSON.stringify({ name: "modcompat-parent", type: "module" }),
89
+ );
90
+ const loader = path.join(parentDir, "load.cjs");
91
+ // Use `.cjs` to ensure Node treats the script as CJS regardless of
92
+ // the enclosing directory's module type — this mirrors how the
93
+ // package's own dist files need to resolve as CJS despite an ESM
94
+ // parent. We `require()` the compiled native.js entrypoint; a
95
+ // parse-time crash (as in #2861) would surface as non-zero exit
96
+ // with the error on stderr.
97
+ writeFileSync(
98
+ loader,
99
+ `require(${JSON.stringify(distPath)});\nconsole.log("OK");\n`,
100
+ );
79
101
 
80
- assert.ok(
81
- !hasBareImportMetaDirname,
82
- "native.ts must not use bare import.meta.url in fileURLToPath() -- " +
83
- "this is a parse-time syntax error in CJS; use indirect eval",
84
- );
85
- assert.ok(
86
- !hasBareImportMetaRequire,
87
- "native.ts must not use bare import.meta.url in createRequire() -- " +
88
- "this is a parse-time syntax error in CJS; use indirect eval",
89
- );
90
- });
102
+ const result = spawnSync(process.execPath, [loader], {
103
+ encoding: "utf8",
104
+ // Inherit nothing that could mask a native loader failure beyond
105
+ // the addon-missing fallback (which writes to stderr but does not
106
+ // exit non-zero — see `loadNative` proxy fallback in native.ts).
107
+ env: { ...process.env },
108
+ });
109
+
110
+ assert.equal(
111
+ result.status,
112
+ 0,
113
+ `compiled CJS output failed to load under ESM parent. ` +
114
+ `stderr: ${result.stderr}\nstdout: ${result.stdout}`,
115
+ );
116
+ assert.match(
117
+ result.stdout,
118
+ /OK/,
119
+ "loader script must reach the final log — any earlier crash is a regression",
120
+ );
121
+ },
122
+ );
91
123
  });
@@ -4,6 +4,7 @@ import { createRequire } from "node:module";
4
4
  import * as path from "node:path";
5
5
  import { fileURLToPath } from "node:url";
6
6
  import { spawn } from "node:child_process";
7
+ import { once } from "node:events";
7
8
 
8
9
  const __dirname = path.dirname(fileURLToPath(import.meta.url));
9
10
  const require = createRequire(import.meta.url);
@@ -62,20 +63,25 @@ describe("native ps: listDescendants()", () => {
62
63
 
63
64
  describe("native ps: killTree()", () => {
64
65
  test("kills a process and its children", async () => {
65
- // Spawn a shell that spawns a sleep subprocess
66
+ // Spawn a shell that spawns a sleep subprocess.
66
67
  const child = spawn("sh", ["-c", "sleep 60"], { stdio: "ignore" });
67
68
 
68
- await new Promise((resolve) => setTimeout(resolve, 100));
69
+ // Wait until the kernel has actually assigned a pid and the process is
70
+ // running. `once(child, 'spawn')` fires after the underlying process
71
+ // has been created, which is the deterministic signal that killTree
72
+ // will find something to kill.
73
+ await once(child, "spawn");
69
74
 
75
+ // Register the exit listener BEFORE killTree: Node EventEmitter does
76
+ // not buffer events, so if the process exits between the kill and the
77
+ // once() call the promise never resolves and the test hangs.
78
+ const exited = once(child, "exit");
70
79
  const killed = native.killTree(child.pid, 9);
71
80
  assert.ok(killed >= 1, `should kill at least 1 process, killed: ${killed}`);
72
81
 
73
- // Verify the child is actually dead
74
- await new Promise((resolve) => {
75
- child.on("exit", resolve);
76
- // Timeout safety — if already exited, resolve immediately
77
- setTimeout(resolve, 500);
78
- });
82
+ // Verify the child is actually dead. `once` waits deterministically
83
+ // for the exit signal rather than a wall-clock timeout.
84
+ await exited;
79
85
  });
80
86
 
81
87
  test("returns 0 for non-existent PID", () => {
@@ -1,8 +1,29 @@
1
1
  import { test, describe } from "node:test";
2
2
  import assert from "node:assert/strict";
3
- import { processStreamChunk } from "../stream-process/index.ts";
3
+ import { createRequire } from "node:module";
4
+ // Import via the compiled package export (matches the convention in
5
+ // xxhash.test.mjs). Importing the raw `.ts` source only worked when Node
6
+ // was invoked with --experimental-strip-types; under the standard test
7
+ // runner it fails with "does not provide an export named X". The npm
8
+ // test script builds the package before running tests, so the compiled
9
+ // export resolves correctly.
10
+ import { processStreamChunk } from "@gsd/native/stream-process";
4
11
 
5
- describe("processStreamChunk", () => {
12
+ // Runtime guard: the `processStreamChunk` native symbol shipped in the
13
+ // source tree is not present in every published `@gsd-build/engine-*`
14
+ // binary. Until the binary is refreshed (tracked in #4854), skip these
15
+ // tests on environments whose native binding lacks the symbol rather
16
+ // than fail CI with a TypeError. This makes the tests behaviour-ready
17
+ // for local devs with a fresh `npm run build:native:dev` while keeping
18
+ // CI green against the published engine.
19
+ const require_ = createRequire(import.meta.url);
20
+ const { native } = require_("../../dist/native.js");
21
+ const skipReason =
22
+ typeof native?.processStreamChunk === "function"
23
+ ? null
24
+ : "native.processStreamChunk missing from @gsd/native binary — see #4854";
25
+
26
+ describe("processStreamChunk", { skip: skipReason ?? undefined }, () => {
6
27
  test("processes a single chunk without state", () => {
7
28
  const result = processStreamChunk(Buffer.from("hello world\n"));
8
29
  assert.equal(result.text, "hello world\n");
@@ -114,12 +114,27 @@ describe("truncateHead", () => {
114
114
 
115
115
  // ── truncateOutput ───────────────────────────────────────────────────────
116
116
 
117
- describe("truncateOutput", () => {
117
+ // `truncateOutput` may be missing from published `@gsd-build/engine-*`
118
+ // binaries (see #4854 — coverage fix surfaced that some symbols weren't
119
+ // in the shipped binary). Skip this suite when the function isn't
120
+ // present rather than failing with a TypeError on every test.
121
+ const truncateOutputSkip =
122
+ typeof native.truncateOutput === "function"
123
+ ? undefined
124
+ : "native.truncateOutput missing from @gsd/native binary — see #4854";
125
+
126
+ describe("truncateOutput", { skip: truncateOutputSkip }, () => {
118
127
  test("no truncation when fits", () => {
119
128
  const r = native.truncateOutput("small", 100);
120
129
  assert.equal(r.truncated, false);
121
130
  assert.equal(r.text, "small");
122
- assert.equal(r.message, null);
131
+ // napi_rs maps `Option::None` → `null` in most versions but some
132
+ // versions elide the field entirely, yielding `undefined`. Accept
133
+ // both until the binary returns a consistent shape (#4854).
134
+ assert.ok(
135
+ r.message === null || r.message === undefined,
136
+ `expected message null/undefined, got ${JSON.stringify(r.message)}`,
137
+ );
123
138
  });
124
139
 
125
140
  test("tail mode (default)", () => {
@@ -3,17 +3,12 @@
3
3
 
4
4
  import { describe, it } from "node:test";
5
5
  import assert from "node:assert/strict";
6
- import { readFileSync } from "node:fs";
7
- import { join, dirname } from "node:path";
8
- import { fileURLToPath } from "node:url";
9
6
  import { Type } from "@sinclair/typebox";
10
7
  import { agentLoop, MAX_CONSECUTIVE_VALIDATION_FAILURES } from "./agent-loop.js";
11
8
  import type { AgentContext, AgentLoopConfig, AgentTool, AgentEvent, AgentMessage } from "./types.js";
12
9
  import { AssistantMessageEventStream, EventStream } from "@gsd/pi-ai";
13
10
  import type { AssistantMessage, AssistantMessageEvent, Model } from "@gsd/pi-ai";
14
11
 
15
- const __dirname = dirname(fileURLToPath(import.meta.url));
16
-
17
12
  describe("agent-loop — pauseTurn handling (#2869)", () => {
18
13
  it("continues to a second assistant turn when stopReason is pauseTurn", async () => {
19
14
  const pauseTurn = makeAssistantMessage({
@@ -75,16 +70,11 @@ describe("agent-loop — pauseTurn handling (#2869)", () => {
75
70
  assert.deepEqual(seenLastRoles, ["user", "assistant"], "second turn must continue from the paused assistant state");
76
71
  });
77
72
 
78
- it("pauseTurn is in the StopReason union type", () => {
79
- // Read the pi-ai types to ensure pauseTurn is a valid StopReason
80
- const typesPath = join(__dirname, "..", "..", "pi-ai", "src", "types.ts");
81
- const typesSource = readFileSync(typesPath, "utf-8");
82
- assert.match(
83
- typesSource,
84
- /["']pauseTurn["']/,
85
- 'StopReason type must include "pauseTurn"',
86
- );
87
- });
73
+ // The behavioural test above ("continues to a second assistant turn ")
74
+ // already exercises `stopReason: "pauseTurn"` at the type level (TS won't
75
+ // compile without the union member) and at runtime (the stream emits it
76
+ // and the loop acts on it). A separate source-text grep added nothing.
77
+ // Deleted per #4797.
88
78
 
89
79
  it("uses provider-supplied external tool results instead of the placeholder", async () => {
90
80
  const externalMessage = makeAssistantMessage({
@@ -1,131 +1,125 @@
1
1
  // Agent activeInferenceModel regression tests
2
- // Verifies that activeInferenceModel is set/cleared correctly in _runLoop,
3
- // and that the footer reads activeInferenceModel instead of state.model.
2
+ // Verifies that activeInferenceModel is set before streaming begins and
3
+ // cleared after streaming completes observed via the streamFn seam and
4
+ // post-condition, not the source text.
4
5
  // Regression test for https://github.com/gsd-build/gsd-2/issues/1844 Bug 2
5
6
 
6
7
  import { describe, it } from "node:test";
7
8
  import assert from "node:assert/strict";
8
- import { readFileSync } from "node:fs";
9
- import { join, dirname } from "node:path";
10
- import { fileURLToPath } from "node:url";
11
9
  import { Agent } from "./agent.ts";
12
10
  import { getModel, type AssistantMessageEventStream } from "@gsd/pi-ai";
13
11
 
14
- const __dirname = dirname(fileURLToPath(import.meta.url));
12
+ function makeDoneStream(modelId: string): AssistantMessageEventStream {
13
+ const usage = {
14
+ input: 0,
15
+ output: 0,
16
+ cacheRead: 0,
17
+ cacheWrite: 0,
18
+ totalTokens: 0,
19
+ cost: { input: 0, output: 0, cacheRead: 0, cacheWrite: 0, total: 0 },
20
+ };
21
+ const message = {
22
+ role: "assistant" as const,
23
+ content: [{ type: "text" as const, text: "ok" }],
24
+ api: "anthropic-messages" as const,
25
+ provider: "anthropic",
26
+ model: modelId,
27
+ usage,
28
+ stopReason: "stop" as const,
29
+ timestamp: Date.now(),
30
+ };
31
+ return {
32
+ async *[Symbol.asyncIterator]() {
33
+ yield { type: "start", partial: message };
34
+ yield { type: "done", message };
35
+ },
36
+ result: async () => message,
37
+ [Symbol.asyncDispose]: async () => {},
38
+ } as AssistantMessageEventStream;
39
+ }
15
40
 
16
41
  describe("Agent — activeInferenceModel (#1844 Bug 2)", () => {
17
- it("activeInferenceModel is declared in AgentState interface", () => {
18
- const typesSource = readFileSync(join(__dirname, "types.ts"), "utf-8");
19
- assert.match(typesSource, /activeInferenceModel\??:\s*Model/,
20
- "AgentState must declare activeInferenceModel field");
21
- });
42
+ it("_runLoop sets activeInferenceModel = model mid-stream and clears it when finished", async () => {
43
+ const model = getModel("anthropic", "claude-3-5-sonnet-20241022");
44
+ let midStreamModel: unknown = "<not-captured>";
22
45
 
23
- it("_runLoop sets activeInferenceModel before streaming and clears in finally", () => {
24
- const agentSource = readFileSync(join(__dirname, "agent.ts"), "utf-8");
46
+ const agent = new Agent({
47
+ initialState: { model, systemPrompt: "test", tools: [] },
48
+ streamFn: (streamModel): AssistantMessageEventStream => {
49
+ // streamFn is invoked AFTER `activeInferenceModel = model` and
50
+ // BEFORE the finally block that clears it. Capture state here.
51
+ midStreamModel = agent.state.activeInferenceModel;
52
+ return makeDoneStream(streamModel.id);
53
+ },
54
+ });
25
55
 
26
- // Must set activeInferenceModel = model before streaming starts
27
- const setLine = agentSource.indexOf("this._state.activeInferenceModel = model");
28
- assert.ok(setLine > -1, "agent.ts must set activeInferenceModel = model in _runLoop");
56
+ // Baseline: undefined before any inference.
57
+ assert.equal(
58
+ agent.state.activeInferenceModel,
59
+ undefined,
60
+ "activeInferenceModel must be undefined before prompt()",
61
+ );
29
62
 
30
- // Must clear activeInferenceModel = undefined after streaming completes
31
- const clearLine = agentSource.indexOf("this._state.activeInferenceModel = undefined");
32
- assert.ok(clearLine > -1, "agent.ts must clear activeInferenceModel in finally block");
63
+ await agent.prompt("hello");
33
64
 
34
- // The set must come before the clear
35
- assert.ok(setLine < clearLine, "activeInferenceModel must be set before cleared");
36
- });
65
+ // Mid-stream: set to the inference model.
66
+ assert.equal(
67
+ (midStreamModel as { id?: string } | undefined)?.id,
68
+ model.id,
69
+ "activeInferenceModel must equal the inference model while streaming",
70
+ );
37
71
 
38
- it("footer displays activeInferenceModel instead of state.model", () => {
39
- const footerPath = join(__dirname, "..", "..", "pi-coding-agent", "src",
40
- "modes", "interactive", "components", "footer.ts");
41
- const footerSource = readFileSync(footerPath, "utf-8");
42
- assert.match(footerSource, /activeInferenceModel/,
43
- "footer.ts must reference activeInferenceModel for display");
72
+ // Post-stream: cleared back to undefined (finally block).
73
+ assert.equal(
74
+ agent.state.activeInferenceModel,
75
+ undefined,
76
+ "activeInferenceModel must be undefined after prompt() resolves",
77
+ );
44
78
  });
45
79
 
46
- it("activeInferenceModel is set before AbortController creation", () => {
47
- const agentSource = readFileSync(join(__dirname, "agent.ts"), "utf-8");
80
+ it("activeInferenceModel is also cleared when the stream throws", async () => {
81
+ const model = getModel("anthropic", "claude-3-5-sonnet-20241022");
82
+ let midStreamModel: unknown = "<not-captured>";
83
+
84
+ const agent = new Agent({
85
+ initialState: { model, systemPrompt: "test", tools: [] },
86
+ streamFn: (): AssistantMessageEventStream => {
87
+ midStreamModel = agent.state.activeInferenceModel;
88
+ return {
89
+ async *[Symbol.asyncIterator]() {
90
+ throw new Error("boom");
91
+ },
92
+ result: async () => {
93
+ throw new Error("boom");
94
+ },
95
+ [Symbol.asyncDispose]: async () => {},
96
+ } as AssistantMessageEventStream;
97
+ },
98
+ });
99
+
100
+ await agent.prompt("hello");
48
101
 
49
- const setLine = agentSource.indexOf("this._state.activeInferenceModel = model");
50
- const abortLine = agentSource.indexOf("this.abortController = new AbortController");
51
- assert.ok(setLine > -1 && abortLine > -1);
52
- assert.ok(setLine < abortLine,
53
- "activeInferenceModel must be set before streaming infrastructure is created");
102
+ assert.equal(
103
+ (midStreamModel as { id?: string } | undefined)?.id,
104
+ model.id,
105
+ "activeInferenceModel must be set even when the stream later throws",
106
+ );
107
+ assert.equal(
108
+ agent.state.activeInferenceModel,
109
+ undefined,
110
+ "activeInferenceModel must be cleared in finally even after stream errors",
111
+ );
54
112
  });
55
113
 
56
114
  it("getProviderOptions are forwarded into the provider stream call", async () => {
57
115
  let capturedOptions: Record<string, unknown> | undefined;
116
+ const model = getModel("anthropic", "claude-3-5-sonnet-20241022");
58
117
  const agent = new Agent({
59
- initialState: {
60
- model: getModel("anthropic", "claude-3-5-sonnet-20241022"),
61
- systemPrompt: "test",
62
- tools: [],
63
- },
118
+ initialState: { model, systemPrompt: "test", tools: [] },
64
119
  getProviderOptions: async () => ({ customRuntimeOption: "present" }),
65
120
  streamFn: (_model, _context, options): AssistantMessageEventStream => {
66
121
  capturedOptions = options as Record<string, unknown> | undefined;
67
- return {
68
- async *[Symbol.asyncIterator]() {
69
- yield {
70
- type: "start",
71
- partial: {
72
- role: "assistant",
73
- content: [],
74
- api: "anthropic-messages",
75
- provider: "anthropic",
76
- model: "claude-3-5-sonnet-20241022",
77
- usage: {
78
- input: 0,
79
- output: 0,
80
- cacheRead: 0,
81
- cacheWrite: 0,
82
- totalTokens: 0,
83
- cost: { input: 0, output: 0, cacheRead: 0, cacheWrite: 0, total: 0 },
84
- },
85
- stopReason: "stop",
86
- timestamp: Date.now(),
87
- },
88
- };
89
- yield {
90
- type: "done",
91
- message: {
92
- role: "assistant",
93
- content: [{ type: "text", text: "ok" }],
94
- api: "anthropic-messages",
95
- provider: "anthropic",
96
- model: "claude-3-5-sonnet-20241022",
97
- usage: {
98
- input: 0,
99
- output: 0,
100
- cacheRead: 0,
101
- cacheWrite: 0,
102
- totalTokens: 0,
103
- cost: { input: 0, output: 0, cacheRead: 0, cacheWrite: 0, total: 0 },
104
- },
105
- stopReason: "stop",
106
- timestamp: Date.now(),
107
- },
108
- };
109
- },
110
- result: async () => ({
111
- role: "assistant",
112
- content: [{ type: "text", text: "ok" }],
113
- api: "anthropic-messages",
114
- provider: "anthropic",
115
- model: "claude-3-5-sonnet-20241022",
116
- usage: {
117
- input: 0,
118
- output: 0,
119
- cacheRead: 0,
120
- cacheWrite: 0,
121
- totalTokens: 0,
122
- cost: { input: 0, output: 0, cacheRead: 0, cacheWrite: 0, total: 0 },
123
- },
124
- stopReason: "stop",
125
- timestamp: Date.now(),
126
- }),
127
- [Symbol.asyncDispose]: async () => {},
128
- } as AssistantMessageEventStream;
122
+ return makeDoneStream(model.id);
129
123
  },
130
124
  });
131
125