@openadapter/koda 1.0.0-beta.10

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 (357) hide show
  1. package/CHANGELOG.md +4448 -0
  2. package/README.md +97 -0
  3. package/dist/bun/cli.d.ts +2 -0
  4. package/dist/bun/cli.js +2 -0
  5. package/dist/bun/register-bedrock.d.ts +1 -0
  6. package/dist/bun/register-bedrock.js +1 -0
  7. package/dist/bun/restore-sandbox-env.d.ts +12 -0
  8. package/dist/bun/restore-sandbox-env.js +1 -0
  9. package/dist/cli/args.d.ts +55 -0
  10. package/dist/cli/args.js +167 -0
  11. package/dist/cli/config-selector.d.ts +13 -0
  12. package/dist/cli/config-selector.js +1 -0
  13. package/dist/cli/file-processor.d.ts +14 -0
  14. package/dist/cli/file-processor.js +7 -0
  15. package/dist/cli/import-sessions.d.ts +34 -0
  16. package/dist/cli/import-sessions.js +6 -0
  17. package/dist/cli/initial-message.d.ts +17 -0
  18. package/dist/cli/initial-message.js +1 -0
  19. package/dist/cli/list-models.d.ts +8 -0
  20. package/dist/cli/list-models.js +2 -0
  21. package/dist/cli/openadapter-setup.d.ts +35 -0
  22. package/dist/cli/openadapter-setup.js +4 -0
  23. package/dist/cli/session-picker.d.ts +8 -0
  24. package/dist/cli/session-picker.js +1 -0
  25. package/dist/cli.d.ts +2 -0
  26. package/dist/cli.js +2 -0
  27. package/dist/config.d.ts +92 -0
  28. package/dist/config.js +1 -0
  29. package/dist/core/agent-session-runtime.d.ts +116 -0
  30. package/dist/core/agent-session-runtime.js +1 -0
  31. package/dist/core/agent-session-services.d.ts +86 -0
  32. package/dist/core/agent-session-services.js +1 -0
  33. package/dist/core/agent-session.d.ts +752 -0
  34. package/dist/core/agent-session.js +32 -0
  35. package/dist/core/auth-guidance.d.ts +4 -0
  36. package/dist/core/auth-guidance.js +8 -0
  37. package/dist/core/auth-storage.d.ts +140 -0
  38. package/dist/core/auth-storage.js +1 -0
  39. package/dist/core/bash-executor.d.ts +31 -0
  40. package/dist/core/bash-executor.js +1 -0
  41. package/dist/core/compaction/branch-summarization.d.ts +89 -0
  42. package/dist/core/compaction/branch-summarization.js +38 -0
  43. package/dist/core/compaction/compaction.d.ts +120 -0
  44. package/dist/core/compaction/compaction.js +104 -0
  45. package/dist/core/compaction/index.d.ts +6 -0
  46. package/dist/core/compaction/index.js +1 -0
  47. package/dist/core/compaction/utils.d.ts +37 -0
  48. package/dist/core/compaction/utils.js +19 -0
  49. package/dist/core/defaults.d.ts +2 -0
  50. package/dist/core/defaults.js +1 -0
  51. package/dist/core/diagnostics.d.ts +14 -0
  52. package/dist/core/diagnostics.js +0 -0
  53. package/dist/core/event-bus.d.ts +8 -0
  54. package/dist/core/event-bus.js +1 -0
  55. package/dist/core/exec.d.ts +28 -0
  56. package/dist/core/exec.js +1 -0
  57. package/dist/core/export-html/ansi-to-html.d.ts +21 -0
  58. package/dist/core/export-html/ansi-to-html.js +1 -0
  59. package/dist/core/export-html/index.d.ts +36 -0
  60. package/dist/core/export-html/index.js +2 -0
  61. package/dist/core/export-html/template.css +1066 -0
  62. package/dist/core/export-html/template.html +55 -0
  63. package/dist/core/export-html/template.js +72 -0
  64. package/dist/core/export-html/tool-renderer.d.ts +33 -0
  65. package/dist/core/export-html/tool-renderer.js +1 -0
  66. package/dist/core/export-html/vendor/highlight.min.js +8 -0
  67. package/dist/core/export-html/vendor/marked.min.js +56 -0
  68. package/dist/core/extensions/index.d.ts +11 -0
  69. package/dist/core/extensions/index.js +1 -0
  70. package/dist/core/extensions/loader.d.ts +23 -0
  71. package/dist/core/extensions/loader.js +1 -0
  72. package/dist/core/extensions/runner.d.ts +160 -0
  73. package/dist/core/extensions/runner.js +1 -0
  74. package/dist/core/extensions/types.d.ts +1180 -0
  75. package/dist/core/extensions/types.js +1 -0
  76. package/dist/core/extensions/wrapper.d.ts +19 -0
  77. package/dist/core/extensions/wrapper.js +1 -0
  78. package/dist/core/footer-data-provider.d.ts +53 -0
  79. package/dist/core/footer-data-provider.js +1 -0
  80. package/dist/core/http-dispatcher.d.ts +20 -0
  81. package/dist/core/http-dispatcher.js +1 -0
  82. package/dist/core/index.d.ts +11 -0
  83. package/dist/core/index.js +1 -0
  84. package/dist/core/keybindings.d.ts +352 -0
  85. package/dist/core/keybindings.js +1 -0
  86. package/dist/core/messages.d.ts +76 -0
  87. package/dist/core/messages.js +17 -0
  88. package/dist/core/model-registry.d.ts +149 -0
  89. package/dist/core/model-registry.js +9 -0
  90. package/dist/core/model-resolver.d.ts +109 -0
  91. package/dist/core/model-resolver.js +1 -0
  92. package/dist/core/output-guard.d.ts +6 -0
  93. package/dist/core/output-guard.js +1 -0
  94. package/dist/core/package-manager.d.ts +203 -0
  95. package/dist/core/package-manager.js +3 -0
  96. package/dist/core/prompt-templates.d.ts +51 -0
  97. package/dist/core/prompt-templates.js +2 -0
  98. package/dist/core/provider-attribution.d.ts +3 -0
  99. package/dist/core/provider-attribution.js +1 -0
  100. package/dist/core/provider-display-names.d.ts +1 -0
  101. package/dist/core/provider-display-names.js +1 -0
  102. package/dist/core/resolve-config-value.d.ts +30 -0
  103. package/dist/core/resolve-config-value.js +1 -0
  104. package/dist/core/resource-loader.d.ts +193 -0
  105. package/dist/core/resource-loader.js +1 -0
  106. package/dist/core/sdk.d.ts +108 -0
  107. package/dist/core/sdk.js +1 -0
  108. package/dist/core/session-cwd.d.ts +18 -0
  109. package/dist/core/session-cwd.js +7 -0
  110. package/dist/core/session-manager.d.ts +331 -0
  111. package/dist/core/session-manager.js +11 -0
  112. package/dist/core/settings-manager.d.ts +265 -0
  113. package/dist/core/settings-manager.js +1 -0
  114. package/dist/core/skills.d.ts +59 -0
  115. package/dist/core/skills.js +4 -0
  116. package/dist/core/slash-commands.d.ts +13 -0
  117. package/dist/core/slash-commands.js +1 -0
  118. package/dist/core/source-info.d.ts +17 -0
  119. package/dist/core/source-info.js +1 -0
  120. package/dist/core/system-prompt.d.ts +27 -0
  121. package/dist/core/system-prompt.js +52 -0
  122. package/dist/core/telemetry.d.ts +2 -0
  123. package/dist/core/telemetry.js +1 -0
  124. package/dist/core/timings.d.ts +7 -0
  125. package/dist/core/timings.js +3 -0
  126. package/dist/core/tools/bash.d.ts +67 -0
  127. package/dist/core/tools/bash.js +18 -0
  128. package/dist/core/tools/edit-diff.d.ts +86 -0
  129. package/dist/core/tools/edit-diff.js +16 -0
  130. package/dist/core/tools/edit.d.ts +50 -0
  131. package/dist/core/tools/edit.js +2 -0
  132. package/dist/core/tools/file-mutation-queue.d.ts +5 -0
  133. package/dist/core/tools/file-mutation-queue.js +1 -0
  134. package/dist/core/tools/find.d.ts +34 -0
  135. package/dist/core/tools/find.js +13 -0
  136. package/dist/core/tools/grep.d.ts +36 -0
  137. package/dist/core/tools/grep.js +13 -0
  138. package/dist/core/tools/index.d.ts +39 -0
  139. package/dist/core/tools/index.js +1 -0
  140. package/dist/core/tools/ls.d.ts +36 -0
  141. package/dist/core/tools/ls.js +9 -0
  142. package/dist/core/tools/output-accumulator.d.ts +51 -0
  143. package/dist/core/tools/output-accumulator.js +4 -0
  144. package/dist/core/tools/path-utils.d.ts +9 -0
  145. package/dist/core/tools/path-utils.js +1 -0
  146. package/dist/core/tools/read.d.ts +34 -0
  147. package/dist/core/tools/read.js +22 -0
  148. package/dist/core/tools/render-utils.d.ts +23 -0
  149. package/dist/core/tools/render-utils.js +4 -0
  150. package/dist/core/tools/tool-definition-wrapper.d.ts +13 -0
  151. package/dist/core/tools/tool-definition-wrapper.js +1 -0
  152. package/dist/core/tools/truncate.d.ts +69 -0
  153. package/dist/core/tools/truncate.js +5 -0
  154. package/dist/core/tools/write.d.ts +25 -0
  155. package/dist/core/tools/write.js +13 -0
  156. package/dist/index.d.ts +30 -0
  157. package/dist/index.js +1 -0
  158. package/dist/main.d.ts +11 -0
  159. package/dist/main.js +1 -0
  160. package/dist/migrations.d.ts +32 -0
  161. package/dist/migrations.js +8 -0
  162. package/dist/modes/index.d.ts +8 -0
  163. package/dist/modes/index.js +1 -0
  164. package/dist/modes/interactive/assets/clankolas.png +0 -0
  165. package/dist/modes/interactive/components/armin.d.ts +33 -0
  166. package/dist/modes/interactive/components/armin.js +1 -0
  167. package/dist/modes/interactive/components/assistant-message.d.ts +19 -0
  168. package/dist/modes/interactive/components/assistant-message.js +1 -0
  169. package/dist/modes/interactive/components/bash-execution.d.ts +33 -0
  170. package/dist/modes/interactive/components/bash-execution.js +13 -0
  171. package/dist/modes/interactive/components/bordered-loader.d.ts +15 -0
  172. package/dist/modes/interactive/components/bordered-loader.js +1 -0
  173. package/dist/modes/interactive/components/branch-summary-message.d.ts +15 -0
  174. package/dist/modes/interactive/components/branch-summary-message.js +3 -0
  175. package/dist/modes/interactive/components/compaction-summary-message.d.ts +15 -0
  176. package/dist/modes/interactive/components/compaction-summary-message.js +3 -0
  177. package/dist/modes/interactive/components/config-selector.d.ts +70 -0
  178. package/dist/modes/interactive/components/config-selector.js +1 -0
  179. package/dist/modes/interactive/components/countdown-timer.d.ts +13 -0
  180. package/dist/modes/interactive/components/countdown-timer.js +1 -0
  181. package/dist/modes/interactive/components/custom-editor.d.ts +20 -0
  182. package/dist/modes/interactive/components/custom-editor.js +1 -0
  183. package/dist/modes/interactive/components/custom-message.d.ts +19 -0
  184. package/dist/modes/interactive/components/custom-message.js +2 -0
  185. package/dist/modes/interactive/components/daxnuts.d.ts +22 -0
  186. package/dist/modes/interactive/components/daxnuts.js +1 -0
  187. package/dist/modes/interactive/components/diff.d.ts +11 -0
  188. package/dist/modes/interactive/components/diff.js +3 -0
  189. package/dist/modes/interactive/components/dynamic-border.d.ts +14 -0
  190. package/dist/modes/interactive/components/dynamic-border.js +1 -0
  191. package/dist/modes/interactive/components/earendil-announcement.d.ts +4 -0
  192. package/dist/modes/interactive/components/earendil-announcement.js +1 -0
  193. package/dist/modes/interactive/components/extension-editor.d.ts +19 -0
  194. package/dist/modes/interactive/components/extension-editor.js +3 -0
  195. package/dist/modes/interactive/components/extension-input.d.ts +22 -0
  196. package/dist/modes/interactive/components/extension-input.js +2 -0
  197. package/dist/modes/interactive/components/extension-selector.d.ts +25 -0
  198. package/dist/modes/interactive/components/extension-selector.js +2 -0
  199. package/dist/modes/interactive/components/footer.d.ts +27 -0
  200. package/dist/modes/interactive/components/footer.js +1 -0
  201. package/dist/modes/interactive/components/index.d.ts +31 -0
  202. package/dist/modes/interactive/components/index.js +1 -0
  203. package/dist/modes/interactive/components/keybinding-hints.d.ts +12 -0
  204. package/dist/modes/interactive/components/keybinding-hints.js +1 -0
  205. package/dist/modes/interactive/components/login-dialog.d.ts +51 -0
  206. package/dist/modes/interactive/components/login-dialog.js +1 -0
  207. package/dist/modes/interactive/components/model-selector.d.ts +46 -0
  208. package/dist/modes/interactive/components/model-selector.js +2 -0
  209. package/dist/modes/interactive/components/oauth-selector.d.ts +30 -0
  210. package/dist/modes/interactive/components/oauth-selector.js +1 -0
  211. package/dist/modes/interactive/components/scoped-models-selector.d.ts +41 -0
  212. package/dist/modes/interactive/components/scoped-models-selector.js +1 -0
  213. package/dist/modes/interactive/components/session-selector-search.d.ts +22 -0
  214. package/dist/modes/interactive/components/session-selector-search.js +1 -0
  215. package/dist/modes/interactive/components/session-selector.d.ts +95 -0
  216. package/dist/modes/interactive/components/session-selector.js +2 -0
  217. package/dist/modes/interactive/components/settings-selector.d.ts +69 -0
  218. package/dist/modes/interactive/components/settings-selector.js +1 -0
  219. package/dist/modes/interactive/components/show-images-selector.d.ts +9 -0
  220. package/dist/modes/interactive/components/show-images-selector.js +1 -0
  221. package/dist/modes/interactive/components/skill-invocation-message.d.ts +16 -0
  222. package/dist/modes/interactive/components/skill-invocation-message.js +3 -0
  223. package/dist/modes/interactive/components/theme-selector.d.ts +10 -0
  224. package/dist/modes/interactive/components/theme-selector.js +1 -0
  225. package/dist/modes/interactive/components/thinking-selector.d.ts +10 -0
  226. package/dist/modes/interactive/components/thinking-selector.js +1 -0
  227. package/dist/modes/interactive/components/tool-execution.d.ts +62 -0
  228. package/dist/modes/interactive/components/tool-execution.js +4 -0
  229. package/dist/modes/interactive/components/tree-selector.d.ts +88 -0
  230. package/dist/modes/interactive/components/tree-selector.js +1 -0
  231. package/dist/modes/interactive/components/user-message-selector.d.ts +29 -0
  232. package/dist/modes/interactive/components/user-message-selector.js +1 -0
  233. package/dist/modes/interactive/components/user-message.d.ts +9 -0
  234. package/dist/modes/interactive/components/user-message.js +1 -0
  235. package/dist/modes/interactive/components/visual-truncate.d.ts +23 -0
  236. package/dist/modes/interactive/components/visual-truncate.js +1 -0
  237. package/dist/modes/interactive/interactive-mode.d.ts +420 -0
  238. package/dist/modes/interactive/interactive-mode.js +116 -0
  239. package/dist/modes/interactive/theme/dark.json +86 -0
  240. package/dist/modes/interactive/theme/light.json +85 -0
  241. package/dist/modes/interactive/theme/theme-schema.json +335 -0
  242. package/dist/modes/interactive/theme/theme.d.ts +101 -0
  243. package/dist/modes/interactive/theme/theme.js +18 -0
  244. package/dist/modes/print-mode.d.ts +27 -0
  245. package/dist/modes/print-mode.js +4 -0
  246. package/dist/modes/rpc/jsonl.d.ts +16 -0
  247. package/dist/modes/rpc/jsonl.js +3 -0
  248. package/dist/modes/rpc/rpc-client.d.ts +226 -0
  249. package/dist/modes/rpc/rpc-client.js +1 -0
  250. package/dist/modes/rpc/rpc-mode.d.ts +19 -0
  251. package/dist/modes/rpc/rpc-mode.js +1 -0
  252. package/dist/modes/rpc/rpc-types.d.ts +419 -0
  253. package/dist/modes/rpc/rpc-types.js +0 -0
  254. package/dist/package-manager-cli.d.ts +3 -0
  255. package/dist/package-manager-cli.js +49 -0
  256. package/dist/utils/ansi.d.ts +1 -0
  257. package/dist/utils/ansi.js +1 -0
  258. package/dist/utils/auto-update.d.ts +13 -0
  259. package/dist/utils/auto-update.js +1 -0
  260. package/dist/utils/changelog.d.ts +20 -0
  261. package/dist/utils/changelog.js +4 -0
  262. package/dist/utils/child-process.d.ts +14 -0
  263. package/dist/utils/child-process.js +1 -0
  264. package/dist/utils/clipboard-image.d.ts +10 -0
  265. package/dist/utils/clipboard-image.js +1 -0
  266. package/dist/utils/clipboard-native.d.ts +9 -0
  267. package/dist/utils/clipboard-native.js +1 -0
  268. package/dist/utils/clipboard.d.ts +1 -0
  269. package/dist/utils/clipboard.js +1 -0
  270. package/dist/utils/deprecation.d.ts +3 -0
  271. package/dist/utils/deprecation.js +1 -0
  272. package/dist/utils/exif-orientation.d.ts +4 -0
  273. package/dist/utils/exif-orientation.js +1 -0
  274. package/dist/utils/frontmatter.d.ts +7 -0
  275. package/dist/utils/frontmatter.js +4 -0
  276. package/dist/utils/fs-watch.d.ts +4 -0
  277. package/dist/utils/fs-watch.js +1 -0
  278. package/dist/utils/git.d.ts +25 -0
  279. package/dist/utils/git.js +1 -0
  280. package/dist/utils/html.d.ts +6 -0
  281. package/dist/utils/html.js +1 -0
  282. package/dist/utils/image-convert.d.ts +8 -0
  283. package/dist/utils/image-convert.js +1 -0
  284. package/dist/utils/image-resize-core.d.ts +29 -0
  285. package/dist/utils/image-resize-core.js +1 -0
  286. package/dist/utils/image-resize-worker.d.ts +1 -0
  287. package/dist/utils/image-resize-worker.js +1 -0
  288. package/dist/utils/image-resize.d.ts +15 -0
  289. package/dist/utils/image-resize.js +1 -0
  290. package/dist/utils/json.d.ts +2 -0
  291. package/dist/utils/json.js +1 -0
  292. package/dist/utils/koda-user-agent.d.ts +1 -0
  293. package/dist/utils/koda-user-agent.js +1 -0
  294. package/dist/utils/mime.d.ts +2 -0
  295. package/dist/utils/mime.js +1 -0
  296. package/dist/utils/paths.d.ts +30 -0
  297. package/dist/utils/paths.js +1 -0
  298. package/dist/utils/photon.d.ts +20 -0
  299. package/dist/utils/photon.js +1 -0
  300. package/dist/utils/shell.d.ts +29 -0
  301. package/dist/utils/shell.js +8 -0
  302. package/dist/utils/sleep.d.ts +4 -0
  303. package/dist/utils/sleep.js +1 -0
  304. package/dist/utils/syntax-highlight.d.ts +11 -0
  305. package/dist/utils/syntax-highlight.js +2 -0
  306. package/dist/utils/tools-manager.d.ts +2 -0
  307. package/dist/utils/tools-manager.js +1 -0
  308. package/dist/utils/version-check.d.ts +14 -0
  309. package/dist/utils/version-check.js +1 -0
  310. package/dist/utils/windows-self-update.d.ts +2 -0
  311. package/dist/utils/windows-self-update.js +1 -0
  312. package/docs/compaction.md +394 -0
  313. package/docs/custom-provider.md +736 -0
  314. package/docs/development.md +71 -0
  315. package/docs/docs.json +148 -0
  316. package/docs/extensions.md +2626 -0
  317. package/docs/images/doom-extension.png +0 -0
  318. package/docs/images/exy.png +0 -0
  319. package/docs/images/interactive-mode.png +0 -0
  320. package/docs/images/tree-view.png +0 -0
  321. package/docs/index.md +80 -0
  322. package/docs/json.md +82 -0
  323. package/docs/keybindings.md +197 -0
  324. package/docs/models.md +493 -0
  325. package/docs/packages.md +226 -0
  326. package/docs/prompt-templates.md +88 -0
  327. package/docs/providers.md +253 -0
  328. package/docs/quickstart.md +165 -0
  329. package/docs/rpc.md +1408 -0
  330. package/docs/sdk.md +1137 -0
  331. package/docs/session-format.md +412 -0
  332. package/docs/sessions.md +145 -0
  333. package/docs/settings.md +281 -0
  334. package/docs/shell-aliases.md +13 -0
  335. package/docs/skills.md +231 -0
  336. package/docs/terminal-setup.md +114 -0
  337. package/docs/termux.md +127 -0
  338. package/docs/themes.md +295 -0
  339. package/docs/tmux.md +61 -0
  340. package/docs/tui.md +927 -0
  341. package/docs/usage.md +288 -0
  342. package/docs/windows.md +17 -0
  343. package/npm-shrinkwrap.json +1792 -0
  344. package/openadapter/extensions/koda-ask.js +12 -0
  345. package/openadapter/extensions/koda-bg.js +14 -0
  346. package/openadapter/extensions/koda-commands.mjs +15 -0
  347. package/openadapter/extensions/koda-help.js +8 -0
  348. package/openadapter/extensions/koda-memory.js +16 -0
  349. package/openadapter/extensions/koda-status.js +1 -0
  350. package/openadapter/extensions/koda-todo.js +4 -0
  351. package/openadapter/extensions/koda-vision.js +4 -0
  352. package/openadapter/extensions/koda-web.js +7 -0
  353. package/openadapter/setup.mjs +175 -0
  354. package/openadapter/skills/code-review/SKILL.md +22 -0
  355. package/openadapter/skills/debugging/SKILL.md +28 -0
  356. package/openadapter/skills/frontend/SKILL.md +38 -0
  357. package/package.json +108 -0
