rird 2.1.231 → 2.3.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (381) hide show
  1. package/AGENTS.md +86 -0
  2. package/COMPLETED_TEST_SUITE.txt +280 -0
  3. package/Dockerfile +18 -0
  4. package/README.md +397 -6
  5. package/RIRD_ERROR_HANDLING_SUMMARY.md +307 -0
  6. package/TESTING.md +512 -0
  7. package/TEST_IMPLEMENTATION_REPORT.md +463 -0
  8. package/TEST_SUITE.md +307 -0
  9. package/TEST_SUMMARY.txt +380 -0
  10. package/bin/rird-perf.js +37 -0
  11. package/bin/rird.js +43 -8
  12. package/bunfig.toml +4 -0
  13. package/create-wrapper.ps1 +51 -0
  14. package/docs/ARCHITECTURE.md +768 -0
  15. package/docs/CLI_REFERENCE.md +681 -0
  16. package/docs/DOCUMENTATION_MANIFEST.md +392 -0
  17. package/docs/INDEX.md +295 -0
  18. package/docs/PRODUCTION_SETUP.md +633 -0
  19. package/docs/TROUBLESHOOTING.md +914 -0
  20. package/facebook_ads_library.png +0 -0
  21. package/nul +0 -0
  22. package/nul`nif +0 -0
  23. package/package.json +104 -15
  24. package/parsers-config.ts +239 -0
  25. package/rird-1.0.199.tgz +0 -0
  26. package/rird-1.0.205.tgz +0 -0
  27. package/script/build-windows.ts +56 -0
  28. package/script/build.ts +165 -0
  29. package/{postinstall.mjs → script/postinstall.mjs} +47 -68
  30. package/script/publish-registries.ts +187 -0
  31. package/script/publish.ts +85 -0
  32. package/script/schema.ts +47 -0
  33. package/src/acp/README.md +164 -0
  34. package/src/acp/agent.ts +1063 -0
  35. package/src/acp/session.ts +101 -0
  36. package/src/acp/types.ts +22 -0
  37. package/src/agent/agent.ts +367 -0
  38. package/src/agent/generate.txt +75 -0
  39. package/src/agent/prompt/compaction.txt +12 -0
  40. package/src/agent/prompt/explore.txt +18 -0
  41. package/src/agent/prompt/summary.txt +10 -0
  42. package/src/agent/prompt/title.txt +36 -0
  43. package/src/auth/index.ts +70 -0
  44. package/src/bun/index.ts +114 -0
  45. package/src/bus/bus-event.ts +43 -0
  46. package/src/bus/global.ts +10 -0
  47. package/src/bus/index.ts +105 -0
  48. package/src/cli/bootstrap.ts +17 -0
  49. package/src/cli/cmd/acp.ts +104 -0
  50. package/src/cli/cmd/activate.ts +50 -0
  51. package/src/cli/cmd/agent.ts +256 -0
  52. package/src/cli/cmd/auth.ts +412 -0
  53. package/src/cli/cmd/cmd.ts +7 -0
  54. package/src/cli/cmd/debug/config.ts +15 -0
  55. package/src/cli/cmd/debug/file.ts +91 -0
  56. package/src/cli/cmd/debug/index.ts +43 -0
  57. package/src/cli/cmd/debug/lsp.ts +48 -0
  58. package/src/cli/cmd/debug/ripgrep.ts +83 -0
  59. package/src/cli/cmd/debug/scrap.ts +15 -0
  60. package/src/cli/cmd/debug/skill.ts +15 -0
  61. package/src/cli/cmd/debug/snapshot.ts +48 -0
  62. package/src/cli/cmd/export.ts +88 -0
  63. package/src/cli/cmd/generate.ts +38 -0
  64. package/src/cli/cmd/github.ts +1400 -0
  65. package/src/cli/cmd/import.ts +98 -0
  66. package/src/cli/cmd/mcp.ts +654 -0
  67. package/src/cli/cmd/models.ts +68 -0
  68. package/src/cli/cmd/pr.ts +112 -0
  69. package/src/cli/cmd/run.ts +434 -0
  70. package/src/cli/cmd/serve.ts +31 -0
  71. package/src/cli/cmd/session.ts +106 -0
  72. package/src/cli/cmd/stats.ts +298 -0
  73. package/src/cli/cmd/tui/app.tsx +694 -0
  74. package/src/cli/cmd/tui/attach.ts +30 -0
  75. package/src/cli/cmd/tui/component/border.tsx +21 -0
  76. package/src/cli/cmd/tui/component/dialog-agent.tsx +31 -0
  77. package/src/cli/cmd/tui/component/dialog-command.tsx +124 -0
  78. package/src/cli/cmd/tui/component/dialog-mcp.tsx +86 -0
  79. package/src/cli/cmd/tui/component/dialog-model.tsx +236 -0
  80. package/src/cli/cmd/tui/component/dialog-provider.tsx +240 -0
  81. package/src/cli/cmd/tui/component/dialog-session-list.tsx +102 -0
  82. package/src/cli/cmd/tui/component/dialog-session-rename.tsx +31 -0
  83. package/src/cli/cmd/tui/component/dialog-stash.tsx +86 -0
  84. package/src/cli/cmd/tui/component/dialog-status.tsx +162 -0
  85. package/src/cli/cmd/tui/component/dialog-tag.tsx +44 -0
  86. package/src/cli/cmd/tui/component/dialog-theme-list.tsx +50 -0
  87. package/src/cli/cmd/tui/component/did-you-know.tsx +85 -0
  88. package/src/cli/cmd/tui/component/logo.tsx +48 -0
  89. package/src/cli/cmd/tui/component/prompt/autocomplete.tsx +574 -0
  90. package/src/cli/cmd/tui/component/prompt/history.tsx +108 -0
  91. package/src/cli/cmd/tui/component/prompt/index.tsx +1087 -0
  92. package/src/cli/cmd/tui/component/prompt/stash.tsx +101 -0
  93. package/src/cli/cmd/tui/component/tips.ts +27 -0
  94. package/src/cli/cmd/tui/component/todo-item.tsx +32 -0
  95. package/src/cli/cmd/tui/context/args.tsx +14 -0
  96. package/src/cli/cmd/tui/context/directory.ts +13 -0
  97. package/src/cli/cmd/tui/context/exit.tsx +23 -0
  98. package/src/cli/cmd/tui/context/helper.tsx +25 -0
  99. package/src/cli/cmd/tui/context/keybind.tsx +101 -0
  100. package/src/cli/cmd/tui/context/kv.tsx +49 -0
  101. package/src/cli/cmd/tui/context/local.tsx +345 -0
  102. package/src/cli/cmd/tui/context/prompt.tsx +18 -0
  103. package/src/cli/cmd/tui/context/route.tsx +46 -0
  104. package/src/cli/cmd/tui/context/sdk.tsx +74 -0
  105. package/src/cli/cmd/tui/context/sync.tsx +372 -0
  106. package/src/cli/cmd/tui/context/theme/aura.json +69 -0
  107. package/src/cli/cmd/tui/context/theme/ayu.json +80 -0
  108. package/src/cli/cmd/tui/context/theme/catppuccin-frappe.json +233 -0
  109. package/src/cli/cmd/tui/context/theme/catppuccin-macchiato.json +233 -0
  110. package/src/cli/cmd/tui/context/theme/catppuccin.json +112 -0
  111. package/src/cli/cmd/tui/context/theme/cobalt2.json +228 -0
  112. package/src/cli/cmd/tui/context/theme/cursor.json +249 -0
  113. package/src/cli/cmd/tui/context/theme/dracula.json +219 -0
  114. package/src/cli/cmd/tui/context/theme/everforest.json +241 -0
  115. package/src/cli/cmd/tui/context/theme/flexoki.json +237 -0
  116. package/src/cli/cmd/tui/context/theme/github.json +233 -0
  117. package/src/cli/cmd/tui/context/theme/gruvbox.json +95 -0
  118. package/src/cli/cmd/tui/context/theme/kanagawa.json +77 -0
  119. package/src/cli/cmd/tui/context/theme/lucent-orng.json +227 -0
  120. package/src/cli/cmd/tui/context/theme/material.json +235 -0
  121. package/src/cli/cmd/tui/context/theme/matrix.json +77 -0
  122. package/src/cli/cmd/tui/context/theme/mercury.json +252 -0
  123. package/src/cli/cmd/tui/context/theme/monokai.json +221 -0
  124. package/src/cli/cmd/tui/context/theme/nightowl.json +221 -0
  125. package/src/cli/cmd/tui/context/theme/nord.json +223 -0
  126. package/src/cli/cmd/tui/context/theme/one-dark.json +84 -0
  127. package/src/cli/cmd/tui/context/theme/orng.json +245 -0
  128. package/src/cli/cmd/tui/context/theme/palenight.json +222 -0
  129. package/src/cli/cmd/tui/context/theme/rird.json +245 -0
  130. package/src/cli/cmd/tui/context/theme/rosepine.json +234 -0
  131. package/src/cli/cmd/tui/context/theme/solarized.json +223 -0
  132. package/src/cli/cmd/tui/context/theme/synthwave84.json +226 -0
  133. package/src/cli/cmd/tui/context/theme/tokyonight.json +243 -0
  134. package/src/cli/cmd/tui/context/theme/vercel.json +245 -0
  135. package/src/cli/cmd/tui/context/theme/vesper.json +218 -0
  136. package/src/cli/cmd/tui/context/theme/zenburn.json +223 -0
  137. package/src/cli/cmd/tui/context/theme.tsx +1109 -0
  138. package/src/cli/cmd/tui/event.ts +40 -0
  139. package/src/cli/cmd/tui/hooks/use-safe-terminal-dimensions.ts +12 -0
  140. package/src/cli/cmd/tui/routes/home.tsx +138 -0
  141. package/src/cli/cmd/tui/routes/session/dialog-fork-from-timeline.tsx +64 -0
  142. package/src/cli/cmd/tui/routes/session/dialog-message.tsx +109 -0
  143. package/src/cli/cmd/tui/routes/session/dialog-subagent.tsx +26 -0
  144. package/src/cli/cmd/tui/routes/session/dialog-timeline.tsx +47 -0
  145. package/src/cli/cmd/tui/routes/session/footer.tsx +88 -0
  146. package/src/cli/cmd/tui/routes/session/header.tsx +125 -0
  147. package/src/cli/cmd/tui/routes/session/index.tsx +1876 -0
  148. package/src/cli/cmd/tui/routes/session/sidebar.tsx +320 -0
  149. package/src/cli/cmd/tui/spawn.ts +60 -0
  150. package/src/cli/cmd/tui/thread.ts +142 -0
  151. package/src/cli/cmd/tui/ui/dialog-alert.tsx +57 -0
  152. package/src/cli/cmd/tui/ui/dialog-confirm.tsx +83 -0
  153. package/src/cli/cmd/tui/ui/dialog-help.tsx +38 -0
  154. package/src/cli/cmd/tui/ui/dialog-prompt.tsx +77 -0
  155. package/src/cli/cmd/tui/ui/dialog-select.tsx +333 -0
  156. package/src/cli/cmd/tui/ui/dialog.tsx +171 -0
  157. package/src/cli/cmd/tui/ui/spinner.ts +368 -0
  158. package/src/cli/cmd/tui/ui/toast.tsx +100 -0
  159. package/src/cli/cmd/tui/util/clipboard.ts +127 -0
  160. package/src/cli/cmd/tui/util/editor.ts +32 -0
  161. package/src/cli/cmd/tui/util/terminal.ts +146 -0
  162. package/src/cli/cmd/tui/worker.ts +63 -0
  163. package/src/cli/cmd/uninstall.ts +344 -0
  164. package/src/cli/cmd/upgrade.ts +127 -0
  165. package/src/cli/cmd/web.ts +84 -0
  166. package/src/cli/error.ts +69 -0
  167. package/src/cli/ui.ts +101 -0
  168. package/src/cli/upgrade.ts +28 -0
  169. package/src/command/index.ts +80 -0
  170. package/src/command/template/initialize.txt +10 -0
  171. package/src/command/template/review.txt +97 -0
  172. package/src/config/config.ts +994 -0
  173. package/src/config/markdown.ts +41 -0
  174. package/src/env/index.ts +26 -0
  175. package/src/file/ignore.ts +83 -0
  176. package/src/file/index.ts +328 -0
  177. package/src/file/ripgrep.ts +393 -0
  178. package/src/file/time.ts +64 -0
  179. package/src/file/watcher.ts +103 -0
  180. package/src/flag/flag.ts +84 -0
  181. package/src/format/formatter.ts +315 -0
  182. package/src/format/index.ts +137 -0
  183. package/src/global/index.ts +101 -0
  184. package/src/id/id.ts +73 -0
  185. package/src/ide/index.ts +76 -0
  186. package/src/index.ts +297 -0
  187. package/src/index.ts.backup +271 -0
  188. package/src/installation/index.ts +258 -0
  189. package/src/lib/IMPLEMENTATION_NOTES.md +345 -0
  190. package/src/lib/error-handler.ts +225 -0
  191. package/src/lib/error-testing-guide.md +258 -0
  192. package/src/lib/errors.ts +285 -0
  193. package/src/lib/performance.ts +70 -0
  194. package/src/lib/telemetry.ts +282 -0
  195. package/src/lsp/client.ts +229 -0
  196. package/src/lsp/index.ts +485 -0
  197. package/src/lsp/language.ts +116 -0
  198. package/src/lsp/server.ts +1895 -0
  199. package/src/mcp/auth.ts +135 -0
  200. package/src/mcp/index.ts +1117 -0
  201. package/src/mcp/intent-analyzer.ts +376 -0
  202. package/src/mcp/oauth-callback.ts +200 -0
  203. package/src/mcp/oauth-provider.ts +154 -0
  204. package/src/patch/index.ts +632 -0
  205. package/src/permission/index.ts +199 -0
  206. package/src/plugin/index.ts +91 -0
  207. package/src/project/bootstrap.ts +33 -0
  208. package/src/project/instance.ts +78 -0
  209. package/src/project/project.ts +236 -0
  210. package/src/project/state.ts +65 -0
  211. package/src/project/vcs.ts +76 -0
  212. package/src/provider/auth.ts +143 -0
  213. package/src/provider/models-macro.ts +55 -0
  214. package/src/provider/models.ts +161 -0
  215. package/src/provider/provider.ts +1109 -0
  216. package/src/provider/sdk/openai-compatible/src/README.md +5 -0
  217. package/src/provider/sdk/openai-compatible/src/index.ts +2 -0
  218. package/src/provider/sdk/openai-compatible/src/openai-compatible-provider.ts +100 -0
  219. package/src/provider/sdk/openai-compatible/src/responses/convert-to-openai-responses-input.ts +303 -0
  220. package/src/provider/sdk/openai-compatible/src/responses/map-openai-responses-finish-reason.ts +22 -0
  221. package/src/provider/sdk/openai-compatible/src/responses/openai-config.ts +18 -0
  222. package/src/provider/sdk/openai-compatible/src/responses/openai-error.ts +22 -0
  223. package/src/provider/sdk/openai-compatible/src/responses/openai-responses-api-types.ts +207 -0
  224. package/src/provider/sdk/openai-compatible/src/responses/openai-responses-language-model.ts +1713 -0
  225. package/src/provider/sdk/openai-compatible/src/responses/openai-responses-prepare-tools.ts +177 -0
  226. package/src/provider/sdk/openai-compatible/src/responses/openai-responses-settings.ts +1 -0
  227. package/src/provider/sdk/openai-compatible/src/responses/tool/code-interpreter.ts +88 -0
  228. package/src/provider/sdk/openai-compatible/src/responses/tool/file-search.ts +128 -0
  229. package/src/provider/sdk/openai-compatible/src/responses/tool/image-generation.ts +115 -0
  230. package/src/provider/sdk/openai-compatible/src/responses/tool/local-shell.ts +65 -0
  231. package/src/provider/sdk/openai-compatible/src/responses/tool/web-search-preview.ts +104 -0
  232. package/src/provider/sdk/openai-compatible/src/responses/tool/web-search.ts +103 -0
  233. package/src/provider/transform.ts +455 -0
  234. package/src/pty/index.ts +231 -0
  235. package/src/security/guardrails.test.ts +341 -0
  236. package/src/security/guardrails.ts +570 -0
  237. package/src/security/index.ts +19 -0
  238. package/src/server/error.ts +36 -0
  239. package/src/server/project.ts +79 -0
  240. package/src/server/server.ts +2641 -0
  241. package/src/server/tui.ts +71 -0
  242. package/src/session/compaction.ts +228 -0
  243. package/src/session/index.ts +464 -0
  244. package/src/session/llm.ts +201 -0
  245. package/src/session/message-v2.ts +695 -0
  246. package/src/session/message.ts +189 -0
  247. package/src/session/processor.ts +409 -0
  248. package/src/session/prompt/act-switch.txt +5 -0
  249. package/src/session/prompt/anthropic-20250930.txt +166 -0
  250. package/src/session/prompt/anthropic.txt +63 -0
  251. package/src/session/prompt/anthropic_spoof.txt +1 -0
  252. package/src/session/prompt/beast.txt +76 -0
  253. package/src/session/prompt/codex.txt +304 -0
  254. package/src/session/prompt/copilot-gpt-5.txt +137 -0
  255. package/src/session/prompt/gemini.txt +62 -0
  256. package/src/session/prompt/max-steps.txt +16 -0
  257. package/src/session/prompt/plan-reminder-anthropic.txt +35 -0
  258. package/src/session/prompt/plan.txt +24 -0
  259. package/src/session/prompt/polaris.txt +88 -0
  260. package/src/session/prompt/qwen.txt +59 -0
  261. package/src/session/prompt.ts +1552 -0
  262. package/src/session/retry.ts +86 -0
  263. package/src/session/revert.ts +108 -0
  264. package/src/session/sensitive-filter.test.ts +327 -0
  265. package/src/session/sensitive-filter.ts +466 -0
  266. package/src/session/status.ts +76 -0
  267. package/src/session/summary.ts +209 -0
  268. package/src/session/system.ts +122 -0
  269. package/src/session/todo.ts +37 -0
  270. package/src/share/share-next.ts +222 -0
  271. package/src/share/share.ts +87 -0
  272. package/src/shell/shell.ts +67 -0
  273. package/src/skill/index.ts +1 -0
  274. package/src/skill/skill.ts +83 -0
  275. package/src/snapshot/index.ts +197 -0
  276. package/src/storage/storage.ts +226 -0
  277. package/src/tests/agent.test.ts +308 -0
  278. package/src/tests/build-guards.test.ts +267 -0
  279. package/src/tests/config.test.ts +664 -0
  280. package/src/tests/tool-registry.test.ts +589 -0
  281. package/src/tool/bash.ts +314 -0
  282. package/src/tool/bash.txt +158 -0
  283. package/src/tool/batch.ts +175 -0
  284. package/src/tool/batch.txt +24 -0
  285. package/src/tool/codesearch.ts +184 -0
  286. package/src/tool/codesearch.txt +12 -0
  287. package/src/tool/edit.ts +675 -0
  288. package/src/tool/edit.txt +10 -0
  289. package/src/tool/glob.ts +65 -0
  290. package/src/tool/glob.txt +6 -0
  291. package/src/tool/grep.ts +121 -0
  292. package/src/tool/grep.txt +8 -0
  293. package/src/tool/invalid.ts +17 -0
  294. package/src/tool/ls.ts +110 -0
  295. package/src/tool/ls.txt +1 -0
  296. package/src/tool/lsp-diagnostics.ts +26 -0
  297. package/src/tool/lsp-diagnostics.txt +1 -0
  298. package/src/tool/lsp-hover.ts +31 -0
  299. package/src/tool/lsp-hover.txt +1 -0
  300. package/src/tool/lsp.ts +87 -0
  301. package/src/tool/lsp.txt +19 -0
  302. package/src/tool/multiedit.ts +46 -0
  303. package/src/tool/multiedit.txt +41 -0
  304. package/src/tool/patch.ts +233 -0
  305. package/src/tool/patch.txt +1 -0
  306. package/src/tool/read.ts +219 -0
  307. package/src/tool/read.txt +12 -0
  308. package/src/tool/registry.ts +162 -0
  309. package/src/tool/skill.ts +100 -0
  310. package/src/tool/task.ts +136 -0
  311. package/src/tool/task.txt +51 -0
  312. package/src/tool/todo.ts +39 -0
  313. package/src/tool/todoread.txt +14 -0
  314. package/src/tool/todowrite.txt +167 -0
  315. package/src/tool/tool.ts +71 -0
  316. package/src/tool/webfetch.ts +198 -0
  317. package/src/tool/webfetch.txt +13 -0
  318. package/src/tool/websearch.ts +268 -0
  319. package/src/tool/websearch.txt +13 -0
  320. package/src/tool/write.ts +110 -0
  321. package/src/tool/write.txt +8 -0
  322. package/src/util/archive.ts +16 -0
  323. package/src/util/color.ts +19 -0
  324. package/src/util/context.ts +25 -0
  325. package/src/util/defer.ts +12 -0
  326. package/src/util/eventloop.ts +20 -0
  327. package/src/util/filesystem.ts +83 -0
  328. package/src/util/fn.ts +11 -0
  329. package/src/util/iife.ts +3 -0
  330. package/src/util/keybind.ts +102 -0
  331. package/src/util/lazy.ts +11 -0
  332. package/src/util/license.ts +362 -0
  333. package/src/util/locale.ts +81 -0
  334. package/src/util/lock.ts +98 -0
  335. package/src/util/log.ts +180 -0
  336. package/src/util/queue.ts +32 -0
  337. package/src/util/rpc.ts +42 -0
  338. package/src/util/scrap.ts +10 -0
  339. package/src/util/signal.ts +12 -0
  340. package/src/util/timeout.ts +14 -0
  341. package/src/util/token.ts +7 -0
  342. package/src/util/wildcard.ts +54 -0
  343. package/sst-env.d.ts +9 -0
  344. package/test/agent/agent.test.ts +146 -0
  345. package/test/bun.test.ts +53 -0
  346. package/test/cli/cmd/acp.test.ts +144 -0
  347. package/test/cli/cmd/run.test.ts +250 -0
  348. package/test/cli/github-remote.test.ts +80 -0
  349. package/test/config/agent-color.test.ts +66 -0
  350. package/test/config/config.test.ts +536 -0
  351. package/test/config/markdown.test.ts +89 -0
  352. package/test/file/ignore.test.ts +10 -0
  353. package/test/fixture/fixture.ts +37 -0
  354. package/test/fixture/lsp/fake-lsp-server.js +77 -0
  355. package/test/helpers.ts +172 -0
  356. package/test/ide/ide.test.ts +82 -0
  357. package/test/installation/installation.test.ts +143 -0
  358. package/test/keybind.test.ts +421 -0
  359. package/test/lsp/client.test.ts +95 -0
  360. package/test/mcp/headers.test.ts +153 -0
  361. package/test/patch/patch.test.ts +348 -0
  362. package/test/preload.ts +57 -0
  363. package/test/project/project.test.ts +74 -0
  364. package/test/provider/provider.test.ts +74 -0
  365. package/test/provider/transform.test.ts +411 -0
  366. package/test/session/retry.test.ts +111 -0
  367. package/test/session/session.test.ts +71 -0
  368. package/test/skill/skill.test.ts +131 -0
  369. package/test/snapshot/snapshot.test.ts +940 -0
  370. package/test/tool/__snapshots__/tool.test.ts.snap +9 -0
  371. package/test/tool/bash.test.ts +434 -0
  372. package/test/tool/grep.test.ts +108 -0
  373. package/test/tool/patch.test.ts +259 -0
  374. package/test/tool/read.test.ts +42 -0
  375. package/test/util/iife.test.ts +36 -0
  376. package/test/util/lazy.test.ts +50 -0
  377. package/test/util/license.test.ts +235 -0
  378. package/test/util/timeout.test.ts +21 -0
  379. package/test/util/wildcard.test.ts +55 -0
  380. package/tsconfig.json +16 -0
  381. package/update-versions.ps1 +65 -0
@@ -0,0 +1,144 @@
1
+ import { test, expect, describe, beforeEach, afterEach } from "bun:test"
2
+ import path from "path"
3
+ import { tmpdir } from "../../fixture/fixture"
4
+ import { Instance } from "../../../src/project/instance"
5
+
6
+ describe("ACP Command", () => {
7
+ test("should have acp command defined with correct options", async () => {
8
+ // Import the ACP command to verify it's defined
9
+ const { AcpCommand } = await import("../../../src/cli/cmd/acp")
10
+
11
+ expect(AcpCommand).toBeDefined()
12
+ expect(AcpCommand.command).toBe("acp")
13
+ expect(AcpCommand.describe).toContain("ACP")
14
+ expect(AcpCommand.describe).toContain("Agent Client Protocol")
15
+ })
16
+
17
+ test("acp command should have port option", async () => {
18
+ const { AcpCommand } = await import("../../../src/cli/cmd/acp")
19
+
20
+ // Verify the builder sets up port option
21
+ expect(AcpCommand.builder).toBeDefined()
22
+
23
+ // The builder is a function that sets up yargs
24
+ // We test that it's callable
25
+ let hasPortOption = false
26
+ let hasHostnameOption = false
27
+
28
+ // Mock yargs to capture builder calls
29
+ const mockYargs = {
30
+ option: (name: string) => {
31
+ if (name === "port") hasPortOption = true
32
+ if (name === "hostname") hasHostnameOption = true
33
+ return mockYargs
34
+ },
35
+ }
36
+
37
+ if (typeof AcpCommand.builder === "function") {
38
+ AcpCommand.builder(mockYargs as any)
39
+ }
40
+
41
+ expect(hasPortOption).toBe(true)
42
+ expect(hasHostnameOption).toBe(true)
43
+ })
44
+
45
+ test("acp command handler should be async function", async () => {
46
+ const { AcpCommand } = await import("../../../src/cli/cmd/acp")
47
+
48
+ expect(AcpCommand.handler).toBeDefined()
49
+ expect(typeof AcpCommand.handler).toBe("function")
50
+
51
+ // Verify it's async
52
+ const result = AcpCommand.handler({
53
+ cwd: process.cwd(),
54
+ port: 0,
55
+ hostname: "127.0.0.1",
56
+ _: [],
57
+ $0: "",
58
+ } as any)
59
+
60
+ expect(result).toBeInstanceOf(Promise)
61
+ })
62
+
63
+ test("acp command should accept custom working directory", async () => {
64
+ await using tmp = await tmpdir()
65
+
66
+ const { AcpCommand } = await import("../../../src/cli/cmd/acp")
67
+
68
+ expect(AcpCommand.builder).toBeDefined()
69
+
70
+ // Verify cwd option exists by checking the builder
71
+ let cwdOptionFound = false
72
+ const mockYargs = {
73
+ option: (name: string, config: any) => {
74
+ if (name === "cwd") {
75
+ cwdOptionFound = true
76
+ expect(config.describe).toContain("working directory")
77
+ expect(config.type).toBe("string")
78
+ }
79
+ return mockYargs
80
+ },
81
+ }
82
+
83
+ if (typeof AcpCommand.builder === "function") {
84
+ AcpCommand.builder(mockYargs as any)
85
+ }
86
+
87
+ expect(cwdOptionFound).toBe(true)
88
+ })
89
+
90
+ test("acp command should support custom port", async () => {
91
+ const { AcpCommand } = await import("../../../src/cli/cmd/acp")
92
+
93
+ let portConfig: any = null
94
+ const mockYargs = {
95
+ option: (name: string, config: any) => {
96
+ if (name === "port") {
97
+ portConfig = config
98
+ }
99
+ return mockYargs
100
+ },
101
+ }
102
+
103
+ if (typeof AcpCommand.builder === "function") {
104
+ AcpCommand.builder(mockYargs as any)
105
+ }
106
+
107
+ expect(portConfig).toBeDefined()
108
+ expect(portConfig.type).toBe("number")
109
+ expect(portConfig.default).toBe(0) // 0 means auto-assign
110
+ })
111
+
112
+ test("acp command should have default hostname", async () => {
113
+ const { AcpCommand } = await import("../../../src/cli/cmd/acp")
114
+
115
+ let hostnameConfig: any = null
116
+ const mockYargs = {
117
+ option: (name: string, config: any) => {
118
+ if (name === "hostname") {
119
+ hostnameConfig = config
120
+ }
121
+ return mockYargs
122
+ },
123
+ }
124
+
125
+ if (typeof AcpCommand.builder === "function") {
126
+ AcpCommand.builder(mockYargs as any)
127
+ }
128
+
129
+ expect(hostnameConfig).toBeDefined()
130
+ expect(hostnameConfig.type).toBe("string")
131
+ expect(hostnameConfig.default).toBe("127.0.0.1")
132
+ })
133
+
134
+ test("acp command handler should unhandled rejection handler", async () => {
135
+ const { AcpCommand } = await import("../../../src/cli/cmd/acp")
136
+
137
+ // Verify there's error handling for unhandled rejections
138
+ expect(AcpCommand).toBeDefined()
139
+
140
+ // The module should have set up unhandledRejection listener
141
+ const listeners = process.listeners("unhandledRejection")
142
+ expect(listeners.length).toBeGreaterThan(0)
143
+ })
144
+ })
@@ -0,0 +1,250 @@
1
+ import { test, expect, describe, beforeEach, afterEach } from "bun:test"
2
+ import path from "path"
3
+ import { tmpdir } from "../../fixture/fixture"
4
+ import { mockEnv } from "../../helpers"
5
+
6
+ describe("Run Command", () => {
7
+ let restoreEnv: (() => void) | undefined
8
+
9
+ beforeEach(() => {
10
+ // Setup test environment
11
+ })
12
+
13
+ afterEach(() => {
14
+ if (restoreEnv) {
15
+ restoreEnv()
16
+ }
17
+ })
18
+
19
+ test("should have run command defined", async () => {
20
+ const { RunCommand } = await import("../../../src/cli/cmd/run")
21
+
22
+ expect(RunCommand).toBeDefined()
23
+ expect(RunCommand.command).toBe("run [message..]")
24
+ expect(RunCommand.describe).toContain("run rird")
25
+ })
26
+
27
+ test("run command should accept message positional argument", async () => {
28
+ const { RunCommand } = await import("../../../src/cli/cmd/run")
29
+
30
+ let messagePositionFound = false
31
+ const mockYargs = {
32
+ positional: (name: string, config: any) => {
33
+ if (name === "message") {
34
+ messagePositionFound = true
35
+ expect(config.type).toBe("string")
36
+ expect(config.array).toBe(true)
37
+ }
38
+ return mockYargs
39
+ },
40
+ option: () => mockYargs,
41
+ }
42
+
43
+ if (typeof RunCommand.builder === "function") {
44
+ RunCommand.builder(mockYargs as any)
45
+ }
46
+
47
+ expect(messagePositionFound).toBe(true)
48
+ })
49
+
50
+ test("run command should have model option", async () => {
51
+ const { RunCommand } = await import("../../../src/cli/cmd/run")
52
+
53
+ let modelOptionFound = false
54
+ const mockYargs = {
55
+ positional: () => mockYargs,
56
+ option: (name: string, config: any) => {
57
+ if (name === "model") {
58
+ modelOptionFound = true
59
+ expect(config.type).toBe("string")
60
+ expect(config.alias).toContain("m")
61
+ }
62
+ return mockYargs
63
+ },
64
+ }
65
+
66
+ if (typeof RunCommand.builder === "function") {
67
+ RunCommand.builder(mockYargs as any)
68
+ }
69
+
70
+ expect(modelOptionFound).toBe(true)
71
+ })
72
+
73
+ test("run command should have session options", async () => {
74
+ const { RunCommand } = await import("../../../src/cli/cmd/run")
75
+
76
+ let sessionOptionFound = false
77
+ let continueOptionFound = false
78
+
79
+ const mockYargs = {
80
+ positional: () => mockYargs,
81
+ option: (name: string, config: any) => {
82
+ if (name === "session") {
83
+ sessionOptionFound = true
84
+ expect(config.type).toBe("string")
85
+ expect(config.alias).toContain("s")
86
+ }
87
+ if (name === "continue") {
88
+ continueOptionFound = true
89
+ expect(config.type).toBe("boolean")
90
+ }
91
+ return mockYargs
92
+ },
93
+ }
94
+
95
+ if (typeof RunCommand.builder === "function") {
96
+ RunCommand.builder(mockYargs as any)
97
+ }
98
+
99
+ expect(sessionOptionFound).toBe(true)
100
+ expect(continueOptionFound).toBe(true)
101
+ })
102
+
103
+ test("run command should have file option", async () => {
104
+ const { RunCommand } = await import("../../../src/cli/cmd/run")
105
+
106
+ let fileOptionFound = false
107
+ const mockYargs = {
108
+ positional: () => mockYargs,
109
+ option: (name: string, config: any) => {
110
+ if (name === "file") {
111
+ fileOptionFound = true
112
+ expect(config.type).toBe("string")
113
+ expect(config.array).toBe(true)
114
+ }
115
+ return mockYargs
116
+ },
117
+ }
118
+
119
+ if (typeof RunCommand.builder === "function") {
120
+ RunCommand.builder(mockYargs as any)
121
+ }
122
+
123
+ expect(fileOptionFound).toBe(true)
124
+ })
125
+
126
+ test("run command should have title option", async () => {
127
+ const { RunCommand } = await import("../../../src/cli/cmd/run")
128
+
129
+ let titleOptionFound = false
130
+ const mockYargs = {
131
+ positional: () => mockYargs,
132
+ option: (name: string, config: any) => {
133
+ if (name === "title") {
134
+ titleOptionFound = true
135
+ expect(config.type).toBe("string")
136
+ }
137
+ return mockYargs
138
+ },
139
+ }
140
+
141
+ if (typeof RunCommand.builder === "function") {
142
+ RunCommand.builder(mockYargs as any)
143
+ }
144
+
145
+ expect(titleOptionFound).toBe(true)
146
+ })
147
+
148
+ test("run command should support format option", async () => {
149
+ const { RunCommand } = await import("../../../src/cli/cmd/run")
150
+
151
+ let formatOptionFound = false
152
+ const mockYargs = {
153
+ positional: () => mockYargs,
154
+ option: (name: string, config: any) => {
155
+ if (name === "format") {
156
+ formatOptionFound = true
157
+ expect(config.type).toBe("string")
158
+ expect(config.choices).toContain("default")
159
+ expect(config.choices).toContain("json")
160
+ }
161
+ return mockYargs
162
+ },
163
+ }
164
+
165
+ if (typeof RunCommand.builder === "function") {
166
+ RunCommand.builder(mockYargs as any)
167
+ }
168
+
169
+ expect(formatOptionFound).toBe(true)
170
+ })
171
+
172
+ test("run command should have handler function", async () => {
173
+ const { RunCommand } = await import("../../../src/cli/cmd/run")
174
+
175
+ expect(RunCommand.handler).toBeDefined()
176
+ expect(typeof RunCommand.handler).toBe("function")
177
+ })
178
+
179
+ test("run command builder should return yargs instance", async () => {
180
+ const { RunCommand } = await import("../../../src/cli/cmd/run")
181
+
182
+ expect(typeof RunCommand.builder === "function").toBe(true)
183
+ })
184
+
185
+ test("run command should support agent option", async () => {
186
+ const { RunCommand } = await import("../../../src/cli/cmd/run")
187
+
188
+ let agentOptionFound = false
189
+ const mockYargs = {
190
+ positional: () => mockYargs,
191
+ option: (name: string, config: any) => {
192
+ if (name === "agent") {
193
+ agentOptionFound = true
194
+ expect(config.type).toBe("string")
195
+ }
196
+ return mockYargs
197
+ },
198
+ }
199
+
200
+ if (typeof RunCommand.builder === "function") {
201
+ RunCommand.builder(mockYargs as any)
202
+ }
203
+
204
+ expect(agentOptionFound).toBe(true)
205
+ })
206
+
207
+ test("run command should support share option", async () => {
208
+ const { RunCommand } = await import("../../../src/cli/cmd/run")
209
+
210
+ let shareOptionFound = false
211
+ const mockYargs = {
212
+ positional: () => mockYargs,
213
+ option: (name: string, config: any) => {
214
+ if (name === "share") {
215
+ shareOptionFound = true
216
+ expect(config.type).toBe("boolean")
217
+ }
218
+ return mockYargs
219
+ },
220
+ }
221
+
222
+ if (typeof RunCommand.builder === "function") {
223
+ RunCommand.builder(mockYargs as any)
224
+ }
225
+
226
+ expect(shareOptionFound).toBe(true)
227
+ })
228
+
229
+ test("run command should have command option", async () => {
230
+ const { RunCommand } = await import("../../../src/cli/cmd/run")
231
+
232
+ let commandOptionFound = false
233
+ const mockYargs = {
234
+ positional: () => mockYargs,
235
+ option: (name: string, config: any) => {
236
+ if (name === "command") {
237
+ commandOptionFound = true
238
+ expect(config.type).toBe("string")
239
+ }
240
+ return mockYargs
241
+ },
242
+ }
243
+
244
+ if (typeof RunCommand.builder === "function") {
245
+ RunCommand.builder(mockYargs as any)
246
+ }
247
+
248
+ expect(commandOptionFound).toBe(true)
249
+ })
250
+ })
@@ -0,0 +1,80 @@
1
+ import { test, expect } from "bun:test"
2
+ import { parseGitHubRemote } from "../../src/cli/cmd/github"
3
+
4
+ test("parses https URL with .git suffix", () => {
5
+ expect(parseGitHubRemote("https://github.com/sst/opencode.git")).toEqual({ owner: "sst", repo: "opencode" })
6
+ })
7
+
8
+ test("parses https URL without .git suffix", () => {
9
+ expect(parseGitHubRemote("https://github.com/sst/opencode")).toEqual({ owner: "sst", repo: "opencode" })
10
+ })
11
+
12
+ test("parses git@ URL with .git suffix", () => {
13
+ expect(parseGitHubRemote("git@github.com:sst/opencode.git")).toEqual({ owner: "sst", repo: "opencode" })
14
+ })
15
+
16
+ test("parses git@ URL without .git suffix", () => {
17
+ expect(parseGitHubRemote("git@github.com:sst/opencode")).toEqual({ owner: "sst", repo: "opencode" })
18
+ })
19
+
20
+ test("parses ssh:// URL with .git suffix", () => {
21
+ expect(parseGitHubRemote("ssh://git@github.com/sst/opencode.git")).toEqual({ owner: "sst", repo: "opencode" })
22
+ })
23
+
24
+ test("parses ssh:// URL without .git suffix", () => {
25
+ expect(parseGitHubRemote("ssh://git@github.com/sst/opencode")).toEqual({ owner: "sst", repo: "opencode" })
26
+ })
27
+
28
+ test("parses http URL", () => {
29
+ expect(parseGitHubRemote("http://github.com/owner/repo")).toEqual({ owner: "owner", repo: "repo" })
30
+ })
31
+
32
+ test("parses URL with hyphenated owner and repo names", () => {
33
+ expect(parseGitHubRemote("https://github.com/my-org/my-repo.git")).toEqual({ owner: "my-org", repo: "my-repo" })
34
+ })
35
+
36
+ test("parses URL with underscores in names", () => {
37
+ expect(parseGitHubRemote("git@github.com:my_org/my_repo.git")).toEqual({ owner: "my_org", repo: "my_repo" })
38
+ })
39
+
40
+ test("parses URL with numbers in names", () => {
41
+ expect(parseGitHubRemote("https://github.com/org123/repo456")).toEqual({ owner: "org123", repo: "repo456" })
42
+ })
43
+
44
+ test("parses repos with dots in the name", () => {
45
+ expect(parseGitHubRemote("https://github.com/socketio/socket.io.git")).toEqual({
46
+ owner: "socketio",
47
+ repo: "socket.io",
48
+ })
49
+ expect(parseGitHubRemote("https://github.com/vuejs/vue.js")).toEqual({
50
+ owner: "vuejs",
51
+ repo: "vue.js",
52
+ })
53
+ expect(parseGitHubRemote("git@github.com:mrdoob/three.js.git")).toEqual({
54
+ owner: "mrdoob",
55
+ repo: "three.js",
56
+ })
57
+ expect(parseGitHubRemote("https://github.com/jashkenas/backbone.git")).toEqual({
58
+ owner: "jashkenas",
59
+ repo: "backbone",
60
+ })
61
+ })
62
+
63
+ test("returns null for non-github URLs", () => {
64
+ expect(parseGitHubRemote("https://gitlab.com/owner/repo.git")).toBeNull()
65
+ expect(parseGitHubRemote("git@gitlab.com:owner/repo.git")).toBeNull()
66
+ expect(parseGitHubRemote("https://bitbucket.org/owner/repo")).toBeNull()
67
+ })
68
+
69
+ test("returns null for invalid URLs", () => {
70
+ expect(parseGitHubRemote("not-a-url")).toBeNull()
71
+ expect(parseGitHubRemote("")).toBeNull()
72
+ expect(parseGitHubRemote("github.com")).toBeNull()
73
+ expect(parseGitHubRemote("https://github.com/")).toBeNull()
74
+ expect(parseGitHubRemote("https://github.com/owner")).toBeNull()
75
+ })
76
+
77
+ test("returns null for URLs with extra path segments", () => {
78
+ expect(parseGitHubRemote("https://github.com/owner/repo/tree/main")).toBeNull()
79
+ expect(parseGitHubRemote("https://github.com/owner/repo/blob/main/file.ts")).toBeNull()
80
+ })
@@ -0,0 +1,66 @@
1
+ import { test, expect } from "bun:test"
2
+ import path from "path"
3
+ import { tmpdir } from "../fixture/fixture"
4
+ import { Instance } from "../../src/project/instance"
5
+ import { Config } from "../../src/config/config"
6
+ import { Agent as AgentSvc } from "../../src/agent/agent"
7
+ import { Color } from "../../src/util/color"
8
+
9
+ test("agent color parsed from project config", async () => {
10
+ await using tmp = await tmpdir({
11
+ init: async (dir) => {
12
+ await Bun.write(
13
+ path.join(dir, "opencode.json"),
14
+ JSON.stringify({
15
+ $schema: "https://rird.ai/config.json",
16
+ agent: {
17
+ act: { color: "#FFA500" },
18
+ },
19
+ }),
20
+ )
21
+ },
22
+ })
23
+ await Instance.provide({
24
+ directory: tmp.path,
25
+ fn: async () => {
26
+ const cfg = await Config.get()
27
+ expect(cfg.agent?.["act"]?.color).toBe("#FFA500")
28
+ },
29
+ })
30
+ })
31
+
32
+ test("Agent.get includes color from config", async () => {
33
+ await using tmp = await tmpdir({
34
+ init: async (dir) => {
35
+ await Bun.write(
36
+ path.join(dir, "opencode.json"),
37
+ JSON.stringify({
38
+ $schema: "https://rird.ai/config.json",
39
+ agent: {
40
+ plan: { color: "#A855F7" },
41
+ },
42
+ }),
43
+ )
44
+ },
45
+ })
46
+ await Instance.provide({
47
+ directory: tmp.path,
48
+ fn: async () => {
49
+ const plan = await AgentSvc.get("plan")
50
+ expect(plan?.color).toBe("#A855F7")
51
+ },
52
+ })
53
+ })
54
+
55
+ test("Color.hexToAnsiBold converts valid hex to ANSI", () => {
56
+ const result = Color.hexToAnsiBold("#FFA500")
57
+ expect(result).toBe("\x1b[38;2;255;165;0m\x1b[1m")
58
+ })
59
+
60
+ test("Color.hexToAnsiBold returns undefined for invalid hex", () => {
61
+ expect(Color.hexToAnsiBold(undefined)).toBeUndefined()
62
+ expect(Color.hexToAnsiBold("")).toBeUndefined()
63
+ expect(Color.hexToAnsiBold("#FFF")).toBeUndefined()
64
+ expect(Color.hexToAnsiBold("FFA500")).toBeUndefined()
65
+ expect(Color.hexToAnsiBold("#GGGGGG")).toBeUndefined()
66
+ })