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,285 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Custom error classes for RIRD CLI production error handling
|
|
3
|
+
* Provides structured error information with user-facing messages and error codes
|
|
4
|
+
*/
|
|
5
|
+
|
|
6
|
+
export interface ErrorContext {
|
|
7
|
+
code: string
|
|
8
|
+
statusCode: number
|
|
9
|
+
suggestion?: string
|
|
10
|
+
details?: Record<string, any>
|
|
11
|
+
originalError?: Error
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
/**
|
|
15
|
+
* Base RIRD error class with structure for production logging
|
|
16
|
+
*/
|
|
17
|
+
export class RirdError extends Error implements ErrorContext {
|
|
18
|
+
code: string
|
|
19
|
+
statusCode: number
|
|
20
|
+
suggestion?: string
|
|
21
|
+
details?: Record<string, any>
|
|
22
|
+
originalError?: Error
|
|
23
|
+
|
|
24
|
+
constructor(message: string, context: Partial<ErrorContext> = {}) {
|
|
25
|
+
super(message)
|
|
26
|
+
this.name = this.constructor.name
|
|
27
|
+
this.code = context.code || "RIRD_ERROR"
|
|
28
|
+
this.statusCode = context.statusCode || 500
|
|
29
|
+
this.suggestion = context.suggestion
|
|
30
|
+
this.details = context.details
|
|
31
|
+
this.originalError = context.originalError
|
|
32
|
+
|
|
33
|
+
// Maintain proper prototype chain
|
|
34
|
+
Object.setPrototypeOf(this, RirdError.prototype)
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
toJSON() {
|
|
38
|
+
return {
|
|
39
|
+
name: this.name,
|
|
40
|
+
message: this.message,
|
|
41
|
+
code: this.code,
|
|
42
|
+
statusCode: this.statusCode,
|
|
43
|
+
suggestion: this.suggestion,
|
|
44
|
+
details: this.details,
|
|
45
|
+
stack: this.stack,
|
|
46
|
+
}
|
|
47
|
+
}
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
/**
|
|
51
|
+
* Network-related errors (timeouts, connection failures)
|
|
52
|
+
*/
|
|
53
|
+
export class NetworkError extends RirdError {
|
|
54
|
+
constructor(message: string, context: Partial<ErrorContext> = {}) {
|
|
55
|
+
super(message, {
|
|
56
|
+
code: "NETWORK_ERROR",
|
|
57
|
+
statusCode: 503,
|
|
58
|
+
suggestion:
|
|
59
|
+
"Check your internet connection, firewall settings, or try again later",
|
|
60
|
+
...context,
|
|
61
|
+
})
|
|
62
|
+
Object.setPrototypeOf(this, NetworkError.prototype)
|
|
63
|
+
}
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
/**
|
|
67
|
+
* Provider/API errors (model not found, invalid endpoints, API failures)
|
|
68
|
+
*/
|
|
69
|
+
export class ProviderError extends RirdError {
|
|
70
|
+
constructor(message: string, context: Partial<ErrorContext> = {}) {
|
|
71
|
+
super(message, {
|
|
72
|
+
code: "PROVIDER_ERROR",
|
|
73
|
+
statusCode: 502,
|
|
74
|
+
suggestion:
|
|
75
|
+
"Verify your provider configuration and API credentials. Check rird status for details.",
|
|
76
|
+
...context,
|
|
77
|
+
})
|
|
78
|
+
Object.setPrototypeOf(this, ProviderError.prototype)
|
|
79
|
+
}
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
/**
|
|
83
|
+
* License/authentication errors
|
|
84
|
+
*/
|
|
85
|
+
export class LicenseError extends RirdError {
|
|
86
|
+
constructor(message: string, context: Partial<ErrorContext> = {}) {
|
|
87
|
+
super(message, {
|
|
88
|
+
code: "LICENSE_ERROR",
|
|
89
|
+
statusCode: 401,
|
|
90
|
+
suggestion: "Run 'rird activate <license-key>' to validate your license",
|
|
91
|
+
...context,
|
|
92
|
+
})
|
|
93
|
+
Object.setPrototypeOf(this, LicenseError.prototype)
|
|
94
|
+
}
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
/**
|
|
98
|
+
* Input validation errors
|
|
99
|
+
*/
|
|
100
|
+
export class ValidationError extends RirdError {
|
|
101
|
+
constructor(message: string, context: Partial<ErrorContext> = {}) {
|
|
102
|
+
super(message, {
|
|
103
|
+
code: "VALIDATION_ERROR",
|
|
104
|
+
statusCode: 400,
|
|
105
|
+
suggestion: "Check the provided inputs and try again",
|
|
106
|
+
...context,
|
|
107
|
+
})
|
|
108
|
+
Object.setPrototypeOf(this, ValidationError.prototype)
|
|
109
|
+
}
|
|
110
|
+
}
|
|
111
|
+
|
|
112
|
+
/**
|
|
113
|
+
* Configuration errors
|
|
114
|
+
*/
|
|
115
|
+
export class ConfigError extends RirdError {
|
|
116
|
+
constructor(message: string, context: Partial<ErrorContext> = {}) {
|
|
117
|
+
super(message, {
|
|
118
|
+
code: "CONFIG_ERROR",
|
|
119
|
+
statusCode: 500,
|
|
120
|
+
suggestion:
|
|
121
|
+
"Check your RIRD configuration file or run 'rird setup' to initialize",
|
|
122
|
+
...context,
|
|
123
|
+
})
|
|
124
|
+
Object.setPrototypeOf(this, ConfigError.prototype)
|
|
125
|
+
}
|
|
126
|
+
}
|
|
127
|
+
|
|
128
|
+
/**
|
|
129
|
+
* File system errors
|
|
130
|
+
*/
|
|
131
|
+
export class FileSystemError extends RirdError {
|
|
132
|
+
constructor(message: string, context: Partial<ErrorContext> = {}) {
|
|
133
|
+
super(message, {
|
|
134
|
+
code: "FILESYSTEM_ERROR",
|
|
135
|
+
statusCode: 500,
|
|
136
|
+
suggestion:
|
|
137
|
+
"Check file permissions and disk space. Ensure the file path is valid.",
|
|
138
|
+
...context,
|
|
139
|
+
})
|
|
140
|
+
Object.setPrototypeOf(this, FileSystemError.prototype)
|
|
141
|
+
}
|
|
142
|
+
}
|
|
143
|
+
|
|
144
|
+
/**
|
|
145
|
+
* Timeout errors
|
|
146
|
+
*/
|
|
147
|
+
export class TimeoutError extends RirdError {
|
|
148
|
+
constructor(message: string, context: Partial<ErrorContext> = {}) {
|
|
149
|
+
super(message, {
|
|
150
|
+
code: "TIMEOUT_ERROR",
|
|
151
|
+
statusCode: 504,
|
|
152
|
+
suggestion: "The operation took too long. Try again or increase timeout.",
|
|
153
|
+
...context,
|
|
154
|
+
})
|
|
155
|
+
Object.setPrototypeOf(this, TimeoutError.prototype)
|
|
156
|
+
}
|
|
157
|
+
}
|
|
158
|
+
|
|
159
|
+
/**
|
|
160
|
+
* Server/process errors
|
|
161
|
+
*/
|
|
162
|
+
export class ServerError extends RirdError {
|
|
163
|
+
constructor(message: string, context: Partial<ErrorContext> = {}) {
|
|
164
|
+
super(message, {
|
|
165
|
+
code: "SERVER_ERROR",
|
|
166
|
+
statusCode: 500,
|
|
167
|
+
suggestion:
|
|
168
|
+
"The RIRD server encountered an error. Check logs or try restarting.",
|
|
169
|
+
...context,
|
|
170
|
+
})
|
|
171
|
+
Object.setPrototypeOf(this, ServerError.prototype)
|
|
172
|
+
}
|
|
173
|
+
}
|
|
174
|
+
|
|
175
|
+
/**
|
|
176
|
+
* Installation/upgrade errors
|
|
177
|
+
*/
|
|
178
|
+
export class InstallationError extends RirdError {
|
|
179
|
+
constructor(message: string, context: Partial<ErrorContext> = {}) {
|
|
180
|
+
super(message, {
|
|
181
|
+
code: "INSTALLATION_ERROR",
|
|
182
|
+
statusCode: 500,
|
|
183
|
+
suggestion:
|
|
184
|
+
"Installation failed. Ensure you have proper permissions and dependencies installed.",
|
|
185
|
+
...context,
|
|
186
|
+
})
|
|
187
|
+
Object.setPrototypeOf(this, InstallationError.prototype)
|
|
188
|
+
}
|
|
189
|
+
}
|
|
190
|
+
|
|
191
|
+
/**
|
|
192
|
+
* Tool/command execution errors
|
|
193
|
+
*/
|
|
194
|
+
export class ToolError extends RirdError {
|
|
195
|
+
constructor(message: string, context: Partial<ErrorContext> = {}) {
|
|
196
|
+
super(message, {
|
|
197
|
+
code: "TOOL_ERROR",
|
|
198
|
+
statusCode: 500,
|
|
199
|
+
suggestion: "A tool execution failed. Check the error details above.",
|
|
200
|
+
...context,
|
|
201
|
+
})
|
|
202
|
+
Object.setPrototypeOf(this, ToolError.prototype)
|
|
203
|
+
}
|
|
204
|
+
}
|
|
205
|
+
|
|
206
|
+
/**
|
|
207
|
+
* Browser automation errors
|
|
208
|
+
*/
|
|
209
|
+
export class BrowserError extends RirdError {
|
|
210
|
+
constructor(message: string, context: Partial<ErrorContext> = {}) {
|
|
211
|
+
super(message, {
|
|
212
|
+
code: "BROWSER_ERROR",
|
|
213
|
+
statusCode: 500,
|
|
214
|
+
suggestion:
|
|
215
|
+
"Browser operation failed. Ensure no other instances are running and try again.",
|
|
216
|
+
...context,
|
|
217
|
+
})
|
|
218
|
+
Object.setPrototypeOf(this, BrowserError.prototype)
|
|
219
|
+
}
|
|
220
|
+
}
|
|
221
|
+
|
|
222
|
+
/**
|
|
223
|
+
* Type guard to check if an error is a RirdError
|
|
224
|
+
*/
|
|
225
|
+
export function isRirdError(error: unknown): error is RirdError {
|
|
226
|
+
return error instanceof RirdError
|
|
227
|
+
}
|
|
228
|
+
|
|
229
|
+
/**
|
|
230
|
+
* Convert any error to RirdError
|
|
231
|
+
*/
|
|
232
|
+
export function toRirdError(error: unknown, defaultCode = "UNKNOWN_ERROR"): RirdError {
|
|
233
|
+
if (isRirdError(error)) {
|
|
234
|
+
return error
|
|
235
|
+
}
|
|
236
|
+
|
|
237
|
+
if (error instanceof Error) {
|
|
238
|
+
// Check if this is a NamedError with data (e.g., Storage.NotFoundError)
|
|
239
|
+
const namedError = error as { data?: Record<string, unknown>; name?: string }
|
|
240
|
+
let message = error.message
|
|
241
|
+
let details: Record<string, unknown> | undefined
|
|
242
|
+
|
|
243
|
+
// NamedError stores its data in .data property
|
|
244
|
+
if (namedError.data && typeof namedError.data === "object") {
|
|
245
|
+
details = namedError.data as Record<string, unknown>
|
|
246
|
+
// Extract message from data if the error message is just the error name
|
|
247
|
+
if (namedError.data.message && typeof namedError.data.message === "string") {
|
|
248
|
+
message = namedError.data.message as string
|
|
249
|
+
} else if (error.message === error.name || !error.message) {
|
|
250
|
+
// Build a descriptive message from the data
|
|
251
|
+
message = `${error.name || defaultCode}: ${JSON.stringify(namedError.data)}`
|
|
252
|
+
}
|
|
253
|
+
}
|
|
254
|
+
|
|
255
|
+
return new RirdError(message, {
|
|
256
|
+
code: error.name || defaultCode,
|
|
257
|
+
originalError: error,
|
|
258
|
+
details,
|
|
259
|
+
})
|
|
260
|
+
}
|
|
261
|
+
|
|
262
|
+
return new RirdError(String(error), { code: defaultCode })
|
|
263
|
+
}
|
|
264
|
+
|
|
265
|
+
/**
|
|
266
|
+
* Format error for user-friendly display
|
|
267
|
+
*/
|
|
268
|
+
export function formatErrorMessage(error: RirdError): string {
|
|
269
|
+
const lines: string[] = []
|
|
270
|
+
|
|
271
|
+
lines.push(`Error [${error.code}]: ${error.message}`)
|
|
272
|
+
|
|
273
|
+
if (error.suggestion) {
|
|
274
|
+
lines.push(`Suggestion: ${error.suggestion}`)
|
|
275
|
+
}
|
|
276
|
+
|
|
277
|
+
if (error.details && Object.keys(error.details).length > 0) {
|
|
278
|
+
lines.push("Details:")
|
|
279
|
+
for (const [key, value] of Object.entries(error.details)) {
|
|
280
|
+
lines.push(` ${key}: ${JSON.stringify(value)}`)
|
|
281
|
+
}
|
|
282
|
+
}
|
|
283
|
+
|
|
284
|
+
return lines.join("\n")
|
|
285
|
+
}
|
|
@@ -0,0 +1,70 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Performance monitoring and profiling utilities for RIRD CLI
|
|
3
|
+
* Tracks startup time, command execution time, and memory usage
|
|
4
|
+
*/
|
|
5
|
+
|
|
6
|
+
const perfMarks = new Map<string, number>();
|
|
7
|
+
const startTime = Date.now();
|
|
8
|
+
|
|
9
|
+
export const Performance = {
|
|
10
|
+
/**
|
|
11
|
+
* Mark a performance checkpoint
|
|
12
|
+
*/
|
|
13
|
+
mark(label: string) {
|
|
14
|
+
const elapsed = Date.now() - startTime;
|
|
15
|
+
perfMarks.set(label, elapsed);
|
|
16
|
+
if (process.env.RIRD_PERF_DEBUG) {
|
|
17
|
+
console.error(`[${elapsed}ms] ${label}`);
|
|
18
|
+
}
|
|
19
|
+
},
|
|
20
|
+
|
|
21
|
+
/**
|
|
22
|
+
* Get elapsed time for a mark
|
|
23
|
+
*/
|
|
24
|
+
getTime(label: string): number | undefined {
|
|
25
|
+
return perfMarks.get(label);
|
|
26
|
+
},
|
|
27
|
+
|
|
28
|
+
/**
|
|
29
|
+
* Get elapsed time since startup
|
|
30
|
+
*/
|
|
31
|
+
elapsed(): number {
|
|
32
|
+
return Date.now() - startTime;
|
|
33
|
+
},
|
|
34
|
+
|
|
35
|
+
/**
|
|
36
|
+
* Get current memory usage in MB
|
|
37
|
+
*/
|
|
38
|
+
memoryUsage(): number {
|
|
39
|
+
const usage = process.memoryUsage();
|
|
40
|
+
return Math.round((usage.heapUsed / 1024 / 1024) * 100) / 100;
|
|
41
|
+
},
|
|
42
|
+
|
|
43
|
+
/**
|
|
44
|
+
* Report all performance metrics
|
|
45
|
+
*/
|
|
46
|
+
report(): Record<string, number> {
|
|
47
|
+
const report: Record<string, number> = {};
|
|
48
|
+
perfMarks.forEach((time, label) => {
|
|
49
|
+
report[label] = time;
|
|
50
|
+
});
|
|
51
|
+
report.total = Performance.elapsed();
|
|
52
|
+
report.memory_mb = Performance.memoryUsage();
|
|
53
|
+
return report;
|
|
54
|
+
},
|
|
55
|
+
|
|
56
|
+
/**
|
|
57
|
+
* Check if startup performance is acceptable
|
|
58
|
+
* Returns null if ok, error message if slow
|
|
59
|
+
*/
|
|
60
|
+
checkStartupPerformance(): string | null {
|
|
61
|
+
const total = Performance.elapsed();
|
|
62
|
+
if (total > 1000) {
|
|
63
|
+
return `Slow startup detected: ${total}ms (target: <1000ms)`;
|
|
64
|
+
}
|
|
65
|
+
return null;
|
|
66
|
+
},
|
|
67
|
+
};
|
|
68
|
+
|
|
69
|
+
// Mark startup
|
|
70
|
+
Performance.mark("startup");
|
|
@@ -0,0 +1,282 @@
|
|
|
1
|
+
import fs from "fs/promises"
|
|
2
|
+
import path from "path"
|
|
3
|
+
import { Global } from "../global"
|
|
4
|
+
import { Log } from "../util/log"
|
|
5
|
+
|
|
6
|
+
export namespace Telemetry {
|
|
7
|
+
const log = Log.create({ service: "telemetry" })
|
|
8
|
+
|
|
9
|
+
const TELEMETRY_DIR = path.join(Global.Path.log, "telemetry")
|
|
10
|
+
const ERROR_LOG_DIR = path.join(TELEMETRY_DIR, "errors")
|
|
11
|
+
const EVENT_LOG_DIR = path.join(TELEMETRY_DIR, "events")
|
|
12
|
+
const METRICS_LOG_DIR = path.join(TELEMETRY_DIR, "metrics")
|
|
13
|
+
|
|
14
|
+
const MAX_LOG_DAYS = 7
|
|
15
|
+
const MAX_LOGS_PER_DIR = 500
|
|
16
|
+
|
|
17
|
+
interface ErrorEntry {
|
|
18
|
+
timestamp: string
|
|
19
|
+
message: string
|
|
20
|
+
error?: string
|
|
21
|
+
stack?: string
|
|
22
|
+
context?: Record<string, any>
|
|
23
|
+
severity: "error" | "warning" | "critical"
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
interface EventEntry {
|
|
27
|
+
timestamp: string
|
|
28
|
+
name: string
|
|
29
|
+
properties?: Record<string, any>
|
|
30
|
+
duration?: number
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
interface MetricEntry {
|
|
34
|
+
timestamp: string
|
|
35
|
+
name: string
|
|
36
|
+
value: number
|
|
37
|
+
unit?: string
|
|
38
|
+
context?: Record<string, any>
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
async function ensureDirectories() {
|
|
42
|
+
try {
|
|
43
|
+
await Promise.all([
|
|
44
|
+
fs.mkdir(TELEMETRY_DIR, { recursive: true }),
|
|
45
|
+
fs.mkdir(ERROR_LOG_DIR, { recursive: true }),
|
|
46
|
+
fs.mkdir(EVENT_LOG_DIR, { recursive: true }),
|
|
47
|
+
fs.mkdir(METRICS_LOG_DIR, { recursive: true }),
|
|
48
|
+
])
|
|
49
|
+
} catch (e) {
|
|
50
|
+
log.warn("Failed to create telemetry directories", { error: e })
|
|
51
|
+
}
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
async function rotateOldLogs(dir: string) {
|
|
55
|
+
try {
|
|
56
|
+
const files = await fs.readdir(dir)
|
|
57
|
+
if (files.length > MAX_LOGS_PER_DIR) {
|
|
58
|
+
const filesToDelete = files.slice(0, files.length - MAX_LOGS_PER_DIR)
|
|
59
|
+
await Promise.all(
|
|
60
|
+
filesToDelete.map((file) =>
|
|
61
|
+
fs.unlink(path.join(dir, file)).catch(() => {})
|
|
62
|
+
)
|
|
63
|
+
)
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
// Also clean up logs older than MAX_LOG_DAYS
|
|
67
|
+
const now = Date.now()
|
|
68
|
+
const maxAge = MAX_LOG_DAYS * 24 * 60 * 60 * 1000
|
|
69
|
+
|
|
70
|
+
for (const file of files) {
|
|
71
|
+
const filePath = path.join(dir, file)
|
|
72
|
+
const stat = await fs.stat(filePath).catch(() => null)
|
|
73
|
+
if (stat && now - stat.mtimeMs > maxAge) {
|
|
74
|
+
await fs.unlink(filePath).catch(() => {})
|
|
75
|
+
}
|
|
76
|
+
}
|
|
77
|
+
} catch (e) {
|
|
78
|
+
log.warn("Failed to rotate old logs", { error: e })
|
|
79
|
+
}
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
async function writeLog(dir: string, filename: string, data: any) {
|
|
83
|
+
try {
|
|
84
|
+
await ensureDirectories()
|
|
85
|
+
const filePath = path.join(dir, filename)
|
|
86
|
+
const content = typeof data === "string" ? data : JSON.stringify(data)
|
|
87
|
+
await fs.appendFile(filePath, content + "\n")
|
|
88
|
+
await rotateOldLogs(dir)
|
|
89
|
+
} catch (e) {
|
|
90
|
+
log.warn("Failed to write telemetry log", { error: e, filename })
|
|
91
|
+
}
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
export async function logError(
|
|
95
|
+
message: string,
|
|
96
|
+
error?: Error | unknown,
|
|
97
|
+
context?: Record<string, any>
|
|
98
|
+
) {
|
|
99
|
+
const timestamp = new Date().toISOString()
|
|
100
|
+
const errorObj = error instanceof Error ? error : new Error(String(error))
|
|
101
|
+
|
|
102
|
+
const entry: ErrorEntry = {
|
|
103
|
+
timestamp,
|
|
104
|
+
message,
|
|
105
|
+
error: errorObj.message,
|
|
106
|
+
stack: errorObj.stack,
|
|
107
|
+
context,
|
|
108
|
+
severity: "error",
|
|
109
|
+
}
|
|
110
|
+
|
|
111
|
+
log.error(message, { error: errorObj, ...context })
|
|
112
|
+
await writeLog(
|
|
113
|
+
ERROR_LOG_DIR,
|
|
114
|
+
`errors-${new Date().toISOString().split("T")[0]}.jsonl`,
|
|
115
|
+
entry
|
|
116
|
+
)
|
|
117
|
+
}
|
|
118
|
+
|
|
119
|
+
export async function logWarning(
|
|
120
|
+
message: string,
|
|
121
|
+
context?: Record<string, any>
|
|
122
|
+
) {
|
|
123
|
+
const timestamp = new Date().toISOString()
|
|
124
|
+
const entry: ErrorEntry = {
|
|
125
|
+
timestamp,
|
|
126
|
+
message,
|
|
127
|
+
context,
|
|
128
|
+
severity: "warning",
|
|
129
|
+
}
|
|
130
|
+
|
|
131
|
+
log.warn(message, context)
|
|
132
|
+
await writeLog(
|
|
133
|
+
ERROR_LOG_DIR,
|
|
134
|
+
`warnings-${new Date().toISOString().split("T")[0]}.jsonl`,
|
|
135
|
+
entry
|
|
136
|
+
)
|
|
137
|
+
}
|
|
138
|
+
|
|
139
|
+
export async function logInfo(
|
|
140
|
+
message: string,
|
|
141
|
+
context?: Record<string, any>
|
|
142
|
+
) {
|
|
143
|
+
const timestamp = new Date().toISOString()
|
|
144
|
+
log.info(message, context)
|
|
145
|
+
}
|
|
146
|
+
|
|
147
|
+
export async function logDebug(
|
|
148
|
+
message: string,
|
|
149
|
+
context?: Record<string, any>
|
|
150
|
+
) {
|
|
151
|
+
const timestamp = new Date().toISOString()
|
|
152
|
+
log.debug(message, context)
|
|
153
|
+
}
|
|
154
|
+
|
|
155
|
+
export async function trackEvent(
|
|
156
|
+
name: string,
|
|
157
|
+
properties?: Record<string, any>,
|
|
158
|
+
duration?: number
|
|
159
|
+
) {
|
|
160
|
+
const timestamp = new Date().toISOString()
|
|
161
|
+
const entry: EventEntry = {
|
|
162
|
+
timestamp,
|
|
163
|
+
name,
|
|
164
|
+
properties,
|
|
165
|
+
duration,
|
|
166
|
+
}
|
|
167
|
+
|
|
168
|
+
log.info(`event:${name}`, properties)
|
|
169
|
+
await writeLog(
|
|
170
|
+
EVENT_LOG_DIR,
|
|
171
|
+
`events-${new Date().toISOString().split("T")[0]}.jsonl`,
|
|
172
|
+
entry
|
|
173
|
+
)
|
|
174
|
+
}
|
|
175
|
+
|
|
176
|
+
export async function trackMetric(
|
|
177
|
+
name: string,
|
|
178
|
+
value: number,
|
|
179
|
+
unit?: string,
|
|
180
|
+
context?: Record<string, any>
|
|
181
|
+
) {
|
|
182
|
+
const timestamp = new Date().toISOString()
|
|
183
|
+
const entry: MetricEntry = {
|
|
184
|
+
timestamp,
|
|
185
|
+
name,
|
|
186
|
+
value,
|
|
187
|
+
unit,
|
|
188
|
+
context,
|
|
189
|
+
}
|
|
190
|
+
|
|
191
|
+
log.info(`metric:${name}`, { value, unit, ...context })
|
|
192
|
+
await writeLog(
|
|
193
|
+
METRICS_LOG_DIR,
|
|
194
|
+
`metrics-${new Date().toISOString().split("T")[0]}.jsonl`,
|
|
195
|
+
entry
|
|
196
|
+
)
|
|
197
|
+
}
|
|
198
|
+
|
|
199
|
+
export async function initialize() {
|
|
200
|
+
try {
|
|
201
|
+
await ensureDirectories()
|
|
202
|
+
log.info("Telemetry initialized", { directory: TELEMETRY_DIR })
|
|
203
|
+
} catch (e) {
|
|
204
|
+
log.warn("Failed to initialize telemetry", { error: e })
|
|
205
|
+
}
|
|
206
|
+
}
|
|
207
|
+
|
|
208
|
+
export async function getLogs(
|
|
209
|
+
type: "errors" | "warnings" | "events" | "metrics" = "errors",
|
|
210
|
+
days: number = 1
|
|
211
|
+
): Promise<string[]> {
|
|
212
|
+
try {
|
|
213
|
+
const dir =
|
|
214
|
+
type === "errors" || type === "warnings"
|
|
215
|
+
? ERROR_LOG_DIR
|
|
216
|
+
: type === "events"
|
|
217
|
+
? EVENT_LOG_DIR
|
|
218
|
+
: METRICS_LOG_DIR
|
|
219
|
+
|
|
220
|
+
const files = await fs.readdir(dir)
|
|
221
|
+
const now = Date.now()
|
|
222
|
+
const maxAge = days * 24 * 60 * 60 * 1000
|
|
223
|
+
|
|
224
|
+
const relevantFiles = []
|
|
225
|
+
for (const file of files) {
|
|
226
|
+
const filePath = path.join(dir, file)
|
|
227
|
+
const stat = await fs.stat(filePath).catch(() => null)
|
|
228
|
+
if (stat && now - stat.mtimeMs <= maxAge) {
|
|
229
|
+
const content = await fs.readFile(filePath, "utf-8")
|
|
230
|
+
relevantFiles.push(content)
|
|
231
|
+
}
|
|
232
|
+
}
|
|
233
|
+
|
|
234
|
+
return relevantFiles
|
|
235
|
+
} catch (e) {
|
|
236
|
+
log.warn("Failed to read telemetry logs", { error: e, type })
|
|
237
|
+
return []
|
|
238
|
+
}
|
|
239
|
+
}
|
|
240
|
+
|
|
241
|
+
export async function printLogs(
|
|
242
|
+
type: "errors" | "warnings" | "events" | "metrics" = "errors",
|
|
243
|
+
days: number = 7
|
|
244
|
+
) {
|
|
245
|
+
const logs = await getLogs(type, days)
|
|
246
|
+
if (logs.length === 0) {
|
|
247
|
+
console.log(`No ${type} logs found for the last ${days} days`)
|
|
248
|
+
return
|
|
249
|
+
}
|
|
250
|
+
|
|
251
|
+
console.log(`\n=== ${type.toUpperCase()} LOGS (Last ${days} days) ===\n`)
|
|
252
|
+
for (const log of logs) {
|
|
253
|
+
const lines = log.split("\n").filter((l) => l.trim())
|
|
254
|
+
for (const line of lines) {
|
|
255
|
+
try {
|
|
256
|
+
const entry = JSON.parse(line)
|
|
257
|
+
console.log(`[${entry.timestamp}] ${entry.message}`)
|
|
258
|
+
if (entry.error) console.log(` Error: ${entry.error}`)
|
|
259
|
+
if (entry.stack) console.log(` Stack: ${entry.stack}`)
|
|
260
|
+
if (entry.context) console.log(` Context: ${JSON.stringify(entry.context)}`)
|
|
261
|
+
} catch {
|
|
262
|
+
console.log(line)
|
|
263
|
+
}
|
|
264
|
+
}
|
|
265
|
+
}
|
|
266
|
+
console.log()
|
|
267
|
+
}
|
|
268
|
+
|
|
269
|
+
export function getLogPath(type: "errors" | "warnings" | "events" | "metrics" = "errors"): string {
|
|
270
|
+
switch (type) {
|
|
271
|
+
case "errors":
|
|
272
|
+
case "warnings":
|
|
273
|
+
return ERROR_LOG_DIR
|
|
274
|
+
case "events":
|
|
275
|
+
return EVENT_LOG_DIR
|
|
276
|
+
case "metrics":
|
|
277
|
+
return METRICS_LOG_DIR
|
|
278
|
+
default:
|
|
279
|
+
return TELEMETRY_DIR
|
|
280
|
+
}
|
|
281
|
+
}
|
|
282
|
+
}
|