feat(cli): add crash reporting for automatic error capture#674
feat(cli): add crash reporting for automatic error capture#674
Conversation
🦋 Changeset detectedLatest commit: 2d685f8 The changes in this PR will be included in the next version bump. This PR includes changesets to release 2 packages
Not sure what this means? Click here to learn what changesets are. Click here if you're a maintainer who wants to add another changeset to this PR |
commit: |
This comment has been minimized.
This comment has been minimized.
This comment has been minimized.
This comment has been minimized.
This comment has been minimized.
This comment has been minimized.
This comment has been minimized.
This comment has been minimized.
This comment has been minimized.
This comment has been minimized.
This comment has been minimized.
This comment has been minimized.
Add crash report infrastructure that writes local crash logs and optionally sends reports to a remote endpoint. Includes privacy- preserving sanitization of sensitive data (paths, UUIDs, emails, tokens) and a `crash-report` subcommand for listing and submitting reports.
- Remove config memoization so env-file settings are respected - Add Windows path sanitization for stack traces, messages, and argv - Fix multiline error message parsing in crash-report send command - Document the crash report webhook endpoint domain
- Sanitize command field via sanitizeMessage to redact emails/UUIDs - Serialize argv as JSON array to preserve argument boundaries - Validate required fields (id, timestamp, crashType) before sending - Support parsing both JSON and legacy space-separated argv formats
- Expand SENSITIVE_FLAGS to cover --value, -b, -H, --cookie, etc. - Strip serialized request bodies from error messages before logging - Suppress crash report banner for handled errors (log only) - Print original error before crash reporting in global handlers
- Limit parseCommand to 2 tokens to avoid leaking positional user input - Allow spaces in Unix path regex to match paths like '/My App/...' - Decouple remoteEnabled from localEnabled so remote-only mode works - Update reportCrash/initCrashReporting to support remote-only config
…ction - Only report crashes for Error subclasses (TypeError, etc.), not plain Error - Add --data/-d, --arg/-a, --email, --user/-u to SENSITIVE_FLAGS - Redact email addresses in argv values
- Extract lastSegment helper to deduplicate path basename extraction - Use AbortSignal.timeout() instead of manual AbortController - Extract handleFatal to deduplicate global error handlers - Avoid duplicate OS string split in crash log parser
Align the directory name with the actual command name "crash-report".
…crash reports Replace hardcoded api.tailor.wiki endpoint with example.com placeholder. Add TAILOR_CRASH_REPORT_ENDPOINT env var to override the endpoint for testing and development.
Add RemoteCrashReport type with only provably PII-free fields and toRemoteReport() converter. Auto-send to remote now uses the strict allowlist (excludes argv, errorMessage, full stackTrace), while local files and manual send retain full detail via existing sanitize.ts.
Replace the SENSITIVE_FLAGS denylist (25 entries) with a blanket rule that redacts the value of every flag. This eliminates maintenance burden when new flags are added and provides stronger defense-in-depth alongside the allowlist-based RemoteCrashReport.
…chema Rename crashType to errorType and remove RemoteCrashReport in favor of sending the full sanitized CrashReport directly. This aligns the client payload with the server's ErrorEventPayload interface, eliminating the need for field mapping and the sdkStackTrace indirection. - Rename CrashType to ErrorType, crashType field to errorType - Remove RemoteCrashReport, toRemoteReport, extractSdkStackFrames - Simplify sender to accept CrashReport only (no union type) - Update writer format label from "Crash Type" to "Error Type" - Update send command parser accordingly
Replace the `constructor !== Error` heuristic with explicit native error type checks (TypeError, RangeError, SyntaxError, ReferenceError). This prevents expected domain errors like ConnectError and CIPromptError from being misclassified as crashes, while still capturing genuine programming bugs. Also show the crash-report banner for all saved reports, including those caught in command handlers, so users know they can submit the report.
- Apply sanitizeMessage to the error message line of stack traces so secrets (tokens, emails, UUIDs) embedded in the message are redacted consistently with the errorMessage field. - Fix sanitizeArgv to recognize consecutive flags: when a boolean flag like --verbose is followed by another flag, don't consume the second flag as a value. Previously `--verbose --workspace-id secret` would leak `secret`. - Narrow crash reporting to TypeError and RangeError only. SyntaxError and ReferenceError at runtime typically originate from dynamically imported user config files, not SDK code defects.
Add tests for the crash-report list command covering sorted output, empty directory, and non-existent directory cases. Document two accepted design trade-offs as code comments: - Error classification misses exhaustiveness checks thrown as plain Error - initCrashReporting runs before env file loading by design
…sage - Deduplicate crash reporting logic in withCommonArgs: consolidate two separate reportCrash call sites into a single shouldReport check after the logging branches. - Replace global EMAIL_PATTERN regex with inline non-global regex in sanitizeArgv to avoid the .test() + global lastIndex state footgun.
- Extract EMAIL_TEST_PATTERN constant for non-global .test() usage - Simplify stack trace first-line sanitization with regex replace - Consolidate flag detection in sanitizeArgv under single startsWith check
Replace the complex text-based parseCrashLogFile (~45 lines of regex parsing) with a simple JSON footer approach. formatCrashReport now appends a `--- JSON ---` section with the full report as JSON, and parseCrashLogFile reads it in 3 lines. Also simplify URL_QUERY_PATTERN to use character class instead of capture group, and remove redundant callback wrapper in stack trace sanitization.
… footer Read TAILOR_CRASH_REPORT_ENDPOINT inside sendCrashReport() instead of at module scope so that env files loaded by withCommonArgs() are respected. Use lastIndexOf to find the final --- JSON --- marker in crash log files, preventing misparse when the marker string appears in error messages.
The send command requires --file but the post-crash hint printed the path as a positional argument, making the suggested command fail.
Wrap the crash log path in double quotes so the suggested command works correctly when the path contains spaces.
This comment has been minimized.
This comment has been minimized.
This comment has been minimized.
This comment has been minimized.
|
I verified crash report submission locally -- the report is generated correctly and the mutation returns |
This comment has been minimized.
This comment has been minimized.
📖 Docs Consistency Check
|
| File | Issue | Suggested Fix |
|---|---|---|
packages/sdk/docs/cli-reference.md |
New crash-report commands not documented in Commands section |
Add a new section under Commands listing crash-report list and crash-report send |
packages/sdk/docs/cli/crash-report.md |
File missing entirely | Create new file following the pattern of other CLI command docs (e.g., secret.md, workflow.md) |
packages/sdk/docs/cli-reference.md |
TAILOR_CRASH_REPORT_ENDPOINT environment variable not documented |
Add row to Environment Variables table documenting this override capability |
Details
1. Missing crash-report commands in cli-reference.md
The PR adds two new CLI commands (crash-report list and crash-report send) which are:
- ✅ Implemented in
packages/sdk/src/cli/commands/crash-report/list.tsandsend.ts - ✅ Registered in
packages/sdk/src/cli/index.ts:54as"crash-report": crashReportCommand - ❌ NOT listed in the Commands section of
packages/sdk/docs/cli-reference.md
All other command groups (Application, TailorDB, User & Auth, Workspace, Auth Resource, Workflow, Function, Executor, Secret, Static Website, Completion) have their own section in cli-reference.md with links to detailed docs. The crash-report commands should follow this pattern.
Expected addition to cli-reference.md around line 207:
### [Crash Report Commands](./cli/crash-report.md)
Commands for managing crash reports.
| Command | Description |
| --------------------------------------------------------- | ------------------------------- |
| [crash-report list](./cli/crash-report.md#crash-report-list) | List local crash report files |
| [crash-report send](./cli/crash-report.md#crash-report-send) | Submit a crash report to remote |2. Missing packages/sdk/docs/cli/crash-report.md
Following the established pattern (see secret.md, workflow.md, etc.), each command group should have its own detailed documentation file under packages/sdk/docs/cli/. This file should include:
- Command overview with description
- Subcommand table of contents
- Detailed documentation for each subcommand with usage, options, and examples
- Auto-generated sections using
<!-- politty:command:crash-report:*:start/end -->markers
Implementation details show:
list.ts:10- Description: "List local crash report files."send.ts:13- Description: "Submit a crash report to help improve the SDK."send.ts:16-20- Has--fileoption (required): "Path to the crash report file"
3. Missing TAILOR_CRASH_REPORT_ENDPOINT environment variable
The implementation in packages/sdk/src/cli/crash-report/sender.ts:54 shows:
const endpoint = process.env.TAILOR_CRASH_REPORT_ENDPOINT || PRODUCTION_ENDPOINT;This environment variable is used to override the remote crash report endpoint (mentioned in the PR description for testing purposes), but it's not documented in the Environment Variables table in cli-reference.md.
Currently documented (lines 64-65):
- ✅
TAILOR_CRASH_REPORTS_LOCAL - ✅
TAILOR_CRASH_REPORTS_REMOTE - ❌
TAILOR_CRASH_REPORT_ENDPOINT
Expected addition to cli-reference.md around line 66:
| `TAILOR_CRASH_REPORT_ENDPOINT` | Override remote crash report endpoint (for testing) |Recommended Actions
- Add crash-report commands section to
packages/sdk/docs/cli-reference.md(between Static Website Commands and Completion sections) - Create
packages/sdk/docs/cli/crash-report.mdwith full command documentation following the existing pattern - Add
TAILOR_CRASH_REPORT_ENDPOINTto the Environment Variables table incli-reference.md - Run
pnpm docs:updateto auto-generate politty markers if needed
📖 Docs Consistency Check
|
| File | Issue | Suggested Fix |
|---|---|---|
| packages/sdk/docs/cli-reference.md | Missing Crash Report Commands section | Add new section listing crash-report commands |
| packages/sdk/docs/cli-reference.md | Missing TAILOR_CRASH_REPORT_ENDPOINT env var | Add row in Environment Variables table |
| packages/sdk/docs/cli/crash-report.md | File does not exist | Create following pattern of other CLI docs |
| packages/sdk/src/cli/docs.test.ts | Missing crash-report in docs test | Add entry to files object |
Details
1. Missing Commands Section in CLI Reference
Location: packages/sdk/docs/cli-reference.md lines 84-215
The main CLI reference lists all command categories but the new crash-report command group is missing.
Implementation:
- Commands registered in packages/sdk/src/cli/index.ts line 54
- Command definition: packages/sdk/src/cli/commands/crash-report/index.ts
- Subcommands: list and send
Expected: Add section for Crash Report Commands linking to cli/crash-report.md
2. Missing Environment Variable
Location: packages/sdk/docs/cli-reference.md lines 52-65
The environment variables table documents TAILOR_CRASH_REPORTS_LOCAL and TAILOR_CRASH_REPORTS_REMOTE but misses TAILOR_CRASH_REPORT_ENDPOINT.
Implementation: packages/sdk/src/cli/crash-report/sender.ts line 54 uses this variable to override the production endpoint.
Expected: Add TAILOR_CRASH_REPORT_ENDPOINT to the environment variables table.
Note: Per the PR description this is mentioned for testing purposes.
3. Missing Detailed Command Documentation
Location: packages/sdk/docs/cli/crash-report.md (file does not exist)
Following the established pattern each command group has a dedicated documentation file in packages/sdk/docs/cli/.
Pattern reference: See packages/sdk/docs/cli/secret.md and workflow.md
4. Missing Docs Test Configuration
Location: packages/sdk/src/cli/docs.test.ts lines 35-80
The files object lists all command groups for documentation generation and validation. The crash-report commands are not included which means:
- Running pnpm docs:check will not validate crash-report command docs
- Running pnpm docs:update will not generate or update crash-report docs
Recommended Actions
- Update packages/sdk/src/cli/docs.test.ts - Add crash-report to the files configuration
- Run pnpm docs:update in packages/sdk/ to auto-generate the new docs file and update cli-reference.md
- Manually add TAILOR_CRASH_REPORT_ENDPOINT to the environment variables table in cli-reference.md
- Run pnpm docs:check to verify all documentation is consistent
Addressed in
|
This comment has been minimized.
This comment has been minimized.
| userId: currentUser, | ||
| userEmail: currentUser, |
There was a problem hiding this comment.
Oh, we only needed one of them...
There was a problem hiding this comment.
Currently only email is stored in the platform config, but the /auth/platform/userinfo endpoint does return a sub field (UUID). If email immutability is guaranteed, a separate userId may not be needed. Otherwise, we could persist sub in the config at login time and use it here as a stable identifier.
There was a problem hiding this comment.
we could persist sub in the config at login time and use it here as a stable identifier.
Since the sub field is guaranteed to be immutable, it would be better to use sub as the ID in the config in the first place, assuming that email addresses can change.
There was a problem hiding this comment.
I'll leave this as-is for now and revisit after the login refactoring lands.
| const originalEnv = process.env; | ||
|
|
||
| beforeEach(() => { | ||
| process.env = { ...originalEnv }; |
There was a problem hiding this comment.
Shouldn't we use vi.stubEnv instead?
There was a problem hiding this comment.
Good call. Replaced with vi.stubEnv / vi.unstubAllEnvs.
This comment has been minimized.
This comment has been minimized.
toiroakr
left a comment
There was a problem hiding this comment.
Let's go with this for now.
Include both crash-report and setup command sections added independently. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This comment has been minimized.
This comment has been minimized.
Code Metrics Report (packages/sdk)
Details | | main (684d2aa) | #674 (25f6630) | +/- |
|--------------------|----------------|----------------|-------|
+ | Coverage | 55.1% | 55.5% | +0.3% |
| Files | 312 | 321 | +9 |
| Lines | 10112 | 10310 | +198 |
+ | Covered | 5576 | 5725 | +149 |
+ | Code to Test Ratio | 1:0.3 | 1:0.4 | +0.0 |
| Code | 58877 | 60195 | +1318 |
+ | Test | 23393 | 24228 | +835 |Code coverage of files in pull request scope (29.4% → 71.6%)
SDK Configure Bundle Size
Runtime Performance
Type Performance (instantiations)
Reported by octocov |
Add crash reporting system that captures unexpected CLI errors and allows users to send reports to aid debugging.
Usage
CLI output on unexpected crash:
New commands:
Main Changes
crash-report listandcrash-report sendCLI commandsRemoteCrashReportfor auto-send path with configurable endpointsubmitCrashReport) with 5s timeout and best-effort semanticsPrivacy / Sanitization
<path>/filenameor~/<redacted>/filename<uuid><redacted><email>?<redacted>--flag valueand--flag=value-> redactedConfiguration
TAILOR_CRASH_REPORTS_LOCALonoffto disable)TAILOR_CRASH_REPORTS_REMOTEoffonto enable)TAILOR_CRASH_REPORT_ENDPOINTNotes
TAILOR_CRASH_REPORT_ENDPOINTfor testing