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.
- package/AGENTS.md +86 -0
- package/COMPLETED_TEST_SUITE.txt +280 -0
- package/Dockerfile +18 -0
- package/README.md +397 -6
- package/RIRD_ERROR_HANDLING_SUMMARY.md +307 -0
- package/TESTING.md +512 -0
- package/TEST_IMPLEMENTATION_REPORT.md +463 -0
- package/TEST_SUITE.md +307 -0
- package/TEST_SUMMARY.txt +380 -0
- package/bin/rird-perf.js +37 -0
- package/bin/rird.js +43 -8
- package/bunfig.toml +4 -0
- package/create-wrapper.ps1 +51 -0
- package/docs/ARCHITECTURE.md +768 -0
- package/docs/CLI_REFERENCE.md +681 -0
- package/docs/DOCUMENTATION_MANIFEST.md +392 -0
- package/docs/INDEX.md +295 -0
- package/docs/PRODUCTION_SETUP.md +633 -0
- package/docs/TROUBLESHOOTING.md +914 -0
- package/facebook_ads_library.png +0 -0
- package/nul +0 -0
- package/nul`nif +0 -0
- package/package.json +104 -15
- package/parsers-config.ts +239 -0
- package/rird-1.0.199.tgz +0 -0
- package/rird-1.0.205.tgz +0 -0
- package/script/build-windows.ts +56 -0
- package/script/build.ts +165 -0
- package/{postinstall.mjs → script/postinstall.mjs} +47 -68
- package/script/publish-registries.ts +187 -0
- package/script/publish.ts +85 -0
- package/script/schema.ts +47 -0
- package/src/acp/README.md +164 -0
- package/src/acp/agent.ts +1063 -0
- package/src/acp/session.ts +101 -0
- package/src/acp/types.ts +22 -0
- package/src/agent/agent.ts +367 -0
- package/src/agent/generate.txt +75 -0
- package/src/agent/prompt/compaction.txt +12 -0
- package/src/agent/prompt/explore.txt +18 -0
- package/src/agent/prompt/summary.txt +10 -0
- package/src/agent/prompt/title.txt +36 -0
- package/src/auth/index.ts +70 -0
- package/src/bun/index.ts +114 -0
- package/src/bus/bus-event.ts +43 -0
- package/src/bus/global.ts +10 -0
- package/src/bus/index.ts +105 -0
- package/src/cli/bootstrap.ts +17 -0
- package/src/cli/cmd/acp.ts +104 -0
- package/src/cli/cmd/activate.ts +50 -0
- package/src/cli/cmd/agent.ts +256 -0
- package/src/cli/cmd/auth.ts +412 -0
- package/src/cli/cmd/cmd.ts +7 -0
- package/src/cli/cmd/debug/config.ts +15 -0
- package/src/cli/cmd/debug/file.ts +91 -0
- package/src/cli/cmd/debug/index.ts +43 -0
- package/src/cli/cmd/debug/lsp.ts +48 -0
- package/src/cli/cmd/debug/ripgrep.ts +83 -0
- package/src/cli/cmd/debug/scrap.ts +15 -0
- package/src/cli/cmd/debug/skill.ts +15 -0
- package/src/cli/cmd/debug/snapshot.ts +48 -0
- package/src/cli/cmd/export.ts +88 -0
- package/src/cli/cmd/generate.ts +38 -0
- package/src/cli/cmd/github.ts +1400 -0
- package/src/cli/cmd/import.ts +98 -0
- package/src/cli/cmd/mcp.ts +654 -0
- package/src/cli/cmd/models.ts +68 -0
- package/src/cli/cmd/pr.ts +112 -0
- package/src/cli/cmd/run.ts +434 -0
- package/src/cli/cmd/serve.ts +31 -0
- package/src/cli/cmd/session.ts +106 -0
- package/src/cli/cmd/stats.ts +298 -0
- package/src/cli/cmd/tui/app.tsx +694 -0
- package/src/cli/cmd/tui/attach.ts +30 -0
- package/src/cli/cmd/tui/component/border.tsx +21 -0
- package/src/cli/cmd/tui/component/dialog-agent.tsx +31 -0
- package/src/cli/cmd/tui/component/dialog-command.tsx +124 -0
- package/src/cli/cmd/tui/component/dialog-mcp.tsx +86 -0
- package/src/cli/cmd/tui/component/dialog-model.tsx +236 -0
- package/src/cli/cmd/tui/component/dialog-provider.tsx +240 -0
- package/src/cli/cmd/tui/component/dialog-session-list.tsx +102 -0
- package/src/cli/cmd/tui/component/dialog-session-rename.tsx +31 -0
- package/src/cli/cmd/tui/component/dialog-stash.tsx +86 -0
- package/src/cli/cmd/tui/component/dialog-status.tsx +162 -0
- package/src/cli/cmd/tui/component/dialog-tag.tsx +44 -0
- package/src/cli/cmd/tui/component/dialog-theme-list.tsx +50 -0
- package/src/cli/cmd/tui/component/did-you-know.tsx +85 -0
- package/src/cli/cmd/tui/component/logo.tsx +48 -0
- package/src/cli/cmd/tui/component/prompt/autocomplete.tsx +574 -0
- package/src/cli/cmd/tui/component/prompt/history.tsx +108 -0
- package/src/cli/cmd/tui/component/prompt/index.tsx +1087 -0
- package/src/cli/cmd/tui/component/prompt/stash.tsx +101 -0
- package/src/cli/cmd/tui/component/tips.ts +27 -0
- package/src/cli/cmd/tui/component/todo-item.tsx +32 -0
- package/src/cli/cmd/tui/context/args.tsx +14 -0
- package/src/cli/cmd/tui/context/directory.ts +13 -0
- package/src/cli/cmd/tui/context/exit.tsx +23 -0
- package/src/cli/cmd/tui/context/helper.tsx +25 -0
- package/src/cli/cmd/tui/context/keybind.tsx +101 -0
- package/src/cli/cmd/tui/context/kv.tsx +49 -0
- package/src/cli/cmd/tui/context/local.tsx +345 -0
- package/src/cli/cmd/tui/context/prompt.tsx +18 -0
- package/src/cli/cmd/tui/context/route.tsx +46 -0
- package/src/cli/cmd/tui/context/sdk.tsx +74 -0
- package/src/cli/cmd/tui/context/sync.tsx +372 -0
- package/src/cli/cmd/tui/context/theme/aura.json +69 -0
- package/src/cli/cmd/tui/context/theme/ayu.json +80 -0
- package/src/cli/cmd/tui/context/theme/catppuccin-frappe.json +233 -0
- package/src/cli/cmd/tui/context/theme/catppuccin-macchiato.json +233 -0
- package/src/cli/cmd/tui/context/theme/catppuccin.json +112 -0
- package/src/cli/cmd/tui/context/theme/cobalt2.json +228 -0
- package/src/cli/cmd/tui/context/theme/cursor.json +249 -0
- package/src/cli/cmd/tui/context/theme/dracula.json +219 -0
- package/src/cli/cmd/tui/context/theme/everforest.json +241 -0
- package/src/cli/cmd/tui/context/theme/flexoki.json +237 -0
- package/src/cli/cmd/tui/context/theme/github.json +233 -0
- package/src/cli/cmd/tui/context/theme/gruvbox.json +95 -0
- package/src/cli/cmd/tui/context/theme/kanagawa.json +77 -0
- package/src/cli/cmd/tui/context/theme/lucent-orng.json +227 -0
- package/src/cli/cmd/tui/context/theme/material.json +235 -0
- package/src/cli/cmd/tui/context/theme/matrix.json +77 -0
- package/src/cli/cmd/tui/context/theme/mercury.json +252 -0
- package/src/cli/cmd/tui/context/theme/monokai.json +221 -0
- package/src/cli/cmd/tui/context/theme/nightowl.json +221 -0
- package/src/cli/cmd/tui/context/theme/nord.json +223 -0
- package/src/cli/cmd/tui/context/theme/one-dark.json +84 -0
- package/src/cli/cmd/tui/context/theme/orng.json +245 -0
- package/src/cli/cmd/tui/context/theme/palenight.json +222 -0
- package/src/cli/cmd/tui/context/theme/rird.json +245 -0
- package/src/cli/cmd/tui/context/theme/rosepine.json +234 -0
- package/src/cli/cmd/tui/context/theme/solarized.json +223 -0
- package/src/cli/cmd/tui/context/theme/synthwave84.json +226 -0
- package/src/cli/cmd/tui/context/theme/tokyonight.json +243 -0
- package/src/cli/cmd/tui/context/theme/vercel.json +245 -0
- package/src/cli/cmd/tui/context/theme/vesper.json +218 -0
- package/src/cli/cmd/tui/context/theme/zenburn.json +223 -0
- package/src/cli/cmd/tui/context/theme.tsx +1109 -0
- package/src/cli/cmd/tui/event.ts +40 -0
- package/src/cli/cmd/tui/hooks/use-safe-terminal-dimensions.ts +12 -0
- package/src/cli/cmd/tui/routes/home.tsx +138 -0
- package/src/cli/cmd/tui/routes/session/dialog-fork-from-timeline.tsx +64 -0
- package/src/cli/cmd/tui/routes/session/dialog-message.tsx +109 -0
- package/src/cli/cmd/tui/routes/session/dialog-subagent.tsx +26 -0
- package/src/cli/cmd/tui/routes/session/dialog-timeline.tsx +47 -0
- package/src/cli/cmd/tui/routes/session/footer.tsx +88 -0
- package/src/cli/cmd/tui/routes/session/header.tsx +125 -0
- package/src/cli/cmd/tui/routes/session/index.tsx +1876 -0
- package/src/cli/cmd/tui/routes/session/sidebar.tsx +320 -0
- package/src/cli/cmd/tui/spawn.ts +60 -0
- package/src/cli/cmd/tui/thread.ts +142 -0
- package/src/cli/cmd/tui/ui/dialog-alert.tsx +57 -0
- package/src/cli/cmd/tui/ui/dialog-confirm.tsx +83 -0
- package/src/cli/cmd/tui/ui/dialog-help.tsx +38 -0
- package/src/cli/cmd/tui/ui/dialog-prompt.tsx +77 -0
- package/src/cli/cmd/tui/ui/dialog-select.tsx +333 -0
- package/src/cli/cmd/tui/ui/dialog.tsx +171 -0
- package/src/cli/cmd/tui/ui/spinner.ts +368 -0
- package/src/cli/cmd/tui/ui/toast.tsx +100 -0
- package/src/cli/cmd/tui/util/clipboard.ts +127 -0
- package/src/cli/cmd/tui/util/editor.ts +32 -0
- package/src/cli/cmd/tui/util/terminal.ts +146 -0
- package/src/cli/cmd/tui/worker.ts +63 -0
- package/src/cli/cmd/uninstall.ts +344 -0
- package/src/cli/cmd/upgrade.ts +127 -0
- package/src/cli/cmd/web.ts +84 -0
- package/src/cli/error.ts +69 -0
- package/src/cli/ui.ts +101 -0
- package/src/cli/upgrade.ts +28 -0
- package/src/command/index.ts +80 -0
- package/src/command/template/initialize.txt +10 -0
- package/src/command/template/review.txt +97 -0
- package/src/config/config.ts +994 -0
- package/src/config/markdown.ts +41 -0
- package/src/env/index.ts +26 -0
- package/src/file/ignore.ts +83 -0
- package/src/file/index.ts +328 -0
- package/src/file/ripgrep.ts +393 -0
- package/src/file/time.ts +64 -0
- package/src/file/watcher.ts +103 -0
- package/src/flag/flag.ts +84 -0
- package/src/format/formatter.ts +315 -0
- package/src/format/index.ts +137 -0
- package/src/global/index.ts +101 -0
- package/src/id/id.ts +73 -0
- package/src/ide/index.ts +76 -0
- package/src/index.ts +297 -0
- package/src/index.ts.backup +271 -0
- package/src/installation/index.ts +258 -0
- package/src/lib/IMPLEMENTATION_NOTES.md +345 -0
- package/src/lib/error-handler.ts +225 -0
- package/src/lib/error-testing-guide.md +258 -0
- package/src/lib/errors.ts +285 -0
- package/src/lib/performance.ts +70 -0
- package/src/lib/telemetry.ts +282 -0
- package/src/lsp/client.ts +229 -0
- package/src/lsp/index.ts +485 -0
- package/src/lsp/language.ts +116 -0
- package/src/lsp/server.ts +1895 -0
- package/src/mcp/auth.ts +135 -0
- package/src/mcp/index.ts +1117 -0
- package/src/mcp/intent-analyzer.ts +376 -0
- package/src/mcp/oauth-callback.ts +200 -0
- package/src/mcp/oauth-provider.ts +154 -0
- package/src/patch/index.ts +632 -0
- package/src/permission/index.ts +199 -0
- package/src/plugin/index.ts +91 -0
- package/src/project/bootstrap.ts +33 -0
- package/src/project/instance.ts +78 -0
- package/src/project/project.ts +236 -0
- package/src/project/state.ts +65 -0
- package/src/project/vcs.ts +76 -0
- package/src/provider/auth.ts +143 -0
- package/src/provider/models-macro.ts +55 -0
- package/src/provider/models.ts +161 -0
- package/src/provider/provider.ts +1109 -0
- package/src/provider/sdk/openai-compatible/src/README.md +5 -0
- package/src/provider/sdk/openai-compatible/src/index.ts +2 -0
- package/src/provider/sdk/openai-compatible/src/openai-compatible-provider.ts +100 -0
- package/src/provider/sdk/openai-compatible/src/responses/convert-to-openai-responses-input.ts +303 -0
- package/src/provider/sdk/openai-compatible/src/responses/map-openai-responses-finish-reason.ts +22 -0
- package/src/provider/sdk/openai-compatible/src/responses/openai-config.ts +18 -0
- package/src/provider/sdk/openai-compatible/src/responses/openai-error.ts +22 -0
- package/src/provider/sdk/openai-compatible/src/responses/openai-responses-api-types.ts +207 -0
- package/src/provider/sdk/openai-compatible/src/responses/openai-responses-language-model.ts +1713 -0
- package/src/provider/sdk/openai-compatible/src/responses/openai-responses-prepare-tools.ts +177 -0
- package/src/provider/sdk/openai-compatible/src/responses/openai-responses-settings.ts +1 -0
- package/src/provider/sdk/openai-compatible/src/responses/tool/code-interpreter.ts +88 -0
- package/src/provider/sdk/openai-compatible/src/responses/tool/file-search.ts +128 -0
- package/src/provider/sdk/openai-compatible/src/responses/tool/image-generation.ts +115 -0
- package/src/provider/sdk/openai-compatible/src/responses/tool/local-shell.ts +65 -0
- package/src/provider/sdk/openai-compatible/src/responses/tool/web-search-preview.ts +104 -0
- package/src/provider/sdk/openai-compatible/src/responses/tool/web-search.ts +103 -0
- package/src/provider/transform.ts +455 -0
- package/src/pty/index.ts +231 -0
- package/src/security/guardrails.test.ts +341 -0
- package/src/security/guardrails.ts +570 -0
- package/src/security/index.ts +19 -0
- package/src/server/error.ts +36 -0
- package/src/server/project.ts +79 -0
- package/src/server/server.ts +2641 -0
- package/src/server/tui.ts +71 -0
- package/src/session/compaction.ts +228 -0
- package/src/session/index.ts +464 -0
- package/src/session/llm.ts +201 -0
- package/src/session/message-v2.ts +695 -0
- package/src/session/message.ts +189 -0
- package/src/session/processor.ts +409 -0
- package/src/session/prompt/act-switch.txt +5 -0
- package/src/session/prompt/anthropic-20250930.txt +166 -0
- package/src/session/prompt/anthropic.txt +63 -0
- package/src/session/prompt/anthropic_spoof.txt +1 -0
- package/src/session/prompt/beast.txt +76 -0
- package/src/session/prompt/codex.txt +304 -0
- package/src/session/prompt/copilot-gpt-5.txt +137 -0
- package/src/session/prompt/gemini.txt +62 -0
- package/src/session/prompt/max-steps.txt +16 -0
- package/src/session/prompt/plan-reminder-anthropic.txt +35 -0
- package/src/session/prompt/plan.txt +24 -0
- package/src/session/prompt/polaris.txt +88 -0
- package/src/session/prompt/qwen.txt +59 -0
- package/src/session/prompt.ts +1552 -0
- package/src/session/retry.ts +86 -0
- package/src/session/revert.ts +108 -0
- package/src/session/sensitive-filter.test.ts +327 -0
- package/src/session/sensitive-filter.ts +466 -0
- package/src/session/status.ts +76 -0
- package/src/session/summary.ts +209 -0
- package/src/session/system.ts +122 -0
- package/src/session/todo.ts +37 -0
- package/src/share/share-next.ts +222 -0
- package/src/share/share.ts +87 -0
- package/src/shell/shell.ts +67 -0
- package/src/skill/index.ts +1 -0
- package/src/skill/skill.ts +83 -0
- package/src/snapshot/index.ts +197 -0
- package/src/storage/storage.ts +226 -0
- package/src/tests/agent.test.ts +308 -0
- package/src/tests/build-guards.test.ts +267 -0
- package/src/tests/config.test.ts +664 -0
- package/src/tests/tool-registry.test.ts +589 -0
- package/src/tool/bash.ts +314 -0
- package/src/tool/bash.txt +158 -0
- package/src/tool/batch.ts +175 -0
- package/src/tool/batch.txt +24 -0
- package/src/tool/codesearch.ts +184 -0
- package/src/tool/codesearch.txt +12 -0
- package/src/tool/edit.ts +675 -0
- package/src/tool/edit.txt +10 -0
- package/src/tool/glob.ts +65 -0
- package/src/tool/glob.txt +6 -0
- package/src/tool/grep.ts +121 -0
- package/src/tool/grep.txt +8 -0
- package/src/tool/invalid.ts +17 -0
- package/src/tool/ls.ts +110 -0
- package/src/tool/ls.txt +1 -0
- package/src/tool/lsp-diagnostics.ts +26 -0
- package/src/tool/lsp-diagnostics.txt +1 -0
- package/src/tool/lsp-hover.ts +31 -0
- package/src/tool/lsp-hover.txt +1 -0
- package/src/tool/lsp.ts +87 -0
- package/src/tool/lsp.txt +19 -0
- package/src/tool/multiedit.ts +46 -0
- package/src/tool/multiedit.txt +41 -0
- package/src/tool/patch.ts +233 -0
- package/src/tool/patch.txt +1 -0
- package/src/tool/read.ts +219 -0
- package/src/tool/read.txt +12 -0
- package/src/tool/registry.ts +162 -0
- package/src/tool/skill.ts +100 -0
- package/src/tool/task.ts +136 -0
- package/src/tool/task.txt +51 -0
- package/src/tool/todo.ts +39 -0
- package/src/tool/todoread.txt +14 -0
- package/src/tool/todowrite.txt +167 -0
- package/src/tool/tool.ts +71 -0
- package/src/tool/webfetch.ts +198 -0
- package/src/tool/webfetch.txt +13 -0
- package/src/tool/websearch.ts +268 -0
- package/src/tool/websearch.txt +13 -0
- package/src/tool/write.ts +110 -0
- package/src/tool/write.txt +8 -0
- package/src/util/archive.ts +16 -0
- package/src/util/color.ts +19 -0
- package/src/util/context.ts +25 -0
- package/src/util/defer.ts +12 -0
- package/src/util/eventloop.ts +20 -0
- package/src/util/filesystem.ts +83 -0
- package/src/util/fn.ts +11 -0
- package/src/util/iife.ts +3 -0
- package/src/util/keybind.ts +102 -0
- package/src/util/lazy.ts +11 -0
- package/src/util/license.ts +362 -0
- package/src/util/locale.ts +81 -0
- package/src/util/lock.ts +98 -0
- package/src/util/log.ts +180 -0
- package/src/util/queue.ts +32 -0
- package/src/util/rpc.ts +42 -0
- package/src/util/scrap.ts +10 -0
- package/src/util/signal.ts +12 -0
- package/src/util/timeout.ts +14 -0
- package/src/util/token.ts +7 -0
- package/src/util/wildcard.ts +54 -0
- package/sst-env.d.ts +9 -0
- package/test/agent/agent.test.ts +146 -0
- package/test/bun.test.ts +53 -0
- package/test/cli/cmd/acp.test.ts +144 -0
- package/test/cli/cmd/run.test.ts +250 -0
- package/test/cli/github-remote.test.ts +80 -0
- package/test/config/agent-color.test.ts +66 -0
- package/test/config/config.test.ts +536 -0
- package/test/config/markdown.test.ts +89 -0
- package/test/file/ignore.test.ts +10 -0
- package/test/fixture/fixture.ts +37 -0
- package/test/fixture/lsp/fake-lsp-server.js +77 -0
- package/test/helpers.ts +172 -0
- package/test/ide/ide.test.ts +82 -0
- package/test/installation/installation.test.ts +143 -0
- package/test/keybind.test.ts +421 -0
- package/test/lsp/client.test.ts +95 -0
- package/test/mcp/headers.test.ts +153 -0
- package/test/patch/patch.test.ts +348 -0
- package/test/preload.ts +57 -0
- package/test/project/project.test.ts +74 -0
- package/test/provider/provider.test.ts +74 -0
- package/test/provider/transform.test.ts +411 -0
- package/test/session/retry.test.ts +111 -0
- package/test/session/session.test.ts +71 -0
- package/test/skill/skill.test.ts +131 -0
- package/test/snapshot/snapshot.test.ts +940 -0
- package/test/tool/__snapshots__/tool.test.ts.snap +9 -0
- package/test/tool/bash.test.ts +434 -0
- package/test/tool/grep.test.ts +108 -0
- package/test/tool/patch.test.ts +259 -0
- package/test/tool/read.test.ts +42 -0
- package/test/util/iife.test.ts +36 -0
- package/test/util/lazy.test.ts +50 -0
- package/test/util/license.test.ts +235 -0
- package/test/util/timeout.test.ts +21 -0
- package/test/util/wildcard.test.ts +55 -0
- package/tsconfig.json +16 -0
- 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
|