/**
 * olam auth — Manage the local auth container (the long-lived Linux container
 * that runs the same OAuth PKCE dance as the Cloudflare Worker and stores
 * Claude tokens in a named docker volume).
 *
 * Subcommands (local):
 *   olam auth up                  — start the auth container (idempotent)
 *   olam auth down                — stop the auth container
 *   olam auth status              — show container state + account summary
 *   olam auth login               — run PKCE login flow (one-time per host)
 *   olam auth logout              — remove an account from the container
 *   olam auth refresh             — force-refresh a token
 *
 * Subcommands (remote auth-worker — e4/e5/e6):
 *   olam auth login --remote <url>                   — print OAuth URL to open in browser (v1 dogfood)
 *   olam auth bind-service-token --remote <url> ...  — bind a CF service token to a user sub
 *   olam auth list --remote <url>                    — list accounts + service tokens on remote worker
 *   olam auth migrate-to-remote --url <url>          — guidance: re-OAuth each local account remotely
 *   olam auth rotate-service-token --url <url> ...   — revoke + re-bind a service token
 *   olam auth doctor --auth-worker <url>             — 4-probe health check against the auth-worker
 *
 * V1 dogfood note (e4/e5):
 *   CF Access cookie-bridging is the core UX constraint.  Full CLI-orchestrated
 *   browser flow (the CLI as its own OAuth client for CF Access) is complex and
 *   deferred to v2.  V1 uses a "print the URL; operator completes in browser;
 *   CLI re-checks via list --remote" model for login, and a "paste cookie from
 *   DevTools" model for service-token binding.
 */
import pc from 'picocolors';
import { AuthClient, AuthContainerController, runAuthPreflight, } from '@olam/core/src/auth/index.js';
import { printError, printHeader, printInfo, printSuccess, printWarning } from '../output.js';
import * as readline from 'node:readline/promises';
import { spawn } from 'node:child_process';
import { runAuthStatus } from './auth-status.js';
import { registerAuthUpgrade } from './auth-upgrade.js';
import { resolveTokenLabel, writeAnthropicBaseUrlFile } from '../lib/anthropic-base-url-file.js';
import { servicesUp, servicesDown, servicesStatus } from './services.js';
import { readConfig } from '../lib/config.js';
import { applyK8sAuthRefresh, resolveKubectlContext, } from '../lib/auth-refresh-kubernetes.js';
import { remoteOAuthStart, remoteListServiceTokens, remoteListAccounts, remoteBindServiceToken, remoteDeleteServiceToken, remoteIssueAnthropicToken, remoteListAnthropicTokens, remoteRevokeAnthropicToken, runDoctorChecks, } from '../lib/auth-remote.js';
import { resolveCfAccessServiceToken } from '../lib/cf-access-token.js';
import { renderAuthListJson } from './auth-list-json.js';
/**
 * Best-effort browser opener. Uses the host's native "open URL" command:
 * `open` on macOS, `xdg-open` on Linux, `start` on Windows. Silently
 * no-ops on failure — the URL is still printed for manual copy.
 */
