rird 1.0.200

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 (350) hide show
  1. package/AGENTS.md +27 -0
  2. package/Dockerfile +18 -0
  3. package/README.md +15 -0
  4. package/bin/opencode +336 -0
  5. package/bin/pty-wrapper.js +285 -0
  6. package/bunfig.toml +4 -0
  7. package/facebook_ads_library.png +0 -0
  8. package/nul`nif +0 -0
  9. package/package.json +111 -0
  10. package/parsers-config.ts +239 -0
  11. package/rird-1.0.199.tgz +0 -0
  12. package/script/build-windows.ts +54 -0
  13. package/script/build.ts +167 -0
  14. package/script/postinstall.mjs +544 -0
  15. package/script/publish-registries.ts +187 -0
  16. package/script/publish.ts +72 -0
  17. package/script/schema.ts +47 -0
  18. package/src/acp/README.md +164 -0
  19. package/src/acp/agent.ts +1063 -0
  20. package/src/acp/session.ts +101 -0
  21. package/src/acp/types.ts +22 -0
  22. package/src/agent/agent.ts +367 -0
  23. package/src/agent/generate.txt +75 -0
  24. package/src/agent/prompt/compaction.txt +12 -0
  25. package/src/agent/prompt/explore.txt +18 -0
  26. package/src/agent/prompt/summary.txt +10 -0
  27. package/src/agent/prompt/title.txt +36 -0
  28. package/src/auth/index.ts +70 -0
  29. package/src/bun/index.ts +114 -0
  30. package/src/bus/bus-event.ts +43 -0
  31. package/src/bus/global.ts +10 -0
  32. package/src/bus/index.ts +105 -0
  33. package/src/cli/bootstrap.ts +17 -0
  34. package/src/cli/cmd/acp.ts +88 -0
  35. package/src/cli/cmd/agent.ts +256 -0
  36. package/src/cli/cmd/auth.ts +391 -0
  37. package/src/cli/cmd/cmd.ts +7 -0
  38. package/src/cli/cmd/debug/config.ts +15 -0
  39. package/src/cli/cmd/debug/file.ts +91 -0
  40. package/src/cli/cmd/debug/index.ts +43 -0
  41. package/src/cli/cmd/debug/lsp.ts +48 -0
  42. package/src/cli/cmd/debug/ripgrep.ts +83 -0
  43. package/src/cli/cmd/debug/scrap.ts +15 -0
  44. package/src/cli/cmd/debug/skill.ts +15 -0
  45. package/src/cli/cmd/debug/snapshot.ts +48 -0
  46. package/src/cli/cmd/export.ts +88 -0
  47. package/src/cli/cmd/generate.ts +38 -0
  48. package/src/cli/cmd/github.ts +1400 -0
  49. package/src/cli/cmd/import.ts +98 -0
  50. package/src/cli/cmd/mcp.ts +654 -0
  51. package/src/cli/cmd/models.ts +77 -0
  52. package/src/cli/cmd/pr.ts +112 -0
  53. package/src/cli/cmd/run.ts +368 -0
  54. package/src/cli/cmd/serve.ts +31 -0
  55. package/src/cli/cmd/session.ts +106 -0
  56. package/src/cli/cmd/stats.ts +298 -0
  57. package/src/cli/cmd/tui/app.tsx +696 -0
  58. package/src/cli/cmd/tui/attach.ts +30 -0
  59. package/src/cli/cmd/tui/component/border.tsx +21 -0
  60. package/src/cli/cmd/tui/component/dialog-agent.tsx +31 -0
  61. package/src/cli/cmd/tui/component/dialog-command.tsx +124 -0
  62. package/src/cli/cmd/tui/component/dialog-mcp.tsx +86 -0
  63. package/src/cli/cmd/tui/component/dialog-model.tsx +245 -0
  64. package/src/cli/cmd/tui/component/dialog-provider.tsx +224 -0
  65. package/src/cli/cmd/tui/component/dialog-session-list.tsx +102 -0
  66. package/src/cli/cmd/tui/component/dialog-session-rename.tsx +31 -0
  67. package/src/cli/cmd/tui/component/dialog-stash.tsx +86 -0
  68. package/src/cli/cmd/tui/component/dialog-status.tsx +162 -0
  69. package/src/cli/cmd/tui/component/dialog-tag.tsx +44 -0
  70. package/src/cli/cmd/tui/component/dialog-theme-list.tsx +50 -0
  71. package/src/cli/cmd/tui/component/did-you-know.tsx +85 -0
  72. package/src/cli/cmd/tui/component/logo.tsx +35 -0
  73. package/src/cli/cmd/tui/component/prompt/autocomplete.tsx +574 -0
  74. package/src/cli/cmd/tui/component/prompt/history.tsx +108 -0
  75. package/src/cli/cmd/tui/component/prompt/index.tsx +1090 -0
  76. package/src/cli/cmd/tui/component/prompt/stash.tsx +101 -0
  77. package/src/cli/cmd/tui/component/tips.ts +27 -0
  78. package/src/cli/cmd/tui/component/todo-item.tsx +32 -0
  79. package/src/cli/cmd/tui/context/args.tsx +14 -0
  80. package/src/cli/cmd/tui/context/directory.ts +13 -0
  81. package/src/cli/cmd/tui/context/exit.tsx +23 -0
  82. package/src/cli/cmd/tui/context/helper.tsx +25 -0
  83. package/src/cli/cmd/tui/context/keybind.tsx +101 -0
  84. package/src/cli/cmd/tui/context/kv.tsx +49 -0
  85. package/src/cli/cmd/tui/context/local.tsx +354 -0
  86. package/src/cli/cmd/tui/context/prompt.tsx +18 -0
  87. package/src/cli/cmd/tui/context/route.tsx +46 -0
  88. package/src/cli/cmd/tui/context/sdk.tsx +74 -0
  89. package/src/cli/cmd/tui/context/sync.tsx +372 -0
  90. package/src/cli/cmd/tui/context/theme/aura.json +69 -0
  91. package/src/cli/cmd/tui/context/theme/ayu.json +80 -0
  92. package/src/cli/cmd/tui/context/theme/catppuccin-frappe.json +233 -0
  93. package/src/cli/cmd/tui/context/theme/catppuccin-macchiato.json +233 -0
  94. package/src/cli/cmd/tui/context/theme/catppuccin.json +112 -0
  95. package/src/cli/cmd/tui/context/theme/cobalt2.json +228 -0
  96. package/src/cli/cmd/tui/context/theme/cursor.json +249 -0
  97. package/src/cli/cmd/tui/context/theme/dracula.json +219 -0
  98. package/src/cli/cmd/tui/context/theme/everforest.json +241 -0
  99. package/src/cli/cmd/tui/context/theme/flexoki.json +237 -0
  100. package/src/cli/cmd/tui/context/theme/github.json +233 -0
  101. package/src/cli/cmd/tui/context/theme/gruvbox.json +95 -0
  102. package/src/cli/cmd/tui/context/theme/kanagawa.json +77 -0
  103. package/src/cli/cmd/tui/context/theme/lucent-orng.json +227 -0
  104. package/src/cli/cmd/tui/context/theme/material.json +235 -0
  105. package/src/cli/cmd/tui/context/theme/matrix.json +77 -0
  106. package/src/cli/cmd/tui/context/theme/mercury.json +252 -0
  107. package/src/cli/cmd/tui/context/theme/monokai.json +221 -0
  108. package/src/cli/cmd/tui/context/theme/nightowl.json +221 -0
  109. package/src/cli/cmd/tui/context/theme/nord.json +223 -0
  110. package/src/cli/cmd/tui/context/theme/one-dark.json +84 -0
  111. package/src/cli/cmd/tui/context/theme/orng.json +245 -0
  112. package/src/cli/cmd/tui/context/theme/palenight.json +222 -0
  113. package/src/cli/cmd/tui/context/theme/rird.json +245 -0
  114. package/src/cli/cmd/tui/context/theme/rosepine.json +234 -0
  115. package/src/cli/cmd/tui/context/theme/solarized.json +223 -0
  116. package/src/cli/cmd/tui/context/theme/synthwave84.json +226 -0
  117. package/src/cli/cmd/tui/context/theme/tokyonight.json +243 -0
  118. package/src/cli/cmd/tui/context/theme/vercel.json +245 -0
  119. package/src/cli/cmd/tui/context/theme/vesper.json +218 -0
  120. package/src/cli/cmd/tui/context/theme/zenburn.json +223 -0
  121. package/src/cli/cmd/tui/context/theme.tsx +1109 -0
  122. package/src/cli/cmd/tui/event.ts +40 -0
  123. package/src/cli/cmd/tui/routes/home.tsx +138 -0
  124. package/src/cli/cmd/tui/routes/session/dialog-fork-from-timeline.tsx +64 -0
  125. package/src/cli/cmd/tui/routes/session/dialog-message.tsx +109 -0
  126. package/src/cli/cmd/tui/routes/session/dialog-subagent.tsx +26 -0
  127. package/src/cli/cmd/tui/routes/session/dialog-timeline.tsx +47 -0
  128. package/src/cli/cmd/tui/routes/session/footer.tsx +88 -0
  129. package/src/cli/cmd/tui/routes/session/header.tsx +125 -0
  130. package/src/cli/cmd/tui/routes/session/index.tsx +1864 -0
  131. package/src/cli/cmd/tui/routes/session/sidebar.tsx +318 -0
  132. package/src/cli/cmd/tui/spawn.ts +60 -0
  133. package/src/cli/cmd/tui/thread.ts +142 -0
  134. package/src/cli/cmd/tui/ui/dialog-alert.tsx +57 -0
  135. package/src/cli/cmd/tui/ui/dialog-confirm.tsx +83 -0
  136. package/src/cli/cmd/tui/ui/dialog-help.tsx +38 -0
  137. package/src/cli/cmd/tui/ui/dialog-prompt.tsx +77 -0
  138. package/src/cli/cmd/tui/ui/dialog-select.tsx +332 -0
  139. package/src/cli/cmd/tui/ui/dialog.tsx +170 -0
  140. package/src/cli/cmd/tui/ui/spinner.ts +368 -0
  141. package/src/cli/cmd/tui/ui/toast.tsx +100 -0
  142. package/src/cli/cmd/tui/util/clipboard.ts +127 -0
  143. package/src/cli/cmd/tui/util/editor.ts +32 -0
  144. package/src/cli/cmd/tui/util/terminal.ts +114 -0
  145. package/src/cli/cmd/tui/worker.ts +63 -0
  146. package/src/cli/cmd/uninstall.ts +344 -0
  147. package/src/cli/cmd/upgrade.ts +100 -0
  148. package/src/cli/cmd/web.ts +84 -0
  149. package/src/cli/error.ts +56 -0
  150. package/src/cli/ui.ts +84 -0
  151. package/src/cli/upgrade.ts +25 -0
  152. package/src/command/index.ts +80 -0
  153. package/src/command/template/initialize.txt +10 -0
  154. package/src/command/template/review.txt +97 -0
  155. package/src/config/config.ts +995 -0
  156. package/src/config/markdown.ts +41 -0
  157. package/src/env/index.ts +26 -0
  158. package/src/file/ignore.ts +83 -0
  159. package/src/file/index.ts +328 -0
  160. package/src/file/ripgrep.ts +393 -0
  161. package/src/file/time.ts +64 -0
  162. package/src/file/watcher.ts +103 -0
  163. package/src/flag/flag.ts +46 -0
  164. package/src/format/formatter.ts +315 -0
  165. package/src/format/index.ts +137 -0
  166. package/src/global/index.ts +52 -0
  167. package/src/id/id.ts +73 -0
  168. package/src/ide/index.ts +76 -0
  169. package/src/index.ts +240 -0
  170. package/src/installation/index.ts +239 -0
  171. package/src/lsp/client.ts +229 -0
  172. package/src/lsp/index.ts +485 -0
  173. package/src/lsp/language.ts +116 -0
  174. package/src/lsp/server.ts +1895 -0
  175. package/src/mcp/auth.ts +135 -0
  176. package/src/mcp/index.ts +690 -0
  177. package/src/mcp/oauth-callback.ts +200 -0
  178. package/src/mcp/oauth-provider.ts +154 -0
  179. package/src/patch/index.ts +622 -0
  180. package/src/permission/index.ts +199 -0
  181. package/src/plugin/index.ts +91 -0
  182. package/src/project/bootstrap.ts +31 -0
  183. package/src/project/instance.ts +78 -0
  184. package/src/project/project.ts +221 -0
  185. package/src/project/state.ts +65 -0
  186. package/src/project/vcs.ts +76 -0
  187. package/src/provider/auth.ts +143 -0
  188. package/src/provider/models-macro.ts +11 -0
  189. package/src/provider/models.ts +106 -0
  190. package/src/provider/provider.ts +1071 -0
  191. package/src/provider/sdk/openai-compatible/src/README.md +5 -0
  192. package/src/provider/sdk/openai-compatible/src/index.ts +2 -0
  193. package/src/provider/sdk/openai-compatible/src/openai-compatible-provider.ts +100 -0
  194. package/src/provider/sdk/openai-compatible/src/responses/convert-to-openai-responses-input.ts +303 -0
  195. package/src/provider/sdk/openai-compatible/src/responses/map-openai-responses-finish-reason.ts +22 -0
  196. package/src/provider/sdk/openai-compatible/src/responses/openai-config.ts +18 -0
  197. package/src/provider/sdk/openai-compatible/src/responses/openai-error.ts +22 -0
  198. package/src/provider/sdk/openai-compatible/src/responses/openai-responses-api-types.ts +207 -0
  199. package/src/provider/sdk/openai-compatible/src/responses/openai-responses-language-model.ts +1713 -0
  200. package/src/provider/sdk/openai-compatible/src/responses/openai-responses-prepare-tools.ts +177 -0
  201. package/src/provider/sdk/openai-compatible/src/responses/openai-responses-settings.ts +1 -0
  202. package/src/provider/sdk/openai-compatible/src/responses/tool/code-interpreter.ts +88 -0
  203. package/src/provider/sdk/openai-compatible/src/responses/tool/file-search.ts +128 -0
  204. package/src/provider/sdk/openai-compatible/src/responses/tool/image-generation.ts +115 -0
  205. package/src/provider/sdk/openai-compatible/src/responses/tool/local-shell.ts +65 -0
  206. package/src/provider/sdk/openai-compatible/src/responses/tool/web-search-preview.ts +104 -0
  207. package/src/provider/sdk/openai-compatible/src/responses/tool/web-search.ts +103 -0
  208. package/src/provider/transform.ts +455 -0
  209. package/src/pty/index.ts +231 -0
  210. package/src/security/guardrails.test.ts +341 -0
  211. package/src/security/guardrails.ts +558 -0
  212. package/src/security/index.ts +19 -0
  213. package/src/server/error.ts +36 -0
  214. package/src/server/project.ts +79 -0
  215. package/src/server/server.ts +2642 -0
  216. package/src/server/tui.ts +71 -0
  217. package/src/session/compaction.ts +223 -0
  218. package/src/session/index.ts +461 -0
  219. package/src/session/llm.ts +201 -0
  220. package/src/session/message-v2.ts +690 -0
  221. package/src/session/message.ts +189 -0
  222. package/src/session/processor.ts +409 -0
  223. package/src/session/prompt/act-switch.txt +5 -0
  224. package/src/session/prompt/anthropic-20250930.txt +166 -0
  225. package/src/session/prompt/anthropic.txt +85 -0
  226. package/src/session/prompt/anthropic_spoof.txt +1 -0
  227. package/src/session/prompt/beast.txt +103 -0
  228. package/src/session/prompt/codex.txt +304 -0
  229. package/src/session/prompt/copilot-gpt-5.txt +138 -0
  230. package/src/session/prompt/gemini.txt +85 -0
  231. package/src/session/prompt/max-steps.txt +16 -0
  232. package/src/session/prompt/plan-reminder-anthropic.txt +35 -0
  233. package/src/session/prompt/plan.txt +24 -0
  234. package/src/session/prompt/polaris.txt +84 -0
  235. package/src/session/prompt/qwen.txt +106 -0
  236. package/src/session/prompt.ts +1509 -0
  237. package/src/session/retry.ts +86 -0
  238. package/src/session/revert.ts +108 -0
  239. package/src/session/sensitive-filter.test.ts +327 -0
  240. package/src/session/sensitive-filter.ts +466 -0
  241. package/src/session/status.ts +76 -0
  242. package/src/session/summary.ts +194 -0
  243. package/src/session/system.ts +120 -0
  244. package/src/session/todo.ts +37 -0
  245. package/src/share/share-next.ts +194 -0
  246. package/src/share/share.ts +87 -0
  247. package/src/shell/shell.ts +67 -0
  248. package/src/skill/index.ts +1 -0
  249. package/src/skill/skill.ts +83 -0
  250. package/src/snapshot/index.ts +197 -0
  251. package/src/storage/storage.ts +226 -0
  252. package/src/tests/agent.test.ts +308 -0
  253. package/src/tests/build-guards.test.ts +267 -0
  254. package/src/tests/config.test.ts +664 -0
  255. package/src/tests/tool-registry.test.ts +589 -0
  256. package/src/tool/bash.ts +317 -0
  257. package/src/tool/bash.txt +158 -0
  258. package/src/tool/batch.ts +175 -0
  259. package/src/tool/batch.txt +24 -0
  260. package/src/tool/codesearch.ts +168 -0
  261. package/src/tool/codesearch.txt +12 -0
  262. package/src/tool/edit.ts +675 -0
  263. package/src/tool/edit.txt +10 -0
  264. package/src/tool/glob.ts +65 -0
  265. package/src/tool/glob.txt +6 -0
  266. package/src/tool/grep.ts +121 -0
  267. package/src/tool/grep.txt +8 -0
  268. package/src/tool/invalid.ts +17 -0
  269. package/src/tool/ls.ts +110 -0
  270. package/src/tool/ls.txt +1 -0
  271. package/src/tool/lsp-diagnostics.ts +26 -0
  272. package/src/tool/lsp-diagnostics.txt +1 -0
  273. package/src/tool/lsp-hover.ts +31 -0
  274. package/src/tool/lsp-hover.txt +1 -0
  275. package/src/tool/lsp.ts +87 -0
  276. package/src/tool/lsp.txt +19 -0
  277. package/src/tool/multiedit.ts +46 -0
  278. package/src/tool/multiedit.txt +41 -0
  279. package/src/tool/patch.ts +233 -0
  280. package/src/tool/patch.txt +1 -0
  281. package/src/tool/read.ts +219 -0
  282. package/src/tool/read.txt +12 -0
  283. package/src/tool/registry.ts +162 -0
  284. package/src/tool/skill.ts +100 -0
  285. package/src/tool/task.ts +136 -0
  286. package/src/tool/task.txt +51 -0
  287. package/src/tool/todo.ts +39 -0
  288. package/src/tool/todoread.txt +14 -0
  289. package/src/tool/todowrite.txt +167 -0
  290. package/src/tool/tool.ts +71 -0
  291. package/src/tool/webfetch.ts +198 -0
  292. package/src/tool/webfetch.txt +13 -0
  293. package/src/tool/websearch.ts +180 -0
  294. package/src/tool/websearch.txt +11 -0
  295. package/src/tool/write.ts +110 -0
  296. package/src/tool/write.txt +8 -0
  297. package/src/util/archive.ts +16 -0
  298. package/src/util/color.ts +19 -0
  299. package/src/util/context.ts +25 -0
  300. package/src/util/defer.ts +12 -0
  301. package/src/util/eventloop.ts +20 -0
  302. package/src/util/filesystem.ts +83 -0
  303. package/src/util/fn.ts +11 -0
  304. package/src/util/iife.ts +3 -0
  305. package/src/util/keybind.ts +102 -0
  306. package/src/util/lazy.ts +11 -0
  307. package/src/util/license.ts +325 -0
  308. package/src/util/locale.ts +81 -0
  309. package/src/util/lock.ts +98 -0
  310. package/src/util/log.ts +180 -0
  311. package/src/util/queue.ts +32 -0
  312. package/src/util/rpc.ts +42 -0
  313. package/src/util/scrap.ts +10 -0
  314. package/src/util/signal.ts +12 -0
  315. package/src/util/timeout.ts +14 -0
  316. package/src/util/token.ts +7 -0
  317. package/src/util/wildcard.ts +54 -0
  318. package/sst-env.d.ts +9 -0
  319. package/test/agent/agent.test.ts +146 -0
  320. package/test/bun.test.ts +53 -0
  321. package/test/cli/github-remote.test.ts +80 -0
  322. package/test/config/agent-color.test.ts +66 -0
  323. package/test/config/config.test.ts +535 -0
  324. package/test/config/markdown.test.ts +89 -0
  325. package/test/file/ignore.test.ts +10 -0
  326. package/test/fixture/fixture.ts +36 -0
  327. package/test/fixture/lsp/fake-lsp-server.js +77 -0
  328. package/test/ide/ide.test.ts +82 -0
  329. package/test/keybind.test.ts +421 -0
  330. package/test/lsp/client.test.ts +95 -0
  331. package/test/mcp/headers.test.ts +153 -0
  332. package/test/patch/patch.test.ts +348 -0
  333. package/test/preload.ts +57 -0
  334. package/test/project/project.test.ts +72 -0
  335. package/test/provider/provider.test.ts +1809 -0
  336. package/test/provider/transform.test.ts +411 -0
  337. package/test/session/retry.test.ts +111 -0
  338. package/test/session/session.test.ts +71 -0
  339. package/test/skill/skill.test.ts +131 -0
  340. package/test/snapshot/snapshot.test.ts +939 -0
  341. package/test/tool/__snapshots__/tool.test.ts.snap +9 -0
  342. package/test/tool/bash.test.ts +434 -0
  343. package/test/tool/grep.test.ts +108 -0
  344. package/test/tool/patch.test.ts +259 -0
  345. package/test/tool/read.test.ts +42 -0
  346. package/test/util/iife.test.ts +36 -0
  347. package/test/util/lazy.test.ts +50 -0
  348. package/test/util/timeout.test.ts +21 -0
  349. package/test/util/wildcard.test.ts +55 -0
  350. package/tsconfig.json +16 -0
@@ -0,0 +1,70 @@
1
+ import path from "path"
2
+ import { Global } from "../global"
3
+ import fs from "fs/promises"
4
+ import z from "zod"
5
+
6
+ export namespace Auth {
7
+ export const Oauth = z
8
+ .object({
9
+ type: z.literal("oauth"),
10
+ refresh: z.string(),
11
+ access: z.string(),
12
+ expires: z.number(),
13
+ enterpriseUrl: z.string().optional(),
14
+ })
15
+ .meta({ ref: "OAuth" })
16
+
17
+ export const Api = z
18
+ .object({
19
+ type: z.literal("api"),
20
+ key: z.string(),
21
+ })
22
+ .meta({ ref: "ApiAuth" })
23
+
24
+ export const WellKnown = z
25
+ .object({
26
+ type: z.literal("wellknown"),
27
+ key: z.string(),
28
+ token: z.string(),
29
+ })
30
+ .meta({ ref: "WellKnownAuth" })
31
+
32
+ export const Info = z.discriminatedUnion("type", [Oauth, Api, WellKnown]).meta({ ref: "Auth" })
33
+ export type Info = z.infer<typeof Info>
34
+
35
+ const filepath = path.join(Global.Path.data, "auth.json")
36
+
37
+ export async function get(providerID: string) {
38
+ const auth = await all()
39
+ return auth[providerID]
40
+ }
41
+
42
+ export async function all(): Promise<Record<string, Info>> {
43
+ const file = Bun.file(filepath)
44
+ const data = await file.json().catch(() => ({}) as Record<string, unknown>)
45
+ return Object.entries(data).reduce(
46
+ (acc, [key, value]) => {
47
+ const parsed = Info.safeParse(value)
48
+ if (!parsed.success) return acc
49
+ acc[key] = parsed.data
50
+ return acc
51
+ },
52
+ {} as Record<string, Info>,
53
+ )
54
+ }
55
+
56
+ export async function set(key: string, info: Info) {
57
+ const file = Bun.file(filepath)
58
+ const data = await all()
59
+ await Bun.write(file, JSON.stringify({ ...data, [key]: info }, null, 2))
60
+ await fs.chmod(file.name!, 0o600)
61
+ }
62
+
63
+ export async function remove(key: string) {
64
+ const file = Bun.file(filepath)
65
+ const data = await all()
66
+ delete data[key]
67
+ await Bun.write(file, JSON.stringify(data, null, 2))
68
+ await fs.chmod(file.name!, 0o600)
69
+ }
70
+ }
@@ -0,0 +1,114 @@
1
+ import z from "zod"
2
+ import { Global } from "../global"
3
+ import { Log } from "../util/log"
4
+ import path from "path"
5
+ import { NamedError } from "@opencode-ai/util/error"
6
+ import { readableStreamToText } from "bun"
7
+ import { createRequire } from "module"
8
+ import { Lock } from "../util/lock"
9
+
10
+ export namespace BunProc {
11
+ const log = Log.create({ service: "bun" })
12
+ const req = createRequire(import.meta.url)
13
+
14
+ export async function run(cmd: string[], options?: Bun.SpawnOptions.OptionsObject<any, any, any>) {
15
+ log.info("running", {
16
+ cmd: [which(), ...cmd],
17
+ ...options,
18
+ })
19
+ const result = Bun.spawn([which(), ...cmd], {
20
+ ...options,
21
+ stdout: "pipe",
22
+ stderr: "pipe",
23
+ env: {
24
+ ...process.env,
25
+ ...options?.env,
26
+ BUN_BE_BUN: "1",
27
+ },
28
+ })
29
+ const code = await result.exited
30
+ const stdout = result.stdout
31
+ ? typeof result.stdout === "number"
32
+ ? result.stdout
33
+ : await readableStreamToText(result.stdout)
34
+ : undefined
35
+ const stderr = result.stderr
36
+ ? typeof result.stderr === "number"
37
+ ? result.stderr
38
+ : await readableStreamToText(result.stderr)
39
+ : undefined
40
+ log.info("done", {
41
+ code,
42
+ stdout,
43
+ stderr,
44
+ })
45
+ if (code !== 0) {
46
+ throw new Error(`Command failed with exit code ${result.exitCode}`)
47
+ }
48
+ return result
49
+ }
50
+
51
+ export function which() {
52
+ return process.execPath
53
+ }
54
+
55
+ export const InstallFailedError = NamedError.create(
56
+ "BunInstallFailedError",
57
+ z.object({
58
+ pkg: z.string(),
59
+ version: z.string(),
60
+ }),
61
+ )
62
+
63
+ export async function install(pkg: string, version = "latest") {
64
+ // Use lock to ensure only one install at a time
65
+ using _ = await Lock.write("bun-install")
66
+
67
+ const mod = path.join(Global.Path.cache, "node_modules", pkg)
68
+ const pkgjson = Bun.file(path.join(Global.Path.cache, "package.json"))
69
+ const parsed = await pkgjson.json().catch(async () => {
70
+ const result = { dependencies: {} }
71
+ await Bun.write(pkgjson.name!, JSON.stringify(result, null, 2))
72
+ return result
73
+ })
74
+ if (parsed.dependencies[pkg] === version) return mod
75
+
76
+ // Build command arguments
77
+ const args = ["add", "--force", "--exact", "--cwd", Global.Path.cache, pkg + "@" + version]
78
+
79
+ // Let Bun handle registry resolution:
80
+ // - If .npmrc files exist, Bun will use them automatically
81
+ // - If no .npmrc files exist, Bun will default to https://registry.npmjs.org
82
+ // - No need to pass --registry flag
83
+ log.info("installing package using Bun's default registry resolution", {
84
+ pkg,
85
+ version,
86
+ })
87
+
88
+ await BunProc.run(args, {
89
+ cwd: Global.Path.cache,
90
+ }).catch((e) => {
91
+ throw new InstallFailedError(
92
+ { pkg, version },
93
+ {
94
+ cause: e,
95
+ },
96
+ )
97
+ })
98
+
99
+ // Resolve actual version from installed package when using "latest"
100
+ // This ensures subsequent starts use the cached version until explicitly updated
101
+ let resolvedVersion = version
102
+ if (version === "latest") {
103
+ const installedPkgJson = Bun.file(path.join(mod, "package.json"))
104
+ const installedPkg = await installedPkgJson.json().catch(() => null)
105
+ if (installedPkg?.version) {
106
+ resolvedVersion = installedPkg.version
107
+ }
108
+ }
109
+
110
+ parsed.dependencies[pkg] = resolvedVersion
111
+ await Bun.write(pkgjson.name!, JSON.stringify(parsed, null, 2))
112
+ return mod
113
+ }
114
+ }
@@ -0,0 +1,43 @@
1
+ import z from "zod"
2
+ import type { ZodType } from "zod"
3
+ import { Log } from "../util/log"
4
+
5
+ export namespace BusEvent {
6
+ const log = Log.create({ service: "event" })
7
+
8
+ export type Definition = ReturnType<typeof define>
9
+
10
+ const registry = new Map<string, Definition>()
11
+
12
+ export function define<Type extends string, Properties extends ZodType>(type: Type, properties: Properties) {
13
+ const result = {
14
+ type,
15
+ properties,
16
+ }
17
+ registry.set(type, result)
18
+ return result
19
+ }
20
+
21
+ export function payloads() {
22
+ return z
23
+ .discriminatedUnion(
24
+ "type",
25
+ registry
26
+ .entries()
27
+ .map(([type, def]) => {
28
+ return z
29
+ .object({
30
+ type: z.literal(type),
31
+ properties: def.properties,
32
+ })
33
+ .meta({
34
+ ref: "Event" + "." + def.type,
35
+ })
36
+ })
37
+ .toArray() as any,
38
+ )
39
+ .meta({
40
+ ref: "Event",
41
+ })
42
+ }
43
+ }
@@ -0,0 +1,10 @@
1
+ import { EventEmitter } from "events"
2
+
3
+ export const GlobalBus = new EventEmitter<{
4
+ event: [
5
+ {
6
+ directory?: string
7
+ payload: any
8
+ },
9
+ ]
10
+ }>()
@@ -0,0 +1,105 @@
1
+ import z from "zod"
2
+ import { Log } from "../util/log"
3
+ import { Instance } from "../project/instance"
4
+ import { BusEvent } from "./bus-event"
5
+ import { GlobalBus } from "./global"
6
+
7
+ export namespace Bus {
8
+ const log = Log.create({ service: "bus" })
9
+ type Subscription = (event: any) => void
10
+
11
+ export const InstanceDisposed = BusEvent.define(
12
+ "server.instance.disposed",
13
+ z.object({
14
+ directory: z.string(),
15
+ }),
16
+ )
17
+
18
+ const state = Instance.state(
19
+ () => {
20
+ const subscriptions = new Map<any, Subscription[]>()
21
+
22
+ return {
23
+ subscriptions,
24
+ }
25
+ },
26
+ async (entry) => {
27
+ const wildcard = entry.subscriptions.get("*")
28
+ if (!wildcard) return
29
+ const event = {
30
+ type: InstanceDisposed.type,
31
+ properties: {
32
+ directory: Instance.directory,
33
+ },
34
+ }
35
+ for (const sub of [...wildcard]) {
36
+ sub(event)
37
+ }
38
+ },
39
+ )
40
+
41
+ export async function publish<Definition extends BusEvent.Definition>(
42
+ def: Definition,
43
+ properties: z.output<Definition["properties"]>,
44
+ ) {
45
+ const payload = {
46
+ type: def.type,
47
+ properties,
48
+ }
49
+ log.info("publishing", {
50
+ type: def.type,
51
+ })
52
+ const pending = []
53
+ for (const key of [def.type, "*"]) {
54
+ const match = state().subscriptions.get(key)
55
+ for (const sub of match ?? []) {
56
+ pending.push(sub(payload))
57
+ }
58
+ }
59
+ GlobalBus.emit("event", {
60
+ directory: Instance.directory,
61
+ payload,
62
+ })
63
+ return Promise.all(pending)
64
+ }
65
+
66
+ export function subscribe<Definition extends BusEvent.Definition>(
67
+ def: Definition,
68
+ callback: (event: { type: Definition["type"]; properties: z.infer<Definition["properties"]> }) => void,
69
+ ) {
70
+ return raw(def.type, callback)
71
+ }
72
+
73
+ export function once<Definition extends BusEvent.Definition>(
74
+ def: Definition,
75
+ callback: (event: {
76
+ type: Definition["type"]
77
+ properties: z.infer<Definition["properties"]>
78
+ }) => "done" | undefined,
79
+ ) {
80
+ const unsub = subscribe(def, (event) => {
81
+ if (callback(event)) unsub()
82
+ })
83
+ }
84
+
85
+ export function subscribeAll(callback: (event: any) => void) {
86
+ return raw("*", callback)
87
+ }
88
+
89
+ function raw(type: string, callback: (event: any) => void) {
90
+ log.info("subscribing", { type })
91
+ const subscriptions = state().subscriptions
92
+ let match = subscriptions.get(type) ?? []
93
+ match.push(callback)
94
+ subscriptions.set(type, match)
95
+
96
+ return () => {
97
+ log.info("unsubscribing", { type })
98
+ const match = subscriptions.get(type)
99
+ if (!match) return
100
+ const index = match.indexOf(callback)
101
+ if (index === -1) return
102
+ match.splice(index, 1)
103
+ }
104
+ }
105
+ }
@@ -0,0 +1,17 @@
1
+ import { InstanceBootstrap } from "../project/bootstrap"
2
+ import { Instance } from "../project/instance"
3
+
4
+ export async function bootstrap<T>(directory: string, cb: () => Promise<T>) {
5
+ return Instance.provide({
6
+ directory,
7
+ init: InstanceBootstrap,
8
+ fn: async () => {
9
+ try {
10
+ const result = await cb()
11
+ return result
12
+ } finally {
13
+ await Instance.dispose()
14
+ }
15
+ },
16
+ })
17
+ }
@@ -0,0 +1,88 @@
1
+ import { Log } from "@/util/log"
2
+ import { bootstrap } from "../bootstrap"
3
+ import { cmd } from "./cmd"
4
+ import { AgentSideConnection, ndJsonStream } from "@agentclientprotocol/sdk"
5
+ import { ACP } from "@/acp/agent"
6
+ import { Server } from "@/server/server"
7
+ import { createOpencodeClient } from "@opencode-ai/sdk/v2"
8
+
9
+ const log = Log.create({ service: "acp-command" })
10
+
11
+ process.on("unhandledRejection", (reason, promise) => {
12
+ log.error("Unhandled rejection", {
13
+ promise,
14
+ reason,
15
+ })
16
+ })
17
+
18
+ export const AcpCommand = cmd({
19
+ command: "acp",
20
+ describe: "start ACP (Agent Client Protocol) server for rird",
21
+ builder: (yargs) => {
22
+ return yargs
23
+ .option("cwd", {
24
+ describe: "working directory",
25
+ type: "string",
26
+ default: process.cwd(),
27
+ })
28
+ .option("port", {
29
+ type: "number",
30
+ describe: "port to listen on",
31
+ default: 0,
32
+ })
33
+ .option("hostname", {
34
+ type: "string",
35
+ describe: "hostname to listen on",
36
+ default: "127.0.0.1",
37
+ })
38
+ },
39
+ handler: async (args) => {
40
+ await bootstrap(process.cwd(), async () => {
41
+ const server = Server.listen({
42
+ port: args.port,
43
+ hostname: args.hostname,
44
+ })
45
+
46
+ const sdk = createOpencodeClient({
47
+ baseUrl: `http://${server.hostname}:${server.port}`,
48
+ })
49
+
50
+ const input = new WritableStream<Uint8Array>({
51
+ write(chunk) {
52
+ return new Promise<void>((resolve, reject) => {
53
+ process.stdout.write(chunk, (err) => {
54
+ if (err) {
55
+ reject(err)
56
+ } else {
57
+ resolve()
58
+ }
59
+ })
60
+ })
61
+ },
62
+ })
63
+ const output = new ReadableStream<Uint8Array>({
64
+ start(controller) {
65
+ process.stdin.on("data", (chunk: Buffer) => {
66
+ controller.enqueue(new Uint8Array(chunk))
67
+ })
68
+ process.stdin.on("end", () => controller.close())
69
+ process.stdin.on("error", (err) => controller.error(err))
70
+ },
71
+ })
72
+
73
+ const stream = ndJsonStream(input, output)
74
+ const agent = await ACP.init({ sdk })
75
+
76
+ new AgentSideConnection((conn) => {
77
+ return agent.create(conn, { sdk })
78
+ }, stream)
79
+
80
+ log.info("setup connection")
81
+ process.stdin.resume()
82
+ await new Promise((resolve, reject) => {
83
+ process.stdin.on("end", resolve)
84
+ process.stdin.on("error", reject)
85
+ })
86
+ })
87
+ },
88
+ })
@@ -0,0 +1,256 @@
1
+ import { cmd } from "./cmd"
2
+ import * as prompts from "@clack/prompts"
3
+ import { UI } from "../ui"
4
+ import { Global } from "../../global"
5
+ import { Agent } from "../../agent/agent"
6
+ import { Provider } from "../../provider/provider"
7
+ import path from "path"
8
+ import fs from "fs/promises"
9
+ import matter from "gray-matter"
10
+ import { Instance } from "../../project/instance"
11
+ import { EOL } from "os"
12
+ import type { Argv } from "yargs"
13
+
14
+ type AgentMode = "all" | "primary" | "subagent"
15
+
16
+ const AVAILABLE_TOOLS = [
17
+ "bash",
18
+ "read",
19
+ "write",
20
+ "edit",
21
+ "list",
22
+ "glob",
23
+ "grep",
24
+ "webfetch",
25
+ "task",
26
+ "todowrite",
27
+ "todoread",
28
+ ]
29
+
30
+ const AgentCreateCommand = cmd({
31
+ command: "create",
32
+ describe: "create a new agent",
33
+ builder: (yargs: Argv) =>
34
+ yargs
35
+ .option("path", {
36
+ type: "string",
37
+ describe: "directory path to generate the agent file",
38
+ })
39
+ .option("description", {
40
+ type: "string",
41
+ describe: "what the agent should do",
42
+ })
43
+ .option("mode", {
44
+ type: "string",
45
+ describe: "agent mode",
46
+ choices: ["all", "primary", "subagent"] as const,
47
+ })
48
+ .option("tools", {
49
+ type: "string",
50
+ describe: `comma-separated list of tools to enable (default: all). Available: "${AVAILABLE_TOOLS.join(", ")}"`,
51
+ })
52
+ .option("model", {
53
+ type: "string",
54
+ alias: ["m"],
55
+ describe: "model to use in the format of provider/model",
56
+ }),
57
+ async handler(args) {
58
+ await Instance.provide({
59
+ directory: process.cwd(),
60
+ async fn() {
61
+ const cliPath = args.path
62
+ const cliDescription = args.description
63
+ const cliMode = args.mode as AgentMode | undefined
64
+ const cliTools = args.tools
65
+
66
+ const isFullyNonInteractive = cliPath && cliDescription && cliMode && cliTools !== undefined
67
+
68
+ if (!isFullyNonInteractive) {
69
+ UI.empty()
70
+ prompts.intro("Create agent")
71
+ }
72
+
73
+ const project = Instance.project
74
+
75
+ // Determine scope/path
76
+ let targetPath: string
77
+ if (cliPath) {
78
+ targetPath = path.join(cliPath, "agent")
79
+ } else {
80
+ let scope: "global" | "project" = "global"
81
+ if (project.vcs === "git") {
82
+ const scopeResult = await prompts.select({
83
+ message: "Location",
84
+ options: [
85
+ {
86
+ label: "Current project",
87
+ value: "project" as const,
88
+ hint: Instance.worktree,
89
+ },
90
+ {
91
+ label: "Global",
92
+ value: "global" as const,
93
+ hint: Global.Path.config,
94
+ },
95
+ ],
96
+ })
97
+ if (prompts.isCancel(scopeResult)) throw new UI.CancelledError()
98
+ scope = scopeResult
99
+ }
100
+ targetPath = path.join(
101
+ scope === "global" ? Global.Path.config : path.join(Instance.worktree, ".opencode"),
102
+ "agent",
103
+ )
104
+ }
105
+
106
+ // Get description
107
+ let description: string
108
+ if (cliDescription) {
109
+ description = cliDescription
110
+ } else {
111
+ const query = await prompts.text({
112
+ message: "Description",
113
+ placeholder: "What should this agent do?",
114
+ validate: (x) => (x && x.length > 0 ? undefined : "Required"),
115
+ })
116
+ if (prompts.isCancel(query)) throw new UI.CancelledError()
117
+ description = query
118
+ }
119
+
120
+ // Generate agent
121
+ const spinner = prompts.spinner()
122
+ spinner.start("Generating agent configuration...")
123
+ const model = args.model ? Provider.parseModel(args.model) : undefined
124
+ const generated = await Agent.generate({ description, model }).catch((error) => {
125
+ spinner.stop(`LLM failed to generate agent: ${error.message}`, 1)
126
+ if (isFullyNonInteractive) process.exit(1)
127
+ throw new UI.CancelledError()
128
+ })
129
+ spinner.stop(`Agent ${generated.identifier} generated`)
130
+
131
+ // Select tools
132
+ let selectedTools: string[]
133
+ if (cliTools !== undefined) {
134
+ selectedTools = cliTools ? cliTools.split(",").map((t) => t.trim()) : AVAILABLE_TOOLS
135
+ } else {
136
+ const result = await prompts.multiselect({
137
+ message: "Select tools to enable",
138
+ options: AVAILABLE_TOOLS.map((tool) => ({
139
+ label: tool,
140
+ value: tool,
141
+ })),
142
+ initialValues: AVAILABLE_TOOLS,
143
+ })
144
+ if (prompts.isCancel(result)) throw new UI.CancelledError()
145
+ selectedTools = result
146
+ }
147
+
148
+ // Get mode
149
+ let mode: AgentMode
150
+ if (cliMode) {
151
+ mode = cliMode
152
+ } else {
153
+ const modeResult = await prompts.select({
154
+ message: "Agent mode",
155
+ options: [
156
+ {
157
+ label: "All",
158
+ value: "all" as const,
159
+ hint: "Can function in both primary and subagent roles",
160
+ },
161
+ {
162
+ label: "Primary",
163
+ value: "primary" as const,
164
+ hint: "Acts as a primary/main agent",
165
+ },
166
+ {
167
+ label: "Subagent",
168
+ value: "subagent" as const,
169
+ hint: "Can be used as a subagent by other agents",
170
+ },
171
+ ],
172
+ initialValue: "all" as const,
173
+ })
174
+ if (prompts.isCancel(modeResult)) throw new UI.CancelledError()
175
+ mode = modeResult
176
+ }
177
+
178
+ // Build tools config
179
+ const tools: Record<string, boolean> = {}
180
+ for (const tool of AVAILABLE_TOOLS) {
181
+ if (!selectedTools.includes(tool)) {
182
+ tools[tool] = false
183
+ }
184
+ }
185
+
186
+ // Build frontmatter
187
+ const frontmatter: {
188
+ description: string
189
+ mode: AgentMode
190
+ tools?: Record<string, boolean>
191
+ } = {
192
+ description: generated.whenToUse,
193
+ mode,
194
+ }
195
+ if (Object.keys(tools).length > 0) {
196
+ frontmatter.tools = tools
197
+ }
198
+
199
+ // Write file
200
+ const content = matter.stringify(generated.systemPrompt, frontmatter)
201
+ const filePath = path.join(targetPath, `${generated.identifier}.md`)
202
+
203
+ await fs.mkdir(targetPath, { recursive: true })
204
+
205
+ const file = Bun.file(filePath)
206
+ if (await file.exists()) {
207
+ if (isFullyNonInteractive) {
208
+ console.error(`Error: Agent file already exists: ${filePath}`)
209
+ process.exit(1)
210
+ }
211
+ prompts.log.error(`Agent file already exists: ${filePath}`)
212
+ throw new UI.CancelledError()
213
+ }
214
+
215
+ await Bun.write(filePath, content)
216
+
217
+ if (isFullyNonInteractive) {
218
+ console.log(filePath)
219
+ } else {
220
+ prompts.log.success(`Agent created: ${filePath}`)
221
+ prompts.outro("Done")
222
+ }
223
+ },
224
+ })
225
+ },
226
+ })
227
+
228
+ const AgentListCommand = cmd({
229
+ command: "list",
230
+ describe: "list all available agents",
231
+ async handler() {
232
+ await Instance.provide({
233
+ directory: process.cwd(),
234
+ async fn() {
235
+ const agents = await Agent.list()
236
+ const sortedAgents = agents.sort((a, b) => {
237
+ if (a.native !== b.native) {
238
+ return a.native ? -1 : 1
239
+ }
240
+ return a.name.localeCompare(b.name)
241
+ })
242
+
243
+ for (const agent of sortedAgents) {
244
+ process.stdout.write(`${agent.name} (${agent.mode})${EOL}`)
245
+ }
246
+ },
247
+ })
248
+ },
249
+ })
250
+
251
+ export const AgentCommand = cmd({
252
+ command: "agent",
253
+ describe: "manage agents",
254
+ builder: (yargs) => yargs.command(AgentCreateCommand).command(AgentListCommand).demandCommand(),
255
+ async handler() {},
256
+ })