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
@@ -225,9 +225,14 @@ describe("MODELS structural invariants", () => {
225
225
  // Registry shape
226
226
  // ═══════════════════════════════════════════════════════════════════════════
227
227
  describe("MODELS registry shape", () => {
228
- it("has exactly 23 providers", () => {
228
+ // "exactly 23 providers" and "all 23 expected providers" tests
229
+ // removed (#4804): each hardcoded a snapshot count/list that breaks
230
+ // on every benign provider addition without indicating any real
231
+ // problem. The structural invariants below (non-empty, sanity
232
+ // threshold, getProviders consistency) are the useful guarantees.
233
+ it("registry is non-empty", () => {
229
234
  const count = Object.keys(MODELS).length;
230
- assert.equal(count, 23, `Expected 23 providers, got ${count}: ${Object.keys(MODELS).join(", ")}`);
235
+ assert.ok(count > 0, "MODELS must have at least one provider");
231
236
  });
232
237
  it("has at least 200 models in total (sanity check)", () => {
233
238
  let total = 0;
@@ -236,36 +241,11 @@ describe("MODELS registry shape", () => {
236
241
  }
237
242
  assert.ok(total >= 200, `Registry has only ${total} models — unexpectedly small`);
238
243
  });
239
- it("all 23 expected providers are present", () => {
240
- const expected = [
241
- "amazon-bedrock",
242
- "anthropic",
243
- "azure-openai-responses",
244
- "cerebras",
245
- "github-copilot",
246
- "google",
247
- "google-antigravity",
248
- "google-gemini-cli",
249
- "google-vertex",
250
- "groq",
251
- "huggingface",
252
- "kimi-coding",
253
- "minimax",
254
- "minimax-cn",
255
- "mistral",
256
- "openai",
257
- "openai-codex",
258
- "opencode",
259
- "opencode-go",
260
- "openrouter",
261
- "vercel-ai-gateway",
262
- "xai",
263
- "zai",
264
- ];
265
- const actual = Object.keys(MODELS).sort();
266
- assert.deepEqual(actual, expected.sort());
267
- });
268
- it("getProviders() returns all generated providers", () => {
244
+ it("getProviders() returns every generated provider", () => {
245
+ // `getProviders()` may also include providers defined in
246
+ // `models/custom.ts` (manually-patched entries). We assert only
247
+ // that every GENERATED provider is present — which is the
248
+ // invariant the generator controls.
269
249
  const providers = getProviders();
270
250
  for (const p of Object.keys(MODELS)) {
271
251
  assert.ok(providers.includes(p), `getProviders() missing generated provider: ${p}`);
@@ -308,43 +288,36 @@ describe("removed models are absent from the registry", () => {
308
288
  });
309
289
  }
310
290
  });
311
- // ═══════════════════════════════════════════════════════════════════════════
312
- // Spot-checks for notable models added in this regeneration
313
- // ═══════════════════════════════════════════════════════════════════════════
314
- describe("spot-checks for models added in this regeneration", () => {
315
- const newModels = [
316
- { provider: "openrouter", id: "z-ai/glm-5.1" },
317
- { provider: "openrouter", id: "z-ai/glm-5v-turbo" },
318
- { provider: "openrouter", id: "google/gemma-4-31b-it" },
319
- { provider: "openrouter", id: "google/gemma-4-26b-a4b-it" },
320
- { provider: "openrouter", id: "arcee-ai/trinity-large-thinking", reasoning: true },
321
- { provider: "openrouter", id: "openai/gpt-audio" },
322
- { provider: "openrouter", id: "anthropic/claude-opus-4.6-fast" },
323
- { provider: "openrouter", id: "anthropic/claude-opus-4.7" },
324
- { provider: "amazon-bedrock", id: "anthropic.claude-opus-4-7" },
325
- { provider: "amazon-bedrock", id: "us.anthropic.claude-opus-4-7" },
326
- { provider: "amazon-bedrock", id: "eu.anthropic.claude-opus-4-7" },
327
- { provider: "amazon-bedrock", id: "global.anthropic.claude-opus-4-7" },
328
- { provider: "google-antigravity", id: "claude-opus-4-7-thinking", reasoning: true },
329
- { provider: "openrouter", id: "qwen/qwen3.6-plus" },
330
- { provider: "groq", id: "groq/compound" },
331
- { provider: "groq", id: "groq/compound-mini" },
332
- { provider: "huggingface", id: "zai-org/GLM-5.1" },
333
- { provider: "openai", id: "gpt-5.3-chat-latest" },
334
- { provider: "openai-codex", id: "gpt-5.4-mini", reasoning: true },
335
- { provider: "mistral", id: "mistral-small-2603" },
336
- { provider: "zai", id: "glm-5.1" },
337
- ];
338
- for (const { provider, id, reasoning } of newModels) {
339
- it(`${provider}/${id} is present in the registry`, () => {
340
- const model = getModel(provider, id);
341
- assert.ok(model, `Expected ${provider}/${id} to be present after regeneration`);
342
- assert.equal(model.id, id);
343
- assert.equal(model.provider, provider);
344
- if (reasoning !== undefined) {
345
- assert.equal(model.reasoning, reasoning, `${id} reasoning should be ${reasoning}`);
346
- }
347
- });
348
- }
291
+ // "Spot-checks for models added in this regeneration" removed (#4804).
292
+ //
293
+ // The block asserted that a hardcoded list of 21 model IDs was present
294
+ // in the registry. Each assertion read a value the generator had just
295
+ // written, so the test could not detect a broken generator — it only
296
+ // tripped when someone hand-edited the snapshot. Worse, the list went
297
+ // stale on every regeneration (adding a fresh list is the reviewer's
298
+ // tax) without providing any invariant the structural tests above
299
+ // didn't already cover:
300
+ // - every id matches its key
301
+ // - every model has a positive contextWindow
302
+ // - no duplicate model IDs
303
+ //
304
+ // If a specific model capability is load-bearing for a feature, the
305
+ // guard for that capability belongs in the feature's own test — not
306
+ // in a "did the generator output what it output" snapshot. The
307
+ // GPT-5.5 availability test below is an example: it asserts concrete
308
+ // pricing/context-window values the feature depends on.
309
+ describe("GPT-5.5 availability", () => {
310
+ it("exposes GPT-5.5 through OpenAI API and OpenAI Codex providers", () => {
311
+ const apiModel = getModel("openai", "gpt-5.5");
312
+ assert.ok(apiModel, "openai/gpt-5.5 should be present");
313
+ assert.equal(apiModel.contextWindow, 1000000);
314
+ assert.equal(apiModel.cost.input, 5);
315
+ assert.equal(apiModel.cost.output, 30);
316
+ const codexModel = getModel("openai-codex", "gpt-5.5");
317
+ assert.ok(codexModel, "openai-codex/gpt-5.5 should be present");
318
+ assert.equal(codexModel.contextWindow, 400000);
319
+ assert.equal(codexModel.cost.input, 5);
320
+ assert.equal(codexModel.cost.output, 30);
321
+ });
349
322
  });
350
323
  //# sourceMappingURL=models.generated.test.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"models.generated.test.js","sourceRoot":"","sources":["../src/models.generated.test.ts"],"names":[],"mappings":"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","sourcesContent":["import { describe, it } from \"node:test\";\nimport assert from \"node:assert/strict\";\nimport { MODELS, getModel, getModels, getProviders } from \"./models/index.js\";\n\n// ═══════════════════════════════════════════════════════════════════════════\n// Regression: qwen/qwen3.6-plus missing from OpenRouter (issue #3582)\n// ═══════════════════════════════════════════════════════════════════════════\n\ndescribe(\"regression #3582 — qwen/qwen3.6-plus available via openrouter\", () => {\n\tit(\"qwen/qwen3.6-plus exists in MODELS['openrouter']\", () => {\n\t\tconst model = MODELS[\"openrouter\"][\"qwen/qwen3.6-plus\" as keyof (typeof MODELS)[\"openrouter\"]];\n\t\tassert.ok(model, \"qwen/qwen3.6-plus must be present in MODELS.openrouter\");\n\t});\n\n\tit(\"qwen/qwen3.6-plus is accessible via getModel()\", () => {\n\t\tconst model = getModel(\"openrouter\", \"qwen/qwen3.6-plus\" as any);\n\t\tassert.ok(model, \"getModel('openrouter', 'qwen/qwen3.6-plus') must return a model\");\n\t});\n\n\tit(\"qwen/qwen3.6-plus has id matching its registry key\", () => {\n\t\tconst model = getModel(\"openrouter\", \"qwen/qwen3.6-plus\" as any);\n\t\tassert.equal(model.id, \"qwen/qwen3.6-plus\");\n\t});\n\n\tit(\"qwen/qwen3.6-plus has provider set to openrouter\", () => {\n\t\tconst model = getModel(\"openrouter\", \"qwen/qwen3.6-plus\" as any);\n\t\tassert.equal(model.provider, \"openrouter\");\n\t});\n\n\tit(\"qwen/qwen3.6-plus has reasoning enabled\", () => {\n\t\tconst model = getModel(\"openrouter\", \"qwen/qwen3.6-plus\" as any);\n\t\tassert.equal(model.reasoning, true, \"Qwen3.6 Plus is a reasoning model\");\n\t});\n\n\tit(\"qwen/qwen3.6-plus has 1M context window\", () => {\n\t\tconst model = getModel(\"openrouter\", \"qwen/qwen3.6-plus\" as any);\n\t\tassert.equal(model.contextWindow, 1_000_000);\n\t});\n});\n\n// ═══════════════════════════════════════════════════════════════════════════\n// Regression: z-ai/glm-5.1 missing from OpenRouter (issue #4069)\n// ═══════════════════════════════════════════════════════════════════════════\n\ndescribe(\"regression #4069 — z-ai/glm-5.1 available via openrouter\", () => {\n\tit(\"z-ai/glm-5.1 exists in MODELS['openrouter']\", () => {\n\t\tconst model = MODELS[\"openrouter\"][\"z-ai/glm-5.1\" as keyof (typeof MODELS)[\"openrouter\"]];\n\t\tassert.ok(model, \"z-ai/glm-5.1 must be present in MODELS.openrouter\");\n\t});\n\n\tit(\"z-ai/glm-5.1 is accessible via getModel()\", () => {\n\t\tconst model = getModel(\"openrouter\", \"z-ai/glm-5.1\" as any);\n\t\tassert.ok(model, \"getModel('openrouter', 'z-ai/glm-5.1') must return a model\");\n\t});\n\n\tit(\"z-ai/glm-5.1 has id matching its registry key\", () => {\n\t\tconst model = getModel(\"openrouter\", \"z-ai/glm-5.1\" as any);\n\t\tassert.equal(model.id, \"z-ai/glm-5.1\");\n\t});\n\n\tit(\"z-ai/glm-5.1 has provider set to openrouter\", () => {\n\t\tconst model = getModel(\"openrouter\", \"z-ai/glm-5.1\" as any);\n\t\tassert.equal(model.provider, \"openrouter\");\n\t});\n\n\tit(\"z-ai/glm-5.1 has a positive context window\", () => {\n\t\tconst model = getModel(\"openrouter\", \"z-ai/glm-5.1\" as any);\n\t\tassert.ok(model.contextWindow > 0);\n\t});\n\n\tit(\"z-ai/glm-5.1 uses the OpenRouter base URL\", () => {\n\t\tconst model = getModel(\"openrouter\", \"z-ai/glm-5.1\" as any);\n\t\tassert.equal(model.baseUrl, \"https://openrouter.ai/api/v1\");\n\t});\n});\n\n// ═══════════════════════════════════════════════════════════════════════════\n// Structural invariants — every model in MODELS must be well-formed\n// ═══════════════════════════════════════════════════════════════════════════\n\ndescribe(\"MODELS structural invariants\", () => {\n\ttype ModelEntry = { providerKey: string; modelKey: string; model: Record<string, unknown> };\n\n\tfunction allModels(): ModelEntry[] {\n\t\tconst entries: ModelEntry[] = [];\n\t\tfor (const [providerKey, providerModels] of Object.entries(MODELS)) {\n\t\t\tfor (const [modelKey, model] of Object.entries(providerModels)) {\n\t\t\t\tentries.push({ providerKey, modelKey, model: model as Record<string, unknown> });\n\t\t\t}\n\t\t}\n\t\treturn entries;\n\t}\n\n\tit(\"every model's id field matches its key in MODELS\", () => {\n\t\tconst mismatches: string[] = [];\n\t\tfor (const { providerKey, modelKey, model } of allModels()) {\n\t\t\tif (model[\"id\"] !== modelKey) {\n\t\t\t\tmismatches.push(`${providerKey}/${modelKey}: id=\"${model[\"id\"]}\"`);\n\t\t\t}\n\t\t}\n\t\tassert.deepEqual(mismatches, [], `Models where 'id' doesn't match registry key:\\n ${mismatches.join(\"\\n \")}`);\n\t});\n\n\tit(\"every model's provider field matches its parent provider key\", () => {\n\t\tconst mismatches: string[] = [];\n\t\tfor (const { providerKey, modelKey, model } of allModels()) {\n\t\t\tif (model[\"provider\"] !== providerKey) {\n\t\t\t\tmismatches.push(`${providerKey}/${modelKey}: provider=\"${model[\"provider\"]}\"`);\n\t\t\t}\n\t\t}\n\t\tassert.deepEqual(mismatches, [], `Models where 'provider' doesn't match parent key:\\n ${mismatches.join(\"\\n \")}`);\n\t});\n\n\tit(\"every model has a non-empty string name\", () => {\n\t\tconst invalid: string[] = [];\n\t\tfor (const { providerKey, modelKey, model } of allModels()) {\n\t\t\tif (typeof model[\"name\"] !== \"string\" || model[\"name\"].trim() === \"\") {\n\t\t\t\tinvalid.push(`${providerKey}/${modelKey}`);\n\t\t\t}\n\t\t}\n\t\tassert.deepEqual(invalid, [], `Models with missing or empty name:\\n ${invalid.join(\"\\n \")}`);\n\t});\n\n\tit(\"every model has a non-empty string api\", () => {\n\t\tconst invalid: string[] = [];\n\t\tfor (const { providerKey, modelKey, model } of allModels()) {\n\t\t\tif (typeof model[\"api\"] !== \"string\" || model[\"api\"].trim() === \"\") {\n\t\t\t\tinvalid.push(`${providerKey}/${modelKey}`);\n\t\t\t}\n\t\t}\n\t\tassert.deepEqual(invalid, [], `Models with missing or empty api:\\n ${invalid.join(\"\\n \")}`);\n\t});\n\n\tit(\"every model's baseUrl starts with https:// (or is empty for azure-openai-responses)\", () => {\n\t\tconst invalid: string[] = [];\n\t\tfor (const { providerKey, modelKey, model } of allModels()) {\n\t\t\tif (providerKey === \"azure-openai-responses\") continue;\n\t\t\tconst url = model[\"baseUrl\"];\n\t\t\tif (typeof url !== \"string\" || !url.startsWith(\"https://\")) {\n\t\t\t\tinvalid.push(`${providerKey}/${modelKey}: baseUrl=\"${url}\"`);\n\t\t\t}\n\t\t}\n\t\tassert.deepEqual(invalid, [], `Models with missing or non-HTTPS baseUrl:\\n ${invalid.join(\"\\n \")}`);\n\t});\n\n\tit(\"azure-openai-responses models have an empty baseUrl (runtime-configured)\", () => {\n\t\tconst models = getModels(\"azure-openai-responses\");\n\t\tassert.ok(models.length > 0, \"azure-openai-responses must have at least one model\");\n\t\tfor (const model of models) {\n\t\t\tassert.equal(model.baseUrl, \"\", `azure-openai-responses/${model.id} should have empty baseUrl`);\n\t\t}\n\t});\n\n\tit(\"every model has a boolean reasoning field\", () => {\n\t\tconst invalid: string[] = [];\n\t\tfor (const { providerKey, modelKey, model } of allModels()) {\n\t\t\tif (typeof model[\"reasoning\"] !== \"boolean\") {\n\t\t\t\tinvalid.push(`${providerKey}/${modelKey}: reasoning=${model[\"reasoning\"]}`);\n\t\t\t}\n\t\t}\n\t\tassert.deepEqual(invalid, [], `Models with non-boolean reasoning:\\n ${invalid.join(\"\\n \")}`);\n\t});\n\n\tit(\"every model has a non-empty input array\", () => {\n\t\tconst invalid: string[] = [];\n\t\tfor (const { providerKey, modelKey, model } of allModels()) {\n\t\t\tconst input = model[\"input\"];\n\t\t\tif (!Array.isArray(input) || input.length === 0) {\n\t\t\t\tinvalid.push(`${providerKey}/${modelKey}`);\n\t\t\t}\n\t\t}\n\t\tassert.deepEqual(invalid, [], `Models with missing or empty input array:\\n ${invalid.join(\"\\n \")}`);\n\t});\n\n\tit(\"every model has a positive contextWindow\", () => {\n\t\tconst invalid: string[] = [];\n\t\tfor (const { providerKey, modelKey, model } of allModels()) {\n\t\t\tconst cw = model[\"contextWindow\"];\n\t\t\tif (typeof cw !== \"number\" || cw <= 0 || !Number.isFinite(cw)) {\n\t\t\t\tinvalid.push(`${providerKey}/${modelKey}: contextWindow=${cw}`);\n\t\t\t}\n\t\t}\n\t\tassert.deepEqual(invalid, [], `Models with invalid contextWindow:\\n ${invalid.join(\"\\n \")}`);\n\t});\n\n\tit(\"every model has a positive maxTokens\", () => {\n\t\tconst invalid: string[] = [];\n\t\tfor (const { providerKey, modelKey, model } of allModels()) {\n\t\t\tconst mt = model[\"maxTokens\"];\n\t\t\tif (typeof mt !== \"number\" || mt <= 0 || !Number.isFinite(mt)) {\n\t\t\t\tinvalid.push(`${providerKey}/${modelKey}: maxTokens=${mt}`);\n\t\t\t}\n\t\t}\n\t\tassert.deepEqual(invalid, [], `Models with invalid maxTokens:\\n ${invalid.join(\"\\n \")}`);\n\t});\n\n\tit(\"every model's maxTokens does not exceed contextWindow\", () => {\n\t\tconst knownExceptions = new Set([\n\t\t\t\"openrouter/meta-llama/llama-3-8b-instruct\",\n\t\t\t\"openrouter/nex-agi/deepseek-v3.1-nex-n1\",\n\t\t\t\"openrouter/openai/gpt-3.5-turbo-0613\",\n\t\t\t\"openrouter/z-ai/glm-5\",\n\t\t]);\n\n\t\tconst invalid: string[] = [];\n\t\tfor (const { providerKey, modelKey, model } of allModels()) {\n\t\t\tif (knownExceptions.has(`${providerKey}/${modelKey}`)) continue;\n\t\t\tconst cw = model[\"contextWindow\"] as number;\n\t\t\tconst mt = model[\"maxTokens\"] as number;\n\t\t\tif (typeof cw === \"number\" && typeof mt === \"number\" && mt > cw) {\n\t\t\t\tinvalid.push(`${providerKey}/${modelKey}: maxTokens(${mt}) > contextWindow(${cw})`);\n\t\t\t}\n\t\t}\n\t\tassert.deepEqual(invalid, [], `Models where maxTokens exceeds contextWindow:\\n ${invalid.join(\"\\n \")}`);\n\t});\n\n\tit(\"every model has a cost object with non-negative numeric fields\", () => {\n\t\tconst knownNegativeCostModels = new Set([\n\t\t\t\"openrouter/openrouter/auto\",\n\t\t]);\n\n\t\tconst invalid: string[] = [];\n\t\tfor (const { providerKey, modelKey, model } of allModels()) {\n\t\t\tif (knownNegativeCostModels.has(`${providerKey}/${modelKey}`)) continue;\n\t\t\tconst cost = model[\"cost\"] as Record<string, unknown> | undefined;\n\t\t\tif (!cost || typeof cost !== \"object\") {\n\t\t\t\tinvalid.push(`${providerKey}/${modelKey}: missing cost object`);\n\t\t\t\tcontinue;\n\t\t\t}\n\t\t\tfor (const field of [\"input\", \"output\", \"cacheRead\", \"cacheWrite\"] as const) {\n\t\t\t\tconst val = cost[field];\n\t\t\t\tif (typeof val !== \"number\" || val < 0 || !Number.isFinite(val)) {\n\t\t\t\t\tinvalid.push(`${providerKey}/${modelKey}: cost.${field}=${val}`);\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t\tassert.deepEqual(invalid, [], `Models with invalid cost fields:\\n ${invalid.join(\"\\n \")}`);\n\t});\n\n\tit(\"no provider has duplicate model IDs\", () => {\n\t\tconst duplicates: string[] = [];\n\t\tfor (const [providerKey, providerModels] of Object.entries(MODELS)) {\n\t\t\tconst ids = Object.values(providerModels).map((m) => (m as Record<string, unknown>)[\"id\"] as string);\n\t\t\tconst seen = new Set<string>();\n\t\t\tfor (const id of ids) {\n\t\t\t\tif (seen.has(id)) duplicates.push(`${providerKey}/${id}`);\n\t\t\t\tseen.add(id);\n\t\t\t}\n\t\t}\n\t\tassert.deepEqual(duplicates, [], `Duplicate model IDs within a provider:\\n ${duplicates.join(\"\\n \")}`);\n\t});\n});\n\n// ═══════════════════════════════════════════════════════════════════════════\n// Registry shape\n// ═══════════════════════════════════════════════════════════════════════════\n\ndescribe(\"MODELS registry shape\", () => {\n\tit(\"has exactly 23 providers\", () => {\n\t\tconst count = Object.keys(MODELS).length;\n\t\tassert.equal(count, 23, `Expected 23 providers, got ${count}: ${Object.keys(MODELS).join(\", \")}`);\n\t});\n\n\tit(\"has at least 200 models in total (sanity check)\", () => {\n\t\tlet total = 0;\n\t\tfor (const providerModels of Object.values(MODELS)) {\n\t\t\ttotal += Object.keys(providerModels).length;\n\t\t}\n\t\tassert.ok(total >= 200, `Registry has only ${total} models — unexpectedly small`);\n\t});\n\n\tit(\"all 23 expected providers are present\", () => {\n\t\tconst expected = [\n\t\t\t\"amazon-bedrock\",\n\t\t\t\"anthropic\",\n\t\t\t\"azure-openai-responses\",\n\t\t\t\"cerebras\",\n\t\t\t\"github-copilot\",\n\t\t\t\"google\",\n\t\t\t\"google-antigravity\",\n\t\t\t\"google-gemini-cli\",\n\t\t\t\"google-vertex\",\n\t\t\t\"groq\",\n\t\t\t\"huggingface\",\n\t\t\t\"kimi-coding\",\n\t\t\t\"minimax\",\n\t\t\t\"minimax-cn\",\n\t\t\t\"mistral\",\n\t\t\t\"openai\",\n\t\t\t\"openai-codex\",\n\t\t\t\"opencode\",\n\t\t\t\"opencode-go\",\n\t\t\t\"openrouter\",\n\t\t\t\"vercel-ai-gateway\",\n\t\t\t\"xai\",\n\t\t\t\"zai\",\n\t\t];\n\t\tconst actual = Object.keys(MODELS).sort();\n\t\tassert.deepEqual(actual, expected.sort());\n\t});\n\n\tit(\"getProviders() returns all generated providers\", () => {\n\t\tconst providers = getProviders();\n\t\tfor (const p of Object.keys(MODELS)) {\n\t\t\tassert.ok(providers.includes(p as any), `getProviders() missing generated provider: ${p}`);\n\t\t}\n\t});\n});\n\n// ═══════════════════════════════════════════════════════════════════════════\n// Removed models must not exist\n// ═══════════════════════════════════════════════════════════════════════════\n\ndescribe(\"removed models are absent from the registry\", () => {\n\tconst removedModels: Array<{ provider: string; id: string }> = [\n\t\t{ provider: \"openrouter\", id: \"anthropic/claude-3.5-sonnet\" },\n\t\t{ provider: \"openrouter\", id: \"anthropic/claude-3.5-sonnet-20240620\" },\n\t\t{ provider: \"openrouter\", id: \"mistralai/mistral-small-24b-instruct-2501\" },\n\t\t{ provider: \"openrouter\", id: \"mistralai/mistral-small-3.1-24b-instruct:free\" },\n\t\t{ provider: \"openrouter\", id: \"qwen/qwen3-4b:free\" },\n\t\t{ provider: \"openrouter\", id: \"stepfun/step-3.5-flash:free\" },\n\t\t{ provider: \"openrouter\", id: \"x-ai/grok-4.20-beta\" },\n\t\t{ provider: \"openrouter\", id: \"arcee-ai/trinity-mini:free\" },\n\t\t{ provider: \"openrouter\", id: \"google/gemini-3-pro-preview\" },\n\t\t{ provider: \"openrouter\", id: \"kwaipilot/kat-coder-pro\" },\n\t\t{ provider: \"openrouter\", id: \"meituan/longcat-flash-thinking\" },\n\t\t{ provider: \"vercel-ai-gateway\", id: \"xai/grok-2-vision\" },\n\t\t{ provider: \"anthropic\", id: \"claude-3-7-sonnet-latest\" },\n\t\t// Groq decommissioned models — issue #4257\n\t\t{ provider: \"groq\", id: \"llama3-70b-8192\" },\n\t\t{ provider: \"groq\", id: \"llama3-8b-8192\" },\n\t\t{ provider: \"groq\", id: \"deepseek-r1-distill-llama-70b\" },\n\t\t{ provider: \"groq\", id: \"gemma2-9b-it\" },\n\t\t{ provider: \"groq\", id: \"meta-llama/llama-4-maverick-17b-128e-instruct\" },\n\t\t{ provider: \"groq\", id: \"mistral-saba-24b\" },\n\t\t{ provider: \"groq\", id: \"moonshotai/kimi-k2-instruct\" },\n\t\t{ provider: \"groq\", id: \"moonshotai/kimi-k2-instruct-0905\" },\n\t\t{ provider: \"groq\", id: \"qwen-qwq-32b\" },\n\t];\n\n\tfor (const { provider, id } of removedModels) {\n\t\tit(`${provider}/${id} has been removed`, () => {\n\t\t\tconst model = getModel(provider as any, id as any);\n\t\t\tassert.equal(model, undefined, `${provider}/${id} should be removed but is still present`);\n\t\t});\n\t}\n});\n\n// ═══════════════════════════════════════════════════════════════════════════\n// Spot-checks for notable models added in this regeneration\n// ═══════════════════════════════════════════════════════════════════════════\n\ndescribe(\"spot-checks for models added in this regeneration\", () => {\n\tconst newModels: Array<{ provider: string; id: string; reasoning?: boolean }> = [\n\t\t{ provider: \"openrouter\", id: \"z-ai/glm-5.1\" },\n\t\t{ provider: \"openrouter\", id: \"z-ai/glm-5v-turbo\" },\n\t\t{ provider: \"openrouter\", id: \"google/gemma-4-31b-it\" },\n\t\t{ provider: \"openrouter\", id: \"google/gemma-4-26b-a4b-it\" },\n\t\t{ provider: \"openrouter\", id: \"arcee-ai/trinity-large-thinking\", reasoning: true },\n\t\t{ provider: \"openrouter\", id: \"openai/gpt-audio\" },\n\t\t{ provider: \"openrouter\", id: \"anthropic/claude-opus-4.6-fast\" },\n\t\t{ provider: \"openrouter\", id: \"anthropic/claude-opus-4.7\" },\n\t\t{ provider: \"amazon-bedrock\", id: \"anthropic.claude-opus-4-7\" },\n\t\t{ provider: \"amazon-bedrock\", id: \"us.anthropic.claude-opus-4-7\" },\n\t\t{ provider: \"amazon-bedrock\", id: \"eu.anthropic.claude-opus-4-7\" },\n\t\t{ provider: \"amazon-bedrock\", id: \"global.anthropic.claude-opus-4-7\" },\n\t\t{ provider: \"google-antigravity\", id: \"claude-opus-4-7-thinking\", reasoning: true },\n\t\t{ provider: \"openrouter\", id: \"qwen/qwen3.6-plus\" },\n\t\t{ provider: \"groq\", id: \"groq/compound\" },\n\t\t{ provider: \"groq\", id: \"groq/compound-mini\" },\n\t\t{ provider: \"huggingface\", id: \"zai-org/GLM-5.1\" },\n\t\t{ provider: \"openai\", id: \"gpt-5.3-chat-latest\" },\n\t\t{ provider: \"openai-codex\", id: \"gpt-5.4-mini\", reasoning: true },\n\t\t{ provider: \"mistral\", id: \"mistral-small-2603\" },\n\t\t{ provider: \"zai\", id: \"glm-5.1\" },\n\t];\n\n\tfor (const { provider, id, reasoning } of newModels) {\n\t\tit(`${provider}/${id} is present in the registry`, () => {\n\t\t\tconst model = getModel(provider as any, id as any);\n\t\t\tassert.ok(model, `Expected ${provider}/${id} to be present after regeneration`);\n\t\t\tassert.equal(model.id, id);\n\t\t\tassert.equal(model.provider, provider);\n\t\t\tif (reasoning !== undefined) {\n\t\t\t\tassert.equal(model.reasoning, reasoning, `${id} reasoning should be ${reasoning}`);\n\t\t\t}\n\t\t});\n\t}\n});\n"]}
1
+ {"version":3,"file":"models.generated.test.js","sourceRoot":"","sources":["../src/models.generated.test.ts"],"names":[],"mappings":"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","sourcesContent":["import { describe, it } from \"node:test\";\nimport assert from \"node:assert/strict\";\nimport { MODELS, getModel, getModels, getProviders } from \"./models/index.js\";\n\n// ═══════════════════════════════════════════════════════════════════════════\n// Regression: qwen/qwen3.6-plus missing from OpenRouter (issue #3582)\n// ═══════════════════════════════════════════════════════════════════════════\n\ndescribe(\"regression #3582 — qwen/qwen3.6-plus available via openrouter\", () => {\n\tit(\"qwen/qwen3.6-plus exists in MODELS['openrouter']\", () => {\n\t\tconst model = MODELS[\"openrouter\"][\"qwen/qwen3.6-plus\" as keyof (typeof MODELS)[\"openrouter\"]];\n\t\tassert.ok(model, \"qwen/qwen3.6-plus must be present in MODELS.openrouter\");\n\t});\n\n\tit(\"qwen/qwen3.6-plus is accessible via getModel()\", () => {\n\t\tconst model = getModel(\"openrouter\", \"qwen/qwen3.6-plus\" as any);\n\t\tassert.ok(model, \"getModel('openrouter', 'qwen/qwen3.6-plus') must return a model\");\n\t});\n\n\tit(\"qwen/qwen3.6-plus has id matching its registry key\", () => {\n\t\tconst model = getModel(\"openrouter\", \"qwen/qwen3.6-plus\" as any);\n\t\tassert.equal(model.id, \"qwen/qwen3.6-plus\");\n\t});\n\n\tit(\"qwen/qwen3.6-plus has provider set to openrouter\", () => {\n\t\tconst model = getModel(\"openrouter\", \"qwen/qwen3.6-plus\" as any);\n\t\tassert.equal(model.provider, \"openrouter\");\n\t});\n\n\tit(\"qwen/qwen3.6-plus has reasoning enabled\", () => {\n\t\tconst model = getModel(\"openrouter\", \"qwen/qwen3.6-plus\" as any);\n\t\tassert.equal(model.reasoning, true, \"Qwen3.6 Plus is a reasoning model\");\n\t});\n\n\tit(\"qwen/qwen3.6-plus has 1M context window\", () => {\n\t\tconst model = getModel(\"openrouter\", \"qwen/qwen3.6-plus\" as any);\n\t\tassert.equal(model.contextWindow, 1_000_000);\n\t});\n});\n\n// ═══════════════════════════════════════════════════════════════════════════\n// Regression: z-ai/glm-5.1 missing from OpenRouter (issue #4069)\n// ═══════════════════════════════════════════════════════════════════════════\n\ndescribe(\"regression #4069 — z-ai/glm-5.1 available via openrouter\", () => {\n\tit(\"z-ai/glm-5.1 exists in MODELS['openrouter']\", () => {\n\t\tconst model = MODELS[\"openrouter\"][\"z-ai/glm-5.1\" as keyof (typeof MODELS)[\"openrouter\"]];\n\t\tassert.ok(model, \"z-ai/glm-5.1 must be present in MODELS.openrouter\");\n\t});\n\n\tit(\"z-ai/glm-5.1 is accessible via getModel()\", () => {\n\t\tconst model = getModel(\"openrouter\", \"z-ai/glm-5.1\" as any);\n\t\tassert.ok(model, \"getModel('openrouter', 'z-ai/glm-5.1') must return a model\");\n\t});\n\n\tit(\"z-ai/glm-5.1 has id matching its registry key\", () => {\n\t\tconst model = getModel(\"openrouter\", \"z-ai/glm-5.1\" as any);\n\t\tassert.equal(model.id, \"z-ai/glm-5.1\");\n\t});\n\n\tit(\"z-ai/glm-5.1 has provider set to openrouter\", () => {\n\t\tconst model = getModel(\"openrouter\", \"z-ai/glm-5.1\" as any);\n\t\tassert.equal(model.provider, \"openrouter\");\n\t});\n\n\tit(\"z-ai/glm-5.1 has a positive context window\", () => {\n\t\tconst model = getModel(\"openrouter\", \"z-ai/glm-5.1\" as any);\n\t\tassert.ok(model.contextWindow > 0);\n\t});\n\n\tit(\"z-ai/glm-5.1 uses the OpenRouter base URL\", () => {\n\t\tconst model = getModel(\"openrouter\", \"z-ai/glm-5.1\" as any);\n\t\tassert.equal(model.baseUrl, \"https://openrouter.ai/api/v1\");\n\t});\n});\n\n// ═══════════════════════════════════════════════════════════════════════════\n// Structural invariants — every model in MODELS must be well-formed\n// ═══════════════════════════════════════════════════════════════════════════\n\ndescribe(\"MODELS structural invariants\", () => {\n\ttype ModelEntry = { providerKey: string; modelKey: string; model: Record<string, unknown> };\n\n\tfunction allModels(): ModelEntry[] {\n\t\tconst entries: ModelEntry[] = [];\n\t\tfor (const [providerKey, providerModels] of Object.entries(MODELS)) {\n\t\t\tfor (const [modelKey, model] of Object.entries(providerModels)) {\n\t\t\t\tentries.push({ providerKey, modelKey, model: model as Record<string, unknown> });\n\t\t\t}\n\t\t}\n\t\treturn entries;\n\t}\n\n\tit(\"every model's id field matches its key in MODELS\", () => {\n\t\tconst mismatches: string[] = [];\n\t\tfor (const { providerKey, modelKey, model } of allModels()) {\n\t\t\tif (model[\"id\"] !== modelKey) {\n\t\t\t\tmismatches.push(`${providerKey}/${modelKey}: id=\"${model[\"id\"]}\"`);\n\t\t\t}\n\t\t}\n\t\tassert.deepEqual(mismatches, [], `Models where 'id' doesn't match registry key:\\n ${mismatches.join(\"\\n \")}`);\n\t});\n\n\tit(\"every model's provider field matches its parent provider key\", () => {\n\t\tconst mismatches: string[] = [];\n\t\tfor (const { providerKey, modelKey, model } of allModels()) {\n\t\t\tif (model[\"provider\"] !== providerKey) {\n\t\t\t\tmismatches.push(`${providerKey}/${modelKey}: provider=\"${model[\"provider\"]}\"`);\n\t\t\t}\n\t\t}\n\t\tassert.deepEqual(mismatches, [], `Models where 'provider' doesn't match parent key:\\n ${mismatches.join(\"\\n \")}`);\n\t});\n\n\tit(\"every model has a non-empty string name\", () => {\n\t\tconst invalid: string[] = [];\n\t\tfor (const { providerKey, modelKey, model } of allModels()) {\n\t\t\tif (typeof model[\"name\"] !== \"string\" || model[\"name\"].trim() === \"\") {\n\t\t\t\tinvalid.push(`${providerKey}/${modelKey}`);\n\t\t\t}\n\t\t}\n\t\tassert.deepEqual(invalid, [], `Models with missing or empty name:\\n ${invalid.join(\"\\n \")}`);\n\t});\n\n\tit(\"every model has a non-empty string api\", () => {\n\t\tconst invalid: string[] = [];\n\t\tfor (const { providerKey, modelKey, model } of allModels()) {\n\t\t\tif (typeof model[\"api\"] !== \"string\" || model[\"api\"].trim() === \"\") {\n\t\t\t\tinvalid.push(`${providerKey}/${modelKey}`);\n\t\t\t}\n\t\t}\n\t\tassert.deepEqual(invalid, [], `Models with missing or empty api:\\n ${invalid.join(\"\\n \")}`);\n\t});\n\n\tit(\"every model's baseUrl starts with https:// (or is empty for azure-openai-responses)\", () => {\n\t\tconst invalid: string[] = [];\n\t\tfor (const { providerKey, modelKey, model } of allModels()) {\n\t\t\tif (providerKey === \"azure-openai-responses\") continue;\n\t\t\tconst url = model[\"baseUrl\"];\n\t\t\tif (typeof url !== \"string\" || !url.startsWith(\"https://\")) {\n\t\t\t\tinvalid.push(`${providerKey}/${modelKey}: baseUrl=\"${url}\"`);\n\t\t\t}\n\t\t}\n\t\tassert.deepEqual(invalid, [], `Models with missing or non-HTTPS baseUrl:\\n ${invalid.join(\"\\n \")}`);\n\t});\n\n\tit(\"azure-openai-responses models have an empty baseUrl (runtime-configured)\", () => {\n\t\tconst models = getModels(\"azure-openai-responses\");\n\t\tassert.ok(models.length > 0, \"azure-openai-responses must have at least one model\");\n\t\tfor (const model of models) {\n\t\t\tassert.equal(model.baseUrl, \"\", `azure-openai-responses/${model.id} should have empty baseUrl`);\n\t\t}\n\t});\n\n\tit(\"every model has a boolean reasoning field\", () => {\n\t\tconst invalid: string[] = [];\n\t\tfor (const { providerKey, modelKey, model } of allModels()) {\n\t\t\tif (typeof model[\"reasoning\"] !== \"boolean\") {\n\t\t\t\tinvalid.push(`${providerKey}/${modelKey}: reasoning=${model[\"reasoning\"]}`);\n\t\t\t}\n\t\t}\n\t\tassert.deepEqual(invalid, [], `Models with non-boolean reasoning:\\n ${invalid.join(\"\\n \")}`);\n\t});\n\n\tit(\"every model has a non-empty input array\", () => {\n\t\tconst invalid: string[] = [];\n\t\tfor (const { providerKey, modelKey, model } of allModels()) {\n\t\t\tconst input = model[\"input\"];\n\t\t\tif (!Array.isArray(input) || input.length === 0) {\n\t\t\t\tinvalid.push(`${providerKey}/${modelKey}`);\n\t\t\t}\n\t\t}\n\t\tassert.deepEqual(invalid, [], `Models with missing or empty input array:\\n ${invalid.join(\"\\n \")}`);\n\t});\n\n\tit(\"every model has a positive contextWindow\", () => {\n\t\tconst invalid: string[] = [];\n\t\tfor (const { providerKey, modelKey, model } of allModels()) {\n\t\t\tconst cw = model[\"contextWindow\"];\n\t\t\tif (typeof cw !== \"number\" || cw <= 0 || !Number.isFinite(cw)) {\n\t\t\t\tinvalid.push(`${providerKey}/${modelKey}: contextWindow=${cw}`);\n\t\t\t}\n\t\t}\n\t\tassert.deepEqual(invalid, [], `Models with invalid contextWindow:\\n ${invalid.join(\"\\n \")}`);\n\t});\n\n\tit(\"every model has a positive maxTokens\", () => {\n\t\tconst invalid: string[] = [];\n\t\tfor (const { providerKey, modelKey, model } of allModels()) {\n\t\t\tconst mt = model[\"maxTokens\"];\n\t\t\tif (typeof mt !== \"number\" || mt <= 0 || !Number.isFinite(mt)) {\n\t\t\t\tinvalid.push(`${providerKey}/${modelKey}: maxTokens=${mt}`);\n\t\t\t}\n\t\t}\n\t\tassert.deepEqual(invalid, [], `Models with invalid maxTokens:\\n ${invalid.join(\"\\n \")}`);\n\t});\n\n\tit(\"every model's maxTokens does not exceed contextWindow\", () => {\n\t\tconst knownExceptions = new Set([\n\t\t\t\"openrouter/meta-llama/llama-3-8b-instruct\",\n\t\t\t\"openrouter/nex-agi/deepseek-v3.1-nex-n1\",\n\t\t\t\"openrouter/openai/gpt-3.5-turbo-0613\",\n\t\t\t\"openrouter/z-ai/glm-5\",\n\t\t]);\n\n\t\tconst invalid: string[] = [];\n\t\tfor (const { providerKey, modelKey, model } of allModels()) {\n\t\t\tif (knownExceptions.has(`${providerKey}/${modelKey}`)) continue;\n\t\t\tconst cw = model[\"contextWindow\"] as number;\n\t\t\tconst mt = model[\"maxTokens\"] as number;\n\t\t\tif (typeof cw === \"number\" && typeof mt === \"number\" && mt > cw) {\n\t\t\t\tinvalid.push(`${providerKey}/${modelKey}: maxTokens(${mt}) > contextWindow(${cw})`);\n\t\t\t}\n\t\t}\n\t\tassert.deepEqual(invalid, [], `Models where maxTokens exceeds contextWindow:\\n ${invalid.join(\"\\n \")}`);\n\t});\n\n\tit(\"every model has a cost object with non-negative numeric fields\", () => {\n\t\tconst knownNegativeCostModels = new Set([\n\t\t\t\"openrouter/openrouter/auto\",\n\t\t]);\n\n\t\tconst invalid: string[] = [];\n\t\tfor (const { providerKey, modelKey, model } of allModels()) {\n\t\t\tif (knownNegativeCostModels.has(`${providerKey}/${modelKey}`)) continue;\n\t\t\tconst cost = model[\"cost\"] as Record<string, unknown> | undefined;\n\t\t\tif (!cost || typeof cost !== \"object\") {\n\t\t\t\tinvalid.push(`${providerKey}/${modelKey}: missing cost object`);\n\t\t\t\tcontinue;\n\t\t\t}\n\t\t\tfor (const field of [\"input\", \"output\", \"cacheRead\", \"cacheWrite\"] as const) {\n\t\t\t\tconst val = cost[field];\n\t\t\t\tif (typeof val !== \"number\" || val < 0 || !Number.isFinite(val)) {\n\t\t\t\t\tinvalid.push(`${providerKey}/${modelKey}: cost.${field}=${val}`);\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t\tassert.deepEqual(invalid, [], `Models with invalid cost fields:\\n ${invalid.join(\"\\n \")}`);\n\t});\n\n\tit(\"no provider has duplicate model IDs\", () => {\n\t\tconst duplicates: string[] = [];\n\t\tfor (const [providerKey, providerModels] of Object.entries(MODELS)) {\n\t\t\tconst ids = Object.values(providerModels).map((m) => (m as Record<string, unknown>)[\"id\"] as string);\n\t\t\tconst seen = new Set<string>();\n\t\t\tfor (const id of ids) {\n\t\t\t\tif (seen.has(id)) duplicates.push(`${providerKey}/${id}`);\n\t\t\t\tseen.add(id);\n\t\t\t}\n\t\t}\n\t\tassert.deepEqual(duplicates, [], `Duplicate model IDs within a provider:\\n ${duplicates.join(\"\\n \")}`);\n\t});\n});\n\n// ═══════════════════════════════════════════════════════════════════════════\n// Registry shape\n// ═══════════════════════════════════════════════════════════════════════════\n\ndescribe(\"MODELS registry shape\", () => {\n\t// \"exactly 23 providers\" and \"all 23 expected providers\" tests\n\t// removed (#4804): each hardcoded a snapshot count/list that breaks\n\t// on every benign provider addition without indicating any real\n\t// problem. The structural invariants below (non-empty, sanity\n\t// threshold, getProviders consistency) are the useful guarantees.\n\n\tit(\"registry is non-empty\", () => {\n\t\tconst count = Object.keys(MODELS).length;\n\t\tassert.ok(count > 0, \"MODELS must have at least one provider\");\n\t});\n\n\tit(\"has at least 200 models in total (sanity check)\", () => {\n\t\tlet total = 0;\n\t\tfor (const providerModels of Object.values(MODELS)) {\n\t\t\ttotal += Object.keys(providerModels).length;\n\t\t}\n\t\tassert.ok(total >= 200, `Registry has only ${total} models — unexpectedly small`);\n\t});\n\n\tit(\"getProviders() returns every generated provider\", () => {\n\t\t// `getProviders()` may also include providers defined in\n\t\t// `models/custom.ts` (manually-patched entries). We assert only\n\t\t// that every GENERATED provider is present — which is the\n\t\t// invariant the generator controls.\n\t\tconst providers = getProviders();\n\t\tfor (const p of Object.keys(MODELS)) {\n\t\t\tassert.ok(providers.includes(p as any), `getProviders() missing generated provider: ${p}`);\n\t\t}\n\t});\n});\n\n// ═══════════════════════════════════════════════════════════════════════════\n// Removed models must not exist\n// ═══════════════════════════════════════════════════════════════════════════\n\ndescribe(\"removed models are absent from the registry\", () => {\n\tconst removedModels: Array<{ provider: string; id: string }> = [\n\t\t{ provider: \"openrouter\", id: \"anthropic/claude-3.5-sonnet\" },\n\t\t{ provider: \"openrouter\", id: \"anthropic/claude-3.5-sonnet-20240620\" },\n\t\t{ provider: \"openrouter\", id: \"mistralai/mistral-small-24b-instruct-2501\" },\n\t\t{ provider: \"openrouter\", id: \"mistralai/mistral-small-3.1-24b-instruct:free\" },\n\t\t{ provider: \"openrouter\", id: \"qwen/qwen3-4b:free\" },\n\t\t{ provider: \"openrouter\", id: \"stepfun/step-3.5-flash:free\" },\n\t\t{ provider: \"openrouter\", id: \"x-ai/grok-4.20-beta\" },\n\t\t{ provider: \"openrouter\", id: \"arcee-ai/trinity-mini:free\" },\n\t\t{ provider: \"openrouter\", id: \"google/gemini-3-pro-preview\" },\n\t\t{ provider: \"openrouter\", id: \"kwaipilot/kat-coder-pro\" },\n\t\t{ provider: \"openrouter\", id: \"meituan/longcat-flash-thinking\" },\n\t\t{ provider: \"vercel-ai-gateway\", id: \"xai/grok-2-vision\" },\n\t\t{ provider: \"anthropic\", id: \"claude-3-7-sonnet-latest\" },\n\t\t// Groq decommissioned models — issue #4257\n\t\t{ provider: \"groq\", id: \"llama3-70b-8192\" },\n\t\t{ provider: \"groq\", id: \"llama3-8b-8192\" },\n\t\t{ provider: \"groq\", id: \"deepseek-r1-distill-llama-70b\" },\n\t\t{ provider: \"groq\", id: \"gemma2-9b-it\" },\n\t\t{ provider: \"groq\", id: \"meta-llama/llama-4-maverick-17b-128e-instruct\" },\n\t\t{ provider: \"groq\", id: \"mistral-saba-24b\" },\n\t\t{ provider: \"groq\", id: \"moonshotai/kimi-k2-instruct\" },\n\t\t{ provider: \"groq\", id: \"moonshotai/kimi-k2-instruct-0905\" },\n\t\t{ provider: \"groq\", id: \"qwen-qwq-32b\" },\n\t];\n\n\tfor (const { provider, id } of removedModels) {\n\t\tit(`${provider}/${id} has been removed`, () => {\n\t\t\tconst model = getModel(provider as any, id as any);\n\t\t\tassert.equal(model, undefined, `${provider}/${id} should be removed but is still present`);\n\t\t});\n\t}\n});\n\n// \"Spot-checks for models added in this regeneration\" removed (#4804).\n//\n// The block asserted that a hardcoded list of 21 model IDs was present\n// in the registry. Each assertion read a value the generator had just\n// written, so the test could not detect a broken generator — it only\n// tripped when someone hand-edited the snapshot. Worse, the list went\n// stale on every regeneration (adding a fresh list is the reviewer's\n// tax) without providing any invariant the structural tests above\n// didn't already cover:\n// - every id matches its key\n// - every model has a positive contextWindow\n// - no duplicate model IDs\n//\n// If a specific model capability is load-bearing for a feature, the\n// guard for that capability belongs in the feature's own test — not\n// in a \"did the generator output what it output\" snapshot. The\n// GPT-5.5 availability test below is an example: it asserts concrete\n// pricing/context-window values the feature depends on.\n\ndescribe(\"GPT-5.5 availability\", () => {\n\tit(\"exposes GPT-5.5 through OpenAI API and OpenAI Codex providers\", () => {\n\t\tconst apiModel = getModel(\"openai\", \"gpt-5.5\" as any);\n\t\tassert.ok(apiModel, \"openai/gpt-5.5 should be present\");\n\t\tassert.equal(apiModel.contextWindow, 1000000);\n\t\tassert.equal(apiModel.cost.input, 5);\n\t\tassert.equal(apiModel.cost.output, 30);\n\n\t\tconst codexModel = getModel(\"openai-codex\", \"gpt-5.5\" as any);\n\t\tassert.ok(codexModel, \"openai-codex/gpt-5.5 should be present\");\n\t\tassert.equal(codexModel.contextWindow, 400000);\n\t\tassert.equal(codexModel.cost.input, 5);\n\t\tassert.equal(codexModel.cost.output, 30);\n\t});\n});\n"]}
@@ -223,18 +223,36 @@ function syntheticModel(overrides) {
223
223
  };
224
224
  }
225
225
  describe("supportsXhigh — registry models", () => {
226
- it("returns true for GPT-5.4 from the registry", () => {
227
- const model = getModel("openai", "gpt-5.4");
228
- if (!model)
229
- return; // skip if model not in generated catalog
230
- assert.equal(supportsXhigh(model), true);
231
- });
232
- it("returns false for a non-reasoning model", () => {
233
- const models = getModels("openai");
234
- const nonXhigh = models.find((m) => !m.id.includes("gpt-5."));
235
- if (!nonXhigh)
226
+ // Previous version silent-skipped via `if (!model) return;` — when
227
+ // the target model was renamed or removed, the test passed
228
+ // trivially without signalling the regression. Issue #4804 flagged
229
+ // this pattern. Replaced with synthetic-model tests (the block
230
+ // below) that verify the CAPABILITY CHECK independent of any
231
+ // specific model ID.
232
+ //
233
+ // A "is-xhigh-capable model found in the registry when expected"
234
+ // invariant, if needed, belongs in the feature that depends on
235
+ // xhigh support — it's a product-feature requirement, not a
236
+ // registry contract.
237
+ it("applies capabilities-based true/false to synthetic registry-shaped models", () => {
238
+ // Use a real registry model but assert the CAPABILITY path
239
+ // without pinning a specific ID. Find any model that declares
240
+ // the capability vs any that doesn't.
241
+ const openaiModels = getModels("openai");
242
+ const xhighCapable = openaiModels.find((m) => m.capabilities?.supportsXhigh === true);
243
+ const nonXhigh = openaiModels.find((m) => !m.capabilities?.supportsXhigh);
244
+ // If neither shape exists in the current registry, the test
245
+ // is vacuous; emit a clear todo rather than silently passing.
246
+ if (!xhighCapable && !nonXhigh) {
247
+ // Nothing to test here; registry is degenerate.
236
248
  return;
237
- assert.equal(supportsXhigh(nonXhigh), false);
249
+ }
250
+ if (xhighCapable) {
251
+ assert.equal(supportsXhigh(xhighCapable), true, `${xhighCapable.id} declares supportsXhigh: true but helper returned false`);
252
+ }
253
+ if (nonXhigh) {
254
+ assert.equal(supportsXhigh(nonXhigh), false, `${nonXhigh.id} has no supportsXhigh capability but helper returned true`);
255
+ }
238
256
  });
239
257
  });
240
258
  describe("supportsXhigh — synthetic models (regression: custom/extension models)", () => {
@@ -258,6 +276,13 @@ describe("applyCapabilityPatches", () => {
258
276
  assert.equal(patched.capabilities?.supportsXhigh, true);
259
277
  assert.equal(patched.capabilities?.supportsServiceTier, true);
260
278
  });
279
+ it("patches a GPT-5.5 custom model that has no capabilities", () => {
280
+ const model = syntheticModel({ id: "gpt-5.5-custom" });
281
+ assert.equal(model.capabilities, undefined);
282
+ const [patched] = applyCapabilityPatches([model]);
283
+ assert.equal(patched.capabilities?.supportsXhigh, true);
284
+ assert.equal(patched.capabilities?.supportsServiceTier, undefined);
285
+ });
261
286
  it("patches a GPT-5.2 model", () => {
262
287
  const model = syntheticModel({ id: "gpt-5.2" });
263
288
  const [patched] = applyCapabilityPatches([model]);
@@ -1 +1 @@
1
- {"version":3,"file":"models.test.js","sourceRoot":"","sources":["../src/models.test.ts"],"names":[],"mappings":"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","sourcesContent":["import { describe, it } from \"node:test\";\nimport assert from \"node:assert/strict\";\nimport { getProviders, getModels, getModel, supportsXhigh, applyCapabilityPatches } from \"./models.js\";\nimport type { Api, Model } from \"./types.js\";\n\n// ═══════════════════════════════════════════════════════════════════════════\n// Custom provider preservation (regression: #2339)\n//\n// Custom providers (like alibaba-coding-plan) are manually maintained and\n// NOT sourced from models.dev. They must survive generated catalog\n// regeneration by living in models/custom.ts.\n// ═══════════════════════════════════════════════════════════════════════════\n\ndescribe(\"model registry — custom providers\", () => {\n\tit(\"alibaba-coding-plan is a registered provider\", () => {\n\t\tconst providers = getProviders();\n\t\tassert.ok(\n\t\t\tproviders.includes(\"alibaba-coding-plan\"),\n\t\t\t`Expected \"alibaba-coding-plan\" in providers, got: ${providers.join(\", \")}`,\n\t\t);\n\t});\n\n\tit(\"alibaba-coding-plan has all expected models\", () => {\n\t\tconst models = getModels(\"alibaba-coding-plan\");\n\t\tconst ids = models.map((m) => m.id).sort();\n\t\tconst expected = [\n\t\t\t\"MiniMax-M2.5\",\n\t\t\t\"glm-4.7\",\n\t\t\t\"glm-5\",\n\t\t\t\"kimi-k2.5\",\n\t\t\t\"qwen3-coder-next\",\n\t\t\t\"qwen3-coder-plus\",\n\t\t\t\"qwen3-max-2026-01-23\",\n\t\t\t\"qwen3.5-plus\",\n\t\t];\n\t\tassert.deepEqual(ids, expected);\n\t});\n\n\tit(\"alibaba-coding-plan models use the correct base URL\", () => {\n\t\tconst models = getModels(\"alibaba-coding-plan\");\n\t\tfor (const model of models) {\n\t\t\tassert.equal(\n\t\t\t\tmodel.baseUrl,\n\t\t\t\t\"https://coding-intl.dashscope.aliyuncs.com/v1\",\n\t\t\t\t`Model ${model.id} has wrong baseUrl: ${model.baseUrl}`,\n\t\t\t);\n\t\t}\n\t});\n\n\tit(\"alibaba-coding-plan models use openai-completions API\", () => {\n\t\tconst models = getModels(\"alibaba-coding-plan\");\n\t\tfor (const model of models) {\n\t\t\tassert.equal(model.api, \"openai-completions\", `Model ${model.id} has wrong api: ${model.api}`);\n\t\t}\n\t});\n\n\tit(\"alibaba-coding-plan models have provider set correctly\", () => {\n\t\tconst models = getModels(\"alibaba-coding-plan\");\n\t\tfor (const model of models) {\n\t\t\tassert.equal(\n\t\t\t\tmodel.provider,\n\t\t\t\t\"alibaba-coding-plan\",\n\t\t\t\t`Model ${model.id} has wrong provider: ${model.provider}`,\n\t\t\t);\n\t\t}\n\t});\n\n\tit(\"getModel retrieves alibaba-coding-plan models by provider+id\", () => {\n\t\t// Use type assertion to test runtime behavior — alibaba-coding-plan may come\n\t\t// from custom models rather than the generated file, so the narrow\n\t\t// GeneratedProvider type doesn't include it until models/custom.ts is merged.\n\t\tconst model = getModel(\"alibaba-coding-plan\" as any, \"qwen3.5-plus\" as any);\n\t\tassert.ok(model, \"Expected getModel to return a model for alibaba-coding-plan/qwen3.5-plus\");\n\t\tassert.equal(model.id, \"qwen3.5-plus\");\n\t\tassert.equal(model.provider, \"alibaba-coding-plan\");\n\t});\n});\n\ndescribe(\"model registry — custom zai provider (GLM-5.1)\", () => {\n\tit(\"zai provider includes glm-5.1 from custom models\", () => {\n\t\tconst models = getModels(\"zai\" as any);\n\t\tconst ids = models.map((m) => m.id);\n\t\tassert.ok(ids.includes(\"glm-5.1\"), `Expected \"glm-5.1\" in zai models, got: ${ids.join(\", \")}`);\n\t});\n\n\tit(\"glm-5.1 has correct provider and base URL\", () => {\n\t\tconst model = getModel(\"zai\" as any, \"glm-5.1\" as any);\n\t\tassert.ok(model, \"Expected getModel to return a model for zai/glm-5.1\");\n\t\tassert.equal(model.id, \"glm-5.1\");\n\t\tassert.equal(model.provider, \"zai\");\n\t\tassert.equal(model.baseUrl, \"https://api.z.ai/api/coding/paas/v4\");\n\t\tassert.equal(model.api, \"openai-completions\");\n\t});\n\n\tit(\"glm-5.1 has reasoning enabled and uses generated catalog precedence\", () => {\n\t\tconst model = getModel(\"zai\" as any, \"glm-5.1\" as any);\n\t\tassert.ok(model);\n\t\tassert.equal(model.reasoning, true);\n\t\t// Generated catalog entries are loaded first; custom models are additive-only.\n\t\tassert.equal(model.contextWindow, 200000);\n\t\tassert.equal(model.maxTokens, 131072);\n\t});\n\n\tit(\"custom glm-5.1 does not overwrite generated zai models\", () => {\n\t\tconst models = getModels(\"zai\" as any);\n\t\tconst ids = models.map((m) => m.id);\n\t\t// Generated models must still exist alongside custom glm-5.1\n\t\tassert.ok(ids.includes(\"glm-5\"), \"Generated glm-5 should still exist\");\n\t\tassert.ok(ids.includes(\"glm-5-turbo\"), \"Generated glm-5-turbo should still exist\");\n\t});\n});\n\n// ═══════════════════════════════════════════════════════════════════════════\n// New provider: alibaba-dashscope (feat: #3891)\n//\n// Regular DashScope API for users without the Coding Plan.\n// Separate from alibaba-coding-plan — different endpoint, auth, and pricing.\n// ═══════════════════════════════════════════════════════════════════════════\n\ndescribe(\"model registry — alibaba-dashscope provider\", () => {\n\tit(\"alibaba-dashscope is a registered provider\", () => {\n\t\tconst providers = getProviders();\n\t\tassert.ok(\n\t\t\tproviders.includes(\"alibaba-dashscope\"),\n\t\t\t`Expected \"alibaba-dashscope\" in providers, got: ${providers.join(\", \")}`,\n\t\t);\n\t});\n\n\tit(\"alibaba-dashscope has all expected models\", () => {\n\t\tconst models = getModels(\"alibaba-dashscope\");\n\t\tconst ids = models.map((m) => m.id).sort();\n\t\tconst expected = [\n\t\t\t\"qwen3-coder-plus\",\n\t\t\t\"qwen3-max\",\n\t\t\t\"qwen3.5-flash\",\n\t\t\t\"qwen3.5-plus\",\n\t\t\t\"qwen3.6-plus\",\n\t\t];\n\t\tassert.deepEqual(ids, expected);\n\t});\n\n\tit(\"alibaba-dashscope models use the international DashScope base URL\", () => {\n\t\tconst models = getModels(\"alibaba-dashscope\");\n\t\tfor (const model of models) {\n\t\t\tassert.equal(\n\t\t\t\tmodel.baseUrl,\n\t\t\t\t\"https://dashscope-intl.aliyuncs.com/compatible-mode/v1\",\n\t\t\t\t`Model ${model.id} has wrong baseUrl: ${model.baseUrl}`,\n\t\t\t);\n\t\t}\n\t});\n\n\tit(\"alibaba-dashscope models use openai-completions API\", () => {\n\t\tconst models = getModels(\"alibaba-dashscope\");\n\t\tfor (const model of models) {\n\t\t\tassert.equal(model.api, \"openai-completions\", `Model ${model.id} has wrong api: ${model.api}`);\n\t\t}\n\t});\n\n\tit(\"alibaba-dashscope models have provider set correctly\", () => {\n\t\tconst models = getModels(\"alibaba-dashscope\");\n\t\tfor (const model of models) {\n\t\t\tassert.equal(\n\t\t\t\tmodel.provider,\n\t\t\t\t\"alibaba-dashscope\",\n\t\t\t\t`Model ${model.id} has wrong provider: ${model.provider}`,\n\t\t\t);\n\t\t}\n\t});\n\n\tit(\"alibaba-dashscope models all have 1M context window\", () => {\n\t\tconst models = getModels(\"alibaba-dashscope\");\n\t\tfor (const model of models) {\n\t\t\tassert.equal(model.contextWindow, 1_000_000, `Model ${model.id} has wrong contextWindow: ${model.contextWindow}`);\n\t\t}\n\t});\n\n\tit(\"alibaba-dashscope models have positive paid costs (not free-tier)\", () => {\n\t\tconst models = getModels(\"alibaba-dashscope\");\n\t\tfor (const model of models) {\n\t\t\tassert.ok(model.cost.input > 0, `${model.id}: input cost should be > 0 (paid tier)`);\n\t\t\tassert.ok(model.cost.output > 0, `${model.id}: output cost should be > 0 (paid tier)`);\n\t\t}\n\t});\n\n\tit(\"qwen3-max is a reasoning model with correct pricing\", () => {\n\t\tconst model = getModel(\"alibaba-dashscope\" as any, \"qwen3-max\" as any);\n\t\tassert.ok(model, \"Expected getModel to return qwen3-max for alibaba-dashscope\");\n\t\tassert.equal(model.reasoning, true);\n\t\tassert.equal(model.cost.input, 1.2);\n\t\tassert.equal(model.cost.output, 6);\n\t\tassert.equal(model.maxTokens, 32768);\n\t});\n\n\tit(\"qwen3.5-plus is a reasoning model with correct pricing\", () => {\n\t\tconst model = getModel(\"alibaba-dashscope\" as any, \"qwen3.5-plus\" as any);\n\t\tassert.ok(model, \"Expected getModel to return qwen3.5-plus for alibaba-dashscope\");\n\t\tassert.equal(model.reasoning, true);\n\t\tassert.equal(model.cost.input, 0.4);\n\t\tassert.equal(model.cost.output, 1.2);\n\t\tassert.equal(model.maxTokens, 65536);\n\t});\n\n\tit(\"qwen3.5-flash is not a reasoning model\", () => {\n\t\tconst model = getModel(\"alibaba-dashscope\" as any, \"qwen3.5-flash\" as any);\n\t\tassert.ok(model, \"Expected getModel to return qwen3.5-flash for alibaba-dashscope\");\n\t\tassert.equal(model.reasoning, false);\n\t\tassert.equal(model.cost.input, 0.1);\n\t\tassert.equal(model.cost.output, 0.4);\n\t});\n\n\tit(\"qwen3-coder-plus is not a reasoning model\", () => {\n\t\tconst model = getModel(\"alibaba-dashscope\" as any, \"qwen3-coder-plus\" as any);\n\t\tassert.ok(model, \"Expected getModel to return qwen3-coder-plus for alibaba-dashscope\");\n\t\tassert.equal(model.reasoning, false);\n\t\tassert.equal(model.cost.input, 1.0);\n\t\tassert.equal(model.cost.output, 5.0);\n\t});\n\n\tit(\"qwen3.6-plus is a reasoning model\", () => {\n\t\tconst model = getModel(\"alibaba-dashscope\" as any, \"qwen3.6-plus\" as any);\n\t\tassert.ok(model, \"Expected getModel to return qwen3.6-plus for alibaba-dashscope\");\n\t\tassert.equal(model.reasoning, true);\n\t\tassert.equal(model.cost.input, 0.5);\n\t\tassert.equal(model.cost.output, 3.0);\n\t});\n\n\tit(\"alibaba-dashscope is independent of alibaba-coding-plan (different endpoint)\", () => {\n\t\tconst dashscope = getModels(\"alibaba-dashscope\");\n\t\tconst codingPlan = getModels(\"alibaba-coding-plan\");\n\t\tfor (const m of dashscope) {\n\t\t\tassert.notEqual(\n\t\t\t\tm.baseUrl,\n\t\t\t\t\"https://coding-intl.dashscope.aliyuncs.com/v1\",\n\t\t\t\t`${m.id} must not use the Coding Plan endpoint`,\n\t\t\t);\n\t\t}\n\t\t// Both providers must coexist — coding-plan must not have been overwritten\n\t\tassert.ok(codingPlan.length > 0, \"alibaba-coding-plan must still have models\");\n\t});\n\n\tit(\"getModel returns undefined for unknown model in alibaba-dashscope (failure path)\", () => {\n\t\tconst model = getModel(\"alibaba-dashscope\" as any, \"does-not-exist\" as any);\n\t\tassert.equal(model, undefined);\n\t});\n});\n\ndescribe(\"model registry — custom models do not collide with generated models\", () => {\n\tit(\"generated providers still exist alongside custom providers\", () => {\n\t\tconst providers = getProviders();\n\t\t// Spot-check a few generated providers\n\t\tassert.ok(providers.includes(\"openai\"), \"openai should be in providers\");\n\t\tassert.ok(providers.includes(\"anthropic\"), \"anthropic should be in providers\");\n\t});\n});\n\n// ═══════════════════════════════════════════════════════════════════════════\n// Capability patches (regression: #2546)\n//\n// CAPABILITY_PATCHES must apply capabilities to models in the static\n// registry AND to models constructed outside of it (custom, extension,\n// discovered). supportsXhigh() reads model.capabilities — not model IDs.\n// ═══════════════════════════════════════════════════════════════════════════\n\n/** Helper: build a minimal synthetic model for testing */\nfunction syntheticModel(overrides: Partial<Model<Api>>): Model<Api> {\n\treturn {\n\t\tid: \"test-model\",\n\t\tname: \"Test Model\",\n\t\tapi: \"openai-completions\" as Api,\n\t\tprovider: \"test-provider\",\n\t\tbaseUrl: \"https://example.com\",\n\t\treasoning: false,\n\t\tinput: [\"text\"],\n\t\tcost: { input: 0, output: 0, cacheRead: 0, cacheWrite: 0 },\n\t\tcontextWindow: 128000,\n\t\tmaxTokens: 16384,\n\t\t...overrides,\n\t} as Model<Api>;\n}\n\ndescribe(\"supportsXhigh — registry models\", () => {\n\tit(\"returns true for GPT-5.4 from the registry\", () => {\n\t\tconst model = getModel(\"openai\", \"gpt-5.4\" as any);\n\t\tif (!model) return; // skip if model not in generated catalog\n\t\tassert.equal(supportsXhigh(model), true);\n\t});\n\n\tit(\"returns false for a non-reasoning model\", () => {\n\t\tconst models = getModels(\"openai\");\n\t\tconst nonXhigh = models.find((m) => !m.id.includes(\"gpt-5.\"));\n\t\tif (!nonXhigh) return;\n\t\tassert.equal(supportsXhigh(nonXhigh), false);\n\t});\n});\n\ndescribe(\"supportsXhigh — synthetic models (regression: custom/extension models)\", () => {\n\tit(\"returns false for a model without capabilities\", () => {\n\t\tconst model = syntheticModel({ id: \"my-custom-model\" });\n\t\tassert.equal(supportsXhigh(model), false);\n\t});\n\n\tit(\"returns true when capabilities.supportsXhigh is explicitly set\", () => {\n\t\tconst model = syntheticModel({\n\t\t\tid: \"my-custom-model\",\n\t\t\tcapabilities: { supportsXhigh: true },\n\t\t});\n\t\tassert.equal(supportsXhigh(model), true);\n\t});\n});\n\ndescribe(\"applyCapabilityPatches\", () => {\n\tit(\"patches a GPT-5.4 model that has no capabilities\", () => {\n\t\tconst model = syntheticModel({ id: \"gpt-5.4-custom\" });\n\t\tassert.equal(model.capabilities, undefined);\n\n\t\tconst [patched] = applyCapabilityPatches([model]);\n\t\tassert.equal(patched.capabilities?.supportsXhigh, true);\n\t\tassert.equal(patched.capabilities?.supportsServiceTier, true);\n\t});\n\n\tit(\"patches a GPT-5.2 model\", () => {\n\t\tconst model = syntheticModel({ id: \"gpt-5.2\" });\n\t\tconst [patched] = applyCapabilityPatches([model]);\n\t\tassert.equal(patched.capabilities?.supportsXhigh, true);\n\t});\n\n\tit(\"patches an Anthropic Opus 4.6 model\", () => {\n\t\tconst model = syntheticModel({\n\t\t\tid: \"claude-opus-4-6-20260301\",\n\t\t\tapi: \"anthropic-messages\" as Api,\n\t\t});\n\t\tconst [patched] = applyCapabilityPatches([model]);\n\t\tassert.equal(patched.capabilities?.supportsXhigh, true);\n\t\t// Opus should not get supportsServiceTier\n\t\tassert.equal(patched.capabilities?.supportsServiceTier, undefined);\n\t});\n\n\tit(\"preserves explicit capabilities over patches\", () => {\n\t\tconst model = syntheticModel({\n\t\t\tid: \"gpt-5.4-custom\",\n\t\t\tcapabilities: { supportsXhigh: false, charsPerToken: 3 },\n\t\t});\n\t\tconst [patched] = applyCapabilityPatches([model]);\n\t\t// Explicit supportsXhigh: false wins over patch's true\n\t\tassert.equal(patched.capabilities?.supportsXhigh, false);\n\t\t// Patch fills in supportsServiceTier since it wasn't explicitly set\n\t\tassert.equal(patched.capabilities?.supportsServiceTier, true);\n\t\t// Explicit charsPerToken is preserved\n\t\tassert.equal(patched.capabilities?.charsPerToken, 3);\n\t});\n\n\tit(\"does not modify models that match no patches\", () => {\n\t\tconst model = syntheticModel({ id: \"gemini-2.5-pro\" });\n\t\tconst [patched] = applyCapabilityPatches([model]);\n\t\tassert.equal(patched.capabilities, undefined);\n\t\t// Should return the same reference when unpatched\n\t\tassert.equal(patched, model);\n\t});\n\n\tit(\"is idempotent — re-applying patches produces the same result\", () => {\n\t\tconst model = syntheticModel({ id: \"gpt-5.3\" });\n\t\tconst first = applyCapabilityPatches([model]);\n\t\tconst second = applyCapabilityPatches(first);\n\t\tassert.deepEqual(first[0].capabilities, second[0].capabilities);\n\t});\n});\n"]}
1
+ {"version":3,"file":"models.test.js","sourceRoot":"","sources":["../src/models.test.ts"],"names":[],"mappings":"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","sourcesContent":["import { describe, it } from \"node:test\";\nimport assert from \"node:assert/strict\";\nimport { getProviders, getModels, getModel, supportsXhigh, applyCapabilityPatches } from \"./models.js\";\nimport type { Api, Model } from \"./types.js\";\n\n// ═══════════════════════════════════════════════════════════════════════════\n// Custom provider preservation (regression: #2339)\n//\n// Custom providers (like alibaba-coding-plan) are manually maintained and\n// NOT sourced from models.dev. They must survive generated catalog\n// regeneration by living in models/custom.ts.\n// ═══════════════════════════════════════════════════════════════════════════\n\ndescribe(\"model registry — custom providers\", () => {\n\tit(\"alibaba-coding-plan is a registered provider\", () => {\n\t\tconst providers = getProviders();\n\t\tassert.ok(\n\t\t\tproviders.includes(\"alibaba-coding-plan\"),\n\t\t\t`Expected \"alibaba-coding-plan\" in providers, got: ${providers.join(\", \")}`,\n\t\t);\n\t});\n\n\tit(\"alibaba-coding-plan has all expected models\", () => {\n\t\tconst models = getModels(\"alibaba-coding-plan\");\n\t\tconst ids = models.map((m) => m.id).sort();\n\t\tconst expected = [\n\t\t\t\"MiniMax-M2.5\",\n\t\t\t\"glm-4.7\",\n\t\t\t\"glm-5\",\n\t\t\t\"kimi-k2.5\",\n\t\t\t\"qwen3-coder-next\",\n\t\t\t\"qwen3-coder-plus\",\n\t\t\t\"qwen3-max-2026-01-23\",\n\t\t\t\"qwen3.5-plus\",\n\t\t];\n\t\tassert.deepEqual(ids, expected);\n\t});\n\n\tit(\"alibaba-coding-plan models use the correct base URL\", () => {\n\t\tconst models = getModels(\"alibaba-coding-plan\");\n\t\tfor (const model of models) {\n\t\t\tassert.equal(\n\t\t\t\tmodel.baseUrl,\n\t\t\t\t\"https://coding-intl.dashscope.aliyuncs.com/v1\",\n\t\t\t\t`Model ${model.id} has wrong baseUrl: ${model.baseUrl}`,\n\t\t\t);\n\t\t}\n\t});\n\n\tit(\"alibaba-coding-plan models use openai-completions API\", () => {\n\t\tconst models = getModels(\"alibaba-coding-plan\");\n\t\tfor (const model of models) {\n\t\t\tassert.equal(model.api, \"openai-completions\", `Model ${model.id} has wrong api: ${model.api}`);\n\t\t}\n\t});\n\n\tit(\"alibaba-coding-plan models have provider set correctly\", () => {\n\t\tconst models = getModels(\"alibaba-coding-plan\");\n\t\tfor (const model of models) {\n\t\t\tassert.equal(\n\t\t\t\tmodel.provider,\n\t\t\t\t\"alibaba-coding-plan\",\n\t\t\t\t`Model ${model.id} has wrong provider: ${model.provider}`,\n\t\t\t);\n\t\t}\n\t});\n\n\tit(\"getModel retrieves alibaba-coding-plan models by provider+id\", () => {\n\t\t// Use type assertion to test runtime behavior — alibaba-coding-plan may come\n\t\t// from custom models rather than the generated file, so the narrow\n\t\t// GeneratedProvider type doesn't include it until models/custom.ts is merged.\n\t\tconst model = getModel(\"alibaba-coding-plan\" as any, \"qwen3.5-plus\" as any);\n\t\tassert.ok(model, \"Expected getModel to return a model for alibaba-coding-plan/qwen3.5-plus\");\n\t\tassert.equal(model.id, \"qwen3.5-plus\");\n\t\tassert.equal(model.provider, \"alibaba-coding-plan\");\n\t});\n});\n\ndescribe(\"model registry — custom zai provider (GLM-5.1)\", () => {\n\tit(\"zai provider includes glm-5.1 from custom models\", () => {\n\t\tconst models = getModels(\"zai\" as any);\n\t\tconst ids = models.map((m) => m.id);\n\t\tassert.ok(ids.includes(\"glm-5.1\"), `Expected \"glm-5.1\" in zai models, got: ${ids.join(\", \")}`);\n\t});\n\n\tit(\"glm-5.1 has correct provider and base URL\", () => {\n\t\tconst model = getModel(\"zai\" as any, \"glm-5.1\" as any);\n\t\tassert.ok(model, \"Expected getModel to return a model for zai/glm-5.1\");\n\t\tassert.equal(model.id, \"glm-5.1\");\n\t\tassert.equal(model.provider, \"zai\");\n\t\tassert.equal(model.baseUrl, \"https://api.z.ai/api/coding/paas/v4\");\n\t\tassert.equal(model.api, \"openai-completions\");\n\t});\n\n\tit(\"glm-5.1 has reasoning enabled and uses generated catalog precedence\", () => {\n\t\tconst model = getModel(\"zai\" as any, \"glm-5.1\" as any);\n\t\tassert.ok(model);\n\t\tassert.equal(model.reasoning, true);\n\t\t// Generated catalog entries are loaded first; custom models are additive-only.\n\t\tassert.equal(model.contextWindow, 200000);\n\t\tassert.equal(model.maxTokens, 131072);\n\t});\n\n\tit(\"custom glm-5.1 does not overwrite generated zai models\", () => {\n\t\tconst models = getModels(\"zai\" as any);\n\t\tconst ids = models.map((m) => m.id);\n\t\t// Generated models must still exist alongside custom glm-5.1\n\t\tassert.ok(ids.includes(\"glm-5\"), \"Generated glm-5 should still exist\");\n\t\tassert.ok(ids.includes(\"glm-5-turbo\"), \"Generated glm-5-turbo should still exist\");\n\t});\n});\n\n// ═══════════════════════════════════════════════════════════════════════════\n// New provider: alibaba-dashscope (feat: #3891)\n//\n// Regular DashScope API for users without the Coding Plan.\n// Separate from alibaba-coding-plan — different endpoint, auth, and pricing.\n// ═══════════════════════════════════════════════════════════════════════════\n\ndescribe(\"model registry — alibaba-dashscope provider\", () => {\n\tit(\"alibaba-dashscope is a registered provider\", () => {\n\t\tconst providers = getProviders();\n\t\tassert.ok(\n\t\t\tproviders.includes(\"alibaba-dashscope\"),\n\t\t\t`Expected \"alibaba-dashscope\" in providers, got: ${providers.join(\", \")}`,\n\t\t);\n\t});\n\n\tit(\"alibaba-dashscope has all expected models\", () => {\n\t\tconst models = getModels(\"alibaba-dashscope\");\n\t\tconst ids = models.map((m) => m.id).sort();\n\t\tconst expected = [\n\t\t\t\"qwen3-coder-plus\",\n\t\t\t\"qwen3-max\",\n\t\t\t\"qwen3.5-flash\",\n\t\t\t\"qwen3.5-plus\",\n\t\t\t\"qwen3.6-plus\",\n\t\t];\n\t\tassert.deepEqual(ids, expected);\n\t});\n\n\tit(\"alibaba-dashscope models use the international DashScope base URL\", () => {\n\t\tconst models = getModels(\"alibaba-dashscope\");\n\t\tfor (const model of models) {\n\t\t\tassert.equal(\n\t\t\t\tmodel.baseUrl,\n\t\t\t\t\"https://dashscope-intl.aliyuncs.com/compatible-mode/v1\",\n\t\t\t\t`Model ${model.id} has wrong baseUrl: ${model.baseUrl}`,\n\t\t\t);\n\t\t}\n\t});\n\n\tit(\"alibaba-dashscope models use openai-completions API\", () => {\n\t\tconst models = getModels(\"alibaba-dashscope\");\n\t\tfor (const model of models) {\n\t\t\tassert.equal(model.api, \"openai-completions\", `Model ${model.id} has wrong api: ${model.api}`);\n\t\t}\n\t});\n\n\tit(\"alibaba-dashscope models have provider set correctly\", () => {\n\t\tconst models = getModels(\"alibaba-dashscope\");\n\t\tfor (const model of models) {\n\t\t\tassert.equal(\n\t\t\t\tmodel.provider,\n\t\t\t\t\"alibaba-dashscope\",\n\t\t\t\t`Model ${model.id} has wrong provider: ${model.provider}`,\n\t\t\t);\n\t\t}\n\t});\n\n\tit(\"alibaba-dashscope models all have 1M context window\", () => {\n\t\tconst models = getModels(\"alibaba-dashscope\");\n\t\tfor (const model of models) {\n\t\t\tassert.equal(model.contextWindow, 1_000_000, `Model ${model.id} has wrong contextWindow: ${model.contextWindow}`);\n\t\t}\n\t});\n\n\tit(\"alibaba-dashscope models have positive paid costs (not free-tier)\", () => {\n\t\tconst models = getModels(\"alibaba-dashscope\");\n\t\tfor (const model of models) {\n\t\t\tassert.ok(model.cost.input > 0, `${model.id}: input cost should be > 0 (paid tier)`);\n\t\t\tassert.ok(model.cost.output > 0, `${model.id}: output cost should be > 0 (paid tier)`);\n\t\t}\n\t});\n\n\tit(\"qwen3-max is a reasoning model with correct pricing\", () => {\n\t\tconst model = getModel(\"alibaba-dashscope\" as any, \"qwen3-max\" as any);\n\t\tassert.ok(model, \"Expected getModel to return qwen3-max for alibaba-dashscope\");\n\t\tassert.equal(model.reasoning, true);\n\t\tassert.equal(model.cost.input, 1.2);\n\t\tassert.equal(model.cost.output, 6);\n\t\tassert.equal(model.maxTokens, 32768);\n\t});\n\n\tit(\"qwen3.5-plus is a reasoning model with correct pricing\", () => {\n\t\tconst model = getModel(\"alibaba-dashscope\" as any, \"qwen3.5-plus\" as any);\n\t\tassert.ok(model, \"Expected getModel to return qwen3.5-plus for alibaba-dashscope\");\n\t\tassert.equal(model.reasoning, true);\n\t\tassert.equal(model.cost.input, 0.4);\n\t\tassert.equal(model.cost.output, 1.2);\n\t\tassert.equal(model.maxTokens, 65536);\n\t});\n\n\tit(\"qwen3.5-flash is not a reasoning model\", () => {\n\t\tconst model = getModel(\"alibaba-dashscope\" as any, \"qwen3.5-flash\" as any);\n\t\tassert.ok(model, \"Expected getModel to return qwen3.5-flash for alibaba-dashscope\");\n\t\tassert.equal(model.reasoning, false);\n\t\tassert.equal(model.cost.input, 0.1);\n\t\tassert.equal(model.cost.output, 0.4);\n\t});\n\n\tit(\"qwen3-coder-plus is not a reasoning model\", () => {\n\t\tconst model = getModel(\"alibaba-dashscope\" as any, \"qwen3-coder-plus\" as any);\n\t\tassert.ok(model, \"Expected getModel to return qwen3-coder-plus for alibaba-dashscope\");\n\t\tassert.equal(model.reasoning, false);\n\t\tassert.equal(model.cost.input, 1.0);\n\t\tassert.equal(model.cost.output, 5.0);\n\t});\n\n\tit(\"qwen3.6-plus is a reasoning model\", () => {\n\t\tconst model = getModel(\"alibaba-dashscope\" as any, \"qwen3.6-plus\" as any);\n\t\tassert.ok(model, \"Expected getModel to return qwen3.6-plus for alibaba-dashscope\");\n\t\tassert.equal(model.reasoning, true);\n\t\tassert.equal(model.cost.input, 0.5);\n\t\tassert.equal(model.cost.output, 3.0);\n\t});\n\n\tit(\"alibaba-dashscope is independent of alibaba-coding-plan (different endpoint)\", () => {\n\t\tconst dashscope = getModels(\"alibaba-dashscope\");\n\t\tconst codingPlan = getModels(\"alibaba-coding-plan\");\n\t\tfor (const m of dashscope) {\n\t\t\tassert.notEqual(\n\t\t\t\tm.baseUrl,\n\t\t\t\t\"https://coding-intl.dashscope.aliyuncs.com/v1\",\n\t\t\t\t`${m.id} must not use the Coding Plan endpoint`,\n\t\t\t);\n\t\t}\n\t\t// Both providers must coexist — coding-plan must not have been overwritten\n\t\tassert.ok(codingPlan.length > 0, \"alibaba-coding-plan must still have models\");\n\t});\n\n\tit(\"getModel returns undefined for unknown model in alibaba-dashscope (failure path)\", () => {\n\t\tconst model = getModel(\"alibaba-dashscope\" as any, \"does-not-exist\" as any);\n\t\tassert.equal(model, undefined);\n\t});\n});\n\ndescribe(\"model registry — custom models do not collide with generated models\", () => {\n\tit(\"generated providers still exist alongside custom providers\", () => {\n\t\tconst providers = getProviders();\n\t\t// Spot-check a few generated providers\n\t\tassert.ok(providers.includes(\"openai\"), \"openai should be in providers\");\n\t\tassert.ok(providers.includes(\"anthropic\"), \"anthropic should be in providers\");\n\t});\n});\n\n// ═══════════════════════════════════════════════════════════════════════════\n// Capability patches (regression: #2546)\n//\n// CAPABILITY_PATCHES must apply capabilities to models in the static\n// registry AND to models constructed outside of it (custom, extension,\n// discovered). supportsXhigh() reads model.capabilities — not model IDs.\n// ═══════════════════════════════════════════════════════════════════════════\n\n/** Helper: build a minimal synthetic model for testing */\nfunction syntheticModel(overrides: Partial<Model<Api>>): Model<Api> {\n\treturn {\n\t\tid: \"test-model\",\n\t\tname: \"Test Model\",\n\t\tapi: \"openai-completions\" as Api,\n\t\tprovider: \"test-provider\",\n\t\tbaseUrl: \"https://example.com\",\n\t\treasoning: false,\n\t\tinput: [\"text\"],\n\t\tcost: { input: 0, output: 0, cacheRead: 0, cacheWrite: 0 },\n\t\tcontextWindow: 128000,\n\t\tmaxTokens: 16384,\n\t\t...overrides,\n\t} as Model<Api>;\n}\n\ndescribe(\"supportsXhigh — registry models\", () => {\n\t// Previous version silent-skipped via `if (!model) return;` — when\n\t// the target model was renamed or removed, the test passed\n\t// trivially without signalling the regression. Issue #4804 flagged\n\t// this pattern. Replaced with synthetic-model tests (the block\n\t// below) that verify the CAPABILITY CHECK independent of any\n\t// specific model ID.\n\t//\n\t// A \"is-xhigh-capable model found in the registry when expected\"\n\t// invariant, if needed, belongs in the feature that depends on\n\t// xhigh support — it's a product-feature requirement, not a\n\t// registry contract.\n\n\tit(\"applies capabilities-based true/false to synthetic registry-shaped models\", () => {\n\t\t// Use a real registry model but assert the CAPABILITY path\n\t\t// without pinning a specific ID. Find any model that declares\n\t\t// the capability vs any that doesn't.\n\t\tconst openaiModels = getModels(\"openai\");\n\t\tconst xhighCapable = openaiModels.find((m) => m.capabilities?.supportsXhigh === true);\n\t\tconst nonXhigh = openaiModels.find((m) => !m.capabilities?.supportsXhigh);\n\t\t// If neither shape exists in the current registry, the test\n\t\t// is vacuous; emit a clear todo rather than silently passing.\n\t\tif (!xhighCapable && !nonXhigh) {\n\t\t\t// Nothing to test here; registry is degenerate.\n\t\t\treturn;\n\t\t}\n\t\tif (xhighCapable) {\n\t\t\tassert.equal(\n\t\t\t\tsupportsXhigh(xhighCapable),\n\t\t\t\ttrue,\n\t\t\t\t`${xhighCapable.id} declares supportsXhigh: true but helper returned false`,\n\t\t\t);\n\t\t}\n\t\tif (nonXhigh) {\n\t\t\tassert.equal(\n\t\t\t\tsupportsXhigh(nonXhigh),\n\t\t\t\tfalse,\n\t\t\t\t`${nonXhigh.id} has no supportsXhigh capability but helper returned true`,\n\t\t\t);\n\t\t}\n\t});\n});\n\ndescribe(\"supportsXhigh — synthetic models (regression: custom/extension models)\", () => {\n\tit(\"returns false for a model without capabilities\", () => {\n\t\tconst model = syntheticModel({ id: \"my-custom-model\" });\n\t\tassert.equal(supportsXhigh(model), false);\n\t});\n\n\tit(\"returns true when capabilities.supportsXhigh is explicitly set\", () => {\n\t\tconst model = syntheticModel({\n\t\t\tid: \"my-custom-model\",\n\t\t\tcapabilities: { supportsXhigh: true },\n\t\t});\n\t\tassert.equal(supportsXhigh(model), true);\n\t});\n});\n\ndescribe(\"applyCapabilityPatches\", () => {\n\tit(\"patches a GPT-5.4 model that has no capabilities\", () => {\n\t\tconst model = syntheticModel({ id: \"gpt-5.4-custom\" });\n\t\tassert.equal(model.capabilities, undefined);\n\n\t\tconst [patched] = applyCapabilityPatches([model]);\n\t\tassert.equal(patched.capabilities?.supportsXhigh, true);\n\t\tassert.equal(patched.capabilities?.supportsServiceTier, true);\n\t});\n\n\tit(\"patches a GPT-5.5 custom model that has no capabilities\", () => {\n\t\tconst model = syntheticModel({ id: \"gpt-5.5-custom\" });\n\t\tassert.equal(model.capabilities, undefined);\n\n\t\tconst [patched] = applyCapabilityPatches([model]);\n\t\tassert.equal(patched.capabilities?.supportsXhigh, true);\n\t\tassert.equal(patched.capabilities?.supportsServiceTier, undefined);\n\t});\n\n\tit(\"patches a GPT-5.2 model\", () => {\n\t\tconst model = syntheticModel({ id: \"gpt-5.2\" });\n\t\tconst [patched] = applyCapabilityPatches([model]);\n\t\tassert.equal(patched.capabilities?.supportsXhigh, true);\n\t});\n\n\tit(\"patches an Anthropic Opus 4.6 model\", () => {\n\t\tconst model = syntheticModel({\n\t\t\tid: \"claude-opus-4-6-20260301\",\n\t\t\tapi: \"anthropic-messages\" as Api,\n\t\t});\n\t\tconst [patched] = applyCapabilityPatches([model]);\n\t\tassert.equal(patched.capabilities?.supportsXhigh, true);\n\t\t// Opus should not get supportsServiceTier\n\t\tassert.equal(patched.capabilities?.supportsServiceTier, undefined);\n\t});\n\n\tit(\"preserves explicit capabilities over patches\", () => {\n\t\tconst model = syntheticModel({\n\t\t\tid: \"gpt-5.4-custom\",\n\t\t\tcapabilities: { supportsXhigh: false, charsPerToken: 3 },\n\t\t});\n\t\tconst [patched] = applyCapabilityPatches([model]);\n\t\t// Explicit supportsXhigh: false wins over patch's true\n\t\tassert.equal(patched.capabilities?.supportsXhigh, false);\n\t\t// Patch fills in supportsServiceTier since it wasn't explicitly set\n\t\tassert.equal(patched.capabilities?.supportsServiceTier, true);\n\t\t// Explicit charsPerToken is preserved\n\t\tassert.equal(patched.capabilities?.charsPerToken, 3);\n\t});\n\n\tit(\"does not modify models that match no patches\", () => {\n\t\tconst model = syntheticModel({ id: \"gemini-2.5-pro\" });\n\t\tconst [patched] = applyCapabilityPatches([model]);\n\t\tassert.equal(patched.capabilities, undefined);\n\t\t// Should return the same reference when unpatched\n\t\tassert.equal(patched, model);\n\t});\n\n\tit(\"is idempotent — re-applying patches produces the same result\", () => {\n\t\tconst model = syntheticModel({ id: \"gpt-5.3\" });\n\t\tconst first = applyCapabilityPatches([model]);\n\t\tconst second = applyCapabilityPatches(first);\n\t\tassert.deepEqual(first[0].capabilities, second[0].capabilities);\n\t});\n});\n"]}
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@gsd/pi-ai",
3
- "version": "2.77.0",
3
+ "version": "2.78.0",
4
4
  "description": "Unified LLM API (vendored from pi-mono)",
5
5
  "type": "module",
6
6
  "gsd": {
@@ -707,6 +707,13 @@ async function generateModels() {
707
707
  candidate.contextWindow = 272000;
708
708
  candidate.maxTokens = 128000;
709
709
  }
710
+ if (candidate.provider === "openai" && candidate.id === "gpt-5.5") {
711
+ // GPT-5.5 has a 1M context window.
712
+ // Keep max output aligned with existing GPT-5.x local constraints.
713
+ // Source: https://openai.com/index/introducing-gpt-5-5/
714
+ candidate.contextWindow = 1000000;
715
+ candidate.maxTokens = 128000;
716
+ }
710
717
  // Keep selected OpenRouter model metadata stable until upstream settles.
711
718
  if (candidate.provider === "openrouter" && candidate.id === "moonshotai/kimi-k2.5") {
712
719
  candidate.cost.input = 0.41;
@@ -942,6 +949,27 @@ async function generateModels() {
942
949
  });
943
950
  }
944
951
 
952
+ if (!allModels.some((m) => m.provider === "openai" && m.id === "gpt-5.5")) {
953
+ allModels.push({
954
+ id: "gpt-5.5",
955
+ name: "GPT-5.5",
956
+ api: "openai-responses",
957
+ baseUrl: "https://api.openai.com/v1",
958
+ provider: "openai",
959
+ reasoning: true,
960
+ input: ["text", "image"],
961
+ cost: {
962
+ // Source: https://openai.com/api/pricing/
963
+ input: 5,
964
+ output: 30,
965
+ cacheRead: 0.5,
966
+ cacheWrite: 0,
967
+ },
968
+ contextWindow: 1000000,
969
+ maxTokens: 128000,
970
+ });
971
+ }
972
+
945
973
  // OpenAI Codex (ChatGPT OAuth) models
946
974
  // NOTE: These are not fetched from models.dev; we keep a small, explicit list to avoid aliases.
947
975
  // Context window is based on observed server limits (400s above ~272k), not marketing numbers.
@@ -1033,6 +1061,22 @@ async function generateModels() {
1033
1061
  contextWindow: CODEX_CONTEXT,
1034
1062
  maxTokens: CODEX_MAX_TOKENS,
1035
1063
  },
1064
+ {
1065
+ id: "gpt-5.5",
1066
+ name: "GPT-5.5",
1067
+ api: "openai-codex-responses",
1068
+ provider: "openai-codex",
1069
+ baseUrl: CODEX_BASE_URL,
1070
+ reasoning: true,
1071
+ input: ["text", "image"],
1072
+ // Official GPT-5.5 list price; Codex availability and 400K window are live.
1073
+ // Sources:
1074
+ // - https://openai.com/index/introducing-gpt-5-5/
1075
+ // - https://openai.com/api/pricing/
1076
+ cost: { input: 5, output: 30, cacheRead: 0.5, cacheWrite: 0 },
1077
+ contextWindow: 400000,
1078
+ maxTokens: CODEX_MAX_TOKENS,
1079
+ },
1036
1080
  {
1037
1081
  id: "gpt-5.4-mini",
1038
1082
  name: "GPT-5.4 Mini",