{"version":3,"file":"crashreport-Cyuz1qiu.mjs","names":[],"sources":["../src/cli/crashreport/config.ts","../src/cli/crashreport/writer.ts","../src/cli/crashreport/sender.ts","../src/cli/crashreport/sanitize.ts","../src/cli/crashreport/report.ts","../src/cli/crashreport/index.ts"],"sourcesContent":["import * as path from \"pathe\";\nimport { isCI } from \"std-env\";\nimport { xdgConfig } from \"xdg-basedir\";\n\nexport interface CrashReportConfig {\n  readonly localEnabled: boolean;\n  readonly remoteEnabled: boolean;\n  readonly localDir: string;\n}\n\n/**\n * Parse crash report configuration from environment variables.\n * Local crash log writing is enabled by default (opt-out via TAILOR_CRASH_REPORTS_LOCAL=off).\n * Remote sending is disabled by default (opt-in via TAILOR_CRASH_REPORTS_REMOTE=on).\n * Both are auto-disabled in CI environments.\n * @returns Crash report configuration\n */\nexport function parseCrashReportConfig(): CrashReportConfig {\n  if (isCI) {\n    return {\n      localEnabled: false,\n      remoteEnabled: false,\n      localDir: \"\",\n    };\n  }\n\n  const localEnabled = (process.env.TAILOR_CRASH_REPORTS_LOCAL ?? \"on\").toLowerCase() !== \"off\";\n  const remoteEnabled = (process.env.TAILOR_CRASH_REPORTS_REMOTE ?? \"off\").toLowerCase() === \"on\";\n  const localDir = xdgConfig ? path.join(xdgConfig, \"tailor-platform\", \"crash-reports\") : \"\";\n\n  return {\n    localEnabled: localEnabled && localDir !== \"\",\n    remoteEnabled,\n    localDir,\n  };\n}\n","import * as fs from \"node:fs\";\nimport * as path from \"pathe\";\nimport { ensureSecretDir, writeSecretFile } from \"#/cli/shared/secret-file\";\nimport type { CrashReport } from \"./report\";\n\nconst MAX_CRASH_FILES = 10;\n\n/** Marker line that separates human-readable content from the JSON footer. */\nexport const JSON_FOOTER_MARKER = \"--- JSON ---\";\n\n/** File extension for crash log files. */\nexport const CRASH_LOG_EXTENSION = \".crash.log\";\n\n/**\n * Format a CrashReport as human-readable text for local crash log files.\n * @param report - Crash report to format\n * @returns Formatted text content\n */\nexport function formatCrashReport(report: CrashReport): string {\n  const lines = [\n    `Crash Report: ${report.id}`,\n    `Timestamp: ${report.timestamp}`,\n    `Error Type: ${report.errorType}`,\n    \"\",\n    \"--- Environment ---\",\n    `SDK Version: ${report.sdkVersion}`,\n    `Node Version: ${report.nodeVersion}`,\n    `OS: ${report.osPlatform} ${report.osRelease}`,\n    `Arch: ${report.arch}`,\n    \"\",\n    \"--- Command ---\",\n    `Command: ${report.command}`,\n    `Arguments: ${JSON.stringify(report.argv)}`,\n    \"\",\n    \"--- Error ---\",\n    `Name: ${report.errorName}`,\n    `Message: ${report.errorMessage}`,\n    \"\",\n    \"--- Stack Trace ---\",\n    report.stackTrace || \"(no stack trace available)\",\n    \"\",\n    JSON_FOOTER_MARKER,\n    JSON.stringify(report),\n    \"\",\n  ];\n  return lines.join(\"\\n\");\n}\n\n/**\n * Generate a filename for a crash log file.\n * Format: {timestamp}-{shortId}.crash.log\n * @param report - Crash report to generate filename for\n * @returns Filename string\n */\nfunction generateFilename(report: CrashReport): string {\n  const safeTimestamp = report.timestamp.replace(/[:.]/g, \"-\");\n  const shortId = report.id.slice(0, 8);\n  return `${safeTimestamp}-${shortId}${CRASH_LOG_EXTENSION}`;\n}\n\n/**\n * Remove old crash log files, keeping only the most recent ones.\n * @param dir - Crash log directory\n */\nfunction cleanupOldFiles(dir: string): void {\n  try {\n    const files = fs\n      .readdirSync(dir)\n      .filter((f) => f.endsWith(CRASH_LOG_EXTENSION))\n      .toSorted()\n      .toReversed();\n\n    for (const file of files.slice(MAX_CRASH_FILES)) {\n      fs.unlinkSync(path.join(dir, file));\n    }\n  } catch {\n    // Best-effort cleanup, ignore errors\n  }\n}\n\n/**\n * Write a crash report to a local file.\n * Creates the directory if it doesn't exist. Keeps only the last 10 crash files.\n * Never throws - returns the file path on success or undefined on failure.\n * @param report - Crash report to write\n * @param dir - Directory to write the crash log file to\n * @returns File path on success, undefined on failure\n */\nexport function writeCrashReport(report: CrashReport, dir: string): string | undefined {\n  try {\n    ensureSecretDir(dir);\n\n    const filename = generateFilename(report);\n    const filePath = path.join(dir, filename);\n    const content = formatCrashReport(report);\n\n    writeSecretFile(filePath, content);\n    cleanupOldFiles(dir);\n\n    return filePath;\n  } catch {\n    return undefined;\n  }\n}\n","import type { CrashReport } from \"./report\";\n\nconst SEND_TIMEOUT_MS = 5000;\nconst PRODUCTION_ENDPOINT = \"https://sdk-error-tracking-926vh9t4cl.erp.dev/query\";\n\nconst SUBMIT_MUTATION = `\nmutation SubmitCrashReport(\n  $id: String!\n  $timestamp: String!\n  $sdkVersion: String!\n  $nodeVersion: String!\n  $osPlatform: String!\n  $osRelease: String!\n  $arch: String!\n  $command: String!\n  $argv: [String]\n  $errorName: String!\n  $errorMessage: String!\n  $stackTrace: String\n  $errorType: String!\n  $userId: String\n  $userEmail: String\n) {\n  submitCrashReport(\n    id: $id\n    timestamp: $timestamp\n    sdkVersion: $sdkVersion\n    nodeVersion: $nodeVersion\n    osPlatform: $osPlatform\n    osRelease: $osRelease\n    arch: $arch\n    command: $command\n    argv: $argv\n    errorName: $errorName\n    errorMessage: $errorMessage\n    stackTrace: $stackTrace\n    errorType: $errorType\n    userId: $userId\n    userEmail: $userEmail\n  ) {\n    success\n  }\n}`;\n\n/**\n * Send a crash report to the remote endpoint via GraphQL mutation.\n * Best-effort: never throws, returns boolean success.\n * @param report - Crash report to send\n * @param ua - User-Agent header value\n * @returns true if the request succeeded, false otherwise\n */\nexport async function sendCrashReport(report: CrashReport, ua: string): Promise<boolean> {\n  try {\n    const endpoint = process.env.TAILOR_CRASH_REPORT_ENDPOINT || PRODUCTION_ENDPOINT;\n    const response = await fetch(endpoint, {\n      method: \"POST\",\n      headers: {\n        \"Content-Type\": \"application/json\",\n        \"User-Agent\": ua,\n      },\n      body: JSON.stringify({\n        query: SUBMIT_MUTATION,\n        variables: report,\n      }),\n      signal: AbortSignal.timeout(SEND_TIMEOUT_MS),\n    });\n\n    if (!response.ok) return false;\n\n    const data = (await response.json()) as {\n      errors?: unknown[];\n      data?: { submitCrashReport: { success: boolean } };\n    };\n    if (data.errors?.length) return false;\n    return data.data?.submitCrashReport.success === true;\n  } catch {\n    return false;\n  }\n}\n","import * as os from \"node:os\";\n\nconst HOME_DIR = os.homedir();\n\n// Patterns for sanitization (global variants for use with .replace())\nconst UUID_PATTERN = /\\b[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}\\b/gi;\nconst LONG_HEX_PATTERN = /\\b[0-9a-fA-F]{32,}\\b/g;\nconst EMAIL_PATTERN = /\\b[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\\.[a-zA-Z]{2,}\\b/g;\nconst ABSOLUTE_PATH_PATTERN = /(?:\\/(?:[\\w.@\\- ]+\\/)+[\\w.@\\- ]+)/g;\nconst WINDOWS_PATH_PATTERN = /(?:[A-Za-z]:\\\\(?:[\\w.@\\- ]+\\\\)+[\\w.@\\- ]+)/g;\nconst URL_QUERY_PATTERN = /[?&][^?\\s]*/g;\n\n// Non-global variants for single-match .test() calls (avoids lastIndex state issues)\nconst EMAIL_TEST_PATTERN = /\\b[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\\.[a-zA-Z]{2,}\\b/;\nconst WINDOWS_DRIVE_TEST_PATTERN = /^[A-Za-z]:\\\\/;\n\n// SDK package path marker for relative paths\nconst SDK_PACKAGE_MARKER = \"packages/sdk/\";\n\nfunction lastSegment(filePath: string, separator: string): string {\n  return filePath.split(separator).pop() ?? filePath;\n}\n\n/**\n * Sanitize a stack trace by replacing absolute paths with relative SDK paths.\n * External paths are replaced with `<external>/filename.ext`.\n * Home directories are replaced with `~/<redacted>/`.\n * @param stack - Raw stack trace string\n * @returns Sanitized stack trace\n */\nexport function sanitizeStackTrace(stack: string): string {\n  // V8 stack traces start with \"ErrorType: message\\n    at ...\".\n  // The error message may span multiple lines before the first \"    at \" frame.\n  // Apply message sanitization to all message lines so secrets embedded in\n  // multiline error messages are redacted consistently with errorMessage.\n  const firstFrameIndex = stack.search(/\\n\\s+at /);\n  let result: string;\n  if (firstFrameIndex !== -1) {\n    result = sanitizeMessage(stack.slice(0, firstFrameIndex)) + stack.slice(firstFrameIndex);\n  } else {\n    result = sanitizeMessage(stack);\n  }\n\n  result = result.replace(ABSOLUTE_PATH_PATTERN, (match) => {\n    const sdkIndex = match.indexOf(SDK_PACKAGE_MARKER);\n    if (sdkIndex !== -1) {\n      return match.slice(sdkIndex);\n    }\n\n    if (match.startsWith(HOME_DIR)) {\n      return `~/<redacted>/${lastSegment(match, \"/\")}`;\n    }\n\n    return `<external>/${lastSegment(match, \"/\")}`;\n  });\n  result = result.replace(WINDOWS_PATH_PATTERN, (match) => {\n    const normalized = match.replace(/\\\\/g, \"/\");\n    const sdkIndex = normalized.indexOf(SDK_PACKAGE_MARKER);\n    if (sdkIndex !== -1) {\n      return normalized.slice(sdkIndex);\n    }\n    return `<external>/${lastSegment(match, \"\\\\\")}`;\n  });\n  return result;\n}\n\n/**\n * Sanitize an error message by redacting sensitive information.\n * Redacts: UUIDs, long hex tokens, email addresses, absolute paths, URL query strings.\n * @param message - Raw error message\n * @returns Sanitized error message\n */\nexport function sanitizeMessage(message: string): string {\n  let result = message;\n  // Strip serialized request/response bodies that may contain secrets\n  result = result.replace(/\\nRequest:\\s*[\\s\\S]*$/, \"\\nRequest: <redacted>\");\n  result = result.replace(UUID_PATTERN, \"<uuid>\");\n  result = result.replace(LONG_HEX_PATTERN, \"<redacted>\");\n  result = result.replace(EMAIL_PATTERN, \"<email>\");\n  result = result.replace(URL_QUERY_PATTERN, \"?<redacted>\");\n  result = result.replace(ABSOLUTE_PATH_PATTERN, (match) => `<path>/${lastSegment(match, \"/\")}`);\n  result = result.replace(WINDOWS_PATH_PATTERN, (match) => `<path>/${lastSegment(match, \"\\\\\")}`);\n\n  return result;\n}\n\n/**\n * Sanitize process.argv by keeping command/subcommand names and redacting\n * values of sensitive flags.\n * @param argv - Raw process.argv array\n * @returns Sanitized argv array\n */\nexport function sanitizeArgv(argv: string[]): string[] {\n  const result: string[] = [];\n  let redactNext = false;\n\n  for (const arg of argv) {\n    if (redactNext) {\n      // If the next token is itself a flag, treat it as a new flag rather\n      // than consuming it as the previous flag's value. This avoids leaking\n      // the *next* flag's value (e.g., `--verbose --workspace-id secret`\n      // would otherwise expose `secret`).\n      if (!arg.startsWith(\"-\")) {\n        result.push(\"<redacted>\");\n        redactNext = false;\n        continue;\n      }\n      redactNext = false;\n    }\n\n    if (arg.startsWith(\"-\")) {\n      // --flag=value: keep flag name, redact value\n      const eqIndex = arg.indexOf(\"=\");\n      if (eqIndex !== -1) {\n        result.push(`${arg.slice(0, eqIndex)}=<redacted>`);\n        continue;\n      }\n\n      // --flag / -f: keep flag name, redact next arg as its value\n      result.push(arg);\n      redactNext = true;\n      continue;\n    }\n\n    // Redact absolute paths\n    if (arg.startsWith(\"/\") && arg.includes(\"/\", 1)) {\n      result.push(\"<path>\");\n      continue;\n    }\n\n    // Redact Windows-style absolute paths\n    if (WINDOWS_DRIVE_TEST_PATTERN.test(arg)) {\n      result.push(\"<path>\");\n      continue;\n    }\n\n    // Redact email addresses\n    if (EMAIL_TEST_PATTERN.test(arg)) {\n      result.push(\"<email>\");\n      continue;\n    }\n\n    result.push(arg);\n  }\n\n  return result;\n}\n","import * as crypto from \"node:crypto\";\nimport * as fs from \"node:fs\";\nimport * as os from \"node:os\";\nimport { parseYAML } from \"confbox\";\nimport * as path from \"pathe\";\nimport { xdgConfig } from \"xdg-basedir\";\nimport { redactSecrets } from \"#/cli/shared/logger\";\nimport { sanitizeArgv, sanitizeMessage, sanitizeStackTrace } from \"./sanitize\";\n\nexport type ErrorType = \"uncaughtException\" | \"unhandledRejection\" | \"handledError\";\n\nexport interface CrashReport {\n  id: string;\n  timestamp: string;\n  sdkVersion: string;\n  nodeVersion: string;\n  osPlatform: string;\n  osRelease: string;\n  arch: string;\n  command: string;\n  argv: string[];\n  errorName: string;\n  errorMessage: string;\n  stackTrace: string;\n  errorType: ErrorType;\n  userId: string | null;\n  userEmail: string | null;\n}\n\ninterface BuildCrashReportOptions {\n  error: unknown;\n  sdkVersion: string;\n  errorType: ErrorType;\n}\n\n// Maximum subcommand depth to keep (e.g., \"tailordb migrate generate\" = 3 tokens).\n// Positional arguments beyond this are potentially sensitive user input.\n// Accepted trade-off: plain-text positional args that don't match known patterns\n// (UUIDs, hex tokens, emails, paths) pass through to `command` and `argv`.\n// Full redaction would require embedding the CLI command tree here, which is fragile.\nconst MAX_COMMAND_TOKENS = 3;\n\n/**\n * Parse the command name from process.argv.\n * Extracts up to MAX_COMMAND_TOKENS non-flag arguments after the script name.\n * @returns Parsed command string\n */\nfunction parseCommand(): string {\n  const args = process.argv.slice(2);\n  const commandParts: string[] = [];\n  for (const arg of args) {\n    if (arg.startsWith(\"-\") || commandParts.length >= MAX_COMMAND_TOKENS) break;\n    commandParts.push(arg);\n  }\n  return commandParts.join(\" \") || \"<unknown>\";\n}\n\n/**\n * Build a CrashReport data structure from an error and context.\n * All sensitive data is sanitized before inclusion: `redactSecrets` masks every registered\n * secret first, then the pattern-based sanitizers below strip known-shape values (UUIDs,\n * long hex, emails, paths) from what's left. `redactSecrets` must run first — the path\n * sanitizer intentionally keeps a path's basename (e.g. `/home/user/.../key.json` becomes\n * `<path>/key.json`), so a registered secret shaped like a path would have that basename\n * survive if the pattern sanitizer ran on it first. This report is written to a local file\n * (and optionally sent remotely) outside the CLI's normal stderr path.\n * @param options - Error, SDK version, and crash type\n * @returns Sanitized crash report\n */\nexport function buildCrashReport(options: BuildCrashReportOptions): CrashReport {\n  const { error, sdkVersion, errorType } = options;\n\n  const isError = error instanceof Error;\n  const rawMessage = isError ? error.message : String(error);\n  const rawStack = isError && error.stack ? error.stack : \"\";\n  const errorName = isError ? error.name : \"UnknownError\";\n\n  const currentUser = readCurrentUser();\n\n  return {\n    id: crypto.randomUUID(),\n    timestamp: new Date().toISOString(),\n    sdkVersion,\n    nodeVersion: process.version,\n    osPlatform: process.platform,\n    osRelease: os.release(),\n    arch: process.arch,\n    command: sanitizeMessage(redactSecrets(parseCommand())),\n    argv: sanitizeArgv(process.argv.map(redactSecrets)),\n    errorName: redactSecrets(errorName),\n    errorMessage: sanitizeMessage(redactSecrets(rawMessage)),\n    stackTrace: sanitizeStackTrace(redactSecrets(rawStack)),\n    errorType,\n    userId: currentUser?.id ? redactSecrets(currentUser.id) : null,\n    userEmail: currentUser?.email ? redactSecrets(currentUser.email) : null,\n  };\n}\n\ntype CurrentUser = {\n  id: string;\n  email: string | null;\n};\n\n/**\n * Read current_user from Tailor Platform config without side effects.\n * Unlike readPlatformConfig(), this never triggers migration or logs warnings.\n * @returns The current user ID and email, or null if unavailable\n */\nfunction readCurrentUser(): CurrentUser | null {\n  try {\n    if (!xdgConfig) return null;\n    const configPath = path.join(xdgConfig, \"tailor-platform\", \"config.yaml\");\n    if (!fs.existsSync(configPath)) return null;\n    const raw = parseYAML(fs.readFileSync(configPath, \"utf-8\")) as {\n      current_user?: string | null;\n      users?: Record<string, { email?: unknown } | undefined>;\n    };\n    // parseYAML returns null for empty documents\n    // oxlint-disable-next-line typescript/no-unnecessary-condition\n    const currentUser = raw?.current_user ?? null;\n    if (!currentUser) return null;\n    const email = raw.users?.[currentUser]?.email;\n    return {\n      id: currentUser,\n      email: typeof email === \"string\" ? email : legacyEmail(currentUser),\n    };\n  } catch {\n    return null;\n  }\n}\n\nfunction legacyEmail(user: string): string | null {\n  return user.includes(\"@\") ? user : null;\n}\n","import { logger } from \"#/cli/shared/logger\";\nimport { readPackageJson } from \"#/cli/shared/package-json\";\nimport { userAgentFromVersion } from \"#/cli/shared/user-agent\";\nimport { parseCrashReportConfig } from \"./config\";\nimport { buildCrashReport, type ErrorType } from \"./report\";\nimport { sendCrashReport } from \"./sender\";\nimport { writeCrashReport } from \"./writer\";\n\n/**\n * Report an unexpected crash. Writes a local crash log file and optionally\n * sends the report to a remote endpoint. Displays a user-facing message\n * with the crash log path and a command to submit the report.\n *\n * Never throws - all errors are silently caught.\n * @param error - The error that caused the crash\n * @param errorType - How the error was caught\n */\nexport async function reportCrash(error: unknown, errorType: ErrorType): Promise<void> {\n  try {\n    const config = parseCrashReportConfig();\n    if (!config.localEnabled && !config.remoteEnabled) return;\n\n    const packageJson = await readPackageJson();\n    const sdkVersion = packageJson.version ?? \"unknown\";\n\n    const report = buildCrashReport({ error, sdkVersion, errorType });\n\n    if (config.localEnabled) {\n      const filePath = writeCrashReport(report, config.localDir);\n      if (filePath) {\n        logger.log(\n          [\n            \"\",\n            \"An unexpected error occurred. A crash report has been saved to:\",\n            `  ${filePath}`,\n            \"\",\n            \"To submit this report:\",\n            `  tailor crashreport send --file \"${filePath}\"`,\n          ].join(\"\\n\"),\n        );\n      }\n    }\n\n    if (config.remoteEnabled) {\n      const ua = userAgentFromVersion(sdkVersion);\n      await sendCrashReport(report, ua);\n    }\n  } catch {\n    // Never throw from crash reporting\n  }\n}\n\n/**\n * Register global uncaughtException and unhandledRejection handlers.\n * These catch errors outside the normal cleanup flow (e.g., during\n * argument parsing). Should be called once at CLI startup before runMain.\n */\nexport function initCrashReporting(): void {\n  const config = parseCrashReportConfig();\n  if (!config.localEnabled && !config.remoteEnabled) return;\n\n  const handleFatal = (error: unknown, errorType: ErrorType) => {\n    const message = error instanceof Error ? error.message : String(error);\n    logger.error(message);\n    void reportCrash(error, errorType).finally(() => {\n      process.exit(1);\n    });\n  };\n\n  process.on(\"uncaughtException\", (error) => handleFatal(error, \"uncaughtException\"));\n  process.on(\"unhandledRejection\", (reason) => handleFatal(reason, \"unhandledRejection\"));\n}\n"],"mappings":"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"}