innocode 1.0.0

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 (434) hide show
  1. package/AGENTS.md +27 -0
  2. package/Dockerfile +18 -0
  3. package/README.md +15 -0
  4. package/bin/innocode +84 -0
  5. package/bin/opencode +84 -0
  6. package/bunfig.toml +5 -0
  7. package/package.json +126 -0
  8. package/parsers-config.ts +253 -0
  9. package/script/build.ts +198 -0
  10. package/script/postinstall.mjs +125 -0
  11. package/script/publish.ts +186 -0
  12. package/script/schema.ts +47 -0
  13. package/script/seed-e2e.ts +50 -0
  14. package/src/acp/README.md +164 -0
  15. package/src/acp/agent.ts +1676 -0
  16. package/src/acp/session.ts +117 -0
  17. package/src/acp/types.ts +23 -0
  18. package/src/agent/agent.ts +338 -0
  19. package/src/agent/generate.txt +75 -0
  20. package/src/agent/prompt/compaction.txt +14 -0
  21. package/src/agent/prompt/explore.txt +18 -0
  22. package/src/agent/prompt/summary.txt +11 -0
  23. package/src/agent/prompt/title.txt +44 -0
  24. package/src/auth/index.ts +70 -0
  25. package/src/bun/index.ts +137 -0
  26. package/src/bun/registry.ts +48 -0
  27. package/src/bus/bus-event.ts +43 -0
  28. package/src/bus/global.ts +10 -0
  29. package/src/bus/index.ts +105 -0
  30. package/src/cli/bootstrap.ts +17 -0
  31. package/src/cli/cmd/acp.ts +70 -0
  32. package/src/cli/cmd/agent.ts +257 -0
  33. package/src/cli/cmd/auth.ts +400 -0
  34. package/src/cli/cmd/cmd.ts +7 -0
  35. package/src/cli/cmd/debug/agent.ts +167 -0
  36. package/src/cli/cmd/debug/config.ts +16 -0
  37. package/src/cli/cmd/debug/file.ts +97 -0
  38. package/src/cli/cmd/debug/index.ts +48 -0
  39. package/src/cli/cmd/debug/lsp.ts +52 -0
  40. package/src/cli/cmd/debug/ripgrep.ts +87 -0
  41. package/src/cli/cmd/debug/scrap.ts +16 -0
  42. package/src/cli/cmd/debug/skill.ts +16 -0
  43. package/src/cli/cmd/debug/snapshot.ts +52 -0
  44. package/src/cli/cmd/export.ts +88 -0
  45. package/src/cli/cmd/generate.ts +38 -0
  46. package/src/cli/cmd/github.ts +1540 -0
  47. package/src/cli/cmd/import.ts +147 -0
  48. package/src/cli/cmd/mcp.ts +765 -0
  49. package/src/cli/cmd/models.ts +77 -0
  50. package/src/cli/cmd/pr.ts +113 -0
  51. package/src/cli/cmd/run.ts +598 -0
  52. package/src/cli/cmd/serve.ts +20 -0
  53. package/src/cli/cmd/session.ts +135 -0
  54. package/src/cli/cmd/stats.ts +426 -0
  55. package/src/cli/cmd/tui/app.tsx +812 -0
  56. package/src/cli/cmd/tui/attach.ts +60 -0
  57. package/src/cli/cmd/tui/component/border.tsx +21 -0
  58. package/src/cli/cmd/tui/component/dialog-agent.tsx +31 -0
  59. package/src/cli/cmd/tui/component/dialog-command.tsx +148 -0
  60. package/src/cli/cmd/tui/component/dialog-mcp.tsx +86 -0
  61. package/src/cli/cmd/tui/component/dialog-model.tsx +165 -0
  62. package/src/cli/cmd/tui/component/dialog-provider.tsx +243 -0
  63. package/src/cli/cmd/tui/component/dialog-session-list.tsx +108 -0
  64. package/src/cli/cmd/tui/component/dialog-session-rename.tsx +31 -0
  65. package/src/cli/cmd/tui/component/dialog-skill.tsx +36 -0
  66. package/src/cli/cmd/tui/component/dialog-stash.tsx +87 -0
  67. package/src/cli/cmd/tui/component/dialog-status.tsx +167 -0
  68. package/src/cli/cmd/tui/component/dialog-tag.tsx +44 -0
  69. package/src/cli/cmd/tui/component/dialog-theme-list.tsx +50 -0
  70. package/src/cli/cmd/tui/component/logo.tsx +85 -0
  71. package/src/cli/cmd/tui/component/prompt/autocomplete.tsx +666 -0
  72. package/src/cli/cmd/tui/component/prompt/frecency.tsx +89 -0
  73. package/src/cli/cmd/tui/component/prompt/history.tsx +108 -0
  74. package/src/cli/cmd/tui/component/prompt/index.tsx +1153 -0
  75. package/src/cli/cmd/tui/component/prompt/stash.tsx +101 -0
  76. package/src/cli/cmd/tui/component/spinner.tsx +24 -0
  77. package/src/cli/cmd/tui/component/textarea-keybindings.ts +73 -0
  78. package/src/cli/cmd/tui/component/tips.tsx +153 -0
  79. package/src/cli/cmd/tui/component/todo-item.tsx +32 -0
  80. package/src/cli/cmd/tui/context/args.tsx +15 -0
  81. package/src/cli/cmd/tui/context/directory.ts +13 -0
  82. package/src/cli/cmd/tui/context/exit.tsx +54 -0
  83. package/src/cli/cmd/tui/context/helper.tsx +25 -0
  84. package/src/cli/cmd/tui/context/keybind.tsx +100 -0
  85. package/src/cli/cmd/tui/context/kv.tsx +52 -0
  86. package/src/cli/cmd/tui/context/local.tsx +409 -0
  87. package/src/cli/cmd/tui/context/prompt.tsx +18 -0
  88. package/src/cli/cmd/tui/context/route.tsx +46 -0
  89. package/src/cli/cmd/tui/context/sdk.tsx +101 -0
  90. package/src/cli/cmd/tui/context/sync.tsx +470 -0
  91. package/src/cli/cmd/tui/context/theme/aura.json +69 -0
  92. package/src/cli/cmd/tui/context/theme/ayu.json +80 -0
  93. package/src/cli/cmd/tui/context/theme/carbonfox.json +248 -0
  94. package/src/cli/cmd/tui/context/theme/catppuccin-frappe.json +233 -0
  95. package/src/cli/cmd/tui/context/theme/catppuccin-macchiato.json +233 -0
  96. package/src/cli/cmd/tui/context/theme/catppuccin.json +112 -0
  97. package/src/cli/cmd/tui/context/theme/cobalt2.json +228 -0
  98. package/src/cli/cmd/tui/context/theme/cursor.json +249 -0
  99. package/src/cli/cmd/tui/context/theme/dracula.json +219 -0
  100. package/src/cli/cmd/tui/context/theme/everforest.json +241 -0
  101. package/src/cli/cmd/tui/context/theme/flexoki.json +237 -0
  102. package/src/cli/cmd/tui/context/theme/github.json +233 -0
  103. package/src/cli/cmd/tui/context/theme/gruvbox.json +242 -0
  104. package/src/cli/cmd/tui/context/theme/innocode.json +245 -0
  105. package/src/cli/cmd/tui/context/theme/kanagawa.json +77 -0
  106. package/src/cli/cmd/tui/context/theme/lucent-orng.json +237 -0
  107. package/src/cli/cmd/tui/context/theme/material.json +235 -0
  108. package/src/cli/cmd/tui/context/theme/matrix.json +77 -0
  109. package/src/cli/cmd/tui/context/theme/mercury.json +252 -0
  110. package/src/cli/cmd/tui/context/theme/monokai.json +221 -0
  111. package/src/cli/cmd/tui/context/theme/nightowl.json +221 -0
  112. package/src/cli/cmd/tui/context/theme/nord.json +223 -0
  113. package/src/cli/cmd/tui/context/theme/one-dark.json +84 -0
  114. package/src/cli/cmd/tui/context/theme/orng.json +249 -0
  115. package/src/cli/cmd/tui/context/theme/osaka-jade.json +93 -0
  116. package/src/cli/cmd/tui/context/theme/palenight.json +222 -0
  117. package/src/cli/cmd/tui/context/theme/rosepine.json +234 -0
  118. package/src/cli/cmd/tui/context/theme/solarized.json +223 -0
  119. package/src/cli/cmd/tui/context/theme/synthwave84.json +226 -0
  120. package/src/cli/cmd/tui/context/theme/tokyonight.json +243 -0
  121. package/src/cli/cmd/tui/context/theme/vercel.json +245 -0
  122. package/src/cli/cmd/tui/context/theme/vesper.json +218 -0
  123. package/src/cli/cmd/tui/context/theme/zenburn.json +223 -0
  124. package/src/cli/cmd/tui/context/theme.tsx +1154 -0
  125. package/src/cli/cmd/tui/event.ts +48 -0
  126. package/src/cli/cmd/tui/routes/home.tsx +145 -0
  127. package/src/cli/cmd/tui/routes/session/dialog-fork-from-timeline.tsx +64 -0
  128. package/src/cli/cmd/tui/routes/session/dialog-message.tsx +109 -0
  129. package/src/cli/cmd/tui/routes/session/dialog-subagent.tsx +26 -0
  130. package/src/cli/cmd/tui/routes/session/dialog-timeline.tsx +47 -0
  131. package/src/cli/cmd/tui/routes/session/footer.tsx +91 -0
  132. package/src/cli/cmd/tui/routes/session/header.tsx +135 -0
  133. package/src/cli/cmd/tui/routes/session/index.tsx +2139 -0
  134. package/src/cli/cmd/tui/routes/session/permission.tsx +508 -0
  135. package/src/cli/cmd/tui/routes/session/question.tsx +466 -0
  136. package/src/cli/cmd/tui/routes/session/sidebar.tsx +313 -0
  137. package/src/cli/cmd/tui/thread.ts +188 -0
  138. package/src/cli/cmd/tui/ui/dialog-alert.tsx +59 -0
  139. package/src/cli/cmd/tui/ui/dialog-confirm.tsx +85 -0
  140. package/src/cli/cmd/tui/ui/dialog-export-options.tsx +207 -0
  141. package/src/cli/cmd/tui/ui/dialog-help.tsx +40 -0
  142. package/src/cli/cmd/tui/ui/dialog-prompt.tsx +80 -0
  143. package/src/cli/cmd/tui/ui/dialog-select.tsx +401 -0
  144. package/src/cli/cmd/tui/ui/dialog.tsx +167 -0
  145. package/src/cli/cmd/tui/ui/link.tsx +28 -0
  146. package/src/cli/cmd/tui/ui/spinner.ts +368 -0
  147. package/src/cli/cmd/tui/ui/toast.tsx +100 -0
  148. package/src/cli/cmd/tui/util/clipboard.ts +159 -0
  149. package/src/cli/cmd/tui/util/editor.ts +32 -0
  150. package/src/cli/cmd/tui/util/signal.ts +7 -0
  151. package/src/cli/cmd/tui/util/terminal.ts +114 -0
  152. package/src/cli/cmd/tui/util/transcript.ts +98 -0
  153. package/src/cli/cmd/tui/win32.ts +129 -0
  154. package/src/cli/cmd/tui/worker.ts +152 -0
  155. package/src/cli/cmd/uninstall.ts +363 -0
  156. package/src/cli/cmd/upgrade.ts +73 -0
  157. package/src/cli/cmd/web.ts +81 -0
  158. package/src/cli/error.ts +57 -0
  159. package/src/cli/logo.ts +6 -0
  160. package/src/cli/network.ts +60 -0
  161. package/src/cli/ui.ts +113 -0
  162. package/src/cli/upgrade.ts +25 -0
  163. package/src/command/index.ts +150 -0
  164. package/src/command/template/initialize.txt +10 -0
  165. package/src/command/template/review.txt +101 -0
  166. package/src/config/config.ts +1517 -0
  167. package/src/config/markdown.ts +98 -0
  168. package/src/env/index.ts +28 -0
  169. package/src/file/ignore.ts +83 -0
  170. package/src/file/index.ts +583 -0
  171. package/src/file/ripgrep.ts +375 -0
  172. package/src/file/time.ts +69 -0
  173. package/src/file/watcher.ts +127 -0
  174. package/src/flag/flag.ts +148 -0
  175. package/src/format/formatter.ts +366 -0
  176. package/src/format/index.ts +137 -0
  177. package/src/global/index.ts +80 -0
  178. package/src/id/id.ts +83 -0
  179. package/src/ide/index.ts +76 -0
  180. package/src/index.ts +160 -0
  181. package/src/installation/index.ts +268 -0
  182. package/src/lsp/client.ts +252 -0
  183. package/src/lsp/index.ts +485 -0
  184. package/src/lsp/language.ts +119 -0
  185. package/src/lsp/server.ts +2046 -0
  186. package/src/mcp/auth.ts +132 -0
  187. package/src/mcp/index.ts +937 -0
  188. package/src/mcp/oauth-callback.ts +200 -0
  189. package/src/mcp/oauth-provider.ts +154 -0
  190. package/src/patch/index.ts +680 -0
  191. package/src/permission/arity.ts +163 -0
  192. package/src/permission/index.ts +210 -0
  193. package/src/permission/next.ts +280 -0
  194. package/src/plugin/codex.ts +624 -0
  195. package/src/plugin/copilot.ts +327 -0
  196. package/src/plugin/index.ts +138 -0
  197. package/src/project/bootstrap.ts +35 -0
  198. package/src/project/instance.ts +114 -0
  199. package/src/project/project.ts +371 -0
  200. package/src/project/state.ts +70 -0
  201. package/src/project/vcs.ts +76 -0
  202. package/src/provider/auth.ts +147 -0
  203. package/src/provider/error.ts +189 -0
  204. package/src/provider/models.ts +133 -0
  205. package/src/provider/provider.ts +1370 -0
  206. package/src/provider/sdk/copilot/README.md +5 -0
  207. package/src/provider/sdk/copilot/chat/convert-to-openai-compatible-chat-messages.ts +164 -0
  208. package/src/provider/sdk/copilot/chat/get-response-metadata.ts +15 -0
  209. package/src/provider/sdk/copilot/chat/map-openai-compatible-finish-reason.ts +17 -0
  210. package/src/provider/sdk/copilot/chat/openai-compatible-api-types.ts +64 -0
  211. package/src/provider/sdk/copilot/chat/openai-compatible-chat-language-model.ts +780 -0
  212. package/src/provider/sdk/copilot/chat/openai-compatible-chat-options.ts +28 -0
  213. package/src/provider/sdk/copilot/chat/openai-compatible-metadata-extractor.ts +44 -0
  214. package/src/provider/sdk/copilot/chat/openai-compatible-prepare-tools.ts +87 -0
  215. package/src/provider/sdk/copilot/copilot-provider.ts +100 -0
  216. package/src/provider/sdk/copilot/index.ts +2 -0
  217. package/src/provider/sdk/copilot/openai-compatible-error.ts +27 -0
  218. package/src/provider/sdk/copilot/responses/convert-to-openai-responses-input.ts +303 -0
  219. package/src/provider/sdk/copilot/responses/map-openai-responses-finish-reason.ts +22 -0
  220. package/src/provider/sdk/copilot/responses/openai-config.ts +18 -0
  221. package/src/provider/sdk/copilot/responses/openai-error.ts +22 -0
  222. package/src/provider/sdk/copilot/responses/openai-responses-api-types.ts +207 -0
  223. package/src/provider/sdk/copilot/responses/openai-responses-language-model.ts +1732 -0
  224. package/src/provider/sdk/copilot/responses/openai-responses-prepare-tools.ts +177 -0
  225. package/src/provider/sdk/copilot/responses/openai-responses-settings.ts +1 -0
  226. package/src/provider/sdk/copilot/responses/tool/code-interpreter.ts +88 -0
  227. package/src/provider/sdk/copilot/responses/tool/file-search.ts +128 -0
  228. package/src/provider/sdk/copilot/responses/tool/image-generation.ts +115 -0
  229. package/src/provider/sdk/copilot/responses/tool/local-shell.ts +65 -0
  230. package/src/provider/sdk/copilot/responses/tool/web-search-preview.ts +104 -0
  231. package/src/provider/sdk/copilot/responses/tool/web-search.ts +103 -0
  232. package/src/provider/transform.ts +806 -0
  233. package/src/pty/index.ts +286 -0
  234. package/src/question/index.ts +171 -0
  235. package/src/scheduler/index.ts +61 -0
  236. package/src/server/error.ts +36 -0
  237. package/src/server/event.ts +7 -0
  238. package/src/server/mdns.ts +60 -0
  239. package/src/server/routes/config.ts +92 -0
  240. package/src/server/routes/experimental.ts +208 -0
  241. package/src/server/routes/file.ts +197 -0
  242. package/src/server/routes/global.ts +183 -0
  243. package/src/server/routes/mcp.ts +225 -0
  244. package/src/server/routes/permission.ts +68 -0
  245. package/src/server/routes/project.ts +82 -0
  246. package/src/server/routes/provider.ts +179 -0
  247. package/src/server/routes/pty.ts +176 -0
  248. package/src/server/routes/question.ts +98 -0
  249. package/src/server/routes/session.ts +939 -0
  250. package/src/server/routes/tui.ts +379 -0
  251. package/src/server/server.ts +621 -0
  252. package/src/session/compaction.ts +261 -0
  253. package/src/session/index.ts +543 -0
  254. package/src/session/instruction.ts +197 -0
  255. package/src/session/llm.ts +283 -0
  256. package/src/session/message-v2.ts +841 -0
  257. package/src/session/message.ts +189 -0
  258. package/src/session/processor.ts +410 -0
  259. package/src/session/prompt/anthropic-20250930.txt +166 -0
  260. package/src/session/prompt/anthropic.txt +105 -0
  261. package/src/session/prompt/beast.txt +147 -0
  262. package/src/session/prompt/build-switch.txt +5 -0
  263. package/src/session/prompt/codex_header.txt +79 -0
  264. package/src/session/prompt/copilot-gpt-5.txt +143 -0
  265. package/src/session/prompt/gemini.txt +155 -0
  266. package/src/session/prompt/max-steps.txt +16 -0
  267. package/src/session/prompt/plan-reminder-anthropic.txt +67 -0
  268. package/src/session/prompt/plan.txt +26 -0
  269. package/src/session/prompt/qwen.txt +109 -0
  270. package/src/session/prompt/trinity.txt +97 -0
  271. package/src/session/prompt.ts +1964 -0
  272. package/src/session/retry.ts +101 -0
  273. package/src/session/revert.ts +121 -0
  274. package/src/session/status.ts +76 -0
  275. package/src/session/summary.ts +203 -0
  276. package/src/session/system.ts +54 -0
  277. package/src/session/todo.ts +37 -0
  278. package/src/share/share-next.ts +200 -0
  279. package/src/share/share.ts +92 -0
  280. package/src/shell/shell.ts +67 -0
  281. package/src/skill/discovery.ts +97 -0
  282. package/src/skill/index.ts +1 -0
  283. package/src/skill/skill.ts +188 -0
  284. package/src/snapshot/index.ts +255 -0
  285. package/src/storage/storage.ts +227 -0
  286. package/src/tool/apply_patch.ts +281 -0
  287. package/src/tool/apply_patch.txt +33 -0
  288. package/src/tool/bash.ts +269 -0
  289. package/src/tool/bash.txt +115 -0
  290. package/src/tool/batch.ts +175 -0
  291. package/src/tool/batch.txt +24 -0
  292. package/src/tool/codesearch.ts +132 -0
  293. package/src/tool/codesearch.txt +12 -0
  294. package/src/tool/edit.ts +655 -0
  295. package/src/tool/edit.txt +10 -0
  296. package/src/tool/external-directory.ts +32 -0
  297. package/src/tool/glob.ts +80 -0
  298. package/src/tool/glob.txt +6 -0
  299. package/src/tool/grep.ts +150 -0
  300. package/src/tool/grep.txt +8 -0
  301. package/src/tool/invalid.ts +17 -0
  302. package/src/tool/ls.ts +121 -0
  303. package/src/tool/ls.txt +1 -0
  304. package/src/tool/lsp.ts +96 -0
  305. package/src/tool/lsp.txt +19 -0
  306. package/src/tool/multiedit.ts +46 -0
  307. package/src/tool/multiedit.txt +41 -0
  308. package/src/tool/plan-enter.txt +14 -0
  309. package/src/tool/plan-exit.txt +13 -0
  310. package/src/tool/plan.ts +130 -0
  311. package/src/tool/question.ts +33 -0
  312. package/src/tool/question.txt +10 -0
  313. package/src/tool/read.ts +261 -0
  314. package/src/tool/read.txt +14 -0
  315. package/src/tool/registry.ts +160 -0
  316. package/src/tool/skill.ts +123 -0
  317. package/src/tool/task.ts +165 -0
  318. package/src/tool/task.txt +60 -0
  319. package/src/tool/todo.ts +53 -0
  320. package/src/tool/todoread.txt +14 -0
  321. package/src/tool/todowrite.txt +167 -0
  322. package/src/tool/tool.ts +89 -0
  323. package/src/tool/truncation.ts +106 -0
  324. package/src/tool/webfetch.ts +186 -0
  325. package/src/tool/webfetch.txt +13 -0
  326. package/src/tool/websearch.ts +150 -0
  327. package/src/tool/websearch.txt +14 -0
  328. package/src/tool/write.ts +85 -0
  329. package/src/tool/write.txt +8 -0
  330. package/src/util/abort.ts +35 -0
  331. package/src/util/archive.ts +16 -0
  332. package/src/util/color.ts +19 -0
  333. package/src/util/context.ts +25 -0
  334. package/src/util/defer.ts +12 -0
  335. package/src/util/eventloop.ts +20 -0
  336. package/src/util/filesystem.ts +93 -0
  337. package/src/util/fn.ts +11 -0
  338. package/src/util/format.ts +20 -0
  339. package/src/util/iife.ts +3 -0
  340. package/src/util/keybind.ts +103 -0
  341. package/src/util/lazy.ts +18 -0
  342. package/src/util/locale.ts +81 -0
  343. package/src/util/lock.ts +98 -0
  344. package/src/util/log.ts +180 -0
  345. package/src/util/proxied.ts +3 -0
  346. package/src/util/queue.ts +32 -0
  347. package/src/util/rpc.ts +66 -0
  348. package/src/util/scrap.ts +10 -0
  349. package/src/util/signal.ts +12 -0
  350. package/src/util/timeout.ts +14 -0
  351. package/src/util/token.ts +7 -0
  352. package/src/util/wildcard.ts +56 -0
  353. package/src/worktree/index.ts +612 -0
  354. package/sst-env.d.ts +9 -0
  355. package/test/acp/agent-interface.test.ts +51 -0
  356. package/test/acp/event-subscription.test.ts +436 -0
  357. package/test/agent/agent.test.ts +675 -0
  358. package/test/bun.test.ts +53 -0
  359. package/test/cli/github-action.test.ts +161 -0
  360. package/test/cli/github-remote.test.ts +80 -0
  361. package/test/cli/import.test.ts +38 -0
  362. package/test/cli/tui/transcript.test.ts +322 -0
  363. package/test/config/agent-color.test.ts +71 -0
  364. package/test/config/config.test.ts +1802 -0
  365. package/test/config/fixtures/empty-frontmatter.md +4 -0
  366. package/test/config/fixtures/frontmatter.md +28 -0
  367. package/test/config/fixtures/markdown-header.md +11 -0
  368. package/test/config/fixtures/no-frontmatter.md +1 -0
  369. package/test/config/fixtures/weird-model-id.md +13 -0
  370. package/test/config/markdown.test.ts +228 -0
  371. package/test/file/ignore.test.ts +10 -0
  372. package/test/file/path-traversal.test.ts +198 -0
  373. package/test/file/ripgrep.test.ts +39 -0
  374. package/test/fixture/fixture.ts +45 -0
  375. package/test/fixture/lsp/fake-lsp-server.js +77 -0
  376. package/test/ide/ide.test.ts +82 -0
  377. package/test/keybind.test.ts +421 -0
  378. package/test/lsp/client.test.ts +95 -0
  379. package/test/mcp/headers.test.ts +153 -0
  380. package/test/mcp/oauth-browser.test.ts +249 -0
  381. package/test/memory/abort-leak.test.ts +136 -0
  382. package/test/patch/patch.test.ts +348 -0
  383. package/test/permission/arity.test.ts +33 -0
  384. package/test/permission/next.test.ts +690 -0
  385. package/test/permission-task.test.ts +319 -0
  386. package/test/plugin/auth-override.test.ts +44 -0
  387. package/test/plugin/codex.test.ts +123 -0
  388. package/test/preload.ts +63 -0
  389. package/test/project/project.test.ts +120 -0
  390. package/test/provider/amazon-bedrock.test.ts +445 -0
  391. package/test/provider/copilot/convert-to-copilot-messages.test.ts +523 -0
  392. package/test/provider/copilot/copilot-chat-model.test.ts +592 -0
  393. package/test/provider/gitlab-duo.test.ts +262 -0
  394. package/test/provider/provider.test.ts +2129 -0
  395. package/test/provider/transform.test.ts +1928 -0
  396. package/test/question/question.test.ts +300 -0
  397. package/test/scheduler.test.ts +73 -0
  398. package/test/server/session-list.test.ts +39 -0
  399. package/test/server/session-select.test.ts +78 -0
  400. package/test/session/compaction.test.ts +423 -0
  401. package/test/session/instruction.test.ts +170 -0
  402. package/test/session/llm.test.ts +667 -0
  403. package/test/session/message-v2.test.ts +924 -0
  404. package/test/session/prompt-missing-file.test.ts +53 -0
  405. package/test/session/prompt-special-chars.test.ts +56 -0
  406. package/test/session/prompt-variant.test.ts +68 -0
  407. package/test/session/retry.test.ts +188 -0
  408. package/test/session/revert-compact.test.ts +285 -0
  409. package/test/session/session.test.ts +71 -0
  410. package/test/session/structured-output-integration.test.ts +233 -0
  411. package/test/session/structured-output.test.ts +385 -0
  412. package/test/skill/discovery.test.ts +60 -0
  413. package/test/skill/skill.test.ts +388 -0
  414. package/test/snapshot/snapshot.test.ts +1040 -0
  415. package/test/tool/__snapshots__/tool.test.ts.snap +9 -0
  416. package/test/tool/apply_patch.test.ts +559 -0
  417. package/test/tool/bash.test.ts +399 -0
  418. package/test/tool/external-directory.test.ts +127 -0
  419. package/test/tool/fixtures/large-image.png +0 -0
  420. package/test/tool/fixtures/models-api.json +38413 -0
  421. package/test/tool/grep.test.ts +110 -0
  422. package/test/tool/question.test.ts +107 -0
  423. package/test/tool/read.test.ts +421 -0
  424. package/test/tool/registry.test.ts +122 -0
  425. package/test/tool/skill.test.ts +112 -0
  426. package/test/tool/truncation.test.ts +159 -0
  427. package/test/util/filesystem.test.ts +39 -0
  428. package/test/util/format.test.ts +59 -0
  429. package/test/util/iife.test.ts +36 -0
  430. package/test/util/lazy.test.ts +50 -0
  431. package/test/util/lock.test.ts +72 -0
  432. package/test/util/timeout.test.ts +21 -0
  433. package/test/util/wildcard.test.ts +75 -0
  434. package/tsconfig.json +16 -0
