opencode-v2 1.1.53

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 (439) hide show
  1. package/AGENTS.md +27 -0
  2. package/Dockerfile +18 -0
  3. package/README.md +15 -0
  4. package/bin/opencode +84 -0
  5. package/bunfig.toml +5 -0
  6. package/package.json +126 -0
  7. package/parsers-config.ts +253 -0
  8. package/script/build.ts +193 -0
  9. package/script/postinstall.mjs +125 -0
  10. package/script/publish.ts +181 -0
  11. package/script/schema.ts +47 -0
  12. package/script/seed-e2e.ts +50 -0
  13. package/src/acp/README.md +164 -0
  14. package/src/acp/agent.ts +1676 -0
  15. package/src/acp/session.ts +117 -0
  16. package/src/acp/types.ts +23 -0
  17. package/src/agent/agent.ts +414 -0
  18. package/src/agent/generate.txt +75 -0
  19. package/src/agent/prompt/compaction.txt +12 -0
  20. package/src/agent/prompt/explore.txt +18 -0
  21. package/src/agent/prompt/summary.txt +11 -0
  22. package/src/agent/prompt/title.txt +44 -0
  23. package/src/auth/index.ts +70 -0
  24. package/src/bun/index.ts +137 -0
  25. package/src/bun/registry.ts +48 -0
  26. package/src/bus/bus-event.ts +43 -0
  27. package/src/bus/global.ts +10 -0
  28. package/src/bus/index.ts +105 -0
  29. package/src/cli/bootstrap.ts +17 -0
  30. package/src/cli/cmd/acp.ts +70 -0
  31. package/src/cli/cmd/agent.ts +257 -0
  32. package/src/cli/cmd/auth.ts +400 -0
  33. package/src/cli/cmd/cmd.ts +7 -0
  34. package/src/cli/cmd/debug/agent.ts +167 -0
  35. package/src/cli/cmd/debug/config.ts +16 -0
  36. package/src/cli/cmd/debug/file.ts +97 -0
  37. package/src/cli/cmd/debug/index.ts +48 -0
  38. package/src/cli/cmd/debug/lsp.ts +52 -0
  39. package/src/cli/cmd/debug/ripgrep.ts +87 -0
  40. package/src/cli/cmd/debug/scrap.ts +16 -0
  41. package/src/cli/cmd/debug/skill.ts +16 -0
  42. package/src/cli/cmd/debug/snapshot.ts +52 -0
  43. package/src/cli/cmd/export.ts +88 -0
  44. package/src/cli/cmd/generate.ts +38 -0
  45. package/src/cli/cmd/github.ts +1540 -0
  46. package/src/cli/cmd/import.ts +147 -0
  47. package/src/cli/cmd/mcp.ts +755 -0
  48. package/src/cli/cmd/models.ts +77 -0
  49. package/src/cli/cmd/pr.ts +112 -0
  50. package/src/cli/cmd/run.ts +617 -0
  51. package/src/cli/cmd/serve.ts +20 -0
  52. package/src/cli/cmd/session.ts +135 -0
  53. package/src/cli/cmd/stats.ts +426 -0
  54. package/src/cli/cmd/tui/app.tsx +801 -0
  55. package/src/cli/cmd/tui/attach.ts +52 -0
  56. package/src/cli/cmd/tui/component/border.tsx +21 -0
  57. package/src/cli/cmd/tui/component/dialog-agent.tsx +31 -0
  58. package/src/cli/cmd/tui/component/dialog-command.tsx +148 -0
  59. package/src/cli/cmd/tui/component/dialog-mcp.tsx +86 -0
  60. package/src/cli/cmd/tui/component/dialog-model.tsx +234 -0
  61. package/src/cli/cmd/tui/component/dialog-provider.tsx +266 -0
  62. package/src/cli/cmd/tui/component/dialog-session-list.tsx +108 -0
  63. package/src/cli/cmd/tui/component/dialog-session-rename.tsx +31 -0
  64. package/src/cli/cmd/tui/component/dialog-skill.tsx +36 -0
  65. package/src/cli/cmd/tui/component/dialog-stash.tsx +87 -0
  66. package/src/cli/cmd/tui/component/dialog-status.tsx +177 -0
  67. package/src/cli/cmd/tui/component/dialog-tag.tsx +44 -0
  68. package/src/cli/cmd/tui/component/dialog-theme-list.tsx +50 -0
  69. package/src/cli/cmd/tui/component/logo.tsx +85 -0
  70. package/src/cli/cmd/tui/component/prompt/autocomplete.tsx +666 -0
  71. package/src/cli/cmd/tui/component/prompt/frecency.tsx +89 -0
  72. package/src/cli/cmd/tui/component/prompt/history.tsx +108 -0
  73. package/src/cli/cmd/tui/component/prompt/index.tsx +1132 -0
  74. package/src/cli/cmd/tui/component/prompt/stash.tsx +101 -0
  75. package/src/cli/cmd/tui/component/spinner.tsx +24 -0
  76. package/src/cli/cmd/tui/component/textarea-keybindings.ts +73 -0
  77. package/src/cli/cmd/tui/component/tips.tsx +153 -0
  78. package/src/cli/cmd/tui/component/todo-item.tsx +32 -0
  79. package/src/cli/cmd/tui/context/args.tsx +15 -0
  80. package/src/cli/cmd/tui/context/directory.ts +13 -0
  81. package/src/cli/cmd/tui/context/exit.tsx +52 -0
  82. package/src/cli/cmd/tui/context/helper.tsx +25 -0
  83. package/src/cli/cmd/tui/context/keybind.tsx +100 -0
  84. package/src/cli/cmd/tui/context/kv.tsx +52 -0
  85. package/src/cli/cmd/tui/context/local.tsx +409 -0
  86. package/src/cli/cmd/tui/context/prompt.tsx +18 -0
  87. package/src/cli/cmd/tui/context/route.tsx +46 -0
  88. package/src/cli/cmd/tui/context/sdk.tsx +101 -0
  89. package/src/cli/cmd/tui/context/sync.tsx +470 -0
  90. package/src/cli/cmd/tui/context/theme/aura.json +69 -0
  91. package/src/cli/cmd/tui/context/theme/ayu.json +80 -0
  92. package/src/cli/cmd/tui/context/theme/carbonfox.json +248 -0
  93. package/src/cli/cmd/tui/context/theme/catppuccin-frappe.json +233 -0
  94. package/src/cli/cmd/tui/context/theme/catppuccin-macchiato.json +233 -0
  95. package/src/cli/cmd/tui/context/theme/catppuccin.json +112 -0
  96. package/src/cli/cmd/tui/context/theme/cobalt2.json +228 -0
  97. package/src/cli/cmd/tui/context/theme/cursor.json +249 -0
  98. package/src/cli/cmd/tui/context/theme/dracula.json +219 -0
  99. package/src/cli/cmd/tui/context/theme/everforest.json +241 -0
  100. package/src/cli/cmd/tui/context/theme/flexoki.json +237 -0
  101. package/src/cli/cmd/tui/context/theme/github.json +233 -0
  102. package/src/cli/cmd/tui/context/theme/gruvbox.json +242 -0
  103. package/src/cli/cmd/tui/context/theme/kanagawa.json +77 -0
  104. package/src/cli/cmd/tui/context/theme/lucent-orng.json +237 -0
  105. package/src/cli/cmd/tui/context/theme/material.json +235 -0
  106. package/src/cli/cmd/tui/context/theme/matrix.json +77 -0
  107. package/src/cli/cmd/tui/context/theme/mercury.json +252 -0
  108. package/src/cli/cmd/tui/context/theme/monokai.json +221 -0
  109. package/src/cli/cmd/tui/context/theme/nightowl.json +221 -0
  110. package/src/cli/cmd/tui/context/theme/nord.json +223 -0
  111. package/src/cli/cmd/tui/context/theme/one-dark.json +84 -0
  112. package/src/cli/cmd/tui/context/theme/orng.json +249 -0
  113. package/src/cli/cmd/tui/context/theme/osaka-jade.json +93 -0
  114. package/src/cli/cmd/tui/context/theme/palenight.json +222 -0
  115. package/src/cli/cmd/tui/context/theme/rosepine.json +234 -0
  116. package/src/cli/cmd/tui/context/theme/solarized.json +223 -0
  117. package/src/cli/cmd/tui/context/theme/synthwave84.json +226 -0
  118. package/src/cli/cmd/tui/context/theme/tokyonight.json +243 -0
  119. package/src/cli/cmd/tui/context/theme/vercel.json +245 -0
  120. package/src/cli/cmd/tui/context/theme/vesper.json +218 -0
  121. package/src/cli/cmd/tui/context/theme/zenburn.json +223 -0
  122. package/src/cli/cmd/tui/context/theme.tsx +1152 -0
  123. package/src/cli/cmd/tui/event.ts +48 -0
  124. package/src/cli/cmd/tui/routes/home.tsx +140 -0
  125. package/src/cli/cmd/tui/routes/session/dialog-fork-from-timeline.tsx +64 -0
  126. package/src/cli/cmd/tui/routes/session/dialog-message.tsx +109 -0
  127. package/src/cli/cmd/tui/routes/session/dialog-subagent.tsx +26 -0
  128. package/src/cli/cmd/tui/routes/session/dialog-timeline.tsx +47 -0
  129. package/src/cli/cmd/tui/routes/session/footer.tsx +91 -0
  130. package/src/cli/cmd/tui/routes/session/header.tsx +142 -0
  131. package/src/cli/cmd/tui/routes/session/index.tsx +2126 -0
  132. package/src/cli/cmd/tui/routes/session/permission.tsx +508 -0
  133. package/src/cli/cmd/tui/routes/session/question.tsx +466 -0
  134. package/src/cli/cmd/tui/routes/session/sidebar.tsx +313 -0
  135. package/src/cli/cmd/tui/thread.ts +175 -0
  136. package/src/cli/cmd/tui/ui/dialog-alert.tsx +68 -0
  137. package/src/cli/cmd/tui/ui/dialog-confirm.tsx +93 -0
  138. package/src/cli/cmd/tui/ui/dialog-export-options.tsx +215 -0
  139. package/src/cli/cmd/tui/ui/dialog-help.tsx +49 -0
  140. package/src/cli/cmd/tui/ui/dialog-prompt.tsx +88 -0
  141. package/src/cli/cmd/tui/ui/dialog-select.tsx +399 -0
  142. package/src/cli/cmd/tui/ui/dialog.tsx +167 -0
  143. package/src/cli/cmd/tui/ui/link.tsx +28 -0
  144. package/src/cli/cmd/tui/ui/spinner.ts +368 -0
  145. package/src/cli/cmd/tui/ui/toast.tsx +100 -0
  146. package/src/cli/cmd/tui/util/clipboard.ts +159 -0
  147. package/src/cli/cmd/tui/util/editor.ts +32 -0
  148. package/src/cli/cmd/tui/util/signal.ts +7 -0
  149. package/src/cli/cmd/tui/util/terminal.ts +114 -0
  150. package/src/cli/cmd/tui/util/transcript.ts +98 -0
  151. package/src/cli/cmd/tui/worker.ts +152 -0
  152. package/src/cli/cmd/uninstall.ts +357 -0
  153. package/src/cli/cmd/upgrade.ts +73 -0
  154. package/src/cli/cmd/web.ts +81 -0
  155. package/src/cli/error.ts +57 -0
  156. package/src/cli/logo.ts +6 -0
  157. package/src/cli/network.ts +60 -0
  158. package/src/cli/ui.ts +113 -0
  159. package/src/cli/upgrade.ts +25 -0
  160. package/src/command/index.ts +150 -0
  161. package/src/command/template/initialize.txt +10 -0
  162. package/src/command/template/review.txt +99 -0
  163. package/src/config/config.ts +1477 -0
  164. package/src/config/markdown.ts +98 -0
  165. package/src/env/index.ts +28 -0
  166. package/src/file/ignore.ts +83 -0
  167. package/src/file/index.ts +583 -0
  168. package/src/file/ripgrep.ts +375 -0
  169. package/src/file/time.ts +69 -0
  170. package/src/file/watcher.ts +127 -0
  171. package/src/flag/flag.ts +97 -0
  172. package/src/format/formatter.ts +366 -0
  173. package/src/format/index.ts +137 -0
  174. package/src/global/index.ts +55 -0
  175. package/src/id/id.ts +83 -0
  176. package/src/ide/index.ts +76 -0
  177. package/src/index.ts +159 -0
  178. package/src/installation/index.ts +246 -0
  179. package/src/lsp/client.ts +252 -0
  180. package/src/lsp/index.ts +485 -0
  181. package/src/lsp/language.ts +119 -0
  182. package/src/lsp/server.ts +2046 -0
  183. package/src/mcp/auth.ts +132 -0
  184. package/src/mcp/index.ts +934 -0
  185. package/src/mcp/oauth-callback.ts +200 -0
  186. package/src/mcp/oauth-provider.ts +154 -0
  187. package/src/patch/index.ts +680 -0
  188. package/src/permission/arity.ts +163 -0
  189. package/src/permission/index.ts +210 -0
  190. package/src/permission/next.ts +280 -0
  191. package/src/plugin/codex.ts +624 -0
  192. package/src/plugin/copilot.ts +327 -0
  193. package/src/plugin/index.ts +138 -0
  194. package/src/project/bootstrap.ts +35 -0
  195. package/src/project/instance.ts +114 -0
  196. package/src/project/project.ts +371 -0
  197. package/src/project/state.ts +70 -0
  198. package/src/project/vcs.ts +76 -0
  199. package/src/provider/auth.ts +147 -0
  200. package/src/provider/models.ts +133 -0
  201. package/src/provider/provider.ts +1262 -0
  202. package/src/provider/sdk/copilot/README.md +5 -0
  203. package/src/provider/sdk/copilot/chat/convert-to-openai-compatible-chat-messages.ts +164 -0
  204. package/src/provider/sdk/copilot/chat/get-response-metadata.ts +15 -0
  205. package/src/provider/sdk/copilot/chat/map-openai-compatible-finish-reason.ts +17 -0
  206. package/src/provider/sdk/copilot/chat/openai-compatible-api-types.ts +64 -0
  207. package/src/provider/sdk/copilot/chat/openai-compatible-chat-language-model.ts +780 -0
  208. package/src/provider/sdk/copilot/chat/openai-compatible-chat-options.ts +28 -0
  209. package/src/provider/sdk/copilot/chat/openai-compatible-metadata-extractor.ts +44 -0
  210. package/src/provider/sdk/copilot/chat/openai-compatible-prepare-tools.ts +87 -0
  211. package/src/provider/sdk/copilot/copilot-provider.ts +100 -0
  212. package/src/provider/sdk/copilot/index.ts +2 -0
  213. package/src/provider/sdk/copilot/openai-compatible-error.ts +27 -0
  214. package/src/provider/sdk/copilot/responses/convert-to-openai-responses-input.ts +303 -0
  215. package/src/provider/sdk/copilot/responses/map-openai-responses-finish-reason.ts +22 -0
  216. package/src/provider/sdk/copilot/responses/openai-config.ts +18 -0
  217. package/src/provider/sdk/copilot/responses/openai-error.ts +22 -0
  218. package/src/provider/sdk/copilot/responses/openai-responses-api-types.ts +207 -0
  219. package/src/provider/sdk/copilot/responses/openai-responses-language-model.ts +1732 -0
  220. package/src/provider/sdk/copilot/responses/openai-responses-prepare-tools.ts +177 -0
  221. package/src/provider/sdk/copilot/responses/openai-responses-settings.ts +1 -0
  222. package/src/provider/sdk/copilot/responses/tool/code-interpreter.ts +88 -0
  223. package/src/provider/sdk/copilot/responses/tool/file-search.ts +128 -0
  224. package/src/provider/sdk/copilot/responses/tool/image-generation.ts +115 -0
  225. package/src/provider/sdk/copilot/responses/tool/local-shell.ts +65 -0
  226. package/src/provider/sdk/copilot/responses/tool/web-search-preview.ts +104 -0
  227. package/src/provider/sdk/copilot/responses/tool/web-search.ts +103 -0
  228. package/src/provider/transform.ts +828 -0
  229. package/src/pty/index.ts +250 -0
  230. package/src/question/index.ts +171 -0
  231. package/src/scheduler/index.ts +61 -0
  232. package/src/server/error.ts +36 -0
  233. package/src/server/event.ts +7 -0
  234. package/src/server/mdns.ts +60 -0
  235. package/src/server/routes/config.ts +92 -0
  236. package/src/server/routes/experimental.ts +208 -0
  237. package/src/server/routes/file.ts +197 -0
  238. package/src/server/routes/global.ts +183 -0
  239. package/src/server/routes/mcp.ts +225 -0
  240. package/src/server/routes/permission.ts +68 -0
  241. package/src/server/routes/project.ts +82 -0
  242. package/src/server/routes/provider.ts +165 -0
  243. package/src/server/routes/pty.ts +169 -0
  244. package/src/server/routes/question.ts +98 -0
  245. package/src/server/routes/session.ts +939 -0
  246. package/src/server/routes/tui.ts +379 -0
  247. package/src/server/server.ts +613 -0
  248. package/src/session/compaction.ts +226 -0
  249. package/src/session/index.ts +524 -0
  250. package/src/session/instruction.ts +197 -0
  251. package/src/session/llm.ts +289 -0
  252. package/src/session/message-v2.ts +802 -0
  253. package/src/session/message.ts +189 -0
  254. package/src/session/processor.ts +407 -0
  255. package/src/session/prompt/agent.txt +43 -0
  256. package/src/session/prompt/anthropic-20250930.txt +166 -0
  257. package/src/session/prompt/anthropic.txt +105 -0
  258. package/src/session/prompt/beast.txt +147 -0
  259. package/src/session/prompt/build-switch.txt +5 -0
  260. package/src/session/prompt/codex_header.txt +79 -0
  261. package/src/session/prompt/copilot-gpt-5.txt +143 -0
  262. package/src/session/prompt/gemini.txt +155 -0
  263. package/src/session/prompt/max-steps.txt +16 -0
  264. package/src/session/prompt/plan-reminder-anthropic.txt +67 -0
  265. package/src/session/prompt/plan.txt +26 -0
  266. package/src/session/prompt/qwen.txt +109 -0
  267. package/src/session/prompt/research.txt +81 -0
  268. package/src/session/prompt/trinity.txt +97 -0
  269. package/src/session/prompt.ts +1952 -0
  270. package/src/session/retry.ts +97 -0
  271. package/src/session/revert.ts +121 -0
  272. package/src/session/status.ts +76 -0
  273. package/src/session/summary.ts +217 -0
  274. package/src/session/system.ts +54 -0
  275. package/src/session/todo.ts +37 -0
  276. package/src/share/share-next.ts +200 -0
  277. package/src/share/share.ts +92 -0
  278. package/src/shell/shell.ts +67 -0
  279. package/src/skill/discovery.ts +97 -0
  280. package/src/skill/index.ts +1 -0
  281. package/src/skill/skill.ts +188 -0
  282. package/src/snapshot/index.ts +255 -0
  283. package/src/storage/storage.ts +227 -0
  284. package/src/tool/agent-enter.txt +1 -0
  285. package/src/tool/agent-exit.txt +1 -0
  286. package/src/tool/agent.ts +237 -0
  287. package/src/tool/apply_patch.ts +281 -0
  288. package/src/tool/apply_patch.txt +33 -0
  289. package/src/tool/bash.ts +269 -0
  290. package/src/tool/bash.txt +115 -0
  291. package/src/tool/batch.ts +175 -0
  292. package/src/tool/batch.txt +24 -0
  293. package/src/tool/chat-enter.txt +15 -0
  294. package/src/tool/chat-exit.txt +7 -0
  295. package/src/tool/chat.ts +217 -0
  296. package/src/tool/codesearch.ts +132 -0
  297. package/src/tool/codesearch.txt +12 -0
  298. package/src/tool/edit.ts +655 -0
  299. package/src/tool/edit.txt +10 -0
  300. package/src/tool/external-directory.ts +32 -0
  301. package/src/tool/glob.ts +78 -0
  302. package/src/tool/glob.txt +6 -0
  303. package/src/tool/grep.ts +147 -0
  304. package/src/tool/grep.txt +8 -0
  305. package/src/tool/invalid.ts +17 -0
  306. package/src/tool/ls.ts +121 -0
  307. package/src/tool/ls.txt +1 -0
  308. package/src/tool/lsp.ts +96 -0
  309. package/src/tool/lsp.txt +19 -0
  310. package/src/tool/multiedit.ts +46 -0
  311. package/src/tool/multiedit.txt +41 -0
  312. package/src/tool/plan-enter.txt +14 -0
  313. package/src/tool/plan-exit.txt +13 -0
  314. package/src/tool/plan.ts +130 -0
  315. package/src/tool/question.ts +33 -0
  316. package/src/tool/question.txt +10 -0
  317. package/src/tool/read.ts +211 -0
  318. package/src/tool/read.txt +12 -0
  319. package/src/tool/registry.ts +167 -0
  320. package/src/tool/research-enter.txt +1 -0
  321. package/src/tool/research-exit.txt +1 -0
  322. package/src/tool/research.ts +134 -0
  323. package/src/tool/skill.ts +123 -0
  324. package/src/tool/task.ts +165 -0
  325. package/src/tool/task.txt +60 -0
  326. package/src/tool/todo.ts +53 -0
  327. package/src/tool/todoread.txt +14 -0
  328. package/src/tool/todowrite.txt +167 -0
  329. package/src/tool/tool.ts +89 -0
  330. package/src/tool/truncation.ts +106 -0
  331. package/src/tool/webfetch.ts +186 -0
  332. package/src/tool/webfetch.txt +13 -0
  333. package/src/tool/websearch.ts +150 -0
  334. package/src/tool/websearch.txt +14 -0
  335. package/src/tool/write.ts +85 -0
  336. package/src/tool/write.txt +8 -0
  337. package/src/util/abort.ts +35 -0
  338. package/src/util/archive.ts +16 -0
  339. package/src/util/color.ts +19 -0
  340. package/src/util/context.ts +25 -0
  341. package/src/util/defer.ts +12 -0
  342. package/src/util/eventloop.ts +20 -0
  343. package/src/util/filesystem.ts +93 -0
  344. package/src/util/fn.ts +11 -0
  345. package/src/util/format.ts +20 -0
  346. package/src/util/iife.ts +3 -0
  347. package/src/util/keybind.ts +103 -0
  348. package/src/util/lazy.ts +18 -0
  349. package/src/util/locale.ts +81 -0
  350. package/src/util/lock.ts +98 -0
  351. package/src/util/log.ts +180 -0
  352. package/src/util/proxied.ts +3 -0
  353. package/src/util/queue.ts +32 -0
  354. package/src/util/rpc.ts +66 -0
  355. package/src/util/scrap.ts +10 -0
  356. package/src/util/signal.ts +12 -0
  357. package/src/util/timeout.ts +14 -0
  358. package/src/util/token.ts +7 -0
  359. package/src/util/wildcard.ts +56 -0
  360. package/src/worktree/index.ts +574 -0
  361. package/sst-env.d.ts +9 -0
  362. package/test/acp/agent-interface.test.ts +51 -0
  363. package/test/acp/event-subscription.test.ts +436 -0
  364. package/test/agent/agent.test.ts +675 -0
  365. package/test/bun.test.ts +53 -0
  366. package/test/cli/github-action.test.ts +161 -0
  367. package/test/cli/github-remote.test.ts +80 -0
  368. package/test/cli/import.test.ts +38 -0
  369. package/test/cli/tui/transcript.test.ts +322 -0
  370. package/test/config/agent-color.test.ts +71 -0
  371. package/test/config/config.test.ts +1802 -0
  372. package/test/config/fixtures/empty-frontmatter.md +4 -0
  373. package/test/config/fixtures/frontmatter.md +28 -0
  374. package/test/config/fixtures/markdown-header.md +11 -0
  375. package/test/config/fixtures/no-frontmatter.md +1 -0
  376. package/test/config/fixtures/weird-model-id.md +13 -0
  377. package/test/config/markdown.test.ts +228 -0
  378. package/test/file/ignore.test.ts +10 -0
  379. package/test/file/path-traversal.test.ts +198 -0
  380. package/test/file/ripgrep.test.ts +39 -0
  381. package/test/fixture/fixture.ts +45 -0
  382. package/test/fixture/lsp/fake-lsp-server.js +77 -0
  383. package/test/ide/ide.test.ts +82 -0
  384. package/test/keybind.test.ts +421 -0
  385. package/test/lsp/client.test.ts +95 -0
  386. package/test/mcp/headers.test.ts +153 -0
  387. package/test/mcp/oauth-browser.test.ts +249 -0
  388. package/test/memory/abort-leak.test.ts +136 -0
  389. package/test/patch/patch.test.ts +348 -0
  390. package/test/permission/arity.test.ts +33 -0
  391. package/test/permission/next.test.ts +690 -0
  392. package/test/permission-task.test.ts +319 -0
  393. package/test/plugin/auth-override.test.ts +44 -0
  394. package/test/plugin/codex.test.ts +123 -0
  395. package/test/preload.ts +63 -0
  396. package/test/project/project.test.ts +120 -0
  397. package/test/provider/amazon-bedrock.test.ts +445 -0
  398. package/test/provider/copilot/convert-to-copilot-messages.test.ts +523 -0
  399. package/test/provider/copilot/copilot-chat-model.test.ts +592 -0
  400. package/test/provider/gitlab-duo.test.ts +262 -0
  401. package/test/provider/provider.test.ts +2129 -0
  402. package/test/provider/transform.test.ts +2022 -0
  403. package/test/question/question.test.ts +300 -0
  404. package/test/scheduler.test.ts +73 -0
  405. package/test/server/session-list.test.ts +39 -0
  406. package/test/server/session-select.test.ts +78 -0
  407. package/test/session/compaction.test.ts +293 -0
  408. package/test/session/instruction.test.ts +170 -0
  409. package/test/session/llm.test.ts +691 -0
  410. package/test/session/message-v2.test.ts +786 -0
  411. package/test/session/prompt-missing-file.test.ts +53 -0
  412. package/test/session/prompt-special-chars.test.ts +56 -0
  413. package/test/session/prompt-variant.test.ts +60 -0
  414. package/test/session/retry.test.ts +179 -0
  415. package/test/session/revert-compact.test.ts +285 -0
  416. package/test/session/session.test.ts +71 -0
  417. package/test/skill/discovery.test.ts +60 -0
  418. package/test/skill/skill.test.ts +388 -0
  419. package/test/snapshot/snapshot.test.ts +1040 -0
  420. package/test/tool/__snapshots__/tool.test.ts.snap +9 -0
  421. package/test/tool/apply_patch.test.ts +559 -0
  422. package/test/tool/bash.test.ts +399 -0
  423. package/test/tool/external-directory.test.ts +127 -0
  424. package/test/tool/fixtures/large-image.png +0 -0
  425. package/test/tool/fixtures/models-api.json +38413 -0
  426. package/test/tool/grep.test.ts +110 -0
  427. package/test/tool/question.test.ts +107 -0
  428. package/test/tool/read.test.ts +358 -0
  429. package/test/tool/registry.test.ts +122 -0
  430. package/test/tool/skill.test.ts +112 -0
  431. package/test/tool/truncation.test.ts +159 -0
  432. package/test/util/filesystem.test.ts +39 -0
  433. package/test/util/format.test.ts +59 -0
  434. package/test/util/iife.test.ts +36 -0
  435. package/test/util/lazy.test.ts +50 -0
  436. package/test/util/lock.test.ts +72 -0
  437. package/test/util/timeout.test.ts +21 -0
  438. package/test/util/wildcard.test.ts +75 -0
  439. package/tsconfig.json +16 -0
