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,258 @@
1
+ import { BusEvent } from "@/bus/bus-event"
2
+ import path from "path"
3
+ import { $ } from "bun"
4
+ import z from "zod"
5
+ import { NamedError } from "@opencode-ai/util/error"
6
+ import { Log } from "../util/log"
7
+ import { iife } from "@/util/iife"
8
+ import { Flag } from "../flag/flag"
9
+
10
+ declare global {
11
+ const RIRD_VERSION: string
12
+ const RIRD_CHANNEL: string
13
+ }
14
+
15
+ export namespace Installation {
16
+ const log = Log.create({ service: "installation" })
17
+
18
+ export type Method = Awaited<ReturnType<typeof method>>
19
+
20
+ export const Event = {
21
+ Updated: BusEvent.define(
22
+ "installation.updated",
23
+ z.object({
24
+ version: z.string(),
25
+ }),
26
+ ),
27
+ UpdateAvailable: BusEvent.define(
28
+ "installation.update-available",
29
+ z.object({
30
+ version: z.string(),
31
+ }),
32
+ ),
33
+ UpdateFailed: BusEvent.define(
34
+ "installation.update-failed",
35
+ z.object({
36
+ version: z.string(),
37
+ error: z.string(),
38
+ }),
39
+ ),
40
+ }
41
+
42
+ export const Info = z
43
+ .object({
44
+ version: z.string(),
45
+ latest: z.string(),
46
+ })
47
+ .meta({
48
+ ref: "InstallationInfo",
49
+ })
50
+ export type Info = z.infer<typeof Info>
51
+
52
+ export async function info() {
53
+ return {
54
+ version: VERSION,
55
+ latest: await latest(),
56
+ }
57
+ }
58
+
59
+ export function isPreview() {
60
+ return CHANNEL !== "latest"
61
+ }
62
+
63
+ export function isLocal() {
64
+ return CHANNEL === "local"
65
+ }
66
+
67
+ export async function method() {
68
+ if (process.execPath.includes(path.join(".rird", "bin"))) return "curl"
69
+ if (process.execPath.includes(path.join(".local", "bin"))) return "curl"
70
+ const exec = process.execPath.toLowerCase()
71
+
72
+ const COMMAND_TIMEOUT = 2000 // 2 second timeout per command
73
+
74
+ async function withTimeout<T>(promise: Promise<T>): Promise<T> {
75
+ return Promise.race([
76
+ promise,
77
+ new Promise<T>((_, reject) =>
78
+ setTimeout(() => reject(new Error("timeout")), COMMAND_TIMEOUT)
79
+ ),
80
+ ])
81
+ }
82
+
83
+ const checks = [
84
+ {
85
+ name: "npm" as const,
86
+ command: () => withTimeout($`npm list -g --depth=0`.throws(false).quiet().text()).catch(() => ""),
87
+ },
88
+ {
89
+ name: "yarn" as const,
90
+ command: () => withTimeout($`yarn global list`.throws(false).quiet().text()).catch(() => ""),
91
+ },
92
+ {
93
+ name: "pnpm" as const,
94
+ command: () => withTimeout($`pnpm list -g --depth=0`.throws(false).quiet().text()).catch(() => ""),
95
+ },
96
+ {
97
+ name: "bun" as const,
98
+ command: () => withTimeout($`bun pm ls -g`.throws(false).quiet().text()).catch(() => ""),
99
+ },
100
+ {
101
+ name: "brew" as const,
102
+ command: () => withTimeout($`brew list --formula rird`.throws(false).quiet().text()).catch(() => ""),
103
+ },
104
+ ]
105
+
106
+ checks.sort((a, b) => {
107
+ const aMatches = exec.includes(a.name)
108
+ const bMatches = exec.includes(b.name)
109
+ if (aMatches && !bMatches) return -1
110
+ if (!aMatches && bMatches) return 1
111
+ return 0
112
+ })
113
+
114
+ for (const check of checks) {
115
+ const output = await check.command()
116
+ if (output.includes("rird")) {
117
+ return check.name
118
+ }
119
+ }
120
+
121
+ return "unknown"
122
+ }
123
+
124
+ export const UpgradeFailedError = NamedError.create(
125
+ "UpgradeFailedError",
126
+ z.object({
127
+ stderr: z.string(),
128
+ }),
129
+ )
130
+
131
+ async function getBrewFormula() {
132
+ const tapFormula = await $`brew list --formula sst/tap/rird`.throws(false).quiet().text()
133
+ if (tapFormula.includes("rird")) return "sst/tap/rird"
134
+ const coreFormula = await $`brew list --formula rird`.throws(false).quiet().text()
135
+ if (coreFormula.includes("rird")) return "rird"
136
+ return "rird"
137
+ }
138
+
139
+ export async function upgrade(method: Method, target: string) {
140
+ let cmd
141
+ switch (method) {
142
+ case "curl":
143
+ cmd = $`curl -fsSL https://rird.ai/install.sh | bash`.env({
144
+ ...process.env,
145
+ VERSION: target,
146
+ })
147
+ break
148
+ case "npm":
149
+ cmd = $`npm install -g rird-ai@${target}`
150
+ break
151
+ case "pnpm":
152
+ cmd = $`pnpm install -g rird-ai@${target}`
153
+ break
154
+ case "bun":
155
+ cmd = $`bun install -g rird-ai@${target}`
156
+ break
157
+ case "brew": {
158
+ const formula = await getBrewFormula()
159
+ cmd = $`brew install ${formula}`.env({
160
+ HOMEBREW_NO_AUTO_UPDATE: "1",
161
+ ...process.env,
162
+ })
163
+ break
164
+ }
165
+ case "unknown":
166
+ // Unknown install method - try force reinstall with multiple package managers
167
+ log.info("unknown install method, attempting force reinstall")
168
+ return forceReinstall()
169
+ default:
170
+ throw new Error(`Unknown method: ${method}`)
171
+ }
172
+ const result = await cmd.quiet().throws(false)
173
+ log.info("upgraded", {
174
+ method,
175
+ target,
176
+ stdout: result.stdout.toString(),
177
+ stderr: result.stderr.toString(),
178
+ })
179
+ if (result.exitCode !== 0)
180
+ throw new UpgradeFailedError({
181
+ stderr: result.stderr.toString("utf8"),
182
+ })
183
+ }
184
+
185
+ export const VERSION = typeof RIRD_VERSION === "string" ? RIRD_VERSION : "local"
186
+ export const CHANNEL = typeof RIRD_CHANNEL === "string" ? RIRD_CHANNEL : "local"
187
+ export const USER_AGENT = `rird/${CHANNEL}/${VERSION}/${Flag.RIRD_CLIENT}`
188
+
189
+ // Package names to try in order (handles legacy installs with wrong package name)
190
+ // rird-ai is the main package, others are for legacy compatibility
191
+ const NPM_PACKAGE_NAMES = ["rird-ai", "rird", "rird-cli"]
192
+
193
+ async function fetchLatestFromNpm(registry: string, channel: string): Promise<string> {
194
+ for (const pkgName of NPM_PACKAGE_NAMES) {
195
+ try {
196
+ const res = await fetch(`${registry}/${pkgName}`)
197
+ if (res.ok) {
198
+ const data = await res.json()
199
+ return data["dist-tags"][channel] || data["dist-tags"].latest
200
+ }
201
+ } catch {
202
+ // Try next package name
203
+ }
204
+ }
205
+ throw new Error(`Could not find package on npm registry. Tried: ${NPM_PACKAGE_NAMES.join(", ")}`)
206
+ }
207
+
208
+ export async function latest(installMethod?: Method) {
209
+ const detectedMethod = installMethod || (await method())
210
+ if (detectedMethod === "brew") {
211
+ const formula = await getBrewFormula()
212
+ if (formula === "rird") {
213
+ return fetch("https://formulae.brew.sh/api/formula/rird.json")
214
+ .then((res) => {
215
+ if (!res.ok) throw new Error(res.statusText)
216
+ return res.json()
217
+ })
218
+ .then((data: any) => data.versions.stable)
219
+ }
220
+ }
221
+
222
+ const registry = await iife(async () => {
223
+ const r = (await $`npm config get registry`.quiet().nothrow().text()).trim()
224
+ const reg = r || "https://registry.npmjs.org"
225
+ return reg.endsWith("/") ? reg.slice(0, -1) : reg
226
+ })
227
+ // Always check the "latest" tag for version updates
228
+ const channel = "latest"
229
+ return fetchLatestFromNpm(registry, channel)
230
+ }
231
+
232
+ // Force reinstall when normal upgrade fails (handles broken legacy installs)
233
+ export async function forceReinstall(): Promise<void> {
234
+ log.info("attempting force reinstall")
235
+
236
+ // Try multiple package managers in order of preference
237
+ const attempts = [
238
+ { name: "bun", cmd: () => $`bun install -g rird-ai@latest` },
239
+ { name: "npm", cmd: () => $`npm install -g rird-ai@latest` },
240
+ { name: "pnpm", cmd: () => $`pnpm install -g rird-ai@latest` },
241
+ ]
242
+ for (const attempt of attempts) {
243
+ try {
244
+ const result = await attempt.cmd().quiet().throws(false)
245
+ if (result.exitCode === 0) {
246
+ log.info("force reinstall succeeded", { method: attempt.name })
247
+ return
248
+ }
249
+ } catch {
250
+ // Try next method
251
+ }
252
+ }
253
+
254
+ throw new UpgradeFailedError({
255
+ stderr: "Force reinstall failed. Please run manually: npm install -g rird-ai@latest",
256
+ })
257
+ }
258
+ }
@@ -0,0 +1,345 @@
1
+ # RIRD Error Handling Implementation Notes
2
+
3
+ ## Architecture Overview
4
+
5
+ The error handling system is built on three pillars:
6
+
7
+ ### 1. Error Types (errors.ts)
8
+ - Custom RirdError base class extending Error
9
+ - 12 specialized error subclasses for specific scenarios
10
+ - Each error includes: code, statusCode, suggestion, details, originalError
11
+
12
+ ### 2. Error Handlers (error-handler.ts)
13
+ - Central handleError() function for error processing
14
+ - Utility functions: withErrorHandling, withTimeout, withRetry
15
+ - Global handlers for uncaught exceptions and rejections
16
+ - Graceful shutdown support
17
+
18
+ ### 3. Integration Points
19
+ - Commands use error classes (run.ts, acp.ts, upgrade.ts)
20
+ - Binary wrapper catches global errors (bin/rird.js)
21
+ - Telemetry logging via Log.create()
22
+
23
+ ## Design Decisions
24
+
25
+ ### Why Custom Error Classes?
26
+
27
+ 1. **Type Safety**: TypeScript catches wrong error types at compile time
28
+ 2. **Structured Data**: Error codes, status codes, suggestions are structured
29
+ 3. **Consistent Format**: All errors follow same message format
30
+ 4. **Easy Filtering**: Telemetry can filter by error type or code
31
+ 5. **User Experience**: Suggestions help users fix issues faster
32
+
33
+ ### Why Separate Utility Functions?
34
+
35
+ 1. **Composability**: withRetry + withTimeout can be combined
36
+ 2. **Reusability**: withRetry works with any async function
37
+ 3. **Single Responsibility**: Each function does one thing well
38
+ 4. **Testing**: Easy to mock/test individual utilities
39
+ 5. **Flexibility**: Users can create custom wrappers
40
+
41
+ ### Why Global Error Handlers?
42
+
43
+ 1. **Safety Net**: Catches errors that slip through try/catch
44
+ 2. **Consistency**: All errors follow same format
45
+ 3. **Support References**: Every error gets unique ID for tracking
46
+ 4. **Debugging**: Stack traces captured for investigation
47
+ 5. **Graceful Exit**: Proper exit codes and cleanup
48
+
49
+ ## Implementation Patterns
50
+
51
+ ### Pattern 1: Try/Catch with Custom Error
52
+
53
+ ```typescript
54
+ try {
55
+ const file = await loadFile(path)
56
+ } catch (error) {
57
+ throw new FileSystemError(`Failed to load file: ${path}`, {
58
+ code: "FILE_LOAD_FAILED",
59
+ originalError: error as Error,
60
+ details: { path }
61
+ })
62
+ }
63
+ ```
64
+
65
+ ### Pattern 2: With Timeout
66
+
67
+ ```typescript
68
+ const response = await withTimeout(
69
+ networkCall(),
70
+ 30000,
71
+ "API request"
72
+ )
73
+ // Throws TimeoutError if takes >30 seconds
74
+ ```
75
+
76
+ ### Pattern 3: With Retry
77
+
78
+ ```typescript
79
+ const result = await withRetry(
80
+ () => apiCall(),
81
+ {
82
+ maxAttempts: 3,
83
+ initialDelayMs: 100,
84
+ backoffMultiplier: 2,
85
+ operationName: "API call"
86
+ }
87
+ )
88
+ // Retries with delays: 100ms, 200ms, 400ms
89
+ ```
90
+
91
+ ### Pattern 4: Handler Wrapping
92
+
93
+ ```typescript
94
+ handler: async (args) => {
95
+ try {
96
+ // Main logic
97
+ } catch (error) {
98
+ await handleError(error, "command-name", { exitOnError: true })
99
+ }
100
+ }
101
+ ```
102
+
103
+ ### Pattern 5: Global Setup
104
+
105
+ ```typescript
106
+ setupGlobalErrorHandlers()
107
+ setupGracefulShutdown(async () => {
108
+ await cleanup()
109
+ })
110
+ ```
111
+
112
+ ## Error Flow in Detail
113
+
114
+ ```
115
+ User runs: rird run --file /bad/path "task"
116
+
117
+ 1. Handler starts
118
+ 2. Try block entered
119
+ 3. File validation fails
120
+ 4. FileSystemError thrown with FILE_NOT_FOUND code
121
+ 5. Catch block catches it (bottom of handler)
122
+ 6. handleError() called:
123
+ a) RirdError detected
124
+ b) Log to telemetry:
125
+ - code: FILE_NOT_FOUND
126
+ - statusCode: 500
127
+ - message: File not found: /bad/path
128
+ - originalError: error details
129
+ c) Format error message for user:
130
+ Error [FILE_NOT_FOUND]: File not found: /bad/path
131
+ Suggestion: Check file permissions and disk space...
132
+ Details:
133
+ filePath: /bad/path
134
+ resolvedPath: /absolute/path
135
+
136
+ Support reference: FILE-1704394848-K9F2A
137
+ d) Exit with code 500
138
+ ```
139
+
140
+ ## Telemetry Integration
141
+
142
+ All errors logged with:
143
+
144
+ ```typescript
145
+ log.error("Error context", {
146
+ code: "ERROR_CODE",
147
+ statusCode: 500,
148
+ message: "User-facing message",
149
+ suggestion: "How to fix",
150
+ details: { /* context */ },
151
+ stack: "optional stack trace"
152
+ })
153
+ ```
154
+
155
+ This allows monitoring systems to:
156
+ - Alert on specific error codes
157
+ - Track error rates by type
158
+ - Group errors by status code
159
+ - Find error patterns
160
+ - Route to correct team
161
+
162
+ ## Testing Approach
163
+
164
+ ### Unit Tests (for error classes)
165
+ ```typescript
166
+ test("FileSystemError has correct code", () => {
167
+ const err = new FileSystemError("File not found")
168
+ expect(err.code).toBe("FILESYSTEM_ERROR")
169
+ expect(err.statusCode).toBe(500)
170
+ })
171
+ ```
172
+
173
+ ### Integration Tests (for handlers)
174
+ ```typescript
175
+ test("handleError logs and exits", async () => {
176
+ const logSpy = jest.spyOn(log, 'error')
177
+ await expect(handleError(new Error("Test"))).rejects.toThrow()
178
+ expect(logSpy).toHaveBeenCalled()
179
+ })
180
+ ```
181
+
182
+ ### Manual Tests (see error-testing-guide.md)
183
+ - Network disconnection
184
+ - File not found
185
+ - Invalid license
186
+ - Server startup failure
187
+ - Timeout scenarios
188
+
189
+ ## Performance Considerations
190
+
191
+ ### Overhead per Error
192
+ - Error creation: <0.1ms
193
+ - Logging: <0.5ms (async)
194
+ - Message formatting: <0.2ms
195
+ - **Total**: ~1ms per error (mostly async)
196
+
197
+ ### No Impact on Happy Path
198
+ - Success cases skip all error handling
199
+ - No try/catch overhead for sync code
200
+ - Global handlers don't interfere
201
+
202
+ ### Optimization Tips
203
+ 1. Suppress stack traces in production (already done)
204
+ 2. Use async logging to avoid blocking
205
+ 3. Batch telemetry writes (external service concern)
206
+ 4. Cache error message templates
207
+
208
+ ## Maintenance Guidelines
209
+
210
+ ### Adding New Error Type
211
+
212
+ 1. Create class in errors.ts:
213
+ ```typescript
214
+ export class NewError extends RirdError {
215
+ constructor(message: string, context: Partial<ErrorContext> = {}) {
216
+ super(message, {
217
+ code: "NEW_ERROR",
218
+ statusCode: 500,
219
+ suggestion: "How to fix this",
220
+ ...context,
221
+ })
222
+ Object.setPrototypeOf(this, NewError.prototype)
223
+ }
224
+ }
225
+ ```
226
+
227
+ 2. Export from errors.ts
228
+ 3. Use in commands:
229
+ ```typescript
230
+ throw new NewError("Something went wrong", {
231
+ details: { /* context */ }
232
+ })
233
+ ```
234
+
235
+ ### Adding New Handler Type
236
+
237
+ 1. Create in error-handler.ts:
238
+ ```typescript
239
+ export async function withNewHandling<T>(
240
+ operation: () => Promise<T>,
241
+ options: { /* options */ } = {}
242
+ ): Promise<T> {
243
+ try {
244
+ return await operation()
245
+ } catch (error) {
246
+ throw toRirdError(error, "NEW_HANDLING_ERROR")
247
+ }
248
+ }
249
+ ```
250
+
251
+ 2. Export from error-handler.ts
252
+ 3. Use in commands:
253
+ ```typescript
254
+ const result = await withNewHandling(async () => {
255
+ // operation
256
+ })
257
+ ```
258
+
259
+ ### Updating Error Messages
260
+
261
+ Error messages should be:
262
+ 1. **Clear**: What went wrong in plain English
263
+ 2. **Specific**: Not generic ("File not found" not "Error")
264
+ 3. **Actionable**: User can do something about it
265
+ 4. **Brief**: 1-2 sentences
266
+
267
+ ### Monitoring Error Codes
268
+
269
+ In production, monitor these signals:
270
+
271
+ 1. **Error Rate by Code**
272
+ - Alert if FILE_NOT_FOUND > 10/min (might be bad path in UI)
273
+ - Alert if NETWORK_ERROR > 5/min (infrastructure issue)
274
+
275
+ 2. **Error Trends**
276
+ - New error codes appearing (new bugs)
277
+ - Old error codes going away (fixes working)
278
+
279
+ 3. **User Impact**
280
+ - High status 400 errors = user mistakes (improve UX)
281
+ - High status 500 errors = server issues (fix backend)
282
+ - High status 503 errors = infrastructure (scale up)
283
+
284
+ ## Debugging Tips
285
+
286
+ ### Find Error by Support Reference
287
+ ```bash
288
+ grep "RIRD-1704394848" ~/.rird/logs/*.log
289
+ ```
290
+
291
+ ### View All Errors of Type
292
+ ```bash
293
+ grep "FILE_NOT_FOUND" ~/.rird/logs/*.log
294
+ ```
295
+
296
+ ### Count Errors by Code
297
+ ```bash
298
+ grep -o "\[.*\]:" ~/.rird/logs/*.log | sort | uniq -c
299
+ ```
300
+
301
+ ### Trace Error Chain
302
+ ```bash
303
+ # Check original error
304
+ grep -A5 "originalError:" ~/.rird/logs/*.log
305
+ ```
306
+
307
+ ## Security Considerations
308
+
309
+ 1. **No Sensitive Data in Errors**: Never log passwords, tokens, etc.
310
+ 2. **Stack Traces in Production**: Disabled by default (suppressStack)
311
+ 3. **Error Messages**: Generic enough not to leak system info
312
+ 4. **Support References**: Cannot be used to access/modify data
313
+ 5. **Telemetry**: Filtered for PII before sending
314
+
315
+ ## Backwards Compatibility
316
+
317
+ - All RirdError subclasses extend Error
318
+ - Code using generic catch works fine
319
+ - Old error messages still flow through
320
+ - Can gradually migrate to custom errors
321
+
322
+ ## Future Enhancements
323
+
324
+ 1. **Error Recovery**: Automatic recovery suggestions
325
+ 2. **Error Tracking**: Sentry/DataDog integration
326
+ 3. **Error Clustering**: Group similar errors
327
+ 4. **Error Analytics**: Dashboard of error trends
328
+ 5. **Error Context**: Breadcrumbs for debugging
329
+ 6. **Error Notifications**: Webhook alerts for critical errors
330
+
331
+ ## Related Files
332
+
333
+ - `errors.ts` - Custom error classes (200 lines)
334
+ - `error-handler.ts` - Error handling utilities (250 lines)
335
+ - `error-testing-guide.md` - Testing procedures
336
+ - `../cmd/run.ts` - Example usage (task execution)
337
+ - `../cmd/acp.ts` - Example usage (server)
338
+ - `../../bin/rird.js` - Binary wrapper error handlers
339
+
340
+ ## References
341
+
342
+ - TypeScript Error Handling: https://www.typescriptlang.org/docs/handbook/release-notes/typescript-4-0.html#error-handling
343
+ - Express Error Handling: https://expressjs.com/en/guide/error-handling.html
344
+ - Node.js Error Handling: https://nodejs.org/en/docs/guides/nodejs-error-handling/
345
+ - HTTP Status Codes: https://httpwg.org/specs/rfc9110.html#status.codes