@toolkit-cli/toolkode 1.3.7

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 (676) hide show
  1. package/AGENTS.md +69 -0
  2. package/BUN_SHELL_MIGRATION_PLAN.md +136 -0
  3. package/Dockerfile +18 -0
  4. package/README.md +15 -0
  5. package/bin/opencode +179 -0
  6. package/bin/toolkode +17 -0
  7. package/bin/toolkode.cjs +190 -0
  8. package/bunfig.toml +7 -0
  9. package/drizzle.config.ts +10 -0
  10. package/git +0 -0
  11. package/migration/20260127222353_familiar_lady_ursula/migration.sql +90 -0
  12. package/migration/20260127222353_familiar_lady_ursula/snapshot.json +796 -0
  13. package/migration/20260211171708_add_project_commands/migration.sql +1 -0
  14. package/migration/20260211171708_add_project_commands/snapshot.json +806 -0
  15. package/migration/20260213144116_wakeful_the_professor/migration.sql +11 -0
  16. package/migration/20260213144116_wakeful_the_professor/snapshot.json +897 -0
  17. package/migration/20260225215848_workspace/migration.sql +7 -0
  18. package/migration/20260225215848_workspace/snapshot.json +959 -0
  19. package/migration/20260227213759_add_session_workspace_id/migration.sql +2 -0
  20. package/migration/20260227213759_add_session_workspace_id/snapshot.json +983 -0
  21. package/migration/20260228203230_blue_harpoon/migration.sql +17 -0
  22. package/migration/20260228203230_blue_harpoon/snapshot.json +1102 -0
  23. package/migration/20260303231226_add_workspace_fields/migration.sql +5 -0
  24. package/migration/20260303231226_add_workspace_fields/snapshot.json +1013 -0
  25. package/migration/20260309230000_move_org_to_state/migration.sql +3 -0
  26. package/migration/20260309230000_move_org_to_state/snapshot.json +1156 -0
  27. package/migration/20260312043431_session_message_cursor/migration.sql +4 -0
  28. package/migration/20260312043431_session_message_cursor/snapshot.json +1168 -0
  29. package/migration/20260323234822_events/migration.sql +13 -0
  30. package/migration/20260323234822_events/snapshot.json +1271 -0
  31. package/package.json +160 -0
  32. package/parsers-config.ts +290 -0
  33. package/script/build-node.ts +54 -0
  34. package/script/build.ts +276 -0
  35. package/script/check-migrations.ts +16 -0
  36. package/script/postinstall.mjs +131 -0
  37. package/script/publish.ts +181 -0
  38. package/script/schema.ts +63 -0
  39. package/script/seed-e2e.ts +60 -0
  40. package/script/upgrade-opentui.ts +64 -0
  41. package/specs/effect-migration.md +293 -0
  42. package/specs/tui-plugins.md +389 -0
  43. package/src/account/account.sql.ts +39 -0
  44. package/src/account/index.ts +397 -0
  45. package/src/account/repo.ts +163 -0
  46. package/src/account/schema.ts +91 -0
  47. package/src/acp/README.md +174 -0
  48. package/src/acp/agent.ts +1743 -0
  49. package/src/acp/session.ts +116 -0
  50. package/src/acp/types.ts +24 -0
  51. package/src/agent/agent.ts +418 -0
  52. package/src/agent/generate.txt +75 -0
  53. package/src/agent/prompt/compaction.txt +14 -0
  54. package/src/agent/prompt/explore.txt +18 -0
  55. package/src/agent/prompt/summary.txt +11 -0
  56. package/src/agent/prompt/title.txt +44 -0
  57. package/src/auth/index.ts +115 -0
  58. package/src/bun/index.ts +128 -0
  59. package/src/bun/registry.ts +50 -0
  60. package/src/bus/bus-event.ts +40 -0
  61. package/src/bus/global.ts +10 -0
  62. package/src/bus/index.ts +184 -0
  63. package/src/channel/index.ts +231 -0
  64. package/src/cli/bootstrap.ts +17 -0
  65. package/src/cli/cmd/account.ts +257 -0
  66. package/src/cli/cmd/acp.ts +70 -0
  67. package/src/cli/cmd/agent.ts +245 -0
  68. package/src/cli/cmd/cmd.ts +7 -0
  69. package/src/cli/cmd/db.ts +119 -0
  70. package/src/cli/cmd/debug/agent.ts +167 -0
  71. package/src/cli/cmd/debug/config.ts +16 -0
  72. package/src/cli/cmd/debug/file.ts +97 -0
  73. package/src/cli/cmd/debug/index.ts +48 -0
  74. package/src/cli/cmd/debug/lsp.ts +53 -0
  75. package/src/cli/cmd/debug/ripgrep.ts +87 -0
  76. package/src/cli/cmd/debug/scrap.ts +16 -0
  77. package/src/cli/cmd/debug/skill.ts +16 -0
  78. package/src/cli/cmd/debug/snapshot.ts +52 -0
  79. package/src/cli/cmd/export.ts +89 -0
  80. package/src/cli/cmd/generate.ts +38 -0
  81. package/src/cli/cmd/github.ts +1646 -0
  82. package/src/cli/cmd/import.ts +207 -0
  83. package/src/cli/cmd/mcp.ts +754 -0
  84. package/src/cli/cmd/models.ts +78 -0
  85. package/src/cli/cmd/plug.ts +231 -0
  86. package/src/cli/cmd/pr.ts +127 -0
  87. package/src/cli/cmd/providers.ts +482 -0
  88. package/src/cli/cmd/run.ts +738 -0
  89. package/src/cli/cmd/serve.ts +42 -0
  90. package/src/cli/cmd/session.ts +159 -0
  91. package/src/cli/cmd/stats.ts +410 -0
  92. package/src/cli/cmd/tui/app.tsx +1255 -0
  93. package/src/cli/cmd/tui/attach.ts +88 -0
  94. package/src/cli/cmd/tui/component/border.tsx +21 -0
  95. package/src/cli/cmd/tui/component/dialog-agent.tsx +31 -0
  96. package/src/cli/cmd/tui/component/dialog-command.tsx +171 -0
  97. package/src/cli/cmd/tui/component/dialog-mcp.tsx +86 -0
  98. package/src/cli/cmd/tui/component/dialog-model.tsx +264 -0
  99. package/src/cli/cmd/tui/component/dialog-provider.tsx +334 -0
  100. package/src/cli/cmd/tui/component/dialog-session-list.tsx +108 -0
  101. package/src/cli/cmd/tui/component/dialog-session-rename.tsx +31 -0
  102. package/src/cli/cmd/tui/component/dialog-skill.tsx +36 -0
  103. package/src/cli/cmd/tui/component/dialog-stash.tsx +87 -0
  104. package/src/cli/cmd/tui/component/dialog-status.tsx +168 -0
  105. package/src/cli/cmd/tui/component/dialog-tag.tsx +44 -0
  106. package/src/cli/cmd/tui/component/dialog-theme-list.tsx +50 -0
  107. package/src/cli/cmd/tui/component/dialog-variant.tsx +29 -0
  108. package/src/cli/cmd/tui/component/dialog-workspace-list.tsx +320 -0
  109. package/src/cli/cmd/tui/component/error-component.tsx +91 -0
  110. package/src/cli/cmd/tui/component/logo.tsx +86 -0
  111. package/src/cli/cmd/tui/component/plugin-route-missing.tsx +14 -0
  112. package/src/cli/cmd/tui/component/prompt/autocomplete.tsx +667 -0
  113. package/src/cli/cmd/tui/component/prompt/frecency.tsx +90 -0
  114. package/src/cli/cmd/tui/component/prompt/history.tsx +108 -0
  115. package/src/cli/cmd/tui/component/prompt/index.tsx +1353 -0
  116. package/src/cli/cmd/tui/component/prompt/part.ts +16 -0
  117. package/src/cli/cmd/tui/component/prompt/stash.tsx +101 -0
  118. package/src/cli/cmd/tui/component/spinner.tsx +24 -0
  119. package/src/cli/cmd/tui/component/startup-loading.tsx +63 -0
  120. package/src/cli/cmd/tui/component/textarea-keybindings.ts +73 -0
  121. package/src/cli/cmd/tui/component/todo-item.tsx +32 -0
  122. package/src/cli/cmd/tui/component/workspace/dialog-session-list.tsx +151 -0
  123. package/src/cli/cmd/tui/context/args.tsx +15 -0
  124. package/src/cli/cmd/tui/context/directory.ts +13 -0
  125. package/src/cli/cmd/tui/context/exit.tsx +60 -0
  126. package/src/cli/cmd/tui/context/helper.tsx +25 -0
  127. package/src/cli/cmd/tui/context/keybind.tsx +105 -0
  128. package/src/cli/cmd/tui/context/kv.tsx +52 -0
  129. package/src/cli/cmd/tui/context/local.tsx +406 -0
  130. package/src/cli/cmd/tui/context/plugin-keybinds.ts +41 -0
  131. package/src/cli/cmd/tui/context/prompt.tsx +18 -0
  132. package/src/cli/cmd/tui/context/route.tsx +52 -0
  133. package/src/cli/cmd/tui/context/sdk.tsx +128 -0
  134. package/src/cli/cmd/tui/context/sync.tsx +504 -0
  135. package/src/cli/cmd/tui/context/theme/amber.json +245 -0
  136. package/src/cli/cmd/tui/context/theme/amiga.json +245 -0
  137. package/src/cli/cmd/tui/context/theme/atari.json +245 -0
  138. package/src/cli/cmd/tui/context/theme/aura.json +69 -0
  139. package/src/cli/cmd/tui/context/theme/ayu.json +80 -0
  140. package/src/cli/cmd/tui/context/theme/borland.json +245 -0
  141. package/src/cli/cmd/tui/context/theme/carbonfox.json +248 -0
  142. package/src/cli/cmd/tui/context/theme/catppuccin-frappe.json +233 -0
  143. package/src/cli/cmd/tui/context/theme/catppuccin-macchiato.json +233 -0
  144. package/src/cli/cmd/tui/context/theme/catppuccin.json +112 -0
  145. package/src/cli/cmd/tui/context/theme/cobalt2.json +228 -0
  146. package/src/cli/cmd/tui/context/theme/commodore.json +245 -0
  147. package/src/cli/cmd/tui/context/theme/cursor.json +249 -0
  148. package/src/cli/cmd/tui/context/theme/dos-edit.json +245 -0
  149. package/src/cli/cmd/tui/context/theme/dracula.json +219 -0
  150. package/src/cli/cmd/tui/context/theme/everforest.json +241 -0
  151. package/src/cli/cmd/tui/context/theme/flexoki.json +237 -0
  152. package/src/cli/cmd/tui/context/theme/github.json +233 -0
  153. package/src/cli/cmd/tui/context/theme/gnu.json +245 -0
  154. package/src/cli/cmd/tui/context/theme/gruvbox.json +242 -0
  155. package/src/cli/cmd/tui/context/theme/hacker.json +245 -0
  156. package/src/cli/cmd/tui/context/theme/irix.json +245 -0
  157. package/src/cli/cmd/tui/context/theme/kanagawa.json +77 -0
  158. package/src/cli/cmd/tui/context/theme/lucent-orng.json +237 -0
  159. package/src/cli/cmd/tui/context/theme/mac84.json +245 -0
  160. package/src/cli/cmd/tui/context/theme/material.json +235 -0
  161. package/src/cli/cmd/tui/context/theme/matrix.json +77 -0
  162. package/src/cli/cmd/tui/context/theme/mercury.json +252 -0
  163. package/src/cli/cmd/tui/context/theme/monokai.json +221 -0
  164. package/src/cli/cmd/tui/context/theme/nightowl.json +221 -0
  165. package/src/cli/cmd/tui/context/theme/nord.json +223 -0
  166. package/src/cli/cmd/tui/context/theme/norton.json +245 -0
  167. package/src/cli/cmd/tui/context/theme/one-dark.json +84 -0
  168. package/src/cli/cmd/tui/context/theme/opencode.json +245 -0
  169. package/src/cli/cmd/tui/context/theme/orng.json +249 -0
  170. package/src/cli/cmd/tui/context/theme/osaka-jade.json +93 -0
  171. package/src/cli/cmd/tui/context/theme/palenight.json +222 -0
  172. package/src/cli/cmd/tui/context/theme/pine.json +245 -0
  173. package/src/cli/cmd/tui/context/theme/retrowave.json +245 -0
  174. package/src/cli/cmd/tui/context/theme/rosepine.json +234 -0
  175. package/src/cli/cmd/tui/context/theme/solarized.json +223 -0
  176. package/src/cli/cmd/tui/context/theme/synthwave84.json +226 -0
  177. package/src/cli/cmd/tui/context/theme/tokyonight.json +243 -0
  178. package/src/cli/cmd/tui/context/theme/toolkode.json +245 -0
  179. package/src/cli/cmd/tui/context/theme/tron.json +245 -0
  180. package/src/cli/cmd/tui/context/theme/ubuntu.json +245 -0
  181. package/src/cli/cmd/tui/context/theme/vercel.json +245 -0
  182. package/src/cli/cmd/tui/context/theme/vesper.json +218 -0
  183. package/src/cli/cmd/tui/context/theme/vt100.json +245 -0
  184. package/src/cli/cmd/tui/context/theme/xcode.json +245 -0
  185. package/src/cli/cmd/tui/context/theme/zenburn.json +223 -0
  186. package/src/cli/cmd/tui/context/theme.tsx +1288 -0
  187. package/src/cli/cmd/tui/context/tui-config.tsx +9 -0
  188. package/src/cli/cmd/tui/event.ts +49 -0
  189. package/src/cli/cmd/tui/feature-plugins/home/tips-view.tsx +152 -0
  190. package/src/cli/cmd/tui/feature-plugins/home/tips.tsx +50 -0
  191. package/src/cli/cmd/tui/feature-plugins/sidebar/agents-panel.tsx +95 -0
  192. package/src/cli/cmd/tui/feature-plugins/sidebar/btw-panel.tsx +105 -0
  193. package/src/cli/cmd/tui/feature-plugins/sidebar/commands-panel.tsx +40 -0
  194. package/src/cli/cmd/tui/feature-plugins/sidebar/context.tsx +63 -0
  195. package/src/cli/cmd/tui/feature-plugins/sidebar/files.tsx +62 -0
  196. package/src/cli/cmd/tui/feature-plugins/sidebar/footer.tsx +93 -0
  197. package/src/cli/cmd/tui/feature-plugins/sidebar/git-panel.tsx +36 -0
  198. package/src/cli/cmd/tui/feature-plugins/sidebar/loop-panel.tsx +124 -0
  199. package/src/cli/cmd/tui/feature-plugins/sidebar/lsp.tsx +66 -0
  200. package/src/cli/cmd/tui/feature-plugins/sidebar/mcp.tsx +96 -0
  201. package/src/cli/cmd/tui/feature-plugins/sidebar/session-panel.tsx +48 -0
  202. package/src/cli/cmd/tui/feature-plugins/sidebar/todo.tsx +48 -0
  203. package/src/cli/cmd/tui/feature-plugins/system/plugins.tsx +270 -0
  204. package/src/cli/cmd/tui/plugin/api.tsx +420 -0
  205. package/src/cli/cmd/tui/plugin/index.ts +3 -0
  206. package/src/cli/cmd/tui/plugin/internal.ts +37 -0
  207. package/src/cli/cmd/tui/plugin/runtime.ts +967 -0
  208. package/src/cli/cmd/tui/plugin/slots.tsx +61 -0
  209. package/src/cli/cmd/tui/routes/home.tsx +173 -0
  210. package/src/cli/cmd/tui/routes/session/dialog-fork-from-timeline.tsx +65 -0
  211. package/src/cli/cmd/tui/routes/session/dialog-message.tsx +110 -0
  212. package/src/cli/cmd/tui/routes/session/dialog-subagent.tsx +26 -0
  213. package/src/cli/cmd/tui/routes/session/dialog-timeline.tsx +47 -0
  214. package/src/cli/cmd/tui/routes/session/footer.tsx +91 -0
  215. package/src/cli/cmd/tui/routes/session/index.tsx +2229 -0
  216. package/src/cli/cmd/tui/routes/session/permission.tsx +685 -0
  217. package/src/cli/cmd/tui/routes/session/question.tsx +467 -0
  218. package/src/cli/cmd/tui/routes/session/sidebar.tsx +72 -0
  219. package/src/cli/cmd/tui/routes/session/subagent-footer.tsx +131 -0
  220. package/src/cli/cmd/tui/thread.ts +232 -0
  221. package/src/cli/cmd/tui/ui/dialog-alert.tsx +59 -0
  222. package/src/cli/cmd/tui/ui/dialog-confirm.tsx +89 -0
  223. package/src/cli/cmd/tui/ui/dialog-export-options.tsx +208 -0
  224. package/src/cli/cmd/tui/ui/dialog-help.tsx +40 -0
  225. package/src/cli/cmd/tui/ui/dialog-prompt.tsx +106 -0
  226. package/src/cli/cmd/tui/ui/dialog-select.tsx +402 -0
  227. package/src/cli/cmd/tui/ui/dialog.tsx +192 -0
  228. package/src/cli/cmd/tui/ui/link.tsx +28 -0
  229. package/src/cli/cmd/tui/ui/spinner.ts +368 -0
  230. package/src/cli/cmd/tui/ui/toast.tsx +100 -0
  231. package/src/cli/cmd/tui/util/clipboard.ts +192 -0
  232. package/src/cli/cmd/tui/util/editor.ts +37 -0
  233. package/src/cli/cmd/tui/util/selection.ts +25 -0
  234. package/src/cli/cmd/tui/util/signal.ts +7 -0
  235. package/src/cli/cmd/tui/util/terminal.ts +114 -0
  236. package/src/cli/cmd/tui/util/transcript.ts +98 -0
  237. package/src/cli/cmd/tui/win32.ts +129 -0
  238. package/src/cli/cmd/tui/worker.ts +204 -0
  239. package/src/cli/cmd/uninstall.ts +353 -0
  240. package/src/cli/cmd/upgrade.ts +73 -0
  241. package/src/cli/cmd/web.ts +81 -0
  242. package/src/cli/effect/prompt.ts +25 -0
  243. package/src/cli/error.ts +46 -0
  244. package/src/cli/logo.ts +7 -0
  245. package/src/cli/network.ts +60 -0
  246. package/src/cli/ui.ts +116 -0
  247. package/src/cli/upgrade.ts +31 -0
  248. package/src/command/index.ts +195 -0
  249. package/src/command/template/initialize.txt +10 -0
  250. package/src/command/template/review.txt +101 -0
  251. package/src/config/config.ts +1693 -0
  252. package/src/config/markdown.ts +99 -0
  253. package/src/config/migrate-tui-config.ts +155 -0
  254. package/src/config/paths.ts +174 -0
  255. package/src/config/tui-schema.ts +36 -0
  256. package/src/config/tui.ts +212 -0
  257. package/src/control-plane/adaptors/index.ts +20 -0
  258. package/src/control-plane/adaptors/worktree.ts +38 -0
  259. package/src/control-plane/schema.ts +17 -0
  260. package/src/control-plane/sse.ts +66 -0
  261. package/src/control-plane/types.ts +21 -0
  262. package/src/control-plane/workspace.sql.ts +17 -0
  263. package/src/control-plane/workspace.ts +154 -0
  264. package/src/cron/index.ts +241 -0
  265. package/src/cron/parse.ts +189 -0
  266. package/src/effect/cross-spawn-spawner.ts +479 -0
  267. package/src/effect/instance-registry.ts +12 -0
  268. package/src/effect/instance-state.ts +47 -0
  269. package/src/effect/run-service.ts +19 -0
  270. package/src/env/index.ts +28 -0
  271. package/src/file/ignore.ts +82 -0
  272. package/src/file/index.ts +693 -0
  273. package/src/file/protected.ts +59 -0
  274. package/src/file/ripgrep.ts +376 -0
  275. package/src/file/time.ts +128 -0
  276. package/src/file/watcher.ts +171 -0
  277. package/src/filesystem/index.ts +226 -0
  278. package/src/flag/flag.ts +157 -0
  279. package/src/format/formatter.ts +396 -0
  280. package/src/format/index.ts +199 -0
  281. package/src/global/index.ts +54 -0
  282. package/src/hooks/index.ts +302 -0
  283. package/src/id/id.ts +85 -0
  284. package/src/ide/index.ts +74 -0
  285. package/src/index.ts +243 -0
  286. package/src/installation/index.ts +363 -0
  287. package/src/lsp/client.ts +252 -0
  288. package/src/lsp/index.ts +558 -0
  289. package/src/lsp/language.ts +120 -0
  290. package/src/lsp/launch.ts +21 -0
  291. package/src/lsp/server.ts +2093 -0
  292. package/src/mcp/auth.ts +181 -0
  293. package/src/mcp/index.ts +926 -0
  294. package/src/mcp/oauth-callback.ts +215 -0
  295. package/src/mcp/oauth-provider.ts +185 -0
  296. package/src/node.ts +1 -0
  297. package/src/patch/index.ts +680 -0
  298. package/src/permission/arity.ts +163 -0
  299. package/src/permission/evaluate.ts +15 -0
  300. package/src/permission/index.ts +322 -0
  301. package/src/permission/schema.ts +17 -0
  302. package/src/plugin/codex.ts +628 -0
  303. package/src/plugin/copilot.ts +343 -0
  304. package/src/plugin/index.ts +331 -0
  305. package/src/plugin/install.ts +384 -0
  306. package/src/plugin/meta.ts +165 -0
  307. package/src/plugin/shared.ts +172 -0
  308. package/src/project/bootstrap.ts +31 -0
  309. package/src/project/instance.ts +167 -0
  310. package/src/project/project.sql.ts +16 -0
  311. package/src/project/project.ts +519 -0
  312. package/src/project/schema.ts +16 -0
  313. package/src/project/state.ts +70 -0
  314. package/src/project/vcs.ts +124 -0
  315. package/src/provider/auth.ts +252 -0
  316. package/src/provider/error.ts +197 -0
  317. package/src/provider/models.ts +138 -0
  318. package/src/provider/provider.ts +1593 -0
  319. package/src/provider/schema.ts +39 -0
  320. package/src/provider/sdk/copilot/README.md +5 -0
  321. package/src/provider/sdk/copilot/chat/convert-to-openai-compatible-chat-messages.ts +170 -0
  322. package/src/provider/sdk/copilot/chat/get-response-metadata.ts +15 -0
  323. package/src/provider/sdk/copilot/chat/map-openai-compatible-finish-reason.ts +19 -0
  324. package/src/provider/sdk/copilot/chat/openai-compatible-api-types.ts +64 -0
  325. package/src/provider/sdk/copilot/chat/openai-compatible-chat-language-model.ts +815 -0
  326. package/src/provider/sdk/copilot/chat/openai-compatible-chat-options.ts +28 -0
  327. package/src/provider/sdk/copilot/chat/openai-compatible-metadata-extractor.ts +44 -0
  328. package/src/provider/sdk/copilot/chat/openai-compatible-prepare-tools.ts +83 -0
  329. package/src/provider/sdk/copilot/copilot-provider.ts +100 -0
  330. package/src/provider/sdk/copilot/index.ts +2 -0
  331. package/src/provider/sdk/copilot/openai-compatible-error.ts +27 -0
  332. package/src/provider/sdk/copilot/responses/convert-to-openai-responses-input.ts +335 -0
  333. package/src/provider/sdk/copilot/responses/map-openai-responses-finish-reason.ts +22 -0
  334. package/src/provider/sdk/copilot/responses/openai-config.ts +18 -0
  335. package/src/provider/sdk/copilot/responses/openai-error.ts +22 -0
  336. package/src/provider/sdk/copilot/responses/openai-responses-api-types.ts +214 -0
  337. package/src/provider/sdk/copilot/responses/openai-responses-language-model.ts +1769 -0
  338. package/src/provider/sdk/copilot/responses/openai-responses-prepare-tools.ts +173 -0
  339. package/src/provider/sdk/copilot/responses/openai-responses-settings.ts +1 -0
  340. package/src/provider/sdk/copilot/responses/tool/code-interpreter.ts +87 -0
  341. package/src/provider/sdk/copilot/responses/tool/file-search.ts +127 -0
  342. package/src/provider/sdk/copilot/responses/tool/image-generation.ts +114 -0
  343. package/src/provider/sdk/copilot/responses/tool/local-shell.ts +64 -0
  344. package/src/provider/sdk/copilot/responses/tool/web-search-preview.ts +103 -0
  345. package/src/provider/sdk/copilot/responses/tool/web-search.ts +102 -0
  346. package/src/provider/toolkit-manifest.ts +110 -0
  347. package/src/provider/transform.ts +1045 -0
  348. package/src/pty/index.ts +397 -0
  349. package/src/pty/schema.ts +17 -0
  350. package/src/question/index.ts +221 -0
  351. package/src/question/schema.ts +17 -0
  352. package/src/server/error.ts +36 -0
  353. package/src/server/event.ts +7 -0
  354. package/src/server/instance.ts +285 -0
  355. package/src/server/mdns.ts +60 -0
  356. package/src/server/middleware.ts +29 -0
  357. package/src/server/projectors.ts +28 -0
  358. package/src/server/router.ts +99 -0
  359. package/src/server/routes/config.ts +92 -0
  360. package/src/server/routes/event.ts +83 -0
  361. package/src/server/routes/experimental.ts +271 -0
  362. package/src/server/routes/file.ts +197 -0
  363. package/src/server/routes/global.ts +339 -0
  364. package/src/server/routes/mcp.ts +225 -0
  365. package/src/server/routes/permission.ts +69 -0
  366. package/src/server/routes/project.ts +118 -0
  367. package/src/server/routes/provider.ts +171 -0
  368. package/src/server/routes/pty.ts +211 -0
  369. package/src/server/routes/question.ts +99 -0
  370. package/src/server/routes/session.ts +1031 -0
  371. package/src/server/routes/tui.ts +379 -0
  372. package/src/server/routes/workspace.ts +94 -0
  373. package/src/server/server.ts +312 -0
  374. package/src/session/compaction.ts +424 -0
  375. package/src/session/index.ts +882 -0
  376. package/src/session/instruction.ts +321 -0
  377. package/src/session/llm.ts +341 -0
  378. package/src/session/message-v2.ts +1030 -0
  379. package/src/session/message.ts +191 -0
  380. package/src/session/overflow.ts +22 -0
  381. package/src/session/processor.ts +554 -0
  382. package/src/session/projectors.ts +135 -0
  383. package/src/session/prompt/anthropic.txt +105 -0
  384. package/src/session/prompt/beast.txt +147 -0
  385. package/src/session/prompt/build-switch.txt +5 -0
  386. package/src/session/prompt/codex.txt +79 -0
  387. package/src/session/prompt/copilot-gpt-5.txt +143 -0
  388. package/src/session/prompt/default.txt +108 -0
  389. package/src/session/prompt/gemini.txt +155 -0
  390. package/src/session/prompt/gpt.txt +107 -0
  391. package/src/session/prompt/max-steps.txt +16 -0
  392. package/src/session/prompt/plan-reminder-anthropic.txt +67 -0
  393. package/src/session/prompt/plan.txt +26 -0
  394. package/src/session/prompt/trinity.txt +97 -0
  395. package/src/session/prompt.ts +2058 -0
  396. package/src/session/retry.ts +106 -0
  397. package/src/session/revert.ts +138 -0
  398. package/src/session/schema.ts +38 -0
  399. package/src/session/session.sql.ts +103 -0
  400. package/src/session/status.ts +102 -0
  401. package/src/session/summary.ts +170 -0
  402. package/src/session/system.ts +74 -0
  403. package/src/session/todo.ts +57 -0
  404. package/src/share/share-next.ts +288 -0
  405. package/src/share/share.sql.ts +13 -0
  406. package/src/shell/shell.ts +73 -0
  407. package/src/skill/discovery.ts +116 -0
  408. package/src/skill/index.ts +284 -0
  409. package/src/skills-marketplace/index.ts +305 -0
  410. package/src/snapshot/index.ts +489 -0
  411. package/src/sql.d.ts +4 -0
  412. package/src/storage/db.bun.ts +8 -0
  413. package/src/storage/db.node.ts +8 -0
  414. package/src/storage/db.ts +177 -0
  415. package/src/storage/json-migration.ts +425 -0
  416. package/src/storage/schema.sql.ts +10 -0
  417. package/src/storage/schema.ts +5 -0
  418. package/src/storage/storage.ts +217 -0
  419. package/src/sync/README.md +179 -0
  420. package/src/sync/event.sql.ts +16 -0
  421. package/src/sync/index.ts +263 -0
  422. package/src/sync/schema.ts +14 -0
  423. package/src/team/index.ts +428 -0
  424. package/src/tool/apply_patch.ts +281 -0
  425. package/src/tool/apply_patch.txt +33 -0
  426. package/src/tool/bash.ts +271 -0
  427. package/src/tool/bash.txt +115 -0
  428. package/src/tool/batch.ts +183 -0
  429. package/src/tool/batch.txt +24 -0
  430. package/src/tool/codesearch.ts +132 -0
  431. package/src/tool/codesearch.txt +12 -0
  432. package/src/tool/cron-create.ts +54 -0
  433. package/src/tool/cron-create.txt +16 -0
  434. package/src/tool/cron-delete.ts +29 -0
  435. package/src/tool/cron-delete.txt +1 -0
  436. package/src/tool/cron-list.ts +41 -0
  437. package/src/tool/cron-list.txt +1 -0
  438. package/src/tool/edit.ts +667 -0
  439. package/src/tool/edit.txt +10 -0
  440. package/src/tool/external-directory.ts +32 -0
  441. package/src/tool/glob.ts +78 -0
  442. package/src/tool/glob.txt +6 -0
  443. package/src/tool/grep.ts +156 -0
  444. package/src/tool/grep.txt +8 -0
  445. package/src/tool/invalid.ts +17 -0
  446. package/src/tool/ls.ts +121 -0
  447. package/src/tool/ls.txt +1 -0
  448. package/src/tool/lsp.ts +97 -0
  449. package/src/tool/lsp.txt +19 -0
  450. package/src/tool/multiedit.ts +46 -0
  451. package/src/tool/multiedit.txt +41 -0
  452. package/src/tool/plan-enter.txt +14 -0
  453. package/src/tool/plan-exit.txt +13 -0
  454. package/src/tool/plan.ts +131 -0
  455. package/src/tool/question.ts +33 -0
  456. package/src/tool/question.txt +10 -0
  457. package/src/tool/read.ts +293 -0
  458. package/src/tool/read.txt +14 -0
  459. package/src/tool/registry.ts +232 -0
  460. package/src/tool/schema.ts +17 -0
  461. package/src/tool/send-message.ts +59 -0
  462. package/src/tool/send-message.txt +7 -0
  463. package/src/tool/skill.ts +105 -0
  464. package/src/tool/task.ts +230 -0
  465. package/src/tool/task.txt +62 -0
  466. package/src/tool/team.ts +235 -0
  467. package/src/tool/team.txt +22 -0
  468. package/src/tool/todo.ts +31 -0
  469. package/src/tool/todowrite.txt +167 -0
  470. package/src/tool/tool.ts +90 -0
  471. package/src/tool/truncate.ts +144 -0
  472. package/src/tool/truncation-dir.ts +4 -0
  473. package/src/tool/webfetch.ts +206 -0
  474. package/src/tool/webfetch.txt +13 -0
  475. package/src/tool/websearch.ts +150 -0
  476. package/src/tool/websearch.txt +14 -0
  477. package/src/tool/write.ts +84 -0
  478. package/src/tool/write.txt +8 -0
  479. package/src/util/abort.ts +35 -0
  480. package/src/util/archive.ts +17 -0
  481. package/src/util/color.ts +19 -0
  482. package/src/util/context.ts +25 -0
  483. package/src/util/data-url.ts +9 -0
  484. package/src/util/defer.ts +12 -0
  485. package/src/util/effect-http-client.ts +11 -0
  486. package/src/util/effect-zod.ts +98 -0
  487. package/src/util/error.ts +77 -0
  488. package/src/util/filesystem.ts +203 -0
  489. package/src/util/flock.ts +333 -0
  490. package/src/util/fn.ts +21 -0
  491. package/src/util/format.ts +20 -0
  492. package/src/util/git.ts +35 -0
  493. package/src/util/glob.ts +34 -0
  494. package/src/util/hash.ts +7 -0
  495. package/src/util/iife.ts +3 -0
  496. package/src/util/keybind.ts +103 -0
  497. package/src/util/lazy.ts +23 -0
  498. package/src/util/locale.ts +81 -0
  499. package/src/util/lock.ts +98 -0
  500. package/src/util/log.ts +182 -0
  501. package/src/util/network.ts +9 -0
  502. package/src/util/process.ts +172 -0
  503. package/src/util/queue.ts +32 -0
  504. package/src/util/record.ts +3 -0
  505. package/src/util/rpc.ts +66 -0
  506. package/src/util/schema.ts +53 -0
  507. package/src/util/scrap.ts +10 -0
  508. package/src/util/signal.ts +12 -0
  509. package/src/util/timeout.ts +14 -0
  510. package/src/util/token.ts +7 -0
  511. package/src/util/update-schema.ts +13 -0
  512. package/src/util/which.ts +14 -0
  513. package/src/util/wildcard.ts +59 -0
  514. package/src/worktree/index.ts +638 -0
  515. package/sst-env.d.ts +10 -0
  516. package/test/AGENTS.md +81 -0
  517. package/test/account/repo.test.ts +326 -0
  518. package/test/account/service.test.ts +282 -0
  519. package/test/acp/agent-interface.test.ts +51 -0
  520. package/test/acp/event-subscription.test.ts +685 -0
  521. package/test/agent/agent.test.ts +717 -0
  522. package/test/auth/auth.test.ts +58 -0
  523. package/test/bun.test.ts +53 -0
  524. package/test/bus/bus-effect.test.ts +164 -0
  525. package/test/bus/bus-integration.test.ts +87 -0
  526. package/test/bus/bus.test.ts +219 -0
  527. package/test/cli/account.test.ts +26 -0
  528. package/test/cli/cmd/tui/prompt-part.test.ts +47 -0
  529. package/test/cli/github-action.test.ts +198 -0
  530. package/test/cli/github-remote.test.ts +80 -0
  531. package/test/cli/import.test.ts +54 -0
  532. package/test/cli/plugin-auth-picker.test.ts +120 -0
  533. package/test/cli/tui/keybind-plugin.test.ts +90 -0
  534. package/test/cli/tui/plugin-add.test.ts +61 -0
  535. package/test/cli/tui/plugin-install.test.ts +95 -0
  536. package/test/cli/tui/plugin-lifecycle.test.ts +225 -0
  537. package/test/cli/tui/plugin-loader-entrypoint.test.ts +189 -0
  538. package/test/cli/tui/plugin-loader-pure.test.ts +71 -0
  539. package/test/cli/tui/plugin-loader.test.ts +563 -0
  540. package/test/cli/tui/plugin-toggle.test.ts +157 -0
  541. package/test/cli/tui/theme-store.test.ts +51 -0
  542. package/test/cli/tui/thread.test.ts +128 -0
  543. package/test/cli/tui/transcript.test.ts +322 -0
  544. package/test/config/agent-color.test.ts +71 -0
  545. package/test/config/config.test.ts +2187 -0
  546. package/test/config/fixtures/empty-frontmatter.md +4 -0
  547. package/test/config/fixtures/frontmatter.md +28 -0
  548. package/test/config/fixtures/markdown-header.md +11 -0
  549. package/test/config/fixtures/no-frontmatter.md +1 -0
  550. package/test/config/fixtures/weird-model-id.md +13 -0
  551. package/test/config/markdown.test.ts +228 -0
  552. package/test/config/tui.test.ts +667 -0
  553. package/test/control-plane/sse.test.ts +56 -0
  554. package/test/effect/cross-spawn-spawner.test.ts +402 -0
  555. package/test/effect/instance-state.test.ts +384 -0
  556. package/test/effect/run-service.test.ts +46 -0
  557. package/test/file/fsmonitor.test.ts +62 -0
  558. package/test/file/ignore.test.ts +10 -0
  559. package/test/file/index.test.ts +946 -0
  560. package/test/file/path-traversal.test.ts +198 -0
  561. package/test/file/ripgrep.test.ts +54 -0
  562. package/test/file/time.test.ts +354 -0
  563. package/test/file/watcher.test.ts +247 -0
  564. package/test/filesystem/filesystem.test.ts +319 -0
  565. package/test/fixture/db.ts +11 -0
  566. package/test/fixture/fixture.test.ts +26 -0
  567. package/test/fixture/fixture.ts +141 -0
  568. package/test/fixture/flock-worker.ts +72 -0
  569. package/test/fixture/lsp/fake-lsp-server.js +77 -0
  570. package/test/fixture/plug-worker.ts +93 -0
  571. package/test/fixture/plugin-meta-worker.ts +26 -0
  572. package/test/fixture/skills/agents-sdk/SKILL.md +152 -0
  573. package/test/fixture/skills/agents-sdk/references/callable.md +92 -0
  574. package/test/fixture/skills/cloudflare/SKILL.md +211 -0
  575. package/test/fixture/skills/index.json +6 -0
  576. package/test/fixture/tui-plugin.ts +335 -0
  577. package/test/fixture/tui-runtime.ts +34 -0
  578. package/test/format/format.test.ts +179 -0
  579. package/test/ide/ide.test.ts +82 -0
  580. package/test/installation/installation.test.ts +151 -0
  581. package/test/keybind.test.ts +421 -0
  582. package/test/lib/effect.ts +37 -0
  583. package/test/lib/filesystem.ts +10 -0
  584. package/test/lsp/client.test.ts +95 -0
  585. package/test/lsp/index.test.ts +55 -0
  586. package/test/lsp/launch.test.ts +22 -0
  587. package/test/lsp/lifecycle.test.ts +147 -0
  588. package/test/mcp/headers.test.ts +153 -0
  589. package/test/mcp/lifecycle.test.ts +750 -0
  590. package/test/mcp/oauth-auto-connect.test.ts +199 -0
  591. package/test/mcp/oauth-browser.test.ts +249 -0
  592. package/test/memory/abort-leak.test.ts +137 -0
  593. package/test/patch/patch.test.ts +348 -0
  594. package/test/permission/arity.test.ts +33 -0
  595. package/test/permission/next.test.ts +1148 -0
  596. package/test/permission-task.test.ts +323 -0
  597. package/test/plugin/auth-override.test.ts +74 -0
  598. package/test/plugin/codex.test.ts +123 -0
  599. package/test/plugin/install-concurrency.test.ts +134 -0
  600. package/test/plugin/install.test.ts +504 -0
  601. package/test/plugin/loader-shared.test.ts +625 -0
  602. package/test/plugin/meta.test.ts +137 -0
  603. package/test/plugin/trigger.test.ts +111 -0
  604. package/test/preload.ts +90 -0
  605. package/test/project/migrate-global.test.ts +140 -0
  606. package/test/project/project.test.ts +459 -0
  607. package/test/project/state.test.ts +115 -0
  608. package/test/project/vcs.test.ts +116 -0
  609. package/test/project/worktree-remove.test.ts +96 -0
  610. package/test/project/worktree.test.ts +173 -0
  611. package/test/provider/amazon-bedrock.test.ts +447 -0
  612. package/test/provider/copilot/convert-to-copilot-messages.test.ts +523 -0
  613. package/test/provider/copilot/copilot-chat-model.test.ts +592 -0
  614. package/test/provider/gitlab-duo.test.ts +412 -0
  615. package/test/provider/provider.test.ts +2284 -0
  616. package/test/provider/transform.test.ts +2758 -0
  617. package/test/pty/pty-output-isolation.test.ts +141 -0
  618. package/test/pty/pty-session.test.ts +92 -0
  619. package/test/question/question.test.ts +453 -0
  620. package/test/server/global-session-list.test.ts +89 -0
  621. package/test/server/project-init-git.test.ts +121 -0
  622. package/test/server/session-list.test.ts +90 -0
  623. package/test/server/session-messages.test.ts +132 -0
  624. package/test/server/session-select.test.ts +78 -0
  625. package/test/session/compaction.test.ts +1094 -0
  626. package/test/session/instruction.test.ts +170 -0
  627. package/test/session/llm.test.ts +882 -0
  628. package/test/session/message-v2.test.ts +957 -0
  629. package/test/session/messages-pagination.test.ts +115 -0
  630. package/test/session/processor-effect.test.ts +838 -0
  631. package/test/session/prompt.test.ts +518 -0
  632. package/test/session/retry.test.ts +232 -0
  633. package/test/session/revert-compact.test.ts +286 -0
  634. package/test/session/session.test.ts +142 -0
  635. package/test/session/structured-output-integration.test.ts +233 -0
  636. package/test/session/structured-output.test.ts +391 -0
  637. package/test/session/system.test.ts +59 -0
  638. package/test/share/share-next.test.ts +76 -0
  639. package/test/skill/discovery.test.ts +116 -0
  640. package/test/skill/skill.test.ts +392 -0
  641. package/test/snapshot/snapshot.test.ts +1235 -0
  642. package/test/storage/db.test.ts +14 -0
  643. package/test/storage/json-migration.test.ts +849 -0
  644. package/test/sync/index.test.ts +191 -0
  645. package/test/tool/__snapshots__/tool.test.ts.snap +9 -0
  646. package/test/tool/apply_patch.test.ts +567 -0
  647. package/test/tool/bash.test.ts +403 -0
  648. package/test/tool/edit.test.ts +681 -0
  649. package/test/tool/external-directory.test.ts +128 -0
  650. package/test/tool/fixtures/large-image.png +0 -0
  651. package/test/tool/fixtures/models-api.json +38413 -0
  652. package/test/tool/grep.test.ts +111 -0
  653. package/test/tool/question.test.ts +108 -0
  654. package/test/tool/read.test.ts +509 -0
  655. package/test/tool/registry.test.ts +126 -0
  656. package/test/tool/skill.test.ts +167 -0
  657. package/test/tool/task.test.ts +49 -0
  658. package/test/tool/truncation.test.ts +161 -0
  659. package/test/tool/webfetch.test.ts +101 -0
  660. package/test/tool/write.test.ts +353 -0
  661. package/test/util/data-url.test.ts +14 -0
  662. package/test/util/effect-zod.test.ts +61 -0
  663. package/test/util/error.test.ts +38 -0
  664. package/test/util/filesystem.test.ts +558 -0
  665. package/test/util/flock.test.ts +383 -0
  666. package/test/util/format.test.ts +59 -0
  667. package/test/util/glob.test.ts +164 -0
  668. package/test/util/iife.test.ts +36 -0
  669. package/test/util/lazy.test.ts +50 -0
  670. package/test/util/lock.test.ts +72 -0
  671. package/test/util/module.test.ts +59 -0
  672. package/test/util/process.test.ts +128 -0
  673. package/test/util/timeout.test.ts +21 -0
  674. package/test/util/which.test.ts +100 -0
  675. package/test/util/wildcard.test.ts +90 -0
  676. package/tsconfig.json +23 -0
