orynacode-ai 1.16.2

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 (938) hide show
  1. package/AGENTS.md +131 -0
  2. package/BUN_SHELL_MIGRATION_PLAN.md +136 -0
  3. package/Dockerfile +18 -0
  4. package/README.md +15 -0
  5. package/bin/orynacode +199 -0
  6. package/bunfig.toml +7 -0
  7. package/git +0 -0
  8. package/migration/20260511173437_session-metadata/migration.sql +1 -0
  9. package/migration/20260511173437_session-metadata/snapshot.json +1500 -0
  10. package/package.json +155 -0
  11. package/parsers-config.ts +386 -0
  12. package/script/bench-search.ts +115 -0
  13. package/script/bench-test-suite.ts +52 -0
  14. package/script/build.ts +244 -0
  15. package/script/generate.ts +14 -0
  16. package/script/httpapi-exercise.ts +1 -0
  17. package/script/postinstall.mjs +189 -0
  18. package/script/profile-test-files.ts +42 -0
  19. package/script/publish.ts +213 -0
  20. package/script/run-workspace-server +106 -0
  21. package/script/schema.ts +77 -0
  22. package/script/time.ts +6 -0
  23. package/script/trace-imports.ts +153 -0
  24. package/specs/effect/error-boundaries-plan.md +235 -0
  25. package/specs/effect/errors.md +207 -0
  26. package/specs/effect/facades.md +218 -0
  27. package/specs/effect/guide.md +247 -0
  28. package/specs/effect/instance-context.md +13 -0
  29. package/specs/effect/loose-ends.md +30 -0
  30. package/specs/effect/migration.md +62 -0
  31. package/specs/effect/routes.md +61 -0
  32. package/specs/effect/schema.md +88 -0
  33. package/specs/effect/server-package.md +58 -0
  34. package/specs/effect/todo.md +241 -0
  35. package/specs/effect/tools.md +88 -0
  36. package/specs/openapi-translation-cleanup.md +204 -0
  37. package/specs/tui-plugins.md +544 -0
  38. package/specs/v2/api.ts +67 -0
  39. package/specs/v2/message-shape.md +136 -0
  40. package/specs/v2/notifications.md +13 -0
  41. package/specs/v2/tui-command-shim.md +67 -0
  42. package/src/account/account.ts +459 -0
  43. package/src/account/repo.ts +170 -0
  44. package/src/account/schema.ts +99 -0
  45. package/src/account/url.ts +8 -0
  46. package/src/acp/agent.ts +95 -0
  47. package/src/acp/config-option.ts +203 -0
  48. package/src/acp/content.ts +250 -0
  49. package/src/acp/directory.ts +210 -0
  50. package/src/acp/error.ts +90 -0
  51. package/src/acp/event.ts +344 -0
  52. package/src/acp/permission.ts +145 -0
  53. package/src/acp/profile.ts +42 -0
  54. package/src/acp/service.ts +1062 -0
  55. package/src/acp/session.ts +231 -0
  56. package/src/acp/tool.ts +317 -0
  57. package/src/acp/usage.ts +239 -0
  58. package/src/agent/agent.ts +433 -0
  59. package/src/agent/generate.txt +75 -0
  60. package/src/agent/prompt/compaction.txt +9 -0
  61. package/src/agent/prompt/explore.txt +18 -0
  62. package/src/agent/prompt/summary.txt +11 -0
  63. package/src/agent/prompt/title.txt +44 -0
  64. package/src/agent/subagent-permissions.ts +35 -0
  65. package/src/audio.d.ts +14 -0
  66. package/src/auth/index.ts +96 -0
  67. package/src/background/job.ts +36 -0
  68. package/src/bus/global.ts +22 -0
  69. package/src/cli/bootstrap.ts +11 -0
  70. package/src/cli/cmd/account.ts +264 -0
  71. package/src/cli/cmd/acp.ts +76 -0
  72. package/src/cli/cmd/agent.ts +259 -0
  73. package/src/cli/cmd/cmd.ts +7 -0
  74. package/src/cli/cmd/db.ts +62 -0
  75. package/src/cli/cmd/debug/agent.handler.ts +193 -0
  76. package/src/cli/cmd/debug/agent.ts +27 -0
  77. package/src/cli/cmd/debug/config.ts +14 -0
  78. package/src/cli/cmd/debug/file.ts +87 -0
  79. package/src/cli/cmd/debug/index.ts +87 -0
  80. package/src/cli/cmd/debug/lsp.ts +51 -0
  81. package/src/cli/cmd/debug/ripgrep.ts +99 -0
  82. package/src/cli/cmd/debug/scrap.ts +18 -0
  83. package/src/cli/cmd/debug/skill.ts +15 -0
  84. package/src/cli/cmd/debug/snapshot.ts +50 -0
  85. package/src/cli/cmd/debug/startup.ts +11 -0
  86. package/src/cli/cmd/debug/v2.ts +46 -0
  87. package/src/cli/cmd/export.ts +292 -0
  88. package/src/cli/cmd/generate.ts +54 -0
  89. package/src/cli/cmd/github.handler.ts +1593 -0
  90. package/src/cli/cmd/github.shared.ts +30 -0
  91. package/src/cli/cmd/github.ts +42 -0
  92. package/src/cli/cmd/import.ts +224 -0
  93. package/src/cli/cmd/mcp.ts +846 -0
  94. package/src/cli/cmd/models.ts +66 -0
  95. package/src/cli/cmd/plug.ts +230 -0
  96. package/src/cli/cmd/pr.ts +115 -0
  97. package/src/cli/cmd/prompt-display.ts +48 -0
  98. package/src/cli/cmd/providers.ts +506 -0
  99. package/src/cli/cmd/run/demo.ts +1274 -0
  100. package/src/cli/cmd/run/entry.body.ts +194 -0
  101. package/src/cli/cmd/run/footer.command.tsx +899 -0
  102. package/src/cli/cmd/run/footer.menu.tsx +306 -0
  103. package/src/cli/cmd/run/footer.permission.tsx +475 -0
  104. package/src/cli/cmd/run/footer.prompt.tsx +1207 -0
  105. package/src/cli/cmd/run/footer.question.tsx +579 -0
  106. package/src/cli/cmd/run/footer.subagent.tsx +171 -0
  107. package/src/cli/cmd/run/footer.ts +1092 -0
  108. package/src/cli/cmd/run/footer.view.tsx +935 -0
  109. package/src/cli/cmd/run/otel.ts +117 -0
  110. package/src/cli/cmd/run/permission.shared.ts +256 -0
  111. package/src/cli/cmd/run/prompt.shared.ts +147 -0
  112. package/src/cli/cmd/run/question.shared.ts +340 -0
  113. package/src/cli/cmd/run/runtime.boot.ts +210 -0
  114. package/src/cli/cmd/run/runtime.lifecycle.ts +369 -0
  115. package/src/cli/cmd/run/runtime.queue.ts +347 -0
  116. package/src/cli/cmd/run/runtime.shared.ts +17 -0
  117. package/src/cli/cmd/run/runtime.stdin.ts +37 -0
  118. package/src/cli/cmd/run/runtime.ts +879 -0
  119. package/src/cli/cmd/run/scrollback.shared.ts +92 -0
  120. package/src/cli/cmd/run/scrollback.surface.ts +435 -0
  121. package/src/cli/cmd/run/scrollback.writer.tsx +335 -0
  122. package/src/cli/cmd/run/session-data.ts +1113 -0
  123. package/src/cli/cmd/run/session-replay.ts +301 -0
  124. package/src/cli/cmd/run/session.shared.ts +196 -0
  125. package/src/cli/cmd/run/splash.ts +310 -0
  126. package/src/cli/cmd/run/stream.transport.ts +1465 -0
  127. package/src/cli/cmd/run/stream.ts +175 -0
  128. package/src/cli/cmd/run/subagent-data.ts +844 -0
  129. package/src/cli/cmd/run/theme.ts +603 -0
  130. package/src/cli/cmd/run/tool.ts +1489 -0
  131. package/src/cli/cmd/run/trace.ts +94 -0
  132. package/src/cli/cmd/run/types.ts +342 -0
  133. package/src/cli/cmd/run/variant.shared.ts +215 -0
  134. package/src/cli/cmd/run.ts +879 -0
  135. package/src/cli/cmd/serve.ts +24 -0
  136. package/src/cli/cmd/session.ts +147 -0
  137. package/src/cli/cmd/stats.ts +393 -0
  138. package/src/cli/cmd/tui/app.tsx +1113 -0
  139. package/src/cli/cmd/tui/attach.ts +103 -0
  140. package/src/cli/cmd/tui/attention.ts +262 -0
  141. package/src/cli/cmd/tui/component/bg-pulse-render.ts +436 -0
  142. package/src/cli/cmd/tui/component/bg-pulse.tsx +99 -0
  143. package/src/cli/cmd/tui/component/border.tsx +21 -0
  144. package/src/cli/cmd/tui/component/command-palette.tsx +79 -0
  145. package/src/cli/cmd/tui/component/dialog-agent.tsx +31 -0
  146. package/src/cli/cmd/tui/component/dialog-console-org.tsx +103 -0
  147. package/src/cli/cmd/tui/component/dialog-mcp.tsx +85 -0
  148. package/src/cli/cmd/tui/component/dialog-model.tsx +185 -0
  149. package/src/cli/cmd/tui/component/dialog-move-session.tsx +240 -0
  150. package/src/cli/cmd/tui/component/dialog-provider.tsx +687 -0
  151. package/src/cli/cmd/tui/component/dialog-retry-action.tsx +160 -0
  152. package/src/cli/cmd/tui/component/dialog-session-delete-failed.tsx +99 -0
  153. package/src/cli/cmd/tui/component/dialog-session-list.tsx +318 -0
  154. package/src/cli/cmd/tui/component/dialog-session-rename.tsx +31 -0
  155. package/src/cli/cmd/tui/component/dialog-skill.tsx +36 -0
  156. package/src/cli/cmd/tui/component/dialog-stash.tsx +87 -0
  157. package/src/cli/cmd/tui/component/dialog-status.tsx +168 -0
  158. package/src/cli/cmd/tui/component/dialog-tag.tsx +47 -0
  159. package/src/cli/cmd/tui/component/dialog-theme-list.tsx +50 -0
  160. package/src/cli/cmd/tui/component/dialog-variant.tsx +39 -0
  161. package/src/cli/cmd/tui/component/dialog-workspace-create.tsx +313 -0
  162. package/src/cli/cmd/tui/component/dialog-workspace-file-changes.tsx +144 -0
  163. package/src/cli/cmd/tui/component/dialog-workspace-list.tsx +112 -0
  164. package/src/cli/cmd/tui/component/dialog-workspace-unavailable.tsx +69 -0
  165. package/src/cli/cmd/tui/component/error-component.tsx +81 -0
  166. package/src/cli/cmd/tui/component/logo.tsx +885 -0
  167. package/src/cli/cmd/tui/component/plugin-route-missing.tsx +14 -0
  168. package/src/cli/cmd/tui/component/prompt/autocomplete.tsx +799 -0
  169. package/src/cli/cmd/tui/component/prompt/cwd.ts +0 -0
  170. package/src/cli/cmd/tui/component/prompt/frecency.tsx +90 -0
  171. package/src/cli/cmd/tui/component/prompt/history.tsx +117 -0
  172. package/src/cli/cmd/tui/component/prompt/index.tsx +1725 -0
  173. package/src/cli/cmd/tui/component/prompt/move.tsx +192 -0
  174. package/src/cli/cmd/tui/component/prompt/part.ts +31 -0
  175. package/src/cli/cmd/tui/component/prompt/stash.tsx +101 -0
  176. package/src/cli/cmd/tui/component/prompt/traits.ts +35 -0
  177. package/src/cli/cmd/tui/component/prompt/workspace.tsx +137 -0
  178. package/src/cli/cmd/tui/component/spinner.tsx +24 -0
  179. package/src/cli/cmd/tui/component/startup-loading.tsx +63 -0
  180. package/src/cli/cmd/tui/component/todo-item.tsx +32 -0
  181. package/src/cli/cmd/tui/component/use-connected.tsx +9 -0
  182. package/src/cli/cmd/tui/component/workspace-label.tsx +19 -0
  183. package/src/cli/cmd/tui/config/cwd.ts +5 -0
  184. package/src/cli/cmd/tui/config/keybind.ts +467 -0
  185. package/src/cli/cmd/tui/config/tui-migrate.ts +154 -0
  186. package/src/cli/cmd/tui/config/tui-schema.ts +88 -0
  187. package/src/cli/cmd/tui/config/tui.ts +308 -0
  188. package/src/cli/cmd/tui/context/agent.tsx +11 -0
  189. package/src/cli/cmd/tui/context/aggregate-failures.ts +51 -0
  190. package/src/cli/cmd/tui/context/args.tsx +15 -0
  191. package/src/cli/cmd/tui/context/directory.ts +15 -0
  192. package/src/cli/cmd/tui/context/editor-zed.ts +287 -0
  193. package/src/cli/cmd/tui/context/editor.ts +469 -0
  194. package/src/cli/cmd/tui/context/event.ts +38 -0
  195. package/src/cli/cmd/tui/context/exit.tsx +42 -0
  196. package/src/cli/cmd/tui/context/helper.tsx +25 -0
  197. package/src/cli/cmd/tui/context/kv.tsx +76 -0
  198. package/src/cli/cmd/tui/context/local.tsx +510 -0
  199. package/src/cli/cmd/tui/context/path-format.tsx +39 -0
  200. package/src/cli/cmd/tui/context/project.tsx +111 -0
  201. package/src/cli/cmd/tui/context/prompt.tsx +18 -0
  202. package/src/cli/cmd/tui/context/route.tsx +52 -0
  203. package/src/cli/cmd/tui/context/sdk.tsx +142 -0
  204. package/src/cli/cmd/tui/context/sync-v2.tsx +447 -0
  205. package/src/cli/cmd/tui/context/sync.tsx +628 -0
  206. package/src/cli/cmd/tui/context/theme/aura.json +69 -0
  207. package/src/cli/cmd/tui/context/theme/ayu.json +80 -0
  208. package/src/cli/cmd/tui/context/theme/carbonfox.json +248 -0
  209. package/src/cli/cmd/tui/context/theme/catppuccin-frappe.json +230 -0
  210. package/src/cli/cmd/tui/context/theme/catppuccin-macchiato.json +230 -0
  211. package/src/cli/cmd/tui/context/theme/catppuccin.json +112 -0
  212. package/src/cli/cmd/tui/context/theme/cobalt2.json +225 -0
  213. package/src/cli/cmd/tui/context/theme/cursor.json +249 -0
  214. package/src/cli/cmd/tui/context/theme/dracula.json +219 -0
  215. package/src/cli/cmd/tui/context/theme/everforest.json +241 -0
  216. package/src/cli/cmd/tui/context/theme/flexoki.json +237 -0
  217. package/src/cli/cmd/tui/context/theme/github.json +233 -0
  218. package/src/cli/cmd/tui/context/theme/gruvbox.json +242 -0
  219. package/src/cli/cmd/tui/context/theme/kanagawa.json +77 -0
  220. package/src/cli/cmd/tui/context/theme/lucent-orng.json +234 -0
  221. package/src/cli/cmd/tui/context/theme/material.json +235 -0
  222. package/src/cli/cmd/tui/context/theme/matrix.json +77 -0
  223. package/src/cli/cmd/tui/context/theme/mercury.json +252 -0
  224. package/src/cli/cmd/tui/context/theme/monokai.json +221 -0
  225. package/src/cli/cmd/tui/context/theme/nightowl.json +221 -0
  226. package/src/cli/cmd/tui/context/theme/nord.json +223 -0
  227. package/src/cli/cmd/tui/context/theme/one-dark.json +84 -0
  228. package/src/cli/cmd/tui/context/theme/opencode.json +245 -0
  229. package/src/cli/cmd/tui/context/theme/orng.json +249 -0
  230. package/src/cli/cmd/tui/context/theme/oryna.json +95 -0
  231. package/src/cli/cmd/tui/context/theme/osaka-jade.json +93 -0
  232. package/src/cli/cmd/tui/context/theme/palenight.json +222 -0
  233. package/src/cli/cmd/tui/context/theme/rosepine.json +234 -0
  234. package/src/cli/cmd/tui/context/theme/solarized.json +223 -0
  235. package/src/cli/cmd/tui/context/theme/synthwave84.json +226 -0
  236. package/src/cli/cmd/tui/context/theme/tokyonight.json +243 -0
  237. package/src/cli/cmd/tui/context/theme/vercel.json +245 -0
  238. package/src/cli/cmd/tui/context/theme/vesper.json +218 -0
  239. package/src/cli/cmd/tui/context/theme/zenburn.json +223 -0
  240. package/src/cli/cmd/tui/context/theme.tsx +1341 -0
  241. package/src/cli/cmd/tui/context/thinking.ts +67 -0
  242. package/src/cli/cmd/tui/context/tui-config.tsx +9 -0
  243. package/src/cli/cmd/tui/event.ts +53 -0
  244. package/src/cli/cmd/tui/feature-plugins/home/footer.tsx +98 -0
  245. package/src/cli/cmd/tui/feature-plugins/home/tips-view.tsx +288 -0
  246. package/src/cli/cmd/tui/feature-plugins/home/tips.tsx +59 -0
  247. package/src/cli/cmd/tui/feature-plugins/session/dialog.tsx +356 -0
  248. package/src/cli/cmd/tui/feature-plugins/session/index.tsx +32 -0
  249. package/src/cli/cmd/tui/feature-plugins/session/preview-pane.tsx +288 -0
  250. package/src/cli/cmd/tui/feature-plugins/session/util.tsx +54 -0
  251. package/src/cli/cmd/tui/feature-plugins/sidebar/context.tsx +65 -0
  252. package/src/cli/cmd/tui/feature-plugins/sidebar/files.tsx +70 -0
  253. package/src/cli/cmd/tui/feature-plugins/sidebar/footer.tsx +96 -0
  254. package/src/cli/cmd/tui/feature-plugins/sidebar/lsp.tsx +65 -0
  255. package/src/cli/cmd/tui/feature-plugins/sidebar/mcp.tsx +97 -0
  256. package/src/cli/cmd/tui/feature-plugins/sidebar/todo.tsx +49 -0
  257. package/src/cli/cmd/tui/feature-plugins/system/diff-viewer-file-tree-utils.ts +232 -0
  258. package/src/cli/cmd/tui/feature-plugins/system/diff-viewer-file-tree.tsx +162 -0
  259. package/src/cli/cmd/tui/feature-plugins/system/diff-viewer-ui.tsx +103 -0
  260. package/src/cli/cmd/tui/feature-plugins/system/diff-viewer.tsx +1058 -0
  261. package/src/cli/cmd/tui/feature-plugins/system/notifications.ts +94 -0
  262. package/src/cli/cmd/tui/feature-plugins/system/plugins.tsx +269 -0
  263. package/src/cli/cmd/tui/feature-plugins/system/session-v2.tsx +1184 -0
  264. package/src/cli/cmd/tui/feature-plugins/system/which-key.tsx +608 -0
  265. package/src/cli/cmd/tui/keymap.tsx +283 -0
  266. package/src/cli/cmd/tui/layer.ts +6 -0
  267. package/src/cli/cmd/tui/plugin/api.tsx +390 -0
  268. package/src/cli/cmd/tui/plugin/command-shim.ts +109 -0
  269. package/src/cli/cmd/tui/plugin/internal.ts +42 -0
  270. package/src/cli/cmd/tui/plugin/runtime.ts +1131 -0
  271. package/src/cli/cmd/tui/plugin/slots.tsx +60 -0
  272. package/src/cli/cmd/tui/routes/home/session-destination.tsx +39 -0
  273. package/src/cli/cmd/tui/routes/home.tsx +149 -0
  274. package/src/cli/cmd/tui/routes/session/dialog-fork-from-timeline.tsx +76 -0
  275. package/src/cli/cmd/tui/routes/session/dialog-message.tsx +108 -0
  276. package/src/cli/cmd/tui/routes/session/dialog-subagent.tsx +26 -0
  277. package/src/cli/cmd/tui/routes/session/dialog-timeline.tsx +47 -0
  278. package/src/cli/cmd/tui/routes/session/footer.tsx +91 -0
  279. package/src/cli/cmd/tui/routes/session/index.tsx +2629 -0
  280. package/src/cli/cmd/tui/routes/session/permission.tsx +729 -0
  281. package/src/cli/cmd/tui/routes/session/question.tsx +514 -0
  282. package/src/cli/cmd/tui/routes/session/sidebar.tsx +102 -0
  283. package/src/cli/cmd/tui/routes/session/subagent-footer.tsx +132 -0
  284. package/src/cli/cmd/tui/thread.ts +264 -0
  285. package/src/cli/cmd/tui/ui/dialog-alert.tsx +66 -0
  286. package/src/cli/cmd/tui/ui/dialog-confirm.tsx +108 -0
  287. package/src/cli/cmd/tui/ui/dialog-export-options.tsx +217 -0
  288. package/src/cli/cmd/tui/ui/dialog-help.tsx +40 -0
  289. package/src/cli/cmd/tui/ui/dialog-prompt.tsx +126 -0
  290. package/src/cli/cmd/tui/ui/dialog-select.tsx +712 -0
  291. package/src/cli/cmd/tui/ui/dialog.tsx +218 -0
  292. package/src/cli/cmd/tui/ui/link.tsx +34 -0
  293. package/src/cli/cmd/tui/ui/spinner.ts +368 -0
  294. package/src/cli/cmd/tui/ui/toast.tsx +102 -0
  295. package/src/cli/cmd/tui/util/audio.ts +58 -0
  296. package/src/cli/cmd/tui/util/clipboard.ts +181 -0
  297. package/src/cli/cmd/tui/util/collapse-tool-output.ts +19 -0
  298. package/src/cli/cmd/tui/util/editor.ts +43 -0
  299. package/src/cli/cmd/tui/util/layout.ts +25 -0
  300. package/src/cli/cmd/tui/util/model.ts +23 -0
  301. package/src/cli/cmd/tui/util/provider-origin.ts +7 -0
  302. package/src/cli/cmd/tui/util/revert-diff.ts +18 -0
  303. package/src/cli/cmd/tui/util/scroll.ts +25 -0
  304. package/src/cli/cmd/tui/util/selection.ts +73 -0
  305. package/src/cli/cmd/tui/util/signal.ts +41 -0
  306. package/src/cli/cmd/tui/util/transcript.ts +112 -0
  307. package/src/cli/cmd/tui/validate-session.ts +29 -0
  308. package/src/cli/cmd/tui/win32.ts +130 -0
  309. package/src/cli/cmd/tui/worker.ts +99 -0
  310. package/src/cli/cmd/uninstall.ts +353 -0
  311. package/src/cli/cmd/upgrade.ts +74 -0
  312. package/src/cli/cmd/web.ts +84 -0
  313. package/src/cli/effect/prompt.ts +37 -0
  314. package/src/cli/effect-cmd.ts +96 -0
  315. package/src/cli/error.ts +118 -0
  316. package/src/cli/heap.ts +59 -0
  317. package/src/cli/logo.ts +21 -0
  318. package/src/cli/network.ts +64 -0
  319. package/src/cli/ui.ts +132 -0
  320. package/src/cli/upgrade.ts +53 -0
  321. package/src/command/index.ts +181 -0
  322. package/src/command/template/initialize.txt +66 -0
  323. package/src/command/template/review.txt +101 -0
  324. package/src/config/agent.ts +68 -0
  325. package/src/config/command.ts +45 -0
  326. package/src/config/config.ts +679 -0
  327. package/src/config/entry-name.ts +19 -0
  328. package/src/config/managed.ts +77 -0
  329. package/src/config/markdown.ts +36 -0
  330. package/src/config/parse.ts +79 -0
  331. package/src/config/paths.ts +45 -0
  332. package/src/config/plugin.ts +79 -0
  333. package/src/config/reference.ts +48 -0
  334. package/src/config/variable.ts +91 -0
  335. package/src/control-plane/adapters/index.ts +41 -0
  336. package/src/control-plane/adapters/worktree.ts +96 -0
  337. package/src/control-plane/dev/README.md +19 -0
  338. package/src/control-plane/dev/debug-workspace-plugin.ts +73 -0
  339. package/src/control-plane/types.ts +59 -0
  340. package/src/control-plane/util.ts +39 -0
  341. package/src/control-plane/workspace-adapter-runtime.ts +51 -0
  342. package/src/control-plane/workspace-context.ts +26 -0
  343. package/src/control-plane/workspace.ts +1075 -0
  344. package/src/effect/app-runtime.ts +133 -0
  345. package/src/effect/bootstrap-runtime.ts +23 -0
  346. package/src/effect/bridge.ts +84 -0
  347. package/src/effect/config-service.ts +67 -0
  348. package/src/effect/instance-ref.ts +11 -0
  349. package/src/effect/instance-registry.ts +12 -0
  350. package/src/effect/instance-state.ts +72 -0
  351. package/src/effect/promise.ts +17 -0
  352. package/src/effect/run-service.ts +47 -0
  353. package/src/effect/runner.ts +217 -0
  354. package/src/effect/runtime-flags.ts +76 -0
  355. package/src/env/index.ts +40 -0
  356. package/src/event-v2-bridge.ts +76 -0
  357. package/src/format/formatter.ts +404 -0
  358. package/src/format/index.ts +212 -0
  359. package/src/git/index.ts +347 -0
  360. package/src/id/id.ts +80 -0
  361. package/src/ide/index.ts +70 -0
  362. package/src/image/image.ts +177 -0
  363. package/src/index.ts +208 -0
  364. package/src/installation/index.ts +349 -0
  365. package/src/lsp/client.ts +686 -0
  366. package/src/lsp/diagnostic.ts +29 -0
  367. package/src/lsp/language.ts +121 -0
  368. package/src/lsp/launch.ts +21 -0
  369. package/src/lsp/lsp.ts +517 -0
  370. package/src/lsp/server.ts +2064 -0
  371. package/src/markdown.d.ts +4 -0
  372. package/src/mcp/auth.ts +171 -0
  373. package/src/mcp/index.ts +982 -0
  374. package/src/mcp/oauth-callback.ts +232 -0
  375. package/src/mcp/oauth-provider.ts +217 -0
  376. package/src/node.ts +5 -0
  377. package/src/oryna/agent.ts +112 -0
  378. package/src/oryna/reply-service.ts +8 -0
  379. package/src/patch/index.ts +689 -0
  380. package/src/permission/arity.ts +163 -0
  381. package/src/permission/evaluate.ts +1 -0
  382. package/src/permission/index.ts +230 -0
  383. package/src/plugin/azure.ts +26 -0
  384. package/src/plugin/cloudflare.ts +76 -0
  385. package/src/plugin/digitalocean.ts +391 -0
  386. package/src/plugin/github-copilot/copilot.ts +417 -0
  387. package/src/plugin/github-copilot/models.ts +246 -0
  388. package/src/plugin/index.ts +323 -0
  389. package/src/plugin/install.ts +439 -0
  390. package/src/plugin/loader.ts +237 -0
  391. package/src/plugin/meta.ts +188 -0
  392. package/src/plugin/openai/README.md +31 -0
  393. package/src/plugin/openai/codex.ts +647 -0
  394. package/src/plugin/openai/ws-pool.ts +290 -0
  395. package/src/plugin/openai/ws.ts +381 -0
  396. package/src/plugin/oryna.ts +349 -0
  397. package/src/plugin/shared.ts +323 -0
  398. package/src/plugin/xai.ts +742 -0
  399. package/src/project/bootstrap-service.ts +9 -0
  400. package/src/project/bootstrap.ts +80 -0
  401. package/src/project/instance-context.ts +24 -0
  402. package/src/project/instance-layer.ts +11 -0
  403. package/src/project/instance-runtime.ts +16 -0
  404. package/src/project/instance-store.ts +207 -0
  405. package/src/project/project.ts +520 -0
  406. package/src/project/vcs.ts +435 -0
  407. package/src/provider/auth.ts +230 -0
  408. package/src/provider/error.ts +188 -0
  409. package/src/provider/model-status.ts +8 -0
  410. package/src/provider/provider.ts +2009 -0
  411. package/src/provider/transform.ts +1363 -0
  412. package/src/pty-preparation.ts +30 -0
  413. package/src/question/index.ts +229 -0
  414. package/src/question/schema.ts +10 -0
  415. package/src/reference/reference.ts +239 -0
  416. package/src/reference/repository-cache.ts +320 -0
  417. package/src/server/auth.ts +48 -0
  418. package/src/server/cors.ts +34 -0
  419. package/src/server/event.ts +13 -0
  420. package/src/server/global-lifecycle.ts +37 -0
  421. package/src/server/init-projectors.ts +3 -0
  422. package/src/server/mdns.ts +60 -0
  423. package/src/server/projectors.ts +1 -0
  424. package/src/server/proxy-util.ts +48 -0
  425. package/src/server/routes/instance/httpapi/AGENTS.md +39 -0
  426. package/src/server/routes/instance/httpapi/api.ts +78 -0
  427. package/src/server/routes/instance/httpapi/errors.ts +193 -0
  428. package/src/server/routes/instance/httpapi/groups/config.ts +65 -0
  429. package/src/server/routes/instance/httpapi/groups/control-plane.ts +35 -0
  430. package/src/server/routes/instance/httpapi/groups/control.ts +76 -0
  431. package/src/server/routes/instance/httpapi/groups/event.ts +29 -0
  432. package/src/server/routes/instance/httpapi/groups/experimental.ts +260 -0
  433. package/src/server/routes/instance/httpapi/groups/file.ts +172 -0
  434. package/src/server/routes/instance/httpapi/groups/global.ts +138 -0
  435. package/src/server/routes/instance/httpapi/groups/instance.ts +206 -0
  436. package/src/server/routes/instance/httpapi/groups/mcp.ts +156 -0
  437. package/src/server/routes/instance/httpapi/groups/metadata.ts +18 -0
  438. package/src/server/routes/instance/httpapi/groups/permission.ts +61 -0
  439. package/src/server/routes/instance/httpapi/groups/project-copy.ts +88 -0
  440. package/src/server/routes/instance/httpapi/groups/project.ts +93 -0
  441. package/src/server/routes/instance/httpapi/groups/provider.ts +101 -0
  442. package/src/server/routes/instance/httpapi/groups/pty.ts +172 -0
  443. package/src/server/routes/instance/httpapi/groups/query.ts +12 -0
  444. package/src/server/routes/instance/httpapi/groups/question.ts +74 -0
  445. package/src/server/routes/instance/httpapi/groups/session.ts +462 -0
  446. package/src/server/routes/instance/httpapi/groups/sync.ts +113 -0
  447. package/src/server/routes/instance/httpapi/groups/tui.ts +208 -0
  448. package/src/server/routes/instance/httpapi/groups/workspace.ts +141 -0
  449. package/src/server/routes/instance/httpapi/handlers/config.ts +151 -0
  450. package/src/server/routes/instance/httpapi/handlers/control-plane.ts +37 -0
  451. package/src/server/routes/instance/httpapi/handlers/control.ts +40 -0
  452. package/src/server/routes/instance/httpapi/handlers/event.ts +102 -0
  453. package/src/server/routes/instance/httpapi/handlers/experimental.ts +187 -0
  454. package/src/server/routes/instance/httpapi/handlers/file.ts +103 -0
  455. package/src/server/routes/instance/httpapi/handlers/global.ts +157 -0
  456. package/src/server/routes/instance/httpapi/handlers/instance.ts +110 -0
  457. package/src/server/routes/instance/httpapi/handlers/mcp.ts +111 -0
  458. package/src/server/routes/instance/httpapi/handlers/permission.ts +41 -0
  459. package/src/server/routes/instance/httpapi/handlers/project-copy.ts +157 -0
  460. package/src/server/routes/instance/httpapi/handlers/project.ts +63 -0
  461. package/src/server/routes/instance/httpapi/handlers/provider.ts +160 -0
  462. package/src/server/routes/instance/httpapi/handlers/pty.ts +258 -0
  463. package/src/server/routes/instance/httpapi/handlers/question.ts +54 -0
  464. package/src/server/routes/instance/httpapi/handlers/session-errors.ts +21 -0
  465. package/src/server/routes/instance/httpapi/handlers/session.ts +442 -0
  466. package/src/server/routes/instance/httpapi/handlers/sync.ts +95 -0
  467. package/src/server/routes/instance/httpapi/handlers/tui.ts +131 -0
  468. package/src/server/routes/instance/httpapi/handlers/workspace.ts +102 -0
  469. package/src/server/routes/instance/httpapi/lifecycle.ts +57 -0
  470. package/src/server/routes/instance/httpapi/middleware/authorization.ts +147 -0
  471. package/src/server/routes/instance/httpapi/middleware/compression.ts +64 -0
  472. package/src/server/routes/instance/httpapi/middleware/cors-vary.ts +29 -0
  473. package/src/server/routes/instance/httpapi/middleware/error.ts +36 -0
  474. package/src/server/routes/instance/httpapi/middleware/fence.ts +25 -0
  475. package/src/server/routes/instance/httpapi/middleware/instance-context.ts +43 -0
  476. package/src/server/routes/instance/httpapi/middleware/proxy.ts +108 -0
  477. package/src/server/routes/instance/httpapi/middleware/schema-error.ts +42 -0
  478. package/src/server/routes/instance/httpapi/middleware/workspace-routing.ts +250 -0
  479. package/src/server/routes/instance/httpapi/public.ts +535 -0
  480. package/src/server/routes/instance/httpapi/server.ts +277 -0
  481. package/src/server/routes/instance/httpapi/websocket-tracker.ts +57 -0
  482. package/src/server/server.ts +218 -0
  483. package/src/server/shared/fence.ts +68 -0
  484. package/src/server/shared/pty-ticket.ts +15 -0
  485. package/src/server/shared/public-ui.ts +12 -0
  486. package/src/server/shared/tui-control.ts +28 -0
  487. package/src/server/shared/ui.ts +108 -0
  488. package/src/server/shared/workspace-routing.ts +38 -0
  489. package/src/session/compaction.ts +609 -0
  490. package/src/session/instruction.ts +237 -0
  491. package/src/session/llm/AGENTS.md +90 -0
  492. package/src/session/llm/ai-sdk.ts +288 -0
  493. package/src/session/llm/native-request.ts +196 -0
  494. package/src/session/llm/native-runtime.ts +195 -0
  495. package/src/session/llm/request.ts +215 -0
  496. package/src/session/llm.ts +402 -0
  497. package/src/session/message-error.ts +14 -0
  498. package/src/session/message-v2.ts +745 -0
  499. package/src/session/message.ts +148 -0
  500. package/src/session/overflow.ts +34 -0
  501. package/src/session/processor.ts +1063 -0
  502. package/src/session/prompt/anthropic.txt +105 -0
  503. package/src/session/prompt/beast.txt +147 -0
  504. package/src/session/prompt/build-switch.txt +5 -0
  505. package/src/session/prompt/codex.txt +79 -0
  506. package/src/session/prompt/copilot-gpt-5.txt +143 -0
  507. package/src/session/prompt/default.txt +95 -0
  508. package/src/session/prompt/gemini.txt +155 -0
  509. package/src/session/prompt/gpt.txt +107 -0
  510. package/src/session/prompt/kimi.txt +95 -0
  511. package/src/session/prompt/max-steps.txt +16 -0
  512. package/src/session/prompt/plan-mode.txt +70 -0
  513. package/src/session/prompt/plan-reminder-anthropic.txt +67 -0
  514. package/src/session/prompt/plan.txt +26 -0
  515. package/src/session/prompt/reference.ts +72 -0
  516. package/src/session/prompt/trinity.txt +97 -0
  517. package/src/session/prompt.ts +1755 -0
  518. package/src/session/reminders.ts +92 -0
  519. package/src/session/retry.ts +201 -0
  520. package/src/session/revert.ts +153 -0
  521. package/src/session/run-state.ts +153 -0
  522. package/src/session/schema.ts +26 -0
  523. package/src/session/session.ts +1116 -0
  524. package/src/session/status.ts +94 -0
  525. package/src/session/summary.ts +162 -0
  526. package/src/session/system.ts +84 -0
  527. package/src/session/todo.ts +87 -0
  528. package/src/session/tools.ts +211 -0
  529. package/src/share/session.ts +58 -0
  530. package/src/share/share-next.ts +379 -0
  531. package/src/shell/shell.ts +215 -0
  532. package/src/skill/discovery.ts +115 -0
  533. package/src/skill/index.ts +357 -0
  534. package/src/snapshot/index.ts +759 -0
  535. package/src/sql.d.ts +4 -0
  536. package/src/storage/schema.ts +5 -0
  537. package/src/storage/storage.ts +329 -0
  538. package/src/sync/README.md +179 -0
  539. package/src/sync/schema.ts +11 -0
  540. package/src/temporary.ts +33 -0
  541. package/src/tool/apply_patch.ts +313 -0
  542. package/src/tool/apply_patch.txt +33 -0
  543. package/src/tool/edit.ts +737 -0
  544. package/src/tool/edit.txt +10 -0
  545. package/src/tool/external-directory.ts +49 -0
  546. package/src/tool/glob.ts +84 -0
  547. package/src/tool/glob.txt +6 -0
  548. package/src/tool/grep.ts +140 -0
  549. package/src/tool/grep.txt +8 -0
  550. package/src/tool/invalid.ts +21 -0
  551. package/src/tool/json-schema.ts +164 -0
  552. package/src/tool/lsp.ts +113 -0
  553. package/src/tool/lsp.txt +24 -0
  554. package/src/tool/mcp-websearch.ts +96 -0
  555. package/src/tool/plan-enter.txt +14 -0
  556. package/src/tool/plan-exit.txt +13 -0
  557. package/src/tool/plan.ts +79 -0
  558. package/src/tool/question.ts +44 -0
  559. package/src/tool/question.txt +10 -0
  560. package/src/tool/read.ts +392 -0
  561. package/src/tool/read.txt +14 -0
  562. package/src/tool/registry.ts +475 -0
  563. package/src/tool/reply.ts +29 -0
  564. package/src/tool/schema.ts +14 -0
  565. package/src/tool/shell/id.ts +19 -0
  566. package/src/tool/shell/prompt.ts +307 -0
  567. package/src/tool/shell/shell.txt +21 -0
  568. package/src/tool/shell.ts +660 -0
  569. package/src/tool/skill.ts +72 -0
  570. package/src/tool/skill.txt +5 -0
  571. package/src/tool/task.ts +338 -0
  572. package/src/tool/task.txt +19 -0
  573. package/src/tool/todo.ts +57 -0
  574. package/src/tool/todowrite.txt +44 -0
  575. package/src/tool/tool.ts +183 -0
  576. package/src/tool/truncate.ts +160 -0
  577. package/src/tool/truncation-dir.ts +4 -0
  578. package/src/tool/webfetch.ts +192 -0
  579. package/src/tool/webfetch.txt +13 -0
  580. package/src/tool/websearch.ts +143 -0
  581. package/src/tool/websearch.txt +14 -0
  582. package/src/tool/write.ts +104 -0
  583. package/src/tool/write.txt +8 -0
  584. package/src/util/archive.ts +17 -0
  585. package/src/util/bom.ts +27 -0
  586. package/src/util/data-url.ts +9 -0
  587. package/src/util/defer.ts +10 -0
  588. package/src/util/effect-http-client.ts +11 -0
  589. package/src/util/error.ts +88 -0
  590. package/src/util/filesystem.ts +251 -0
  591. package/src/util/format.ts +20 -0
  592. package/src/util/iife.ts +3 -0
  593. package/src/util/lan-scan.ts +90 -0
  594. package/src/util/lazy.ts +20 -0
  595. package/src/util/local-context.ts +25 -0
  596. package/src/util/locale.ts +86 -0
  597. package/src/util/media.ts +26 -0
  598. package/src/util/process.ts +176 -0
  599. package/src/util/proxy-env.ts +72 -0
  600. package/src/util/queue.ts +32 -0
  601. package/src/util/record.ts +3 -0
  602. package/src/util/repository.ts +232 -0
  603. package/src/util/rpc.ts +66 -0
  604. package/src/util/signal.ts +12 -0
  605. package/src/util/timeout.ts +13 -0
  606. package/src/util/token.ts +1 -0
  607. package/src/util/wildcard.ts +59 -0
  608. package/src/worktree/index.ts +645 -0
  609. package/sst-env.d.ts +10 -0
  610. package/test/AGENTS.md +204 -0
  611. package/test/EFFECT_TEST_MIGRATION.md +169 -0
  612. package/test/account/repo.test.ts +353 -0
  613. package/test/account/service.test.ts +453 -0
  614. package/test/acp/config-option.test.ts +229 -0
  615. package/test/acp/content.test.ts +201 -0
  616. package/test/acp/directory.test.ts +186 -0
  617. package/test/acp/error.test.ts +67 -0
  618. package/test/acp/event.test.ts +711 -0
  619. package/test/acp/permission.test.ts +273 -0
  620. package/test/acp/service-session.test.ts +1174 -0
  621. package/test/acp/session.test.ts +200 -0
  622. package/test/acp/tool.test.ts +210 -0
  623. package/test/acp/usage.test.ts +315 -0
  624. package/test/agent/agent.test.ts +710 -0
  625. package/test/agent/plan-mode-subagent-bypass.test.ts +213 -0
  626. package/test/agent/plugin-agent-regression.test.ts +62 -0
  627. package/test/auth/auth.test.ts +77 -0
  628. package/test/background/job.test.ts +243 -0
  629. package/test/cli/account.test.ts +30 -0
  630. package/test/cli/acp/acp-test-client.ts +97 -0
  631. package/test/cli/acp/config-options.test.ts +103 -0
  632. package/test/cli/acp/helpers.ts +96 -0
  633. package/test/cli/acp/initialize-auth.test.ts +61 -0
  634. package/test/cli/acp/lifecycle.test.ts +118 -0
  635. package/test/cli/acp/prompt-content.test.ts +97 -0
  636. package/test/cli/acp/skills.test.ts +38 -0
  637. package/test/cli/cmd/tui/aggregate-failures.test.ts +93 -0
  638. package/test/cli/cmd/tui/attention.test.ts +484 -0
  639. package/test/cli/cmd/tui/dialog-workspace-create.test.ts +28 -0
  640. package/test/cli/cmd/tui/model-options.test.ts +30 -0
  641. package/test/cli/cmd/tui/notifications.test.ts +267 -0
  642. package/test/cli/cmd/tui/prompt-history.test.ts +44 -0
  643. package/test/cli/cmd/tui/prompt-part.test.ts +77 -0
  644. package/test/cli/cmd/tui/prompt-traits.test.ts +29 -0
  645. package/test/cli/cmd/tui/provider-options.test.ts +29 -0
  646. package/test/cli/cmd/tui/sync-fixture.tsx +64 -0
  647. package/test/cli/cmd/tui/sync-live-hydration.test.tsx +278 -0
  648. package/test/cli/cmd/tui/sync-undefined-messages.test.tsx +47 -0
  649. package/test/cli/cmd/tui/sync.test.tsx +70 -0
  650. package/test/cli/effect-cmd-instance-als.test.ts +39 -0
  651. package/test/cli/error.test.ts +95 -0
  652. package/test/cli/github-action.test.ts +199 -0
  653. package/test/cli/github-remote.test.ts +90 -0
  654. package/test/cli/help/__snapshots__/help-snapshots.test.ts.snap +631 -0
  655. package/test/cli/help/help-snapshots.test.ts +137 -0
  656. package/test/cli/import.test.ts +54 -0
  657. package/test/cli/mcp-add.test.ts +74 -0
  658. package/test/cli/plugin-auth-picker.test.ts +120 -0
  659. package/test/cli/run/entry.body.test.ts +536 -0
  660. package/test/cli/run/footer.menu.test.ts +43 -0
  661. package/test/cli/run/footer.view.test.tsx +927 -0
  662. package/test/cli/run/permission.shared.test.ts +144 -0
  663. package/test/cli/run/prompt.shared.test.ts +133 -0
  664. package/test/cli/run/question.shared.test.ts +115 -0
  665. package/test/cli/run/run-process.test.ts +84 -0
  666. package/test/cli/run/runtime.boot.test.ts +282 -0
  667. package/test/cli/run/runtime.queue.test.ts +465 -0
  668. package/test/cli/run/runtime.stdin.test.ts +71 -0
  669. package/test/cli/run/scrollback.surface.test.ts +1048 -0
  670. package/test/cli/run/session-data.test.ts +595 -0
  671. package/test/cli/run/session-replay.test.ts +456 -0
  672. package/test/cli/run/session.shared.test.ts +247 -0
  673. package/test/cli/run/stream.test.ts +56 -0
  674. package/test/cli/run/stream.transport.test.ts +2363 -0
  675. package/test/cli/run/subagent-data.test.ts +456 -0
  676. package/test/cli/run/theme.test.ts +152 -0
  677. package/test/cli/run/variant.shared.test.ts +217 -0
  678. package/test/cli/serve/serve-process.test.ts +61 -0
  679. package/test/cli/smokes/read-only.test.ts +115 -0
  680. package/test/cli/tui/__snapshots__/inline-tool-wrap-snapshot.test.tsx.snap +72 -0
  681. package/test/cli/tui/app-lifecycle.test.ts +261 -0
  682. package/test/cli/tui/dialog-prompt.test.tsx +146 -0
  683. package/test/cli/tui/diff-viewer-file-tree-utils.test.ts +323 -0
  684. package/test/cli/tui/diff-viewer-file-tree.test.tsx +197 -0
  685. package/test/cli/tui/diff-viewer.test.tsx +230 -0
  686. package/test/cli/tui/editor-context-zed.test.ts +384 -0
  687. package/test/cli/tui/editor-context.test.tsx +288 -0
  688. package/test/cli/tui/inline-tool-wrap-snapshot.test.tsx +232 -0
  689. package/test/cli/tui/keymap.test.tsx +136 -0
  690. package/test/cli/tui/plugin-add.test.ts +110 -0
  691. package/test/cli/tui/plugin-install.test.ts +87 -0
  692. package/test/cli/tui/plugin-lifecycle.test.ts +224 -0
  693. package/test/cli/tui/plugin-loader-entrypoint.test.ts +485 -0
  694. package/test/cli/tui/plugin-loader-pure.test.ts +72 -0
  695. package/test/cli/tui/plugin-loader.test.ts +1332 -0
  696. package/test/cli/tui/plugin-toggle.test.ts +264 -0
  697. package/test/cli/tui/prompt-submit-race.test.ts +98 -0
  698. package/test/cli/tui/revert-diff.test.ts +35 -0
  699. package/test/cli/tui/slot-replace.test.tsx +50 -0
  700. package/test/cli/tui/sync-v2.test.tsx +558 -0
  701. package/test/cli/tui/theme-store.test.ts +76 -0
  702. package/test/cli/tui/thinking.test.ts +36 -0
  703. package/test/cli/tui/thread.test.ts +28 -0
  704. package/test/cli/tui/transcript.test.ts +426 -0
  705. package/test/cli/tui/use-event.test.tsx +145 -0
  706. package/test/config/agent-color.test.ts +47 -0
  707. package/test/config/config.test.ts +1991 -0
  708. package/test/config/entry-name.test.ts +57 -0
  709. package/test/config/fixtures/empty-frontmatter.md +4 -0
  710. package/test/config/fixtures/frontmatter.md +28 -0
  711. package/test/config/fixtures/markdown-header.md +11 -0
  712. package/test/config/fixtures/no-frontmatter.md +1 -0
  713. package/test/config/fixtures/weird-model-id.md +13 -0
  714. package/test/config/lsp.test.ts +69 -0
  715. package/test/config/markdown.test.ts +228 -0
  716. package/test/config/plugin.test.ts +0 -0
  717. package/test/config/tui.test.ts +878 -0
  718. package/test/control-plane/adapters.test.ts +71 -0
  719. package/test/control-plane/workspace.test.ts +1704 -0
  720. package/test/effect/app-runtime-logger.test.ts +105 -0
  721. package/test/effect/config-service.test.ts +65 -0
  722. package/test/effect/instance-state.test.ts +391 -0
  723. package/test/effect/run-service.test.ts +89 -0
  724. package/test/effect/runner.test.ts +514 -0
  725. package/test/effect/runtime-flags.test.ts +373 -0
  726. package/test/fake/account.ts +9 -0
  727. package/test/fake/auth.ts +8 -0
  728. package/test/fake/npm.ts +8 -0
  729. package/test/fake/provider.ts +82 -0
  730. package/test/fake/skill.ts +8 -0
  731. package/test/filesystem/filesystem.test.ts +319 -0
  732. package/test/fixture/agent-plugin.constants.ts +6 -0
  733. package/test/fixture/agent-plugin.ts +12 -0
  734. package/test/fixture/config.ts +23 -0
  735. package/test/fixture/db.ts +11 -0
  736. package/test/fixture/fixture.test.ts +26 -0
  737. package/test/fixture/fixture.ts +224 -0
  738. package/test/fixture/flag.ts +20 -0
  739. package/test/fixture/flock-worker.ts +72 -0
  740. package/test/fixture/lsp/fake-lsp-server.js +249 -0
  741. package/test/fixture/plug-worker.ts +93 -0
  742. package/test/fixture/plugin-meta-worker.ts +19 -0
  743. package/test/fixture/plugin.ts +10 -0
  744. package/test/fixture/skills/agents-sdk/SKILL.md +152 -0
  745. package/test/fixture/skills/agents-sdk/references/callable.md +92 -0
  746. package/test/fixture/skills/cloudflare/SKILL.md +211 -0
  747. package/test/fixture/skills/index.json +6 -0
  748. package/test/fixture/tui-plugin.ts +355 -0
  749. package/test/fixture/tui-runtime.ts +64 -0
  750. package/test/fixture/tui-sdk.ts +82 -0
  751. package/test/fixture/workspace.ts +30 -0
  752. package/test/fixtures/recordings/session/native-anthropic-tool-loop.json +49 -0
  753. package/test/fixtures/recordings/session/native-openai-oauth-tool-loop.json +45 -0
  754. package/test/fixtures/recordings/session/native-zen-tool-loop.json +49 -0
  755. package/test/format/format.test.ts +228 -0
  756. package/test/git/git.test.ts +178 -0
  757. package/test/ide/ide.test.ts +82 -0
  758. package/test/image/fixtures/picture-5mb-base64.png +0 -0
  759. package/test/image/image.test.ts +123 -0
  760. package/test/installation/installation.test.ts +230 -0
  761. package/test/lib/cli-process.ts +459 -0
  762. package/test/lib/effect.ts +177 -0
  763. package/test/lib/filesystem.ts +10 -0
  764. package/test/lib/llm-server.ts +771 -0
  765. package/test/lib/snapshot.ts +73 -0
  766. package/test/lib/test-provider.ts +37 -0
  767. package/test/lib/websocket.ts +46 -0
  768. package/test/lsp/client.test.ts +493 -0
  769. package/test/lsp/index.test.ts +232 -0
  770. package/test/lsp/launch.test.ts +22 -0
  771. package/test/lsp/lifecycle.test.ts +160 -0
  772. package/test/mcp/auth.test.ts +78 -0
  773. package/test/mcp/headers.test.ts +126 -0
  774. package/test/mcp/lifecycle.test.ts +888 -0
  775. package/test/mcp/oauth-auto-connect.test.ts +236 -0
  776. package/test/mcp/oauth-browser.test.ts +228 -0
  777. package/test/mcp/oauth-callback.test.ts +34 -0
  778. package/test/mcp/oauth-provider.test.ts +61 -0
  779. package/test/patch/patch.test.ts +383 -0
  780. package/test/permission/arity.test.ts +33 -0
  781. package/test/permission/next.test.ts +1176 -0
  782. package/test/permission-task.test.ts +318 -0
  783. package/test/plugin/auth-override.test.ts +105 -0
  784. package/test/plugin/cloudflare.test.ts +68 -0
  785. package/test/plugin/codex.test.ts +247 -0
  786. package/test/plugin/github-copilot-models.test.ts +332 -0
  787. package/test/plugin/install-concurrency.test.ts +140 -0
  788. package/test/plugin/install.test.ts +570 -0
  789. package/test/plugin/loader-shared.test.ts +1303 -0
  790. package/test/plugin/meta.test.ts +137 -0
  791. package/test/plugin/openai-rollout.test.ts +17 -0
  792. package/test/plugin/openai-ws.test.ts +877 -0
  793. package/test/plugin/shared.test.ts +88 -0
  794. package/test/plugin/trigger.test.ts +120 -0
  795. package/test/plugin/workspace-adapter.test.ts +137 -0
  796. package/test/plugin/xai.test.ts +634 -0
  797. package/test/preload.ts +95 -0
  798. package/test/project/instance-bootstrap.test.ts +110 -0
  799. package/test/project/instance.test.ts +245 -0
  800. package/test/project/migrate-global.test.ts +170 -0
  801. package/test/project/project-directory.test.ts +169 -0
  802. package/test/project/project.test.ts +818 -0
  803. package/test/project/vcs.test.ts +336 -0
  804. package/test/project/worktree-remove.test.ts +126 -0
  805. package/test/project/worktree.test.ts +320 -0
  806. package/test/provider/amazon-bedrock.test.ts +360 -0
  807. package/test/provider/cf-ai-gateway-e2e.test.ts +132 -0
  808. package/test/provider/digitalocean.test.ts +123 -0
  809. package/test/provider/gitlab-duo.test.ts +412 -0
  810. package/test/provider/header-timeout.test.ts +233 -0
  811. package/test/provider/model-status.test.ts +61 -0
  812. package/test/provider/provider.test.ts +1793 -0
  813. package/test/provider/transform.test.ts +3937 -0
  814. package/test/pty/pty-shell.test.ts +102 -0
  815. package/test/question/question.test.ts +465 -0
  816. package/test/reference/reference.test.ts +310 -0
  817. package/test/server/AGENTS.md +15 -0
  818. package/test/server/auth.test.ts +59 -0
  819. package/test/server/global-bus.ts +31 -0
  820. package/test/server/global-session-list.test.ts +107 -0
  821. package/test/server/httpapi-authorization.test.ts +174 -0
  822. package/test/server/httpapi-compression.test.ts +154 -0
  823. package/test/server/httpapi-config.test.ts +113 -0
  824. package/test/server/httpapi-control-plane.test.ts +63 -0
  825. package/test/server/httpapi-cors-vary.test.ts +66 -0
  826. package/test/server/httpapi-cors.test.ts +122 -0
  827. package/test/server/httpapi-error-middleware.test.ts +96 -0
  828. package/test/server/httpapi-event.test.ts +97 -0
  829. package/test/server/httpapi-exercise/assertions.ts +64 -0
  830. package/test/server/httpapi-exercise/backend.ts +144 -0
  831. package/test/server/httpapi-exercise/dsl.ts +210 -0
  832. package/test/server/httpapi-exercise/environment.ts +40 -0
  833. package/test/server/httpapi-exercise/index.ts +1535 -0
  834. package/test/server/httpapi-exercise/report.ts +66 -0
  835. package/test/server/httpapi-exercise/routing.ts +96 -0
  836. package/test/server/httpapi-exercise/runner.ts +267 -0
  837. package/test/server/httpapi-exercise/runtime.ts +52 -0
  838. package/test/server/httpapi-exercise/types.ts +123 -0
  839. package/test/server/httpapi-experimental.test.ts +300 -0
  840. package/test/server/httpapi-file.test.ts +76 -0
  841. package/test/server/httpapi-global.test.ts +66 -0
  842. package/test/server/httpapi-instance-context.test.ts +347 -0
  843. package/test/server/httpapi-instance-route-auth.test.ts +84 -0
  844. package/test/server/httpapi-instance.test.ts +265 -0
  845. package/test/server/httpapi-layer.ts +33 -0
  846. package/test/server/httpapi-listen.test.ts +415 -0
  847. package/test/server/httpapi-mcp-oauth.test.ts +73 -0
  848. package/test/server/httpapi-mcp.test.ts +226 -0
  849. package/test/server/httpapi-mdns.test.ts +82 -0
  850. package/test/server/httpapi-promptasync-context.test.ts +222 -0
  851. package/test/server/httpapi-provider.test.ts +403 -0
  852. package/test/server/httpapi-pty.test.ts +275 -0
  853. package/test/server/httpapi-public-openapi.test.ts +297 -0
  854. package/test/server/httpapi-query-schema-drift.test.ts +330 -0
  855. package/test/server/httpapi-schema-error-body.test.ts +165 -0
  856. package/test/server/httpapi-sdk.test.ts +909 -0
  857. package/test/server/httpapi-session.test.ts +1013 -0
  858. package/test/server/httpapi-sync.test.ts +154 -0
  859. package/test/server/httpapi-ui.test.ts +456 -0
  860. package/test/server/httpapi-v2-location.test.ts +85 -0
  861. package/test/server/httpapi-workspace-routing.test.ts +554 -0
  862. package/test/server/httpapi-workspace.test.ts +515 -0
  863. package/test/server/negative-tokens-regression.test.ts +83 -0
  864. package/test/server/project-copy.test.ts +101 -0
  865. package/test/server/project-init-git.test.ts +117 -0
  866. package/test/server/proxy-util.test.ts +113 -0
  867. package/test/server/sdk-error-shape.test.ts +84 -0
  868. package/test/server/sdk-v1-smoke.test.ts +60 -0
  869. package/test/server/session-actions.test.ts +112 -0
  870. package/test/server/session-diff-missing-patch.test.ts +99 -0
  871. package/test/server/session-list.test.ts +314 -0
  872. package/test/server/session-messages.test.ts +182 -0
  873. package/test/server/session-select.test.ts +69 -0
  874. package/test/server/workspace-proxy.test.ts +181 -0
  875. package/test/server/workspace-routing.test.ts +94 -0
  876. package/test/server/worktree-endpoint-repro.test.ts +307 -0
  877. package/test/session/compaction.test.ts +1835 -0
  878. package/test/session/instruction.test.ts +256 -0
  879. package/test/session/llm-native-recorded.test.ts +433 -0
  880. package/test/session/llm-native.test.ts +760 -0
  881. package/test/session/llm.test.ts +1932 -0
  882. package/test/session/message-v2.test.ts +1661 -0
  883. package/test/session/messages-pagination.test.ts +1059 -0
  884. package/test/session/processor-effect.test.ts +1101 -0
  885. package/test/session/prompt.test.ts +2318 -0
  886. package/test/session/retry.test.ts +439 -0
  887. package/test/session/revert-compact.test.ts +642 -0
  888. package/test/session/schema-decoding.test.ts +313 -0
  889. package/test/session/session-schema.test.ts +78 -0
  890. package/test/session/session.test.ts +251 -0
  891. package/test/session/snapshot-tool-race.test.ts +280 -0
  892. package/test/session/structured-output-integration.test.ts +235 -0
  893. package/test/session/structured-output.test.ts +387 -0
  894. package/test/session/system.test.ts +84 -0
  895. package/test/share/share-next.test.ts +344 -0
  896. package/test/shell/shell.test.ts +99 -0
  897. package/test/skill/discovery.test.ts +139 -0
  898. package/test/skill/skill.test.ts +571 -0
  899. package/test/snapshot/snapshot.test.ts +1121 -0
  900. package/test/storage/storage.test.ts +296 -0
  901. package/test/storage/workspace-time-migration.test.ts +50 -0
  902. package/test/tool/__snapshots__/parameters.test.ts.snap +484 -0
  903. package/test/tool/__snapshots__/tool.test.ts.snap +9 -0
  904. package/test/tool/apply_patch.test.ts +533 -0
  905. package/test/tool/edit.test.ts +578 -0
  906. package/test/tool/external-directory.test.ts +155 -0
  907. package/test/tool/fixtures/large-image.png +0 -0
  908. package/test/tool/fixtures/models-api.json +117299 -0
  909. package/test/tool/glob.test.ts +188 -0
  910. package/test/tool/grep.test.ts +266 -0
  911. package/test/tool/lsp.test.ts +181 -0
  912. package/test/tool/parameters.test.ts +293 -0
  913. package/test/tool/question.test.ts +138 -0
  914. package/test/tool/read.test.ts +654 -0
  915. package/test/tool/registry.test.ts +539 -0
  916. package/test/tool/shell.test.ts +1238 -0
  917. package/test/tool/skill.test.ts +132 -0
  918. package/test/tool/task.test.ts +901 -0
  919. package/test/tool/tool-define.test.ts +153 -0
  920. package/test/tool/truncation.test.ts +266 -0
  921. package/test/tool/webfetch.test.ts +113 -0
  922. package/test/tool/websearch.test.ts +99 -0
  923. package/test/tool/write.test.ts +276 -0
  924. package/test/util/data-url.test.ts +14 -0
  925. package/test/util/error.test.ts +64 -0
  926. package/test/util/filesystem.test.ts +656 -0
  927. package/test/util/format.test.ts +59 -0
  928. package/test/util/glob.test.ts +164 -0
  929. package/test/util/iife.test.ts +36 -0
  930. package/test/util/lazy.test.ts +50 -0
  931. package/test/util/log.test.ts +77 -0
  932. package/test/util/module.test.ts +59 -0
  933. package/test/util/process.test.ts +128 -0
  934. package/test/util/repository.test.ts +93 -0
  935. package/test/util/timeout.test.ts +21 -0
  936. package/test/util/wildcard.test.ts +90 -0
  937. package/test/v2/session-message-updater.test.ts +270 -0
  938. package/tsconfig.json +17 -0
