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,742 @@
1
+ import type { Hooks, PluginInput } from "@opencode-ai/plugin"
2
+ import * as Log from "@opencode-ai/core/util/log"
3
+ import { OAUTH_DUMMY_KEY } from "../auth"
4
+ import { createServer } from "http"
5
+ import { InstallationVersion } from "@opencode-ai/core/installation/version"
6
+
7
+ const log = Log.create({ service: "plugin.xai" })
8
+
9
+ // Public Grok-CLI OAuth client. xAI's auth server rejects loopback OAuth from
10
+ // non-allowlisted clients, so we reuse the Grok-CLI client_id that xAI ships
11
+ // for desktop OAuth flows. Source of truth: hermes-agent PR #26534.
12
+ const CLIENT_ID = "b1a00492-073a-47ea-816f-4c329264a828"
13
+ const AUTHORIZE_URL = "https://auth.x.ai/oauth2/authorize"
14
+ const TOKEN_URL = "https://auth.x.ai/oauth2/token"
15
+ // RFC 8628 device authorization grant. Confirmed exposed by xAI's
16
+ // /.well-known/openid-configuration as `device_authorization_endpoint`
17
+ // with the matching `urn:ietf:params:oauth:grant-type:device_code` grant
18
+ // in `grant_types_supported`. This is the headless / VPS path: no
19
+ // loopback callback server, no SSH port forwarding, no inbound firewall
20
+ // holes — the user opens the URL on any device with a browser, types
21
+ // the short user_code, and the CLI long-polls the token endpoint.
22
+ const DEVICE_AUTHORIZATION_URL = "https://auth.x.ai/oauth2/device/code"
23
+ const DEVICE_CODE_GRANT_TYPE = "urn:ietf:params:oauth:grant-type:device_code"
24
+ const SCOPE = "openid profile email offline_access grok-cli:access api:access"
25
+
26
+ // Bounds for the device-code poll loop. xAI returns `interval` (seconds)
27
+ // but we floor it to avoid hammering and we add the spec's slow_down
28
+ // increment when xAI explicitly asks us to back off.
29
+ const DEVICE_CODE_DEFAULT_INTERVAL_MS = 5_000
30
+ const DEVICE_CODE_MIN_INTERVAL_MS = 1_000
31
+ const DEVICE_CODE_SLOW_DOWN_INCREMENT_MS = 5_000
32
+ const DEVICE_CODE_DEFAULT_EXPIRES_MS = 5 * 60 * 1000
33
+ const OAUTH_POLLING_SAFETY_MARGIN_MS = 3_000
34
+
35
+ // xAI rejects redirect_uris that don't match what was registered for the
36
+ // Grok-CLI client. The host:port pair is part of the registration, so we have
37
+ // to bind the loopback server to this exact port.
38
+ const OAUTH_HOST = "127.0.0.1"
39
+ const OAUTH_PORT = 56121
40
+ const OAUTH_REDIRECT_PATH = "/callback"
41
+ const REDIRECT_URI = `http://${OAUTH_HOST}:${OAUTH_PORT}${OAUTH_REDIRECT_PATH}`
42
+
43
+ // Refresh the access token a little before it actually expires so a single
44
+ // long-running tool call doesn't have to recover from a mid-flight 401.
45
+ const ACCESS_TOKEN_REFRESH_SKEW_MS = 120_000
46
+
47
+ interface XaiAuthPluginOptions {
48
+ authorizeUrl?: string
49
+ tokenUrl?: string
50
+ deviceAuthorizationUrl?: string
51
+ }
52
+
53
+ interface PkceCodes {
54
+ verifier: string
55
+ challenge: string
56
+ }
57
+
58
+ async function generatePKCE(): Promise<PkceCodes> {
59
+ const verifier = generateRandomString(64)
60
+ const hash = await crypto.subtle.digest("SHA-256", new TextEncoder().encode(verifier))
61
+ return { verifier, challenge: base64UrlEncode(hash) }
62
+ }
63
+
64
+ function generateRandomString(length: number): string {
65
+ const chars = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789-._~"
66
+ return Array.from(crypto.getRandomValues(new Uint8Array(length)))
67
+ .map((b) => chars[b % chars.length])
68
+ .join("")
69
+ }
70
+
71
+ function base64UrlEncode(buffer: ArrayBuffer): string {
72
+ const binary = String.fromCharCode(...new Uint8Array(buffer))
73
+ return btoa(binary).replace(/\+/g, "-").replace(/\//g, "_").replace(/=+$/, "")
74
+ }
75
+
76
+ function generateState(): string {
77
+ return base64UrlEncode(crypto.getRandomValues(new Uint8Array(32)).buffer)
78
+ }
79
+
80
+ export function escapeHtml(value: string): string {
81
+ return value.replace(/[&<>"']/g, (char) => {
82
+ switch (char) {
83
+ case "&":
84
+ return "&amp;"
85
+ case "<":
86
+ return "&lt;"
87
+ case ">":
88
+ return "&gt;"
89
+ case '"':
90
+ return "&quot;"
91
+ case "'":
92
+ return "&#39;"
93
+ default:
94
+ return char
95
+ }
96
+ })
97
+ }
98
+
99
+ interface TokenResponse {
100
+ access_token: string
101
+ refresh_token: string
102
+ id_token?: string
103
+ token_type?: string
104
+ expires_in?: number
105
+ scope?: string
106
+ }
107
+
108
+ function authHeaders() {
109
+ return {
110
+ "Content-Type": "application/x-www-form-urlencoded",
111
+ Accept: "application/json",
112
+ "User-Agent": `opencode/${InstallationVersion}`,
113
+ }
114
+ }
115
+
116
+ // Parse the `exp` claim out of a JWT access_token without verifying the
117
+ // signature. We only use this to decide whether to proactively refresh, never
118
+ // to make trust decisions, so unsigned decode is safe. Returns false for
119
+ // opaque tokens (no JWT shape), which conservatively skips the proactive
120
+ // refresh and lets the 401-on-call path drive the refresh instead.
121
+ export function accessTokenIsExpiring(
122
+ token: string | undefined,
123
+ skewMs: number = ACCESS_TOKEN_REFRESH_SKEW_MS,
124
+ ): boolean {
125
+ if (!token || typeof token !== "string") return false
126
+ const parts = token.split(".")
127
+ if (parts.length < 2) return false
128
+ try {
129
+ let payload = parts[1].replace(/-/g, "+").replace(/_/g, "/")
130
+ while (payload.length % 4 !== 0) payload += "="
131
+ const claims = JSON.parse(Buffer.from(payload, "base64").toString("utf8"))
132
+ if (typeof claims?.exp !== "number") return false
133
+ return claims.exp * 1000 <= Date.now() + Math.max(0, skewMs)
134
+ } catch {
135
+ return false
136
+ }
137
+ }
138
+
139
+ export function buildAuthorizeUrl(
140
+ pkce: PkceCodes,
141
+ state: string,
142
+ nonce: string,
143
+ options: XaiAuthPluginOptions = {},
144
+ ): string {
145
+ // `plan=generic` opts the consent screen into xAI's generic OAuth plan tier;
146
+ // without it, accounts.x.ai rejects loopback OAuth from non-allowlisted
147
+ // clients. `referrer=opencode` lets xAI attribute opencode-originated
148
+ // logins in their OAuth server logs (best-effort attribution while we
149
+ // continue to reuse the Grok-CLI client_id).
150
+ const params = new URLSearchParams({
151
+ response_type: "code",
152
+ client_id: CLIENT_ID,
153
+ redirect_uri: REDIRECT_URI,
154
+ scope: SCOPE,
155
+ code_challenge: pkce.challenge,
156
+ code_challenge_method: "S256",
157
+ state,
158
+ nonce,
159
+ plan: "generic",
160
+ referrer: "opencode",
161
+ })
162
+ return `${options.authorizeUrl ?? AUTHORIZE_URL}?${params.toString()}`
163
+ }
164
+
165
+ async function exchangeCodeForTokens(
166
+ code: string,
167
+ pkce: PkceCodes,
168
+ options: XaiAuthPluginOptions = {},
169
+ ): Promise<TokenResponse> {
170
+ const response = await fetch(options.tokenUrl ?? TOKEN_URL, {
171
+ method: "POST",
172
+ headers: authHeaders(),
173
+ body: new URLSearchParams({
174
+ grant_type: "authorization_code",
175
+ code,
176
+ redirect_uri: REDIRECT_URI,
177
+ client_id: CLIENT_ID,
178
+ code_verifier: pkce.verifier,
179
+ }).toString(),
180
+ })
181
+ if (!response.ok) {
182
+ const detail = await response.text().catch(() => "")
183
+ throw new Error(`xAI token exchange failed (${response.status})${detail ? `: ${detail}` : ""}`)
184
+ }
185
+ return response.json() as Promise<TokenResponse>
186
+ }
187
+
188
+ async function refreshAccessToken(refreshToken: string, options: XaiAuthPluginOptions = {}): Promise<TokenResponse> {
189
+ const response = await fetch(options.tokenUrl ?? TOKEN_URL, {
190
+ method: "POST",
191
+ headers: authHeaders(),
192
+ body: new URLSearchParams({
193
+ grant_type: "refresh_token",
194
+ refresh_token: refreshToken,
195
+ client_id: CLIENT_ID,
196
+ }).toString(),
197
+ })
198
+ if (!response.ok) {
199
+ const detail = await response.text().catch(() => "")
200
+ throw new Error(`xAI token refresh failed (${response.status})${detail ? `: ${detail}` : ""}`)
201
+ }
202
+ return response.json() as Promise<TokenResponse>
203
+ }
204
+
205
+ export interface DeviceCodeResponse {
206
+ device_code: string
207
+ user_code: string
208
+ verification_uri: string
209
+ verification_uri_complete?: string
210
+ expires_in?: number
211
+ interval?: number
212
+ }
213
+
214
+ interface DeviceTokenErrorBody {
215
+ error?: string
216
+ error_description?: string
217
+ }
218
+
219
+ export async function requestDeviceCode(options: XaiAuthPluginOptions = {}): Promise<DeviceCodeResponse> {
220
+ const response = await fetch(options.deviceAuthorizationUrl ?? DEVICE_AUTHORIZATION_URL, {
221
+ method: "POST",
222
+ headers: authHeaders(),
223
+ body: new URLSearchParams({
224
+ client_id: CLIENT_ID,
225
+ scope: SCOPE,
226
+ }).toString(),
227
+ })
228
+ if (!response.ok) {
229
+ const detail = await response.text().catch(() => "")
230
+ throw new Error(`xAI device code request failed (${response.status})${detail ? `: ${detail}` : ""}`)
231
+ }
232
+ const json = (await response.json()) as DeviceCodeResponse
233
+ if (!json.device_code || !json.user_code || !json.verification_uri) {
234
+ throw new Error("xAI device code response is missing device_code / user_code / verification_uri")
235
+ }
236
+ return json
237
+ }
238
+
239
+ // Default sleep used between device-code polls. Test-injectable so we can
240
+ // exercise authorization_pending / slow_down branches without real waits.
241
+ async function defaultSleep(ms: number): Promise<void> {
242
+ await new Promise<void>((resolve) => setTimeout(resolve, ms))
243
+ }
244
+
245
+ // Normalize a server-supplied seconds value to milliseconds, falling back to
246
+ // the supplied default when the input is missing, non-positive, or not a
247
+ // finite number. Defends the polling loop against garbage like `NaN`, `"NaN"`,
248
+ // `null`, or `-5` from a misbehaving device-code endpoint — without this,
249
+ // a NaN interval would slip through `?? default` (NaN is typeof number),
250
+ // reach `setTimeout(_, NaN)` which is treated as 0, and busy-loop until the
251
+ // hard deadline. Matches the defensive normalization Codex uses for the same
252
+ // field (`parseInt(deviceData.interval) || 5`).
253
+ function positiveSecondsToMs(value: unknown, defaultMs: number): number {
254
+ const seconds = Number(value)
255
+ return Number.isFinite(seconds) && seconds > 0 ? seconds * 1000 : defaultMs
256
+ }
257
+
258
+ export async function pollDeviceCodeToken(
259
+ device: DeviceCodeResponse,
260
+ options: XaiAuthPluginOptions & { sleep?: (ms: number) => Promise<void>; now?: () => number } = {},
261
+ ): Promise<TokenResponse> {
262
+ const sleep = options.sleep ?? defaultSleep
263
+ const now = options.now ?? (() => Date.now())
264
+ const expiresInMs = positiveSecondsToMs(device.expires_in, DEVICE_CODE_DEFAULT_EXPIRES_MS)
265
+ const deadline = now() + expiresInMs
266
+ let intervalMs = Math.max(
267
+ positiveSecondsToMs(device.interval, DEVICE_CODE_DEFAULT_INTERVAL_MS),
268
+ DEVICE_CODE_MIN_INTERVAL_MS,
269
+ )
270
+
271
+ while (now() < deadline) {
272
+ const response = await fetch(options.tokenUrl ?? TOKEN_URL, {
273
+ method: "POST",
274
+ headers: authHeaders(),
275
+ body: new URLSearchParams({
276
+ grant_type: DEVICE_CODE_GRANT_TYPE,
277
+ client_id: CLIENT_ID,
278
+ device_code: device.device_code,
279
+ }).toString(),
280
+ })
281
+ if (response.ok) return (await response.json()) as TokenResponse
282
+
283
+ const body = (await response.json().catch(() => ({}))) as DeviceTokenErrorBody
284
+ const remaining = Math.max(0, deadline - now())
285
+ // RFC 8628 §3.5: authorization_pending = keep polling at the same
286
+ // interval; slow_down = bump the interval by ≥5s and keep polling.
287
+ // Anything else is terminal.
288
+ if (body.error === "authorization_pending") {
289
+ await sleep(Math.min(intervalMs + OAUTH_POLLING_SAFETY_MARGIN_MS, remaining))
290
+ continue
291
+ }
292
+ if (body.error === "slow_down") {
293
+ intervalMs += DEVICE_CODE_SLOW_DOWN_INCREMENT_MS
294
+ await sleep(Math.min(intervalMs + OAUTH_POLLING_SAFETY_MARGIN_MS, remaining))
295
+ continue
296
+ }
297
+ if (body.error === "access_denied" || body.error === "authorization_denied") {
298
+ throw new Error("xAI device authorization was denied")
299
+ }
300
+ if (body.error === "expired_token") {
301
+ throw new Error("xAI device code expired - please re-run login")
302
+ }
303
+ const detail = body.error_description ?? body.error ?? ""
304
+ throw new Error(`xAI device token exchange failed (${response.status})${detail ? `: ${detail}` : ""}`)
305
+ }
306
+ throw new Error("xAI device authorization timed out")
307
+ }
308
+
309
+ const HTML_SUCCESS = `<!doctype html>
310
+ <html>
311
+ <head>
312
+ <title>OpenCode - xAI Authorization Successful</title>
313
+ <style>
314
+ body {
315
+ font-family:
316
+ system-ui,
317
+ -apple-system,
318
+ sans-serif;
319
+ display: flex;
320
+ justify-content: center;
321
+ align-items: center;
322
+ height: 100vh;
323
+ margin: 0;
324
+ background: #131010;
325
+ color: #f1ecec;
326
+ }
327
+ .container {
328
+ text-align: center;
329
+ padding: 2rem;
330
+ }
331
+ h1 {
332
+ color: #f1ecec;
333
+ margin-bottom: 1rem;
334
+ }
335
+ p {
336
+ color: #b7b1b1;
337
+ }
338
+ </style>
339
+ </head>
340
+ <body>
341
+ <div class="container">
342
+ <h1>Authorization Successful</h1>
343
+ <p>You can close this window and return to OpenCode.</p>
344
+ </div>
345
+ <script>
346
+ setTimeout(() => window.close(), 2000)
347
+ </script>
348
+ </body>
349
+ </html>`
350
+
351
+ const HTML_ERROR = (error: string) => `<!doctype html>
352
+ <html>
353
+ <head>
354
+ <title>OpenCode - xAI Authorization Failed</title>
355
+ <style>
356
+ body {
357
+ font-family:
358
+ system-ui,
359
+ -apple-system,
360
+ sans-serif;
361
+ display: flex;
362
+ justify-content: center;
363
+ align-items: center;
364
+ height: 100vh;
365
+ margin: 0;
366
+ background: #131010;
367
+ color: #f1ecec;
368
+ }
369
+ .container {
370
+ text-align: center;
371
+ padding: 2rem;
372
+ }
373
+ h1 {
374
+ color: #fc533a;
375
+ margin-bottom: 1rem;
376
+ }
377
+ p {
378
+ color: #b7b1b1;
379
+ }
380
+ .error {
381
+ color: #ff917b;
382
+ font-family: monospace;
383
+ margin-top: 1rem;
384
+ padding: 1rem;
385
+ background: #3c140d;
386
+ border-radius: 0.5rem;
387
+ }
388
+ </style>
389
+ </head>
390
+ <body>
391
+ <div class="container">
392
+ <h1>Authorization Failed</h1>
393
+ <p>An error occurred during authorization.</p>
394
+ <div class="error">${escapeHtml(error)}</div>
395
+ </div>
396
+ </body>
397
+ </html>`
398
+
399
+ // CORS allowlist for the loopback callback. The redirect_uri itself is
400
+ // already bound to 127.0.0.1 and gated by PKCE+state, so we only accept
401
+ // xAI's own auth origins for additional defense-in-depth on the OPTIONS
402
+ // preflight.
403
+ const CORS_ALLOWED_ORIGINS = new Set(["https://accounts.x.ai", "https://auth.x.ai"])
404
+
405
+ interface PendingOAuth {
406
+ pkce: PkceCodes
407
+ state: string
408
+ resolve: (tokens: TokenResponse) => void
409
+ reject: (error: Error) => void
410
+ }
411
+
412
+ let oauthServer: ReturnType<typeof createServer> | undefined
413
+ let pendingOAuth: PendingOAuth | undefined
414
+
415
+ async function startOAuthServer(): Promise<{ port: number; redirectUri: string }> {
416
+ if (oauthServer) return { port: OAUTH_PORT, redirectUri: REDIRECT_URI }
417
+
418
+ const server = createServer((req, res) => {
419
+ const reqUrl = req.url || "/"
420
+ const url = new URL(reqUrl, `http://${OAUTH_HOST}:${OAUTH_PORT}`)
421
+
422
+ const origin = req.headers["origin"]
423
+ const allowOrigin = typeof origin === "string" && CORS_ALLOWED_ORIGINS.has(origin) ? origin : ""
424
+ if (allowOrigin) {
425
+ res.setHeader("Access-Control-Allow-Origin", allowOrigin)
426
+ res.setHeader("Access-Control-Allow-Methods", "GET, OPTIONS")
427
+ res.setHeader("Access-Control-Allow-Headers", "Content-Type")
428
+ res.setHeader("Access-Control-Allow-Private-Network", "true")
429
+ res.setHeader("Vary", "Origin")
430
+ }
431
+
432
+ if (req.method === "OPTIONS") {
433
+ res.writeHead(204)
434
+ res.end()
435
+ return
436
+ }
437
+
438
+ if (url.pathname === OAUTH_REDIRECT_PATH) {
439
+ const code = url.searchParams.get("code")
440
+ const state = url.searchParams.get("state")
441
+ const error = url.searchParams.get("error")
442
+ const errorDescription = url.searchParams.get("error_description")
443
+
444
+ if (error) {
445
+ const errorMsg = errorDescription || error
446
+ pendingOAuth?.reject(new Error(errorMsg))
447
+ pendingOAuth = undefined
448
+ res.writeHead(200, { "Content-Type": "text/html" })
449
+ res.end(HTML_ERROR(errorMsg))
450
+ return
451
+ }
452
+
453
+ if (!code) {
454
+ const errorMsg = "Missing authorization code"
455
+ pendingOAuth?.reject(new Error(errorMsg))
456
+ pendingOAuth = undefined
457
+ res.writeHead(400, { "Content-Type": "text/html" })
458
+ res.end(HTML_ERROR(errorMsg))
459
+ return
460
+ }
461
+
462
+ if (!pendingOAuth || state !== pendingOAuth.state) {
463
+ const errorMsg = "Invalid state - potential CSRF attack"
464
+ pendingOAuth?.reject(new Error(errorMsg))
465
+ pendingOAuth = undefined
466
+ res.writeHead(400, { "Content-Type": "text/html" })
467
+ res.end(HTML_ERROR(errorMsg))
468
+ return
469
+ }
470
+
471
+ const current = pendingOAuth
472
+ pendingOAuth = undefined
473
+
474
+ exchangeCodeForTokens(code, current.pkce)
475
+ .then((tokens) => current.resolve(tokens))
476
+ .catch((err) => current.reject(err))
477
+
478
+ res.writeHead(200, { "Content-Type": "text/html" })
479
+ res.end(HTML_SUCCESS)
480
+ return
481
+ }
482
+
483
+ if (url.pathname === "/cancel") {
484
+ pendingOAuth?.reject(new Error("Login cancelled"))
485
+ pendingOAuth = undefined
486
+ res.writeHead(200)
487
+ res.end("Login cancelled")
488
+ return
489
+ }
490
+
491
+ res.writeHead(404)
492
+ res.end("Not found")
493
+ })
494
+
495
+ // listen() failures (e.g. EADDRINUSE because Grok-CLI is bound to the same
496
+ // pinned port) must clear `oauthServer` and remove our error listener,
497
+ // otherwise the next startOAuthServer() short-circuits on the truthy check
498
+ // and returns a redirect_uri pointing at nothing.
499
+ await new Promise<void>((resolve, reject) => {
500
+ const onError = (err: Error) => {
501
+ oauthServer = undefined
502
+ reject(err)
503
+ }
504
+ server.once("error", onError)
505
+ server.listen(OAUTH_PORT, OAUTH_HOST, () => {
506
+ server.removeListener("error", onError)
507
+ // After listen() succeeds, install a permanent log-only listener so
508
+ // that subsequent server errors (e.g. accept() failures, socket-level
509
+ // errors) don't trip Node's default "unhandled error event = throw"
510
+ // behavior and crash the entire opencode process. Matches the silent-
511
+ // swallow behavior the Codex plugin gets from its permanent
512
+ // `oauthServer!.on("error", reject)`.
513
+ server.on("error", (err) => log.warn("xai oauth server error", { error: err }))
514
+ log.info("xai oauth server started", { host: OAUTH_HOST, port: OAUTH_PORT })
515
+ resolve()
516
+ })
517
+ oauthServer = server
518
+ })
519
+
520
+ return { port: OAUTH_PORT, redirectUri: REDIRECT_URI }
521
+ }
522
+
523
+ function stopOAuthServer() {
524
+ if (oauthServer) {
525
+ oauthServer.close(() => log.info("xai oauth server stopped"))
526
+ oauthServer = undefined
527
+ }
528
+ }
529
+
530
+ function waitForOAuthCallback(pkce: PkceCodes, state: string): Promise<TokenResponse> {
531
+ // A previous in-flight authorize() that the user abandoned (or that is
532
+ // being superseded by a fresh attempt) still owns `pendingOAuth`. Reject
533
+ // it eagerly so its caller stops waiting on a state value that can never
534
+ // match the next callback.
535
+ if (pendingOAuth) {
536
+ pendingOAuth.reject(new Error("Superseded by a newer xAI authorize request"))
537
+ pendingOAuth = undefined
538
+ }
539
+ return new Promise((resolve, reject) => {
540
+ const timeout = setTimeout(
541
+ () => {
542
+ if (pendingOAuth) {
543
+ pendingOAuth = undefined
544
+ reject(new Error("OAuth callback timeout - authorization took too long"))
545
+ }
546
+ },
547
+ 5 * 60 * 1000,
548
+ )
549
+
550
+ pendingOAuth = {
551
+ pkce,
552
+ state,
553
+ resolve: (tokens) => {
554
+ clearTimeout(timeout)
555
+ resolve(tokens)
556
+ },
557
+ reject: (error) => {
558
+ clearTimeout(timeout)
559
+ reject(error)
560
+ },
561
+ }
562
+ })
563
+ }
564
+
565
+ interface RefreshResult {
566
+ access: string
567
+ refresh: string
568
+ expires: number
569
+ }
570
+
571
+ export async function XaiAuthPlugin(input: PluginInput, options: XaiAuthPluginOptions = {}): Promise<Hooks> {
572
+ return {
573
+ auth: {
574
+ provider: "xai",
575
+ async loader(getAuth) {
576
+ const auth = await getAuth()
577
+ if (auth.type !== "oauth") return {}
578
+
579
+ // Single-flight refresh: collapse concurrent fetches from this loaded
580
+ // provider onto one HTTP call so we don't replay a rotating refresh_token.
581
+ let refreshPromise: Promise<RefreshResult> | undefined
582
+
583
+ return {
584
+ // Dummy bearer keeps the AI SDK from bailing on "missing apiKey"; the
585
+ // real OAuth token is injected by the fetch override below.
586
+ // We intentionally do NOT set baseURL — @ai-sdk/xai already defaults
587
+ // to https://api.x.ai/v1 and overriding here would silently route
588
+ // around a user-configured gateway.
589
+ apiKey: OAUTH_DUMMY_KEY,
590
+ async fetch(requestInput: RequestInfo | URL, init?: RequestInit) {
591
+ let currentAuth = await getAuth()
592
+ // Auth can flip from oauth to api mid-session (user re-runs
593
+ // /connect with a pasted key). When that happens, pass the
594
+ // request through untouched so the AI SDK's own apiKey-based
595
+ // Authorization header reaches xAI unmodified.
596
+ if (currentAuth.type !== "oauth") return fetch(requestInput, init)
597
+
598
+ // Refresh either when the stored expires timestamp is within the
599
+ // skew window, or — for JWT access tokens — when the JWT exp
600
+ // claim itself is. The stored expires field is best-effort
601
+ // (xAI doesn't always return expires_in) so the JWT check is the
602
+ // load-bearing one for tokens that lack a fresh stored deadline.
603
+ const expiresSoon =
604
+ !currentAuth.expires ||
605
+ currentAuth.expires - Date.now() <= ACCESS_TOKEN_REFRESH_SKEW_MS ||
606
+ accessTokenIsExpiring(currentAuth.access)
607
+ if (expiresSoon) {
608
+ if (!refreshPromise) {
609
+ const refreshToken = currentAuth.refresh
610
+ log.info("refreshing xai access token")
611
+ refreshPromise = refreshAccessToken(refreshToken, options)
612
+ .then(async (tokens) => {
613
+ const refreshedExpires = Date.now() + (tokens.expires_in ?? 3600) * 1000
614
+ const refreshedRefresh = tokens.refresh_token || refreshToken
615
+ // Persist the rotated pair as best-effort. xAI has already consumed the
616
+ // old refresh_token by the time we get here; an auth.set failure leaves
617
+ // the on-disk state stale but the in-memory result is still valid for
618
+ // this turn. The next live refresh against the stale disk state will
619
+ // 4xx and force re-login — a known cross-process limitation.
620
+ await input.client.auth
621
+ .set({
622
+ path: { id: "xai" },
623
+ body: {
624
+ type: "oauth",
625
+ access: tokens.access_token,
626
+ refresh: refreshedRefresh,
627
+ expires: refreshedExpires,
628
+ },
629
+ })
630
+ .catch((err) => log.warn("failed to persist refreshed xai tokens", { error: err }))
631
+ return { access: tokens.access_token, refresh: refreshedRefresh, expires: refreshedExpires }
632
+ })
633
+ .finally(() => {
634
+ refreshPromise = undefined
635
+ })
636
+ }
637
+ const refreshed = await refreshPromise
638
+ currentAuth = { ...currentAuth, ...refreshed }
639
+ }
640
+
641
+ // Copy the caller's headers into a fresh Headers (case-insensitive)
642
+ // so we never mutate the RequestInit the AI SDK may reuse on retry.
643
+ // Headers.set overwrites case-insensitively, which kills the dummy
644
+ // bearer the AI SDK injected from apiKey in a single line.
645
+ const headers = new Headers(requestInput instanceof Request ? requestInput.headers : undefined)
646
+ if (init?.headers) {
647
+ const entries =
648
+ init.headers instanceof Headers
649
+ ? init.headers.entries()
650
+ : Array.isArray(init.headers)
651
+ ? init.headers
652
+ : Object.entries(init.headers as Record<string, string | undefined>)
653
+ for (const [key, value] of entries) {
654
+ if (value !== undefined) headers.set(key, String(value))
655
+ }
656
+ }
657
+ headers.set("authorization", `Bearer ${currentAuth.access}`)
658
+ headers.set("User-Agent", `opencode/${InstallationVersion}`)
659
+
660
+ return fetch(requestInput, { ...init, headers })
661
+ },
662
+ }
663
+ },
664
+ methods: [
665
+ {
666
+ label: "xAI Grok OAuth (SuperGrok Subscription)",
667
+ type: "oauth",
668
+ authorize: async () => {
669
+ await startOAuthServer()
670
+ const pkce = await generatePKCE()
671
+ const state = generateState()
672
+ const nonce = generateState()
673
+ const authUrl = buildAuthorizeUrl(pkce, state, nonce, options)
674
+
675
+ const callbackPromise = waitForOAuthCallback(pkce, state)
676
+
677
+ return {
678
+ url: authUrl,
679
+ instructions: "Complete authorization in your browser. This window will close automatically.",
680
+ method: "auto" as const,
681
+ callback: async () => {
682
+ try {
683
+ const tokens = await callbackPromise
684
+ return {
685
+ type: "success" as const,
686
+ refresh: tokens.refresh_token,
687
+ access: tokens.access_token,
688
+ expires: Date.now() + (tokens.expires_in ?? 3600) * 1000,
689
+ }
690
+ } catch (err) {
691
+ log.error("xai oauth callback failed", { error: err })
692
+ return { type: "failed" as const }
693
+ } finally {
694
+ stopOAuthServer()
695
+ }
696
+ },
697
+ }
698
+ },
699
+ },
700
+ {
701
+ // RFC 8628 device-code flow. The CLI prints a verification URL
702
+ // and a short user_code that the user enters in a browser on
703
+ // any device. No loopback callback server runs on the CLI host,
704
+ // so this works on VPS / SSH / Docker / CI / WSL / any
705
+ // environment where 127.0.0.1:56121 isn't reachable from the
706
+ // user's browser. Defends the only attack surface (the polling
707
+ // loop) with the standard authorization_pending / slow_down
708
+ // backoff and a hard deadline from xAI's `expires_in`.
709
+ label: "xAI Grok OAuth (Headless / Remote / VPS)",
710
+ type: "oauth",
711
+ authorize: async () => {
712
+ const device = await requestDeviceCode(options)
713
+ const browserUrl = device.verification_uri_complete ?? device.verification_uri
714
+ return {
715
+ url: browserUrl,
716
+ instructions: `Open ${device.verification_uri} on any device and enter code: ${device.user_code}`,
717
+ method: "auto" as const,
718
+ callback: async () => {
719
+ try {
720
+ const tokens = await pollDeviceCodeToken(device, options)
721
+ return {
722
+ type: "success" as const,
723
+ refresh: tokens.refresh_token,
724
+ access: tokens.access_token,
725
+ expires: Date.now() + (tokens.expires_in ?? 3600) * 1000,
726
+ }
727
+ } catch (err) {
728
+ log.error("xai device code callback failed", { error: err })
729
+ return { type: "failed" as const }
730
+ }
731
+ },
732
+ }
733
+ },
734
+ },
735
+ {
736
+ label: "Manually enter API Key",
737
+ type: "api",
738
+ },
739
+ ],
740
+ },
741
+ }
742
+ }