@gravity-rail/cli 0.46.0 → 0.49.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@gravity-rail/cli",
3
- "version": "0.46.0",
3
+ "version": "0.49.0",
4
4
  "description": "Gravity Rail CLI — manage workspaces from the command line",
5
5
  "type": "module",
6
6
  "bin": {
@@ -47,13 +47,13 @@
47
47
  "test:ci": "jest --forceExit --passWithNoTests --coverage --coverageReporters=json-summary --coverageReporters=text-summary"
48
48
  },
49
49
  "dependencies": {
50
- "@gravity-rail/sdk": "^0.46.0",
50
+ "@gravity-rail/sdk": "^0.49.0",
51
51
  "js-yaml": "^5.4.2"
52
52
  },
53
53
  "devDependencies": {
54
54
  "@gravity-rail/sandbox": "0.7.29",
55
55
  "@types/jest": "^30.0.0",
56
- "@types/node": "^26.2.0",
56
+ "@types/node": "^26.6.4",
57
57
  "jest": "^30.5.2",
58
58
  "ts-jest": "29.4.9",
59
59
  "tsup": "^8.5.1",
@@ -1 +0,0 @@
1
- {"version":3,"sources":["../src/lib/pagination.ts","../src/lib/jq.ts","../src/lib/output.ts","../src/lib/context.ts","../src/lib/org-auth.ts","../src/lib/sandbox-fetch.ts","../src/lib/concierge-api.ts"],"sourcesContent":["import type { ArgDef, ParsedArgs } from './types';\nimport { CLIError } from './errors';\n\n// ── Response shape detection ─────────────────────────────────────────\n\n/** Metadata extracted from a paginated API response */\nexport interface PaginationMeta {\n /** Total number of items across all pages (page-based only) */\n total?: number;\n /** Current page number (page-based only) */\n page?: number;\n /** Total pages (page-based only) */\n totalPages?: number;\n /** Whether more pages exist (cursor-based only) */\n hasMore?: boolean;\n /** Cursor for next page (cursor-based only) */\n nextCursor?: string;\n}\n\n/** Explicit pagination contract passed from commands to outputData */\nexport interface ListResult {\n items: unknown[];\n meta?: PaginationMeta;\n supportsAll?: boolean;\n}\n\n/** Type guard: is the value a ListResult (explicit contract)? */\nexport function isListResult(data: unknown): data is ListResult {\n if (!data || typeof data !== 'object' || Array.isArray(data)) return false;\n const obj = data as Record<string, unknown>;\n return (\n Array.isArray(obj.items) &&\n ('supportsAll' in obj ||\n ('meta' in obj && (obj.meta === undefined || typeof obj.meta === 'object')))\n );\n}\n\n/** Check if a response looks like a page-based paginated envelope.\n * Matches both `{ items, total, totalPages, page }` (standard) and\n * `{ items, total, page, pageSize }` (legacy — e.g. InvitationListResponse,\n * InquiryListResponse). This is a pure type guard with no side effects;\n * totalPages computation for legacy shapes happens in extractPaginationMeta. */\nexport function isPagePaginatedResponse(data: unknown): data is {\n items: unknown[];\n total: number;\n page: number;\n totalPages?: number;\n pageSize?: number;\n} {\n if (!data || typeof data !== 'object') return false;\n const obj = data as Record<string, unknown>;\n if (!Array.isArray(obj.items) || typeof obj.page !== 'number') return false;\n\n // Standard shape: has totalPages\n if (typeof obj.totalPages === 'number') return true;\n\n // Legacy shape: has total + pageSize but no totalPages\n if (typeof obj.total === 'number' && typeof obj.pageSize === 'number') return true;\n\n return false;\n}\n\n/** Check if a response looks like a cursor-based paginated envelope */\nexport function isCursorPaginatedResponse(data: unknown): data is {\n items: unknown[];\n hasMore: boolean;\n nextCursor?: string;\n} {\n if (!data || typeof data !== 'object') return false;\n const obj = data as Record<string, unknown>;\n return Array.isArray(obj.items) && typeof obj.hasMore === 'boolean';\n}\n\n/** Check if a response is any paginated envelope ({ items: [...], ... }) */\nexport function isPaginatedResponse(data: unknown): boolean {\n return isPagePaginatedResponse(data) || isCursorPaginatedResponse(data);\n}\n\n/** Extract pagination metadata from a response, or return undefined for non-paginated responses.\n * For legacy shapes without totalPages, computes it from total/pageSize. */\nexport function extractPaginationMeta(data: unknown): PaginationMeta | undefined {\n if (isPagePaginatedResponse(data)) {\n const totalPages =\n data.totalPages ?? (data.pageSize ? Math.ceil(data.total / data.pageSize) : undefined);\n return {\n total: data.total,\n page: data.page,\n totalPages,\n };\n }\n if (isCursorPaginatedResponse(data)) {\n return {\n hasMore: data.hasMore,\n nextCursor: data.nextCursor,\n };\n }\n return undefined;\n}\n\n// ── Warning formatting ───────────────────────────────────────────────\n\n/** Format a pagination warning for stderr. Returns undefined if no warning needed.\n * When `supportsAll` is false, the \"Use --all\" hint is omitted because the\n * command does not actually expose the --all flag. */\nexport function formatPaginationWarning(\n meta: PaginationMeta | undefined,\n supportsAll: boolean = true\n): string | undefined {\n if (!meta) return undefined;\n\n const allHint = supportsAll ? ' Use --all to fetch all pages.' : '';\n\n // Page-based: warn when there are multiple pages\n if (meta.totalPages !== undefined && meta.totalPages > 1) {\n const pageNum = meta.page ?? 1;\n return `Showing page ${pageNum} of ${meta.totalPages} (${meta.total} total items).${allHint}`;\n }\n\n // Cursor-based: warn when more pages exist\n if (meta.hasMore === true) {\n return `More results available.${allHint}`;\n }\n\n return undefined;\n}\n\n// ── Unwrapping ───────────────────────────────────────────────────────\n\n/** Unwrap items from a paginated response or return the data as-is if it's an array */\nexport function unwrapItems(data: unknown): unknown[] {\n if (Array.isArray(data)) return data;\n if (\n data &&\n typeof data === 'object' &&\n 'items' in data &&\n Array.isArray((data as Record<string, unknown>).items)\n ) {\n return (data as Record<string, unknown>).items as unknown[];\n }\n return [data];\n}\n\n// ── Arg definitions ──────────────────────────────────────────────────\n\n/** Default pagination args for list commands (page, page-size, all). No search. */\nexport const LIST_PAGINATION_ARGS: ArgDef[] = [\n { name: 'page', description: 'Page number' },\n { name: 'page-size', description: 'Page size' },\n { name: 'all', description: 'Fetch all pages and return combined results', isFlag: true },\n];\n\n// ── Arg-to-options helpers ───────────────────────────────────────────\n\n/** Convert parsed CLI args to API pagination options */\nexport function parsePaginationArgs(args: ParsedArgs): {\n page?: number;\n pageSize?: number;\n all?: boolean;\n} {\n const result: { page?: number; pageSize?: number; all?: boolean } = {};\n\n if (args.all === true) {\n result.all = true;\n }\n\n if (args.page !== undefined) {\n const num = Number(args.page);\n if (isNaN(num) || num < 1) throw new CLIError('--page must be a positive integer');\n result.page = num;\n }\n\n if (args['page-size'] !== undefined) {\n const num = Number(args['page-size']);\n if (isNaN(num) || num < 1) throw new CLIError('--page-size must be a positive integer');\n if (num > 100) throw new CLIError('--page-size must be at most 100 (API limit)');\n result.pageSize = num;\n }\n\n return result;\n}\n\n// ── fetchAll helpers ─────────────────────────────────────────────────\n\nconst MAX_PAGE_SIZE = 100;\nconst MAX_PAGES = 200; // Safety limit to prevent infinite loops\n\n/**\n * Fetch all pages from a page-based paginated endpoint.\n * The fetcher receives { page, pageSize } and should return the raw API response.\n * Throws CLIError if MAX_PAGES is reached without exhausting all pages.\n */\nexport async function fetchAllPages(\n fetcher: (opts: { page: number; pageSize: number }) => Promise<unknown>\n): Promise<unknown[]> {\n const allItems: unknown[] = [];\n let page = 1;\n\n while (page <= MAX_PAGES) {\n const result = await fetcher({ page, pageSize: MAX_PAGE_SIZE });\n const items = unwrapItems(result);\n allItems.push(...items);\n\n // Use server metadata for termination\n const meta = extractPaginationMeta(result);\n if (meta?.totalPages !== undefined) {\n if (page >= meta.totalPages) break;\n } else if (!isPagePaginatedResponse(result)) {\n // Raw array or no metadata — single fetch is enough\n if (items.length < MAX_PAGE_SIZE) break;\n }\n\n if (page === MAX_PAGES) {\n throw new CLIError(\n `Reached maximum page limit (${MAX_PAGES}). Results may be incomplete.`\n );\n }\n\n page++;\n }\n\n return allItems;\n}\n\n/**\n * Fetch all pages from a cursor-based paginated endpoint.\n * The fetcher receives { cursor? } and should return the raw API response.\n * Throws CLIError if MAX_PAGES is reached without exhausting all pages.\n */\nexport async function fetchAllCursorPages(\n fetcher: (opts: { cursor?: string }) => Promise<unknown>\n): Promise<unknown[]> {\n const allItems: unknown[] = [];\n let cursor: string | undefined;\n let pages = 0;\n\n while (pages < MAX_PAGES) {\n const result = await fetcher({ cursor });\n const items = unwrapItems(result);\n allItems.push(...items);\n pages++;\n\n if (isCursorPaginatedResponse(result) && result.hasMore && result.nextCursor) {\n cursor = result.nextCursor;\n } else {\n break;\n }\n\n if (pages === MAX_PAGES) {\n throw new CLIError(\n `Reached maximum page limit (${MAX_PAGES}). Results may be incomplete.`\n );\n }\n }\n\n return allItems;\n}\n\n// ── ListResult factory ──────────────────────────────────────────────\n\n/**\n * Wrap a raw API response into a ListResult with explicit pagination metadata.\n * Works with both page-based and cursor-based responses, as well as plain arrays.\n *\n * @param data - Raw API response (paginated envelope or plain array)\n * @param supportsAll - Whether the calling command exposes --all\n */\nexport function listResult(data: unknown, supportsAll: boolean = false): ListResult {\n return {\n items: unwrapItems(data),\n meta: extractPaginationMeta(data),\n supportsAll,\n };\n}\n","import { spawnSync } from 'node:child_process';\nimport { CLIError } from './errors';\n\n/**\n * Apply a jq filter to CLI output, in-process.\n *\n * Why this exists rather than telling callers to pipe: `gr … -o json | jq …`\n * puts the burden of building a valid pipeline on the caller, and that is where\n * it breaks. A forensic pass over 90 days of Workspace Manager chats found\n * `jq: parse error` in 49 of 392 chats (PR #22929) — the second most common\n * failure signature in the whole corpus. The agent pipes a table-formatted\n * listing into jq, or pipes a command that errored and emitted nothing, and jq\n * chokes on input the agent never inspected.\n *\n * `--jq` removes the failure mode rather than documenting around it: the filter\n * runs against the JSON *we* just serialised, so the input is valid by\n * construction and `-o json` is implied. A bad filter now produces one clear\n * error about the filter, instead of a parse error about bytes the caller\n * cannot see.\n *\n * We shell out to the system `jq` deliberately. A pure-JS reimplementation\n * would be a new dependency and a second dialect to keep in sync with the one\n * people already know; the sandbox and every developer machine has `jq` on\n * PATH. When it is genuinely missing we say so and name the fallback, rather\n * than silently emitting unfiltered JSON that a script would then misread.\n */\nexport function applyJqFilter(json: string, filter: string): string {\n // No try/catch: spawnSync reports a missing or unspawnable binary through\n // `result.error`, it does not throw for those cases. A catch here would be\n // unreachable for exactly the failures it claimed to handle.\n const result = spawnSync('jq', ['-r', filter], {\n input: json,\n encoding: 'utf8',\n maxBuffer: 64 * 1024 * 1024,\n });\n\n if (result.error && (result.error as NodeJS.ErrnoException).code === 'ENOENT') {\n throw new CLIError(\n '--jq requires the `jq` binary on PATH, and it was not found. ' +\n 'Install jq, or omit --jq and filter the JSON yourself.'\n );\n }\n // A filter jq cannot COMPILE makes it print the syntax error and exit\n // without ever reading stdin, so our write lands on a closed pipe and\n // spawnSync reports EPIPE in `error` *alongside* jq's real exit status. It is\n // a race at any input size — whether the write or jq's exit gets there first\n // — which is why checking `error` before `status` replaced jq's diagnostic\n // with a pipe error only intermittently, and read as an unrelated flake.\n // EPIPE together with an exit status is therefore not a spawn failure; every\n // other `error` (ENOENT above, ENOBUFS from maxBuffer, a failed fork) is.\n const wroteToExitedJq =\n (result.error as NodeJS.ErrnoException | undefined)?.code === 'EPIPE' &&\n result.status !== null;\n if (result.error && !wroteToExitedJq) {\n throw new CLIError(`--jq could not run jq: ${result.error.message}`);\n }\n if (result.status !== 0) {\n // jq's own diagnostic is the useful part — it names the position in the\n // filter. Prefixing it keeps the caller from reading it as a gr error.\n const exited = result.signal\n ? `jq was killed by ${result.signal}`\n : `jq exited ${result.status}`;\n const detail = (result.stderr || '').trim() || exited;\n throw new CLIError(`--jq filter failed: ${detail}`);\n }\n\n return (result.stdout || '').replace(/\\n$/, '');\n}\n","import { printTable } from '../cli-utils';\nimport { applyJqFilter } from './jq';\nimport {\n type PaginationMeta,\n isListResult,\n extractPaginationMeta,\n formatPaginationWarning,\n unwrapItems,\n} from './pagination';\n\nexport type OutputFormat = 'json' | 'jsonl' | 'table';\n\nexport interface OutputOptions {\n outputFormat: OutputFormat;\n /**\n * jq filter applied to the serialised JSON before it reaches stdout.\n *\n * Setting this implies JSON output regardless of `outputFormat`: a filter\n * over a rendered table is meaningless, and silently filtering nothing is\n * worse than ignoring the flag. See `lib/jq.ts` for why the filter lives\n * here rather than in a shell pipe.\n */\n jq?: string;\n}\n\nexport interface TableColumn<T> {\n header: string;\n getValue: (item: T) => string;\n maxWidth?: number;\n}\n\n/** Write JSON to stdout, applying `opts.jq` when one was requested. */\nfunction writeJson(value: unknown, opts: OutputOptions, pretty = true): void {\n const json = pretty ? JSON.stringify(value, null, 2) : JSON.stringify(value);\n if (opts.jq) {\n const filtered = applyJqFilter(json, opts.jq);\n process.stdout.write(filtered === '' ? '\\n' : filtered + '\\n');\n return;\n }\n process.stdout.write(json + '\\n');\n}\n\n/** Detect default output format based on whether stdout is a TTY */\nexport function detectOutputFormat(explicit?: string): OutputFormat {\n if (explicit) return explicit as OutputFormat;\n return process.stdout.isTTY ? 'table' : 'json';\n}\n\n/**\n * Write a list of items to stdout in the requested format.\n *\n * Accepts:\n * - A `ListResult` (explicit contract with items, meta, supportsAll) — preferred.\n * - Raw arrays, paginated responses ({ items: [...] }), or any object — legacy.\n *\n * When a `ListResult` is passed, its explicit `meta` and `supportsAll` are used.\n * When raw data is passed, pagination metadata is auto-detected with\n * `supportsAll: false` as the safe default.\n *\n * The optional `paginationMeta` and `supportsAll` parameters are kept for\n * backward compatibility but are ignored when a `ListResult` is passed.\n */\nexport function outputData(\n data: unknown,\n opts: OutputOptions,\n columns?: TableColumn<any>[],\n paginationMeta?: PaginationMeta,\n supportsAll?: boolean\n): void {\n let items: unknown[];\n let meta: PaginationMeta | undefined;\n let allSupported: boolean;\n\n if (isListResult(data)) {\n // Explicit contract: use ListResult fields directly\n items = data.items;\n meta = data.meta;\n allSupported = data.supportsAll ?? false;\n } else {\n // Legacy path: auto-detect from raw data\n items = unwrapItems(data);\n meta = paginationMeta ?? extractPaginationMeta(data);\n allSupported = supportsAll ?? false;\n }\n\n const warning = formatPaginationWarning(meta, allSupported);\n if (warning) {\n process.stderr.write(warning + '\\n');\n }\n\n if (opts.jq) {\n writeJson(items, opts);\n return;\n }\n\n switch (opts.outputFormat) {\n case 'json':\n writeJson(items, opts);\n break;\n case 'jsonl':\n for (const item of items) {\n process.stdout.write(JSON.stringify(item) + '\\n');\n }\n break;\n case 'table':\n if (columns) {\n printTable(items, columns);\n } else {\n writeJson(items, opts);\n }\n break;\n }\n}\n\n/** Write a single object to stdout in the requested format */\nexport function outputSingle<T>(data: T, opts: OutputOptions, columns?: TableColumn<T>[]): void {\n if (opts.jq) {\n writeJson(data, opts);\n return;\n }\n\n switch (opts.outputFormat) {\n case 'json':\n writeJson(data, opts);\n break;\n case 'jsonl':\n process.stdout.write(JSON.stringify(data) + '\\n');\n break;\n case 'table':\n if (columns) {\n printTable([data], columns);\n } else {\n writeJson(data, opts);\n }\n break;\n }\n}\n\n/** Common column factory helpers for domain files.\n *\n * GR app-facing API wire is camelCase. First-party consumers (CLI, lambdas we\n * own) read that shape only — no snake_case dual-read \"bandaid\". When the API\n * flips a key, convert the consumer; do not carry both. (#19305)\n */\nexport const COL = {\n id: (): TableColumn<any> => ({ header: 'ID', getValue: (item) => String(item.id ?? '') }),\n uuid: (): TableColumn<any> => ({ header: 'UUID', getValue: (item) => item.uuid ?? '' }),\n name: (): TableColumn<any> => ({ header: 'NAME', getValue: (item) => item.name ?? '' }),\n status: (): TableColumn<any> => ({ header: 'STATUS', getValue: (item) => item.status ?? '' }),\n created: (): TableColumn<any> => ({\n header: 'CREATED',\n getValue: (item) => item.createdAt ?? '',\n }),\n updated: (): TableColumn<any> => ({\n header: 'UPDATED',\n getValue: (item) => item.updatedAt ?? '',\n }),\n description: (): TableColumn<any> => ({\n header: 'DESCRIPTION',\n getValue: (item) => item.description ?? '',\n }),\n enabled: (): TableColumn<any> => ({\n header: 'ENABLED',\n getValue: (item) => String(item.enabled ?? ''),\n }),\n};\n\n/**\n * Print a follow-on suggestion under the result, table output only.\n *\n * Suppressed for json/jsonl so machine consumers get parseable output — a hint\n * written to stdout would corrupt it.\n */\nexport function hint(opts: { outputFormat?: string }, lines: string[]): void {\n if ((opts.outputFormat ?? 'table') !== 'table') return;\n process.stdout.write('\\n' + lines.join('\\n') + '\\n');\n}\n\n/** Write a status/progress message to stderr (never pollutes stdout) */\nexport function stderr(msg: string): void {\n process.stderr.write(msg + '\\n');\n}\n\n/**\n * Wait until everything written to stdout has actually reached the OS.\n *\n * Call this before `process.exit()`. `process.exit` does not flush a pending\n * asynchronous write, and stdout **is** asynchronous whenever it is a pipe\n * (Node only makes it synchronous for files and TTYs), so a large piped payload\n * is silently cut at the pipe buffer — 8KB on Linux, 64KB elsewhere.\n *\n * `writableNeedDrain` is the wrong probe and was the bug: it only goes true\n * once the buffered amount exceeds `highWaterMark` (16KB by default). A 10KB\n * JSON document sits fully buffered with `needDrain === false`, so the guard\n * passed and `process.exit` discarded the tail. Observed as\n * `json.decoder.JSONDecodeError: Expecting ':' delimiter` at exactly char 8192\n * in a script reading `gr admin workspaces list -o json` through a pipe, while\n * the same command redirected to a file was complete and valid.\n *\n * The reliable signal is the write callback, which fires only after the data is\n * handed off. An empty write queues behind whatever is already pending, so its\n * callback is a barrier for all of it.\n */\nexport async function flushStdout(): Promise<void> {\n if (process.stdout.writableLength === 0) return;\n await new Promise<void>((resolve) => {\n process.stdout.write('', () => resolve());\n });\n}\n","import { GravityRailClient } from '@gravity-rail/sdk';\nimport {\n CredentialsManager,\n getEnvironmentConfig,\n resolveNonInteractiveAuth,\n type AuthResult,\n type EnvironmentConfig,\n} from '../cli-utils';\nimport { homedir } from 'os';\nimport { detectOutputFormat, type OutputFormat } from './output';\nimport { AuthRequiredError } from './errors';\nimport { registerOrgAuthHandler, type OrgAuthContext } from './org-auth';\nimport { createSandboxFetchFromEnv } from './sandbox-fetch';\n\n/** Build an authenticated API client with the CLI org-auth handler registered. */\nfunction makeApiClient(\n accessToken: string | undefined,\n apiUrl: string,\n fetchFn?: typeof fetch,\n orgAuthCtx?: OrgAuthContext\n): GravityRailClient {\n const resolvedFetch = fetchFn ?? createSandboxFetchFromEnv();\n const apiClient = new GravityRailClient(accessToken, apiUrl, resolvedFetch);\n registerOrgAuthHandler(apiClient, apiUrl, accessToken ?? '', orgAuthCtx);\n return apiClient;\n}\n\n/**\n * Org-auth context for a profile (login) command: enables the browser SSO\n * step-up and caches the captured session under the profile. API-key and\n * credential-broker contexts omit this — API keys are gate-exempt, and the\n * sandbox broker is non-interactive (no browser).\n */\nfunction interactiveOrgAuth(ctx: CommandContext): OrgAuthContext {\n return {\n credentialsManager: ctx.credentialsManager,\n env: ctx.env,\n profile: ctx.profile,\n frontendUrl: ctx.envConfig.frontendUrl,\n interactive: true,\n };\n}\n\n/**\n * Credential-broker context (code-interpreter sandbox): the scoped token is held\n * by the broker and absent from the env, so the CLI talks to the loopback broker\n * with NO auth header. Returns null when not in the sandbox (no broker URL) — the\n * standalone CLI then falls through to GRAVITY_RAIL_API_KEY / profile auth.\n */\n/**\n * The credential broker is ALWAYS a loopback listener inside the sandbox VM.\n * Requests sent to it carry no Authorization header (the broker adds it), so a\n * non-loopback value here would ship unauthenticated API traffic — including\n * request bodies — to an arbitrary host. uid-1000 code can set env vars, so\n * treat the URL as untrusted and accept only loopback. Anything else is ignored\n * (we fall through to normal auth) rather than trusted.\n */\nfunction isLoopbackBrokerUrl(rawUrl: string): boolean {\n try {\n const { hostname, protocol } = new URL(rawUrl);\n if (protocol !== 'http:' && protocol !== 'https:') return false;\n // URL() preserves brackets on IPv6 literals.\n const host = hostname.replace(/^\\[|\\]$/g, '');\n return host === '127.0.0.1' || host === '::1' || host === 'localhost';\n } catch {\n return false;\n }\n}\n\n/**\n * The sandbox's loopback broker URL, or null when not running in a sandbox.\n *\n * Single place the `GRAVITY_RAIL_BROKER_URL` loopback check lives, so every\n * caller — authenticated commands and unauthenticated ones like `docs search` —\n * applies the same validation.\n */\nexport function sandboxBrokerUrl(): string | null {\n const brokerUrl = process.env.GRAVITY_RAIL_BROKER_URL;\n if (!brokerUrl || !isLoopbackBrokerUrl(brokerUrl)) return null;\n return brokerUrl;\n}\n\nfunction tryBrokerContext(ctx: CommandContext): AuthenticatedContext | null {\n const brokerUrl = sandboxBrokerUrl();\n if (!brokerUrl) return null;\n const apiClient = makeApiClient(undefined, brokerUrl, createSandboxFetchFromEnv());\n return { ...ctx, accessToken: '', apiClient };\n}\n\nfunction contextWithToken(ctx: CommandContext, auth: AuthResult): AuthenticatedContext {\n const apiClient = makeApiClient(\n auth.accessToken,\n ctx.envConfig.apiUrl,\n undefined,\n auth.credentials ? interactiveOrgAuth(ctx) : undefined\n );\n return {\n ...ctx,\n accessToken: auth.accessToken,\n apiClient,\n profileWorkspace: auth.credentials?.workspaceUuid,\n };\n}\n\nexport interface GlobalOptions {\n env: string;\n /** Override API base URL (also: GRAVITY_RAIL_API_URL env var). */\n apiUrl?: string;\n outputFormat?: string;\n jq?: string;\n verbose?: boolean;\n allowWrite?: boolean;\n /** Named credential profile (`--profile` / GRAVITY_RAIL_PROFILE). */\n profile?: string;\n /** Directory to classify as a linked worktree. Defaults to `process.cwd()`. */\n startDir?: string;\n}\n\nexport interface PublicGlobalOptions {\n env?: string;\n apiUrl?: string;\n frontendUrl?: string;\n outputFormat?: string;\n jq?: string;\n verbose?: boolean;\n allowWrite?: boolean;\n /** Named credential profile (`--profile` / GRAVITY_RAIL_PROFILE). */\n profile?: string;\n /** Directory to classify as a linked worktree. Defaults to `process.cwd()`. */\n startDir?: string;\n}\n\nexport interface CommandContext {\n env: string;\n envConfig: EnvironmentConfig;\n outputFormat: OutputFormat;\n /** `--jq` filter, applied to JSON output. See `lib/jq.ts`. */\n jq?: string;\n verbose: boolean;\n allowWrite: boolean;\n credentialsManager: CredentialsManager;\n /** Resolved credential profile for this invocation. */\n profile: string;\n}\n\nexport interface AuthenticatedContext extends CommandContext {\n accessToken: string;\n apiClient: GravityRailClient;\n /** Default workspace UUID from the profile (dev workspace/member profiles). */\n profileWorkspace?: string;\n}\n\n/** Create a base command context (no auth required) */\nexport function createContext(opts: GlobalOptions): CommandContext {\n const envConfig = getEnvironmentConfig(opts.env, {\n apiUrl: opts.apiUrl,\n startDir: opts.startDir,\n });\n const credentialsManager = new CredentialsManager(homedir(), envConfig.apiUrl);\n const profile = credentialsManager.resolveProfileName(opts.profile, opts.env);\n return {\n env: opts.env,\n envConfig,\n outputFormat: detectOutputFormat(opts.outputFormat),\n jq: opts.jq,\n verbose: opts.verbose ?? false,\n allowWrite: opts.allowWrite ?? false,\n credentialsManager,\n profile,\n };\n}\n\n/**\n * Create an authenticated command context.\n * Order: GRAVITY_RAIL_API_KEY → named/current profile store. Never auto-triggers OAuth.\n *\n * Dev accounts that used to be selected with `--realm` are now named profiles\n * (import with `gr auth import-dev` after provisioning).\n */\nexport async function createAuthenticatedContext(\n opts: GlobalOptions\n): Promise<AuthenticatedContext> {\n // eslint-disable-next-line @eslint-react/naming-convention-context-name -- CLI handler context, not React\n const ctx = createContext(opts);\n\n // Credential-broker mode takes precedence: token lives in the root daemon,\n // not the env, so route through the loopback broker with no auth header.\n const brokerCtx = tryBrokerContext(ctx);\n if (brokerCtx) return brokerCtx;\n\n const auth = await resolveNonInteractiveAuth({\n env: ctx.env,\n envConfig: ctx.envConfig,\n credentialsManager: ctx.credentialsManager,\n profile: ctx.profile,\n });\n if (auth) return contextWithToken(ctx, auth);\n\n if (ctx.profile !== 'default') {\n throw new AuthRequiredError(\n `No credentials for profile \"${ctx.profile}\" (${ctx.env}). ` +\n `Run: gr auth login --name ${ctx.profile} or gr auth import-dev`\n );\n }\n throw new AuthRequiredError(\n 'Not authenticated. Run `gr login`, `gr auth import-dev` (local dev), or set GRAVITY_RAIL_API_KEY.'\n );\n}\n\n/**\n * Narrow a handler context to `AuthenticatedContext`.\n *\n * Handler `ctx` is typed as `AuthenticatedContext | CommandContext` so that\n * `requiresAuth: false` handlers can also share the type. At runtime, every\n * handler that did not opt out of auth will receive an `AuthenticatedContext`,\n * but TypeScript cannot verify this — call this helper before accessing\n * `apiClient` / `accessToken`.\n *\n * Throws if called from a handler that did not declare `requiresAuth`.\n */\nexport function requireAuth(ctx: AuthenticatedContext | CommandContext): AuthenticatedContext {\n if (!('apiClient' in ctx)) {\n throw new Error('Command handler accessed apiClient without declaring requiresAuth');\n }\n return ctx;\n}\n\n/** Create a base command context for the public CLI (defaults to prod) */\nexport function createPublicContext(opts: PublicGlobalOptions): CommandContext {\n // INVARIANT — the public `gr` CLI defaults to PROD. Public API consumers have NO access to\n // our dev/staging environments; prod is the only API they can reach, so an unset env MUST\n // resolve to prod. Do NOT change this to 'dev'/'staging' for internal convenience or to\n // satisfy a ticket claiming the prod default is a bug (see #15819 — the bug was the --help\n // text, not this default). Internal devs select a non-prod env with an explicit `--env`.\n const env = opts.env ?? 'prod';\n const envConfig = getEnvironmentConfig(env, {\n apiUrl: opts.apiUrl,\n frontendUrl: opts.frontendUrl,\n startDir: opts.startDir,\n });\n const credentialsManager = new CredentialsManager(homedir(), envConfig.apiUrl);\n const profile = credentialsManager.resolveProfileName(opts.profile, env);\n return {\n env,\n envConfig,\n outputFormat: detectOutputFormat(opts.outputFormat),\n jq: opts.jq,\n verbose: opts.verbose ?? false,\n allowWrite: opts.allowWrite ?? false,\n credentialsManager,\n profile,\n };\n}\n\n/** Create an authenticated context for the public CLI. Tries env var, then cached token. */\nexport async function createPublicAuthenticatedContext(\n opts: PublicGlobalOptions\n): Promise<AuthenticatedContext> {\n const ctx = createPublicContext(opts);\n\n // Credential-broker mode takes precedence: the scoped token lives in the root\n // daemon, not the env, so route through the loopback broker with no auth header.\n // `gr.ts` (the `gr` entry point) uses THIS function, so the code-interpreter\n // sandbox reaches the API through here — without this check the sandbox CLI\n // throws AuthRequiredError because the broker deliberately strips\n // GRAVITY_RAIL_API_KEY from `.gr-env`. Returns null outside the sandbox, so\n // standalone/public CLI behavior is unchanged.\n const brokerCtx = tryBrokerContext(ctx);\n if (brokerCtx) return brokerCtx;\n\n const auth = await resolveNonInteractiveAuth({\n env: ctx.env,\n envConfig: ctx.envConfig,\n credentialsManager: ctx.credentialsManager,\n profile: ctx.profile,\n });\n if (auth) return contextWithToken(ctx, auth);\n\n throw new AuthRequiredError();\n}\n","/**\n * CLI handler for organization-level authentication challenges (GRA-6994/6995).\n *\n * When a workspace API call returns a 401 with WWW-Authenticate: Bearer realm=\"org\",\n * the SDK calls this handler. The CLI satisfies the challenge, in order:\n *\n * 1. Cached org session — a `gr_sess_` captured on a prior invocation and stored\n * under the profile. Replayed as `X-Org-Session`; no browser.\n * 2. Non-SSO direct join — `POST /o/{org}/join` with the account bearer token,\n * reading the org session from the Set-Cookie response (orgs that allow\n * internal auth). Result is cached like (1).\n * 3. SSO browser step-up (loopback callback, RFC 8252) — open the org SSO URL in\n * the browser with a `return_to` pointing at the `/cli/org-auth` bridge page,\n * which POSTs the freshly minted `gr_sess_` back to a one-time `127.0.0.1`\n * listener the CLI runs. Captured session is cached like (1). Interactive\n * (profile) contexts only.\n * 4. Headless / non-interactive — throw a clear hint (use `gr login` or an API key).\n */\n\nimport { createServer, type IncomingMessage, type ServerResponse } from 'http';\nimport { execFile } from 'child_process';\nimport { randomBytes } from 'crypto';\nimport type { AddressInfo } from 'net';\nimport type { GravityRailClient } from '@gravity-rail/sdk';\nimport type { OrgAuthInfo } from '@gravity-rail/sdk';\nimport type { CredentialsManager } from '../cli-utils';\nimport { stderr } from './output';\n\nconst ORG_AUTH_TIMEOUT_MS = 5 * 60 * 1000;\n\n/**\n * Cache captured SSO sessions conservatively under the server's 7-day org\n * session TTL (`ORG_SCOPED_SESSION_TTL_SECONDS`) so a cached session is\n * refreshed by a fresh step-up before it can 401 mid-command.\n */\nconst ORG_SESSION_CACHE_TTL_MS = 6.5 * 24 * 60 * 60 * 1000;\n\n/** Bridge page path on the frontend host that relays the org session to loopback. */\nconst CLI_ORG_AUTH_BRIDGE_PATH = '/cli/org-auth';\n\n/** Canonical UUID shape for the org id carried in the 401 challenge. */\nconst ORG_UUID_RE = /^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/i;\n\n/**\n * Context the org-auth handler needs to cache sessions and decide whether an\n * interactive browser step-up is permitted.\n */\nexport interface OrgAuthContext {\n /** Present for profile (login) contexts; absent for API-key / broker. */\n credentialsManager?: CredentialsManager;\n env: string;\n profile?: string;\n /** Configured frontend origin — the exact host the org SSO URL must live on. */\n frontendUrl?: string;\n /**\n * Whether a browser step-up may be launched. False for non-interactive\n * contexts (code-interpreter broker, CI) — those get the headless hint.\n */\n interactive: boolean;\n}\n\n/** Parse an org session credential from Set-Cookie header strings. */\nfunction extractOrgSessionFromSetCookies(\n setCookieValues: string[],\n preferredCookieName: string\n): string | undefined {\n let fallback: string | undefined;\n\n for (const value of setCookieValues) {\n const nameValue = value.split(';')[0]?.trim() ?? '';\n const eqIdx = nameValue.indexOf('=');\n if (eqIdx === -1) continue;\n\n const name = nameValue.slice(0, eqIdx).trim();\n const credentialValue = nameValue.slice(eqIdx + 1).trim() || undefined;\n if (!credentialValue) continue;\n\n if (name === preferredCookieName) return credentialValue;\n // Prefer opaque orgSession... cookies. Legacy orgToken... JWE cookies are\n // accepted only as a compatibility fallback during the cutover.\n if (!fallback && (name.startsWith('orgToken') || name.startsWith('orgSession'))) {\n fallback = credentialValue;\n }\n }\n\n return fallback;\n}\n\n/**\n * Attempt to satisfy an org auth challenge via the direct join endpoint.\n * Returns the org session credential on success, null when SSO is required.\n * Throws on unexpected network / server errors.\n */\nasync function tryDirectJoin(\n apiUrl: string,\n accessToken: string,\n orgAuthInfo: OrgAuthInfo\n): Promise<string | null> {\n const response = await fetch(`${apiUrl}/api/v2/o/${orgAuthInfo.orgUuid}/join`, {\n method: 'POST',\n headers: {\n 'Content-Type': 'application/json',\n Authorization: `Bearer ${accessToken}`,\n },\n body: '{}',\n });\n\n if (response.status === 400) {\n // Org requires SSO — direct join is not permitted for this account\n return null;\n }\n\n if (!response.ok) {\n // Don't include the response body — the backend currently returns safe\n // JSON, but a future change could put PHI or other sensitive data there.\n // Status code is sufficient to disambiguate the failure mode.\n throw new Error(`Org join failed (HTTP ${response.status})`);\n }\n\n // Read Set-Cookie headers to extract the org session value.\n // Node ≥18 exposes getSetCookie() on Headers; fall back to get() for older runtimes.\n const rawHeaders = response.headers as Headers & {\n getSetCookie?: () => string[];\n };\n const setCookies: string[] =\n rawHeaders.getSetCookie?.() ??\n (rawHeaders.get('set-cookie') ? [rawHeaders.get('set-cookie')!] : []);\n\n if (setCookies.length === 0) {\n throw new Error('Org join succeeded but no Set-Cookie header returned');\n }\n\n const orgSession = extractOrgSessionFromSetCookies(setCookies, orgAuthInfo.cookieName);\n if (!orgSession) {\n throw new Error('Org join succeeded but org session cookie not found in Set-Cookie');\n }\n\n return orgSession;\n}\n\n/**\n * Validate that an auth URL is safe to hand to the OS URL opener.\n *\n * `open` / `xdg-open` / `cmd.exe start` will follow any URI scheme the OS\n * registers — including `file://`, `javascript:`, and custom app handlers —\n * so a compromised/MITMed server returning an attacker-controlled `authUrl`\n * could trigger arbitrary URI execution. Restrict to http(s) and require\n * the same parent domain as the configured API host (e.g. SSO login on\n * `app.gravityrail.com` is allowed when the API is `api.gravityrail.com`,\n * but `attacker.example` against `api.gravityrail.com` is rejected).\n *\n * \"Same parent domain\" is a last-2-labels match. This is a heuristic — it\n * does not consult the Public Suffix List, so `foo.co.uk` and `bar.co.uk`\n * would falsely match — but Gravity Rail's auth hosts do not live under\n * those ccTLDs. The auth host is always the configured frontend host\n * (backend `build_org_auth_url` uses `SYSTEM_CONFIG.frontend_url`), so we\n * match it EXACTLY against the known API + frontend hosts rather than any\n * subdomain heuristic — a last-2-labels match would admit\n * `evil.gravityrail.com`. Both `apiUrl` and `frontendUrl` are trust anchors\n * derived from the CLI's own env config, not from the server response.\n */\nfunction isAllowedAuthUrl(url: string, apiUrl: string, frontendUrl?: string): boolean {\n try {\n const parsed = new URL(url);\n if (parsed.protocol !== 'https:' && parsed.protocol !== 'http:') return false;\n const allowedHosts = [apiUrl, frontendUrl]\n .filter((u): u is string => Boolean(u))\n .map((u) => {\n try {\n return new URL(u).hostname;\n } catch {\n return undefined;\n }\n })\n .filter((h): h is string => Boolean(h));\n return allowedHosts.includes(parsed.hostname);\n } catch {\n return false;\n }\n}\n\n/** Open a URL in the system browser (cross-platform). */\nfunction openBrowser(url: string): void {\n let command: string;\n let args: string[];\n\n if (process.platform === 'darwin') {\n command = 'open';\n args = [url];\n } else if (process.platform === 'win32') {\n command = 'cmd.exe';\n args = ['/c', 'start', '', url];\n } else {\n command = 'xdg-open';\n args = [url];\n }\n\n execFile(command, args, (_err) => {\n // Failure is non-fatal — the URL is printed to stderr so the user can open it manually.\n });\n}\n\n/**\n * Non-interactive when there is no way to complete a browser step-up: an\n * explicit opt-out, or a Linux session with no display server. macOS/Windows\n * always have a windowing system available to `open`/`start`.\n */\nfunction isHeadless(): boolean {\n if (process.env.GRAVITY_RAIL_NO_BROWSER) return true;\n if (process.platform === 'linux') {\n return !process.env.DISPLAY && !process.env.WAYLAND_DISPLAY;\n }\n return false;\n}\n\ninterface OrgSessionCapture {\n /** Resolves with the ephemeral bound loopback port once the server is listening. */\n ready: Promise<number>;\n /** Resolves with the captured `gr_sess_` once the bridge POSTs it. */\n session: Promise<string>;\n close: () => void;\n}\n\n/**\n * Start a one-time `127.0.0.1` listener that the browser bridge page POSTs the\n * org session to. Bound to loopback only (never `0.0.0.0`), ephemeral port,\n * state-nonce bound. Responds to the bridge's CORS preflight (including\n * Private Network Access) so a secure-context page on the app origin can reach\n * it. Resolves on the first POST whose `state` + `org_uuid` match.\n */\nexport function startOrgSessionCapture(\n expectedState: string,\n expectedOrgUuid: string,\n allowedOrigin: string\n): OrgSessionCapture {\n let resolveSession!: (value: string) => void;\n let rejectSession!: (reason: Error) => void;\n const session = new Promise<string>((resolve, reject) => {\n resolveSession = resolve;\n rejectSession = reject;\n });\n\n const applyCors = (req: IncomingMessage, res: ServerResponse): void => {\n // Allow only the expected app origin, and emit the trusted CONSTANT (never\n // the request-supplied Origin) so no attacker-controlled value reaches the\n // Access-Control-Allow-Origin header; any other origin gets no header and\n // the browser blocks it.\n if (req.headers.origin && req.headers.origin === allowedOrigin) {\n res.setHeader('Access-Control-Allow-Origin', allowedOrigin);\n res.setHeader('Vary', 'Origin');\n }\n res.setHeader('Access-Control-Allow-Methods', 'POST, OPTIONS');\n res.setHeader('Access-Control-Allow-Headers', 'Content-Type');\n };\n\n const server = createServer((req, res) => {\n applyCors(req, res);\n\n if (req.method === 'OPTIONS') {\n // Chrome Private Network Access: an HTTPS page reaching a loopback\n // address must have the PREFLIGHT acknowledge the private-network\n // access (this header is only meaningful on the preflight).\n res.setHeader('Access-Control-Allow-Private-Network', 'true');\n res.writeHead(204);\n res.end();\n return;\n }\n if (req.method !== 'POST') {\n res.writeHead(405);\n res.end();\n return;\n }\n\n let body = '';\n let tooLarge = false;\n req.on('data', (chunk) => {\n body += chunk;\n // Cap the body — a valid payload is a few hundred bytes.\n if (body.length > 16 * 1024) {\n tooLarge = true;\n req.destroy();\n }\n });\n req.on('end', () => {\n if (tooLarge) return;\n let capturedSession: string | undefined;\n try {\n const payload = JSON.parse(body) as {\n org_session?: unknown;\n org_uuid?: unknown;\n state?: unknown;\n };\n if (\n typeof payload.org_session === 'string' &&\n payload.org_session.length > 0 &&\n payload.state === expectedState &&\n payload.org_uuid === expectedOrgUuid\n ) {\n capturedSession = payload.org_session;\n }\n } catch {\n // fall through to 400\n }\n\n if (capturedSession) {\n res.writeHead(200, { 'Content-Type': 'application/json' });\n res.end('{\"ok\":true}');\n resolveSession(capturedSession);\n } else {\n res.writeHead(400, { 'Content-Type': 'application/json' });\n res.end('{\"ok\":false}');\n }\n });\n });\n\n let resolveReady!: (port: number) => void;\n let rejectReady!: (reason: Error) => void;\n const ready = new Promise<number>((resolve, reject) => {\n resolveReady = resolve;\n rejectReady = reject;\n });\n\n server.on('error', (err) => {\n rejectReady(err);\n rejectSession(err);\n });\n server.listen(0, '127.0.0.1', () => {\n // Inside the 'listening' callback address() is always the bound AddressInfo.\n resolveReady((server.address() as AddressInfo).port);\n });\n\n const timeout = setTimeout(() => {\n rejectSession(\n new Error(\n 'Organization authentication timed out.\\n' +\n 'Complete sign-in in the browser, then re-run the command.'\n )\n );\n }, ORG_AUTH_TIMEOUT_MS);\n timeout.unref();\n\n // Idempotent — the caller's finally and any test both call close(); a second\n // server.close() would otherwise error on an already-closed server.\n let closed = false;\n const close = (): void => {\n if (closed) return;\n closed = true;\n clearTimeout(timeout);\n server.close();\n };\n\n return { ready, session, close };\n}\n\n/** Build the browser URL: the org SSO auth URL with a return_to to the bridge. */\nexport function buildStepUpUrl(\n authUrl: string,\n orgUuid: string,\n port: number,\n state: string\n): string {\n const url = new URL(authUrl);\n // Encode the inner bridge query with URLSearchParams so org/port/state can't\n // break out of their params, then set the whole relative return_to (the\n // callback sanitizes it relative-only — open-redirect guard — and\n // URLSearchParams.set percent-encodes the outer value).\n const bridgeQuery = new URLSearchParams({ org: orgUuid, port: String(port), state });\n url.searchParams.set('return_to', `${CLI_ORG_AUTH_BRIDGE_PATH}?${bridgeQuery.toString()}`);\n return url.toString();\n}\n\n/** Randomised state nonce binding the browser flow to this CLI process. */\nfunction newStateNonce(): string {\n return randomBytes(16).toString('hex');\n}\n\n/**\n * Complete an SSO org challenge via the browser + loopback bridge.\n * Returns the captured `gr_sess_` org session.\n */\nasync function stepUpViaBrowser(orgAuthInfo: OrgAuthInfo): Promise<string> {\n // Precondition: the caller has already validated authUrl via isAllowedAuthUrl.\n const state = newStateNonce();\n const allowedOrigin = new URL(orgAuthInfo.authUrl).origin;\n const capture = startOrgSessionCapture(state, orgAuthInfo.orgUuid, allowedOrigin);\n\n try {\n const port = await capture.ready;\n const stepUpUrl = buildStepUpUrl(orgAuthInfo.authUrl, orgAuthInfo.orgUuid, port, state);\n stderr(`\\nThis workspace requires organization SSO authentication.`);\n stderr(`Opening browser to complete sign-in...`);\n stderr(` ${stepUpUrl}\\n`);\n stderr(`If the browser does not open, visit the URL above manually.`);\n openBrowser(stepUpUrl);\n return await capture.session;\n } finally {\n capture.close();\n }\n}\n\n/**\n * Register a CLI org-auth handler on the given client.\n *\n * See the module docstring for the resolution order (cache → non-SSO join →\n * SSO browser step-up → headless hint). Captured sessions are cached under the\n * profile (when a credentials manager is provided) and set on the client via\n * `setOrgSession()` so the SDK retries with `X-Org-Session` after the handler\n * resolves (Node.js has no document.cookie).\n */\nexport function registerOrgAuthHandler(\n apiClient: GravityRailClient,\n apiUrl: string,\n accessToken: string,\n orgAuthCtx?: OrgAuthContext\n): void {\n apiClient.setOrgAuthHandler(async (orgAuthInfo: OrgAuthInfo): Promise<void> => {\n const orgUuid = orgAuthInfo.orgUuid;\n // The org id is server-supplied (parsed from the challenge header). Reject\n // anything that is not a canonical UUID before it flows into a join URL\n // path or the bridge return_to query.\n if (!ORG_UUID_RE.test(orgUuid)) {\n throw new Error('Invalid organization id in auth challenge');\n }\n const cm = orgAuthCtx?.credentialsManager;\n\n // Persist a freshly obtained session under the profile and set it on the\n // client for the SDK's post-handler retry.\n const adopt = (session: string): void => {\n if (cm && orgAuthCtx) {\n const expiresAt = new Date(Date.now() + ORG_SESSION_CACHE_TTL_MS).toISOString();\n cm.setOrgSession(orgAuthCtx.env, orgAuthCtx.profile, orgUuid, session, expiresAt);\n }\n apiClient.setOrgSession(session, orgUuid);\n };\n\n // 1. Cached org session — no browser.\n if (cm && orgAuthCtx) {\n const cached = cm.getOrgSession(orgAuthCtx.env, orgAuthCtx.profile, orgUuid);\n if (cached) {\n apiClient.setOrgSession(cached, orgUuid);\n return;\n }\n }\n\n // 2. Non-SSO direct join.\n try {\n const orgSession = await tryDirectJoin(apiUrl, accessToken, orgAuthInfo);\n if (orgSession !== null) {\n adopt(orgSession);\n return;\n }\n } catch (err) {\n const msg = err instanceof Error ? err.message : String(err);\n stderr(`Warning: org direct-join failed (${msg}); trying browser sign-in`);\n }\n\n // 3./4. SSO org — browser step-up when interactive, else the headless hint.\n if (!orgAuthCtx?.interactive || isHeadless()) {\n throw new Error(\n 'This workspace’s organization requires SSO sign-in, which needs a browser.\\n' +\n 'Run an interactive `gr` command on a machine with a browser to sign in once ' +\n '(the session is then cached), or use an API key for non-interactive use:\\n' +\n ' export GRAVITY_RAIL_API_KEY=<key> (see: gr api-keys)'\n );\n }\n\n // Validate the auth URL against the exact configured API + frontend hosts\n // before opening it, so a hostile/MITM'd URL can't pivot the OS opener.\n if (!isAllowedAuthUrl(orgAuthInfo.authUrl, apiUrl, orgAuthCtx.frontendUrl)) {\n throw new Error(\n `Refusing to open organization auth URL: host does not match the configured API/frontend host. ` +\n `Re-run with the expected --api-url, or contact support.`\n );\n }\n\n const session = await stepUpViaBrowser(orgAuthInfo);\n adopt(session);\n });\n}\n","/**\n * Audit headers for API calls made from a code-interpreter sandbox.\n *\n * The private-ALB DNS pin that used to live here is gone: it was driven by\n * `GRAVITY_RAIL_API_IP`, which only the sandbox `.gr-env` ever set, and sandbox\n * clients no longer dial the API host at all — every call goes to the loopback\n * credential broker, and the root daemon applies the pin on the far side.\n */\n\nexport interface SandboxAuditHeaders {\n chatId?: number;\n sessionId?: string;\n toolCallId?: string;\n}\n\ntype ToolCallGlobal = typeof globalThis & {\n __GRAVITY_RAIL_TOOL_CALL_ID__?: string;\n};\n\ntype WebRequest = Parameters<typeof fetch>[0];\ntype WebRequestInit = Parameters<typeof fetch>[1];\n\nexport function withAuditHeaders(\n fetchFn: typeof fetch,\n headers: SandboxAuditHeaders\n): typeof fetch {\n const { chatId, sessionId, toolCallId } = headers;\n\n return async (input: WebRequest, init?: WebRequestInit): Promise<Response> => {\n const reqHeaders = new Headers(init?.headers);\n const dynamicToolCallId =\n (globalThis as ToolCallGlobal).__GRAVITY_RAIL_TOOL_CALL_ID__ ||\n (typeof process !== 'undefined' ? process.env.GRAVITY_RAIL_TOOL_CALL_ID : undefined);\n if (chatId !== undefined) {\n reqHeaders.set('X-GR-Chat-Id', String(chatId));\n }\n if (sessionId) {\n reqHeaders.set('X-GR-Session-Id', sessionId);\n }\n if (dynamicToolCallId || toolCallId) {\n reqHeaders.set('X-GR-Tool-Call-Id', dynamicToolCallId || toolCallId || '');\n }\n return fetchFn(input, { ...init, headers: reqHeaders });\n };\n}\n\n/**\n * Build fetch for CLI API calls, adding the sandbox correlation headers when\n * the GRAVITY_RAIL_* session vars are present.\n *\n * Outside a sandbox those vars are unset and this is plain `fetch` with a\n * pass-through header copy. Inside one, auth is added by the loopback broker,\n * never here.\n */\nexport function createSandboxFetchFromEnv(): typeof fetch {\n const env: Record<string, string | undefined> =\n typeof process !== 'undefined' ? process.env : {};\n const chatIdRaw = env.GRAVITY_RAIL_CHAT_ID;\n const chatId = chatIdRaw ? Number(chatIdRaw) : undefined;\n return withAuditHeaders(fetch, {\n chatId: chatId !== undefined && Number.isFinite(chatId) ? chatId : undefined,\n sessionId: env.GRAVITY_RAIL_SESSION_ID,\n toolCallId: env.GRAVITY_RAIL_TOOL_CALL_ID,\n });\n}\n","/**\n * Concierge API client — direct HTTP calls to the global concierge endpoints.\n *\n * The concierge is account-level (no workspace), so these bypass the ApiClient\n * which is workspace-oriented.\n */\n\nimport type { AuthenticatedContext } from './context';\n\nexport interface ConciergeChat {\n id: number;\n uuid: string;\n chatType: string;\n title: string | null;\n threadId: string;\n createdAt: string;\n updatedAt: string;\n}\n\nexport interface ConciergeMessage {\n id: string;\n role: string;\n content: string;\n createdAt: string | null;\n toolCalls: any[] | null;\n toolCallId: string | null;\n}\n\nfunction baseUrl(ctx: AuthenticatedContext): string {\n return `${ctx.envConfig.apiUrl}/api/v2/concierge`;\n}\n\nfunction authHeaders(ctx: AuthenticatedContext): Record<string, string> {\n return {\n Authorization: `Bearer ${ctx.accessToken}`,\n 'Content-Type': 'application/json',\n };\n}\n\n/**\n * Map GlobalChatResponse wire → local shape.\n *\n * App fields are camelCase only (we own both ends — no snake dual-read).\n * `tool_calls` / `tool_call_id` on messages stay snake_case intentionally\n * (OpenAI message protocol on ConciergeMessageResponse). (#19305)\n */\nfunction toCamelChat(raw: any): ConciergeChat {\n return {\n id: raw.id,\n uuid: raw.uuid,\n chatType: raw.chatType,\n title: raw.title,\n threadId: raw.threadId,\n createdAt: raw.createdAt,\n updatedAt: raw.updatedAt,\n };\n}\n\nfunction toCamelMessage(raw: any): ConciergeMessage {\n return {\n id: raw.id,\n role: raw.role,\n content: raw.content ?? '',\n createdAt: raw.createdAt ?? null,\n // Protocol-exempt snake_case on wire (see ConciergeMessageResponse)\n toolCalls: raw.tool_calls ?? null,\n toolCallId: raw.tool_call_id ?? null,\n };\n}\n\nexport async function listConciergeChats(ctx: AuthenticatedContext): Promise<ConciergeChat[]> {\n const res = await fetch(`${baseUrl(ctx)}/chats`, { headers: authHeaders(ctx) });\n if (!res.ok) throw new Error(`Failed to list concierge chats: ${res.status}`);\n const data = await res.json();\n return (data as any[]).map(toCamelChat);\n}\n\nexport async function createConciergeChat(\n ctx: AuthenticatedContext,\n title?: string\n): Promise<ConciergeChat> {\n const res = await fetch(`${baseUrl(ctx)}/chats`, {\n method: 'POST',\n headers: authHeaders(ctx),\n body: JSON.stringify({ title: title ?? null }),\n });\n if (!res.ok) throw new Error(`Failed to create concierge chat: ${res.status}`);\n return toCamelChat(await res.json());\n}\n\nexport async function getConciergeChat(\n ctx: AuthenticatedContext,\n chatId: number\n): Promise<ConciergeChat> {\n const res = await fetch(`${baseUrl(ctx)}/chats/${chatId}`, { headers: authHeaders(ctx) });\n if (!res.ok) throw new Error(`Failed to get concierge chat ${chatId}: ${res.status}`);\n return toCamelChat(await res.json());\n}\n\nexport interface ConciergeCallResult {\n callSid: string;\n startedAt: string;\n}\n\nexport interface ConciergeSmsResult {\n messageSid: string;\n conversationId: string;\n}\n\nexport async function originateConciergeCall(\n ctx: AuthenticatedContext,\n kind = 'concierge_setup',\n outboundMessage?: string,\n clientSurface?: string\n): Promise<ConciergeCallResult> {\n const body: Record<string, string | undefined> = { kind };\n if (outboundMessage) body.outbound_message = outboundMessage;\n if (clientSurface) body.client_surface = clientSurface;\n const res = await fetch(`${baseUrl(ctx)}/calls`, {\n method: 'POST',\n headers: authHeaders(ctx),\n body: JSON.stringify(body),\n });\n if (res.status === 412) {\n throw new Error('Your account phone is not verified. Run `gr account verify-phone` first.');\n }\n if (!res.ok) {\n const detail = await res.text();\n throw new Error(`Failed to start concierge call: ${res.status} ${detail}`);\n }\n return (await res.json()) as ConciergeCallResult;\n}\n\nexport async function originateConciergeSms(\n ctx: AuthenticatedContext,\n kind = 'concierge_setup'\n): Promise<ConciergeSmsResult> {\n const res = await fetch(`${baseUrl(ctx)}/sms`, {\n method: 'POST',\n headers: authHeaders(ctx),\n body: JSON.stringify({ kind }),\n });\n if (res.status === 412) {\n throw new Error('Your account phone is not verified. Run `gr account verify-phone` first.');\n }\n if (!res.ok) {\n const detail = await res.text();\n throw new Error(`Failed to start concierge SMS: ${res.status} ${detail}`);\n }\n return (await res.json()) as ConciergeSmsResult;\n}\n\nexport async function startAccountPhoneVerify(\n ctx: AuthenticatedContext,\n phone: string\n): Promise<void> {\n const res = await fetch(`${ctx.envConfig.apiUrl}/api/v2/account/phone/verify/start`, {\n method: 'POST',\n headers: authHeaders(ctx),\n body: JSON.stringify({ phone }),\n });\n if (!res.ok) {\n const detail = await res.text();\n throw new Error(`Failed to send verification code: ${res.status} ${detail}`);\n }\n}\n\nexport async function confirmAccountPhoneVerify(\n ctx: AuthenticatedContext,\n code: string\n): Promise<void> {\n const res = await fetch(`${ctx.envConfig.apiUrl}/api/v2/account/phone/verify/confirm`, {\n method: 'POST',\n headers: authHeaders(ctx),\n body: JSON.stringify({ code }),\n });\n if (!res.ok) {\n const detail = await res.text();\n throw new Error(`Failed to confirm verification code: ${res.status} ${detail}`);\n }\n}\n\nexport async function getConciergeChatMessages(\n ctx: AuthenticatedContext,\n chatId: number\n): Promise<ConciergeMessage[]> {\n const res = await fetch(`${baseUrl(ctx)}/chats/${chatId}/messages`, {\n headers: authHeaders(ctx),\n });\n if (!res.ok)\n throw new Error(`Failed to get concierge messages for chat ${chatId}: ${res.status}`);\n const data = await res.json();\n return (data as any[]).map(toCamelMessage);\n}\n"],"mappings":"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","names":["session"]}