@@ -0,0 +1,321 @@
1
+ import path from "path"
2
+ import os from "os"
3
+ import { Global } from "../global"
4
+ import { Filesystem } from "../util/filesystem"
5
+ import { Config } from "../config/config"
6
+ import { Instance } from "../project/instance"
7
+ import { Flag } from "@/flag/flag"
8
+ import { Log } from "../util/log"
9
+ import { Glob } from "../util/glob"
10
+ import type { MessageV2 } from "./message-v2"
11
+
12
+ const log = Log.create({ service: "instruction" })
13
+
14
+ const FILES = [
15
+ "AGENTS.md",
16
+ ...(Flag.OPENCODE_DISABLE_CLAUDE_CODE_PROMPT ? [] : ["CLAUDE.md"]),
17
+ ...(Flag.OPENCODE_DISABLE_CLAUDE_CODE_PROMPT ? [] : ["CLAUDE.local.md"]),
18
+ "CONTEXT.md", // deprecated
19
+ ]
20
+
21
+ function globalFiles() {
22
+ const files = []
23
+ if (Flag.OPENCODE_CONFIG_DIR) {
24
+ files.push(path.join(Flag.OPENCODE_CONFIG_DIR, "AGENTS.md"))
25
+ }
26
+ files.push(path.join(Global.Path.config, "AGENTS.md"))
27
+ if (!Flag.OPENCODE_DISABLE_CLAUDE_CODE_PROMPT) {
28
+ files.push(path.join(os.homedir(), ".claude", "CLAUDE.md"))
29
+ }
30
+ return files
31
+ }
32
+
33
+ /**
34
+ * Auto-memory: load MEMORY.md from the project's memory directory.
35
+ * Stored at ~/.claude/projects/<project-path-hash>/memory/MEMORY.md
36
+ * First 200 lines or 25KB loaded every session.
37
+ * Uses Instance.worktree (git root) so all subdirs share the same memory.
38
+ */
39
+ function memoryDir(): string {
40
+ // Check for custom directory in config (async not possible here, use env fallback)
41
+ const customDir = process.env.TOOLKODE_MEMORY_DIR
42
+ if (customDir) return customDir
43
+
44
+ const projectPath = Instance.worktree || Instance.directory || process.cwd()
45
+ const safe = projectPath.replace(/\//g, "-").replace(/^-/, "")
46
+ return path.join(os.homedir(), ".claude", "projects", safe, "memory")
47
+ }
48
+
49
+ async function loadAutoMemory(): Promise<string> {
50
+ const dir = memoryDir()
51
+ const memoryFile = path.join(dir, "MEMORY.md")
52
+
53
+ // ALWAYS return the path so agent knows where to write (even on first use)
54
+ const header = `Auto-memory directory: ${dir}\nAuto-memory file: ${memoryFile}`
55
+
56
+ try {
57
+ const content = await Filesystem.readText(memoryFile)
58
+ if (!content || !content.trim()) return header + "\n(empty)"
59
+ const lines = content.split("\n")
60
+ const limited = lines.slice(0, 200).join("\n")
61
+ const trimmed = limited.length > 25_000 ? limited.slice(0, 25_000) : limited
62
+ return header + "\n" + trimmed
63
+ } catch {
64
+ return header + "\n(no memory file yet)"
65
+ }
66
+ }
67
+
68
+ async function resolveRelative(instruction: string): Promise<string[]> {
69
+ if (!Flag.OPENCODE_DISABLE_PROJECT_CONFIG) {
70
+ return Filesystem.globUp(instruction, Instance.directory, Instance.worktree).catch(() => [])
71
+ }
72
+ if (!Flag.OPENCODE_CONFIG_DIR) {
73
+ log.warn(
74
+ `Skipping relative instruction "${instruction}" - no OPENCODE_CONFIG_DIR set while project config is disabled`,
75
+ )
76
+ return []
77
+ }
78
+ return Filesystem.globUp(instruction, Flag.OPENCODE_CONFIG_DIR, Flag.OPENCODE_CONFIG_DIR).catch(() => [])
79
+ }
80
+
81
+ /**
82
+ * Expand @import syntax in CLAUDE.md files.
83
+ * Supports @path/to/file and @~/path. Max depth 5.
84
+ */
85
+ async function expandImports(content: string, baseDir: string, depth: number): Promise<string> {
86
+ if (depth >= 5) return content
87
+ const lines = content.split("\n")
88
+ const result: string[] = []
89
+
90
+ for (const line of lines) {
91
+ // Match @path references (not inside code blocks)
92
+ const match = line.match(/(?:^|\s)@(~?[\/\w.\-]+\.md)/)
93
+ if (match) {
94
+ let importPath = match[1]
95
+ if (importPath.startsWith("~/")) {
96
+ importPath = path.join(os.homedir(), importPath.slice(2))
97
+ } else if (!path.isAbsolute(importPath)) {
98
+ importPath = path.join(baseDir, importPath)
99
+ }
100
+ try {
101
+ const imported = await Filesystem.readText(importPath)
102
+ if (imported) {
103
+ const expanded = await expandImports(imported, path.dirname(importPath), depth + 1)
104
+ result.push(`<!-- Imported from: ${importPath} -->`)
105
+ result.push(expanded)
106
+ continue
107
+ }
108
+ } catch {}
109
+ }
110
+ result.push(line)
111
+ }
112
+
113
+ return result.join("\n")
114
+ }
115
+
116
+ export namespace InstructionPrompt {
117
+ const state = Instance.state(() => {
118
+ return {
119
+ claims: new Map<string, Set<string>>(),
120
+ }
121
+ })
122
+
123
+ function isClaimed(messageID: string, filepath: string) {
124
+ const claimed = state().claims.get(messageID)
125
+ if (!claimed) return false
126
+ return claimed.has(filepath)
127
+ }
128
+
129
+ function claim(messageID: string, filepath: string) {
130
+ const current = state()
131
+ let claimed = current.claims.get(messageID)
132
+ if (!claimed) {
133
+ claimed = new Set()
134
+ current.claims.set(messageID, claimed)
135
+ }
136
+ claimed.add(filepath)
137
+ }
138
+
139
+ export function clear(messageID: string) {
140
+ state().claims.delete(messageID)
141
+ }
142
+
143
+ export async function systemPaths() {
144
+ const config = await Config.get()
145
+ const paths = new Set<string>()
146
+
147
+ if (!Flag.OPENCODE_DISABLE_PROJECT_CONFIG) {
148
+ for (const file of FILES) {
149
+ const matches = await Filesystem.findUp(file, Instance.directory, Instance.worktree)
150
+ if (matches.length > 0) {
151
+ matches.forEach((p) => {
152
+ paths.add(path.resolve(p))
153
+ })
154
+ break
155
+ }
156
+ }
157
+
158
+ // Load .claude/rules/*.md (path-scoped rules)
159
+ const rulesDir = path.join(Instance.worktree || Instance.directory, ".claude", "rules")
160
+ try {
161
+ const ruleFiles = await Glob.scan("**/*.md", { cwd: rulesDir, absolute: true })
162
+ for (const ruleFile of ruleFiles) {
163
+ paths.add(path.resolve(ruleFile))
164
+ }
165
+ } catch {}
166
+
167
+ // Also check .toolkode/rules/*.md
168
+ const tkRulesDir = path.join(Instance.worktree || Instance.directory, ".toolkode", "rules")
169
+ try {
170
+ const tkRuleFiles = await Glob.scan("**/*.md", { cwd: tkRulesDir, absolute: true })
171
+ for (const ruleFile of tkRuleFiles) {
172
+ paths.add(path.resolve(ruleFile))
173
+ }
174
+ } catch {}
175
+ }
176
+
177
+ for (const file of globalFiles()) {
178
+ if (await Filesystem.exists(file)) {
179
+ paths.add(path.resolve(file))
180
+ break
181
+ }
182
+ }
183
+
184
+ // Load user-level rules: ~/.claude/rules/*.md
185
+ const userRulesDir = path.join(os.homedir(), ".claude", "rules")
186
+ try {
187
+ const userRuleFiles = await Glob.scan("**/*.md", { cwd: userRulesDir, absolute: true })
188
+ for (const ruleFile of userRuleFiles) {
189
+ paths.add(path.resolve(ruleFile))
190
+ }
191
+ } catch {}
192
+
193
+ if (config.instructions) {
194
+ for (let instruction of config.instructions) {
195
+ if (instruction.startsWith("https://") || instruction.startsWith("http://")) continue
196
+ if (instruction.startsWith("~/")) {
197
+ instruction = path.join(os.homedir(), instruction.slice(2))
198
+ }
199
+ const matches = path.isAbsolute(instruction)
200
+ ? await Glob.scan(path.basename(instruction), {
201
+ cwd: path.dirname(instruction),
202
+ absolute: true,
203
+ include: "file",
204
+ }).catch(() => [])
205
+ : await resolveRelative(instruction)
206
+ matches.forEach((p) => {
207
+ paths.add(path.resolve(p))
208
+ })
209
+ }
210
+ }
211
+
212
+ return paths
213
+ }
214
+
215
+ export async function system() {
216
+ const config = await Config.get()
217
+ const paths = await systemPaths()
218
+
219
+ // Filter out excluded paths (claudeMdExcludes setting)
220
+ const excludes: string[] = (config as any).claudeMdExcludes ?? []
221
+ const filteredPaths = Array.from(paths).filter((p) => {
222
+ if (excludes.length === 0) return true
223
+ const abs = path.resolve(p)
224
+ return !excludes.some((pattern) => {
225
+ if (pattern.includes("*")) {
226
+ // Simple glob matching
227
+ const regex = new RegExp("^" + pattern.replace(/\*\*/g, ".*").replace(/\*/g, "[^/]*") + "$")
228
+ return regex.test(abs)
229
+ }
230
+ return abs.includes(pattern)
231
+ })
232
+ })
233
+
234
+ const files = filteredPaths.map(async (p) => {
235
+ let content = await Filesystem.readText(p).catch(() => "")
236
+ if (!content) return ""
237
+ // Expand @import syntax: @path/to/file or @~/path
238
+ content = await expandImports(content, path.dirname(p), 0)
239
+ return "Instructions from: " + p + "\n" + content
240
+ })
241
+
242
+ const urls: string[] = []
243
+ if (config.instructions) {
244
+ for (const instruction of config.instructions) {
245
+ if (instruction.startsWith("https://") || instruction.startsWith("http://")) {
246
+ urls.push(instruction)
247
+ }
248
+ }
249
+ }
250
+ const fetches = urls.map((url) =>
251
+ fetch(url, { signal: AbortSignal.timeout(5000) })
252
+ .then((res) => (res.ok ? res.text() : ""))
253
+ .catch(() => "")
254
+ .then((x) => (x ? "Instructions from: " + url + "\n" + x : "")),
255
+ )
256
+
257
+ // Load auto-memory (if enabled — check autoMemoryEnabled setting)
258
+ const autoMemoryEnabled = (config as any).autoMemoryEnabled !== false
259
+ const memory = autoMemoryEnabled
260
+ ? loadAutoMemory().then((content) =>
261
+ content ? `Auto-memory from: ${path.join(memoryDir(), "MEMORY.md")}\n${content}` : "",
262
+ )
263
+ : Promise.resolve("")
264
+
265
+ return Promise.all([...files, ...fetches, memory]).then((result) => result.filter(Boolean))
266
+ }
267
+
268
+ /** Get the auto-memory directory for the current project */
269
+ export function getMemoryDir(): string {
270
+ return memoryDir()
271
+ }
272
+
273
+ export function loaded(messages: MessageV2.WithParts[]) {
274
+ const paths = new Set<string>()
275
+ for (const msg of messages) {
276
+ for (const part of msg.parts) {
277
+ if (part.type === "tool" && part.tool === "read" && part.state.status === "completed") {
278
+ if (part.state.time.compacted) continue
279
+ const loaded = part.state.metadata?.loaded
280
+ if (!loaded || !Array.isArray(loaded)) continue
281
+ for (const p of loaded) {
282
+ if (typeof p === "string") paths.add(p)
283
+ }
284
+ }
285
+ }
286
+ }
287
+ return paths
288
+ }
289
+
290
+ export async function find(dir: string) {
291
+ for (const file of FILES) {
292
+ const filepath = path.resolve(path.join(dir, file))
293
+ if (await Filesystem.exists(filepath)) return filepath
294
+ }
295
+ }
296
+
297
+ export async function resolve(messages: MessageV2.WithParts[], filepath: string, messageID: string) {
298
+ const system = await systemPaths()
299
+ const already = loaded(messages)
300
+ const results: { filepath: string; content: string }[] = []
301
+
302
+ const target = path.resolve(filepath)
303
+ let current = path.dirname(target)
304
+ const root = path.resolve(Instance.directory)
305
+
306
+ while (current.startsWith(root) && current !== root) {
307
+ const found = await find(current)
308
+
309
+ if (found && found !== target && !system.has(found) && !already.has(found) && !isClaimed(messageID, found)) {
310
+ claim(messageID, found)
311
+ const content = await Filesystem.readText(found).catch(() => undefined)
312
+ if (content) {
313
+ results.push({ filepath: found, content: "Instructions from: " + found + "\n" + content })
314
+ }
315
+ }
316
+ current = path.dirname(current)
317
+ }
318
+
319
+ return results
320
+ }
321
+ }
@@ -0,0 +1,341 @@
1
+ import { Provider } from "@/provider/provider"
2
+ import { Log } from "@/util/log"
3
+ import { Effect, Layer, ServiceMap } from "effect"
4
+ import * as Stream from "effect/Stream"
5
+ import { streamText, wrapLanguageModel, type ModelMessage, type Tool, tool, jsonSchema } from "ai"
6
+ import { mergeDeep, pipe } from "remeda"
7
+ import { GitLabWorkflowLanguageModel } from "gitlab-ai-provider"
8
+ import { ProviderTransform } from "@/provider/transform"
9
+ import { Config } from "@/config/config"
10
+ import { Instance } from "@/project/instance"
11
+ import type { Agent } from "@/agent/agent"
12
+ import type { MessageV2 } from "./message-v2"
13
+ import { Plugin } from "@/plugin"
14
+ import { SystemPrompt } from "./system"
15
+ import { Flag } from "@/flag/flag"
16
+ import { Permission } from "@/permission"
17
+ import { Auth } from "@/auth"
18
+ import { Installation } from "@/installation"
19
+
20
+ export namespace LLM {
21
+ const log = Log.create({ service: "llm" })
22
+ export const OUTPUT_TOKEN_MAX = ProviderTransform.OUTPUT_TOKEN_MAX
23
+
24
+ export type StreamInput = {
25
+ user: MessageV2.User
26
+ sessionID: string
27
+ model: Provider.Model
28
+ agent: Agent.Info
29
+ permission?: Permission.Ruleset
30
+ system: string[]
31
+ abort: AbortSignal
32
+ messages: ModelMessage[]
33
+ small?: boolean
34
+ tools: Record<string, Tool>
35
+ retries?: number
36
+ toolChoice?: "auto" | "required" | "none"
37
+ }
38
+
39
+ export type Event = Awaited<ReturnType<typeof stream>>["fullStream"] extends AsyncIterable<infer T> ? T : never
40
+
41
+ export interface Interface {
42
+ readonly stream: (input: StreamInput) => Stream.Stream<Event, unknown>
43
+ }
44
+
45
+ export class Service extends ServiceMap.Service<Service, Interface>()("@opencode/LLM") {}
46
+
47
+ export const layer = Layer.effect(
48
+ Service,
49
+ Effect.gen(function* () {
50
+ return Service.of({
51
+ stream(input) {
52
+ return Stream.unwrap(
53
+ Effect.promise(() => LLM.stream(input)).pipe(
54
+ Effect.map((result) =>
55
+ Stream.fromAsyncIterable(result.fullStream, (err) => err).pipe(
56
+ Stream.mapEffect((event) => Effect.succeed(event)),
57
+ ),
58
+ ),
59
+ ),
60
+ )
61
+ },
62
+ })
63
+ }),
64
+ )
65
+
66
+ export const defaultLayer = layer
67
+
68
+ export async function stream(input: StreamInput) {
69
+ const l = log
70
+ .clone()
71
+ .tag("providerID", input.model.providerID)
72
+ .tag("modelID", input.model.id)
73
+ .tag("sessionID", input.sessionID)
74
+ .tag("small", (input.small ?? false).toString())
75
+ .tag("agent", input.agent.name)
76
+ .tag("mode", input.agent.mode)
77
+ l.info("stream", {
78
+ modelID: input.model.id,
79
+ providerID: input.model.providerID,
80
+ })
81
+ const [language, cfg, provider, auth] = await Promise.all([
82
+ Provider.getLanguage(input.model),
83
+ Config.get(),
84
+ Provider.getProvider(input.model.providerID),
85
+ Auth.get(input.model.providerID),
86
+ ])
87
+ // TODO: move this to a proper hook
88
+ const isOpenaiOauth = provider.id === "openai" && auth?.type === "oauth"
89
+
90
+ const system: string[] = []
91
+ system.push(
92
+ [
93
+ // use agent prompt otherwise provider prompt
94
+ ...(input.agent.prompt ? [input.agent.prompt] : SystemPrompt.provider(input.model)),
95
+ // any custom prompt passed into this call
96
+ ...input.system,
97
+ // any custom prompt from last user message
98
+ ...(input.user.system ? [input.user.system] : []),
99
+ ]
100
+ .filter((x) => x)
101
+ .join("\n"),
102
+ )
103
+
104
+ const header = system[0]
105
+ await Plugin.trigger(
106
+ "experimental.chat.system.transform",
107
+ { sessionID: input.sessionID, model: input.model },
108
+ { system },
109
+ )
110
+ // rejoin to maintain 2-part structure for caching if header unchanged
111
+ if (system.length > 2 && system[0] === header) {
112
+ const rest = system.slice(1)
113
+ system.length = 0
114
+ system.push(header, rest.join("\n"))
115
+ }
116
+
117
+ const variant =
118
+ !input.small && input.model.variants && input.user.variant ? input.model.variants[input.user.variant] : {}
119
+ const base = input.small
120
+ ? ProviderTransform.smallOptions(input.model)
121
+ : ProviderTransform.options({
122
+ model: input.model,
123
+ sessionID: input.sessionID,
124
+ providerOptions: provider.options,
125
+ })
126
+ const options: Record<string, any> = pipe(
127
+ base,
128
+ mergeDeep(input.model.options),
129
+ mergeDeep(input.agent.options),
130
+ mergeDeep(variant),
131
+ )
132
+ if (isOpenaiOauth) {
133
+ options.instructions = system.join("\n")
134
+ }
135
+
136
+ const isWorkflow = language instanceof GitLabWorkflowLanguageModel
137
+ const messages = isOpenaiOauth
138
+ ? input.messages
139
+ : isWorkflow
140
+ ? input.messages
141
+ : [
142
+ ...system.map(
143
+ (x): ModelMessage => ({
144
+ role: "system",
145
+ content: x,
146
+ }),
147
+ ),
148
+ ...input.messages,
149
+ ]
150
+
151
+ const params = await Plugin.trigger(
152
+ "chat.params",
153
+ {
154
+ sessionID: input.sessionID,
155
+ agent: input.agent,
156
+ model: input.model,
157
+ provider,
158
+ message: input.user,
159
+ },
160
+ {
161
+ temperature: input.model.capabilities.temperature
162
+ ? (input.agent.temperature ?? ProviderTransform.temperature(input.model))
163
+ : undefined,
164
+ topP: input.agent.topP ?? ProviderTransform.topP(input.model),
165
+ topK: ProviderTransform.topK(input.model),
166
+ options,
167
+ },
168
+ )
169
+
170
+ const { headers } = await Plugin.trigger(
171
+ "chat.headers",
172
+ {
173
+ sessionID: input.sessionID,
174
+ agent: input.agent,
175
+ model: input.model,
176
+ provider,
177
+ message: input.user,
178
+ },
179
+ {
180
+ headers: {},
181
+ },
182
+ )
183
+
184
+ const maxOutputTokens =
185
+ isOpenaiOauth || provider.id.includes("github-copilot")
186
+ ? undefined
187
+ : ProviderTransform.maxOutputTokens(input.model)
188
+
189
+ const tools = await resolveTools(input)
190
+
191
+ // LiteLLM and some Anthropic proxies require the tools parameter to be present
192
+ // when message history contains tool calls, even if no tools are being used.
193
+ // Add a dummy tool that is never called to satisfy this validation.
194
+ // This is enabled for:
195
+ // 1. Providers with "litellm" in their ID or API ID (auto-detected)
196
+ // 2. Providers with explicit "litellmProxy: true" option (opt-in for custom gateways)
197
+ const isLiteLLMProxy =
198
+ provider.options?.["litellmProxy"] === true ||
199
+ input.model.providerID.toLowerCase().includes("litellm") ||
200
+ input.model.api.id.toLowerCase().includes("litellm")
201
+
202
+ if (isLiteLLMProxy && Object.keys(tools).length === 0 && hasToolCalls(input.messages)) {
203
+ tools["_noop"] = tool({
204
+ description:
205
+ "Placeholder for LiteLLM/Anthropic proxy compatibility - required when message history contains tool calls but no active tools are needed",
206
+ inputSchema: jsonSchema({ type: "object", properties: {} }),
207
+ execute: async () => ({ output: "", title: "", metadata: {} }),
208
+ })
209
+ }
210
+
211
+ // Wire up toolExecutor for DWS workflow models so that tool calls
212
+ // from the workflow service are executed via opencode's tool system
213
+ // and results sent back over the WebSocket.
214
+ if (language instanceof GitLabWorkflowLanguageModel) {
215
+ const workflowModel = language
216
+ workflowModel.systemPrompt = system.join("\n")
217
+ workflowModel.toolExecutor = async (toolName, argsJson, _requestID) => {
218
+ const t = tools[toolName]
219
+ if (!t || !t.execute) {
220
+ return { result: "", error: `Unknown tool: ${toolName}` }
221
+ }
222
+ try {
223
+ const result = await t.execute!(JSON.parse(argsJson), {
224
+ toolCallId: _requestID,
225
+ messages: input.messages,
226
+ abortSignal: input.abort,
227
+ })
228
+ const output = typeof result === "string" ? result : (result?.output ?? JSON.stringify(result))
229
+ return {
230
+ result: output,
231
+ metadata: typeof result === "object" ? result?.metadata : undefined,
232
+ title: typeof result === "object" ? result?.title : undefined,
233
+ }
234
+ } catch (e: any) {
235
+ return { result: "", error: e.message ?? String(e) }
236
+ }
237
+ }
238
+ }
239
+
240
+ return streamText({
241
+ onError(error) {
242
+ l.error("stream error", {
243
+ error,
244
+ })
245
+ },
246
+ async experimental_repairToolCall(failed) {
247
+ const lower = failed.toolCall.toolName.toLowerCase()
248
+ if (lower !== failed.toolCall.toolName && tools[lower]) {
249
+ l.info("repairing tool call", {
250
+ tool: failed.toolCall.toolName,
251
+ repaired: lower,
252
+ })
253
+ return {
254
+ ...failed.toolCall,
255
+ toolName: lower,
256
+ }
257
+ }
258
+ return {
259
+ ...failed.toolCall,
260
+ input: JSON.stringify({
261
+ tool: failed.toolCall.toolName,
262
+ error: failed.error.message,
263
+ }),
264
+ toolName: "invalid",
265
+ }
266
+ },
267
+ temperature: params.temperature,
268
+ topP: params.topP,
269
+ topK: params.topK,
270
+ providerOptions: ProviderTransform.providerOptions(input.model, params.options),
271
+ activeTools: Object.keys(tools).filter((x) => x !== "invalid"),
272
+ tools,
273
+ toolChoice: input.toolChoice,
274
+ maxOutputTokens,
275
+ abortSignal: input.abort,
276
+ headers: {
277
+ ...(input.model.providerID.startsWith("opencode")
278
+ ? {
279
+ "x-opencode-project": Instance.project.id,
280
+ "x-opencode-session": input.sessionID,
281
+ "x-opencode-request": input.user.id,
282
+ "x-opencode-client": Flag.OPENCODE_CLIENT,
283
+ }
284
+ : {
285
+ "User-Agent": `opencode/${Installation.VERSION}`,
286
+ }),
287
+ ...input.model.headers,
288
+ ...headers,
289
+ },
290
+ maxRetries: input.retries ?? 0,
291
+ messages,
292
+ model: wrapLanguageModel({
293
+ model: language,
294
+ middleware: [
295
+ {
296
+ specificationVersion: "v3" as const,
297
+ async transformParams(args) {
298
+ if (args.type === "stream") {
299
+ // @ts-expect-error
300
+ args.params.prompt = ProviderTransform.message(args.params.prompt, input.model, options)
301
+ }
302
+ return args.params
303
+ },
304
+ },
305
+ ],
306
+ }),
307
+ experimental_telemetry: {
308
+ isEnabled: cfg.experimental?.openTelemetry,
309
+ metadata: {
310
+ userId: cfg.username ?? "unknown",
311
+ sessionId: input.sessionID,
312
+ },
313
+ },
314
+ })
315
+ }
316
+
317
+ async function resolveTools(input: Pick<StreamInput, "tools" | "agent" | "permission" | "user">) {
318
+ const disabled = Permission.disabled(
319
+ Object.keys(input.tools),
320
+ Permission.merge(input.agent.permission, input.permission ?? []),
321
+ )
322
+ for (const tool of Object.keys(input.tools)) {
323
+ if (input.user.tools?.[tool] === false || disabled.has(tool)) {
324
+ delete input.tools[tool]
325
+ }
326
+ }
327
+ return input.tools
328
+ }
329
+
330
+ // Check if messages contain any tool-call content
331
+ // Used to determine if a dummy tool should be added for LiteLLM proxy compatibility
332
+ export function hasToolCalls(messages: ModelMessage[]): boolean {
333
+ for (const msg of messages) {
334
+ if (!Array.isArray(msg.content)) continue
335
+ for (const part of msg.content) {
336
+ if (part.type === "tool-call" || part.type === "tool-result") return true
337
+ }
338
+ }
339
+ return false
340
+ }
341
+ }