@@ -0,0 +1,293 @@
1
+ import { describe, expect, test } from "bun:test"
2
+ import path from "path"
3
+ import { SessionCompaction } from "../../src/session/compaction"
4
+ import { Token } from "../../src/util/token"
5
+ import { Instance } from "../../src/project/instance"
6
+ import { Log } from "../../src/util/log"
7
+ import { tmpdir } from "../fixture/fixture"
8
+ import { Session } from "../../src/session"
9
+ import type { Provider } from "../../src/provider/provider"
10
+
11
+ Log.init({ print: false })
12
+
13
+ function createModel(opts: {
14
+ context: number
15
+ output: number
16
+ input?: number
17
+ cost?: Provider.Model["cost"]
18
+ }): Provider.Model {
19
+ return {
20
+ id: "test-model",
21
+ providerID: "test",
22
+ name: "Test",
23
+ limit: {
24
+ context: opts.context,
25
+ input: opts.input,
26
+ output: opts.output,
27
+ },
28
+ cost: opts.cost ?? { input: 0, output: 0, cache: { read: 0, write: 0 } },
29
+ capabilities: {
30
+ toolcall: true,
31
+ attachment: false,
32
+ reasoning: false,
33
+ temperature: true,
34
+ input: { text: true, image: false, audio: false, video: false },
35
+ output: { text: true, image: false, audio: false, video: false },
36
+ },
37
+ api: { npm: "@ai-sdk/anthropic" },
38
+ options: {},
39
+ } as Provider.Model
40
+ }
41
+
42
+ describe("session.compaction.isOverflow", () => {
43
+ test("returns true when token count exceeds usable context", async () => {
44
+ await using tmp = await tmpdir()
45
+ await Instance.provide({
46
+ directory: tmp.path,
47
+ fn: async () => {
48
+ const model = createModel({ context: 100_000, output: 32_000 })
49
+ const tokens = { input: 75_000, output: 5_000, reasoning: 0, cache: { read: 0, write: 0 } }
50
+ expect(await SessionCompaction.isOverflow({ tokens, model })).toBe(true)
51
+ },
52
+ })
53
+ })
54
+
55
+ test("returns false when token count within usable context", async () => {
56
+ await using tmp = await tmpdir()
57
+ await Instance.provide({
58
+ directory: tmp.path,
59
+ fn: async () => {
60
+ const model = createModel({ context: 200_000, output: 32_000 })
61
+ const tokens = { input: 100_000, output: 10_000, reasoning: 0, cache: { read: 0, write: 0 } }
62
+ expect(await SessionCompaction.isOverflow({ tokens, model })).toBe(false)
63
+ },
64
+ })
65
+ })
66
+
67
+ test("includes cache.read in token count", async () => {
68
+ await using tmp = await tmpdir()
69
+ await Instance.provide({
70
+ directory: tmp.path,
71
+ fn: async () => {
72
+ const model = createModel({ context: 100_000, output: 32_000 })
73
+ const tokens = { input: 50_000, output: 10_000, reasoning: 0, cache: { read: 10_000, write: 0 } }
74
+ expect(await SessionCompaction.isOverflow({ tokens, model })).toBe(true)
75
+ },
76
+ })
77
+ })
78
+
79
+ test("respects input limit for input caps", async () => {
80
+ await using tmp = await tmpdir()
81
+ await Instance.provide({
82
+ directory: tmp.path,
83
+ fn: async () => {
84
+ const model = createModel({ context: 400_000, input: 272_000, output: 128_000 })
85
+ const tokens = { input: 271_000, output: 1_000, reasoning: 0, cache: { read: 2_000, write: 0 } }
86
+ expect(await SessionCompaction.isOverflow({ tokens, model })).toBe(true)
87
+ },
88
+ })
89
+ })
90
+
91
+ test("returns false when input/output are within input caps", async () => {
92
+ await using tmp = await tmpdir()
93
+ await Instance.provide({
94
+ directory: tmp.path,
95
+ fn: async () => {
96
+ const model = createModel({ context: 400_000, input: 272_000, output: 128_000 })
97
+ const tokens = { input: 200_000, output: 20_000, reasoning: 0, cache: { read: 10_000, write: 0 } }
98
+ expect(await SessionCompaction.isOverflow({ tokens, model })).toBe(false)
99
+ },
100
+ })
101
+ })
102
+
103
+ test("returns false when output within limit with input caps", async () => {
104
+ await using tmp = await tmpdir()
105
+ await Instance.provide({
106
+ directory: tmp.path,
107
+ fn: async () => {
108
+ const model = createModel({ context: 200_000, input: 120_000, output: 10_000 })
109
+ const tokens = { input: 50_000, output: 9_999, reasoning: 0, cache: { read: 0, write: 0 } }
110
+ expect(await SessionCompaction.isOverflow({ tokens, model })).toBe(false)
111
+ },
112
+ })
113
+ })
114
+
115
+ test("returns false when model context limit is 0", async () => {
116
+ await using tmp = await tmpdir()
117
+ await Instance.provide({
118
+ directory: tmp.path,
119
+ fn: async () => {
120
+ const model = createModel({ context: 0, output: 32_000 })
121
+ const tokens = { input: 100_000, output: 10_000, reasoning: 0, cache: { read: 0, write: 0 } }
122
+ expect(await SessionCompaction.isOverflow({ tokens, model })).toBe(false)
123
+ },
124
+ })
125
+ })
126
+
127
+ test("returns false when compaction.auto is disabled", async () => {
128
+ await using tmp = await tmpdir({
129
+ init: async (dir) => {
130
+ await Bun.write(
131
+ path.join(dir, "opencode.json"),
132
+ JSON.stringify({
133
+ compaction: { auto: false },
134
+ }),
135
+ )
136
+ },
137
+ })
138
+ await Instance.provide({
139
+ directory: tmp.path,
140
+ fn: async () => {
141
+ const model = createModel({ context: 100_000, output: 32_000 })
142
+ const tokens = { input: 75_000, output: 5_000, reasoning: 0, cache: { read: 0, write: 0 } }
143
+ expect(await SessionCompaction.isOverflow({ tokens, model })).toBe(false)
144
+ },
145
+ })
146
+ })
147
+ })
148
+
149
+ describe("util.token.estimate", () => {
150
+ test("estimates tokens from text (4 chars per token)", () => {
151
+ const text = "x".repeat(4000)
152
+ expect(Token.estimate(text)).toBe(1000)
153
+ })
154
+
155
+ test("estimates tokens from larger text", () => {
156
+ const text = "y".repeat(20_000)
157
+ expect(Token.estimate(text)).toBe(5000)
158
+ })
159
+
160
+ test("returns 0 for empty string", () => {
161
+ expect(Token.estimate("")).toBe(0)
162
+ })
163
+ })
164
+
165
+ describe("session.getUsage", () => {
166
+ test("normalizes standard usage to token format", () => {
167
+ const model = createModel({ context: 100_000, output: 32_000 })
168
+ const result = Session.getUsage({
169
+ model,
170
+ usage: {
171
+ inputTokens: 1000,
172
+ outputTokens: 500,
173
+ totalTokens: 1500,
174
+ },
175
+ })
176
+
177
+ expect(result.tokens.input).toBe(1000)
178
+ expect(result.tokens.output).toBe(500)
179
+ expect(result.tokens.reasoning).toBe(0)
180
+ expect(result.tokens.cache.read).toBe(0)
181
+ expect(result.tokens.cache.write).toBe(0)
182
+ })
183
+
184
+ test("extracts cached tokens to cache.read", () => {
185
+ const model = createModel({ context: 100_000, output: 32_000 })
186
+ const result = Session.getUsage({
187
+ model,
188
+ usage: {
189
+ inputTokens: 1000,
190
+ outputTokens: 500,
191
+ totalTokens: 1500,
192
+ cachedInputTokens: 200,
193
+ },
194
+ })
195
+
196
+ expect(result.tokens.input).toBe(800)
197
+ expect(result.tokens.cache.read).toBe(200)
198
+ })
199
+
200
+ test("handles anthropic cache write metadata", () => {
201
+ const model = createModel({ context: 100_000, output: 32_000 })
202
+ const result = Session.getUsage({
203
+ model,
204
+ usage: {
205
+ inputTokens: 1000,
206
+ outputTokens: 500,
207
+ totalTokens: 1500,
208
+ },
209
+ metadata: {
210
+ anthropic: {
211
+ cacheCreationInputTokens: 300,
212
+ },
213
+ },
214
+ })
215
+
216
+ expect(result.tokens.cache.write).toBe(300)
217
+ })
218
+
219
+ test("does not subtract cached tokens for anthropic provider", () => {
220
+ const model = createModel({ context: 100_000, output: 32_000 })
221
+ const result = Session.getUsage({
222
+ model,
223
+ usage: {
224
+ inputTokens: 1000,
225
+ outputTokens: 500,
226
+ totalTokens: 1500,
227
+ cachedInputTokens: 200,
228
+ },
229
+ metadata: {
230
+ anthropic: {},
231
+ },
232
+ })
233
+
234
+ expect(result.tokens.input).toBe(1000)
235
+ expect(result.tokens.cache.read).toBe(200)
236
+ })
237
+
238
+ test("handles reasoning tokens", () => {
239
+ const model = createModel({ context: 100_000, output: 32_000 })
240
+ const result = Session.getUsage({
241
+ model,
242
+ usage: {
243
+ inputTokens: 1000,
244
+ outputTokens: 500,
245
+ totalTokens: 1500,
246
+ reasoningTokens: 100,
247
+ },
248
+ })
249
+
250
+ expect(result.tokens.reasoning).toBe(100)
251
+ })
252
+
253
+ test("handles undefined optional values gracefully", () => {
254
+ const model = createModel({ context: 100_000, output: 32_000 })
255
+ const result = Session.getUsage({
256
+ model,
257
+ usage: {
258
+ inputTokens: 0,
259
+ outputTokens: 0,
260
+ totalTokens: 0,
261
+ },
262
+ })
263
+
264
+ expect(result.tokens.input).toBe(0)
265
+ expect(result.tokens.output).toBe(0)
266
+ expect(result.tokens.reasoning).toBe(0)
267
+ expect(result.tokens.cache.read).toBe(0)
268
+ expect(result.tokens.cache.write).toBe(0)
269
+ expect(Number.isNaN(result.cost)).toBe(false)
270
+ })
271
+
272
+ test("calculates cost correctly", () => {
273
+ const model = createModel({
274
+ context: 100_000,
275
+ output: 32_000,
276
+ cost: {
277
+ input: 3,
278
+ output: 15,
279
+ cache: { read: 0.3, write: 3.75 },
280
+ },
281
+ })
282
+ const result = Session.getUsage({
283
+ model,
284
+ usage: {
285
+ inputTokens: 1_000_000,
286
+ outputTokens: 100_000,
287
+ totalTokens: 1_100_000,
288
+ },
289
+ })
290
+
291
+ expect(result.cost).toBe(3 + 1.5)
292
+ })
293
+ })
@@ -0,0 +1,170 @@
1
+ import { afterEach, beforeEach, describe, expect, test } from "bun:test"
2
+ import path from "path"
3
+ import { InstructionPrompt } from "../../src/session/instruction"
4
+ import { Instance } from "../../src/project/instance"
5
+ import { Global } from "../../src/global"
6
+ import { tmpdir } from "../fixture/fixture"
7
+
8
+ describe("InstructionPrompt.resolve", () => {
9
+ test("returns empty when AGENTS.md is at project root (already in systemPaths)", async () => {
10
+ await using tmp = await tmpdir({
11
+ init: async (dir) => {
12
+ await Bun.write(path.join(dir, "AGENTS.md"), "# Root Instructions")
13
+ await Bun.write(path.join(dir, "src", "file.ts"), "const x = 1")
14
+ },
15
+ })
16
+ await Instance.provide({
17
+ directory: tmp.path,
18
+ fn: async () => {
19
+ const system = await InstructionPrompt.systemPaths()
20
+ expect(system.has(path.join(tmp.path, "AGENTS.md"))).toBe(true)
21
+
22
+ const results = await InstructionPrompt.resolve([], path.join(tmp.path, "src", "file.ts"), "test-message-1")
23
+ expect(results).toEqual([])
24
+ },
25
+ })
26
+ })
27
+
28
+ test("returns AGENTS.md from subdirectory (not in systemPaths)", async () => {
29
+ await using tmp = await tmpdir({
30
+ init: async (dir) => {
31
+ await Bun.write(path.join(dir, "subdir", "AGENTS.md"), "# Subdir Instructions")
32
+ await Bun.write(path.join(dir, "subdir", "nested", "file.ts"), "const x = 1")
33
+ },
34
+ })
35
+ await Instance.provide({
36
+ directory: tmp.path,
37
+ fn: async () => {
38
+ const system = await InstructionPrompt.systemPaths()
39
+ expect(system.has(path.join(tmp.path, "subdir", "AGENTS.md"))).toBe(false)
40
+
41
+ const results = await InstructionPrompt.resolve(
42
+ [],
43
+ path.join(tmp.path, "subdir", "nested", "file.ts"),
44
+ "test-message-2",
45
+ )
46
+ expect(results.length).toBe(1)
47
+ expect(results[0].filepath).toBe(path.join(tmp.path, "subdir", "AGENTS.md"))
48
+ },
49
+ })
50
+ })
51
+
52
+ test("doesn't reload AGENTS.md when reading it directly", async () => {
53
+ await using tmp = await tmpdir({
54
+ init: async (dir) => {
55
+ await Bun.write(path.join(dir, "subdir", "AGENTS.md"), "# Subdir Instructions")
56
+ await Bun.write(path.join(dir, "subdir", "nested", "file.ts"), "const x = 1")
57
+ },
58
+ })
59
+ await Instance.provide({
60
+ directory: tmp.path,
61
+ fn: async () => {
62
+ const filepath = path.join(tmp.path, "subdir", "AGENTS.md")
63
+ const system = await InstructionPrompt.systemPaths()
64
+ expect(system.has(filepath)).toBe(false)
65
+
66
+ const results = await InstructionPrompt.resolve([], filepath, "test-message-2")
67
+ expect(results).toEqual([])
68
+ },
69
+ })
70
+ })
71
+ })
72
+
73
+ describe("InstructionPrompt.systemPaths OPENCODE_CONFIG_DIR", () => {
74
+ let originalConfigDir: string | undefined
75
+
76
+ beforeEach(() => {
77
+ originalConfigDir = process.env["OPENCODE_CONFIG_DIR"]
78
+ })
79
+
80
+ afterEach(() => {
81
+ if (originalConfigDir === undefined) {
82
+ delete process.env["OPENCODE_CONFIG_DIR"]
83
+ } else {
84
+ process.env["OPENCODE_CONFIG_DIR"] = originalConfigDir
85
+ }
86
+ })
87
+
88
+ test("prefers OPENCODE_CONFIG_DIR AGENTS.md over global when both exist", async () => {
89
+ await using profileTmp = await tmpdir({
90
+ init: async (dir) => {
91
+ await Bun.write(path.join(dir, "AGENTS.md"), "# Profile Instructions")
92
+ },
93
+ })
94
+ await using globalTmp = await tmpdir({
95
+ init: async (dir) => {
96
+ await Bun.write(path.join(dir, "AGENTS.md"), "# Global Instructions")
97
+ },
98
+ })
99
+ await using projectTmp = await tmpdir()
100
+
101
+ process.env["OPENCODE_CONFIG_DIR"] = profileTmp.path
102
+ const originalGlobalConfig = Global.Path.config
103
+ ;(Global.Path as { config: string }).config = globalTmp.path
104
+
105
+ try {
106
+ await Instance.provide({
107
+ directory: projectTmp.path,
108
+ fn: async () => {
109
+ const paths = await InstructionPrompt.systemPaths()
110
+ expect(paths.has(path.join(profileTmp.path, "AGENTS.md"))).toBe(true)
111
+ expect(paths.has(path.join(globalTmp.path, "AGENTS.md"))).toBe(false)
112
+ },
113
+ })
114
+ } finally {
115
+ ;(Global.Path as { config: string }).config = originalGlobalConfig
116
+ }
117
+ })
118
+
119
+ test("falls back to global AGENTS.md when OPENCODE_CONFIG_DIR has no AGENTS.md", async () => {
120
+ await using profileTmp = await tmpdir()
121
+ await using globalTmp = await tmpdir({
122
+ init: async (dir) => {
123
+ await Bun.write(path.join(dir, "AGENTS.md"), "# Global Instructions")
124
+ },
125
+ })
126
+ await using projectTmp = await tmpdir()
127
+
128
+ process.env["OPENCODE_CONFIG_DIR"] = profileTmp.path
129
+ const originalGlobalConfig = Global.Path.config
130
+ ;(Global.Path as { config: string }).config = globalTmp.path
131
+
132
+ try {
133
+ await Instance.provide({
134
+ directory: projectTmp.path,
135
+ fn: async () => {
136
+ const paths = await InstructionPrompt.systemPaths()
137
+ expect(paths.has(path.join(profileTmp.path, "AGENTS.md"))).toBe(false)
138
+ expect(paths.has(path.join(globalTmp.path, "AGENTS.md"))).toBe(true)
139
+ },
140
+ })
141
+ } finally {
142
+ ;(Global.Path as { config: string }).config = originalGlobalConfig
143
+ }
144
+ })
145
+
146
+ test("uses global AGENTS.md when OPENCODE_CONFIG_DIR is not set", async () => {
147
+ await using globalTmp = await tmpdir({
148
+ init: async (dir) => {
149
+ await Bun.write(path.join(dir, "AGENTS.md"), "# Global Instructions")
150
+ },
151
+ })
152
+ await using projectTmp = await tmpdir()
153
+
154
+ delete process.env["OPENCODE_CONFIG_DIR"]
155
+ const originalGlobalConfig = Global.Path.config
156
+ ;(Global.Path as { config: string }).config = globalTmp.path
157
+
158
+ try {
159
+ await Instance.provide({
160
+ directory: projectTmp.path,
161
+ fn: async () => {
162
+ const paths = await InstructionPrompt.systemPaths()
163
+ expect(paths.has(path.join(globalTmp.path, "AGENTS.md"))).toBe(true)
164
+ },
165
+ })
166
+ } finally {
167
+ ;(Global.Path as { config: string }).config = originalGlobalConfig
168
+ }
169
+ })
170
+ })