@@ -0,0 +1,877 @@
1
+ import { describe, expect, test } from "bun:test"
2
+ import { EventEmitter } from "node:events"
3
+ import { createServer, type IncomingMessage, type Server as HttpServer } from "node:http"
4
+ import net, { type AddressInfo, type Socket } from "node:net"
5
+ import WebSocket, { WebSocketServer } from "ws"
6
+ import { APICallError } from "ai"
7
+ import { ProviderError } from "../../src/provider/error"
8
+ import { OpenAIWebSocket } from "../../src/plugin/openai/ws"
9
+ import { OpenAIWebSocketPool, TITLE_HEADER } from "../../src/plugin/openai/ws-pool"
10
+
11
+ describe("plugin.openai.ws", () => {
12
+ test("derives websocket URLs and sends auth plus protocol headers", async () => {
13
+ let headers: IncomingMessage["headers"] | undefined
14
+ await using server = await createWebSocketServer((_socket, request) => {
15
+ headers = request.headers
16
+ })
17
+
18
+ const socket = await OpenAIWebSocket.connectResponsesWebSocket({
19
+ url: server.wsUrl,
20
+ headers: { authorization: "Bearer test", "content-length": "123" },
21
+ })
22
+
23
+ expect(OpenAIWebSocket.toWebSocketUrl("http://example.com/v1/responses")).toBe("ws://example.com/v1/responses")
24
+ expect(OpenAIWebSocket.toWebSocketUrl("https://example.com/v1/responses")).toBe("wss://example.com/v1/responses")
25
+ expect(headers?.authorization).toBe("Bearer test")
26
+ expect(headers?.["openai-beta"]).toBe(OpenAIWebSocket.PROTOCOL_HEADER)
27
+ expect(headers?.["content-length"]).toBeUndefined()
28
+ socket.terminate()
29
+ })
30
+
31
+ test("enforces websocket connect timeout", async () => {
32
+ await using server = await createHangingTcpServer()
33
+
34
+ await expect(
35
+ OpenAIWebSocket.connectResponsesWebSocket({
36
+ url: server.wsUrl,
37
+ headers: {},
38
+ timeout: 20,
39
+ }),
40
+ ).rejects.toThrow("WebSocket connect timed out")
41
+ })
42
+
43
+ test("surfaces websocket upgrade rejection messages", async () => {
44
+ await using server = await createRejectingWebSocketServer(() => {})
45
+
46
+ await expect(
47
+ OpenAIWebSocket.connectResponsesWebSocket({
48
+ url: server.wsUrl,
49
+ headers: {},
50
+ }),
51
+ ).rejects.toThrow("Expected 101 status code")
52
+ })
53
+
54
+ test("enforces websocket send idle timeout", async () => {
55
+ const socket = new (class extends EventEmitter {
56
+ send(_data: string, _callback: (error?: Error) => void) {}
57
+ })() as unknown as WebSocket
58
+ const invalid: string[] = []
59
+ const response = OpenAIWebSocket.streamResponsesWebSocket({
60
+ socket,
61
+ body: { stream: true, input: "hi" },
62
+ idleTimeout: 20,
63
+ onConnectionInvalid: (error) => invalid.push(error.message),
64
+ })
65
+
66
+ expect((await readTextError(response.text())).message).toContain("idle timeout sending websocket request")
67
+ expect(invalid).toEqual(["idle timeout sending websocket request"])
68
+ })
69
+
70
+ test("streams websocket events as SSE and handles response.done", async () => {
71
+ let requestBody: unknown
72
+ await using server = await createWebSocketServer((socket) => {
73
+ socket.once("message", (data) => {
74
+ requestBody = JSON.parse(data.toString())
75
+ socket.send(JSON.stringify({ type: "response.output_text.delta", delta: "hello" }))
76
+ socket.send(JSON.stringify({ type: "response.done", response: { id: "resp_123" } }))
77
+ socket.close(1000, "done")
78
+ })
79
+ })
80
+
81
+ const socket = await OpenAIWebSocket.connectResponsesWebSocket({
82
+ url: server.wsUrl,
83
+ headers: { authorization: "Bearer test", "content-length": "123" },
84
+ })
85
+ const completed: Record<string, unknown>[] = []
86
+ const response = OpenAIWebSocket.streamResponsesWebSocket({
87
+ socket,
88
+ body: { stream: true, background: true, input: "hi" },
89
+ onComplete: (event) => completed.push(event),
90
+ })
91
+
92
+ expect(await response.text()).toBe(
93
+ 'data: {"type":"response.output_text.delta","delta":"hello"}\n\ndata: {"type":"response.done","response":{"id":"resp_123"}}\n\ndata: [DONE]\n\n',
94
+ )
95
+ expect(requestBody).toEqual({ type: "response.create", input: "hi" })
96
+ expect(completed).toHaveLength(1)
97
+ expect(completed[0]?.type).toBe("response.done")
98
+ })
99
+
100
+ test("errors the SSE stream when the server closes before a terminal event", async () => {
101
+ const invalid: Error[] = []
102
+ await using server = await createWebSocketServer((socket) => {
103
+ socket.once("message", () => {
104
+ socket.close(1009, "payload too large")
105
+ })
106
+ })
107
+
108
+ const socket = await OpenAIWebSocket.connectResponsesWebSocket({ url: server.wsUrl, headers: {} })
109
+ const response = OpenAIWebSocket.streamResponsesWebSocket({
110
+ socket,
111
+ body: { stream: true, input: "hi" },
112
+ onConnectionInvalid: (error) => invalid.push(error),
113
+ })
114
+
115
+ expect((await readTextError(response.text())).message).toContain(
116
+ "WebSocket closed before response.completed (code 1009: message too big: payload too large)",
117
+ )
118
+ expect(invalid[0]).toBeInstanceOf(ProviderError.ResponseStreamError)
119
+ expect(invalid.map((error) => error.message)).toEqual([
120
+ "WebSocket closed before response.completed (code 1009: message too big: payload too large)",
121
+ ])
122
+ })
123
+
124
+ test("rejects unexpected binary websocket frames", async () => {
125
+ const invalid: string[] = []
126
+ await using server = await createWebSocketServer((socket) => {
127
+ socket.once("message", () => {
128
+ socket.send(Buffer.from("not json text"))
129
+ })
130
+ })
131
+
132
+ const socket = await OpenAIWebSocket.connectResponsesWebSocket({ url: server.wsUrl, headers: {} })
133
+ const response = OpenAIWebSocket.streamResponsesWebSocket({
134
+ socket,
135
+ body: { stream: true, input: "hi" },
136
+ onConnectionInvalid: (error) => invalid.push(error.message),
137
+ })
138
+
139
+ expect((await readTextError(response.text())).message).toContain("Unexpected binary WebSocket frame")
140
+ expect(invalid).toEqual(["Unexpected binary WebSocket frame"])
141
+ })
142
+ })
143
+
144
+ describe("plugin.openai.ws-pool", () => {
145
+ test("reuses one healthy websocket for sequential requests", async () => {
146
+ let connections = 0
147
+ let messages = 0
148
+ await using server = await createWebSocketServer((socket) => {
149
+ connections += 1
150
+ socket.on("message", () => {
151
+ messages += 1
152
+ socket.send(JSON.stringify({ type: "response.completed", response: { id: `resp_${messages}` } }))
153
+ })
154
+ })
155
+ const fetch = OpenAIWebSocketPool.createWebSocketFetch({
156
+ url: server.url,
157
+ })
158
+
159
+ const first = await fetch(server.url, streamRequest())
160
+ expect(await first.text()).toContain("data: [DONE]")
161
+
162
+ const second = await fetch(server.url, streamRequest())
163
+ expect(await second.text()).toContain("data: [DONE]")
164
+ expect(connections).toBe(1)
165
+ expect(messages).toBe(2)
166
+ fetch.close()
167
+ })
168
+
169
+ test("rotates a socket that exceeds max connection age", async () => {
170
+ let connections = 0
171
+ await using server = await createWebSocketServer((socket) => {
172
+ connections += 1
173
+ socket.on("message", () => {
174
+ socket.send(JSON.stringify({ type: "response.completed", response: { id: `resp_${connections}` } }))
175
+ })
176
+ })
177
+ const fetch = OpenAIWebSocketPool.createWebSocketFetch({
178
+ url: server.url,
179
+ maxConnectionAge: 0,
180
+ })
181
+
182
+ const first = await fetch(server.url, streamRequest())
183
+ expect(await first.text()).toContain("data: [DONE]")
184
+
185
+ const second = await fetch(server.url, streamRequest())
186
+ expect(await second.text()).toContain("data: [DONE]")
187
+ expect(connections).toBe(2)
188
+ fetch.close()
189
+ })
190
+
191
+ test("falls back to HTTP after websocket setup retries are exhausted", async () => {
192
+ const attempts: string[] = []
193
+ await using server = await createRejectingWebSocketServer(() => attempts.push("websocket"))
194
+ const fetch = OpenAIWebSocketPool.createWebSocketFetch({
195
+ url: server.url,
196
+ connectTimeout: 100,
197
+ streamRetries: 1,
198
+ })
199
+
200
+ const first = await fetch(server.url, streamRequest({ [TITLE_HEADER]: "false" }))
201
+ expect(await readTextError(first.text())).toBeInstanceOf(ProviderError.ResponseStreamError)
202
+ const second = await fetch(server.url, streamRequest({ [TITLE_HEADER]: "false" }))
203
+ const third = await fetch(server.url, streamRequest({ [TITLE_HEADER]: "false" }))
204
+
205
+ expect(await second.text()).toBe("http")
206
+ expect(await third.text()).toBe("http")
207
+ expect(attempts).toEqual(["websocket", "websocket"])
208
+ expect(server.httpRequests).toHaveLength(2)
209
+ expect(server.httpRequests[0]?.headers[TITLE_HEADER]).toBeUndefined()
210
+ expect(server.httpRequests[1]?.headers[TITLE_HEADER]).toBeUndefined()
211
+ fetch.close()
212
+ })
213
+
214
+ test("keeps HTTP fallback active after its idle timeout", async () => {
215
+ let websocketAttempts = 0
216
+ await using server = await createRejectingWebSocketServer(() => websocketAttempts++)
217
+ const fetch = OpenAIWebSocketPool.createWebSocketFetch({
218
+ url: server.url,
219
+ connectTimeout: 100,
220
+ idleTimeout: 20,
221
+ streamRetries: 0,
222
+ })
223
+
224
+ const first = await fetch(server.url, streamRequest())
225
+ expect(await first.text()).toBe("http")
226
+ await new Promise((resolve) => setTimeout(resolve, 50))
227
+ const second = await fetch(server.url, streamRequest())
228
+
229
+ expect(await second.text()).toBe("http")
230
+ expect(websocketAttempts).toBe(1)
231
+ expect(server.httpRequests).toHaveLength(2)
232
+ fetch.close()
233
+ })
234
+
235
+ test("removes HTTP fallback when its session is deleted", async () => {
236
+ let websocketAttempts = 0
237
+ await using server = await createRejectingWebSocketServer(() => websocketAttempts++)
238
+ const fetch = OpenAIWebSocketPool.createWebSocketFetch({
239
+ url: server.url,
240
+ connectTimeout: 100,
241
+ streamRetries: 0,
242
+ })
243
+
244
+ const first = await fetch(server.url, streamRequest())
245
+ expect(await first.text()).toBe("http")
246
+ fetch.remove("session-1")
247
+ const second = await fetch(server.url, streamRequest())
248
+
249
+ expect(await second.text()).toBe("http")
250
+ expect(websocketAttempts).toBe(2)
251
+ expect(server.httpRequests).toHaveLength(2)
252
+ fetch.close()
253
+ })
254
+
255
+ test("terminates active websocket connections when their session is deleted", async () => {
256
+ let connections = 0
257
+ await using server = await createWebSocketServer((socket) => {
258
+ connections += 1
259
+ socket.once("message", () => {
260
+ if (connections === 1) {
261
+ socket.send(JSON.stringify({ type: "response.output_text.delta", delta: "started" }))
262
+ return
263
+ }
264
+ socket.send(JSON.stringify({ type: "response.completed", response: { id: "resp_after_remove" } }))
265
+ })
266
+ })
267
+ const fetch = OpenAIWebSocketPool.createWebSocketFetch({
268
+ url: server.url,
269
+ })
270
+
271
+ const first = await fetch(server.url, streamRequest())
272
+ const firstText = first.text()
273
+ fetch.remove("session-1")
274
+ expect((await readTextError(firstText)).message).toContain("WebSocket closed before response.completed")
275
+
276
+ const second = await fetch(server.url, streamRequest())
277
+
278
+ expect(await second.text()).toContain("data: [DONE]")
279
+ expect(connections).toBe(2)
280
+ fetch.close()
281
+ })
282
+
283
+ test("prunes idle websocket connections after completed responses", async () => {
284
+ let connections = 0
285
+ let closed = 0
286
+ await using server = await createWebSocketServer((socket) => {
287
+ connections += 1
288
+ socket.once("close", () => closed++)
289
+ socket.once("message", () => {
290
+ socket.send(JSON.stringify({ type: "response.completed", response: { id: `resp_${connections}` } }))
291
+ })
292
+ })
293
+ const fetch = OpenAIWebSocketPool.createWebSocketFetch({
294
+ url: server.url,
295
+ idleTimeout: 20,
296
+ })
297
+
298
+ const first = await fetch(server.url, streamRequest())
299
+ expect(await first.text()).toContain("data: [DONE]")
300
+ await waitFor(() => closed === 1, "idle websocket was not pruned")
301
+
302
+ const second = await fetch(server.url, streamRequest())
303
+
304
+ expect(await second.text()).toContain("data: [DONE]")
305
+ expect(connections).toBe(2)
306
+ fetch.close()
307
+ })
308
+
309
+ test("invalidates but does not reuse a socket after terminal failure frames", async () => {
310
+ let connections = 0
311
+ await using server = await createWebSocketServer((socket) => {
312
+ connections += 1
313
+ socket.once("message", () => {
314
+ socket.send(JSON.stringify({ type: connections === 1 ? "response.failed" : "response.completed" }))
315
+ })
316
+ })
317
+ const fetch = OpenAIWebSocketPool.createWebSocketFetch({
318
+ url: server.url,
319
+ })
320
+
321
+ const first = await fetch(server.url, streamRequest())
322
+ expect(await first.text()).toContain('data: {"type":"response.failed"}')
323
+
324
+ const second = await fetch(server.url, streamRequest())
325
+ expect(await second.text()).toContain('data: {"type":"response.completed"}')
326
+ expect(connections).toBe(2)
327
+ expect(server.httpRequests).toHaveLength(0)
328
+ fetch.close()
329
+ })
330
+
331
+ test("returns initial websocket error frames as HTTP-style API errors", async () => {
332
+ const error = {
333
+ type: "invalid_request_error",
334
+ message: "The model is not supported when using Codex with a ChatGPT account.",
335
+ }
336
+ const event = {
337
+ type: "error",
338
+ status: 400,
339
+ error,
340
+ headers: {
341
+ "x-codex-primary-window-minutes": 15,
342
+ ignored: { nested: true },
343
+ },
344
+ }
345
+ await using server = await createWebSocketServer((socket) => {
346
+ socket.once("message", () => {
347
+ socket.send(JSON.stringify(event))
348
+ })
349
+ })
350
+ const fetch = OpenAIWebSocketPool.createWebSocketFetch({
351
+ url: server.url,
352
+ })
353
+
354
+ const response = await fetch(server.url, streamRequest())
355
+
356
+ expect(response.status).toBe(400)
357
+ expect(response.headers.get("content-type")).toContain("application/json")
358
+ expect(response.headers.get("x-codex-primary-window-minutes")).toBe("15")
359
+ expect(response.headers.get("ignored")).toBeNull()
360
+ expect(await response.json()).toEqual(event)
361
+ fetch.close()
362
+ })
363
+
364
+ test("fails mid-stream wrapped websocket errors as HTTP-style API errors", async () => {
365
+ const event = {
366
+ type: "error",
367
+ status_code: 429,
368
+ error: {
369
+ type: "usage_limit_reached",
370
+ message: "The usage limit has been reached",
371
+ },
372
+ headers: {
373
+ "x-codex-primary-used-percent": "100.0",
374
+ },
375
+ }
376
+ await using server = await createWebSocketServer((socket) => {
377
+ socket.once("message", () => {
378
+ socket.send(JSON.stringify({ type: "response.output_text.delta", delta: "started" }))
379
+ socket.send(JSON.stringify(event))
380
+ })
381
+ })
382
+ const fetch = OpenAIWebSocketPool.createWebSocketFetch({
383
+ url: server.url,
384
+ })
385
+
386
+ const response = await fetch(server.url, streamRequest())
387
+ const error = await readTextError(response.text())
388
+
389
+ expect(APICallError.isInstance(error)).toBe(true)
390
+ if (!APICallError.isInstance(error)) throw new Error("Expected APICallError")
391
+ expect(error.statusCode).toBe(429)
392
+ expect(error.responseHeaders).toEqual({ "x-codex-primary-used-percent": "100.0" })
393
+ expect(error.responseBody).toBe(JSON.stringify(event))
394
+ fetch.close()
395
+ })
396
+
397
+ test("retries websocket connection limit errors on the next stream attempt", async () => {
398
+ let connections = 0
399
+ let messages = 0
400
+ await using server = await createWebSocketServer((socket) => {
401
+ connections += 1
402
+ socket.once("message", () => {
403
+ messages += 1
404
+ if (connections === 1) {
405
+ socket.send(
406
+ JSON.stringify({
407
+ type: "error",
408
+ status: 400,
409
+ error: {
410
+ type: "invalid_request_error",
411
+ code: "websocket_connection_limit_reached",
412
+ message: "Responses websocket connection limit reached",
413
+ },
414
+ }),
415
+ )
416
+ return
417
+ }
418
+ socket.send(JSON.stringify({ type: "response.completed", response: { id: "resp_retry" } }))
419
+ })
420
+ })
421
+ const fetch = OpenAIWebSocketPool.createWebSocketFetch({
422
+ url: server.url,
423
+ })
424
+
425
+ const first = await fetch(server.url, streamRequest())
426
+ expect((await readTextError(first.text())).message).toContain("Responses websocket connection limit reached")
427
+ const second = await fetch(server.url, streamRequest())
428
+ const text = await second.text()
429
+
430
+ expect(text).not.toContain("websocket_connection_limit_reached")
431
+ expect(text).toContain('data: {"type":"response.completed","response":{"id":"resp_retry"}}')
432
+ expect(text).toContain("data: [DONE]")
433
+ expect(connections).toBe(2)
434
+ expect(messages).toBe(2)
435
+ expect(server.httpRequests).toHaveLength(0)
436
+ fetch.close()
437
+ })
438
+
439
+ test("falls back to HTTP after websocket connection limit retries are exhausted", async () => {
440
+ let connections = 0
441
+ await using server = await createWebSocketServer((socket) => {
442
+ connections += 1
443
+ socket.once("message", () => {
444
+ socket.send(
445
+ JSON.stringify({
446
+ type: "error",
447
+ status: 400,
448
+ error: {
449
+ type: "invalid_request_error",
450
+ code: "websocket_connection_limit_reached",
451
+ message: "Responses websocket connection limit reached",
452
+ },
453
+ }),
454
+ )
455
+ })
456
+ })
457
+ const fetch = OpenAIWebSocketPool.createWebSocketFetch({
458
+ url: server.url,
459
+ streamRetries: 2,
460
+ })
461
+
462
+ const first = await fetch(server.url, streamRequest())
463
+ expect((await readTextError(first.text())).message).toContain("Responses websocket connection limit reached")
464
+ const second = await fetch(server.url, streamRequest())
465
+ expect((await readTextError(second.text())).message).toContain("Responses websocket connection limit reached")
466
+ const third = await fetch(server.url, streamRequest())
467
+ const fourth = await fetch(server.url, streamRequest())
468
+
469
+ expect(await third.text()).toBe("http")
470
+ expect(await fourth.text()).toBe("http")
471
+ expect(connections).toBe(3)
472
+ expect(server.httpRequests).toHaveLength(2)
473
+ fetch.close()
474
+ })
475
+
476
+ test("shares the websocket retry budget across stream and connection limit failures", async () => {
477
+ let connections = 0
478
+ await using server = await createWebSocketServer((socket) => {
479
+ connections += 1
480
+ socket.once("message", () => {
481
+ if (connections === 1) {
482
+ socket.send(JSON.stringify({ type: "response.output_text.delta", delta: "started" }))
483
+ socket.terminate()
484
+ return
485
+ }
486
+ socket.send(
487
+ JSON.stringify({
488
+ type: "error",
489
+ error: {
490
+ code: "websocket_connection_limit_reached",
491
+ message: "Responses websocket connection limit reached",
492
+ },
493
+ }),
494
+ )
495
+ })
496
+ })
497
+ const fetch = OpenAIWebSocketPool.createWebSocketFetch({
498
+ url: server.url,
499
+ streamRetries: 1,
500
+ })
501
+
502
+ const first = await fetch(server.url, streamRequest())
503
+ expect((await readTextError(first.text())).message).toContain("WebSocket closed before response.completed")
504
+ const second = await fetch(server.url, streamRequest())
505
+
506
+ expect(await second.text()).toBe("http")
507
+ expect(connections).toBe(2)
508
+ expect(server.httpRequests).toHaveLength(1)
509
+ fetch.close()
510
+ })
511
+
512
+ test("retries websocket idle failures before first event then falls back to HTTP", async () => {
513
+ let connections = 0
514
+ await using server = await createWebSocketServer((socket) => {
515
+ connections += 1
516
+ socket.once("message", () => {})
517
+ })
518
+ const fetch = OpenAIWebSocketPool.createWebSocketFetch({
519
+ url: server.url,
520
+ idleTimeout: 20,
521
+ streamRetries: 1,
522
+ })
523
+
524
+ const first = await fetch(server.url, streamRequest())
525
+ expect((await readTextError(first.text())).message).toContain("idle timeout waiting for websocket")
526
+ const second = await fetch(server.url, streamRequest())
527
+ const third = await fetch(server.url, streamRequest())
528
+
529
+ expect(await second.text()).toBe("http")
530
+ expect(await third.text()).toBe("http")
531
+ expect(connections).toBe(2)
532
+ expect(server.httpRequests).toHaveLength(2)
533
+ fetch.close()
534
+ })
535
+
536
+ test("keeps websocket retry state until the failed stream becomes idle", async () => {
537
+ let connections = 0
538
+ await using server = await createWebSocketServer((socket) => {
539
+ connections += 1
540
+ socket.once("message", () => {})
541
+ })
542
+ const fetch = OpenAIWebSocketPool.createWebSocketFetch({
543
+ url: server.url,
544
+ idleTimeout: 500,
545
+ streamRetries: 1,
546
+ })
547
+
548
+ await new Promise((resolve) => setTimeout(resolve, 250))
549
+ const first = await fetch(server.url, streamRequest())
550
+ expect((await readTextError(first.text())).message).toContain("idle timeout waiting for websocket")
551
+ await new Promise((resolve) => setTimeout(resolve, 300))
552
+
553
+ const second = await fetch(server.url, streamRequest())
554
+
555
+ expect(await second.text()).toBe("http")
556
+ expect(connections).toBe(2)
557
+ expect(server.httpRequests).toHaveLength(1)
558
+ fetch.close()
559
+ })
560
+
561
+ test("retries failed websocket streams before using HTTP fallback", async () => {
562
+ await using server = await createWebSocketServer((socket) => {
563
+ socket.once("message", () => {
564
+ socket.send(JSON.stringify({ type: "response.output_text.delta", delta: "started" }))
565
+ })
566
+ })
567
+ const fetch = OpenAIWebSocketPool.createWebSocketFetch({
568
+ url: server.url,
569
+ idleTimeout: 20,
570
+ streamRetries: 1,
571
+ })
572
+
573
+ const first = await fetch(server.url, streamRequest())
574
+ expect((await readTextError(first.text())).message).toContain("idle timeout waiting for websocket")
575
+ const second = await fetch(server.url, streamRequest())
576
+ expect((await readTextError(second.text())).message).toContain("idle timeout waiting for websocket")
577
+ const third = await fetch(server.url, streamRequest())
578
+
579
+ expect(await third.text()).toBe("http")
580
+ expect(server.httpRequests).toHaveLength(1)
581
+ fetch.close()
582
+ })
583
+
584
+ test("resets websocket stream failures after a completed response", async () => {
585
+ let connections = 0
586
+ let requests = 0
587
+ await using server = await createWebSocketServer((socket) => {
588
+ connections += 1
589
+ socket.on("message", () => {
590
+ requests += 1
591
+ if (requests === 1 || requests === 3) {
592
+ socket.send(JSON.stringify({ type: "response.output_text.delta", delta: "started" }))
593
+ socket.terminate()
594
+ return
595
+ }
596
+ socket.send(JSON.stringify({ type: "response.completed", response: { id: `resp_${requests}` } }))
597
+ })
598
+ })
599
+ const fetch = OpenAIWebSocketPool.createWebSocketFetch({
600
+ url: server.url,
601
+ streamRetries: 1,
602
+ })
603
+
604
+ const first = await fetch(server.url, streamRequest())
605
+ expect((await readTextError(first.text())).message).toContain("WebSocket closed before response.completed")
606
+ const second = await fetch(server.url, streamRequest())
607
+ expect(await second.text()).toContain("data: [DONE]")
608
+ const third = await fetch(server.url, streamRequest())
609
+ expect((await readTextError(third.text())).message).toContain("WebSocket closed before response.completed")
610
+ const fourth = await fetch(server.url, streamRequest())
611
+
612
+ expect(await fourth.text()).toContain("data: [DONE]")
613
+ expect(connections).toBe(3)
614
+ expect(requests).toBe(4)
615
+ expect(server.httpRequests).toHaveLength(0)
616
+ fetch.close()
617
+ })
618
+
619
+ test("falls back to HTTP for missing session and title requests", async () => {
620
+ await using server = await createWebSocketServer(() => {})
621
+ const fetch = OpenAIWebSocketPool.createWebSocketFetch()
622
+
623
+ const missingSession = await fetch(server.url, {
624
+ method: "POST",
625
+ headers: { [TITLE_HEADER]: "false" },
626
+ body: JSON.stringify({ stream: true }),
627
+ })
628
+ const title = await fetch(server.url, streamRequest({ [TITLE_HEADER]: "true" }))
629
+
630
+ expect(await missingSession.text()).toBe("http")
631
+ expect(await title.text()).toBe("http")
632
+ expect(server.httpRequests).toHaveLength(2)
633
+ expect(server.httpRequests[0]?.headers[TITLE_HEADER]).toBeUndefined()
634
+ expect(server.httpRequests[1]?.headers[TITLE_HEADER]).toBeUndefined()
635
+ fetch.close()
636
+ })
637
+
638
+ test("falls back to HTTP while a websocket lane is busy", async () => {
639
+ let connections = 0
640
+ await using server = await createWebSocketServer((socket) => {
641
+ connections += 1
642
+ socket.once("message", () => {
643
+ socket.send(JSON.stringify({ type: "response.output_text.delta", delta: "started" }))
644
+ })
645
+ })
646
+ const abort = new AbortController()
647
+ const fetch = OpenAIWebSocketPool.createWebSocketFetch({
648
+ url: server.url,
649
+ })
650
+
651
+ const first = await fetch(server.url, streamRequest({}, abort.signal))
652
+ const firstText = first.text()
653
+ await waitFor(() => connections === 1, "websocket did not connect")
654
+ const second = await fetch(server.url, streamRequest())
655
+
656
+ expect(await second.text()).toBe("http")
657
+ expect(server.httpRequests).toHaveLength(1)
658
+ expect(connections).toBe(1)
659
+ abort.abort(new Error("stop"))
660
+ expect((await readTextError(firstText)).message).toContain("stop")
661
+ fetch.close()
662
+ })
663
+
664
+ test("reserves a websocket lane while its socket is connecting", async () => {
665
+ await using server = await createHangingTcpServer()
666
+ await using fallback = await createHttpServer()
667
+ const fetch = OpenAIWebSocketPool.createWebSocketFetch({
668
+ url: server.url,
669
+ connectTimeout: 20,
670
+ streamRetries: 0,
671
+ })
672
+
673
+ const first = fetch(fallback.url, streamRequest())
674
+ await waitFor(() => server.connections() === 1, "first websocket did not begin connecting")
675
+ const second = fetch(fallback.url, streamRequest())
676
+
677
+ expect(await (await second).text()).toBe("http")
678
+ expect(await (await first).text()).toBe("http")
679
+ expect(server.connections()).toBe(1)
680
+ expect(fallback.httpRequests).toHaveLength(2)
681
+ fetch.close()
682
+ })
683
+
684
+ test("retries unexpected closes before first event then falls back to HTTP", async () => {
685
+ let connections = 0
686
+ await using server = await createWebSocketServer((socket) => {
687
+ connections += 1
688
+ socket.once("message", () => {
689
+ socket.close(1001, "server shutdown")
690
+ })
691
+ })
692
+ const fetch = OpenAIWebSocketPool.createWebSocketFetch({
693
+ url: server.url,
694
+ streamRetries: 1,
695
+ })
696
+
697
+ const first = await fetch(server.url, streamRequest())
698
+ expect((await readTextError(first.text())).message).toContain("WebSocket closed before response.completed")
699
+ const second = await fetch(server.url, streamRequest())
700
+ const third = await fetch(server.url, streamRequest())
701
+
702
+ expect(await second.text()).toBe("http")
703
+ expect(await third.text()).toBe("http")
704
+ expect(connections).toBe(2)
705
+ expect(server.httpRequests).toHaveLength(2)
706
+ fetch.close()
707
+ })
708
+
709
+ test("does not keep HTTP fallback active after aborting a websocket response", async () => {
710
+ let connections = 0
711
+ await using server = await createWebSocketServer((socket) => {
712
+ connections += 1
713
+ socket.once("message", () => {
714
+ if (connections === 1) {
715
+ socket.send(JSON.stringify({ type: "response.output_text.delta", delta: "started" }))
716
+ return
717
+ }
718
+ socket.send(JSON.stringify({ type: "response.completed", response: { id: "resp_456" } }))
719
+ })
720
+ })
721
+ const abort = new AbortController()
722
+ const fetch = OpenAIWebSocketPool.createWebSocketFetch({
723
+ url: server.url,
724
+ })
725
+
726
+ const first = await fetch(server.url, streamRequest({}, abort.signal))
727
+ const firstText = first.text()
728
+ await waitFor(() => connections === 1, "first websocket did not connect")
729
+ abort.abort(new Error("stop"))
730
+ expect((await readTextError(firstText)).message).toContain("stop")
731
+
732
+ const second = await fetch(server.url, streamRequest())
733
+
734
+ expect(await second.text()).toContain("data: [DONE]")
735
+ expect(connections).toBe(2)
736
+ expect(server.httpRequests).toHaveLength(0)
737
+ fetch.close()
738
+ })
739
+
740
+ test("releases the websocket lane when the response body is cancelled", async () => {
741
+ let connections = 0
742
+ await using server = await createWebSocketServer((socket) => {
743
+ connections += 1
744
+ socket.once("message", () => {
745
+ if (connections === 1) {
746
+ socket.send(JSON.stringify({ type: "response.output_text.delta", delta: "started" }))
747
+ return
748
+ }
749
+ socket.send(JSON.stringify({ type: "response.completed", response: { id: "resp_after_cancel" } }))
750
+ })
751
+ })
752
+ const fetch = OpenAIWebSocketPool.createWebSocketFetch({
753
+ url: server.url,
754
+ })
755
+
756
+ const first = await fetch(server.url, streamRequest())
757
+ await waitFor(() => connections === 1, "first websocket did not connect")
758
+ await first.body!.cancel("stop")
759
+
760
+ const second = await fetch(server.url, streamRequest())
761
+
762
+ expect(await second.text()).toContain("data: [DONE]")
763
+ expect(connections).toBe(2)
764
+ expect(server.httpRequests).toHaveLength(0)
765
+ fetch.close()
766
+ })
767
+ })
768
+
769
+ function streamRequest(headers?: Record<string, string>, signal?: AbortSignal): RequestInit {
770
+ return {
771
+ method: "POST",
772
+ headers: {
773
+ "session-id": "session-1",
774
+ authorization: "Bearer test",
775
+ ...headers,
776
+ },
777
+ body: JSON.stringify({ stream: true, input: "hi" }),
778
+ signal,
779
+ }
780
+ }
781
+
782
+ async function readTextError(promise: Promise<string>) {
783
+ // Bun 1.3.14 hangs on expect(response.text()).rejects for streams errored from ws callbacks.
784
+ return promise.then(
785
+ () => {
786
+ throw new Error("Expected response text to reject")
787
+ },
788
+ (error) => {
789
+ expect(error).toBeInstanceOf(Error)
790
+ return error as Error
791
+ },
792
+ )
793
+ }
794
+
795
+ async function createWebSocketServer(onConnection: (socket: WebSocket, request: IncomingMessage) => void) {
796
+ const http = await createHttpServer()
797
+ const server = new WebSocketServer({ server: http.server })
798
+ server.on("connection", onConnection)
799
+ return websocketServerHandle(server, http)
800
+ }
801
+
802
+ async function createHangingTcpServer() {
803
+ const sockets = new Set<Socket>()
804
+ let connections = 0
805
+ const server = net.createServer((socket) => {
806
+ connections += 1
807
+ sockets.add(socket)
808
+ socket.on("close", () => sockets.delete(socket))
809
+ })
810
+ await new Promise<void>((resolve) => server.listen(0, "127.0.0.1", resolve))
811
+ const address = server.address() as AddressInfo
812
+ return {
813
+ url: `http://127.0.0.1:${address.port}/v1/responses`,
814
+ wsUrl: `ws://127.0.0.1:${address.port}/v1/responses`,
815
+ connections: () => connections,
816
+ async [Symbol.asyncDispose]() {
817
+ for (const socket of sockets) socket.destroy()
818
+ server.close()
819
+ },
820
+ }
821
+ }
822
+
823
+ async function createRejectingWebSocketServer(onAttempt: () => void) {
824
+ const http = await createHttpServer()
825
+ const server = new WebSocketServer({
826
+ server: http.server,
827
+ verifyClient(_info, callback) {
828
+ onAttempt()
829
+ callback(false, 401, "denied")
830
+ },
831
+ })
832
+ return websocketServerHandle(server, http)
833
+ }
834
+
835
+ async function createHttpServer() {
836
+ const httpRequests: IncomingMessage[] = []
837
+ const server = createServer((request, response) => {
838
+ httpRequests.push(request)
839
+ response.writeHead(200, { "content-type": "text/plain" })
840
+ response.end("http")
841
+ })
842
+ await new Promise<void>((resolve) => server.listen(0, "127.0.0.1", resolve))
843
+ const address = server.address() as AddressInfo
844
+ return {
845
+ server,
846
+ httpRequests,
847
+ url: `http://127.0.0.1:${address.port}/v1/responses`,
848
+ async [Symbol.asyncDispose]() {
849
+ await closeHttpServer(server)
850
+ },
851
+ }
852
+ }
853
+
854
+ function websocketServerHandle(server: WebSocketServer, http: Awaited<ReturnType<typeof createHttpServer>>) {
855
+ return {
856
+ url: http.url,
857
+ wsUrl: http.url.replace(/^http/, "ws"),
858
+ httpRequests: http.httpRequests,
859
+ async [Symbol.asyncDispose]() {
860
+ for (const socket of server.clients) socket.terminate()
861
+ server.close()
862
+ http.server.close()
863
+ },
864
+ }
865
+ }
866
+
867
+ function closeHttpServer(server: HttpServer) {
868
+ return new Promise<void>((resolve, reject) => server.close((error) => (error ? reject(error) : resolve())))
869
+ }
870
+
871
+ async function waitFor(predicate: () => boolean, message: string) {
872
+ const started = Date.now()
873
+ while (!predicate()) {
874
+ if (Date.now() - started > 1_000) throw new Error(message)
875
+ await new Promise((resolve) => setTimeout(resolve, 1))
876
+ }
877
+ }