{"version":3,"sources":["../src/cli/utils/governance/login-flow.ts","../src/cli/utils/governance/login-ceremony.ts"],"sourcesContent":["/**\n * Shared device-code login implementations. Two entry points:\n *\n *   1. `runUnifiedLoginFlow({ kind })` — the canonical flow used by\n *      `langwatch login` (interactive routes here for both modes). The\n *      same browser-approval ceremony works for either credential type;\n *      only the persist target differs:\n *        kind: 'device_session' → ~/.langwatch/config.json\n *        kind: 'project_api_key' → $CWD/.env (LANGWATCH_API_KEY)\n *      No copy-paste of the credential ever — the server ships it\n *      back to the CLI over the same RFC 8628 poll endpoint.\n *\n *   2. `runDeviceFlowLogin(...)` — back-compat wrapper that calls\n *      `runUnifiedLoginFlow({ kind: 'device_session' })`. Preserved so\n *      `commands/login.ts --device` and `utils/governance/wrapper.ts`\n *      auto-login keep working without churn.\n *\n * Spec: specs/ai-governance/cli-onboarding/login-unified.feature\n */\n\nimport * as fs from \"node:fs\";\nimport * as path from \"node:path\";\nimport chalk from \"chalk\";\nimport ora from \"ora\";\nimport {\n  startDeviceCode,\n  pollUntilDone,\n  DeviceFlowError,\n  type CredentialType,\n  type ExchangeApiKeyResult,\n  type ExchangeDeviceSessionResult,\n} from \"./device-flow\";\nimport { loadConfig, saveConfig, type GovernanceConfig } from \"./config\";\nimport { formatLoginCeremony } from \"./login-ceremony\";\nimport {\n  extractLookupIdFromToken,\n  getCliBootstrap,\n  listIngestionKeys,\n  type CliBootstrapResponse,\n} from \"./cli-api\";\n\nexport interface RunUnifiedLoginOptions {\n  /** Credential type to mint. Defaults to 'device_session' for back-compat. */\n  kind?: CredentialType;\n  /** Optional browser override (LANGWATCH_BROWSER also honoured). */\n  browser?: string;\n  /** Pre-loaded config to mutate; defaults to `loadConfig()`. */\n  cfg?: GovernanceConfig;\n}\n\nexport type RunDeviceFlowLoginOptions = Omit<RunUnifiedLoginOptions, \"kind\">;\n\n/**\n * Run the canonical device-code login flow end-to-end. Selects what to\n * mint via `kind` (defaults to device_session); the same browser\n * approval ceremony covers both modes. On success, persists to the\n * right store + returns the latest GovernanceConfig.\n */\nexport async function runUnifiedLoginFlow(\n  opts: RunUnifiedLoginOptions = {},\n): Promise<GovernanceConfig> {\n  const kind: CredentialType = opts.kind ?? \"device_session\";\n  const cfg = opts.cfg ?? loadConfig();\n  const baseUrl = cfg.control_plane_url;\n\n  console.log(chalk.blue(\"🔐 LangWatch login\"));\n  console.log(chalk.gray(`Control plane: ${baseUrl}`));\n  console.log(\n    chalk.gray(\n      kind === \"project_api_key\"\n        ? \"Mode: project SDK API key (will write .env)\"\n        : \"Mode: device session (will write ~/.langwatch/config.json)\",\n    ),\n  );\n\n  const dc = await startDeviceCode({ baseUrl }, { credentialType: kind });\n  const verifyURL =\n    dc.verification_uri_complete ??\n    `${dc.verification_uri.replace(/\\/+$/, \"\")}?user_code=${encodeURIComponent(dc.user_code)}`;\n\n  console.log();\n  console.log(chalk.cyan(`Opening: ${verifyURL}`));\n  console.log(\n    chalk.gray(\n      `If your browser doesn't open, paste the URL above and enter code: ${chalk.bold(dc.user_code)}`,\n    ),\n  );\n  console.log();\n\n  await openInBrowser(verifyURL, opts.browser);\n\n  // discardStdin:false is load-bearing. ora's default (true) flips stdin to\n  // raw mode while the spinner runs, so Ctrl+C arrives as a raw 0x03 byte that\n  // ora swallows instead of a SIGINT — the wait becomes unkillable. Keeping\n  // stdin cooked lets the terminal deliver SIGINT; the handler stops the\n  // spinner and exits cleanly so the user can always abort the login wait.\n  const spinner = ora({\n    text: \"Waiting for you to approve in the browser\",\n    discardStdin: false,\n  }).start();\n  const onSigint = () => {\n    spinner.stop();\n    console.log(chalk.gray(\"\\nLogin cancelled.\"));\n    process.exit(130);\n  };\n  process.once(\"SIGINT\", onSigint);\n  try {\n    const result = await pollUntilDone({ baseUrl }, dc);\n    if (result.kind === \"device_session\") {\n      spinner.succeed(`Logged in as ${result.user.email}`);\n      persistDeviceSession(cfg, result);\n      saveConfig(cfg);\n\n      const bootstrap = await fetchBootstrapSafely(cfg);\n\n      // Pick up the server's authoritative gateway URL. Without this,\n      // self-hosted CLI users would see the SaaS default\n      // (https://gateway.langwatch.ai) on whoami / login output even\n      // though the actual gateway is on localhost:5563. The server's\n      // `gatewayUrl` reflects `LW_GATEWAY_BASE_URL` or the IS_SAAS-\n      // aware fallback. Backwards-compatible: older servers (without\n      // this field) leave the local default in place.\n      if (bootstrap?.gatewayUrl) {\n        cfg.gateway_url = bootstrap.gatewayUrl;\n        saveConfig(cfg);\n      }\n\n      // Cache the org's per-tool path policy so the `langwatch <tool>`\n      // wrapper gates path selection on the admin's choices offline.\n      // Older servers omit the field; the wrapper then falls back to\n      // the hardcoded defaults.\n      if (bootstrap?.toolPolicies) {\n        cfg.tool_policies = bootstrap.toolPolicies;\n        saveConfig(cfg);\n      }\n\n      // Reconcile cached ingestion keys (#4755): after a fresh login, drop\n      // any locally cached entries whose token was revoked on the platform.\n      // Errors are swallowed — a login must never fail on reconcile; the\n      // worst outcome is a stale cache entry that the per-invocation wrapper\n      // check will catch anyway.\n      if (cfg.default_personal_ingest_keys && Object.keys(cfg.default_personal_ingest_keys).length > 0) {\n        try {\n          const liveKeys = await listIngestionKeys(cfg);\n          const liveSet = new Set(liveKeys.map((k) => `${k.sourceType}:${k.lookupId}`));\n          const reconciled: GovernanceConfig[\"default_personal_ingest_keys\"] = {};\n          let changed = false;\n          for (const [sourceType, entry] of Object.entries(cfg.default_personal_ingest_keys)) {\n            const lookupId = extractLookupIdFromToken(entry.secret ?? \"\");\n            if (lookupId && liveSet.has(`${sourceType}:${lookupId}`)) {\n              reconciled[sourceType] = entry;\n            } else {\n              // Entry is stale (revoked or lookupId missing) — omit from reconciled\n              changed = true;\n            }\n          }\n          if (changed) {\n            cfg.default_personal_ingest_keys = reconciled;\n            saveConfig(cfg);\n          }\n        } catch {\n          // Network error / older server: keep existing cache untouched\n        }\n      }\n\n      console.log();\n      const ceremonyLines = formatLoginCeremony({\n        email: cfg.user?.email ?? result.user.email,\n        organizationName: cfg.organization?.name,\n        tools: bootstrap?.tools,\n        providers: bootstrap?.providers,\n        budget:\n          bootstrap?.budget?.monthlyLimitUsd != null\n            ? {\n                period: bootstrap.budget.period,\n                limitUsd: bootstrap.budget.monthlyLimitUsd,\n                usedUsd: bootstrap.budget.monthlyUsedUsd,\n              }\n            : undefined,\n      });\n      for (const line of ceremonyLines) {\n        console.log(line);\n      }\n      console.log();\n      console.log(chalk.gray(`  Dashboard: ${cfg.control_plane_url}`));\n\n      return cfg;\n    }\n\n    // kind === 'api_key' — write to project-local .env (NO copy-paste)\n    spinner.succeed(\n      `API key generated for project ${chalk.bold(result.project.name)}`,\n    );\n    const envResult = writeApiKeyToEnv(result.api_key);\n    console.log();\n    console.log(chalk.green(\"✓ API key saved to .env\"));\n    if (envResult.created) {\n      console.log(chalk.gray(`  • Created .env file at ${envResult.path}`));\n    } else if (envResult.updated) {\n      console.log(chalk.gray(`  • Updated existing API key in ${envResult.path}`));\n    } else {\n      console.log(chalk.gray(`  • Added API key to ${envResult.path}`));\n    }\n    console.log();\n    console.log(\n      chalk.gray(\n        `  Project: ${result.project.name} (${result.project.slug})`,\n      ),\n    );\n    console.log(chalk.gray(`  Dashboard: ${cfg.control_plane_url}`));\n    return cfg;\n  } catch (err) {\n    spinner.fail();\n    if (err instanceof DeviceFlowError) {\n      switch (err.kind) {\n        case \"denied\":\n          throw new Error(\n            \"authorization denied — you can retry `langwatch login`\",\n          );\n        case \"expired\":\n          throw new Error(\n            \"authorization request expired — run `langwatch login` again\",\n          );\n        default:\n          throw err;\n      }\n    }\n    throw err;\n  } finally {\n    process.removeListener(\"SIGINT\", onSigint);\n  }\n}\n\n/**\n * Back-compat wrapper. New callers should use `runUnifiedLoginFlow`\n * directly with an explicit `kind`.\n */\nexport async function runDeviceFlowLogin(\n  opts: RunDeviceFlowLoginOptions = {},\n): Promise<GovernanceConfig> {\n  return runUnifiedLoginFlow({ ...opts, kind: \"device_session\" });\n}\n\nfunction persistDeviceSession(\n  cfg: GovernanceConfig,\n  result: ExchangeDeviceSessionResult,\n): void {\n  cfg.access_token = result.access_token;\n  cfg.refresh_token = result.refresh_token;\n  cfg.expires_at = Math.floor(Date.now() / 1000) + result.expires_in;\n  cfg.user = {\n    id: result.user.id,\n    email: result.user.email,\n    name: result.user.name,\n  };\n  cfg.organization = {\n    id: result.organization.id,\n    slug: result.organization.slug,\n    name: result.organization.name,\n  };\n  if (result.default_personal_vk) {\n    cfg.default_personal_vk = {\n      id: result.default_personal_vk.id,\n      secret: result.default_personal_vk.secret,\n      prefix: result.default_personal_vk.prefix,\n    };\n  }\n  if (result.endpoint) {\n    cfg.control_plane_url = result.endpoint.replace(/\\/+$/, \"\");\n  }\n}\n\ninterface EnvWriteResult {\n  created: boolean;\n  updated: boolean;\n  path: string;\n}\n\nfunction writeApiKeyToEnv(apiKey: string): EnvWriteResult {\n  const envPath = path.join(process.cwd(), \".env\");\n  if (!fs.existsSync(envPath)) {\n    fs.writeFileSync(envPath, `LANGWATCH_API_KEY=${apiKey}\\n`);\n    return { created: true, updated: false, path: envPath };\n  }\n  const content = fs.readFileSync(envPath, \"utf-8\");\n  const lines = content.split(\"\\n\");\n  let found = false;\n  const updatedLines = lines.map((line) => {\n    if (line.startsWith(\"LANGWATCH_API_KEY=\")) {\n      found = true;\n      return `LANGWATCH_API_KEY=${apiKey}`;\n    }\n    return line;\n  });\n  if (!found) {\n    if (content.endsWith(\"\\n\") || content === \"\") {\n      updatedLines.push(`LANGWATCH_API_KEY=${apiKey}`);\n    } else {\n      updatedLines.push(\"\", `LANGWATCH_API_KEY=${apiKey}`);\n    }\n  }\n  fs.writeFileSync(envPath, updatedLines.join(\"\\n\"));\n  return { created: false, updated: found, path: envPath };\n}\n\nasync function fetchBootstrapSafely(\n  cfg: GovernanceConfig,\n): Promise<CliBootstrapResponse | null> {\n  try {\n    return await getCliBootstrap(cfg);\n  } catch {\n    return null;\n  }\n}\n\nasync function openInBrowser(url: string, override?: string): Promise<void> {\n  const choice =\n    override ?? process.env.LANGWATCH_BROWSER ?? process.env.BROWSER ?? \"\";\n  if (choice === \"none\") return;\n  const open = (await import(\"open\")).default;\n  try {\n    if (!choice || choice === \"default\") {\n      await open(url);\n      return;\n    }\n    await open(url, { app: { name: choice } });\n  } catch {\n    // browser failure shouldn't break login — user can paste manually\n  }\n}\n\n// The post-login shell-rc persist offer was removed when `langwatch\n// login` became auth-only: the device session in config.json is\n// already authoritative, so login never edits the shell rc. The\n// persist offer now lives in the `langwatch <tool>` wrapper and fires\n// only in ingestion mode (maybeOfferIngestionShellRcPersist in\n// shell-rc.ts), framed as installing telemetry.\n\n// Type-only re-exports so callers can import the shapes from this\n// module without reaching into device-flow.ts.\nexport type { ExchangeApiKeyResult, ExchangeDeviceSessionResult };\n","/**\n * Render the \"You're in!\" ceremony emitted by `langwatch login` after a\n * successful device-flow exchange.\n *\n * Two clearly-separated lists, sourced from the org's AI Tools catalog:\n *\n *   ✓ Logged in as jane@acme.com @ Acme\n *\n *   Your AI tools (run any of these):\n *     $ langwatch claude   # Claude Code\n *     $ langwatch codex    # Codex\n *\n *   Model providers you can issue a virtual key for:\n *     • anthropic   Claude\n *     • openai      (not configured yet)\n *\n *   Monthly budget: $500   |   Used: $0.00\n *\n *   Or open the app in your browser:\n *     $ langwatch open\n *\n * The two sections answer two different questions: which coding assistants\n * can I run right now (`tools`), and which model providers can I mint my own\n * virtual key for (`providers`). They are NOT the same thing — conflating\n * them was the bug this rewrite fixes.\n *\n * Pure function: takes the data, returns an array of lines. Caller applies\n * any chalk colouring + writes to stdout. Lets unit tests assert on the\n * literal output without colour/escape noise.\n */\n\nexport interface LoginCeremonyTool {\n  /** CLI slug the wrapper runs (e.g. \"claude\", \"codex\"). */\n  slug: string;\n  /** Human-readable assistant name (e.g. \"Claude Code\"). */\n  displayName: string;\n}\n\nexport interface LoginCeremonyProvider {\n  /** Provider key (lowercase, e.g. \"anthropic\", \"openai\", \"gemini\"). */\n  name: string;\n  /** Optional human-readable provider label (e.g. \"Anthropic\"). */\n  displayName?: string;\n  /**\n   * Whether the org has a live credential for this provider. When false the\n   * ceremony annotates the row so the user knows the tile still needs setup\n   * before a minted key will work.\n   */\n  configured?: boolean;\n}\n\nexport interface LoginCeremonyBudget {\n  /** Period label (e.g. \"Monthly\"). Capitalised in output. */\n  period: string;\n  /** Spend ceiling in USD (rendered as `$N`). */\n  limitUsd: number;\n  /** Used so far in USD (rendered with two decimals). */\n  usedUsd: number;\n}\n\nexport interface LoginCeremonyInput {\n  email: string;\n  organizationName?: string;\n  /**\n   * Coding assistants the user can run via `langwatch <slug>`, sourced from\n   * the org's catalog. When empty / omitted the ceremony falls back to the\n   * built-in default wrappers so a fresh org still gets a next-step.\n   */\n  tools?: LoginCeremonyTool[];\n  /** Model providers the user can mint their own virtual key for. */\n  providers?: LoginCeremonyProvider[];\n  budget?: LoginCeremonyBudget;\n  /** Whether the `langwatch open` browser-launch command is available. */\n  openCommand?: boolean;\n}\n\n/** Fallback wrappers when the org has not published any coding-assistant tile. */\nconst DEFAULT_TOOLS: LoginCeremonyTool[] = [\n  { slug: \"claude\", displayName: \"Claude Code\" },\n  { slug: \"codex\", displayName: \"Codex\" },\n  { slug: \"cursor\", displayName: \"Cursor\" },\n];\n\nfunction padRight(s: string, width: number): string {\n  if (s.length >= width) return s;\n  return s + \" \".repeat(width - s.length);\n}\n\nfunction formatUsd(n: number): string {\n  // $500 (whole) → \"$500\"; $42.18 → \"$42.18\".\n  if (Number.isInteger(n)) return `$${n}`;\n  return `$${n.toFixed(2)}`;\n}\n\nfunction formatUsedUsd(n: number): string {\n  return `$${n.toFixed(2)}`;\n}\n\nexport function formatLoginCeremony(input: LoginCeremonyInput): string[] {\n  const lines: string[] = [];\n\n  const orgSuffix = input.organizationName ? ` @ ${input.organizationName}` : \"\";\n  lines.push(`✓ Logged in as ${input.email}${orgSuffix}`);\n\n  // AI tools (coding assistants). Fall back to the built-in wrappers when the\n  // org published none, so the user always gets a runnable next-step.\n  const tools =\n    input.tools && input.tools.length > 0 ? input.tools : DEFAULT_TOOLS;\n  lines.push(\"\");\n  lines.push(\"Your AI tools (run any of these):\");\n  const cmdWidth = Math.max(\n    ...tools.map((t) => `langwatch ${t.slug}`.length),\n  );\n  for (const tool of tools) {\n    const cmd = `langwatch ${tool.slug}`;\n    const labelSuffix = tool.displayName ? `  # ${tool.displayName}` : \"\";\n    lines.push(`  $ ${padRight(cmd, cmdWidth)}${labelSuffix}`);\n  }\n\n  // Model providers the user can mint a virtual key for — a different concept\n  // from the tools above. Only shown when the org published provider tiles.\n  if (input.providers && input.providers.length > 0) {\n    lines.push(\"\");\n    lines.push(\"Model providers you can issue a virtual key for:\");\n    const nameWidth = Math.max(...input.providers.map((p) => p.name.length));\n    for (const p of input.providers) {\n      const padded = padRight(p.name, nameWidth);\n      const annotations: string[] = [];\n      if (p.displayName && p.displayName !== p.name) {\n        annotations.push(p.displayName);\n      }\n      if (p.configured === false) annotations.push(\"(not configured yet)\");\n      const suffix = annotations.length > 0 ? `  ${annotations.join(\"  \")}` : \"\";\n      lines.push(`  • ${padded}${suffix}`);\n    }\n  }\n\n  if (input.budget) {\n    lines.push(\"\");\n    const period =\n      input.budget.period.charAt(0).toUpperCase() +\n      input.budget.period.slice(1).toLowerCase();\n    lines.push(\n      `${period} budget: ${formatUsd(input.budget.limitUsd)}   |   Used: ${formatUsedUsd(input.budget.usedUsd)}`,\n    );\n  }\n\n  if (input.openCommand !== false) {\n    lines.push(\"\");\n    lines.push(\"Or open the app in your browser:\");\n    lines.push(\"  $ langwatch open\");\n  }\n\n  return lines;\n}\n"],"mappings":"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","names":[]}