{"record":{"id":"52e61f542acf7816","repo":"JuliusBrussee/caveman","slug":"choose-plain-or-open","errorCode":null,"errorMessage":"choose --plain or --open","messagePattern":"choose --plain or --open","errorType":"validation","errorClass":"Error","httpStatus":null,"severity":"error","filePath":"packages/cli/src/stats-cli.ts","lineNumber":55,"sourceCode":"    const arg = argv[i]!;\n    if (seen.has(arg)) throw new Error(`duplicate ${arg}`);\n    seen.add(arg);\n    if (valueFlags.has(arg)) {\n      const value = argv[++i];\n      if (!value || value.startsWith(\"--\") || /[\\u0000-\\u001f\\u007f]/u.test(value)) throw new Error(`${arg} requires a value`);\n      if (arg === \"--days\" && (!/^\\d+$/u.test(value) || Number(value) < 1 || Number(value) > 3660)) {\n        throw new Error(\"--days must be an integer from 1 to 3660\");\n      }\n      if (arg === \"--out\") result.out = value;\n      else result.filters.push(arg, value);\n    } else if (arg === \"--json\") result.json = true;\n    else if (arg === \"--plain\" || arg === \"--no-open\") result.plain = true;\n    else if (arg === \"--open\") result.open = true;\n    else if (arg === \"--all-time\") result.filters.push(\"--days\", \"0\");\n    else throw new Error(`unknown option ${arg}`);\n  }\n  if (seen.has(\"--days\") && seen.has(\"--all-time\")) throw new Error(\"choose --days or --all-time\");\n  if (result.plain && result.open) throw new Error(\"choose --plain or --open\");\n  if (result.json && result.open) throw new Error(\"--json cannot open a browser\");\n  return result;\n}\n\ntype StatsMetrics = {\n  requests: number;\n  successful_requests: number;\n  failed_requests: number;\n  input_tokens: number;\n  output_tokens: number;\n  cache_read_tokens: number;\n  cache_write_tokens: number;\n  complete_usage_requests: number;\n  partial_usage_requests: number;\n  measured_requests: number;\n  unmeasured_requests: number;\n  before_tokens: number;\n  after_tokens: number;","sourceCodeStart":37,"sourceCodeEnd":73,"githubUrl":"https://github.com/JuliusBrussee/caveman/blob/3ee70a102609e550bd2e68004bf5990a9341c851/packages/cli/src/stats-cli.ts#L37-L73","documentation":"Thrown by parseStatsOptions, the hand-rolled argv validator for the `stats` command, when the caller fails to pick exactly one output mode: `--plain` and `--open` are a mutually exclusive choice — both together or neither is invalid. It is a sentinel validation error raised before any stats are computed, so the caller gets usage guidance instead of an ambiguous output target.","triggerScenarios":"`stats --plain --open`; an alias or wrapper that injects --no-open while the user appends --open.","commonSituations":"Shell aliases that default to one mode; scripts copying flag lists between invocations; users toggling output style without removing the previous flag.","solutions":["Drop one of the two flags — keep --open for browser output or --plain/--no-open for terminal output","Audit shell aliases/functions that add --no-open or --open automatically","Choose one mode explicitly in scripts instead of concatenating flag arrays"],"exampleFix":"// before\nmyapp stats --plain --open\n// after\nmyapp stats --open","handlingStrategy":"validation","validationCode":"const open = argv.includes(\"--open\");\nconst plain = argv.includes(\"--plain\") || argv.includes(\"--no-open\");\nif (open && plain) throw new Error(\"pass --open or --plain, not both\");","typeGuard":null,"tryCatchPattern":"try {\n  const opts = parseStatsOptions(argv);\n} catch (e) {\n  if (e.message === \"choose --plain or --open\") {\n    console.error(e.message); process.exitCode = 2;\n  } else throw e;\n}","preventionTips":["Pick one presentation mode per invocation; don't concatenate user flags with alias-injected flags","Audit shell aliases that hardcode --open or --no-open","Use an explicit env var (e.g. STATS_OUTPUT=json|plain|browser) instead of stacking flags"],"tags":["cli","conflicting-options"],"backgroundTag":"mutually-exclusive-flags","analyzedSha":"3ee70a102609e550bd2e68004bf5990a9341c851","analyzedAt":"2026-09-20T15:53:39.229Z","contentChangedAt":"2026-09-20T15:53:39.229Z","schemaVersion":2},"datasetVersion":"2026-09-23T08:17:48.524Z"}