package/README.md ADDED
@@ -0,0 +1,97 @@
1
+ <h1 align="center">Koda</h1>
2
+
3
+ <p align="center"><strong>The coding agent that makes affordable models actually finish the job.</strong></p>
4
+
5
+ <p align="center">
6
+ <a href="https://www.npmjs.com/package/@openadapter/koda"><img alt="npm" src="https://img.shields.io/npm/v/@openadapter/koda/beta?style=flat-square&label=beta" /></a>
7
+ <a href="https://openadapter.in"><img alt="OpenAdapter" src="https://img.shields.io/badge/built%20for-OpenAdapter-7c3aed?style=flat-square" /></a>
8
+ <img alt="license" src="https://img.shields.io/badge/license-MIT-green?style=flat-square" />
9
+ </p>
10
+
11
+ ---
12
+
13
+ **Koda** is a terminal coding agent built for [OpenAdapter](https://openadapter.in). One key gives you many models — and Koda wraps a **reliability layer** around them so cheaper, faster models still ship working code: it never idles on rate limits, fails over when a model stalls, verifies its own work, and steps up to a stronger model only when it has to.
14
+
15
+ It runs in your terminal like the coding CLIs you already know — just harder to break, and tuned end-to-end for OpenAdapter.
16
+
17
+ ## Install
18
+
19
+ ```bash
20
+ npm i -g @openadapter/koda@beta
21
+ koda
22
+ ```
23
+
24
+ First launch runs a one-time setup: paste your OpenAdapter API key (`sk-cv-…` from your [dashboard](https://openadapter.in)) and Koda wires up the models, tools, and skills. That's it.
25
+
26
+ ```bash
27
+ koda # start (or resume) in the current folder
28
+ koda --continue # reopen the latest session here
29
+ koda --resume # pick a past session
30
+ koda setup # re-run setup any time
31
+ koda import # pull in past sessions from other CLIs (see below)
32
+ ```
33
+
34
+ ## What makes Koda different
35
+
36
+ **One key, many models — tiered.** Point Koda at any OpenAdapter model (max / pro / lite). Koda reads live health/latency signals to route well, and you stay on *your* pick.
37
+
38
+ **Reliability that keeps cheap models honest:**
39
+
40
+ - **Never idle on a rate limit** — `/zenitsu` speed mode instantly reroutes a 429 to a healthy, faster model (no waiting), then snaps back to your preferred one the moment it's free.
41
+ - **Failover, not failure** — provider/model hiccups are retried and routed around; a request rarely dies from a single flake.
42
+ - **Run-it verification** — when code changed, Koda runs your build/tests/lint and treats the **exit code as ground truth**, not the model's opinion.
43
+ - **Overseer + escalation** — a stronger model double-checks "done" on smaller models and, if it's stuck, Koda climbs the tier ladder — capped, then sticks.
44
+ - **Heal, don't crash** — loop/state errors recover instead of killing your session; repetition/garbage output is detected and replaced.
45
+
46
+ **Features that respect your time:**
47
+
48
+ - **Ask & suggest** — on open-ended requests Koda proposes an approach and asks the decisions that matter (framework, storage…) with a clean multiple-choice card, instead of guessing wrong.
49
+ - **Vision on any model** — paste a screenshot even on a non-vision model; Koda reads it with a vision model and passes the details along.
50
+ - **Bring your history** — `koda import` (and a first-run prompt) imports past sessions from **Claude Code** and **OpenCode** into Koda, organized by project. Nothing left behind.
51
+ - **Memory, web, background tasks** — remember/recall with semantic search, web search + fetch, and long-running servers via `run_background`.
52
+ - **Skills & modes** — drop-in Agent Skills (frontend, debugging, code-review), `/plan` and `/build` modes.
53
+ - **Stays current** — checks for updates and updates itself in the background; the model list auto-refreshes daily so you always have the newest models.
54
+ - **Calm, useful UX** — live working indicator, an end-of-task recap, a session-resume hint when you reopen a folder, and contextual tips that surface the right feature exactly when it helps.
55
+
56
+ ## Common commands
57
+
58
+ | Command | What it does |
59
+ |---|---|
60
+ | `/zenitsu` | Toggle speed mode (never wait on a rate limit) |
61
+ | `/goal` | Set a session goal Koda tracks to completion |
62
+ | `/plan` · `/build` | Switch between plan and build modes |
63
+ | `/resume` · `/continue` | Open a past session |
64
+ | `/memory` · `/todos` | Memory and task list |
65
+ | `/use <skill>` | Keep a skill active for the session |
66
+ | `/trace` | What the harness did (failover / verify / escalate …) |
67
+ | `/settings` | Settings (incl. "Import past sessions") |
68
+ | `/help` | Full help |
69
+
70
+ ## Configuration (env flags)
71
+
72
+ | Flag | Effect |
73
+ |---|---|
74
+ | `KODA_ZENITSU=1` | Start in speed mode |
75
+ | `KODA_NO_AUTO_UPDATE=1` | Notify about updates but don't auto-install |
76
+ | `KODA_NO_MODEL_REFRESH=1` | Don't auto-refresh the model list |
77
+ | `KODA_NO_RESUME_HINT=1` | Hide the "past sessions in this folder" hint |
78
+ | `KODA_TIPS=0` | Disable contextual feature tips |
79
+ | `KODA_OFFLINE=1` | No network calls (version check, model refresh, tool downloads) |
80
+
81
+ ## Built on Pi — credit where it's due
82
+
83
+ Koda stands on **[Pi](https://github.com/earendil-works/pi)**, the excellent open-source terminal coding harness by **Mario Zechner** ([@badlogic](https://github.com/badlogic)). A huge amount of what makes Koda pleasant to use is Pi's, and we're grateful for it.
84
+
85
+ **Pi provides the foundation** — the interactive TUI + editor, sessions & branching, context compaction, the extension / skill / prompt-template / theme system, prompt-template and package management, and the interactive / print / RPC / SDK run modes.
86
+
87
+ **Koda adds, on top of Pi:**
88
+ - OpenAdapter integration (one key → many tiered models) and the first-run setup.
89
+ - The reliability layer — zenitsu never-idle rerouting, model failover, run-it verification, the overseer + escalation, heal-don't-crash, poison guard.
90
+ - Ask & suggest, the vision bridge, session import from Claude Code & OpenCode.
91
+ - Auto-update + daily model refresh, the resume hint, contextual tips, recap, and the live status UX.
92
+
93
+ Thank you to the Pi project and its contributors.
94
+
95
+ ## License
96
+
97
+ MIT — see [LICENSE](../../LICENSE). Copyright © Mario Zechner (original "pi" project) and OpenAdapter (the "Koda" fork).
@@ -0,0 +1,2 @@
1
+ #!/usr/bin/env node
2
+ export {};
@@ -0,0 +1,2 @@
1
+ #!/usr/bin/env node
2
+ import{APP_NAME as r}from"../config.js";process.title=r,process.emitWarning=(()=>{});import{restoreSandboxEnv as o}from"./restore-sandbox-env.js";o(),await import("./register-bedrock.js"),await import("../cli.js");
@@ -0,0 +1 @@
1
+ export {};
@@ -0,0 +1 @@
1
+ import{setBedrockProviderModule as o}from"@openadapter/koda-ai";import{bedrockProviderModule as r}from"@openadapter/koda-ai/bedrock-provider";o(r);
@@ -0,0 +1,12 @@
1
+ /**
2
+ * Workaround for https://github.com/oven-sh/bun/issues/27802
3
+ *
4
+ * Bun compiled binaries have an empty `process.env` when running inside
5
+ * sandbox environments (e.g. nono on Linux/macOS). On Linux we can recover
6
+ * the environment from `/proc/self/environ`.
7
+ */
8
+ /**
9
+ * Restore environment variables from `/proc/self/environ` when running
10
+ * inside a sandbox where Bun's `process.env` is empty.
11
+ */
12
+ export declare function restoreSandboxEnv(): void;
@@ -0,0 +1 @@
1
+ var s=Object.defineProperty;var o=(n,e)=>s(n,"name",{value:e,configurable:!0});import{readFileSync as t}from"node:fs";function f(){if(process.versions?.bun&&!(Object.keys(process.env).length>0))try{const n=t("/proc/self/environ","utf-8");for(const e of n.split("\0")){const r=e.indexOf("=");r>0&&(process.env[e.slice(0,r)]=e.slice(r+1))}}catch{}}o(f,"restoreSandboxEnv");export{f as restoreSandboxEnv};
@@ -0,0 +1,55 @@
1
+ /**
2
+ * CLI argument parsing and help display
3
+ */
4
+ import type { ThinkingLevel } from "@openadapter/koda-agent-core";
5
+ import type { ExtensionFlag } from "../core/extensions/types.ts";
6
+ export type Mode = "text" | "json" | "rpc";
7
+ export interface Args {
8
+ provider?: string;
9
+ model?: string;
10
+ apiKey?: string;
11
+ systemPrompt?: string;
12
+ appendSystemPrompt?: string[];
13
+ thinking?: ThinkingLevel;
14
+ continue?: boolean;
15
+ resume?: boolean;
16
+ help?: boolean;
17
+ version?: boolean;
18
+ mode?: Mode;
19
+ name?: string;
20
+ noSession?: boolean;
21
+ session?: string;
22
+ sessionId?: string;
23
+ fork?: string;
24
+ sessionDir?: string;
25
+ models?: string[];
26
+ tools?: string[];
27
+ excludeTools?: string[];
28
+ noTools?: boolean;
29
+ noBuiltinTools?: boolean;
30
+ extensions?: string[];
31
+ noExtensions?: boolean;
32
+ print?: boolean;
33
+ export?: string;
34
+ noSkills?: boolean;
35
+ skills?: string[];
36
+ promptTemplates?: string[];
37
+ noPromptTemplates?: boolean;
38
+ themes?: string[];
39
+ noThemes?: boolean;
40
+ noContextFiles?: boolean;
41
+ listModels?: string | true;
42
+ offline?: boolean;
43
+ verbose?: boolean;
44
+ messages: string[];
45
+ fileArgs: string[];
46
+ /** Unknown flags (potentially extension flags) - map of flag name to value */
47
+ unknownFlags: Map<string, boolean | string>;
48
+ diagnostics: Array<{
49
+ type: "warning" | "error";
50
+ message: string;
51
+ }>;
52
+ }
53
+ export declare function isValidThinkingLevel(level: string): level is ThinkingLevel;
54
+ export declare function parseArgs(args: string[]): Args;
55
+ export declare function printHelp(extensionFlags?: ExtensionFlag[]): void;
@@ -0,0 +1,167 @@
1
+ var c=Object.defineProperty;var a=(o,t)=>c(o,"name",{value:t,configurable:!0});import l from"chalk";import{APP_NAME as n,CONFIG_DIR_NAME as d,ENV_AGENT_DIR as u,ENV_SESSION_DIR as A}from"../config.js";const m=["off","minimal","low","medium","high","xhigh"];function f(o){return m.includes(o)}a(f,"isValidThinkingLevel");function _(o){const t={messages:[],fileArgs:[],unknownFlags:new Map,diagnostics:[]};for(let s=0;s<o.length;s++){const e=o[s];if(e==="--help"||e==="-h")t.help=!0;else if(e==="--version"||e==="-v")t.version=!0;else if(e==="--mode"&&s+1<o.length){const i=o[++s];(i==="text"||i==="json"||i==="rpc")&&(t.mode=i)}else if(e==="--continue"||e==="-c")t.continue=!0;else if(e==="--resume"||e==="-r")t.resume=!0;else if(e==="--provider"&&s+1<o.length)t.provider=o[++s];else if(e==="--model"&&s+1<o.length)t.model=o[++s];else if(e==="--api-key"&&s+1<o.length)t.apiKey=o[++s];else if(e==="--system-prompt"&&s+1<o.length)t.systemPrompt=o[++s];else if(e==="--append-system-prompt"&&s+1<o.length)t.appendSystemPrompt=t.appendSystemPrompt??[],t.appendSystemPrompt.push(o[++s]);else if(e==="--name"||e==="-n")s+1<o.length?t.name=o[++s]:t.diagnostics.push({type:"error",message:"--name requires a value"});else if(e==="--no-session")t.noSession=!0;else if(e==="--session"&&s+1<o.length)t.session=o[++s];else if(e==="--session-id"&&s+1<o.length)t.sessionId=o[++s];else if(e==="--fork"&&s+1<o.length)t.fork=o[++s];else if(e==="--session-dir"&&s+1<o.length)t.sessionDir=o[++s];else if(e==="--models"&&s+1<o.length)t.models=o[++s].split(",").map(i=>i.trim());else if(e==="--no-tools"||e==="-nt")t.noTools=!0;else if(e==="--no-builtin-tools"||e==="-nbt")t.noBuiltinTools=!0;else if((e==="--tools"||e==="-t")&&s+1<o.length)t.tools=o[++s].split(",").map(i=>i.trim()).filter(i=>i.length>0);else if((e==="--exclude-tools"||e==="-xt")&&s+1<o.length)t.excludeTools=o[++s].split(",").map(i=>i.trim()).filter(i=>i.length>0);else if(e==="--thinking"&&s+1<o.length){const i=o[++s];f(i)?t.thinking=i:t.diagnostics.push({type:"warning",message:`Invalid thinking level "${i}". Valid values: ${m.join(", ")}`})}else if(e==="--print"||e==="-p"){t.print=!0;const i=o[s+1];i!==void 0&&!i.startsWith("@")&&(!i.startsWith("-")||i.startsWith("---"))&&(t.messages.push(i),s++)}else if(e==="--export"&&s+1<o.length)t.export=o[++s];else if((e==="--extension"||e==="-e")&&s+1<o.length)t.extensions=t.extensions??[],t.extensions.push(o[++s]);else if(e==="--no-extensions"||e==="-ne")t.noExtensions=!0;else if(e==="--skill"&&s+1<o.length)t.skills=t.skills??[],t.skills.push(o[++s]);else if(e==="--prompt-template"&&s+1<o.length)t.promptTemplates=t.promptTemplates??[],t.promptTemplates.push(o[++s]);else if(e==="--theme"&&s+1<o.length)t.themes=t.themes??[],t.themes.push(o[++s]);else if(e==="--no-skills"||e==="-ns")t.noSkills=!0;else if(e==="--no-prompt-templates"||e==="-np")t.noPromptTemplates=!0;else if(e==="--no-themes")t.noThemes=!0;else if(e==="--no-context-files"||e==="-nc")t.noContextFiles=!0;else if(e==="--list-models")s+1<o.length&&!o[s+1].startsWith("-")&&!o[s+1].startsWith("@")?t.listModels=o[++s]:t.listModels=!0;else if(e==="--verbose")t.verbose=!0;else if(e==="--offline")t.offline=!0;else if(e.startsWith("@"))t.fileArgs.push(e.slice(1));else if(e.startsWith("--")){const i=e.indexOf("=");if(i!==-1)t.unknownFlags.set(e.slice(2,i),e.slice(i+1));else{const p=e.slice(2),r=o[s+1];r!==void 0&&!r.startsWith("-")&&!r.startsWith("@")?(t.unknownFlags.set(p,r),s++):t.unknownFlags.set(p,!0)}}else e.startsWith("-")&&!e.startsWith("--")?t.diagnostics.push({type:"error",message:`Unknown option: ${e}`}):e.startsWith("-")||t.messages.push(e)}return t}a(_,"parseArgs");function k(o){const t=o&&o.length>0?`
2
+ ${l.bold("Extension CLI Flags:")}
3
+ ${o.map(s=>{const e=s.type==="string"?" <value>":"",i=s.description??`Registered by ${s.extensionPath}`;return` --${s.name}${e}`.padEnd(30)+i}).join(`
4
+ `)}
5
+ `:"";console.log(`${l.bold(n)} - AI coding assistant with read, bash, edit, write tools
6
+
7
+ ${l.bold("Usage:")}
8
+ ${n} [options] [@files...] [messages...]
9
+
10
+ ${l.bold("Commands:")}
11
+ ${n} install <source> [-l] Install extension source and add to settings
12
+ ${n} remove <source> [-l] Remove extension source from settings
13
+ ${n} uninstall <source> [-l] Alias for remove
14
+ ${n} update [source|self|koda] Update koda and installed extensions
15
+ ${n} list List installed extensions from settings
16
+ ${n} config Open TUI to enable/disable package resources
17
+ ${n} <command> --help Show help for install/remove/uninstall/update/list
18
+
19
+ ${l.bold("Options:")}
20
+ --provider <name> Provider name (default: google)
21
+ --model <pattern> Model pattern or ID (supports "provider/id" and optional ":<thinking>")
22
+ --api-key <key> API key (defaults to env vars)
23
+ --system-prompt <text> System prompt (default: coding assistant prompt)
24
+ --append-system-prompt <text> Append text or file contents to the system prompt (can be used multiple times)
25
+ --mode <mode> Output mode: text (default), json, or rpc
26
+ --print, -p Non-interactive mode: process prompt and exit
27
+ --continue, -c Continue previous session
28
+ --resume, -r Select a session to resume
29
+ --session <path|id> Use specific session file or partial UUID
30
+ --session-id <id> Use exact project session ID, creating it if missing
31
+ --fork <path|id> Fork specific session file or partial UUID into a new session
32
+ --session-dir <dir> Directory for session storage and lookup
33
+ --no-session Don't save session (ephemeral)
34
+ --name, -n <name> Set session display name
35
+ --models <patterns> Comma-separated model patterns for Ctrl+P cycling
36
+ Supports globs (anthropic/*, *sonnet*) and fuzzy matching
37
+ --no-tools, -nt Disable all tools by default (built-in and extension)
38
+ --no-builtin-tools, -nbt Disable built-in tools by default but keep extension/custom tools enabled
39
+ --tools, -t <tools> Comma-separated allowlist of tool names to enable
40
+ Applies to built-in, extension, and custom tools
41
+ --exclude-tools, -xt <tools> Comma-separated denylist of tool names to disable
42
+ Applies to built-in, extension, and custom tools
43
+ --thinking <level> Set thinking level: off, minimal, low, medium, high, xhigh
44
+ --extension, -e <path> Load an extension file (can be used multiple times)
45
+ --no-extensions, -ne Disable extension discovery (explicit -e paths still work)
46
+ --skill <path> Load a skill file or directory (can be used multiple times)
47
+ --no-skills, -ns Disable skills discovery and loading
48
+ --prompt-template <path> Load a prompt template file or directory (can be used multiple times)
49
+ --no-prompt-templates, -np Disable prompt template discovery and loading
50
+ --theme <path> Load a theme file or directory (can be used multiple times)
51
+ --no-themes Disable theme discovery and loading
52
+ --no-context-files, -nc Disable AGENTS.md and CLAUDE.md discovery and loading
53
+ --export <file> Export session file to HTML and exit
54
+ --list-models [search] List available models (with optional fuzzy search)
55
+ --verbose Force verbose startup (overrides quietStartup setting)
56
+ --offline Disable startup network operations (same as KODA_OFFLINE=1)
57
+ --help, -h Show this help
58
+ --version, -v Show version number
59
+
60
+ Extensions can register additional flags (e.g., --plan from plan-mode extension).${t}
61
+
62
+ ${l.bold("Examples:")}
63
+ # Interactive mode
64
+ ${n}
65
+
66
+ # Interactive mode with initial prompt
67
+ ${n} "List all .ts files in src/"
68
+
69
+ # Include files in initial message
70
+ ${n} @prompt.md @image.png "What color is the sky?"
71
+
72
+ # Non-interactive mode (process and exit)
73
+ ${n} -p "List all .ts files in src/"
74
+
75
+ # Multiple messages (interactive)
76
+ ${n} "Read package.json" "What dependencies do we have?"
77
+
78
+ # Continue previous session
79
+ ${n} --continue "What did we discuss?"
80
+
81
+ # Start a named session
82
+ ${n} --name "Refactor auth module"
83
+
84
+ # Use different model
85
+ ${n} --provider openai --model gpt-4o-mini "Help me refactor this code"
86
+
87
+ # Use model with provider prefix (no --provider needed)
88
+ ${n} --model openai/gpt-4o "Help me refactor this code"
89
+
90
+ # Use model with thinking level shorthand
91
+ ${n} --model sonnet:high "Solve this complex problem"
92
+
93
+ # Limit model cycling to specific models
94
+ ${n} --models claude-sonnet,claude-haiku,gpt-4o
95
+
96
+ # Limit to a specific provider with glob pattern
97
+ ${n} --models "github-copilot/*"
98
+
99
+ # Cycle models with fixed thinking levels
100
+ ${n} --models sonnet:high,haiku:low
101
+
102
+ # Start with a specific thinking level
103
+ ${n} --thinking high "Solve this complex problem"
104
+
105
+ # Read-only mode (no file modifications possible)
106
+ ${n} --tools read,grep,find,ls -p "Review the code in src/"
107
+
108
+ # Disable one tool while keeping the rest available
109
+ ${n} --exclude-tools ask_question
110
+
111
+ # Export a session file to HTML
112
+ ${n} --export ~/${d}/agent/sessions/--path--/session.jsonl
113
+ ${n} --export session.jsonl output.html
114
+
115
+ ${l.bold("Environment Variables:")}
116
+ ANTHROPIC_API_KEY - Anthropic Claude API key
117
+ ANTHROPIC_OAUTH_TOKEN - Anthropic OAuth token (alternative to API key)
118
+ OPENAI_API_KEY - OpenAI GPT API key
119
+ AZURE_OPENAI_API_KEY - Azure OpenAI API key
120
+ AZURE_OPENAI_BASE_URL - Azure OpenAI/Cognitive Services base URL (e.g. https://{resource}.openai.azure.com)
121
+ AZURE_OPENAI_RESOURCE_NAME - Azure OpenAI resource name (alternative to base URL)
122
+ AZURE_OPENAI_API_VERSION - Azure OpenAI API version (default: v1)
123
+ AZURE_OPENAI_DEPLOYMENT_NAME_MAP - Azure OpenAI model=deployment map (comma-separated)
124
+ DEEPSEEK_API_KEY - DeepSeek API key
125
+ NVIDIA_API_KEY - NVIDIA NIM API key
126
+ GEMINI_API_KEY - Google Gemini API key
127
+ GROQ_API_KEY - Groq API key
128
+ CEREBRAS_API_KEY - Cerebras API key
129
+ XAI_API_KEY - xAI Grok API key
130
+ FIREWORKS_API_KEY - Fireworks API key
131
+ TOGETHER_API_KEY - Together AI API key
132
+ OPENROUTER_API_KEY - OpenRouter API key
133
+ AI_GATEWAY_API_KEY - Vercel AI Gateway API key
134
+ ZAI_API_KEY - ZAI API key
135
+ MISTRAL_API_KEY - Mistral API key
136
+ MINIMAX_API_KEY - MiniMax API key
137
+ MOONSHOT_API_KEY - Moonshot AI API key
138
+ OPENCODE_API_KEY - OpenCode Zen/OpenCode Go API key
139
+ KIMI_API_KEY - Kimi For Coding API key
140
+ CLOUDFLARE_API_KEY - Cloudflare API token (Workers AI and AI Gateway)
141
+ CLOUDFLARE_ACCOUNT_ID - Cloudflare account id (required for both)
142
+ CLOUDFLARE_GATEWAY_ID - Cloudflare AI Gateway slug (required for AI Gateway)
143
+ XIAOMI_API_KEY - Xiaomi MiMo API key (api.xiaomimimo.com billing)
144
+ XIAOMI_TOKEN_PLAN_CN_API_KEY - Xiaomi MiMo Token Plan API key (China region)
145
+ XIAOMI_TOKEN_PLAN_AMS_API_KEY - Xiaomi MiMo Token Plan API key (Amsterdam region)
146
+ XIAOMI_TOKEN_PLAN_SGP_API_KEY - Xiaomi MiMo Token Plan API key (Singapore region)
147
+ AWS_PROFILE - AWS profile for Amazon Bedrock
148
+ AWS_ACCESS_KEY_ID - AWS access key for Amazon Bedrock
149
+ AWS_SECRET_ACCESS_KEY - AWS secret key for Amazon Bedrock
150
+ AWS_BEARER_TOKEN_BEDROCK - Bedrock API key (bearer token)
151
+ AWS_REGION - AWS region for Amazon Bedrock (e.g., us-east-1)
152
+ ${u.padEnd(32)} - Config directory (default: ~/${d}/agent)
153
+ ${A.padEnd(32)} - Session storage directory (overridden by --session-dir)
154
+ KODA_PACKAGE_DIR - Override package directory (for Nix/Guix store paths)
155
+ KODA_OFFLINE - Disable startup network operations when set to 1/true/yes
156
+ KODA_TELEMETRY - Override install telemetry when set to 1/true/yes or 0/false/no
157
+ KODA_SHARE_VIEWER_URL - Base URL for /share command (default: https://openadapter.in/session/)
158
+
159
+ ${l.bold("Built-in Tool Names:")}
160
+ read - Read file contents
161
+ bash - Execute bash commands
162
+ edit - Edit files with find/replace
163
+ write - Write files (creates/overwrites)
164
+ grep - Search file contents (read-only, off by default)
165
+ find - Find files by glob pattern (read-only, off by default)
166
+ ls - List directory contents (read-only, off by default)
167
+ `)}a(k,"printHelp");export{f as isValidThinkingLevel,_ as parseArgs,k as printHelp};
@@ -0,0 +1,13 @@
1
+ /**
2
+ * TUI config selector for `pi config` command
3
+ */
4
+ import type { ResolvedPaths } from "../core/package-manager.ts";
5
+ import type { SettingsManager } from "../core/settings-manager.ts";
6
+ export interface ConfigSelectorOptions {
7
+ resolvedPaths: ResolvedPaths;
8
+ settingsManager: SettingsManager;
9
+ cwd: string;
10
+ agentDir: string;
11
+ }
12
+ /** Show TUI config selector and return when closed */
13
+ export declare function selectConfig(options: ConfigSelectorOptions): Promise<void>;
@@ -0,0 +1 @@
1
+ var a=Object.defineProperty;var o=(e,r)=>a(e,"name",{value:r,configurable:!0});import{ProcessTerminal as c,TUI as m}from"@openadapter/koda-tui";import{ConfigSelectorComponent as l}from"../modes/interactive/components/config-selector.js";import{initTheme as g,stopThemeWatcher as i}from"../modes/interactive/theme/theme.js";async function w(e){return g(e.settingsManager.getTheme(),!0),new Promise(r=>{const t=new m(new c);let s=!1;const n=new l(e.resolvedPaths,e.settingsManager,e.cwd,e.agentDir,()=>{s||(s=!0,t.stop(),i(),r())},()=>{t.stop(),i(),process.exit(0)},()=>t.requestRender(),t.terminal.rows);t.addChild(n),t.setFocus(n.getResourceList()),t.start()})}o(w,"selectConfig");export{w as selectConfig};
@@ -0,0 +1,14 @@
1
+ /**
2
+ * Process @file CLI arguments into text content and image attachments
3
+ */
4
+ import type { ImageContent } from "@openadapter/koda-ai";
5
+ export interface ProcessedFiles {
6
+ text: string;
7
+ images: ImageContent[];
8
+ }
9
+ export interface ProcessFileOptions {
10
+ /** Whether to auto-resize images to 2000x2000 max. Default: true */
11
+ autoResizeImages?: boolean;
12
+ }
13
+ /** Process @file arguments into text content and image attachments */
14
+ export declare function processFileArguments(fileArgs: string[], options?: ProcessFileOptions): Promise<ProcessedFiles>;
@@ -0,0 +1,7 @@
1
+ var u=Object.defineProperty;var l=(a,s)=>u(a,"name",{value:s,configurable:!0});import{access as y,readFile as f,stat as $}from"node:fs/promises";import p from"chalk";import{resolve as h}from"path";import{resolveReadPath as w}from"../core/tools/path-utils.js";import{formatDimensionNote as z,resizeImage as F}from"../utils/image-resize.js";import{detectSupportedImageMimeTypeFromFile as I}from"../utils/mime.js";async function N(a,s){const d=s?.autoResizeImages??!0;let o="";const c=[];for(const g of a){const e=h(w(g,process.cwd()));try{await y(e)}catch{console.error(p.red(`Error: File not found: ${e}`)),process.exit(1)}if((await $(e)).size===0)continue;const n=await I(e);if(n){const t=await f(e);let i,m;if(d){const r=await F(t,n);if(!r){o+=`<file name="${e}">[Image omitted: could not be resized below the inline image size limit.]</file>
2
+ `;continue}m=z(r),i={type:"image",mimeType:r.mimeType,data:r.data}}else i={type:"image",mimeType:n,data:t.toString("base64")};c.push(i),m?o+=`<file name="${e}">${m}</file>
3
+ `:o+=`<file name="${e}"></file>
4
+ `}else try{const t=await f(e,"utf-8");o+=`<file name="${e}">
5
+ ${t}
6
+ </file>
7
+ `}catch(t){const i=t instanceof Error?t.message:String(t);console.error(p.red(`Error: Could not read file ${e}: ${i}`)),process.exit(1)}}return{text:o,images:c}}l(N,"processFileArguments");export{N as processFileArguments};
@@ -0,0 +1,34 @@
1
+ /**
2
+ * Import past sessions from other coding CLIs into Koda's own session store, so
3
+ * nothing is left behind when you switch. Currently supports:
4
+ * - Claude Code (~/.claude/projects/<cwd>/<uuid>.jsonl)
5
+ * - OpenCode (~/.local/share/opencode/opencode.db — SQLite)
6
+ *
7
+ * Each external session is converted to a Koda session (one per source session),
8
+ * organized under the session's own project cwd so it shows up in `koda --resume`.
9
+ * Conversion is "text + tool summaries": the full user/assistant conversation as
10
+ * text, with tool actions noted compactly (e.g. "[tool: edit src/foo.ts]"). It is
11
+ * idempotent — a small registry tracks imported source ids and skips them on re-run.
12
+ *
13
+ * Entry points: `koda import` (CLI) and the first-run setup prompt.
14
+ */
15
+ export interface ImportCounts {
16
+ claude: number;
17
+ opencode: number;
18
+ }
19
+ export interface ImportResult {
20
+ imported: number;
21
+ skipped: number;
22
+ perSource: {
23
+ claude: number;
24
+ opencode: number;
25
+ };
26
+ errors: number;
27
+ }
28
+ /** Count importable (not-yet-imported) sessions per source. */
29
+ export declare function detectImportable(currentCwdOnly?: string): Promise<ImportCounts>;
30
+ /** Convert + write all not-yet-imported sessions. */
31
+ export declare function importExternalSessions(opts?: {
32
+ currentCwdOnly?: string;
33
+ onProgress?: (done: number, total: number) => void;
34
+ }): Promise<ImportResult>;
@@ -0,0 +1,6 @@
1
+ var _=Object.defineProperty;var a=(t,e)=>_(t,"name",{value:e,configurable:!0});import{existsSync as h,readdirSync as y,readFileSync as S,writeFileSync as b}from"node:fs";import{homedir as m}from"node:os";import{join as f}from"node:path";import{getAgentDir as x}from"../config.js";import{SessionManager as A}from"../core/session-manager.js";const I={input:0,output:0,cacheRead:0,cacheWrite:0,totalTokens:0,cost:{input:0,output:0,cacheRead:0,cacheWrite:0,total:0}};function w(t,e){return{role:"user",content:t,timestamp:e}}a(w,"userMsg");function D(t,e,r){return{role:"assistant",content:[{type:"text",text:t}],api:"openai-completions",provider:"openadapter",model:e||"imported",usage:I,stopReason:"stop",timestamp:r}}a(D,"asstMsg");function W(){return f(m(),".claude","projects")}a(W,"claudeProjectsDir");function C(){return f(m(),".local","share","opencode","opencode.db")}a(C,"openCodeDbPath");function E(t){return f(t,".koda-import.json")}a(E,"registryPath");function $(t){try{return JSON.parse(S(E(t),"utf-8"))}catch{return{}}}a($,"loadRegistry");function P(t,e){try{b(E(t),`${JSON.stringify(e,null,2)}
2
+ `,"utf-8")}catch{}}a(P,"saveRegistry");const M=a((t,e=120)=>t.length>e?`${t.slice(0,e)}\u2026`:t,"trunc");function j(t,e){const r=e?.file_path||e?.path||e?.command||e?.pattern||e?.url||"";return`[tool: ${t}${r?` ${M(String(r),80)}`:""}]`}a(j,"summarizeTool");function R(){const t=W();if(!h(t))return[];const e=[];for(const r of y(t)){const o=f(t,r);let s;try{s=y(o).filter(n=>n.endsWith(".jsonl"))}catch{continue}for(const n of s)try{const c=F(f(o,n),n.replace(/\.jsonl$/,""),r);c?.turns.length&&e.push(c)}catch{}}return e}a(R,"readClaudeSessions");function F(t,e,r){const o=S(t,"utf-8").split(`
3
+ `).filter(Boolean),s=[];let n="",c=e,p=0;for(const u of o){let i;try{i=JSON.parse(u)}catch{continue}if(i?.cwd&&!n&&(n=i.cwd),i?.sessionId&&(c=i.sessionId),i?.timestamp&&!p&&(p=Date.parse(i.timestamp)||0),i?.isSidechain)continue;const d=i?.timestamp&&Date.parse(i.timestamp)||Date.now();if(i?.type==="user"&&i.message){const l=N(i.message.content);l.trim()&&s.push({role:"user",text:l,ts:d})}else if(i?.type==="assistant"&&i.message){const l=T(i.message.content);l.trim()&&s.push({role:"assistant",text:l,model:i.message.model,ts:d})}}return n||(n=J(r)),{source:"claude",sourceId:c,cwd:n,createdMs:p||Date.now(),turns:s}}a(F,"readClaudeFile");function N(t){if(typeof t=="string")return t;if(!Array.isArray(t))return"";const e=[];for(const r of t)if(r?.type==="text"&&r.text)e.push(r.text);else if(r?.type==="tool_result"){const o=typeof r.content=="string"?r.content:Array.isArray(r.content)?r.content.map(s=>s?.text||"").join(" "):"";e.push(`[tool result: ${M(String(o).replace(/\s+/g," "))}]`)}return e.join(`
4
+ `)}a(N,"extractClaudeUser");function T(t){if(typeof t=="string")return t;if(!Array.isArray(t))return"";const e=[];for(const r of t)r?.type==="text"&&r.text?e.push(r.text):r?.type==="tool_use"&&e.push(j(r.name||"call",r.input));return e.join(`
5
+ `)}a(T,"extractClaudeAssistant");function J(t){return t.startsWith("-")?t.replace(/-/g,"/"):t}a(J,"decodeProjectDir");async function O(){const t=C();if(!h(t))return[];const e=process.emitWarning;process.emitWarning=()=>{};let r;try{({DatabaseSync:r}=await import("node:sqlite"))}catch{return[]}finally{process.emitWarning=e}const o=[];let s;try{s=new r(t,{readOnly:!0});const n=s.prepare("SELECT id, title, path, time_created, model FROM session").all(),c=s.prepare("SELECT id, data, time_created FROM message WHERE session_id = ? ORDER BY time_created, id"),p=s.prepare("SELECT data FROM part WHERE message_id = ? ORDER BY time_created, id");for(const u of n)try{const i=[];for(const d of c.all(u.id)){let l;try{l=JSON.parse(d.data)?.role}catch{continue}if(l!=="user"&&l!=="assistant")continue;const g=k(p.all(d.id));g.trim()&&i.push({role:l,text:g,model:u.model,ts:d.time_created||Date.now()})}i.length&&o.push({source:"opencode",sourceId:u.id,cwd:u.path||m(),title:u.title,createdMs:u.time_created||Date.now(),turns:i})}catch{}}catch{return o}finally{try{s?.close()}catch{}}return o}a(O,"readOpenCodeSessions");function k(t){const e=[];for(const r of t){let o;try{o=JSON.parse(r.data)}catch{continue}const s=o?.type;if(s==="text"&&o.text)e.push(o.text);else if(typeof s=="string"&&s.startsWith("tool")){const n=o.tool||o.name||o.toolName||"call";e.push(j(n,o.state?.input||o.input))}}return e.join(`
6
+ `)}a(k,"extractOpenCodeParts");async function K(t){const e=x(),r=$(e),o=R().filter(n=>!r[`claude:${n.sourceId}`]&&(!t||n.cwd===t)).length,s=(await O()).filter(n=>!r[`opencode:${n.sourceId}`]&&(!t||n.cwd===t)).length;return{claude:o,opencode:s}}a(K,"detectImportable");async function q(t){const e=x(),r=$(e),o=[...R(),...await O()].filter(c=>!r[`${c.source}:${c.sourceId}`]&&(!t?.currentCwdOnly||c.cwd===t.currentCwdOnly)),s={imported:0,skipped:0,perSource:{claude:0,opencode:0},errors:0};let n=0;for(const c of o){try{const p=B(c);r[`${c.source}:${c.sourceId}`]=p,s.imported++,s.perSource[c.source]++}catch{s.errors++}t?.onProgress?.(++n,o.length)}return P(e,r),s}a(q,"importExternalSessions");function B(t){const e=A.create(t.cwd),r=t.title?.trim()?`${t.title.trim()} `:"";e.appendMessage(w(`${r}[imported from ${t.source}]`,t.createdMs));let o=!1;for(const s of t.turns){const n=s.role==="user"?w(s.text,s.ts):D(s.text,s.model,s.ts);s.role==="assistant"&&(o=!0),e.appendMessage(n)}return o||e.appendMessage(D("[no assistant response was recorded in the original session]",void 0,t.createdMs)),e.getSessionFile()??""}a(B,"writeKodaSession");export{K as detectImportable,q as importExternalSessions};
@@ -0,0 +1,17 @@
1
+ import type { ImageContent } from "@openadapter/koda-ai";
2
+ import type { Args } from "./args.ts";
3
+ export interface InitialMessageInput {
4
+ parsed: Args;
5
+ fileText?: string;
6
+ fileImages?: ImageContent[];
7
+ stdinContent?: string;
8
+ }
9
+ export interface InitialMessageResult {
10
+ initialMessage?: string;
11
+ initialImages?: ImageContent[];
12
+ }
13
+ /**
14
+ * Combine stdin content, @file text, and the first CLI message into a single
15
+ * initial prompt for non-interactive mode.
16
+ */
17
+ export declare function buildInitialMessage({ parsed, fileText, fileImages, stdinContent }: InitialMessageInput): InitialMessageResult;
@@ -0,0 +1 @@
1
+ var g=Object.defineProperty;var t=(s,n)=>g(s,"name",{value:n,configurable:!0});function a({parsed:s,fileText:n,fileImages:e,stdinContent:u}){const i=[];return u!==void 0&&i.push(u),n&&i.push(n),s.messages.length>0&&(i.push(s.messages[0]),s.messages.shift()),{initialMessage:i.length>0?i.join(""):void 0,initialImages:e&&e.length>0?e:void 0}}t(a,"buildInitialMessage");export{a as buildInitialMessage};
@@ -0,0 +1,8 @@
1
+ /**
2
+ * List available models with optional fuzzy search
3
+ */
4
+ import type { ModelRegistry } from "../core/model-registry.ts";
5
+ /**
6
+ * List available models, optionally filtered by search pattern
7
+ */
8
+ export declare function listModels(modelRegistry: ModelRegistry, searchPattern?: string): Promise<void>;
@@ -0,0 +1,2 @@
1
+ var x=Object.defineProperty;var m=(i,e)=>x(i,"name",{value:e,configurable:!0});import{fuzzyFilter as c}from"@openadapter/koda-tui";import u from"chalk";import{formatNoModelsAvailableMessage as f}from"../core/auth-guidance.js";function p(i){if(i>=1e6){const e=i/1e6;return e%1===0?`${e}M`:`${e.toFixed(1)}M`}if(i>=1e3){const e=i/1e3;return e%1===0?`${e}K`:`${e.toFixed(1)}K`}return i.toString()}m(p,"formatTokenCount");async function O(i,e){const s=i.getError();s&&console.error(u.yellow(`Warning: errors loading models.json:
2
+ ${s}`));const l=i.getAvailable();if(l.length===0){console.log(f());return}let a=l;if(e&&(a=c(l,e,o=>`${o.provider} ${o.id}`)),a.length===0){console.log(`No models matching "${e}"`);return}a.sort((o,d)=>{const g=o.provider.localeCompare(d.provider);return g!==0?g:o.id.localeCompare(d.id)});const r=a.map(o=>({provider:o.provider,model:o.id,context:p(o.contextWindow),maxOut:p(o.maxTokens),thinking:o.reasoning?"yes":"no",images:o.input.includes("image")?"yes":"no"})),n={provider:"provider",model:"model",context:"context",maxOut:"max-out",thinking:"thinking",images:"images"},t={provider:Math.max(n.provider.length,...r.map(o=>o.provider.length)),model:Math.max(n.model.length,...r.map(o=>o.model.length)),context:Math.max(n.context.length,...r.map(o=>o.context.length)),maxOut:Math.max(n.maxOut.length,...r.map(o=>o.maxOut.length)),thinking:Math.max(n.thinking.length,...r.map(o=>o.thinking.length)),images:Math.max(n.images.length,...r.map(o=>o.images.length))},h=[n.provider.padEnd(t.provider),n.model.padEnd(t.model),n.context.padEnd(t.context),n.maxOut.padEnd(t.maxOut),n.thinking.padEnd(t.thinking),n.images.padEnd(t.images)].join(" ");console.log(h);for(const o of r){const d=[o.provider.padEnd(t.provider),o.model.padEnd(t.model),o.context.padEnd(t.context),o.maxOut.padEnd(t.maxOut),o.thinking.padEnd(t.thinking),o.images.padEnd(t.images)].join(" ");console.log(d)}}m(O,"listModels");export{O as listModels};
@@ -0,0 +1,35 @@
1
+ /**
2
+ * OpenAdapter first-run setup for Koda.
3
+ *
4
+ * Koda ships an OpenAdapter layer (provider config + extensions + skills) that a
5
+ * fresh install needs wired up. This runs the bundled `setup.mjs` wizard, which
6
+ * prompts for the user's own sk-cv key, fetches the model list, registers the
7
+ * extensions, and copies the skills.
8
+ *
9
+ * koda setup → re-run the wizard any time
10
+ * first launch with no → auto-run once (interactive only)
11
+ * OpenAdapter provider
12
+ */
13
+ /**
14
+ * Offer to import past sessions from Claude Code + OpenCode so nothing is left
15
+ * behind. `auto` = called from first-run (skip silently if there's nothing).
16
+ */
17
+ export declare function runInteractiveImport(opts?: {
18
+ auto?: boolean;
19
+ }): Promise<void>;
20
+ /**
21
+ * Once a day, refresh the OpenAdapter model list from the gateway so users
22
+ * automatically get newly-added models without re-running setup. Best-effort and
23
+ * throttled (24h); KODA_NO_MODEL_REFRESH=1 or KODA_OFFLINE disables.
24
+ */
25
+ export declare function maybeRefreshOpenAdapterModels(agentDir: string): Promise<void>;
26
+ /** `koda import` — import sessions from other CLIs any time. */
27
+ export declare function handleImportCommand(args: string[]): Promise<boolean>;
28
+ /** Run the bundled wizard interactively. Returns true on success. */
29
+ export declare function runOpenAdapterSetup(extraArgs?: string[]): boolean;
30
+ /** `koda setup [sk-cv-...]` — explicit (re)configuration. */
31
+ export declare function handleSetupCommand(args: string[]): Promise<boolean>;
32
+ /** True when no OpenAdapter provider is configured yet (a fresh install). */
33
+ export declare function needsOpenAdapterSetup(agentDir: string): boolean;
34
+ /** On the first interactive launch with no OpenAdapter config, run the wizard. */
35
+ export declare function maybeFirstRunSetup(agentDir: string): Promise<void>;
@@ -0,0 +1,4 @@
1
+ var y=Object.defineProperty;var n=(t,e)=>y(t,"name",{value:e,configurable:!0});import{spawnSync as h}from"node:child_process";import{existsSync as S,readFileSync as p,writeFileSync as g}from"node:fs";import{dirname as w,join as i}from"node:path";import{createInterface as O}from"node:readline/promises";import{fileURLToPath as $}from"node:url";import u from"chalk";import{getPackageDir as x}from"../config.js";import{detectImportable as A,importExternalSessions as C}from"./import-sessions.js";async function b(t,e=!0){const r=O({input:process.stdin,output:process.stdout});try{const o=(await r.question(`${t} ${e?"[Y/n]":"[y/N]"} `)).trim().toLowerCase();return o?o==="y"||o==="yes":e}finally{r.close()}}n(b,"askYesNo");async function f(t){let e;try{e=await A()}catch{return}if(e.claude+e.opencode===0){t?.auto||console.log("No new sessions to import from Claude Code or OpenCode.");return}const o=[e.claude?`${e.claude} from Claude Code`:"",e.opencode?`${e.opencode} from OpenCode`:""].filter(Boolean).join(" and ");if(!await b(u.bold(`Import ${o} into Koda so all your history is here?`)))return;process.stdout.write("Importing\u2026 ");const s=await C({onProgress:n((l,c)=>{process.stdout.write(`\rImporting\u2026 ${l}/${c} `)},"onProgress")});process.stdout.write("\r"),console.log(`\u2713 Imported ${s.imported} session(s) (${s.perSource.claude} Claude Code, ${s.perSource.opencode} OpenCode)${s.errors?`, ${s.errors} skipped`:""}. Find them with \`koda --resume\`.`)}n(f,"runInteractiveImport");async function E(t){if(process.env.KODA_NO_MODEL_REFRESH==="1"||process.env.KODA_OFFLINE)return;const e=i(t,"models.json");let r;try{r=JSON.parse(p(e,"utf-8"))}catch{return}const o=r?.providers?.openadapter;if(!o?.apiKey||!o?.baseUrl)return;const d=typeof o.modelsRefreshedAt=="number"?o.modelsRefreshedAt:0;if(!(Date.now()-d<1440*60*1e3))try{const s=await fetch(`${String(o.baseUrl).replace(/\/$/,"")}/models`,{headers:{Authorization:`Bearer ${o.apiKey}`},signal:AbortSignal.timeout(5e3)});if(!s.ok)return;const c=((await s.json()).data??[]).filter(a=>(a.endpoint_format||a.model_type)==="chat");if(c.length===0)return;o.models=c.map(a=>({id:a.id,name:a.id,input:a.supports_vision?["text","image"]:["text"],maxTokens:16e3})),o.modelsRefreshedAt=Date.now(),g(e,`${JSON.stringify(r,null,2)}
2
+ `,"utf-8")}catch{}}n(E,"maybeRefreshOpenAdapterModels");async function J(t){return t[0]!=="import"?!1:(await f(),!0)}n(J,"handleImportCommand");function I(){const t=w($(import.meta.url)),e=[i(x(),"openadapter","setup.mjs"),i(t,"..","..","openadapter","setup.mjs"),i(t,"..","..","..","..","scripts","setup-openadapter.mjs")];for(const r of e)if(S(r))return r;return null}n(I,"findSetupScript");function m(t=[]){const e=I();return e?h(process.execPath,[e,...t],{stdio:"inherit"}).status===0:(console.error(u.red("Koda setup script not found in this install.")),!1)}n(m,"runOpenAdapterSetup");async function L(t){if(t[0]!=="setup")return!1;const e=t.slice(1).find(r=>r.startsWith("sk-"));return m(e?[e]:[]),!0}n(L,"handleSetupCommand");function K(t){try{if(JSON.parse(p(i(t,"settings.json"),"utf-8"))?.defaultProvider==="openadapter")return!1}catch{}try{if(JSON.parse(p(i(t,"models.json"),"utf-8"))?.providers?.openadapter?.apiKey)return!1}catch{}return!0}n(K,"needsOpenAdapterSetup");async function U(t){if(process.env.KODA_SKIP_SETUP!=="1"&&K(t)){console.log(u.bold(`
3
+ Welcome to Koda \u2014 let's connect it to OpenAdapter (one-time).
4
+ `)),m([]),console.log("");try{await f({auto:!0})}catch{}}}n(U,"maybeFirstRunSetup");export{J as handleImportCommand,L as handleSetupCommand,U as maybeFirstRunSetup,E as maybeRefreshOpenAdapterModels,K as needsOpenAdapterSetup,f as runInteractiveImport,m as runOpenAdapterSetup};
@@ -0,0 +1,8 @@
1
+ /**
2
+ * TUI session selector for --resume flag
3
+ */
4
+ import type { SessionInfo, SessionListProgress } from "../core/session-manager.ts";
5
+ type SessionsLoader = (onProgress?: SessionListProgress) => Promise<SessionInfo[]>;
6
+ /** Show TUI session selector and return selected session path or null if cancelled */
7
+ export declare function selectSession(currentSessionsLoader: SessionsLoader, allSessionsLoader: SessionsLoader): Promise<string | null>;
8
+ export {};
@@ -0,0 +1 @@
1
+ var l=Object.defineProperty;var c=(t,n)=>l(t,"name",{value:n,configurable:!0});import{ProcessTerminal as m,setKeybindings as p,TUI as d}from"@openadapter/koda-tui";import{KeybindingsManager as f}from"../core/keybindings.js";import{SessionSelectorComponent as u}from"../modes/interactive/components/session-selector.js";async function b(t,n){return new Promise(o=>{const e=new d(new m),i=f.create();p(i);let s=!1;const r=new u(t,n,a=>{s||(s=!0,e.stop(),o(a))},()=>{s||(s=!0,e.stop(),o(null))},()=>{e.stop(),process.exit(0)},()=>e.requestRender(),{showRenameHint:!1,keybindings:i});e.addChild(r),e.setFocus(r.getSessionList()),e.start()})}c(b,"selectSession");export{b as selectSession};
package/dist/cli.d.ts ADDED
@@ -0,0 +1,2 @@
1
+ #!/usr/bin/env node
2
+ export {};
package/dist/cli.js ADDED
@@ -0,0 +1,2 @@
1
+ #!/usr/bin/env node
2
+ import{APP_NAME as r}from"./config.js";import{configureHttpDispatcher as e}from"./core/http-dispatcher.js";import{main as o}from"./main.js";process.title=r,process.env.KODA_CODING_AGENT="true",process.emitWarning=(()=>{}),e(),o(process.argv.slice(2));