@@ -0,0 +1,80 @@
1
+ import fs from "fs/promises"
2
+ import { xdgData, xdgCache, xdgConfig, xdgState } from "xdg-basedir"
3
+ import path from "path"
4
+ import os from "os"
5
+
6
+ const app = "innocode"
7
+ const legacyApp = "opencode"
8
+
9
+ const data = path.join(xdgData!, app)
10
+ const cache = path.join(xdgCache!, app)
11
+ const config = path.join(xdgConfig!, app)
12
+ const state = path.join(xdgState!, app)
13
+
14
+ const legacyData = path.join(xdgData!, legacyApp)
15
+ const legacyConfig = path.join(xdgConfig!, legacyApp)
16
+ const legacyState = path.join(xdgState!, legacyApp)
17
+
18
+ export namespace Global {
19
+ export const Path = {
20
+ // Allow override via OPENCODE_TEST_HOME for test isolation
21
+ get home() {
22
+ return process.env.OPENCODE_TEST_HOME || os.homedir()
23
+ },
24
+ data,
25
+ bin: path.join(data, "bin"),
26
+ log: path.join(data, "log"),
27
+ cache,
28
+ config,
29
+ state,
30
+ }
31
+ }
32
+
33
+ async function pathExists(target: string) {
34
+ return fs
35
+ .access(target)
36
+ .then(() => true)
37
+ .catch(() => false)
38
+ }
39
+
40
+ async function migrateLegacyDir(source: string, dest: string) {
41
+ const sourceExists = await pathExists(source)
42
+ const destExists = await pathExists(dest)
43
+ if (!sourceExists || destExists) return
44
+ await fs.cp(source, dest, { recursive: true, errorOnExist: false })
45
+ }
46
+
47
+ await Promise.all([
48
+ migrateLegacyDir(legacyData, data),
49
+ migrateLegacyDir(legacyConfig, config),
50
+ migrateLegacyDir(legacyState, state),
51
+ ])
52
+
53
+ await Promise.all([
54
+ fs.mkdir(Global.Path.data, { recursive: true }),
55
+ fs.mkdir(Global.Path.config, { recursive: true }),
56
+ fs.mkdir(Global.Path.state, { recursive: true }),
57
+ fs.mkdir(Global.Path.log, { recursive: true }),
58
+ fs.mkdir(Global.Path.bin, { recursive: true }),
59
+ ])
60
+
61
+ const CACHE_VERSION = "21"
62
+
63
+ const version = await Bun.file(path.join(Global.Path.cache, "version"))
64
+ .text()
65
+ .catch(() => "0")
66
+
67
+ if (version !== CACHE_VERSION) {
68
+ try {
69
+ const contents = await fs.readdir(Global.Path.cache)
70
+ await Promise.all(
71
+ contents.map((item) =>
72
+ fs.rm(path.join(Global.Path.cache, item), {
73
+ recursive: true,
74
+ force: true,
75
+ }),
76
+ ),
77
+ )
78
+ } catch (e) {}
79
+ await Bun.file(path.join(Global.Path.cache, "version")).write(CACHE_VERSION)
80
+ }
package/src/id/id.ts ADDED
@@ -0,0 +1,83 @@
1
+ import z from "zod"
2
+ import { randomBytes } from "crypto"
3
+
4
+ export namespace Identifier {
5
+ const prefixes = {
6
+ session: "ses",
7
+ message: "msg",
8
+ permission: "per",
9
+ question: "que",
10
+ user: "usr",
11
+ part: "prt",
12
+ pty: "pty",
13
+ tool: "tool",
14
+ } as const
15
+
16
+ export function schema(prefix: keyof typeof prefixes) {
17
+ return z.string().startsWith(prefixes[prefix])
18
+ }
19
+
20
+ const LENGTH = 26
21
+
22
+ // State for monotonic ID generation
23
+ let lastTimestamp = 0
24
+ let counter = 0
25
+
26
+ export function ascending(prefix: keyof typeof prefixes, given?: string) {
27
+ return generateID(prefix, false, given)
28
+ }
29
+
30
+ export function descending(prefix: keyof typeof prefixes, given?: string) {
31
+ return generateID(prefix, true, given)
32
+ }
33
+
34
+ function generateID(prefix: keyof typeof prefixes, descending: boolean, given?: string): string {
35
+ if (!given) {
36
+ return create(prefix, descending)
37
+ }
38
+
39
+ if (!given.startsWith(prefixes[prefix])) {
40
+ throw new Error(`ID ${given} does not start with ${prefixes[prefix]}`)
41
+ }
42
+ return given
43
+ }
44
+
45
+ function randomBase62(length: number): string {
46
+ const chars = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz"
47
+ let result = ""
48
+ const bytes = randomBytes(length)
49
+ for (let i = 0; i < length; i++) {
50
+ result += chars[bytes[i] % 62]
51
+ }
52
+ return result
53
+ }
54
+
55
+ export function create(prefix: keyof typeof prefixes, descending: boolean, timestamp?: number): string {
56
+ const currentTimestamp = timestamp ?? Date.now()
57
+
58
+ if (currentTimestamp !== lastTimestamp) {
59
+ lastTimestamp = currentTimestamp
60
+ counter = 0
61
+ }
62
+ counter++
63
+
64
+ let now = BigInt(currentTimestamp) * BigInt(0x1000) + BigInt(counter)
65
+
66
+ now = descending ? ~now : now
67
+
68
+ const timeBytes = Buffer.alloc(6)
69
+ for (let i = 0; i < 6; i++) {
70
+ timeBytes[i] = Number((now >> BigInt(40 - 8 * i)) & BigInt(0xff))
71
+ }
72
+
73
+ return prefixes[prefix] + "_" + timeBytes.toString("hex") + randomBase62(LENGTH - 12)
74
+ }
75
+
76
+ /** Extract timestamp from an ascending ID. Does not work with descending IDs. */
77
+ export function timestamp(id: string): number {
78
+ const prefix = id.split("_")[0]
79
+ const hex = id.slice(prefix.length + 1, prefix.length + 13)
80
+ const encoded = BigInt("0x" + hex)
81
+ return Number(encoded / BigInt(0x1000))
82
+ }
83
+ }
@@ -0,0 +1,76 @@
1
+ import { BusEvent } from "@/bus/bus-event"
2
+ import { Bus } from "@/bus"
3
+ import { spawn } from "bun"
4
+ import z from "zod"
5
+ import { NamedError } from "@opencode-ai/util/error"
6
+ import { Log } from "../util/log"
7
+
8
+ const SUPPORTED_IDES = [
9
+ { name: "Windsurf" as const, cmd: "windsurf" },
10
+ { name: "Visual Studio Code - Insiders" as const, cmd: "code-insiders" },
11
+ { name: "Visual Studio Code" as const, cmd: "code" },
12
+ { name: "Cursor" as const, cmd: "cursor" },
13
+ { name: "VSCodium" as const, cmd: "codium" },
14
+ ]
15
+
16
+ export namespace Ide {
17
+ const log = Log.create({ service: "ide" })
18
+
19
+ export const Event = {
20
+ Installed: BusEvent.define(
21
+ "ide.installed",
22
+ z.object({
23
+ ide: z.string(),
24
+ }),
25
+ ),
26
+ }
27
+
28
+ export const AlreadyInstalledError = NamedError.create("AlreadyInstalledError", z.object({}))
29
+
30
+ export const InstallFailedError = NamedError.create(
31
+ "InstallFailedError",
32
+ z.object({
33
+ stderr: z.string(),
34
+ }),
35
+ )
36
+
37
+ export function ide() {
38
+ if (process.env["TERM_PROGRAM"] === "vscode") {
39
+ const v = process.env["GIT_ASKPASS"]
40
+ for (const ide of SUPPORTED_IDES) {
41
+ if (v?.includes(ide.name)) return ide.name
42
+ }
43
+ }
44
+ return "unknown"
45
+ }
46
+
47
+ export function alreadyInstalled() {
48
+ return process.env["OPENCODE_CALLER"] === "vscode" || process.env["OPENCODE_CALLER"] === "vscode-insiders"
49
+ }
50
+
51
+ export async function install(ide: (typeof SUPPORTED_IDES)[number]["name"]) {
52
+ const cmd = SUPPORTED_IDES.find((i) => i.name === ide)?.cmd
53
+ if (!cmd) throw new Error(`Unknown IDE: ${ide}`)
54
+
55
+ const p = spawn([cmd, "--install-extension", "sst-dev.opencode"], {
56
+ stdout: "pipe",
57
+ stderr: "pipe",
58
+ })
59
+ await p.exited
60
+ const stdout = await new Response(p.stdout).text()
61
+ const stderr = await new Response(p.stderr).text()
62
+
63
+ log.info("installed", {
64
+ ide,
65
+ stdout,
66
+ stderr,
67
+ })
68
+
69
+ if (p.exitCode !== 0) {
70
+ throw new InstallFailedError({ stderr })
71
+ }
72
+ if (stdout.includes("already installed")) {
73
+ throw new AlreadyInstalledError({})
74
+ }
75
+ }
76
+ }
package/src/index.ts ADDED
@@ -0,0 +1,160 @@
1
+ import yargs from "yargs"
2
+ import { hideBin } from "yargs/helpers"
3
+ import { RunCommand } from "./cli/cmd/run"
4
+ import { GenerateCommand } from "./cli/cmd/generate"
5
+ import { Log } from "./util/log"
6
+ import { AuthCommand } from "./cli/cmd/auth"
7
+ import { AgentCommand } from "./cli/cmd/agent"
8
+ import { UpgradeCommand } from "./cli/cmd/upgrade"
9
+ import { UninstallCommand } from "./cli/cmd/uninstall"
10
+ import { ModelsCommand } from "./cli/cmd/models"
11
+ import { UI } from "./cli/ui"
12
+ import { Installation } from "./installation"
13
+ import { NamedError } from "@opencode-ai/util/error"
14
+ import { FormatError } from "./cli/error"
15
+ import { ServeCommand } from "./cli/cmd/serve"
16
+ import { DebugCommand } from "./cli/cmd/debug"
17
+ import { StatsCommand } from "./cli/cmd/stats"
18
+ import { McpCommand } from "./cli/cmd/mcp"
19
+ import { GithubCommand } from "./cli/cmd/github"
20
+ import { ExportCommand } from "./cli/cmd/export"
21
+ import { ImportCommand } from "./cli/cmd/import"
22
+ import { AttachCommand } from "./cli/cmd/tui/attach"
23
+ import { TuiThreadCommand } from "./cli/cmd/tui/thread"
24
+ import { AcpCommand } from "./cli/cmd/acp"
25
+ import { EOL } from "os"
26
+ import { WebCommand } from "./cli/cmd/web"
27
+ import { PrCommand } from "./cli/cmd/pr"
28
+ import { SessionCommand } from "./cli/cmd/session"
29
+
30
+ process.on("unhandledRejection", (e) => {
31
+ Log.Default.error("rejection", {
32
+ e: e instanceof Error ? e.message : e,
33
+ })
34
+ })
35
+
36
+ process.on("uncaughtException", (e) => {
37
+ Log.Default.error("exception", {
38
+ e: e instanceof Error ? e.message : e,
39
+ })
40
+ })
41
+
42
+ const cli = yargs(hideBin(process.argv))
43
+ .parserConfiguration({ "populate--": true })
44
+ .scriptName("innocode")
45
+ .wrap(100)
46
+ .help("help", "show help")
47
+ .alias("help", "h")
48
+ .version("version", "show version number", Installation.VERSION)
49
+ .alias("version", "v")
50
+ .option("print-logs", {
51
+ describe: "print logs to stderr",
52
+ type: "boolean",
53
+ })
54
+ .option("log-level", {
55
+ describe: "log level",
56
+ type: "string",
57
+ choices: ["DEBUG", "INFO", "WARN", "ERROR"],
58
+ })
59
+ .middleware(async (opts) => {
60
+ await Log.init({
61
+ print: process.argv.includes("--print-logs"),
62
+ dev: Installation.isLocal(),
63
+ level: (() => {
64
+ if (opts.logLevel) return opts.logLevel as Log.Level
65
+ if (Installation.isLocal()) return "DEBUG"
66
+ return "INFO"
67
+ })(),
68
+ })
69
+
70
+ process.env.AGENT = "1"
71
+ process.env.OPENCODE = "1"
72
+ process.env.INNOCODE = "1"
73
+
74
+ Log.Default.info("innocode", {
75
+ version: Installation.VERSION,
76
+ args: process.argv.slice(2),
77
+ })
78
+ })
79
+ .usage("\n" + UI.logo())
80
+ .completion("completion", "generate shell completion script")
81
+ .command(AcpCommand)
82
+ .command(McpCommand)
83
+ .command(TuiThreadCommand)
84
+ .command(AttachCommand)
85
+ .command(RunCommand)
86
+ .command(GenerateCommand)
87
+ .command(DebugCommand)
88
+ .command(AuthCommand)
89
+ .command(AgentCommand)
90
+ .command(UpgradeCommand)
91
+ .command(UninstallCommand)
92
+ .command(ServeCommand)
93
+ .command(WebCommand)
94
+ .command(ModelsCommand)
95
+ .command(StatsCommand)
96
+ .command(ExportCommand)
97
+ .command(ImportCommand)
98
+ .command(GithubCommand)
99
+ .command(PrCommand)
100
+ .command(SessionCommand)
101
+ .fail((msg, err) => {
102
+ if (
103
+ msg?.startsWith("Unknown argument") ||
104
+ msg?.startsWith("Not enough non-option arguments") ||
105
+ msg?.startsWith("Invalid values:")
106
+ ) {
107
+ if (err) throw err
108
+ cli.showHelp("log")
109
+ }
110
+ if (err) throw err
111
+ process.exit(1)
112
+ })
113
+ .strict()
114
+
115
+ try {
116
+ await cli.parse()
117
+ } catch (e) {
118
+ let data: Record<string, any> = {}
119
+ if (e instanceof NamedError) {
120
+ const obj = e.toObject()
121
+ Object.assign(data, {
122
+ ...obj.data,
123
+ })
124
+ }
125
+
126
+ if (e instanceof Error) {
127
+ Object.assign(data, {
128
+ name: e.name,
129
+ message: e.message,
130
+ cause: e.cause?.toString(),
131
+ stack: e.stack,
132
+ })
133
+ }
134
+
135
+ if (e instanceof ResolveMessage) {
136
+ Object.assign(data, {
137
+ name: e.name,
138
+ message: e.message,
139
+ code: e.code,
140
+ specifier: e.specifier,
141
+ referrer: e.referrer,
142
+ position: e.position,
143
+ importKind: e.importKind,
144
+ })
145
+ }
146
+ Log.Default.error("fatal", data)
147
+ const formatted = FormatError(e)
148
+ if (formatted) UI.error(formatted)
149
+ if (formatted === undefined) {
150
+ UI.error("Unexpected error, check log file at " + Log.file() + " for more details" + EOL)
151
+ console.error(e instanceof Error ? e.message : String(e))
152
+ }
153
+ process.exitCode = 1
154
+ } finally {
155
+ // Some subprocesses don't react properly to SIGTERM and similar signals.
156
+ // Most notably, some docker-container-based MCP servers don't handle such signals unless
157
+ // run using `docker run --init`.
158
+ // Explicitly exit to avoid any hanging subprocesses.
159
+ process.exit()
160
+ }
@@ -0,0 +1,268 @@
1
+ import { BusEvent } from "@/bus/bus-event"
2
+ import path from "path"
3
+ import { $ } from "bun"
4
+ import z from "zod"
5
+ import { NamedError } from "@opencode-ai/util/error"
6
+ import { Log } from "../util/log"
7
+ import { iife } from "@/util/iife"
8
+ import { Flag } from "../flag/flag"
9
+
10
+ declare global {
11
+ const OPENCODE_VERSION: string
12
+ const OPENCODE_CHANNEL: string
13
+ }
14
+
15
+ export namespace Installation {
16
+ const log = Log.create({ service: "installation" })
17
+
18
+ export type Method = Awaited<ReturnType<typeof method>>
19
+
20
+ export const Event = {
21
+ Updated: BusEvent.define(
22
+ "installation.updated",
23
+ z.object({
24
+ version: z.string(),
25
+ }),
26
+ ),
27
+ UpdateAvailable: BusEvent.define(
28
+ "installation.update-available",
29
+ z.object({
30
+ version: z.string(),
31
+ }),
32
+ ),
33
+ }
34
+
35
+ export const Info = z
36
+ .object({
37
+ version: z.string(),
38
+ latest: z.string(),
39
+ })
40
+ .meta({
41
+ ref: "InstallationInfo",
42
+ })
43
+ export type Info = z.infer<typeof Info>
44
+
45
+ export async function info() {
46
+ return {
47
+ version: VERSION,
48
+ latest: await latest(),
49
+ }
50
+ }
51
+
52
+ export function isPreview() {
53
+ return CHANNEL !== "latest"
54
+ }
55
+
56
+ export function isLocal() {
57
+ return CHANNEL === "local"
58
+ }
59
+
60
+ export async function method() {
61
+ if (process.execPath.includes(path.join(".innocode", "bin"))) return "curl"
62
+ if (process.execPath.includes(path.join(".opencode", "bin"))) return "curl"
63
+ if (process.execPath.includes(path.join(".local", "bin"))) return "curl"
64
+ const exec = process.execPath.toLowerCase()
65
+
66
+ const checks = [
67
+ {
68
+ name: "npm" as const,
69
+ command: () => $`npm list -g --depth=0`.throws(false).quiet().text(),
70
+ },
71
+ {
72
+ name: "yarn" as const,
73
+ command: () => $`yarn global list`.throws(false).quiet().text(),
74
+ },
75
+ {
76
+ name: "pnpm" as const,
77
+ command: () => $`pnpm list -g --depth=0`.throws(false).quiet().text(),
78
+ },
79
+ {
80
+ name: "bun" as const,
81
+ command: () => $`bun pm ls -g`.throws(false).quiet().text(),
82
+ },
83
+ {
84
+ name: "brew" as const,
85
+ command: () => $`brew list --formula`.throws(false).quiet().text(),
86
+ },
87
+ {
88
+ name: "scoop" as const,
89
+ command: () => $`scoop list`.throws(false).quiet().text(),
90
+ },
91
+ {
92
+ name: "choco" as const,
93
+ command: () => $`choco list --limit-output`.throws(false).quiet().text(),
94
+ },
95
+ ]
96
+
97
+ checks.sort((a, b) => {
98
+ const aMatches = exec.includes(a.name)
99
+ const bMatches = exec.includes(b.name)
100
+ if (aMatches && !bMatches) return -1
101
+ if (!aMatches && bMatches) return 1
102
+ return 0
103
+ })
104
+
105
+ for (const check of checks) {
106
+ const output = await check.command()
107
+ const installedNames =
108
+ check.name === "brew" || check.name === "choco" || check.name === "scoop"
109
+ ? ["innocode", "opencode"]
110
+ : ["innocode", "opencode-ai"]
111
+ if (installedNames.some((name) => output.includes(name))) {
112
+ return check.name
113
+ }
114
+ }
115
+
116
+ return "unknown"
117
+ }
118
+
119
+ export const UpgradeFailedError = NamedError.create(
120
+ "UpgradeFailedError",
121
+ z.object({
122
+ stderr: z.string(),
123
+ }),
124
+ )
125
+
126
+ async function getBrewFormula() {
127
+ const tapFormula = await $`brew list --formula inno-ki/tap/innocode`.throws(false).quiet().text()
128
+ if (tapFormula.includes("innocode")) return "inno-ki/tap/innocode"
129
+ const coreFormula = await $`brew list --formula innocode`.throws(false).quiet().text()
130
+ if (coreFormula.includes("innocode")) return "innocode"
131
+ const legacyTap = await $`brew list --formula anomalyco/tap/opencode`.throws(false).quiet().text()
132
+ if (legacyTap.includes("opencode")) return "anomalyco/tap/opencode"
133
+ const legacyCore = await $`brew list --formula opencode`.throws(false).quiet().text()
134
+ if (legacyCore.includes("opencode")) return "opencode"
135
+ return "innocode"
136
+ }
137
+
138
+ export async function upgrade(method: Method, target: string) {
139
+ let cmd
140
+ switch (method) {
141
+ case "curl":
142
+ cmd = $`curl -fsSL https://innocode.io/install | bash`.env({
143
+ ...process.env,
144
+ VERSION: target,
145
+ })
146
+ break
147
+ case "npm":
148
+ cmd = $`npm install -g innocode@${target}`
149
+ break
150
+ case "pnpm":
151
+ cmd = $`pnpm install -g innocode@${target}`
152
+ break
153
+ case "bun":
154
+ cmd = $`bun install -g innocode@${target}`
155
+ break
156
+ case "brew": {
157
+ const formula = await getBrewFormula()
158
+ if (formula.includes("/")) {
159
+ cmd =
160
+ $`brew tap inno-ki/tap && cd "$(brew --repo inno-ki/tap)" && git pull --ff-only && brew upgrade ${formula}`.env(
161
+ {
162
+ HOMEBREW_NO_AUTO_UPDATE: "1",
163
+ ...process.env,
164
+ },
165
+ )
166
+ break
167
+ }
168
+ cmd = $`brew upgrade ${formula}`.env({
169
+ HOMEBREW_NO_AUTO_UPDATE: "1",
170
+ ...process.env,
171
+ })
172
+ break
173
+ }
174
+ case "choco":
175
+ cmd = $`echo Y | choco upgrade innocode --version=${target}`
176
+ break
177
+ case "scoop":
178
+ cmd = $`scoop install innocode@${target}`
179
+ break
180
+ default:
181
+ throw new Error(`Unknown method: ${method}`)
182
+ }
183
+ const result = await cmd.quiet().throws(false)
184
+ if (result.exitCode !== 0) {
185
+ const stderr = method === "choco" ? "not running from an elevated command shell" : result.stderr.toString("utf8")
186
+ throw new UpgradeFailedError({
187
+ stderr: stderr,
188
+ })
189
+ }
190
+ log.info("upgraded", {
191
+ method,
192
+ target,
193
+ stdout: result.stdout.toString(),
194
+ stderr: result.stderr.toString(),
195
+ })
196
+ await $`${process.execPath} --version`.nothrow().quiet().text()
197
+ }
198
+
199
+ export const VERSION = typeof OPENCODE_VERSION === "string" ? OPENCODE_VERSION : "local"
200
+ export const CHANNEL = typeof OPENCODE_CHANNEL === "string" ? OPENCODE_CHANNEL : "local"
201
+ export const USER_AGENT = `innocode/${CHANNEL}/${VERSION}/${Flag.INNOCODE_CLIENT}`
202
+
203
+ export async function latest(installMethod?: Method) {
204
+ const detectedMethod = installMethod || (await method())
205
+
206
+ if (detectedMethod === "brew") {
207
+ const formula = await getBrewFormula()
208
+ if (formula.includes("/")) {
209
+ const infoJson = await $`brew info --json=v2 ${formula}`.quiet().text()
210
+ const info = JSON.parse(infoJson)
211
+ const version = info.formulae?.[0]?.versions?.stable
212
+ if (!version) throw new Error(`Could not detect version for tap formula: ${formula}`)
213
+ return version
214
+ }
215
+ return fetch("https://formulae.brew.sh/api/formula/innocode.json")
216
+ .then((res) => {
217
+ if (!res.ok) throw new Error(res.statusText)
218
+ return res.json()
219
+ })
220
+ .then((data: any) => data.versions.stable)
221
+ }
222
+
223
+ if (detectedMethod === "npm" || detectedMethod === "bun" || detectedMethod === "pnpm") {
224
+ const registry = await iife(async () => {
225
+ const r = (await $`npm config get registry`.quiet().nothrow().text()).trim()
226
+ const reg = r || "https://registry.npmjs.org"
227
+ return reg.endsWith("/") ? reg.slice(0, -1) : reg
228
+ })
229
+ const channel = CHANNEL
230
+ return fetch(`${registry}/innocode/${channel}`)
231
+ .then((res) => {
232
+ if (!res.ok) throw new Error(res.statusText)
233
+ return res.json()
234
+ })
235
+ .then((data: any) => data.version)
236
+ }
237
+
238
+ if (detectedMethod === "choco") {
239
+ return fetch(
240
+ "https://community.chocolatey.org/api/v2/Packages?$filter=Id%20eq%20%27innocode%27%20and%20IsLatestVersion&$select=Version",
241
+ { headers: { Accept: "application/json;odata=verbose" } },
242
+ )
243
+ .then((res) => {
244
+ if (!res.ok) throw new Error(res.statusText)
245
+ return res.json()
246
+ })
247
+ .then((data: any) => data.d.results[0].Version)
248
+ }
249
+
250
+ if (detectedMethod === "scoop") {
251
+ return fetch("https://raw.githubusercontent.com/ScoopInstaller/Main/master/bucket/innocode.json", {
252
+ headers: { Accept: "application/json" },
253
+ })
254
+ .then((res) => {
255
+ if (!res.ok) throw new Error(res.statusText)
256
+ return res.json()
257
+ })
258
+ .then((data: any) => data.version)
259
+ }
260
+
261
+ return fetch("https://api.github.com/repos/Inno-ki/innocode/releases/latest")
262
+ .then((res) => {
263
+ if (!res.ok) throw new Error(res.statusText)
264
+ return res.json()
265
+ })
266
+ .then((data: any) => data.tag_name.replace(/^v/, ""))
267
+ }
268
+ }