{"version":3,"sources":["../src/cli/utils/governance/wrapper.ts","../src/cli/utils/governance/brand.ts","../src/cli/utils/governance/budget.ts","../src/cli/utils/governance/platform-tool-policy.ts","../src/cli/utils/governance/shell-rc.ts","../src/cli/utils/opencode-config-flag.ts","../src/cli/utils/governance/gemini-settings-preflight.ts","../src/cli/utils/governance/wrapper-mode.ts","../src/cli/utils/governance/codex-rollout-otlp.ts","../src/cli/utils/governance/codex-rollout.ts","../src/cli/utils/governance/wrapper-path-choice.ts"],"sourcesContent":["/**\n * exec wrapper helper for `langwatch claude` / `codex` / `cursor` /\n * `gemini`. Loads the persisted device-flow config, optionally\n * pre-checks the budget (Screen-8 box + exit 2 if exceeded),\n * computes the right env-var pair for the tool, and spawns the\n * underlying binary inheriting stdio so the user keeps their\n * familiar UX.\n *\n * On Unix we use spawn() with stdio:'inherit'; signals (Ctrl-C,\n * SIGTERM) propagate via the child process group. We do NOT use\n * execve replacement - Node's child_process never replaces the\n * current process, but this is functionally equivalent for the\n * end-user (same exit code, same terminal handling) and works on\n * Windows where execve doesn't exist.\n */\n\nimport { spawn } from \"node:child_process\";\nimport type { GovernanceConfig } from \"./config\";\nimport { loadConfig, saveConfig, isLoggedIn } from \"./config\";\nimport { lwTag } from \"./brand\";\nimport { checkBudget, renderBudgetExceeded } from \"./budget\";\nimport { getCliBootstrap, GovernanceCliError } from \"./cli-api\";\nimport { runDeviceFlowLogin } from \"./login-flow\";\nimport { resolvePlatformToolPolicy } from \"./platform-tool-policy\";\nimport { maybeOfferIngestionShellRcPersist } from \"./shell-rc\";\nimport { resolveWrapperMode } from \"./wrapper-mode\";\nimport { createCodexIOStreamer } from \"./codex-rollout-otlp\";\nimport { parseToolModeFlag, resolveWrapperPath } from \"./wrapper-path-choice\";\n\n/**\n * How often the wrapper polls codex's append-only rollout while the session\n * runs, streaming each completed turn's I/O instead of one burst on exit.\n */\nconst CODEX_IO_POLL_MS = 2_500;\n\nexport interface ToolEnv {\n  /** Env-var name → value pairs to inject into the child process. */\n  vars: Record<string, string>;\n  /**\n   * Env-var names to STRIP from the inherited parent environment\n   * before spawning the tool. Used to scrub legacy credentials the\n   * user has exported in their shell (e.g. ANTHROPIC_API_KEY set\n   * from a previous direct-Anthropic workflow) that would otherwise\n   * race with the gateway-routed auth (ANTHROPIC_AUTH_TOKEN) we\n   * inject - claude-code 2.x detects both and warns\n   * \"auth may not work as expected\", so we have to actively unset\n   * the conflicting twin rather than just pile on top of it.\n   * Unset BEFORE the merge so a tool that intentionally sets both\n   * (opencode for provider auto-detect) still wins.\n   */\n  clears?: string[];\n}\n\n/**\n * Mirror of the Go CLI's env-injection map. The wrapped tools\n * read these standard env vars (Anthropic, OpenAI, Google) and\n * route through the gateway with the user's personal VK as bearer.\n *\n * Gateway-only on purpose: when the VK is on the API path the\n * gateway already captures every request + response server-side\n * (full I/O, exact cost). Injecting OTEL_* on top would make the\n * wrapped tool emit its own telemetry for the SAME calls = double\n * trace + double cost in /messages. The OTLP ingest path is for\n * users who can't go through the gateway at all (Claude Max\n * subscription, no swappable API key); they paste the OTEL env\n * block from the /me drawer manually. See\n * docs/ai-governance/track-your-claude-code-usage.mdx (Path A vs\n * Path B).\n */\nexport function envForTool(cfg: GovernanceConfig, tool: string): ToolEnv {\n  const gw = cfg.gateway_url.replace(/\\/+$/, \"\");\n  const auth = cfg.default_personal_vk?.secret;\n  if (!auth) return { vars: {} };\n  switch (tool) {\n    case \"claude\":\n      // claude-code (2.1.x) appends `/v1/messages` to ANTHROPIC_BASE_URL itself.\n      // Clear the legacy ANTHROPIC_API_KEY twin: claude-code warns\n      // \"Both ANTHROPIC_AUTH_TOKEN and ANTHROPIC_API_KEY set, auth may\n      // not work as expected\" when both are present (the gateway route\n      // uses AUTH_TOKEN; API_KEY is left over from pre-langwatch direct\n      // SDK usage). Stripping it leaves only the gateway-routed creds\n      // on the child env.\n      return {\n        vars: {\n          ANTHROPIC_BASE_URL: gw,\n          ANTHROPIC_AUTH_TOKEN: auth,\n        },\n        clears: [\"ANTHROPIC_API_KEY\"],\n      };\n    case \"codex\":\n      // codex 0.134 appends `/v1/chat/completions` itself.\n      return {\n        vars: {\n          OPENAI_BASE_URL: gw,\n          OPENAI_API_KEY: auth,\n        },\n      };\n    case \"cursor\":\n      // Same warning surface as claude: Anthropic SDKs nested in\n      // cursor's runtime will read ANTHROPIC_API_KEY in preference to\n      // ANTHROPIC_AUTH_TOKEN if both are set, bypassing the gateway.\n      // Scrub the legacy key.\n      return {\n        vars: {\n          OPENAI_BASE_URL: gw,\n          OPENAI_API_KEY: auth,\n          ANTHROPIC_BASE_URL: gw,\n          ANTHROPIC_AUTH_TOKEN: auth,\n        },\n        clears: [\"ANTHROPIC_API_KEY\"],\n      };\n    case \"gemini\":\n      // gemini-cli 0.46-preview honours `GOOGLE_GEMINI_BASE_URL`\n      // (verified empirically in the bundled binary). It POSTs to\n      // `{BASE}/v1beta/models/{model}:generateContent`, prepending\n      // the `/v1beta/` itself. The base must therefore be the bare\n      // gateway URL without the API version suffix; an earlier guess\n      // of `${gw}/v1beta` doubled the prefix to `/v1beta/v1beta/` and\n      // the gateway 404'd the routing call, surfacing as\n      // \"Unexpected end of JSON input\" on the cli side.\n      // `GOOGLE_GENAI_API_BASE` is NOT read by gemini-cli (separate\n      // guess that silently no-op'd in earlier wrapper revisions).\n      return {\n        vars: {\n          GOOGLE_GEMINI_BASE_URL: gw,\n          GEMINI_API_KEY: auth,\n          GOOGLE_API_KEY: auth,\n        },\n      };\n    case \"opencode\":\n      // opencode 1.x is multi-provider; under the hood it uses the\n      // Vercel AI SDK, which appends `/messages` and `/chat/completions`\n      // to the configured base URL WITHOUT prepending `/v1`. So opencode\n      // needs the base to ALREADY include `/v1`, unlike claude-code +\n      // codex which append it themselves. Verified via `--log-level\n      // DEBUG` - opencode hit `${ANTHROPIC_BASE_URL}/messages` and\n      // got a gateway 404 because the gateway exposes `/v1/messages`.\n      //\n      // Also: opencode's provider auto-detection at init time gates on\n      // ANTHROPIC_API_KEY (NOT ANTHROPIC_AUTH_TOKEN, which claude-code\n      // uses). Without it, opencode logs `providerID=openai found` /\n      // `providerID=opencode found` but NOT anthropic, then fails any\n      // `--model anthropic/...` invocation with ProviderModelNotFoundError.\n      // Set both so anthropic is detected AND the gateway gets the VK on\n      // the wire (the AI SDK forwards x-api-key from ANTHROPIC_API_KEY).\n      return {\n        vars: {\n          OPENAI_BASE_URL: `${gw}/v1`,\n          OPENAI_API_KEY: auth,\n          ANTHROPIC_BASE_URL: `${gw}/v1`,\n          ANTHROPIC_AUTH_TOKEN: auth,\n          ANTHROPIC_API_KEY: auth,\n        },\n      };\n    default:\n      return { vars: {} };\n  }\n}\n\n/**\n * Provider families the tool needs upstream. Used by `preflightWrapper`\n * to verify the org has at least one matching provider configured -\n * otherwise the gateway can authenticate the VK but has nothing to\n * route the request to, surfacing as a confusing tool-side error.\n *\n * Multi-provider tools (cursor, opencode) match any listed family.\n */\nconst TOOL_PROVIDER_FAMILIES: Record<string, string[]> = {\n  claude: [\"anthropic\"],\n  codex: [\"openai\"],\n  cursor: [\"anthropic\", \"openai\"],\n  gemini: [\"google\", \"gemini\"],\n  opencode: [\"anthropic\", \"openai\"],\n};\n\nexport interface PreflightResult {\n  ok: boolean;\n  /** Human-readable, action-oriented message rendered to stderr on failure. */\n  message?: string;\n  /**\n   * Set on a failure a later retry might clear on its own - the gateway data\n   * plane is momentarily unreachable. When absent/false the gateway path is\n   * structurally unusable for this account/org (no virtual key, no provider\n   * configured), so a remembered gateway choice is worth forgetting to re-offer\n   * direct OTLP next time.\n   */\n  retryable?: boolean;\n}\n\n/**\n * Whether to forget a remembered gateway path choice after a failed gateway\n * preflight. True only when the user had pinned gateway AND the failure is\n * structural (no virtual key / no provider) rather than a retryable\n * gateway-down, so the next run re-prompts and can offer direct OTLP instead\n * of dead-ending on the same pinned choice every time.\n */\nexport function shouldForgetGatewayPin(args: {\n  pinnedMode: string | undefined;\n  retryable: boolean | undefined;\n}): boolean {\n  return args.pinnedMode === \"gateway\" && args.retryable !== true;\n}\n\nexport interface PreflightOptions {\n  fetchImpl?: typeof fetch;\n  bootstrapImpl?: typeof getCliBootstrap;\n  /** Per-probe timeout, ms. Default 3000. */\n  timeoutMs?: number;\n}\n\n/**\n * Render the \"who to talk to\" footer attached to every preflight\n * failure message. Single source of truth so the admin-mailto format\n * stays consistent across the three failure shapes. Bootstrap is the\n * source of `adminEmail`; on legacy servers or unreachable control\n * planes it'll be null and we fall back to a generic line.\n */\nfunction renderContactFooter(adminEmail: string | null | undefined): string {\n  if (adminEmail) {\n    return `Need help? Contact your LangWatch admin: ${adminEmail}\\n`;\n  }\n  return `If you need help, contact your LangWatch admin.\\n`;\n}\n\n/**\n * Pre-exec probe for `langwatch <tool>` wrappers. Three layered checks,\n * each gracefully degrading rather than blocking on transient hiccups:\n *\n *   1. `cfg.default_personal_vk?.secret` present - without it the\n *      wrapper would silently inject no env vars and the underlying\n *      tool would call the upstream provider directly (api.anthropic.com\n *      etc.), surfacing as the wrong error or - when there's stale\n *      env from a prior session - a confusing ConnectionRefused\n *      against a stale base URL.\n *   2. `GET <gateway_url>/healthz` reachable. Catches \"data plane not\n *      running\" and bad `LANGWATCH_GATEWAY_URL` overrides. Fatal: if\n *      the gateway isn't reachable the tool will spin in a retry loop\n *      and there's no recovery. We don't name a specific run command\n *      (`make`, helm chart, docker compose, `npx @langwatch/server`,\n *      etc.) because deployments vary; point the user at the admin\n *      contact instead.\n *   3. `getCliBootstrap()` providers cover the tool's family. Catches\n *      the shape where login succeeds but the org has no AI provider\n *      configured yet, so the gateway has nothing to route to. 404 /\n *      missing-providers data passes through (older self-hosted\n *      servers without the endpoint).\n *\n * Bootstrap is fetched up-front (it lives on the control plane,\n * independent of the gateway data plane) so every failure message can\n * embed the org admin's email as a real contact path. A bootstrap\n * error is non-fatal; we just lose the admin mailto and continue.\n */\nexport async function preflightWrapper(\n  cfg: GovernanceConfig,\n  tool: string,\n  opts: PreflightOptions = {},\n): Promise<PreflightResult> {\n  const cp = cfg.control_plane_url.replace(/\\/+$/, \"\");\n  const bootstrap = await (opts.bootstrapImpl ?? getCliBootstrap)(cfg).catch(\n    () => null,\n  );\n  const adminEmail = bootstrap?.adminEmail ?? null;\n\n  if (!cfg.default_personal_vk?.secret) {\n    return {\n      ok: false,\n      message:\n        `No personal virtual key on this account.\\n` +\n        `Your organization needs at least one AI provider configured before\\n` +\n        `\\`langwatch ${tool}\\` can route requests.\\n` +\n        `If you're an admin, set one up at\\n` +\n        `  ${cp}/settings/model-providers\\n` +\n        `then run \\`langwatch login --device\\` to refresh your credentials.\\n` +\n        renderContactFooter(adminEmail),\n    };\n  }\n\n  const gw = cfg.gateway_url.replace(/\\/+$/, \"\");\n  const f = opts.fetchImpl ?? fetch;\n  const timeoutMs = opts.timeoutMs ?? 3000;\n  try {\n    const res = await f(`${gw}/healthz`, {\n      method: \"GET\",\n      signal: AbortSignal.timeout(timeoutMs),\n    });\n    if (!res.ok) {\n      return {\n        ok: false,\n        retryable: true,\n        message:\n          `AI Gateway at ${gw} returned HTTP ${res.status}.\\n` +\n          `The wrapper cannot route \\`langwatch ${tool}\\` requests until the\\n` +\n          `data plane is healthy. Check that the LangWatch gateway is running.\\n` +\n          renderContactFooter(adminEmail),\n      };\n    }\n  } catch (err) {\n    return {\n      ok: false,\n      retryable: true,\n      message:\n        `Cannot reach AI Gateway at ${gw}\\n` +\n        `  ${(err as Error).message}\\n` +\n        `Check that the LangWatch gateway is running, or set LANGWATCH_GATEWAY_URL\\n` +\n        `if you've deployed it elsewhere.\\n` +\n        renderContactFooter(adminEmail),\n    };\n  }\n\n  // The gateway program is opt-in per tool: an org enables it for a coding\n  // assistant by publishing that tool's coding-assistant tile in the AI Tools\n  // catalog. Without a tile for THIS tool the org hasn't turned the gateway on\n  // for it (direct OTLP ingestion stays available separately), so don't route\n  // a virtual key through it. `tools` undefined => legacy server that can't\n  // report the catalog; skip the gate for back-compat.\n  if (Array.isArray(bootstrap?.tools)) {\n    const published = bootstrap.tools.some((t) => t.slug === tool);\n    if (!published) {\n      return {\n        ok: false,\n        message:\n          `The gateway isn't enabled for \\`${tool}\\` in your organization.\\n` +\n          `An admin needs to publish a ${tool} coding-assistant tile in the\\n` +\n          `AI Tools catalog (with the gateway path enabled):\\n` +\n          `  ${cp}/settings/governance/tool-catalog\\n` +\n          renderContactFooter(adminEmail),\n      };\n    }\n  }\n\n  // The gateway routes through CONFIGURED provider credentials, not the curated\n  // model_provider catalog tiles (those only gate the /me one-click \"mint your\n  // own VK\" surface). Prefer the credential-derived families; fall back to the\n  // tile list only on legacy servers that don't send `gatewayProviders`.\n  const need = TOOL_PROVIDER_FAMILIES[tool];\n  const configured =\n    bootstrap?.gatewayProviders ?? bootstrap?.providers?.map((p) => p.name);\n  if (need && need.length > 0 && Array.isArray(configured)) {\n    const have = new Set(configured.map((n) => n.toLowerCase()));\n    const matches = need.filter((n) => have.has(n));\n    if (matches.length === 0) {\n      const list = need.map((n) => `\\`${n}\\``).join(\" or \");\n      return {\n        ok: false,\n        message:\n          `No ${list} provider credential is configured for your organization.\\n` +\n          `\\`langwatch ${tool}\\` needs at least one enabled provider to route\\n` +\n          `requests through the gateway. If you're an admin, add one at\\n` +\n          `  ${cp}/settings/model-providers\\n` +\n          renderContactFooter(adminEmail),\n      };\n    }\n  }\n\n  return { ok: true };\n}\n\n/**\n * When the wrapper is invoked without a usable config, decide whether to\n * auto-trigger the device-flow login inline or to fail fast. The device\n * flow needs a TTY (the user has to copy a code or click a browser link),\n * so default ON only when stdin is a TTY. CI/scripted callers can opt in\n * explicitly via `LANGWATCH_AUTO_LOGIN=1`, or opt out via\n * `LANGWATCH_AUTO_LOGIN=0` even on an interactive shell.\n */\nfunction shouldAutoLogin(): boolean {\n  const flag = process.env.LANGWATCH_AUTO_LOGIN;\n  if (flag === \"1\" || flag === \"true\") return true;\n  if (flag === \"0\" || flag === \"false\") return false;\n  return Boolean(process.stdin.isTTY);\n}\n\n/**\n * Run the named tool routed through the gateway. Inherits stdio so\n * the user gets the same interactive UX they'd have invoking the\n * tool directly. Exits the parent process with the child's exit\n * code (or 2 if the budget pre-check fired).\n */\nexport async function runWrapped(tool: string, args: string[]): Promise<never> {\n  let cfg = loadConfig();\n  if (!isLoggedIn(cfg)) {\n    if (!shouldAutoLogin()) {\n      process.stderr.write(\n        \"Not logged in. Run `langwatch login --device` first.\\n\",\n      );\n      process.exit(1);\n    }\n    process.stderr.write(\n      \"Not logged in. Starting device-flow login...\\n\",\n    );\n    try {\n      cfg = await runDeviceFlowLogin({ cfg });\n    } catch (err) {\n      process.stderr.write(\n        `login failed: ${(err as Error).message ?? \"unknown error\"}\\n`,\n      );\n      process.exit(1);\n    }\n    if (!isLoggedIn(cfg)) {\n      process.stderr.write(\"login did not complete - exiting\\n\");\n      process.exit(1);\n    }\n  }\n\n  // Budget pre-check - render Screen-8 box + exit 2 BEFORE exec.\n  const exceeded = await checkBudget(cfg);\n  if (exceeded) {\n    process.stderr.write(renderBudgetExceeded(exceeded));\n    if (exceeded.request_increase_url) {\n      cfg.last_request_increase_url = exceeded.request_increase_url;\n      try {\n        saveConfig(cfg);\n      } catch {\n        // Config write failure shouldn't change the spec'd exit\n        // code - the next `langwatch request-increase` falls back\n        // to the static page.\n      }\n    }\n    process.exit(2);\n  }\n\n  // Strip the wrapper-only `--tool-mode` flag from the args BEFORE anything\n  // forwards them to the real tool, and resolve any explicit override.\n  // Everything else stays verbatim + in order for the child invocation.\n  const { args: toolArgs, override: pathOverride } = parseToolModeFlag(args);\n\n  // Decide Path A (gateway) vs Path B (ingestion) for this run. Prompts\n  // (and remembers the answer) only when the org policy allows BOTH paths,\n  // stdin/stdout is a TTY, and there's no pinned preference / override.\n  // Runs BEFORE env injection + spawn so the prompt owns stdin.\n  let pathChoice;\n  try {\n    pathChoice = await resolveWrapperPath({\n      cfg,\n      tool,\n      args: toolArgs,\n      override: pathOverride,\n      // Re-check the org policy at run time so a path the admin disabled\n      // after login is respected without a re-login. Best-effort: on any\n      // failure resolveWrapperPath keeps the login-cached policy map.\n      refreshPolicies: (c) =>\n        getCliBootstrap(c).then((b) => b?.toolPolicies ?? null),\n    });\n  } catch (err) {\n    process.stderr.write(`path selection failed: ${(err as Error).message}\\n`);\n    process.exit(2);\n  }\n\n  const toolEnv = envForTool(cfg, tool);\n  const gatewayVars = toolEnv.vars;\n  const gatewayClears = toolEnv.clears ?? [];\n  let modeResult;\n  try {\n    modeResult = await resolveWrapperMode(\n      cfg,\n      tool,\n      gatewayVars,\n      gatewayClears,\n      pathChoice.mode,\n    );\n  } catch (err) {\n    // Path B (ingestion) setup can fail at mint time - e.g. the user has\n    // no personal workspace yet, or the control plane is unreachable. If\n    // the gateway path is allowed for this tool, surface a clear message\n    // and fall back to it rather than dead-ending. The both-paths-off\n    // `tool_disabled` policy error is NOT a mint failure, so it never\n    // falls back; it exits with the admin hint.\n    const isToolDisabled =\n      err instanceof GovernanceCliError && err.code === \"tool_disabled\";\n    const policy = resolvePlatformToolPolicy(tool, cfg.tool_policies);\n    if (pathChoice.mode === \"ingestion\" && policy.allowVk && !isToolDisabled) {\n      process.stderr.write(\n        `${lwTag()} couldn't set up direct OTLP ingestion for ${tool} ` +\n          `(${(err as Error).message}). Falling back to the gateway path.\\n`,\n      );\n      try {\n        modeResult = await resolveWrapperMode(\n          cfg,\n          tool,\n          gatewayVars,\n          gatewayClears,\n          \"gateway\",\n        );\n      } catch (err2) {\n        process.stderr.write(\n          `mode resolution failed: ${(err2 as Error).message}\\n`,\n        );\n        process.exit(2);\n      }\n    } else {\n      process.stderr.write(\n        `mode resolution failed: ${(err as Error).message}\\n`,\n      );\n      process.exit(2);\n    }\n  }\n\n  // Surface any platform-policy path change (e.g. the org admin turned\n  // direct OTLP off for this tool, so the wrapper routed through the\n  // gateway instead) so the member sees why the path differs.\n  if (modeResult.notice) {\n    process.stderr.write(`${modeResult.notice}\\n`);\n  }\n\n  if (modeResult.mode === \"gateway\") {\n    const probe = await preflightWrapper(cfg, tool);\n    if (!probe.ok) {\n      process.stderr.write(probe.message ?? \"preflight failed\\n\");\n      // A remembered gateway choice that can't actually serve this account/org\n      // (no virtual key / no provider configured) would re-fail every run. Drop\n      // the pin so the next run re-asks and the user can pick direct OTLP. A\n      // transient gateway-down failure keeps the pin (a retry may succeed).\n      if (\n        shouldForgetGatewayPin({\n          pinnedMode: cfg.tool_mode?.[tool],\n          retryable: probe.retryable,\n        })\n      ) {\n        const toolMode = { ...cfg.tool_mode };\n        delete toolMode[tool];\n        cfg.tool_mode = toolMode;\n        try {\n          saveConfig(cfg);\n          process.stderr.write(\n            `${lwTag()} cleared the saved gateway path for \\`${tool}\\`; ` +\n              `you'll be asked again next time so you can pick direct OTLP.\\n`,\n          );\n        } catch {\n          // Best-effort: a config write failure just leaves the pin in place.\n        }\n      }\n      process.exit(2);\n    }\n    if (modeResult.codexConfigPath) {\n      process.stderr.write(\n        `${lwTag()} wired [model_providers.langwatch] in ${modeResult.codexConfigPath}.\\n`,\n      );\n    }\n    if (modeResult.codexProfilePath) {\n      process.stderr.write(\n        `${lwTag()} wrote profile body to ${modeResult.codexProfilePath}.\\n`,\n      );\n    }\n  } else {\n    // ingestion mode side-effect feedback so the user sees what\n    // the wrapper just did on their behalf.\n    if (modeResult.newKeyMinted) {\n      process.stderr.write(\n        `${lwTag()} minted a personal ingestion key for ${tool}.\\n`,\n      );\n    }\n    if (modeResult.codexConfigPath) {\n      process.stderr.write(\n        `${lwTag()} wrote [otel] activation block to ${modeResult.codexConfigPath}.\\n`,\n      );\n    }\n\n    // Path B only: offer to persist the OTLP telemetry exports so a future\n    // plain `<tool>` (without the langwatch wrapper) captures\n    // automatically. Gated on ingestion mode + opt-out remembered. Runs\n    // BEFORE spawn so the prompt still owns stdin.\n    await maybeOfferIngestionShellRcPersist({\n      cfg,\n      tool,\n      vars: modeResult.vars,\n    });\n  }\n\n  // Scrub conflicting twins from the inherited parent env BEFORE merging\n  // our vars in. The clears list per tool exists because legacy creds\n  // exported in the user's shell (e.g. ANTHROPIC_API_KEY from direct\n  // Anthropic SDK usage) would otherwise race with the gateway-routed\n  // ANTHROPIC_AUTH_TOKEN we set, surfacing as the claude-code warning\n  // \"Both ANTHROPIC_AUTH_TOKEN and ANTHROPIC_API_KEY set, auth may not\n  // work as expected\" and, worse, occasionally letting the SDK pick the\n  // wrong credential.\n  const parentEnv = { ...process.env };\n  for (const key of modeResult.clears ?? []) {\n    delete parentEnv[key];\n  }\n  const env = { ...parentEnv, ...modeResult.vars };\n  // Forward the user's args verbatim and in order, minus the stripped\n  // wrapper flag (`--tool-mode`). Any mode-specific prepends (e.g. codex\n  // `--profile langwatch-gateway`) lead.\n  const finalArgs = [...(modeResult.extraArgs ?? []), ...toolArgs];\n\n  // Resolve the tool the way the user's own shell would: route it through\n  // their interactive login shell (zsh/bash) so aliases AND functions are\n  // honored - e.g. `alias claude='claude --dangerously-skip-permissions'`,\n  // not just the bare PATH binary. `-i` sources the rc file where aliases\n  // live; the wrapper's env (mode vars + clears) is re-applied *after* that\n  // so a user's rc can't clobber the gateway / OTLP wiring. Args ride\n  // positional params (\"$@\") and are never re-quoted. `tool` is whitelisted\n  // (claude/codex/cursor/gemini/opencode) so the command string is safe.\n  const shellName = (process.env.SHELL ?? \"\").split(\"/\").pop() ?? \"\";\n  const aliasShell =\n    process.platform !== \"win32\" && (shellName === \"zsh\" || shellName === \"bash\")\n      ? process.env.SHELL!\n      : null;\n\n  const notFoundMessage = `${tool} not found in PATH - install it first (https://docs.langwatch.ai/ai-gateway/governance/admin-setup#cli-device-flow-rest-api)`;\n\n  // Stamp the session start so the codex rollout harvest only reads rollout\n  // files this run produced (codex names them by start time + mtime).\n  const sessionStartMs = Date.now();\n\n  // Codex never puts the prompt or the assistant reply on the wire (its OTLP\n  // spans carry tokens + model only), but it writes the full transcript to an\n  // append-only rollout file whose per-turn `task_started` records the exact\n  // OTLP trace_id. Poll it WHILE codex runs and emit each turn the moment it\n  // completes, so content streams in per turn instead of one multi-megabyte\n  // burst on exit. The poll plus a final sweep on close are idempotent (the\n  // per-turn span id is trace_id-derived), so overlap dedups server-side.\n  const codexStreamer =\n    tool === \"codex\" &&\n    modeResult.mode === \"ingestion\" &&\n    modeResult.endpoint &&\n    modeResult.ingestionToken\n      ? createCodexIOStreamer({\n          sinceMs: sessionStartMs,\n          endpoint: `${modeResult.endpoint.replace(/\\/+$/, \"\")}/v1/traces`,\n          token: modeResult.ingestionToken,\n        })\n      : null;\n  let codexPoll: ReturnType<typeof setInterval> | null = null;\n  if (codexStreamer) {\n    let inFlight = false;\n    codexPoll = setInterval(() => {\n      // Skip a tick if the previous harvest (file read + POST, ≤5s) is still\n      // running so slow ticks can't pile up.\n      if (inFlight) return;\n      inFlight = true;\n      void codexStreamer\n        .harvest(Date.now())\n        .catch(() => 0)\n        .finally(() => {\n          inFlight = false;\n        });\n    }, CODEX_IO_POLL_MS);\n    // The child process drives the lifecycle; never let the poll keep the event\n    // loop alive on its own.\n    codexPoll.unref?.();\n  }\n\n  let child;\n  if (aliasShell) {\n    const q = (s: string) => `'${s.replace(/'/g, \"'\\\\''\")}'`;\n    const reapply = [\n      ...(modeResult.clears ?? []).map((k) => `unset ${k}`),\n      ...Object.entries(modeResult.vars).map(([k, v]) => `export ${k}=${q(v)}`),\n    ].join(\"; \");\n    // Resolve the tool inside the same login shell before handing over so a\n    // missing tool surfaces our actionable message rather than a bare\n    // `command not found`. `command -v` honors the aliases/functions/PATH the\n    // spawn below would use. The direct-spawn branch relies on ENOENT instead.\n    const guard = `command -v -- ${q(tool)} >/dev/null 2>&1 || { printf '%s\\\\n' ${q(notFoundMessage)} >&2; exit 127; }`;\n    const command = `${reapply ? `${reapply}; ` : \"\"}${guard}; ${tool} \"$@\"`;\n    child = spawn(aliasShell, [\"-i\", \"-c\", command, tool, ...finalArgs], {\n      stdio: \"inherit\",\n      env,\n    });\n  } else {\n    // Windows (npm installs the tools as `.cmd` shims, so resolve via the\n    // shell) or a shell we don't special-case (fish, etc.): spawn directly.\n    child = spawn(tool, finalArgs, {\n      stdio: \"inherit\",\n      env,\n      shell: process.platform === \"win32\",\n    });\n  }\n  child.on(\"error\", (err) => {\n    if ((err as NodeJS.ErrnoException).code === \"ENOENT\") {\n      process.stderr.write(`${notFoundMessage}\\n`);\n      process.exit(127);\n    }\n    process.stderr.write(`exec ${tool}: ${err.message}\\n`);\n    process.exit(1);\n  });\n  const exitCode = await new Promise<number>((resolve) => {\n    child.on(\"close\", (code) => resolve(code ?? 1));\n  });\n\n  // Stop polling and do one final sweep so the last turn (completed between the\n  // last poll and exit) still lands. Best-effort: a coding session must never\n  // fail or stall on the content harvest.\n  if (codexPoll) clearInterval(codexPoll);\n  if (codexStreamer) {\n    try {\n      await codexStreamer.harvest(Date.now());\n    } catch {\n      /* content recovery is non-essential; never block exit on it */\n    }\n  }\n\n  process.exit(exitCode);\n}\n","import chalk from \"chalk\";\n\n/** LangWatch accent orange, used to tint the CLI notice tag. */\nconst LANGWATCH_ORANGE = \"#ED8926\";\n\n/**\n * The styled `langwatch` tag that prefixes wrapper notices. A small spark\n * plus the brand name in bold orange so the chatter reads as LangWatch and\n * not a generic log line. chalk auto-strips the color when stdout is not a\n * TTY (piped / CI), so plain-text consumers still get `✦ langwatch ...`.\n *\n * Replaces the flat `langwatch:` prefix. Call sites read as a sentence,\n * e.g. `${lwTag()} saved.` -> \"✦ langwatch saved.\".\n */\nexport function lwTag(): string {\n  return chalk.hex(LANGWATCH_ORANGE).bold(\"✦ langwatch\");\n}\n","/**\n * Pre-exec budget probe + Screen-8 ASCII renderer for the langwatch\n * wrappers (`langwatch claude` / `codex` / `cursor` / `gemini`).\n *\n * Per `specs/ai-gateway/governance/budget-exceeded.feature`: before\n * any wrapped command exec's the underlying tool, the CLI hits\n * `GET /api/auth/cli/budget/status`. On 402, render the spec\n * canonical box and exit 2 (configuration / quota error) without\n * spawning the tool.\n */\n\nimport { type GovernanceConfig } from \"./config\";\n\nexport interface BudgetExceededPayload {\n  type: string;\n  scope: \"user\" | \"team\" | \"org\" | \"project\";\n  limit_usd: string;\n  spent_usd: string;\n  period: string; // \"month\" | \"week\" | \"day\" | ...\n  request_increase_url?: string;\n  admin_email?: string;\n}\n\nexport interface CheckBudgetOptions {\n  fetchImpl?: typeof fetch;\n}\n\n/**\n * Returns the 402 payload if the user is currently blocked, null\n * otherwise. 404 is treated as \"older self-hosted server doesn't\n * expose this endpoint yet — pass through\" so the CLI degrades\n * gracefully against legacy deploys. Network/5xx/etc. also\n * pass-through (the gateway's own 402 will surface via the wrapped\n * tool's error rendering as a fallback).\n */\nexport async function checkBudget(\n  cfg: GovernanceConfig,\n  opts: CheckBudgetOptions = {},\n): Promise<BudgetExceededPayload | null> {\n  if (!cfg.access_token) return null;\n  const f = opts.fetchImpl ?? fetch;\n  const url = cfg.control_plane_url.replace(/\\/+$/, \"\") + \"/api/auth/cli/budget/status\";\n  let res: Response;\n  try {\n    res = await f(url, {\n      method: \"GET\",\n      headers: {\n        Authorization: `Bearer ${cfg.access_token}`,\n        Accept: \"application/json\",\n      },\n    });\n  } catch {\n    return null; // network error — never block the user on this check\n  }\n  if (res.status === 200) return null;\n  if (res.status === 404) return null; // older server, no endpoint yet\n  if (res.status === 402) {\n    try {\n      const body = (await res.json()) as { error?: BudgetExceededPayload };\n      if (body.error?.type && body.error.scope) return body.error;\n    } catch {\n      // malformed payload — fall through, let the underlying tool's\n      // error render whatever the gateway returns\n    }\n  }\n  return null;\n}\n\n/**\n * Spec-canonical Screen-8 box. ASCII only — no ANSI codes — so\n * piping `langwatch claude | tee log` doesn't litter the log with\n * escape sequences. Lines match the budget-exceeded.feature\n * scenario character-for-character.\n */\n// Gateway emits root-form periods from the `GatewayBudgetWindow` Prisma\n// enum lowercased (\"month\", \"week\", \"day\", \"hour\", \"minute\", \"total\").\n// Naive `${period}ly` produces \"dayly\" / \"totally\" / \"minutely\" — map\n// explicitly. Unknown periods (e.g. older server adds \"rolling_24h\")\n// fall through to the raw value rather than render gibberish.\nconst PERIOD_LABEL: Record<string, string> = {\n  minute: \"per-minute\",\n  hour: \"hourly\",\n  day: \"daily\",\n  week: \"weekly\",\n  month: \"monthly\",\n  total: \"total\",\n};\n\nexport function renderBudgetExceeded(e: BudgetExceededPayload): string {\n  const period = (e.period || \"month\").toLowerCase();\n  const periodLabel = PERIOD_LABEL[period] ?? period;\n  const lines: string[] = [];\n  lines.push(\"⚠  Budget limit reached\");\n  lines.push(\"\");\n  lines.push(`   You've used $${e.spent_usd} of your $${e.limit_usd} ${periodLabel} budget.`);\n  lines.push(\"   To continue, ask your team admin to raise your limit.\");\n  lines.push(\"\");\n  if (e.admin_email) {\n    lines.push(`   Admin: ${e.admin_email}`);\n    lines.push(\"\");\n  }\n  lines.push(\"   Need urgent access? Run:\");\n  lines.push(\"     langwatch request-increase\");\n  return lines.join(\"\\n\") + \"\\n\";\n}\n","/**\n * Platform-tool policy table.\n *\n * Per-tool toggles that gate the two `langwatch <tool>` paths the\n * wrapper can take:\n *\n *   - allowVk: tool may route through the gateway via the user's\n *     personal VK (Path A). When false, the wrapper forces Path B\n *     even if a VK is present.\n *   - allowOtelDirect: tool may route via OTLP straight to\n *     `/api/otel/v1/logs` with the user's ingestion key (Path B).\n *     When false, the wrapper refuses to install Path B and surfaces\n *     a clear error.\n *\n * The resolver prefers the policy map the CLI cached at login\n * (`cfg.tool_policies`, served by the control plane's\n * PlatformToolPolicyService) and falls back to the hardcoded defaults\n * below when the cache is absent: an offline or legacy CLI that never\n * cached a map, or a tool the server did not return. The defaults must\n * stay in sync with the server-side PLATFORM_TOOL_POLICY_DEFAULTS.\n */\n\nexport type PlatformToolSlug =\n  | \"claude\"\n  | \"codex\"\n  | \"gemini\"\n  | \"opencode\"\n  | \"cursor\";\n\nexport interface PlatformToolPolicy {\n  allowVk: boolean;\n  allowOtelDirect: boolean;\n}\n\n/**\n * The login-cached policy map. Comes from config.json (untyped JSON),\n * so every slug is optional and a missing entry falls back to the\n * hardcoded default.\n */\nexport type PlatformToolPolicyMap = Partial<Record<string, PlatformToolPolicy>>;\n\nconst DEFAULTS: PlatformToolPolicy = {\n  allowVk: true,\n  allowOtelDirect: true,\n};\n\nexport const PLATFORM_TOOL_POLICIES: Record<PlatformToolSlug, PlatformToolPolicy> = {\n  claude: { ...DEFAULTS },\n  codex: { ...DEFAULTS },\n  gemini: { ...DEFAULTS },\n  opencode: { ...DEFAULTS },\n  // cursor is GUI-only; Path B is not meaningful (no terminal env\n  // reaches the agent panel). The wrapper still gates on this so\n  // future GUI integrations can flip allowOtelDirect to true.\n  cursor: { allowVk: true, allowOtelDirect: false },\n};\n\nfunction hardcodedPolicy(toolSlug: string): PlatformToolPolicy {\n  if (toolSlug in PLATFORM_TOOL_POLICIES) {\n    return PLATFORM_TOOL_POLICIES[toolSlug as PlatformToolSlug];\n  }\n  return DEFAULTS;\n}\n\n/**\n * Resolve the policy for a given tool slug. Prefers the login-cached\n * server map when it carries an entry for the tool; otherwise falls\n * back to the hardcoded defaults. A non-platform slug (typo) also\n * resolves to DEFAULTS so the wrapper never crashes.\n */\nexport function resolvePlatformToolPolicy(\n  toolSlug: string,\n  cachedPolicies?: PlatformToolPolicyMap,\n): PlatformToolPolicy {\n  const cached = cachedPolicies?.[toolSlug];\n  if (cached) return cached;\n  return hardcodedPolicy(toolSlug);\n}\n","/**\n * Persist the langwatch export block to the user's shell rc file\n * (~/.zshrc / ~/.bashrc / ~/.config/fish/config.fish) so a new\n * shell auto-picks up the gateway + OTLP env vars without running\n * `langwatch <tool>` as a wrapper.\n *\n * Spec for bug-bash item 1:\n *   1.2 - after login, OFFER to persist the export block. Y/n/never.\n *   1.3 - Remember choice. Stay quiet inside an already-configured\n *         shell (env already has the gateway vars set).\n *\n * Design notes:\n *   - The block is bracketed with marker comments so a second\n *     persist run is idempotent (regex replace, no duplicate\n *     blocks).\n *   - \"never\" persists `shell_rc_preference: \"skip\"` on the config\n *     so future logins on this machine stay quiet.\n *   - \"not now\" (n) does NOT persist - the next login re-asks. The\n *     in-shell quietness comes from the already-configured detect.\n *   - Detect \"already configured\" by checking process.env for both\n *     ANTHROPIC_BASE_URL and ANTHROPIC_AUTH_TOKEN. If either is\n *     present, assume the user already wired it up (via the rc\n *     file or by sourcing the export manually) and skip the\n *     prompt silently.\n */\n\nimport * as fs from \"node:fs\";\nimport * as os from \"node:os\";\nimport * as path from \"node:path\";\nimport * as readline from \"node:readline\";\n\nimport chalk from \"chalk\";\n\nimport { type GovernanceConfig, saveConfig } from \"./config\";\nimport { envForTool, type ToolEnv } from \"./wrapper\";\n\n/** Wrapped tools included in the union'd export block. */\nconst TOOLS = [\"claude\", \"codex\", \"cursor\", \"gemini\", \"opencode\"] as const;\n\nconst BLOCK_BEGIN = \"# >>> langwatch begin >>>\";\nconst BLOCK_END = \"# <<< langwatch end <<<\";\n\nexport type DetectedShell = \"zsh\" | \"bash\" | \"fish\";\n\n/**\n * Best-effort shell detection from $SHELL. Falls back to zsh on\n * macOS (default since Catalina) and bash on Linux. Returns null\n * when running under an unsupported shell (cmd, powershell, etc.)\n * - the persist flow skips entirely in that case.\n */\nexport function detectShell(): DetectedShell | null {\n  const raw = (process.env.SHELL ?? \"\").toLowerCase();\n  if (raw.includes(\"fish\")) return \"fish\";\n  if (raw.includes(\"zsh\")) return \"zsh\";\n  if (raw.includes(\"bash\")) return \"bash\";\n  if (process.platform === \"darwin\") return \"zsh\";\n  if (process.platform === \"linux\") return \"bash\";\n  return null;\n}\n\n/** Returns the absolute path of the shell rc file. */\nexport function rcPath(shell: DetectedShell): string {\n  const home = os.homedir();\n  switch (shell) {\n    case \"zsh\":\n      return path.join(home, \".zshrc\");\n    case \"bash\":\n      return path.join(home, \".bashrc\");\n    case \"fish\":\n      return path.join(home, \".config\", \"fish\", \"config.fish\");\n  }\n}\n\n/**\n * Whether the current shell already has the gateway env vars\n * exported. If true the persist prompt stays quiet (per 1.3).\n */\nexport function isShellAlreadyConfigured(): boolean {\n  return (\n    !!process.env.ANTHROPIC_BASE_URL && !!process.env.ANTHROPIC_AUTH_TOKEN\n  );\n}\n\n/**\n * Whether the shell rc file already has a langwatch marker block carrying\n * THIS export set. Lets the persist offer stay quiet when the user has\n * already installed the current exports but hasn't sourced the rc in this\n * shell yet (so the env isn't live in process.env). Checks the file on\n * disk, not just the environment.\n *\n * `requiredKeys` makes the match export-set aware: a bare marker block, or\n * a block for a DIFFERENT export set (e.g. a stale block missing the OTLP\n * vars this run needs), does NOT count as installed, so the offer still\n * fires and persists the current vars. Omit `requiredKeys` to test only\n * for the presence of a well-formed block.\n */\nexport function rcHasLangwatchBlock({\n  shell,\n  requiredKeys,\n}: {\n  shell: DetectedShell;\n  requiredKeys?: string[];\n}): boolean {\n  try {\n    const content = fs.readFileSync(rcPath(shell), \"utf8\");\n    const begin = content.indexOf(BLOCK_BEGIN);\n    const end = content.indexOf(BLOCK_END);\n    if (begin === -1 || end === -1 || end < begin) return false;\n    if (!requiredKeys || requiredKeys.length === 0) return true;\n    const block = content.slice(begin, end);\n    return requiredKeys.every((k) => block.includes(k));\n  } catch {\n    return false;\n  }\n}\n\n/**\n * Build the export-block body (without the begin/end markers) for\n * the given shell. Iterates the 5 wrapped tools and dedups env keys\n * so a multi-provider tool (cursor / opencode) doesn't repeat\n * OPENAI_* + ANTHROPIC_*.\n */\nexport function buildExportBlock(\n  cfg: GovernanceConfig,\n  shell: DetectedShell,\n): string {\n  const seen = new Set<string>();\n  const entries: Array<[string, string]> = [];\n  for (const tool of TOOLS) {\n    const env: ToolEnv = envForTool(cfg, tool);\n    for (const [k, v] of Object.entries(env.vars)) {\n      if (seen.has(k)) continue;\n      seen.add(k);\n      entries.push([k, v]);\n    }\n  }\n  const fmt =\n    shell === \"fish\"\n      ? ([k, v]: [string, string]) => `set -gx ${k} ${quote(v)}`\n      : ([k, v]: [string, string]) => `export ${k}=${quote(v)}`;\n  return entries.map(fmt).join(\"\\n\");\n}\n\nfunction quote(s: string): string {\n  if (!/[ \\t\\n'\"$\\\\]/.test(s)) return s;\n  return \"'\" + s.replace(/'/g, \"'\\\\''\") + \"'\";\n}\n\n/**\n * Format an env-var map into a shell export block (body only, no\n * begin/end markers) for the given shell. fish uses `set -gx KEY VALUE`;\n * posix shells (zsh / bash) use `export KEY=VALUE`. Values are quoted via\n * the same posix-safe quoter the rest of this module uses.\n *\n * Used for the Path B (ingestion) telemetry exports: pass the exact\n * OTEL_EXPORTER_OTLP_* env the wrapper computed for the run so a plain\n * `<tool>` (without the `langwatch` prefix) inherits it. Order follows\n * the map's insertion order so the block is stable across runs.\n */\nexport function buildOtelExportBlock(\n  vars: Record<string, string>,\n  shell: DetectedShell,\n): string {\n  const entries = Object.entries(vars);\n  const fmt =\n    shell === \"fish\"\n      ? ([k, v]: [string, string]) => `set -gx ${k} ${quote(v)}`\n      : ([k, v]: [string, string]) => `export ${k}=${quote(v)}`;\n  return entries.map(fmt).join(\"\\n\");\n}\n\n/**\n * Append (or replace, if the marker block already exists) the\n * export block to the shell rc file. Creates the file if missing.\n * Idempotent: a second run replaces the block in place rather\n * than duplicating it.\n *\n * Returns the path that was written for the caller to surface.\n */\nexport function persistBlockToRc(\n  shell: DetectedShell,\n  block: string,\n): string {\n  const file = rcPath(shell);\n  const dir = path.dirname(file);\n  fs.mkdirSync(dir, { recursive: true });\n  const wrapped = `${BLOCK_BEGIN}\\n${block}\\n${BLOCK_END}\\n`;\n\n  let existing = \"\";\n  try {\n    existing = fs.readFileSync(file, \"utf8\");\n  } catch {\n    // ENOENT - fresh file\n  }\n\n  const marker = new RegExp(\n    `${escapeRegex(BLOCK_BEGIN)}[\\\\s\\\\S]*?${escapeRegex(BLOCK_END)}\\\\n?`,\n    \"m\",\n  );\n  let next: string;\n  if (marker.test(existing)) {\n    next = existing.replace(marker, wrapped);\n  } else {\n    const needsNewline = existing.length > 0 && !existing.endsWith(\"\\n\");\n    next = existing + (needsNewline ? \"\\n\" : \"\") + \"\\n\" + wrapped;\n  }\n  fs.writeFileSync(file, next);\n  return file;\n}\n\nfunction escapeRegex(s: string): string {\n  return s.replace(/[.*+?^${}()|[\\]\\\\]/g, \"\\\\$&\");\n}\n\n/**\n * Y/n/never prompt for stdin. Returns:\n *   - \"yes\" → append the block now\n *   - \"no\" → skip this login, re-ask next time\n *   - \"never\" → set shell_rc_preference=skip so we stay quiet forever\n *   - \"skip\" → non-TTY / closed stdin; do nothing\n */\nexport type PersistChoice = \"yes\" | \"no\" | \"never\" | \"skip\";\n\nexport async function askPersistChoice(\n  rcPathHint: string,\n  tool: string,\n): Promise<PersistChoice> {\n  if (!process.stdin.isTTY) return \"skip\";\n\n  const rl = readline.createInterface({\n    input: process.stdin,\n    output: process.stdout,\n  });\n  const ans = await new Promise<string>((resolve) => {\n    rl.question(\n      `Install env vars to ${rcPathHint} so that next time the plain \\`${tool}\\` command keeps capturing telemetry data? [Y/n/never] `,\n      (a) => resolve(a),\n    );\n  });\n  rl.close();\n\n  const norm = ans.trim().toLowerCase();\n  if (norm === \"\" || norm === \"y\" || norm === \"yes\") return \"yes\";\n  if (norm === \"never\") return \"never\";\n  return \"no\";\n}\n\n/**\n * Ingestion-mode (Path B) variant of the shell-rc persist offer. Called\n * by the `langwatch <tool>` wrapper AFTER it resolves to ingestion mode,\n * so the user can install the tool's OTLP telemetry exports into their\n * shell rc. Once persisted, a plain `<tool>` invocation (without the\n * `langwatch` wrapper) inherits the OTEL_EXPORTER_OTLP_* env and captures\n * automatically - which is the whole point of \"installing\" the telemetry.\n *\n * Unlike the login-time gateway offer, this persists the exact OTEL env\n * the wrapper just computed for this run (`vars`), not the gateway block.\n * Y / n / never, same `shell_rc_preference=skip` opt-out. Stays quiet when\n * the shell already has the OTLP exporter env set.\n */\nexport async function maybeOfferIngestionShellRcPersist({\n  cfg,\n  tool,\n  vars,\n}: {\n  cfg: GovernanceConfig;\n  tool: string;\n  vars: Record<string, string>;\n}): Promise<void> {\n  if (cfg.shell_rc_preference === \"skip\") return;\n  // Already wired up - the OTLP exporter env is present in this shell.\n  if (process.env.OTEL_EXPORTER_OTLP_ENDPOINT) return;\n  const shell = detectShell();\n  if (!shell) return;\n  if (Object.keys(vars).length === 0) return;\n  // Already installed in the rc file, even if this shell hasn't sourced it\n  // yet (so the OTEL env isn't in process.env). Keyed on the current vars so\n  // a stale / different export block doesn't suppress installing this one.\n  if (rcHasLangwatchBlock({ shell, requiredKeys: Object.keys(vars) })) return;\n\n  const block = buildOtelExportBlock(vars, shell);\n\n  const target = rcPath(shell);\n  console.log();\n  const choice = await askPersistChoice(target, tool);\n  if (choice === \"skip\" || choice === \"no\") return;\n  if (choice === \"never\") {\n    cfg.shell_rc_preference = \"skip\";\n    try {\n      saveConfig(cfg);\n    } catch {\n      // best effort\n    }\n    return;\n  }\n  // \"yes\"\n  try {\n    const wrote = persistBlockToRc(shell, block);\n    console.log(\n      chalk.green(`  ✓ Installed langwatch telemetry exports to ${wrote}`),\n    );\n  } catch (err) {\n    console.log(\n      chalk.yellow(`  ! Couldn't write to ${target}: ${(err as Error).message}`),\n    );\n  }\n}\n","/**\n * Idempotent merge of `experimental.openTelemetry: true` into\n * `~/.config/opencode/opencode.jsonc`.\n *\n * opencode's OTLP exporter is gated on the `experimental.openTelemetry`\n * config flag — without it the SDK is constructed but never exports a\n * single span, even with all the OTEL_EXPORTER_OTLP_* env vars set on\n * the child. Path B (langwatch opencode run) is dead-on-arrival without\n * this flag flipped, so the wrapper writes it on first ingestion mode\n * invocation. Idempotent: if the key is already set true, we don't\n * touch the file. If it's set false explicitly, we DON'T overwrite —\n * the user expressed intent, surface a warning at the call site.\n *\n * The flag lives in `experimental.openTelemetry` per the binary's\n * lookup path `h.experimental?.openTelemetry` — a JSON-style nested\n * key, not a flat one.\n */\n\nimport fs from \"node:fs\";\nimport os from \"node:os\";\nimport path from \"node:path\";\n\nexport interface OpencodeConfigFlagResult {\n  /** `created` (new file), `updated` (added/changed flag), `unchanged` (already true), `disabled-by-user` (user set false). */\n  action: \"created\" | \"updated\" | \"unchanged\" | \"disabled-by-user\";\n  /** Absolute path of the file that was inspected / written. */\n  path: string;\n}\n\n/** Default config.jsonc path under the user's home directory. */\nexport function defaultOpencodeConfigPath(): string {\n  const xdg = process.env.XDG_CONFIG_HOME;\n  const configHome = xdg && xdg.length > 0 ? xdg : path.join(os.homedir(), \".config\");\n  return path.join(configHome, \"opencode\", \"opencode.jsonc\");\n}\n\n/**\n * Strip the most common JSONC noise (// line + /* block comments)\n * before JSON.parse. opencode's default config is a 2-line file with\n * just a $schema field, so this stays simple — not a full JSONC parser.\n */\nfunction stripJsoncComments(s: string): string {\n  return s\n    .replace(/\\/\\*[\\s\\S]*?\\*\\//g, \"\")\n    .replace(/^\\s*\\/\\/.*$/gm, \"\");\n}\n\n/**\n * Set `experimental.openTelemetry = true` in the opencode config.jsonc.\n * Preserves all other top-level keys. Behaviour:\n *\n * - Missing file: write a fresh JSON document with `$schema` +\n *   `experimental.openTelemetry: true`. Action: `created`.\n * - File present, flag missing: deep-merge under `experimental`,\n *   re-serialize the whole document. Action: `updated`.\n * - File present, flag === true: no write. Action: `unchanged`.\n * - File present, flag === false: bail without overwriting; caller\n *   logs a warning so the user knows Path B will silently produce no\n *   spans until they flip it. Action: `disabled-by-user`.\n *\n * JSONC comments + trailing commas in the existing file are preserved\n * approximately by stripping them for parse + re-emitting as plain\n * JSON. A user with a heavily annotated config will lose comments\n * after this runs — acceptable for an experimental flag the wrapper\n * manages.\n */\nexport function setOpencodeOpenTelemetryFlag(\n  options: { filePath?: string } = {},\n): OpencodeConfigFlagResult {\n  const filePath = options.filePath ?? defaultOpencodeConfigPath();\n\n  if (!fs.existsSync(filePath)) {\n    fs.mkdirSync(path.dirname(filePath), { recursive: true });\n    const content =\n      JSON.stringify(\n        {\n          $schema: \"https://opencode.ai/config.json\",\n          experimental: { openTelemetry: true },\n        },\n        null,\n        2,\n      ) + \"\\n\";\n    fs.writeFileSync(filePath, content, { mode: 0o600 });\n    return { action: \"created\", path: filePath };\n  }\n\n  const raw = fs.readFileSync(filePath, \"utf8\");\n  let parsed: Record<string, unknown>;\n  try {\n    parsed = JSON.parse(stripJsoncComments(raw)) as Record<string, unknown>;\n  } catch {\n    parsed = { $schema: \"https://opencode.ai/config.json\" };\n  }\n\n  const experimental =\n    (parsed.experimental as Record<string, unknown> | undefined) ?? {};\n  const prior = experimental.openTelemetry;\n  if (prior === true) return { action: \"unchanged\", path: filePath };\n  if (prior === false) return { action: \"disabled-by-user\", path: filePath };\n\n  parsed.experimental = { ...experimental, openTelemetry: true };\n  fs.writeFileSync(filePath, JSON.stringify(parsed, null, 2) + \"\\n\", {\n    mode: 0o600,\n  });\n  return { action: \"updated\", path: filePath };\n}\n","import * as fs from \"node:fs\";\nimport * as os from \"node:os\";\nimport * as path from \"node:path\";\n\nexport type GeminiSettingsPreflightAction =\n  | \"oauth-selected\"\n  | \"api-key-selected\"\n  | \"no-settings\"\n  | \"parse-error\";\n\nexport interface GeminiSettingsPreflightResult {\n  action: GeminiSettingsPreflightAction;\n  warned: boolean;\n}\n\nexport interface GeminiSettingsPreflightOptions {\n  filePath?: string;\n  writeLine?: (line: string) => void;\n}\n\nexport function defaultGeminiSettingsPath(): string {\n  const home = process.env.HOME ?? os.homedir();\n  return path.join(home, \".gemini\", \"settings.json\");\n}\n\nfunction stripJsoncComments(s: string): string {\n  return s\n    .replace(/\\/\\*[\\s\\S]*?\\*\\//g, \"\")\n    .replace(/^\\s*\\/\\/.*$/gm, \"\");\n}\n\nexport function warnIfGeminiOAuthSelected(\n  options: GeminiSettingsPreflightOptions = {},\n): GeminiSettingsPreflightResult {\n  const filePath = options.filePath ?? defaultGeminiSettingsPath();\n  const writeLine =\n    options.writeLine ?? ((line: string) => process.stderr.write(line + \"\\n\"));\n\n  if (!fs.existsSync(filePath)) {\n    return { action: \"no-settings\", warned: false };\n  }\n\n  let raw: string;\n  try {\n    raw = fs.readFileSync(filePath, \"utf8\");\n  } catch {\n    return { action: \"parse-error\", warned: false };\n  }\n\n  let parsed: unknown;\n  try {\n    parsed = JSON.parse(stripJsoncComments(raw));\n  } catch {\n    return { action: \"parse-error\", warned: false };\n  }\n\n  const selectedType = readSelectedType(parsed);\n\n  if (selectedType === \"gemini-oauth\") {\n    writeLine(\n      \"warning: ~/.gemini/settings.json has security.auth.selectedType=\\\"gemini-oauth\\\". \" +\n        \"gemini-cli 0.46 will use cached OAuth and ignore GOOGLE_API_KEY / GEMINI_API_KEY, \" +\n        \"so this `langwatch gemini` call will bypass the gateway. \" +\n        \"To route through langwatch: edit ~/.gemini/settings.json and set \" +\n        \"security.auth.selectedType to \\\"gemini-api-key\\\".\",\n    );\n    return { action: \"oauth-selected\", warned: true };\n  }\n\n  return { action: \"api-key-selected\", warned: false };\n}\n\nfunction readSelectedType(parsed: unknown): string | null {\n  if (parsed === null || typeof parsed !== \"object\") return null;\n  const security = (parsed as Record<string, unknown>).security;\n  if (security === null || typeof security !== \"object\") return null;\n  const auth = (security as Record<string, unknown>).auth;\n  if (auth === null || typeof auth !== \"object\") return null;\n  const selectedType = (auth as Record<string, unknown>).selectedType;\n  return typeof selectedType === \"string\" ? selectedType : null;\n}\n","/**\n * Wrapper mode selection - Path A (gateway) vs Path B (ingestion).\n *\n * Decides, before each `langwatch <tool>` invocation, which routing\n * shape to apply:\n *\n *   - Path A (gateway): VK present + provider configured + user\n *     hasn't opted out -> inject the base-URL swap envs from\n *     envForTool(). Gateway captures I/O server-side; no OTel\n *     emission from the child.\n *   - Path B (ingestion): no VK (Claude Max-style subscription,\n *     user explicitly opted in) -> mint (or reuse a cached) personal\n *     ingest key (sk-lw-*) for this tool, write the [otel] activation\n *     block to ~/.codex/config.toml (codex only), return the OTel\n *     exporter env block for the child.\n *\n * The two modes are mutually exclusive per the no-double-trace\n * rule - gateway capture + OTel emission of the same call would\n * double-count both traces and cost.\n *\n * Persisted preference lives at cfg.tool_mode[tool]; an unset\n * entry resolves at runtime as \"gateway if VK present else\n * ingestion\" with no prompt. Future iterations can layer a\n * first-run prompt similar to shell-rc.ts on top.\n */\n\nimport {\n  writeCodexGatewayBlock,\n  writeCodexOtelBlock,\n} from \"@/cli/utils/codex-config-toml\";\nimport { setOpencodeOpenTelemetryFlag } from \"@/cli/utils/opencode-config-flag\";\n\nimport { lwTag } from \"./brand\";\nimport type { GovernanceConfig } from \"./config\";\nimport { saveConfig } from \"./config\";\nimport {\n  extractLookupIdFromToken,\n  GovernanceCliError,\n  listIngestionKeys,\n  mintIngestionKey,\n} from \"./cli-api\";\nimport { warnIfGeminiOAuthSelected } from \"./gemini-settings-preflight\";\nimport { resolvePlatformToolPolicy } from \"./platform-tool-policy\";\n\nexport type WrapperMode = \"gateway\" | \"ingestion\";\n\nexport interface WrapperModeResult {\n  mode: WrapperMode;\n  /** Env additions to merge into the child process.env. */\n  vars: Record<string, string>;\n  /**\n   * Path of the codex config.toml that was created / updated. Set\n   * for both codex Path A (writes [model_providers.langwatch]) and\n   * Path B (writes [otel]).\n   */\n  codexConfigPath?: string;\n  /**\n   * Path of the sibling profile file\n   * (~/.codex/langwatch-gateway.config.toml). Set only on codex\n   * Path A. codex 0.134+ requires the profile body in a separate\n   * file when --profile is passed.\n   */\n  codexProfilePath?: string;\n  /**\n   * Extra args to prepend to the child invocation. Used for codex\n   * Path A: `--profile langwatch-gateway` forces the new provider\n   * entry without touching the user's default model_provider.\n   */\n  extraArgs?: string[];\n  /**\n   * Env-var names to STRIP from the inherited parent environment\n   * before merging the wrapper's vars in. Propagated from the\n   * per-tool ToolEnv.clears so the resolver can pass legacy-twin\n   * scrubs through to the spawn step (e.g. claude clears\n   * ANTHROPIC_API_KEY so claude-code 2.x doesn't warn \"Both\n   * ANTHROPIC_AUTH_TOKEN and ANTHROPIC_API_KEY set, auth may not\n   * work as expected\").\n   */\n  clears?: string[];\n  /** True when the wrapper minted a fresh ingest key (vs reused a cached one). */\n  newKeyMinted?: boolean;\n  /**\n   * Path B (ingestion) only: the OTLP base endpoint (`.../api/otel`) and the\n   * ingest key. The wrapper uses these AFTER the child exits to POST codex's\n   * recovered turn input/output (from the rollout transcript) onto codex's own\n   * trace_ids, since codex never puts content on the wire itself.\n   */\n  endpoint?: string;\n  ingestionToken?: string;\n  /**\n   * Optional one-line notice for the wrapper to print to stderr, set when\n   * the platform policy changed the resolved path (e.g. the org admin turned\n   * direct OTLP off for this tool, so the wrapper routed through the gateway\n   * instead). The member sees why the path differs from the default.\n   */\n  notice?: string;\n}\n\nconst SOURCE_TYPE_BY_TOOL: Record<string, string> = {\n  claude: \"claude_code\",\n  codex: \"codex\",\n  gemini: \"gemini\",\n  opencode: \"opencode\",\n};\n\n/**\n * Resolve mode for a single tool invocation. Returns the env block\n * the wrapper should hand to the child process. May persist a\n * refreshed ingestion token cache to ~/.langwatch/config.json as a\n * side effect.\n *\n * Does NOT prompt the user. The path-selection UX (interactive select\n * when both paths are allowed) lives upstream in `resolveWrapperPath`,\n * which passes its decision in via `forcedMode`. When `forcedMode` is\n * omitted the resolver falls back to the legacy state-only derivation\n * (persisted tool_mode, else VK-present-implies-gateway).\n *\n * The platform policy still GATES the resolved mode here (downgrade /\n * throw) regardless of how the mode was chosen, so a forced mode the\n * org admin disabled is handled the same as before.\n */\nexport async function resolveWrapperMode(\n  cfg: GovernanceConfig,\n  tool: string,\n  gatewayVars: Record<string, string>,\n  gatewayClears: string[] = [],\n  forcedMode?: WrapperMode,\n): Promise<WrapperModeResult> {\n  const persistedMode = cfg.tool_mode?.[tool];\n  const hasVk = !!cfg.default_personal_vk?.secret;\n  // Prefer the per-(org, tool) policy the CLI cached at login\n  // (cfg.tool_policies, from the control plane's PlatformToolPolicyService).\n  // An offline / legacy CLI with no cached map falls back to the hardcoded\n  // defaults inside the resolver.\n  const policy = resolvePlatformToolPolicy(tool, cfg.tool_policies);\n\n  if (!policy.allowVk && !policy.allowOtelDirect) {\n    throw new GovernanceCliError(\n      403,\n      \"tool_disabled\",\n      `Tool '${tool}' is disabled in the platform policy (both gateway and direct OTLP paths off). Ask your org admin to enable allow_vk or allow_otel_direct.`,\n    );\n  }\n\n  let notice: string | undefined;\n\n  // EFFECTIVE mode rules:\n  //   forcedMode set        -> use it (the path-selection UX upstream\n  //                            already applied flag / pref / prompt /\n  //                            single-allowed-path; we just honor it).\n  //   persisted=\"gateway\"   -> gateway (even if VK absent; preflight surfaces the gap)\n  //   persisted=\"ingestion\" -> ingestion\n  //   persisted=\"ask\" / unset:\n  //     hasVk -> gateway (no surprise: VK users keep current behavior)\n  //     no VK -> ingestion (auto-install Path B; closes the \"$5 VPS\" scenario)\n  //\n  // Platform policy then GATES the resolved mode (the both-disabled case\n  // already threw above, so exactly one path is available when a swap is\n  // needed):\n  //   - mode=gateway + !allowVk          -> downgrade to ingestion\n  //   - mode=ingestion + !allowOtelDirect -> route through the gateway\n  //     (never minting an ingestion key the admin disabled)\n  let mode: WrapperMode =\n    forcedMode ??\n    (persistedMode === \"gateway\"\n      ? \"gateway\"\n      : persistedMode === \"ingestion\"\n        ? \"ingestion\"\n        : hasVk\n          ? \"gateway\"\n          : \"ingestion\");\n\n  // Symmetric fall-back: when the resolved mode is disabled but the\n  // OTHER mode is allowed, swap into it rather than throwing. Lets\n  // cursor (allowVk=true, allowOtelDirect=false) keep working via\n  // gateway when no VK is yet configured (preflight surfaces the\n  // missing VK separately, same as before this gate existed).\n  //\n  // The direct-OTLP gate sits ABOVE the ingestion-key mint below: when\n  // the admin disabled direct OTLP for this tool, the wrapper never\n  // reaches mintIngestionKey; it routes through the gateway (allowVk is\n  // guaranteed true here, since the both-disabled case threw above).\n  if (mode === \"gateway\" && !policy.allowVk) {\n    mode = \"ingestion\";\n    notice = `${lwTag()} gateway path is disabled for ${tool} by your org admin; using direct OTLP ingestion instead.`;\n  }\n  if (mode === \"ingestion\" && !policy.allowOtelDirect) {\n    mode = \"gateway\";\n    notice = `${lwTag()} direct OTLP ingestion is disabled for ${tool} by your org admin; routing through the gateway instead.`;\n  }\n\n  if (mode === \"gateway\") {\n    if (tool === \"gemini\") {\n      warnIfGeminiOAuthSelected();\n    }\n    // Codex 0.130+ defers to ChatGPT OAuth by default and ignores\n    // OPENAI_API_KEY unless the active model_provider is an\n    // explicit env-keyed entry. Write a langwatch provider +\n    // profile to ~/.codex/config.toml and force codex into it via\n    // `--profile`. Other tools (claude/gemini/cursor/opencode)\n    // honour their base-URL+API-key env directly, no toml needed.\n    if (tool === \"codex\") {\n      const gw = writeCodexGatewayBlock({\n        gatewayUrl: cfg.gateway_url,\n        envKey: \"OPENAI_API_KEY\",\n      });\n      return {\n        mode,\n        vars: gatewayVars,\n        clears: gatewayClears,\n        codexConfigPath: gw.path,\n        codexProfilePath: gw.profilePath,\n        extraArgs: [\"--profile\", gw.profile],\n        notice,\n      };\n    }\n    return { mode, vars: gatewayVars, clears: gatewayClears, notice };\n  }\n\n  // INGESTION mode: ensure key + (for codex) toml.\n  const sourceType = SOURCE_TYPE_BY_TOOL[tool];\n  if (!sourceType) {\n    // No ingestion template defined for this tool (cursor is the\n    // current example - GUI app, no useful OTel). Fall through to\n    // gateway shape; the existing preflight will tell the user\n    // what's missing.\n    return { mode: \"gateway\", vars: gatewayVars, clears: gatewayClears, notice };\n  }\n\n  // Defense-in-depth: the direct-OTLP gate above already routes to the\n  // gateway when allowOtelDirect is off, so this mint is unreachable in\n  // that case. Guard it explicitly so a future refactor of the gate can\n  // never silently mint an ingestion key the admin disabled.\n  if (!policy.allowOtelDirect) {\n    throw new GovernanceCliError(\n      403,\n      \"otel_direct_disabled\",\n      `Direct OTLP ingestion is disabled for '${tool}' by your org admin. Ask them to enable allow_otel_direct, or run with the gateway path.`,\n    );\n  }\n\n  // Reuse a cached personal ingest key (sk-lw-*) for this source when\n  // present; otherwise mint a fresh one. The mint route returns the\n  // plaintext key once, so we persist it to the per-tool cache below\n  // and read it back on subsequent invocations rather than re-minting.\n  //\n  // Stale-cache check (#4755): before reusing a cached key, confirm it is\n  // still live on the platform. Token format: `ik-lw-{16-char lookupId}_{secret}`.\n  // If the server resolves and the lookupId is absent → the key was revoked\n  // (hard-cut rotation also invalidates the cache) → mint fresh and overwrite.\n  // If the request rejects (offline / older server without this endpoint) →\n  // offline-first fallback: reuse the cache so air-gapped / degraded environments\n  // still work.\n  const cached = cfg.default_personal_ingest_keys?.[sourceType];\n  let token: string;\n  let prefix: string | undefined;\n  let endpoint: string;\n  let minted: boolean;\n  if (cached?.secret) {\n    const cachedLookupId = extractLookupIdFromToken(cached.secret);\n    let cacheIsLive = true; // assume live; falsified when server confirms otherwise\n    try {\n      const liveKeys = await listIngestionKeys(cfg);\n      // Server resolved — verify the cached lookupId is still present for this sourceType\n      const liveEntry = liveKeys.find(\n        (k) => k.sourceType === sourceType && k.lookupId === cachedLookupId,\n      );\n      if (!liveEntry) {\n        // Key was revoked or rotated on the platform — treat as no cache\n        cacheIsLive = false;\n      }\n    } catch {\n      // Network error / older server without the endpoint: reuse cache as-is\n      // (offline-first fallback — hard-cut rotation is a re-mint-kills-old\n      // invariant, so a genuinely revoked key will self-correct next time the\n      // device is online).\n    }\n    if (cacheIsLive) {\n      token = cached.secret;\n      prefix = cached.prefix;\n      endpoint = `${cfg.control_plane_url.replace(/\\/+$/, \"\")}/api/otel`;\n      minted = false;\n    } else {\n      const r = await mintIngestionKey(cfg, sourceType);\n      token = r.token;\n      prefix = r.prefix;\n      endpoint = r.endpoint;\n      minted = true;\n    }\n  } else {\n    const r = await mintIngestionKey(cfg, sourceType);\n    token = r.token;\n    prefix = r.prefix;\n    endpoint = r.endpoint;\n    minted = true;\n  }\n\n  const vars = buildOtelEnvBlock(tool, endpoint, token);\n\n  let codexConfigPath: string | undefined;\n  if (tool === \"codex\") {\n    // codex's OTLP/HTTP exporter sends every signal to the configured\n    // endpoint verbatim - it does NOT append `/v1/traces` the way the\n    // OTel SDKs in Node/Python/Go do. Spell the trace-signal suffix\n    // out here so the POST lands on the real handler. codex only\n    // emits traces today (no logs/metrics), so one suffix suffices.\n    const result = writeCodexOtelBlock({\n      endpoint: `${endpoint}/v1/traces`,\n      ingestionToken: token,\n      environment: cfg.organization?.slug ?? \"langwatch\",\n    });\n    codexConfigPath = result.path;\n  }\n\n  if (tool === \"opencode\") {\n    // opencode constructs its OTLP exporter but only EMITS spans when\n    // `experimental.openTelemetry` is true in ~/.config/opencode/opencode.jsonc.\n    // Without this the OTEL_EXPORTER_OTLP_* env vars we set below are\n    // accepted-and-ignored - Path B silently produces nothing. Idempotent\n    // merge: if the user already turned it on, no write; if they\n    // explicitly set false, we don't overwrite their intent.\n    setOpencodeOpenTelemetryFlag();\n  }\n\n  // Persist mode + (when freshly minted) the ingest key so the next\n  // invocation skips re-deriving the mode and reuses the cached key\n  // instead of minting again.\n  const next: GovernanceConfig = {\n    ...cfg,\n    tool_mode: { ...(cfg.tool_mode ?? {}), [tool]: \"ingestion\" },\n  };\n  if (minted) {\n    next.default_personal_ingest_keys = {\n      ...(cfg.default_personal_ingest_keys ?? {}),\n      [sourceType]: { secret: token, prefix },\n    };\n  }\n  try {\n    saveConfig(next);\n  } catch {\n    // Best-effort cache - failure to persist doesn't block this run.\n  }\n\n  return {\n    mode,\n    vars,\n    codexConfigPath,\n    newKeyMinted: minted,\n    notice,\n    endpoint,\n    ingestionToken: token,\n  };\n}\n\nfunction buildOtelEnvBlock(\n  tool: string,\n  endpoint: string,\n  token: string,\n): Record<string, string> {\n  const base = {\n    OTEL_EXPORTER_OTLP_ENDPOINT: endpoint,\n    OTEL_EXPORTER_OTLP_HEADERS: `Authorization=Bearer ${token}`,\n  };\n\n  switch (tool) {\n    case \"claude\":\n      // Three further OTel unlock knobs found in the claude-code 2.x\n      // bundled binary string sweep (alongside OTEL_LOG_USER_PROMPTS\n      // which we already set), all four officially documented on\n      // code.claude.com/docs/en/monitoring-usage:\n      //   OTEL_LOG_TOOL_DETAILS  - lifts tool_input / tool_parameters\n      //     attrs (Bash command text, Edit diffs, Read file paths,\n      //     etc) onto tool_decision + tool_result events. The\n      //     receiver-side previously had only `tool_input_size_bytes`\n      //     and `tool_result_size_bytes` - proven across the\n      //     andre-claude-tool-calls + sergey-third-eye dump set.\n      //   OTEL_LOG_TOOL_CONTENT  - TRACES-ONLY + requires beta\n      //     tracing. claude 2.x is LOGS-ONLY today so this is a\n      //     no-op for us. Set anyway as forward-compat for when\n      //     claude turns on traces. Tool I/O on the logs path\n      //     actually comes from TOOL_DETAILS + RAW_API_BODIES.\n      //   OTEL_LOG_RAW_API_BODIES - emits two NEW event types\n      //     `api_request_body` + `api_response_body` carrying the\n      //     FULL JSON of every message (system prompts + user content\n      //     + assistant text + tool_use blocks). THIS IS THE ONLY\n      //     surface that carries the assistant response text - every\n      //     other event (api_request, user_prompt, tool_*) is\n      //     metadata only. Andre's live-dogfood (proxy intercept on\n      //     :4318) found \"UNLOCK-KNOBS-TEST-PROOF-7777\" in\n      //     api_response_body.content[].text with this flag set. Also\n      //     the heaviest payload class (system prompts can be 100KB+,\n      //     message history grows turn-over-turn) - same fat-payload\n      //     class as the CH merge memory-ceiling incident\n      //     [[project_skai_ch_merge_memory_ceiling_outage]].\n      //\n      // Default policy: ALL FOUR knobs ON. rchaves \"fix everything,\n      // collect all humanly possible\". Payload risk is bounded:\n      // claude 2.x caps api_request_body + api_response_body at 60KB\n      // INLINE per event (inline is the default; the optional\n      // file:<dir> mode that writes untruncated bodies to disk is NOT\n      // enabled). Alexis ships a complementary receiver-side guard\n      // in the same PR as defense-in-depth on fold accumulation +\n      // a Body cap in case future claude versions remove the 60KB\n      // inline limit. PII / logging-opt-out controls already live on\n      // the platform settings page. Note: extended-thinking content\n      // is ALWAYS redacted by claude from raw bodies - we cannot\n      // capture it regardless of flag state.\n      return {\n        CLAUDE_CODE_ENABLE_TELEMETRY: \"1\",\n        OTEL_TRACES_EXPORTER: \"otlp\",\n        OTEL_LOGS_EXPORTER: \"otlp\",\n        OTEL_METRICS_EXPORTER: \"otlp\",\n        OTEL_EXPORTER_OTLP_PROTOCOL: \"http/json\",\n        OTEL_LOG_USER_PROMPTS: \"1\",\n        OTEL_LOG_TOOL_DETAILS: \"1\",\n        OTEL_LOG_TOOL_CONTENT: \"1\",\n        OTEL_LOG_RAW_API_BODIES: \"1\",\n        ...base,\n        OTEL_RESOURCE_ATTRIBUTES: \"service.name=claude-code\",\n      };\n    case \"codex\":\n      return {\n        OTEL_TRACES_EXPORTER: \"otlp\",\n        OTEL_EXPORTER_OTLP_PROTOCOL: \"http/json\",\n        ...base,\n        OTEL_RESOURCE_ATTRIBUTES: \"service.name=codex\",\n      };\n    case \"gemini\":\n      // gemini-cli 0.46 telemetry resolver (packages/core/dist/src/telemetry/config.js):\n      //   target ∈ {local, gcp} - NOT otlp. The JSON-schema doc string\n      //   mentions otlp as an \"example\", but the runtime validator\n      //   (parseTelemetryTargetValue) only accepts local|gcp; passing\n      //   otlp throws FatalConfigError at startup.\n      //   To forward spans + log records to our OTLP endpoint we use\n      //   `local` (in-process exporters) + `useCollector=true` which\n      //   routes through @opentelemetry/exporter-trace-otlp-http +\n      //   exporter-logs-otlp-http to GEMINI_TELEMETRY_OTLP_ENDPOINT\n      //   (falls back to OTEL_EXPORTER_OTLP_ENDPOINT).\n      //   `traces=true` enables the detail-attribute span path so the\n      //   user prompt + tool calls land as span attributes (not just\n      //   token counts).\n      //   `logPrompts=true` is what makes gemini-cli embed the actual\n      //   user prompt text in the user_prompt event - without it the\n      //   receiver-side fold has no input text to lift onto\n      //   langwatch.input.value, same class as claude-code.\n      return {\n        GEMINI_TELEMETRY_ENABLED: \"true\",\n        GEMINI_TELEMETRY_TARGET: \"local\",\n        GEMINI_TELEMETRY_USE_COLLECTOR: \"true\",\n        GEMINI_TELEMETRY_TRACES_ENABLED: \"true\",\n        GEMINI_TELEMETRY_OTLP_PROTOCOL: \"http\",\n        GEMINI_TELEMETRY_OTLP_ENDPOINT: endpoint,\n        GEMINI_TELEMETRY_LOG_PROMPTS: \"true\",\n        OTEL_TRACES_EXPORTER: \"otlp\",\n        OTEL_EXPORTER_OTLP_PROTOCOL: \"http/json\",\n        ...base,\n        OTEL_RESOURCE_ATTRIBUTES: \"service.name=gemini-cli\",\n      };\n    case \"opencode\":\n      return {\n        OTEL_TRACES_EXPORTER: \"otlp\",\n        OTEL_LOGS_EXPORTER: \"otlp\",\n        OTEL_METRICS_EXPORTER: \"otlp\",\n        OTEL_EXPORTER_OTLP_PROTOCOL: \"http/json\",\n        ...base,\n        OTEL_RESOURCE_ATTRIBUTES: \"service.name=opencode\",\n      };\n    default:\n      return base;\n  }\n}\n","/**\n * Emit codex turn input/output (recovered from the rollout transcript) as OTLP\n * spans on codex's own per-turn trace_ids, so they join the native token-spans\n * and the trace summary's computed input/output populate with no receiver\n * change. See codex-rollout.ts for why the transcript is the only content\n * source codex offers.\n */\nimport { createHash } from \"node:crypto\";\nimport { readFile, readdir, stat } from \"node:fs/promises\";\nimport { homedir } from \"node:os\";\nimport { join } from \"node:path\";\nimport { type CodexTurnIO, parseCodexRollout } from \"./codex-rollout\";\n\n/** Deterministic 16-hex span id derived from the turn's trace_id. */\nfunction ioSpanId(traceId: string): string {\n  return createHash(\"sha256\").update(`${traceId}:langwatch.io`).digest(\"hex\").slice(0, 16);\n}\n\nfunction attr(key: string, value: string) {\n  return { key, value: { stringValue: value } };\n}\n\ninterface OtlpExportRequest {\n  resourceSpans: unknown[];\n}\n\n/**\n * Build an OTLP/JSON ExportTraceServiceRequest with one span per turn. Each\n * span rides codex's real trace_id and carries `langwatch.input` /\n * `langwatch.output` (read directly by the trace-summary IO accumulation) plus\n * `langwatch.span.type=llm` so the drawer renders it as the model response.\n *\n * `langwatch.input` is the full request body as the LangWatch structured\n * `chat_messages` envelope (system prompt + accumulated conversation + tool\n * calls). The receiver's `parseJsonStringValues` step parses the JSON string\n * into the `{ type, value }` object, and the LangWatch extractor canonicalises\n * it to `gen_ai.input.messages` + `gen_ai.system_instructions`, so the drawer\n * renders the same full conversation a claude trace does.\n */\nexport function buildCodexIOExportRequest(\n  turns: CodexTurnIO[],\n  nowMs: number,\n): OtlpExportRequest {\n  const spans = turns.map((turn) => {\n    const startMs = turn.startedAtMs ?? nowMs;\n    const endMs = Math.max(startMs, nowMs);\n    const attributes = [\n      attr(\"langwatch.span.type\", \"llm\"),\n      attr(\n        \"langwatch.input\",\n        JSON.stringify({ type: \"chat_messages\", value: turn.inputMessages }),\n      ),\n      attr(\"langwatch.output\", turn.output),\n    ];\n    if (turn.model) {\n      attributes.push(attr(\"gen_ai.request.model\", turn.model));\n      attributes.push(attr(\"gen_ai.response.model\", turn.model));\n    }\n    return {\n      traceId: turn.traceId,\n      spanId: ioSpanId(turn.traceId),\n      name: \"codex.turn.response\",\n      kind: 1,\n      startTimeUnixNano: `${startMs}000000`,\n      endTimeUnixNano: `${endMs}000000`,\n      attributes,\n      status: {},\n    };\n  });\n\n  return {\n    resourceSpans: [\n      {\n        resource: { attributes: [attr(\"service.name\", \"codex\")] },\n        scopeSpans: [\n          {\n            // A langwatch.* scope (NOT codex_cli_rs) so the ingestion\n            // infra-span filter leaves these content spans alone.\n            scope: { name: \"langwatch.codex.rollout\" },\n            spans,\n          },\n        ],\n      },\n    ],\n  };\n}\n\n/**\n * Find rollout files codex wrote at or after `sinceMs`. Codex lays them out as\n * ~/.codex/sessions/YYYY/MM/DD/rollout-<ts>-<sessionid>.jsonl; we walk the\n * date subdirs and keep files whose mtime is within the session window.\n */\nexport async function findRecentRollouts(\n  sinceMs: number,\n  sessionsRoot = join(homedir(), \".codex\", \"sessions\"),\n): Promise<string[]> {\n  const out: string[] = [];\n  async function walk(dir: string, depth: number): Promise<void> {\n    let entries;\n    try {\n      entries = await readdir(dir, { withFileTypes: true });\n    } catch {\n      return;\n    }\n    for (const e of entries) {\n      const full = join(dir, e.name);\n      if (e.isDirectory()) {\n        // Year/month/day nesting is 3 deep; don't descend forever.\n        if (depth < 3) await walk(full, depth + 1);\n      } else if (\n        e.isFile() &&\n        e.name.startsWith(\"rollout-\") &&\n        e.name.endsWith(\".jsonl\")\n      ) {\n        try {\n          const s = await stat(full);\n          if (s.mtimeMs >= sinceMs) out.push(full);\n        } catch {\n          /* skip unreadable */\n        }\n      }\n    }\n  }\n  await walk(sessionsRoot, 0);\n  return out;\n}\n\n/** Read + parse every in-window rollout into one flat turn list. */\nasync function readRolloutTurns(\n  sinceMs: number,\n  sessionsRoot: string,\n): Promise<CodexTurnIO[]> {\n  const files = await findRecentRollouts(sinceMs, sessionsRoot);\n  const turns: CodexTurnIO[] = [];\n  for (const file of files) {\n    try {\n      turns.push(...parseCodexRollout(await readFile(file, \"utf8\")));\n    } catch {\n      /* skip unreadable rollout */\n    }\n  }\n  return turns;\n}\n\n/**\n * POST a batch of turns as OTLP IO spans. Capped at 5s so a slow or unreachable\n * endpoint can't wedge the user's shell; the caller swallows failures (content\n * recovery must never break a coding session).\n */\nasync function postCodexTurns(args: {\n  turns: CodexTurnIO[];\n  nowMs: number;\n  endpoint: string;\n  token: string;\n  fetchImpl?: typeof fetch;\n}): Promise<void> {\n  const { turns, nowMs, endpoint, token, fetchImpl } = args;\n  const body = buildCodexIOExportRequest(turns, nowMs);\n  const doFetch = fetchImpl ?? fetch;\n  const controller = new AbortController();\n  const timeout = setTimeout(() => controller.abort(), 5_000);\n  try {\n    await doFetch(endpoint, {\n      method: \"POST\",\n      headers: {\n        \"content-type\": \"application/json\",\n        authorization: `Bearer ${token}`,\n      },\n      body: JSON.stringify(body),\n      signal: controller.signal,\n    });\n  } finally {\n    clearTimeout(timeout);\n  }\n}\n\n/**\n * Recover codex turn I/O from rollouts written during this session and POST it\n * as OTLP spans. Best-effort and fully swallowed: a coding session must never\n * fail because the post-hoc content harvest hit a snag. Returns the number of\n * turns emitted (0 when nothing was found).\n */\nexport async function harvestAndEmitCodexIO(args: {\n  sinceMs: number;\n  nowMs: number;\n  endpoint: string;\n  token: string;\n  sessionsRoot?: string;\n  fetchImpl?: typeof fetch;\n}): Promise<number> {\n  const { sinceMs, nowMs, endpoint, token, sessionsRoot, fetchImpl } = args;\n  const turns = await readRolloutTurns(\n    sinceMs,\n    sessionsRoot ?? join(homedir(), \".codex\", \"sessions\"),\n  );\n  if (turns.length === 0) return 0;\n  await postCodexTurns({ turns, nowMs, endpoint, token, fetchImpl });\n  return turns.length;\n}\n\n/**\n * Streaming harvester: emits each turn the moment it completes instead of\n * dumping the whole session in one POST on exit. The wrapper polls `harvest()`\n * on an interval while codex runs (plus one final sweep on exit). The rollout\n * is append-only and `parseCodexRollout` only yields turns that have a reply,\n * so an in-flight turn simply isn't in the parse yet; we additionally dedup by\n * trace_id so a turn is POSTed exactly once across ticks. Re-emitting the same\n * turn would be idempotent server-side anyway (the span id is derived from the\n * trace_id), so a failed POST is safely retried on the next tick.\n */\nexport function createCodexIOStreamer(args: {\n  sinceMs: number;\n  endpoint: string;\n  token: string;\n  sessionsRoot?: string;\n  fetchImpl?: typeof fetch;\n}): { harvest: (nowMs: number) => Promise<number> } {\n  const root = args.sessionsRoot ?? join(homedir(), \".codex\", \"sessions\");\n  const emitted = new Set<string>();\n  return {\n    async harvest(nowMs: number): Promise<number> {\n      const turns = await readRolloutTurns(args.sinceMs, root);\n      const fresh = turns.filter((t) => t.traceId && !emitted.has(t.traceId));\n      if (fresh.length === 0) return 0;\n      await postCodexTurns({\n        turns: fresh,\n        nowMs,\n        endpoint: args.endpoint,\n        token: args.token,\n        fetchImpl: args.fetchImpl,\n      });\n      // Mark emitted only after a successful POST so a transient failure\n      // retries the same turns next tick (dedup keeps the retry idempotent).\n      for (const t of fresh) emitted.add(t.traceId);\n      return fresh.length;\n    },\n  };\n}\n","/**\n * Codex rollout transcript -> per-turn chat-message request body + reply.\n *\n * Codex's native OTLP spans (scope `codex_cli_rs`) carry tokens, model, and\n * timing but never the prompt, the system instructions, the tool calls, or the\n * assistant reply. Codex DOES persist the whole conversation to disk as a JSONL\n * \"rollout\" at `~/.codex/sessions/YYYY/MM/DD/rollout-<ts>-<sessionid>.jsonl`,\n * and crucially each turn's `task_started` event records the exact OTLP\n * `trace_id` codex used for that turn's spans. That lets the wrapper recover the\n * FULL request body codex sent to the model AFTER the session and emit it on\n * codex's own trace_id, so it joins the token-spans on the same trace with no\n * receiver-side join.\n *\n * The rollout is the running conversation state (the OpenAI Responses API\n * `input` array), append-only. We replay it into an accumulating chat history\n * and, at each turn boundary, snapshot that history as the turn's `input` (the\n * request actually sent to the model: system prompt + every prior message + the\n * current user prompt + any mid-turn tool calls/results) with the turn's final\n * assistant answer as `output`. This mirrors how the claude log-to-span fold\n * turns a `/v1/messages` body into `gen_ai.input.messages`, so a codex trace\n * renders the same full conversation a claude trace does.\n *\n * Rollout line shapes this parser relies on (codex 0.137):\n * - `{\"type\":\"session_meta\",\"payload\":{\"base_instructions\":\"...\",\"cwd\":\"...\"}}`\n * - `{\"type\":\"turn_context\",\"payload\":{\"model\":\"gpt-5.5\"}}`\n * - `{\"type\":\"event_msg\",\"payload\":{\"type\":\"task_started\",\"turn_id\":\"...\",\"trace_id\":\"<hex32>\"}}`\n * - `{\"type\":\"response_item\",\"payload\":{\"type\":\"message\",\"role\":\"developer|user|assistant\",\"content\":[{\"type\":\"input_text|output_text\",\"text\":\"...\"}]}}`\n * - `{\"type\":\"response_item\",\"payload\":{\"type\":\"function_call\",\"name\":\"exec_command\",\"arguments\":\"{...}\",\"call_id\":\"...\"}}`\n * - `{\"type\":\"response_item\",\"payload\":{\"type\":\"function_call_output\",\"call_id\":\"...\",\"output\":\"...\"}}`\n * - `{\"type\":\"event_msg\",\"payload\":{\"type\":\"agent_message\",\"message\":\"...\",\"phase\":\"final_answer\"}}`\n */\n\n/** Per-message content cap so a single huge tool output can't dominate the span. */\nconst MAX_CONTENT_CHARS = 30_000;\n/** Whole-input cap (well under the 256KB ingestion attribute ceiling). */\nconst MAX_INPUT_CHARS = 120_000;\n/** Final-answer cap. */\nconst MAX_OUTPUT_CHARS = 30_000;\n\n/**\n * A LangWatch chat message. Roles map to the canonical chat roles\n * (`system|user|assistant|tool`); codex's `developer` role is folded into\n * `system`. Shapes a subset of the platform `chatMessageSchema` so the\n * receiver's LangWatch extractor canonicalises it to `gen_ai.input.messages`.\n */\nexport interface CodexChatMessage {\n  role: \"system\" | \"user\" | \"assistant\" | \"tool\";\n  content?: string;\n  tool_calls?: {\n    id: string;\n    type: \"function\";\n    function: { name: string; arguments: string };\n  }[];\n  tool_call_id?: string;\n}\n\nexport interface CodexTurnIO {\n  /** Hex OTLP trace_id codex used for this turn's spans (the join key). */\n  traceId: string;\n  turnId: string | null;\n  model: string | null;\n  /**\n   * The full request body as sent to the model for this turn: the system\n   * prompt, every prior message, the current user prompt, and any mid-turn\n   * tool calls/results — everything except the turn's final assistant answer.\n   */\n  inputMessages: CodexChatMessage[];\n  /** The assistant's final reply for the turn (plain text). */\n  output: string;\n  /** Turn start in unix ms, for a sane span start time (best-effort). */\n  startedAtMs: number | null;\n}\n\nfunction truncate(text: string, max: number): string {\n  return text.length > max ? `${text.slice(0, max)}…[truncated]` : text;\n}\n\nfunction textFromContent(content: unknown): string {\n  if (!Array.isArray(content)) return \"\";\n  const parts: string[] = [];\n  for (const part of content) {\n    if (part && typeof part === \"object\") {\n      const t = (part as { text?: unknown }).text;\n      const ot = (part as { output_text?: unknown }).output_text;\n      if (typeof t === \"string\") parts.push(t);\n      else if (typeof ot === \"string\") parts.push(ot);\n    }\n  }\n  return parts.join(\"\").trim();\n}\n\nfunction outputToText(output: unknown): string {\n  if (typeof output === \"string\") return output;\n  if (output && typeof output === \"object\") {\n    // codex wraps exec output as { output: \"...\", metadata: {...} } sometimes\n    const inner = (output as { output?: unknown }).output;\n    if (typeof inner === \"string\") return inner;\n    try {\n      return JSON.stringify(output);\n    } catch {\n      return \"\";\n    }\n  }\n  if (typeof output === \"number\" || typeof output === \"boolean\") {\n    return String(output);\n  }\n  return \"\";\n}\n\n/**\n * Bound the serialized input: cap each message's content, then drop the oldest\n * NON-system messages until the whole array is under the total cap. System\n * messages (the prompt the user actually asked to see) are always preserved.\n */\nfunction capInputMessages(messages: CodexChatMessage[]): CodexChatMessage[] {\n  const capped = messages.map((m) =>\n    typeof m.content === \"string\" && m.content.length > MAX_CONTENT_CHARS\n      ? { ...m, content: truncate(m.content, MAX_CONTENT_CHARS) }\n      : m,\n  );\n  const serializedLength = () => JSON.stringify(capped).length;\n  let i = 0;\n  while (serializedLength() > MAX_INPUT_CHARS && i < capped.length) {\n    if (capped[i]?.role === \"system\") {\n      i++;\n      continue;\n    }\n    capped.splice(i, 1);\n  }\n  return capped;\n}\n\n/** One parsed rollout JSONL line: a tagged envelope with an opaque payload. */\ninterface RolloutLine {\n  type?: string;\n  payload?: Record<string, unknown>;\n}\n\n/** The tool call's explicit id (`call_id`, then `id`), or null if codex omitted both. */\nfunction explicitToolCallId(payload: Record<string, unknown>): string | null {\n  if (typeof payload.call_id === \"string\" && payload.call_id) {\n    return payload.call_id;\n  }\n  if (typeof payload.id === \"string\" && payload.id) return payload.id;\n  return null;\n}\n\n/**\n * Replays a codex rollout's events into a running chat history and snapshots one\n * {@link CodexTurnIO} per turn boundary. All the cross-event state (the running\n * history, the open turn, the held assistant text, the authoritative final\n * answer, the session model) lives here so {@link parseCodexRollout} stays a\n * thin parse-and-dispatch coordinator.\n */\nclass CodexTurnAccumulator {\n  /** Emitted turns, in rollout order. */\n  private readonly turns: CodexTurnIO[] = [];\n  /** Accumulating conversation across the whole rollout (claude-style). */\n  private readonly history: CodexChatMessage[] = [];\n  private sessionModel: string | null = null;\n  private cur: {\n    traceId: string;\n    turnId: string | null;\n    model: string | null;\n    startedAtMs: number | null;\n  } | null = null;\n  /** Latest assistant text not yet committed to history (the final-answer candidate). */\n  private pendingAssistant: string | null = null;\n  /** Authoritative final answer from the agent_message(final_answer) event. */\n  private agentFinal: string | null = null;\n  /**\n   * Synthetic ids minted for tool calls that arrived without a `call_id`, queued\n   * FIFO so the matching (also id-less) function_call_output pairs to the same id\n   * instead of drifting as the running history grows.\n   */\n  private readonly pendingToolCallIds: string[] = [];\n  private autoToolCallSeq = 0;\n\n  /** Route one parsed rollout line to the handler for its event type. */\n  handle(obj: RolloutLine): void {\n    const payload = obj.payload ?? {};\n    switch (obj.type) {\n      case \"session_meta\":\n        return this.onSessionMeta(payload);\n      case \"turn_context\":\n        return this.onTurnContext(payload);\n      case \"event_msg\":\n        return this.onEventMsg(payload);\n      case \"response_item\":\n        return this.onResponseItem(payload);\n    }\n  }\n\n  /** Close the trailing open turn and return every emitted turn. */\n  finish(): CodexTurnIO[] {\n    this.closeTurn();\n    return this.turns;\n  }\n\n  private onSessionMeta(payload: Record<string, unknown>): void {\n    const bi = payload.base_instructions;\n    if (typeof bi === \"string\" && bi.trim()) {\n      this.history.push({ role: \"system\", content: bi.trim() });\n    }\n  }\n\n  private onTurnContext(payload: Record<string, unknown>): void {\n    const m = payload.model;\n    if (typeof m === \"string\" && m) {\n      this.sessionModel = m;\n      if (this.cur) this.cur.model = m;\n    }\n  }\n\n  private onEventMsg(payload: Record<string, unknown>): void {\n    if (payload.type === \"task_started\") return this.onTaskStarted(payload);\n    if (payload.type === \"task_complete\") return this.closeTurn();\n    // Everything below belongs to the open turn; ignore it outside one.\n    if (!this.cur) return;\n    if (payload.type === \"agent_message\") this.onAgentMessage(payload);\n  }\n\n  private onTaskStarted(payload: Record<string, unknown>): void {\n    this.closeTurn();\n    const traceId =\n      typeof payload.trace_id === \"string\" ? payload.trace_id : null;\n    if (!traceId) return;\n    this.cur = {\n      traceId,\n      turnId: typeof payload.turn_id === \"string\" ? payload.turn_id : null,\n      model: this.sessionModel,\n      startedAtMs:\n        typeof payload.started_at === \"number\"\n          ? payload.started_at * 1000\n          : null,\n    };\n  }\n\n  private onAgentMessage(payload: Record<string, unknown>): void {\n    // The clean final answer rides the agent_message(final_answer) event; prefer\n    // it over the raw assistant response_item which can repeat tool scaffolding.\n    const msg = payload.message;\n    if (\n      typeof msg === \"string\" &&\n      msg.trim() &&\n      payload.phase === \"final_answer\"\n    ) {\n      this.agentFinal = msg.trim();\n    }\n  }\n\n  private onResponseItem(payload: Record<string, unknown>): void {\n    // response_items belong to the open turn; ignore them outside one.\n    if (!this.cur) return;\n    switch (payload.type) {\n      case \"message\":\n        return this.onMessage(payload);\n      case \"function_call\":\n        return this.onFunctionCall(payload);\n      case \"function_call_output\":\n        return this.onFunctionCallOutput(payload);\n    }\n  }\n\n  private onMessage(payload: Record<string, unknown>): void {\n    const role = payload.role;\n    const text = textFromContent(payload.content);\n    if (!text) return;\n    if (role === \"developer\") {\n      this.flushPendingAssistant();\n      this.history.push({ role: \"system\", content: text });\n    } else if (role === \"user\") {\n      this.flushPendingAssistant();\n      this.history.push({ role: \"user\", content: text });\n    } else if (role === \"assistant\") {\n      // Hold: this may be a mid-turn preamble (committed to history when the\n      // next item arrives) or the turn's final answer (consumed by closeTurn).\n      this.flushPendingAssistant();\n      this.pendingAssistant = text;\n    }\n  }\n\n  private onFunctionCall(payload: Record<string, unknown>): void {\n    this.flushPendingAssistant();\n    let callId = explicitToolCallId(payload);\n    if (!callId) {\n      // codex omitted the id: mint a stable one and queue it for the output.\n      callId = `call_auto_${this.autoToolCallSeq++}`;\n      this.pendingToolCallIds.push(callId);\n    }\n    const name = typeof payload.name === \"string\" ? payload.name : \"tool\";\n    const args =\n      typeof payload.arguments === \"string\"\n        ? payload.arguments\n        : payload.arguments != null\n          ? JSON.stringify(payload.arguments)\n          : \"\";\n    this.history.push({\n      role: \"assistant\",\n      tool_calls: [\n        {\n          id: callId,\n          type: \"function\",\n          function: { name, arguments: truncate(args, MAX_CONTENT_CHARS) },\n        },\n      ],\n    });\n  }\n\n  private onFunctionCallOutput(payload: Record<string, unknown>): void {\n    this.flushPendingAssistant();\n    // Reuse the id codex gave; else pair FIFO with the matching id-less call.\n    const callId =\n      explicitToolCallId(payload) ??\n      this.pendingToolCallIds.shift() ??\n      `call_auto_${this.autoToolCallSeq++}`;\n    this.history.push({\n      role: \"tool\",\n      tool_call_id: callId,\n      content: truncate(outputToText(payload.output), MAX_CONTENT_CHARS),\n    });\n  }\n\n  private flushPendingAssistant(): void {\n    if (this.pendingAssistant !== null) {\n      this.history.push({ role: \"assistant\", content: this.pendingAssistant });\n      this.pendingAssistant = null;\n    }\n  }\n\n  private closeTurn(): void {\n    if (this.cur) {\n      const finalAnswer = this.agentFinal ?? this.pendingAssistant;\n      if (finalAnswer?.trim()) {\n        this.turns.push({\n          traceId: this.cur.traceId,\n          turnId: this.cur.turnId,\n          model: this.cur.model ?? this.sessionModel,\n          inputMessages: capInputMessages([...this.history]),\n          output: truncate(finalAnswer.trim(), MAX_OUTPUT_CHARS),\n          startedAtMs: this.cur.startedAtMs,\n        });\n        this.history.push({ role: \"assistant\", content: finalAnswer.trim() });\n      }\n    }\n    // Synthetic fallback ids only pair a call with its output *within* a turn.\n    // A call left unmatched at the boundary (output never arrived) must not\n    // leak its queued id into the next turn, or that turn's first id-less\n    // output would pair to the wrong call. `autoToolCallSeq` stays monotonic\n    // so the ids themselves remain unique across the session.\n    this.pendingToolCallIds.length = 0;\n    this.cur = null;\n    this.pendingAssistant = null;\n    this.agentFinal = null;\n  }\n}\n\n/**\n * Parse a codex rollout JSONL into one chat-message request/reply record per\n * turn. Turns with no assistant reply are dropped (an empty span helps no one).\n */\nexport function parseCodexRollout(content: string): CodexTurnIO[] {\n  const acc = new CodexTurnAccumulator();\n  for (const line of content.split(\"\\n\")) {\n    const trimmed = line.trim();\n    if (!trimmed) continue;\n    let obj: RolloutLine;\n    try {\n      obj = JSON.parse(trimmed) as RolloutLine;\n    } catch {\n      continue;\n    }\n    acc.handle(obj);\n  }\n  return acc.finish();\n}\n","/**\n * Runtime path-selection UX for the `langwatch <tool>` wrapper.\n *\n * Before env injection + spawn, the wrapper has to decide which routing\n * shape to apply for this run:\n *\n *   - Path A \"gateway\"   - LLM calls route through the LangWatch gateway\n *                          via the user's personal virtual key. LLM usage\n *                          is billed to the gateway.\n *   - Path B \"ingestion\" - the tool calls its own provider with the\n *                          user's own plan/auth; only OTLP telemetry is\n *                          sent to LangWatch via the personal ingest key.\n *\n * Historically the wrapper silently picked the gateway whenever a VK was\n * present and never asked, even when the org policy allowed BOTH paths.\n * This module fixes that: when both paths are allowed, on a TTY, with no\n * remembered answer, it shows an interactive select and remembers the\n * choice in cfg.tool_mode[tool] (the existing per-tool routing field, so\n * the rest of the wrapper reads it the same way it always has).\n *\n * Precedence (highest first):\n *   1. explicit override - `--tool-mode=gateway|otlp` flag, then\n *      `LANGWATCH_TOOL_MODE=gateway|otlp` env. Never prompts, never persists.\n *   2. remembered answer - cfg.tool_mode[tool] pinned to gateway/ingestion.\n *   3. exactly one allowed path (policy gate) - used silently.\n *   4. both allowed + TTY + not forced-auto-login - PROMPT, persist the\n *      answer, print a one-line tip.\n *   5. both allowed + non-TTY / CI / LANGWATCH_AUTO_LOGIN - default gateway,\n *      no prompt, no persist.\n *\n * The `--tool-mode` flag is a WRAPPER flag: it is stripped from the args\n * before they are forwarded to the real tool. Every other arg is\n * forwarded verbatim and in order.\n */\n\nimport prompts from \"prompts\";\n\nimport { lwTag } from \"./brand\";\nimport type { GovernanceConfig } from \"./config\";\nimport { saveConfig } from \"./config\";\nimport type { WrapperMode } from \"./wrapper-mode\";\nimport {\n  resolvePlatformToolPolicy,\n  type PlatformToolPolicyMap,\n} from \"./platform-tool-policy\";\n\n/** Wrapper-only flag name. */\nconst TOOL_MODE_FLAG = \"--tool-mode\";\n\n/**\n * Map a user-facing path token (`gateway` / `otlp`) to the internal\n * WrapperMode vocabulary (`gateway` / `ingestion`). Returns null for an\n * unrecognized token so the caller can ignore a typo rather than crash.\n */\nfunction tokenToMode(token: string | undefined): WrapperMode | null {\n  const t = (token ?? \"\").trim().toLowerCase();\n  if (t === \"gateway\" || t === \"vk\") return \"gateway\";\n  if (t === \"otlp\" || t === \"ingestion\" || t === \"direct\") return \"ingestion\";\n  return null;\n}\n\nexport interface ParsedToolMode {\n  /** Args with every `--tool-mode` form removed, order otherwise preserved. */\n  args: string[];\n  /** The override mode if `--tool-mode` (or LANGWATCH_TOOL_MODE env) set one. */\n  override?: WrapperMode;\n}\n\n/**\n * Strip the wrapper-only `--tool-mode` flag from the forwarded args and\n * resolve any explicit override. Supports both `--tool-mode=gateway` and\n * the space-separated `--tool-mode gateway` form. Falls back to the\n * `LANGWATCH_TOOL_MODE` env var when the flag is absent (the flag wins).\n *\n * CRITICAL: only `--tool-mode` is consumed. Every other arg (including\n * flags like `--dangerously-skip-permissions` and quoted positional\n * values) is forwarded untouched and in order.\n */\nexport function parseToolModeFlag(\n  args: string[],\n  env: NodeJS.ProcessEnv = process.env,\n): ParsedToolMode {\n  const out: string[] = [];\n  let flagOverride: WrapperMode | undefined;\n  for (let i = 0; i < args.length; i++) {\n    const arg = args[i]!;\n    if (arg === TOOL_MODE_FLAG) {\n      // Space-separated form: consume the next token as the value.\n      const value = args[i + 1];\n      const mode = tokenToMode(value);\n      if (mode) flagOverride = mode;\n      // Skip the value token too (whether or not it parsed) so a bare\n      // `--tool-mode gateway` never leaks `gateway` to the child as a\n      // stray positional.\n      if (value !== undefined) i++;\n      continue;\n    }\n    if (arg.startsWith(`${TOOL_MODE_FLAG}=`)) {\n      const value = arg.slice(TOOL_MODE_FLAG.length + 1);\n      const mode = tokenToMode(value);\n      if (mode) flagOverride = mode;\n      continue;\n    }\n    out.push(arg);\n  }\n\n  const override = flagOverride ?? tokenToMode(env.LANGWATCH_TOOL_MODE) ?? undefined;\n  return { args: out, override };\n}\n\n/**\n * Whether an explicit forced-auto-login signal is set. The path prompt\n * is skipped in that case (CI / agent contexts that opted into the\n * non-interactive device flow shouldn't get stuck on an extra select).\n * Mirrors the LANGWATCH_AUTO_LOGIN handling in the wrapper's login gate.\n */\nfunction isForcedAutoLogin(env: NodeJS.ProcessEnv): boolean {\n  const flag = env.LANGWATCH_AUTO_LOGIN;\n  return flag === \"1\" || flag === \"true\";\n}\n\nexport interface ResolveWrapperPathOptions {\n  cfg: GovernanceConfig;\n  tool: string;\n  /** Args already passed through `parseToolModeFlag` (flag stripped). */\n  args: string[];\n  /** Explicit override from `parseToolModeFlag`, if any. */\n  override?: WrapperMode;\n  /** TTY detection seam for tests. Defaults to stdin AND stdout being a TTY. */\n  isTTY?: boolean;\n  /** Prompt seam for tests. Defaults to the real `prompts` select. */\n  promptImpl?: typeof prompts;\n  /** Persist seam for tests. Defaults to the real saveConfig. */\n  saveImpl?: typeof saveConfig;\n  /** Output seam for tests. Defaults to process.stderr.write. */\n  writeImpl?: (s: string) => void;\n  env?: NodeJS.ProcessEnv;\n  /**\n   * Re-fetch the org's per-tool path policy at run time. Invoked only when\n   * the decision rides on policy (no override, no remembered answer), so a\n   * path the admin disabled AFTER login is honored without a re-login. Returns\n   * null (or throws) when offline; the resolver then keeps the cached map.\n   */\n  refreshPolicies?: (\n    cfg: GovernanceConfig,\n  ) => Promise<PlatformToolPolicyMap | null>;\n}\n\nexport interface ResolveWrapperPathResult {\n  /**\n   * The mode to force into resolveWrapperMode. Always concrete so the\n   * wrapper never falls back to the silent VK-present-implies-gateway\n   * default. resolveWrapperMode still applies the policy gates on top\n   * (downgrade / throw) so a forced mode the admin disabled is handled.\n   */\n  mode: WrapperMode;\n  /** True when this run made a fresh interactive choice (and persisted it). */\n  prompted: boolean;\n}\n\n/**\n * Human-readable copy for the interactive select. Kept as a constant so\n * tests can assert it and the wording stays in one place.\n */\nexport function pathChoiceMessage(tool: string): string {\n  return `How should \\`langwatch ${tool}\\` run?`;\n}\n\nexport function gatewayChoiceTitle(): string {\n  return \"Gateway (virtual key) - route LLM calls through LangWatch (usage billed per token)\";\n}\n\nexport function otlpChoiceTitle(tool: string): string {\n  return `Direct OTLP - use your own ${tool} plan, send only telemetry to LangWatch`;\n}\n\n/**\n * Resolve the path for this `langwatch <tool>` run. Prompts (and\n * persists) only when both paths are allowed, on a TTY, with no\n * remembered answer and no forced-auto-login. See the module header for\n * the full precedence.\n */\nexport async function resolveWrapperPath(\n  opts: ResolveWrapperPathOptions,\n): Promise<ResolveWrapperPathResult> {\n  const {\n    cfg,\n    tool,\n    override,\n    promptImpl = prompts,\n    saveImpl = saveConfig,\n    writeImpl = (s: string) => void process.stderr.write(s),\n    env = process.env,\n  } = opts;\n  const isTTY =\n    opts.isTTY ?? (Boolean(process.stdin.isTTY) && Boolean(process.stdout.isTTY));\n\n  // 1. Explicit override (flag or env) wins outright - no prompt, no persist.\n  if (override) {\n    return { mode: override, prompted: false };\n  }\n\n  // 2. Remembered answer pinned in cfg.tool_mode[tool].\n  const pinned = cfg.tool_mode?.[tool];\n  if (pinned === \"gateway\" || pinned === \"ingestion\") {\n    return { mode: pinned, prompted: false };\n  }\n\n  // 3. No override and no remembered answer: the decision rides on the org\n  // policy, which the admin may have flipped since login. Refresh it from the\n  // server (best-effort) so a freshly-disabled path is honored at run time,\n  // then re-cache it. A saved tool_mode short-circuits above, so this costs a\n  // request only on the runs before the user pins a path.\n  if (opts.refreshPolicies) {\n    try {\n      const fresh = await opts.refreshPolicies(cfg);\n      if (fresh) {\n        cfg.tool_policies = fresh;\n        try {\n          saveImpl({ ...cfg, tool_policies: fresh });\n        } catch {\n          // best-effort re-cache; a write failure must not block the run.\n        }\n      }\n    } catch {\n      // offline / server error: fall back to the cached policy map.\n    }\n  }\n\n  // Resolve which paths the org policy permits for this tool.\n  const policy = resolvePlatformToolPolicy(tool, cfg.tool_policies);\n  const allowGateway = policy.allowVk;\n  const allowOtlp = policy.allowOtelDirect;\n\n  // Exactly one allowed path is used silently. resolveWrapperMode also\n  // enforces this (downgrade / throw), but resolving it here keeps the\n  // prompt logic honest: we only ever prompt for a real either-or.\n  if (allowGateway && !allowOtlp) {\n    return { mode: \"gateway\", prompted: false };\n  }\n  if (!allowGateway && allowOtlp) {\n    return { mode: \"ingestion\", prompted: false };\n  }\n  if (!allowGateway && !allowOtlp) {\n    // Both disabled - let resolveWrapperMode surface the canonical\n    // tool-disabled error. Pick gateway here only to hand it a concrete\n    // value; the gate throws before it matters.\n    return { mode: \"gateway\", prompted: false };\n  }\n\n  // 4 / 5. Both paths allowed.\n  const canPrompt = isTTY && !isForcedAutoLogin(env);\n  if (!canPrompt) {\n    // Non-TTY / CI / forced-auto-login - default to the gateway, no prompt.\n    return { mode: \"gateway\", prompted: false };\n  }\n\n  const res = await promptImpl({\n    type: \"select\",\n    name: \"path\",\n    message: pathChoiceMessage(tool),\n    choices: [\n      {\n        title: gatewayChoiceTitle(),\n        value: \"gateway\",\n      },\n      {\n        title: otlpChoiceTitle(tool),\n        value: \"ingestion\",\n      },\n    ],\n    initial: 0,\n  });\n\n  const chosen = tokenToMode(res?.path as string | undefined);\n  if (!chosen) {\n    // User aborted the prompt (Ctrl-C / empty). Default to the gateway\n    // for this run without persisting, so the next run asks again.\n    return { mode: \"gateway\", prompted: false };\n  }\n\n  // Remember the choice so subsequent runs don't prompt.\n  const next: GovernanceConfig = {\n    ...cfg,\n    tool_mode: { ...(cfg.tool_mode ?? {}), [tool]: chosen },\n  };\n  try {\n    saveImpl(next);\n    // Mutate the in-memory cfg too so the rest of this run sees the pin.\n    cfg.tool_mode = next.tool_mode;\n  } catch {\n    // Best-effort persist - a write failure shouldn't block the run.\n  }\n\n  const label = chosen === \"gateway\" ? \"gateway\" : \"otlp\";\n  writeImpl(\n    `${lwTag()} saved. \\`${tool}\\` will use the ${label} path. ` +\n      `Override with --tool-mode=${chosen === \"gateway\" ? \"otlp\" : \"gateway\"}, ` +\n      `or edit ~/.langwatch/config.json (tool_mode.${tool}).\\n`,\n  );\n\n  return { mode: chosen, prompted: true };\n}\n"],"mappings":"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","names":["chalk","chalk","fs","os","path","path","os","fs","fs","os","path","stripJsoncComments","homedir","join","join","homedir","e","join","homedir","_a"]}