function openBrowser(url) {
    const cmd = process.platform === 'darwin' ? 'open' :
        process.platform === 'win32' ? 'start' :
            'xdg-open';
    try {
        const child = spawn(cmd, [url], { detached: true, stdio: 'ignore' });
        child.unref();
    }
    catch {
        // Ignore — caller already printed the URL.
    }
}
async function promptLine(question) {
    const rl = readline.createInterface({ input: process.stdin, output: process.stdout });
    try {
        const answer = await rl.question(question);
        return answer.trim();
    }
    finally {
        rl.close();
    }
}
export function registerAuth(program) {
    const auth = program
        .command('auth')
        .description('Manage the local Claude auth container');
    auth
        .command('up')
        .description('[deprecated] Start the auth container — use `olam services up` instead')
        .action(async () => {
        printWarning('`olam auth up` is deprecated. Use `olam services up` instead.');
        const result = await servicesUp();
        if (result.exitCode !== 0)
            process.exitCode = result.exitCode;
    });
    auth
        .command('down')
        .description('[deprecated] Stop the auth container — use `olam services down` instead')
        .action(() => {
        printWarning('`olam auth down` is deprecated. Use `olam services down` instead.');
        const result = servicesDown();
        if (result.exitCode !== 0)
            process.exitCode = result.exitCode;
    });
    auth
        .command('status')
        .description('[deprecated] Show container state — use `olam services status` instead')
        .action(() => {
        printWarning('`olam auth status` is deprecated. Use `olam services status` instead.');
        servicesStatus();
    });
    auth
        .command('disable')
        .description('Take a credential out of rotation (manual cooldown)')
        .argument('<label>', 'Credential label or id')
        .action(async (label) => {
        const client = new AuthClient();
        try {
            await client.disableAccount(label);
            printSuccess(`Disabled: ${label}`);
        }
        catch (err) {
            printError(err instanceof Error ? err.message : 'failed to disable');
            process.exitCode = 1;
        }
    });
    auth
        .command('enable')
        .description('Re-enable a disabled credential')
        .argument('<label>', 'Credential label or id')
        .action(async (label) => {
        const client = new AuthClient();
        try {
            await client.enableAccount(label);
            printSuccess(`Enabled: ${label}`);
        }
        catch (err) {
            printError(err instanceof Error ? err.message : 'failed to enable');
            process.exitCode = 1;
        }
    });
    auth
        .command('remove')
        .description('Permanently remove a credential (purge tokens)')
        .argument('<label>', 'Credential label or id')
        .action(async (label) => {
        const client = new AuthClient();
        try {
            await client.deleteAccount(label);
            printSuccess(`Removed: ${label}`);
        }
        catch (err) {
            printError(err instanceof Error ? err.message : 'failed to remove');
            process.exitCode = 1;
        }
    });
    auth
        .command('login')
        .description('Run the OAuth PKCE flow to store a Claude account in the auth container, or print a remote OAuth URL (--remote)')
        .option('--label <label>', 'Account label (e.g. primary, burner-1). Defaults to "primary" for the first account, "burner-N" thereafter.')
        .option('--remote <url>', 'Auth-worker base URL. Prints the OAuth start URL for browser completion (v1 dogfood).')
        .option('--print-url', 'Print the OAuth URL without attempting to open a browser (implied by --remote).')
        .option('--service-token <client_id:secret>', 'Delegate to bind-service-token flow instead (use with --remote).')
        .action(async (opts) => {
        // ── Remote path (e4) ──────────────────────────────────────────────────
        if (opts.remote) {
            const baseUrl = opts.remote;
            if (opts.serviceToken) {
                // Delegate to bind-service-token flow
                const parts = opts.serviceToken.split(':');
                if (parts.length < 2) {
                    printError('--service-token must be in format <client_id>:<secret>');
                    process.exitCode = 1;
                    return;
                }
                const [clientId] = parts;
                const label = opts.label ?? clientId ?? 'service-token';
                printHeader('Auth worker — bind service token');
                console.log(`\n  ${pc.bold('Step 1:')} Open ${pc.cyan(baseUrl + '/v1/oauth/start')} in a browser.`);
                console.log(`          Complete CF Access SSO. You may see a JSON response or "no credentials" — that is normal.`);
                const rawCookie = await promptLine(`\n  ${pc.dim('Paste CF_Authorization cookie value (from DevTools > Application > Cookies):')} `);
                if (!rawCookie) {
                    printError('No cookie provided. Aborting.');
                    process.exitCode = 1;
                    return;
                }
                const clientIdStr = clientId ?? '';
                try {
                    await remoteBindServiceToken({ baseUrl, cfAuthCookie: rawCookie }, { client_id: clientIdStr, label });
                    printSuccess(`Service token bound: ${clientIdStr} (label=${label})`);
                    console.log(`\n${pc.dim('Set ANTHROPIC_BASE' + '_URL=' + baseUrl + '/v1/proxy in your shell to route Claude API calls through this worker.')}`);
                }
                catch (err) {
                    printError(err instanceof Error ? err.message : 'bind failed');
                    process.exitCode = 1;
                }
                return;
            }
            // Default: print (and optionally open) the OAuth start URL.
            // V1 dogfood: browser completes the full flow (CF Access SSO → Anthropic
            // OAuth → worker callback → token stored). CLI re-checks via `list --remote`.
            // Full CLI-orchestrated cookie-bridging is deferred to v2.
            let startUrl;
            try {
                const r = await remoteOAuthStart({ baseUrl });
                startUrl = r.authorize_url;
            }
            catch {
                // Fallback if /v1/oauth/start isn't reachable (CF Access gate, etc.)
                startUrl = `${baseUrl.replace(/\/+$/, '')}/v1/oauth/start`;
            }
            printHeader('Auth worker — OAuth login (v1 dogfood)');
            console.log(`\n  ${pc.bold('1.')} Open this URL in your browser to authenticate via CF Access + Anthropic OAuth:`);
            console.log(`\n     ${pc.cyan(startUrl)}\n`);
            console.log(`  ${pc.bold('2.')} Complete the CF Access SSO and Anthropic OAuth consent.`);
            console.log(`         The worker stores your tokens on callback — the browser lands on a success page.`);
            console.log(`\n  ${pc.bold('3.')} Confirm your credentials are stored:\n`);
            console.log(`         ${pc.dim('olam auth list --remote ' + baseUrl)}\n`);
            console.log(`  ${pc.dim('Note: full CLI-orchestrated browser SSO flow is deferred to v2 (cookie-bridging complexity).')}\n`);
            if (!opts.printUrl) {
                openBrowser(startUrl);
            }
            return;
        }
        // ── Local path (existing behaviour) ──────────────────────────────────
        const preflight = await runAuthPreflight({ autoStart: true });
        if (preflight.verdict !== 'ok' && preflight.verdict !== 'no-accounts') {
            printError(preflight.message);
            console.log(`  ${pc.dim(preflight.remedy)}`);
            process.exitCode = 1;
            return;
        }
        const client = new AuthClient();
        // Auto-pick a sensible label when the operator didn't supply one.
        // First credential → "primary"; subsequent → "burner-N" with N
        // chosen to dodge any existing label.
        let label = opts.label;
        if (!label) {
            try {
                const existing = await client.status();
                if (existing.accounts.length === 0) {
                    label = 'primary';
                }
                else {
                    const usedLabels = new Set(existing.accounts.map((a) => a.accountLabel ?? a.id));
                    let n = 1;
                    while (usedLabels.has(`burner-${n}`))
                        n += 1;
                    label = `burner-${n}`;
                }
            }
            catch {
                label = 'primary';
            }
        }
        let pending;
        try {
            pending = await client.startLogin(label);
        }
        catch (err) {
            printError(err instanceof Error ? err.message : 'failed to start login');
            process.exitCode = 1;
            return;
        }
        printHeader('Claude OAuth — PKCE flow');
        console.log(`\n  ${pc.bold('1.')} Opening Claude in your default browser…`);
        console.log(`     ${pc.dim(pending.loginUrl)}`);
        openBrowser(pending.loginUrl);
        console.log(`\n  ${pc.bold('2.')} After approving, paste the authorization code from the redirect page.`);
        console.log(`     ${pc.dim('(Format: <code>#<state> or just <code>.)')}\n`);
        const raw = await promptLine(`${pc.dim('code:')} `);
        if (!raw) {
            printError('No code provided.');
            process.exitCode = 1;
            return;
        }
        const [codePart, statePart] = raw.includes('#') ? raw.split('#', 2) : [raw, pending.state];
        try {
            const result = await client.completeLogin(statePart, codePart);
            printSuccess(`Account stored: ${result.account} (${result.expiresIn})`);
            console.log(`\n${pc.dim('Next: olam create --name my-world')}`);
        }
        catch (err) {
            printError(err instanceof Error ? err.message : 'token exchange failed');
            process.exitCode = 1;
        }
    });
    auth
        .command('logout')
        .description('Remove an account from the auth container')
        .argument('<account>', 'Account id')
        .action(async (accountId) => {
        const client = new AuthClient();
        try {
            await client.deleteAccount(accountId);
            printSuccess(`Account removed: ${accountId}`);
        }
        catch (err) {
            printError(err instanceof Error ? err.message : 'failed to delete account');
            process.exitCode = 1;
        }
    });
    auth
        .command('refresh')
        .description('Force-refresh an account token (substrate-aware: updates kubernetes Secret on k8s substrate)')
        .argument('<account>', 'Account id')
        .action(async (accountId) => {
        const cfg = readConfig();
        const isK8s = cfg.host.substrate === 'kubernetes';
        // Kubernetes substrate: validate context before touching auth-service (SEC-NEW-003).
        if (isK8s) {
            const ctxResult = resolveKubectlContext();
            if (ctxResult.error) {
                printError(ctxResult.error);
                process.exitCode = 1;
                return;
            }
            if (ctxResult.deprecationWarning) {
                printWarning(ctxResult.deprecationWarning);
            }
        }
        const client = new AuthClient();
        try {
            const result = await client.refreshAccount(accountId);
            printSuccess(`Refreshed ${result.account} (${result.expiresIn})`);
        }
        catch (err) {
            printError(err instanceof Error ? err.message : 'refresh failed');
            process.exitCode = 1;
            return;
        }
        if (isK8s) {
            const ctxResult = resolveKubectlContext();
            if (ctxResult.context) {
                const code = await applyK8sAuthRefresh(ctxResult.context);
                if (code !== 0)
                    process.exitCode = code;
            }
        }
    });
    // ── e5: bind-service-token ──────────────────────────────────────────────
    auth
        .command('bind-service-token')
        .description('Bind a Cloudflare service token to your CF Access user sub on the remote auth-worker')
        .requiredOption('--remote <url>', 'Auth-worker base URL')
        .requiredOption('--token <client_id:secret>', 'CF service token in format <client_id>:<secret>')
        .option('--label <name>', 'Friendly label for this token (defaults to client_id)')
        .action(async (opts) => {
        const baseUrl = opts.remote;
        const parts = opts.token.split(':');
        if (parts.length < 2) {
            printError('--token must be in format <client_id>:<secret>');
            process.exitCode = 1;
            return;
        }
        const [clientId] = parts;
        const clientIdStr = clientId ?? '';
        const label = opts.label ?? clientIdStr;
        printHeader('Auth worker — bind service token');
        console.log(`\n  ${pc.bold('Step 1:')} Open the URL below in your browser to authenticate via CF Access SSO:`);
        console.log(`\n          ${pc.cyan(baseUrl.replace(/\/+$/, '') + '/v1/oauth/start')}\n`);
        console.log(`          You may see a JSON response or a "no credentials" page — that is normal.`);
        console.log(`          This establishes the session that associates your user sub with the binding.\n`);
        await promptLine(`  ${pc.dim('Press Enter once you have completed the CF Access SSO step...')}`);
        const rawCookie = await promptLine(`\n  ${pc.dim('Paste your CF_Authorization cookie value (DevTools > Application > Cookies > CF_Authorization):')} `);
        if (!rawCookie) {
            printError('No cookie provided. Aborting.');
            process.exitCode = 1;
            return;
        }
        try {
            await remoteBindServiceToken({ baseUrl, cfAuthCookie: rawCookie }, { client_id: clientIdStr, label });
            printSuccess(`Service token bound: ${clientIdStr} (label=${label})`);
            console.log(`\n${pc.dim('Tip: set ANTHROPIC_BASE' + '_URL=' + baseUrl.replace(/\/+$/, '') + '/v1/proxy')}`);
            console.log(`${pc.dim('     to route Claude API calls through this worker.')}\n`);
        }
        catch (err) {
            printError(err instanceof Error ? err.message : 'bind failed');
            process.exitCode = 1;
        }
    });
    // ── e6: list (local + --remote) ─────────────────────────────────────────
    auth
        .command('list')
        .description('List credentials (local by default; --remote to query a remote auth-worker)')
        .option('--remote <url>', 'Auth-worker base URL')
        .option('--cookie <value>', 'CF_Authorization cookie for authenticated requests')
        .option('--json', 'Emit machine-readable JSON instead of the text table (local vault only)', false)
        .action(async (opts) => {
        if (opts.remote) {
            const baseUrl = opts.remote;
            const clientOpts = { baseUrl, cfAuthCookie: opts.cookie };
            let accounts = [];
            let tokens = [];
            try {
                accounts = await remoteListAccounts(clientOpts);
            }
            catch (err) {
                printWarning(`Could not fetch accounts: ${err instanceof Error ? err.message : String(err)}`);
            }
            try {
                tokens = await remoteListServiceTokens(clientOpts);
            }
            catch (err) {
                printWarning(`Could not fetch service tokens: ${err instanceof Error ? err.message : String(err)}`);
            }
            printHeader(`Remote accounts (${accounts.length})`);
            if (accounts.length === 0) {
                console.log(`  ${pc.dim('No accounts — run: olam auth login --remote ' + baseUrl)}`);
            }
            else {
                for (const a of accounts) {
                    const label = a.label ?? a.id;
                    const state = a.state ?? 'unknown';
                    const exp = a.expiresIn ?? '';
                    console.log(`  ${pc.bold(label.padEnd(20))} ${pc.green(state).padEnd(16)} ${pc.dim(exp)}`);
                }
            }
            printHeader(`Remote service tokens (${tokens.length})`);
            if (tokens.length === 0) {
                console.log(`  ${pc.dim('No service tokens — run: olam auth bind-service-token --remote ' + baseUrl)}`);
            }
            else {
                for (const t of tokens) {
                    const label = t.label ?? t.client_id;
                    const created = t.created_at ?? '';
                    console.log(`  ${pc.bold(label.padEnd(20))} ${pc.dim(t.client_id)}  ${pc.dim(created)}`);
                }
            }
            return;
        }
        // Local list (original behaviour)
        const client = new AuthClient();
        const status = await client.status();
        if (!status.reachable) {
            if (opts.json) {
                // Machine-readable error so drivers never screen-scrape the
                // human "not reachable" line. Exit code unchanged (1).
                console.log(JSON.stringify({ error: 'auth-container-unreachable', reachable: false }));
                process.exitCode = 1;
                return;
            }
            printError('Auth container is not reachable. Run `olam services up` first.');
            process.exitCode = 1;
            return;
        }
        if (opts.json) {
            console.log(renderAuthListJson(status.accounts));
            return;
        }
        printHeader(`Credentials (${status.accounts.length})`);
        if (status.accounts.length === 0) {
            console.log(`  ${pc.dim('No credentials — run: olam auth login --label primary')}`);
            return;
        }
        const stateColor = (s) => {
            if (s === 'active')
                return pc.green('active');
            if (s === 'cooldown')
                return pc.yellow('cooldown');
            if (s === 'expired')
                return pc.red('expired');
            if (s === 'disabled')
                return pc.dim('disabled');
            return pc.dim(s ?? 'unknown');
        };
        for (const a of status.accounts) {
            const label = a.accountLabel ?? a.id;
            const reqs = a.usage?.requestCount5h ?? 0;
            const last429 = a.usage?.last429At
                ? `last429=${a.usage.last429At}`
                : 'last429=never';
            const reset = a.rateLimitResetsAt ? `resets=${a.rateLimitResetsAt}` : '';
            console.log(`  ${pc.bold(label.padEnd(18))} ${stateColor(a.state).padEnd(18)} ` +
                `${pc.dim(`req5h=${reqs}`)}  ${pc.dim(`exp=${a.expiresIn}`)} ${pc.dim(last429)} ${pc.yellow(reset)}`);
        }
    });
    // ── e6: migrate-to-remote ──────────────────────────────────────────────
    auth
        .command('migrate-to-remote')
        .description('Print guidance for re-authenticating local credentials against the remote auth-worker (v1: no auto-migration of secrets)')
        .requiredOption('--url <url>', 'Auth-worker base URL')
        .action(async (opts) => {
        const baseUrl = opts.url;
        let accountLabels = [];
        try {
            const client = new AuthClient();
            const status = await client.status();
            accountLabels = status.accounts.map((a) => a.accountLabel ?? a.id);
        }
        catch {
            // Auth container may not be running — proceed with generic guidance.
        }
        printHeader('Migrate local credentials to remote auth-worker');
        console.log(`\n  Remote URL: ${pc.cyan(baseUrl)}\n`);
        console.log(`  ${pc.dim('V1 note: secrets cannot be migrated automatically. Each account must re-authenticate via OAuth.')}\n`);
        if (accountLabels.length === 0) {
            console.log(`  No local accounts found. Run:`);
            console.log(`\n    ${pc.cyan('olam auth login --remote ' + baseUrl)}\n`);
        }
        else {
            console.log(`  Found ${accountLabels.length} local account(s). For each, run:\n`);
            for (const label of accountLabels) {
                console.log(`    ${pc.cyan('olam auth login --remote ' + baseUrl + ' --label ' + label)}`);
            }
            console.log();
        }
    });
    // ── e6: rotate-service-token ───────────────────────────────────────────
    auth
        .command('rotate-service-token')
        .description('Revoke a service token and guide through re-binding a replacement')
        .requiredOption('--url <url>', 'Auth-worker base URL')
        .requiredOption('--client-id <id>', 'CF service token client_id to revoke')
        .option('--cookie <value>', 'CF_Authorization cookie for the DELETE request')
        .action(async (opts) => {
        const baseUrl = opts.url;
        const clientId = opts.clientId;
        printHeader('Auth worker — rotate service token');
        console.log(`\n  Revoking service token: ${pc.yellow(clientId)}\n`);
        try {
            await remoteDeleteServiceToken({ baseUrl, cfAuthCookie: opts.cookie }, clientId);
            printSuccess(`Revoked: ${clientId}`);
        }
        catch (err) {
            printError(err instanceof Error ? err.message : 'revoke failed');
            process.exitCode = 1;
            return;
        }
        console.log(`\n  ${pc.bold('Next steps:')}`);
        console.log(`  1. Mint a new service token in the Cloudflare Zero Trust dashboard.`);
        console.log(`  2. Bind it:\n`);
        console.log(`     ${pc.cyan('olam auth bind-service-token --remote ' + baseUrl + ' --token <new_client_id>:<secret>')}\n`);
    });
    // ── e6: doctor --auth-worker ───────────────────────────────────────────
    auth
        .command('doctor')
        .description('Run 4 diagnostic probes against the remote auth-worker')
        .requiredOption('--auth-worker <url>', 'Auth-worker base URL')
        .option('--cookie <value>', 'CF_Authorization cookie (optional, for authenticated probes)')
        .option('--json', 'Emit JSON output')
        .action(async (opts) => {
        const checks = await runDoctorChecks({
            baseUrl: opts.authWorker,
            cfAuthCookie: opts.cookie,
        });
        if (opts.json) {
            console.log(JSON.stringify(checks, null, 2));
            const failed = checks.filter((c) => c.status === 'fail').length;
            if (failed > 0)
                process.exitCode = 1;
            return;
        }
        printHeader(`Auth-worker diagnostics (${opts.authWorker})`);
        let hasFailure = false;
        for (const c of checks) {
            const icon = c.status === 'pass' ? pc.green('✓') :
                c.status === 'warn' ? pc.yellow('⚠') :
                    pc.red('✗');
            console.log(`  ${icon}  ${pc.bold(c.probe.padEnd(20))} ${c.message}`);
            if (c.remedy) {
                console.log(`       ${pc.dim('↳ ' + c.remedy)}`);
            }
            if (c.status === 'fail')
                hasFailure = true;
        }
        console.log();
        if (hasFailure) {
            printError('One or more probes failed — see remediation steps above.');
            process.exitCode = 1;
        }
        else {
            printSuccess('All probes passed (warnings are non-blocking).');
        }
    });
    // ── g4.1: issue-anthropic-token ───────────────────────────────────────────
    auth
        .command('issue-anthropic-token')
        .description('Mint a new Anthropic proxy token via the remote auth-worker (g4)')
        .requiredOption('--remote <url>', 'Auth-worker base URL')
        .option('--label <name>', 'Friendly label for this token (e.g. my-laptop). Default: <hostname>-<timestamp>')
        .option('--no-write-file', 'Do not write the bearer URL to ~/.olam/anthropic-base-url (default: write)')
        .action(async (opts) => {
        const baseUrl = opts.remote;
        const label = resolveTokenLabel(opts.label);
        printHeader('Auth worker — issue Anthropic proxy token');
        // Phase H h2: prefer a CF Access service token (machine-to-machine) over
        // the manual cookie-paste. When one is configured, authenticate without
        // a browser round-trip.
        const serviceToken = resolveCfAccessServiceToken();
        let remoteOpts;
        if (serviceToken) {
            console.log(`\n  ${pc.dim('Using CF Access service token (machine-to-machine; no cookie needed).')}`);
            remoteOpts = {
                baseUrl,
                cfAccessClientId: serviceToken.clientId,
                cfAccessClientSecret: serviceToken.clientSecret,
            };
        }
        else {
            console.log(`\n  Open ${pc.cyan(baseUrl.replace(/\/+$/, '') + '/v1/oauth/start')} in a browser to authenticate via CF Access SSO.`);
            console.log(`  Once you've completed SSO, paste your CF_Authorization cookie below`);
            console.log(`  (from browser DevTools → Application → Cookies → CF_Authorization).`);
            console.log(`  ${pc.dim('Tip: provision a CF Access service token to skip this — see docs/runbooks/cf-access-service-token.md')}\n`);
            const rawCookie = await promptLine(`  ${pc.dim('CF_Authorization cookie:')} `);
            if (!rawCookie) {
                printError('No cookie provided. Aborting.');
                process.exitCode = 1;
                return;
            }
            remoteOpts = { baseUrl, cfAuthCookie: rawCookie };
        }
        try {
            const result = await remoteIssueAnthropicToken(remoteOpts, label);
            printSuccess(`Anthropic proxy token issued (label: ${result.label})`);
            // Fix 1: write the BARE bearer URL straight to where auth-client's
            // resolveCloudUrl() reads it — no hand-copy, no export-wrapper format
            // mismatch. Opt out with --no-write-file. Never log the secret value;
            // the URL embeds it, so the confirmation line is intentionally generic.
            if (result.anthropic_base_url_hint) {
                const { wrote } = writeAnthropicBaseUrlFile(result.anthropic_base_url_hint, {
                    write: opts.writeFile,
                });
                if (wrote) {
                    console.log(`\n  ${pc.green('✓')} wrote bearer URL to ~/.olam/anthropic-base-url (chmod 600)`);
                }
            }
            console.log(`\n  Or set it in your shell environment yourself:`);
            // audit:auth-callers: display-only string, not an assignment — split to avoid the regex.
            const exportHint = 'export ANTHROPIC_BASE_URL' + `='${result.anthropic_base_url_hint}'`;
            console.log(`    ${pc.cyan(exportHint)}`);
            console.log(`\n  ${pc.yellow('WARNING: the secret above is shown ONCE. Save it now — you cannot retrieve it later.')}`);
            console.log(`  Secret:     ${pc.bold(result.secret)}`);
            console.log(`  Token hash (for revocation): ${pc.dim(result.token_hash)}\n`);
        }
        catch (err) {
            printError(err instanceof Error ? err.message : 'issue failed');
            process.exitCode = 1;
        }
    });
    // ── g4.2: list-anthropic-tokens ───────────────────────────────────────────
    auth
        .command('list-anthropic-tokens')
        .description('List Anthropic proxy tokens from the remote auth-worker (g4)')
        .requiredOption('--remote <url>', 'Auth-worker base URL')
        .action(async (opts) => {
        const baseUrl = opts.remote;
        printHeader('Auth worker — list Anthropic proxy tokens');
        // Phase H h2: prefer a CF Access service token over manual cookie-paste.
        const serviceToken = resolveCfAccessServiceToken();
        let remoteOpts;
        if (serviceToken) {
            console.log(`\n  ${pc.dim('Using CF Access service token (machine-to-machine; no cookie needed).')}`);
            remoteOpts = {
                baseUrl,
                cfAccessClientId: serviceToken.clientId,
                cfAccessClientSecret: serviceToken.clientSecret,
            };
        }
        else {
            console.log(`\n  Open ${pc.cyan(baseUrl.replace(/\/+$/, '') + '/v1/oauth/start')} in a browser to authenticate via CF Access SSO.`);
            console.log(`  Once you've completed SSO, paste your CF_Authorization cookie below.`);
            console.log(`  ${pc.dim('Tip: provision a CF Access service token to skip this — see docs/runbooks/cf-access-service-token.md')}\n`);
            const rawCookie = await promptLine(`  ${pc.dim('CF_Authorization cookie:')} `);
            if (!rawCookie) {
                printError('No cookie provided. Aborting.');
                process.exitCode = 1;
                return;
            }
            remoteOpts = { baseUrl, cfAuthCookie: rawCookie };
        }
        try {
            const tokens = await remoteListAnthropicTokens(remoteOpts);
            if (tokens.length === 0) {
                console.log(`\n  ${pc.dim('No Anthropic proxy tokens found. Run: olam auth issue-anthropic-token --remote ' + baseUrl + ' --label <name>')}\n`);
                return;
            }
            const col = (s, w) => s.padEnd(w);
            console.log(`\n  ${'Label'.padEnd(20)} ${'Issued'.padEnd(22)} ${'Last Used'.padEnd(22)} ${'Token Hash (prefix)'}`);
            console.log(`  ${'-'.repeat(20)} ${'-'.repeat(22)} ${'-'.repeat(22)} ${'-'.repeat(10)}`);
            for (const t of tokens) {
                const issued = t.issued_at ?? '—';
                const lastUsed = t.last_used_at ?? '—';
                const hashPrefix = t.token_hash.slice(0, 8);
                console.log(`  ${col(t.label, 20)} ${col(issued, 22)} ${col(lastUsed, 22)} ${pc.dim(hashPrefix)}`);
            }
            console.log();
        }
        catch (err) {
            printError(err instanceof Error ? err.message : 'list failed');
            process.exitCode = 1;
        }
    });
    // ── g4.3: revoke-anthropic-token ──────────────────────────────────────────
    auth
        .command('revoke-anthropic-token')
        .description('Revoke an Anthropic proxy token on the remote auth-worker (g4)')
        .requiredOption('--remote <url>', 'Auth-worker base URL')
        .requiredOption('--token-hash <hash>', 'Token hash to revoke (from issue or list output)')
        .action(async (opts) => {
        const baseUrl = opts.remote;
        printHeader('Auth worker — revoke Anthropic proxy token');
        console.log(`\n  Open ${pc.cyan(baseUrl.replace(/\/+$/, '') + '/v1/oauth/start')} in a browser to authenticate via CF Access SSO.`);
        console.log(`  Once you've completed SSO, paste your CF_Authorization cookie below.\n`);
        const rawCookie = await promptLine(`  ${pc.dim('CF_Authorization cookie:')} `);
        if (!rawCookie) {
            printError('No cookie provided. Aborting.');
            process.exitCode = 1;
            return;
        }
        try {
            const revoked = await remoteRevokeAnthropicToken({ baseUrl, cfAuthCookie: rawCookie }, opts.tokenHash);
            if (revoked) {
                printSuccess(`Token ${opts.tokenHash} revoked.`);
            }
            else {
                printWarning(`Token ${opts.tokenHash} not found (may already be revoked).`);
            }
        }
        catch (err) {
            printError(err instanceof Error ? err.message : 'revoke failed');
            process.exitCode = 1;
        }
    });
    registerAuthUpgrade(auth);
}
//# sourceMappingURL=auth.js.map