@gravity-rail/cli 0.18.1 → 0.22.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.18.1",
3
+ "version": "0.22.0",
4
4
  "description": "Gravity Rail CLI — manage workspaces from the command line",
5
5
  "type": "module",
6
6
  "bin": {
@@ -47,14 +47,14 @@
47
47
  "test:ci": "jest --forceExit --passWithNoTests --coverage --coverageReporters=json-summary --coverageReporters=text-summary"
48
48
  },
49
49
  "dependencies": {
50
- "@gravity-rail/sdk": "^0.18.1"
50
+ "@gravity-rail/sdk": "^0.22.0"
51
51
  },
52
52
  "devDependencies": {
53
53
  "@gravity-rail/sandbox": "workspace:*",
54
54
  "@types/jest": "^30.0.0",
55
- "@types/node": "^26.1.2",
55
+ "@types/node": "^26.2.0",
56
56
  "jest": "^30.4.2",
57
- "ts-jest": "^29.4.6",
57
+ "ts-jest": "29.4.9",
58
58
  "tsup": "^8.3.5",
59
59
  "typescript": "^6.0.3",
60
60
  "undici": "^6.28.0"
@@ -1 +0,0 @@
1
- {"version":3,"sources":["../src/cli-utils/config.ts","../src/cli-utils/auth.ts","../src/cli-utils/credentials-manager.ts","../src/cli-utils/ui.ts","../src/cli-utils/agui.ts"],"sourcesContent":["/**\n * CLI configuration for remote environments\n */\n\nimport { existsSync, readFileSync } from 'fs';\nimport { dirname, join, resolve } from 'path';\n\nexport interface EnvironmentConfig {\n apiUrl: string;\n frontendUrl: string;\n}\n\nexport const ENVIRONMENTS: Record<string, EnvironmentConfig> = {\n dev: {\n apiUrl: 'https://api.gravityrail.test:5054',\n frontendUrl: 'https://app.gravityrail.test:3000',\n },\n prod: {\n apiUrl: 'https://api.gravityrail.com',\n frontendUrl: 'https://app.gravityrail.com',\n },\n staging: {\n apiUrl: 'https://api.gr-staging.com',\n frontendUrl: 'https://app.gr-staging.com',\n },\n};\n\nexport const CALLBACK_PORT = 31337;\nexport const CALLBACK_PATH = '/oauth/callback';\nexport const REDIRECT_URI = `http://localhost:${CALLBACK_PORT}${CALLBACK_PATH}`;\n\n/**\n * Detect worktree port overrides from docker-compose.override.yml.\n * The override file is generated by worktree-setup.sh and contains lines like:\n * - '5250:5050' (API)\n * - '3200:3000' (Frontend)\n * We extract the host port for the default internal ports (5050, 3000).\n */\nfunction detectWorktreePorts(): { apiPort?: number; frontendPort?: number } {\n // Walk up from cwd to find docker-compose.override.yml\n let dir = resolve(process.cwd());\n let overridePath: string | undefined;\n while (true) {\n const candidate = join(dir, 'docker-compose.override.yml');\n\n if (existsSync(candidate)) {\n overridePath = candidate;\n break;\n }\n const parent = dirname(dir);\n if (parent === dir) break; // reached filesystem root\n dir = parent;\n }\n if (!overridePath) return {};\n\n let content: string;\n try {\n content = readFileSync(overridePath, 'utf-8');\n } catch {\n return {};\n }\n\n // Only use this if it's a worktree override (generated by worktree-setup.sh)\n if (!content.includes('worktree-setup.sh')) return {};\n\n // Match port mappings: - 'HOST:CONTAINER'\n // Prefer api-nginx HTTPS (container 443, or legacy 5054) — never the raw\n // FastAPI container 5050 (plain HTTP; yarn gr uses https://api.gravityrail.test).\n let apiPort: number | undefined;\n let frontendPort: number | undefined;\n for (const match of content.matchAll(/-\\s*'(\\d+):(\\d+)'/g)) {\n const host = parseInt(match[1]!, 10);\n const container = parseInt(match[2]!, 10);\n if (container === 443 || container === 5054) apiPort = host;\n if (container === 3000) frontendPort = host;\n }\n return { apiPort, frontendPort };\n}\n\nexport function getEnvironmentConfig(env: string): EnvironmentConfig {\n // Handle dev-cloud environments: --env dev-cloud:NAMESPACE\n if (env.startsWith('dev-cloud:')) {\n const namespace = env.slice('dev-cloud:'.length);\n if (!namespace) {\n throw new Error('dev-cloud environment requires a namespace: --env dev-cloud:NAMESPACE');\n }\n return {\n apiUrl: `https://${namespace}-api.gravityrail-dev.com`,\n frontendUrl: `https://${namespace}-app.gravityrail-dev.com`,\n };\n }\n\n const config = ENVIRONMENTS[env];\n if (!config) {\n throw new Error(\n `Invalid environment: ${env}. Use 'dev', 'staging', 'prod', or 'dev-cloud:NAMESPACE'.`\n );\n }\n\n // Allow env var overrides (used by code interpreter sandboxes)\n const apiUrl = process.env.GRAVITY_RAIL_API_URL || config.apiUrl;\n const frontendUrl = process.env.GRAVITY_RAIL_FRONTEND_URL || config.frontendUrl;\n if (apiUrl !== config.apiUrl || frontendUrl !== config.frontendUrl) {\n return { apiUrl, frontendUrl };\n }\n\n // For dev, detect worktree port overrides\n if (env === 'dev') {\n const ports = detectWorktreePorts();\n if (ports.apiPort || ports.frontendPort) {\n return {\n apiUrl: ports.apiPort ? `https://api.gravityrail.test:${ports.apiPort}` : config.apiUrl,\n frontendUrl: ports.frontendPort\n ? `https://app.gravityrail.test:${ports.frontendPort}`\n : config.frontendUrl,\n };\n }\n }\n\n return config;\n}\n","/**\n * CLI OAuth2 authentication utilities\n *\n * Provides OAuth2 with PKCE flow for CLI tools, including:\n * - Credential caching (per environment + named profile)\n * - Dynamic client registration\n * - Token refresh\n * - Browser-based authorization\n *\n * Credential persistence lives in `./credentials-manager` (multi-account profiles).\n */\n\nimport { createServer } from 'http';\nimport { createHash, randomBytes } from 'crypto';\nimport { exec } from 'child_process';\nimport { EnvironmentConfig, CALLBACK_PORT, CALLBACK_PATH, REDIRECT_URI } from './config';\nimport { CredentialsManager, type CLICredentials } from './credentials-manager';\n\nexport {\n CredentialsManager,\n DEFAULT_PROFILE,\n type CLICredentials,\n type ProfileSummary,\n} from './credentials-manager';\n\nexport interface AuthResult {\n accessToken: string;\n credentials?: CLICredentials;\n}\n\nfunction stderr(msg: string): void {\n process.stderr.write(msg + '\\n');\n}\n\n/**\n * Parse an OAuth error response body, checking the JSON `error` field first,\n * falling back to text matching.\n */\nfunction isOAuthError(body: string, errorCode: string): boolean {\n try {\n const parsed = JSON.parse(body);\n if (parsed.error === errorCode) return true;\n } catch {\n // Not JSON — fall through to text match\n }\n return body.includes(errorCode);\n}\n\n/**\n * Validate and extract fields from an OAuth token response.\n * Throws on malformed responses per RFC 6749 §5.1.\n */\nfunction validateTokenResponse(tokenData: Record<string, unknown>): {\n accessToken: string;\n refreshToken?: string;\n expiresIn: number;\n} {\n if (!tokenData.access_token || typeof tokenData.access_token !== 'string') {\n throw new Error('Token response missing access_token');\n }\n\n if (tokenData.token_type && String(tokenData.token_type).toLowerCase() !== 'bearer') {\n throw new Error(`Unsupported token type: ${tokenData.token_type}`);\n }\n\n let expiresIn = 86400; // default 24h\n if (tokenData.expires_in != null) {\n const raw = Number(tokenData.expires_in);\n if (!Number.isFinite(raw) || raw < 60 || raw > 31536000) {\n stderr(` Warning: unusual expires_in value (${tokenData.expires_in}), using default`);\n } else {\n expiresIn = raw;\n }\n }\n\n return {\n accessToken: tokenData.access_token,\n refreshToken:\n typeof tokenData.refresh_token === 'string' ? tokenData.refresh_token : undefined,\n expiresIn,\n };\n}\n\n/**\n * Generate PKCE code verifier and challenge\n */\nexport function generatePKCE(): { codeVerifier: string; codeChallenge: string } {\n const codeVerifier = randomBytes(64).toString('base64url').slice(0, 128);\n const codeChallenge = createHash('sha256').update(codeVerifier).digest('base64url');\n return { codeVerifier, codeChallenge };\n}\n\n/**\n * Open a URL in the default browser\n */\nexport function openBrowser(url: string): void {\n const platform = process.platform;\n let cmd: string;\n if (platform === 'darwin') {\n cmd = `open \"${url}\"`;\n } else if (platform === 'win32') {\n cmd = `start \"\" \"${url}\"`;\n } else {\n cmd = `xdg-open \"${url}\"`;\n }\n\n exec(cmd, (err) => {\n if (err) {\n stderr(' Could not open browser automatically.');\n }\n });\n}\n\n/**\n * Start a local HTTP server to receive the OAuth callback\n */\nexport function startCallbackServer(): Promise<{ code: string; state: string }> {\n return new Promise((resolve, reject) => {\n let authCode: string | null = null;\n let error: string | null = null;\n let receivedState: string | null = null;\n\n const server = createServer((req, res) => {\n const url = new URL(req.url!, `http://localhost:${CALLBACK_PORT}`);\n\n if (url.pathname !== CALLBACK_PATH) {\n res.writeHead(404);\n res.end('Not found');\n return;\n }\n\n if (url.searchParams.has('error')) {\n error = url.searchParams.get('error');\n const errorDesc = url.searchParams.get('error_description') || 'Unknown error';\n res.writeHead(200, { 'Content-Type': 'text/html' });\n res.end(`\n <html>\n <head><title>Authorization Failed</title></head>\n <body style=\"font-family: system-ui; text-align: center; padding: 50px;\">\n <h1 style=\"color: #dc2626;\">Authorization Failed</h1>\n <p>${errorDesc}</p>\n <p>You can close this window.</p>\n </body>\n </html>\n `);\n server.close();\n reject(new Error(`Authorization failed: ${error}`));\n } else if (url.searchParams.has('code')) {\n authCode = url.searchParams.get('code')!;\n receivedState = url.searchParams.get('state')!;\n res.writeHead(200, { 'Content-Type': 'text/html' });\n res.end(`\n <html>\n <head><title>Authorization Successful</title></head>\n <body style=\"font-family: system-ui; text-align: center; padding: 50px;\">\n <h1 style=\"color: #16a34a;\">Authorization Successful!</h1>\n <p>You can close this window and return to the terminal.</p>\n <script>setTimeout(() => window.close(), 2000);</script>\n </body>\n </html>\n `);\n server.close();\n resolve({ code: authCode, state: receivedState });\n } else {\n res.writeHead(400);\n res.end('Missing code parameter');\n }\n });\n\n server.listen(CALLBACK_PORT, 'localhost', () => {\n // Server started\n });\n\n // Timeout after 5 minutes (unref so it doesn't keep the process alive)\n const timeout = setTimeout(\n () => {\n if (!authCode && !error) {\n server.close();\n reject(new Error('Authorization timeout - no response received'));\n }\n },\n 5 * 60 * 1000\n );\n timeout.unref();\n });\n}\n\n/**\n * Register a new OAuth client dynamically\n */\nasync function dynamicClientRegistration(\n envConfig: EnvironmentConfig,\n clientName: string = 'Gravity CLI'\n): Promise<{ client_id: string; client_secret: string }> {\n stderr(' Registering OAuth client...');\n\n const registrationUrl = `${envConfig.apiUrl}/api/v2/oauth/register`;\n\n const registrationData = {\n client_name: clientName,\n redirect_uris: [REDIRECT_URI],\n grant_types: ['authorization_code', 'refresh_token'],\n response_types: ['code'],\n token_endpoint_auth_method: 'client_secret_basic',\n scope: 'workspace:admin',\n };\n\n const response = await fetch(registrationUrl, {\n method: 'POST',\n headers: { 'Content-Type': 'application/json' },\n body: JSON.stringify(registrationData),\n });\n\n if (!response.ok) {\n throw new Error(`Client registration failed: ${response.status} - ${await response.text()}`);\n }\n\n return (await response.json()) as { client_id: string; client_secret: string };\n}\n\nexport interface OAuthFlowOptions {\n env: string;\n envConfig: EnvironmentConfig;\n credentialsManager: CredentialsManager;\n clientName?: string;\n /** Named account profile to store tokens under (default: resolved current). */\n profile?: string;\n}\n\n/**\n * Perform the full OAuth2 browser-based flow with PKCE.\n *\n * This always opens the browser for authorization. It never returns a cached\n * token — that's the job of createAuthenticatedContext. The only thing reused\n * is the registered OAuth client ID (which is identity, not auth).\n */\nexport async function performOAuthFlow(options: OAuthFlowOptions): Promise<AuthResult> {\n const { env, envConfig, credentialsManager, clientName = 'Gravity CLI', profile } = options;\n const profileName = credentialsManager.resolveProfileName(profile, env);\n let hasRetried = false;\n\n while (true) {\n // Reuse registered client credentials if available, otherwise register\n let creds = credentialsManager.load(env, profileName);\n if (!creds || !creds.clientId || !creds.clientSecret) {\n const registration = await dynamicClientRegistration(envConfig, clientName);\n creds = {\n clientId: registration.client_id,\n clientSecret: registration.client_secret,\n };\n credentialsManager.save(env, creds, profileName);\n } else {\n stderr(' Using cached client credentials');\n }\n\n // Token-only (import-dev) profiles cannot start OAuth; re-register if needed.\n if (!creds.clientId || !creds.clientSecret) {\n throw new Error('OAuth client credentials missing after registration');\n }\n const clientId = creds.clientId;\n const clientSecret = creds.clientSecret;\n\n const { codeVerifier, codeChallenge } = generatePKCE();\n const state = randomBytes(32).toString('base64url');\n\n const authParams = new URLSearchParams({\n response_type: 'code',\n client_id: clientId,\n redirect_uri: REDIRECT_URI,\n scope: 'workspace:admin',\n state: state,\n code_challenge: codeChallenge,\n code_challenge_method: 'S256',\n });\n\n const authUrl = `${envConfig.apiUrl}/api/v2/oauth/authorize?${authParams}`;\n\n const callbackPromise = startCallbackServer();\n\n stderr('\\n Opening browser for authorization...');\n stderr(` Profile: ${profileName}`);\n stderr(` If browser doesn't open, visit:\\n ${authUrl}\\n`);\n openBrowser(authUrl);\n\n stderr(' Waiting for authorization (timeout: 5 minutes)...');\n let code: string;\n let receivedState: string;\n try {\n ({ code, state: receivedState } = await callbackPromise);\n } catch (err) {\n const msg = err instanceof Error ? err.message : String(err);\n if (!hasRetried && isOAuthError(msg, 'invalid_client')) {\n stderr(' Cached client credentials expired, re-registering...');\n credentialsManager.clear(env, profileName);\n hasRetried = true;\n continue;\n }\n throw err;\n }\n\n if (receivedState !== state) {\n throw new Error('State mismatch - possible CSRF attack');\n }\n\n stderr(' Authorization code received!');\n stderr(' Exchanging code for tokens...');\n\n const tokenUrl = `${envConfig.apiUrl}/api/v2/oauth/token`;\n const authHeader = Buffer.from(`${clientId}:${clientSecret}`).toString('base64');\n\n const tokenResponse = await fetch(tokenUrl, {\n method: 'POST',\n headers: {\n Authorization: `Basic ${authHeader}`,\n 'Content-Type': 'application/x-www-form-urlencoded',\n },\n body: new URLSearchParams({\n grant_type: 'authorization_code',\n code: code,\n redirect_uri: REDIRECT_URI,\n code_verifier: codeVerifier,\n }),\n });\n\n if (!tokenResponse.ok) {\n const body = await tokenResponse.text();\n if (!hasRetried && isOAuthError(body, 'invalid_client')) {\n stderr(' Cached client credentials expired, re-registering...');\n credentialsManager.clear(env, profileName);\n hasRetried = true;\n continue;\n }\n throw new Error(`Token exchange failed: ${tokenResponse.status} - ${body}`);\n }\n\n const tokenData = (await tokenResponse.json()) as Record<string, unknown>;\n const { accessToken, refreshToken, expiresIn } = validateTokenResponse(tokenData);\n\n creds.accessToken = accessToken;\n creds.refreshToken = refreshToken ?? creds.refreshToken;\n creds.expiresAt = new Date(Date.now() + expiresIn * 1000).toISOString();\n\n credentialsManager.save(env, creds, profileName);\n credentialsManager.setCurrentProfile(env, profileName);\n stderr(' Authentication successful!');\n\n return { accessToken, credentials: creds };\n }\n}\n\n/**\n * Refresh an access token using a stored refresh token.\n * Returns updated credentials on success, null on failure.\n * Clears only the named profile on failure (other accounts stay intact).\n */\nexport async function refreshAccessToken(\n envConfig: EnvironmentConfig,\n creds: CLICredentials,\n credentialsManager: CredentialsManager,\n env: string,\n profile?: string\n): Promise<CLICredentials | null> {\n if (!creds.refreshToken || !creds.clientId || !creds.clientSecret) {\n stderr(' Cannot refresh: missing credentials (re-login required)');\n return null;\n }\n\n const profileName = credentialsManager.resolveProfileName(profile, env);\n const tokenUrl = `${envConfig.apiUrl}/api/v2/oauth/token`;\n const authHeader = Buffer.from(`${creds.clientId}:${creds.clientSecret}`).toString('base64');\n\n try {\n const response = await fetch(tokenUrl, {\n method: 'POST',\n headers: {\n Authorization: `Basic ${authHeader}`,\n 'Content-Type': 'application/x-www-form-urlencoded',\n },\n body: new URLSearchParams({\n grant_type: 'refresh_token',\n refresh_token: creds.refreshToken,\n }),\n });\n\n if (!response.ok) {\n const body = await response.text();\n const isExpiredRefresh = isOAuthError(body, 'invalid_grant');\n if (isExpiredRefresh) {\n stderr(' Refresh token expired, re-login required');\n } else {\n stderr(` Token refresh failed (${response.status}), clearing credentials`);\n }\n credentialsManager.clear(env, profileName);\n return null;\n }\n\n const tokenData = (await response.json()) as Record<string, unknown>;\n const { accessToken, refreshToken, expiresIn } = validateTokenResponse(tokenData);\n\n const updated: CLICredentials = {\n ...creds,\n accessToken,\n refreshToken: refreshToken ?? creds.refreshToken,\n expiresAt: new Date(Date.now() + expiresIn * 1000).toISOString(),\n };\n\n credentialsManager.save(env, updated, profileName);\n return updated;\n } catch (err) {\n stderr(` Token refresh error: ${err instanceof Error ? err.message : 'unknown'}`);\n credentialsManager.clear(env, profileName);\n return null;\n }\n}\n","/**\n * CLI credential store with multi-account profile support.\n *\n * Store location: `~/.gr-cli/credentials-<env>.json` (mode 0600; dir mode 0700).\n * Format is versioned JSON with named profiles (aws-style). Flat single-credential\n * files from older CLI versions migrate to profile \"default\" on first read/write.\n *\n * Security notes (for operators / security review):\n * - Tokens and client secrets live only on the local filesystem under the user's home.\n * - Files are written mode 0600; the cache directory is created mode 0700.\n * - Profile and environment names are allowlist-validated with a\n * resolve()/relative() containment check so path traversal cannot escape `.gr-cli`.\n * - Callers must never log credential field values (accessToken, refreshToken, secrets).\n * - `GRAVITY_RAIL_API_KEY` is not persisted here; it remains process-env only and\n * overrides stored profiles for non-interactive automation.\n * - Dev profiles imported from `dev-realms.json` store bearer tokens only (no OAuth\n * client secret). They are local-dev conveniences and must never be committed.\n */\n\nimport {\n readFileSync,\n writeFileSync,\n existsSync,\n mkdirSync,\n chmodSync,\n unlinkSync,\n renameSync,\n} from 'fs';\nimport { join, resolve, relative, isAbsolute } from 'path';\n\nexport const DEFAULT_PROFILE = 'default';\n\n/**\n * Stored credentials for one named profile.\n *\n * OAuth logins have clientId/clientSecret (+ optional refresh).\n * Dev profiles imported from dev-realms.json are token-only (accessToken +\n * optional workspaceUuid) — no OAuth client registration.\n */\n/**\n * A cached org-scoped SSO session (`gr_sess_...`) obtained via browser step-up.\n * Replayed as the `X-Org-Session` header so subsequent invocations skip the\n * browser until the session expires (GRA-6995).\n */\nexport interface StoredOrgSession {\n session: string;\n /** ISO expiry; treated as a cache miss once passed. */\n expiresAt?: string;\n}\n\nexport interface CLICredentials {\n clientId?: string;\n clientSecret?: string;\n accessToken?: string;\n refreshToken?: string;\n expiresAt?: string;\n /** Default workspace UUID (workspace/member profiles from dev-realms). */\n workspaceUuid?: string;\n /**\n * Cached org-scoped SSO sessions keyed by organization UUID. Populated by the\n * org-auth step-up handler; independent of the account token's own expiry.\n */\n orgSessions?: Record<string, StoredOrgSession>;\n}\n\nexport interface ProfileSummary {\n name: string;\n current: boolean;\n hasAccessToken: boolean;\n /** ISO timestamp if known; never includes the token itself. */\n expiresAt?: string;\n /** Present when the profile pins a default workspace. */\n workspaceUuid?: string;\n}\n\ninterface CredentialStoreV2 {\n version: 2;\n currentProfile: string;\n profiles: Record<string, CLICredentials>;\n}\n\n/**\n * Manages CLI credentials storage (one file per environment, multi-profile).\n */\nexport class CredentialsManager {\n private cacheDir: string;\n private apiUrl?: string;\n\n constructor(rootDir: string, apiUrl?: string) {\n // `rootDir` is supplied only by CLI bootstrap (context.ts passes\n // os.homedir()) — the local user's own home directory, never remote or\n // request input — joined with the constant '.gr-cli'. FP (CWE-22).\n // bearer:disable javascript_lang_path_traversal\n // nosemgrep: javascript.lang.security.audit.path-traversal.path-join-resolve-traversal.path-join-resolve-traversal\n this.cacheDir = join(rootDir, '.gr-cli');\n this.apiUrl = apiUrl;\n }\n\n /**\n * Validate a profile name. Allows the legacy realm path form\n * `workspace/member` so `acme-demo/acme-admin` works as a profile name.\n * Rejects path traversal and absolute paths.\n */\n validateProfileName(profile: string): void {\n if (!profile) {\n throw new Error('Invalid profile name: (empty).');\n }\n if (profile.includes('..') || profile.startsWith('/') || profile.endsWith('/')) {\n throw new Error(\n `Invalid profile name: ${profile}. Do not use \"..\" or leading/trailing \"/\".`\n );\n }\n // Letters, digits, '_', '-', '.', and a single-level '/' for workspace/member.\n if (!/^[a-zA-Z0-9_.-]+(?:\\/[a-zA-Z0-9_.-]+)?$/.test(profile)) {\n throw new Error(\n `Invalid profile name: ${profile}. Use letters, digits, '_', '-', '.', ` +\n `or workspace/member form (one slash).`\n );\n }\n }\n\n /**\n * Resolve which profile to use for this invocation.\n * Precedence: explicit flag → GRAVITY_RAIL_PROFILE → stored current → \"default\".\n */\n resolveProfileName(explicit?: string | null, env?: string): string {\n if (explicit) {\n this.validateProfileName(explicit);\n return explicit;\n }\n const fromEnv = process.env.GRAVITY_RAIL_PROFILE;\n if (fromEnv) {\n this.validateProfileName(fromEnv);\n return fromEnv;\n }\n if (env) {\n return this.getCurrentProfile(env);\n }\n return DEFAULT_PROFILE;\n }\n\n getCurrentProfile(env: string): string {\n const parsed = this.readStore(env);\n if (!parsed) return DEFAULT_PROFILE;\n return parsed.store.currentProfile || DEFAULT_PROFILE;\n }\n\n setCurrentProfile(env: string, profile: string): void {\n this.validateProfileName(profile);\n const store = this.readStore(env)?.store ?? this.emptyStore(profile);\n if (!store.profiles[profile]) {\n throw new Error(\n `Profile \"${profile}\" has no stored credentials for ${env}. ` +\n `Run: gr auth login --name ${profile} (or gr auth import-dev for local tokens)`\n );\n }\n store.currentProfile = profile;\n this.writeStore(env, store);\n }\n\n listProfiles(env: string): ProfileSummary[] {\n const parsed = this.readStore(env);\n if (!parsed) return [];\n const store = parsed.store;\n const current = store.currentProfile || DEFAULT_PROFILE;\n return Object.keys(store.profiles)\n .sort()\n .map((name) => {\n const creds = store.profiles[name]!;\n return {\n name,\n current: name === current,\n hasAccessToken: Boolean(creds.accessToken || creds.refreshToken),\n expiresAt: creds.expiresAt,\n workspaceUuid: creds.workspaceUuid,\n };\n });\n }\n\n private getCredentialsPath(env: string): string {\n // `env` comes from --env and the dev-cloud:NAMESPACE branch accepts an\n // arbitrary namespace, so it could contain `..` or a path separator and\n // escape the cache directory. Validate against an allowlist first (real\n // env names are alphanumerics, `-`, `_`, `.`, and the dev-cloud `:`\n // separator). This rejects path separators outright — including the\n // `foo/bar` case that would otherwise resolve inside .gr-cli but fail\n // later with a cryptic ENOENT from the un-created subdirectory.\n if (!/^[a-zA-Z0-9_:.-]+$/.test(env)) {\n throw new Error(`Invalid environment name: ${env}`);\n }\n // Defense-in-depth: also contain the resolved path before any fs\n // operation, so a future change to buildCredentialsPath can't reintroduce\n // an escape even if the allowlist is loosened.\n const candidate = this.buildCredentialsPath(env);\n // `this.cacheDir` is rooted at os.homedir() (see constructor) — a constant\n // resolve of the user's own dir, no attacker input. FP (CWE-22).\n // bearer:disable javascript_lang_path_traversal\n const resolvedDir = resolve(this.cacheDir);\n // This resolve()/relative() pair IS the containment sanitizer — `env` was\n // already allowlist-validated above. Semgrep's taint tracker flags the\n // resolve() of the env-derived candidate without modelling the guard.\n // bearer:disable javascript_lang_path_traversal\n // nosemgrep: javascript.lang.security.audit.path-traversal.path-join-resolve-traversal.path-join-resolve-traversal\n const rel = relative(resolvedDir, resolve(candidate));\n if (rel.startsWith('..') || isAbsolute(rel)) {\n throw new Error(`Invalid environment name: ${env}`);\n }\n return candidate;\n }\n\n private buildCredentialsPath(env: string): string {\n // Isolate credential files by non-default API port so worktrees (shifted\n // ports + separate DBs) do not clobber each other's imported tokens.\n if (this.apiUrl) {\n try {\n const url = new URL(this.apiUrl);\n const port = url.port;\n if (port && port !== '80' && port !== '443') {\n const isCanonicalLocalDev =\n (url.hostname === 'localhost' && port === '5050') ||\n (url.hostname.endsWith('gravityrail.test') && port === '5054');\n if (!isCanonicalLocalDev) {\n // `env` is allowlist-validated in getCredentialsPath before this\n // builder runs, cacheDir is homedir-rooted, and url.port is a\n // parsed URL port — no traversal component. FP (CWE-22).\n // bearer:disable javascript_lang_path_traversal\n // nosemgrep: javascript.lang.security.audit.path-traversal.path-join-resolve-traversal.path-join-resolve-traversal\n return join(this.cacheDir, `credentials-${env}-${port}.json`);\n }\n }\n } catch {\n // ignore invalid URLs\n }\n }\n // `env` is allowlist-validated in getCredentialsPath before this builder\n // runs and cacheDir is homedir-rooted — no traversal component. FP (CWE-22).\n // bearer:disable javascript_lang_path_traversal\n // nosemgrep: javascript.lang.security.audit.path-traversal.path-join-resolve-traversal.path-join-resolve-traversal\n return join(this.cacheDir, `credentials-${env}.json`);\n }\n\n private emptyStore(currentProfile = DEFAULT_PROFILE): CredentialStoreV2 {\n return { version: 2, currentProfile, profiles: {} };\n }\n\n private isCredentialShape(value: unknown): value is CLICredentials {\n if (!value || typeof value !== 'object') return false;\n const v = value as Record<string, unknown>;\n // Local JSON shape check only — typeof / field presence, not secret comparison.\n // FP (CWE-208): no secret values are compared; short-circuit cannot leak content.\n // bearer:disable javascript_lang_observable_timing\n const hasOAuth = typeof v.clientId === 'string' && typeof v.clientSecret === 'string';\n // bearer:disable javascript_lang_observable_timing\n const hasToken = typeof v.accessToken === 'string' && v.accessToken.length > 0;\n return hasOAuth || hasToken;\n }\n\n /**\n * Read and normalize the on-disk store (migrating legacy formats in memory).\n * `wasLegacy` is true when the file was not already v2 so callers can rewrite once.\n */\n private readStore(env: string): { store: CredentialStoreV2; wasLegacy: boolean } | null {\n const credsPath = this.getCredentialsPath(env);\n if (!existsSync(credsPath)) {\n return null;\n }\n\n try {\n const raw = JSON.parse(readFileSync(credsPath, 'utf-8')) as Record<string, unknown>;\n\n // v2 multi-profile\n if (raw.version === 2 && raw.profiles && typeof raw.profiles === 'object') {\n const profiles: Record<string, CLICredentials> = {};\n for (const [name, value] of Object.entries(raw.profiles as Record<string, unknown>)) {\n if (this.isCredentialShape(value)) {\n profiles[name] = value;\n }\n }\n const current =\n typeof raw.currentProfile === 'string' && profiles[raw.currentProfile]\n ? raw.currentProfile\n : Object.keys(profiles)[0] || DEFAULT_PROFILE;\n return {\n store: { version: 2, currentProfile: current, profiles },\n wasLegacy: false,\n };\n }\n\n // Flat single-credential format (pre-multi-account)\n if (this.isCredentialShape(raw)) {\n return {\n store: {\n version: 2,\n currentProfile: DEFAULT_PROFILE,\n profiles: { [DEFAULT_PROFILE]: raw },\n },\n wasLegacy: true,\n };\n }\n\n // Old org-namespaced format { default: {...} }\n const legacyDefault = (raw as { default?: unknown }).default;\n if (this.isCredentialShape(legacyDefault)) {\n return {\n store: {\n version: 2,\n currentProfile: DEFAULT_PROFILE,\n profiles: { [DEFAULT_PROFILE]: legacyDefault },\n },\n wasLegacy: true,\n };\n }\n\n return null;\n } catch {\n return null;\n }\n }\n\n private ensureCacheDir(): void {\n if (!existsSync(this.cacheDir)) {\n mkdirSync(this.cacheDir, { recursive: true, mode: 0o700 });\n try {\n chmodSync(this.cacheDir, 0o700);\n } catch {\n // Ignore permission errors on Windows\n }\n }\n }\n\n private writeStore(env: string, store: CredentialStoreV2): void {\n this.ensureCacheDir();\n const credsPath = this.getCredentialsPath(env);\n // Atomic replace: write a sibling temp file, chmod, then rename into place.\n // POSIX rename is atomic, so a crash mid-write cannot leave a partial JSON\n // that would wipe every profile on the next parse failure.\n const tmpPath = `${credsPath}.tmp`;\n writeFileSync(tmpPath, JSON.stringify(store, null, 2) + '\\n', { mode: 0o600 });\n try {\n chmodSync(tmpPath, 0o600);\n } catch {\n // Ignore permission errors on Windows\n }\n renameSync(tmpPath, credsPath);\n try {\n chmodSync(credsPath, 0o600);\n } catch {\n // Ignore permission errors on Windows\n }\n }\n\n private filterExpired(creds: CLICredentials): CLICredentials | null {\n if (creds.expiresAt) {\n const expiresAt = new Date(creds.expiresAt);\n if (expiresAt <= new Date()) {\n if (creds.refreshToken) {\n return creds;\n }\n return null;\n }\n }\n return creds;\n }\n\n /**\n * Load credentials for an environment + profile.\n * When `profile` is omitted, uses the resolved current profile for `env`.\n */\n load(env: string, profile?: string): CLICredentials | null {\n const parsed = this.readStore(env);\n if (!parsed) return null;\n\n const { store, wasLegacy } = parsed;\n const name = profile ?? store.currentProfile ?? DEFAULT_PROFILE;\n if (profile) this.validateProfileName(profile);\n const creds = store.profiles[name];\n if (!creds) return null;\n\n // Persist migration from flat/org formats so subsequent multi-profile ops work.\n // wasLegacy comes from the single parse in readStore — no second file read.\n if (wasLegacy) {\n this.writeStore(env, store);\n }\n\n return this.filterExpired(creds);\n }\n\n /**\n * Save credentials for an environment + profile.\n * When `profile` is omitted, uses the current profile (or \"default\").\n * Sets currentProfile to the saved profile when the store was empty.\n */\n save(env: string, creds: CLICredentials, profile?: string): void {\n if (profile) this.validateProfileName(profile);\n const store = this.readStore(env)?.store ?? this.emptyStore();\n const name = profile ?? store.currentProfile ?? DEFAULT_PROFILE;\n if (profile) {\n // Explicit profile on save also becomes current when first created, or when\n // the caller is logging into a named account.\n store.profiles[name] = creds;\n if (!store.profiles[store.currentProfile] || Object.keys(store.profiles).length === 1) {\n store.currentProfile = name;\n }\n } else {\n store.profiles[name] = creds;\n if (!store.currentProfile) {\n store.currentProfile = name;\n }\n }\n this.writeStore(env, store);\n }\n\n /**\n * Bulk-save many profiles in one write (used by dev-realms import).\n * Does not change currentProfile unless the store was empty — then uses\n * `preferCurrent` if provided and present, else `superadmin`, else first.\n */\n saveMany(env: string, profiles: Record<string, CLICredentials>, preferCurrent?: string): number {\n const names = Object.keys(profiles);\n for (const name of names) {\n this.validateProfileName(name);\n }\n const store = this.readStore(env)?.store ?? this.emptyStore();\n const wasEmpty = Object.keys(store.profiles).length === 0;\n for (const [name, creds] of Object.entries(profiles)) {\n store.profiles[name] = creds;\n }\n if (wasEmpty) {\n if (preferCurrent && store.profiles[preferCurrent]) {\n store.currentProfile = preferCurrent;\n } else if (store.profiles.superadmin) {\n store.currentProfile = 'superadmin';\n } else {\n store.currentProfile = names.sort()[0] ?? DEFAULT_PROFILE;\n }\n }\n this.writeStore(env, store);\n return names.length;\n }\n\n /**\n * Clear one profile (default: current profile). Deletes the file when no profiles remain.\n * Pass a profile name to clear a specific account without touching others.\n */\n clear(env: string, profile?: string): void {\n const parsed = this.readStore(env);\n if (!parsed) return;\n const store = parsed.store;\n\n const name = profile ?? store.currentProfile ?? DEFAULT_PROFILE;\n if (profile) this.validateProfileName(profile);\n delete store.profiles[name];\n\n if (Object.keys(store.profiles).length === 0) {\n const credsPath = this.getCredentialsPath(env);\n if (existsSync(credsPath)) {\n try {\n unlinkSync(credsPath);\n } catch {\n // Ignore\n }\n }\n return;\n }\n\n if (store.currentProfile === name) {\n store.currentProfile = Object.keys(store.profiles).sort()[0]!;\n }\n this.writeStore(env, store);\n }\n\n /**\n * Read a cached org-scoped SSO session for an org, if present and unexpired.\n * Independent of the account token's expiry — a valid org session is reusable\n * even while the account token is being refreshed.\n */\n getOrgSession(env: string, profile: string | undefined, orgUuid: string): string | undefined {\n const parsed = this.readStore(env);\n if (!parsed) return undefined;\n const name = profile ?? parsed.store.currentProfile ?? DEFAULT_PROFILE;\n if (profile) this.validateProfileName(profile);\n const entry = parsed.store.profiles[name]?.orgSessions?.[orgUuid];\n if (!entry?.session) return undefined;\n if (entry.expiresAt && new Date(entry.expiresAt) <= new Date()) return undefined;\n return entry.session;\n }\n\n /**\n * Cache an org-scoped SSO session under an existing profile, keyed by org UUID.\n * No-op when the profile does not exist — org sessions only attach to a\n * logged-in account profile (never create a token-less profile row).\n */\n setOrgSession(\n env: string,\n profile: string | undefined,\n orgUuid: string,\n session: string,\n expiresAt?: string\n ): void {\n const parsed = this.readStore(env);\n if (!parsed) return;\n const store = parsed.store;\n const name = profile ?? store.currentProfile ?? DEFAULT_PROFILE;\n if (profile) this.validateProfileName(profile);\n const creds = store.profiles[name];\n if (!creds) return;\n creds.orgSessions = {\n ...(creds.orgSessions ?? {}),\n [orgUuid]: { session, ...(expiresAt ? { expiresAt } : {}) },\n };\n this.writeStore(env, store);\n }\n\n getCacheDir(): string {\n return this.cacheDir;\n }\n\n /** Absolute path of the credentials file for `env` (for docs / `auth list`). */\n getCredentialsFilePath(env: string): string {\n return this.getCredentialsPath(env);\n }\n}\n","/**\n * CLI terminal UI utilities\n *\n * Provides interactive terminal UI components for CLI tools\n */\n\nimport * as readline from 'readline';\n\nexport interface SelectOption<T> {\n item: T;\n label: string;\n detail?: string;\n}\n\nexport interface SelectFromListOptions<T> {\n title?: string;\n labelFn?: (item: T) => string;\n detailFn?: (item: T) => string | null;\n env?: string;\n emptyMessage?: string;\n allowNew?: boolean;\n newLabel?: string;\n}\n\nexport interface SelectResult<T> {\n item: T | null;\n isNew: boolean;\n}\n\nconst NEW_ITEM_MARKER = Symbol('NEW_ITEM');\n\n/**\n * Interactive list picker using arrow keys\n */\nexport async function selectFromList<T>(\n items: T[],\n options: SelectFromListOptions<T> = {}\n): Promise<SelectResult<T>> {\n const {\n title = 'Select an item',\n labelFn = (item: T) => String((item as any).name || (item as any).title || item),\n detailFn = null,\n env = null,\n emptyMessage = 'No items found.',\n allowNew = false,\n newLabel = 'Create new...',\n } = options;\n\n if ((!items || items.length === 0) && !allowNew) {\n console.log(`\\n ${emptyMessage}`);\n return { item: null, isNew: false };\n }\n\n // Prepend \"Create new\" option if allowed\n const displayItems: (T | typeof NEW_ITEM_MARKER)[] = allowNew\n ? [NEW_ITEM_MARKER, ...items]\n : items;\n\n return new Promise((resolve) => {\n let selectedIndex = allowNew ? 1 : 0;\n let filterText = '';\n\n const getFilteredItems = (): (T | typeof NEW_ITEM_MARKER)[] => {\n if (!filterText) return displayItems;\n const lower = filterText.toLowerCase();\n return displayItems.filter((item) => {\n if (item === NEW_ITEM_MARKER) return true;\n const label = labelFn(item);\n return label.toLowerCase().includes(lower);\n });\n };\n\n const render = (): void => {\n const filtered = getFilteredItems();\n\n // Clear screen and move cursor to top\n process.stdout.write('\\x1B[2J\\x1B[H');\n\n console.log('='.repeat(60));\n console.log(`${title} (↑/↓ to move, Enter to select, Esc to cancel)`);\n console.log('='.repeat(60));\n if (env) {\n console.log(`Environment: ${env}`);\n }\n console.log(`Filter: ${filterText}${filterText ? '' : '(type to filter)'}`);\n console.log('');\n\n if (filtered.length === 0) {\n console.log(` ${emptyMessage}`);\n console.log('');\n return;\n }\n\n // Show up to 15 items around the selected one\n const maxVisible = 15;\n let startIdx = Math.max(0, selectedIndex - Math.floor(maxVisible / 2));\n let endIdx = Math.min(filtered.length, startIdx + maxVisible);\n if (endIdx - startIdx < maxVisible && startIdx > 0) {\n startIdx = Math.max(0, endIdx - maxVisible);\n }\n\n if (startIdx > 0) {\n console.log(` ... ${startIdx} more above ...`);\n }\n\n for (let i = startIdx; i < endIdx; i++) {\n const item = filtered[i]!;\n const prefix = i === selectedIndex ? '> ' : ' ';\n\n let line: string;\n if (item === NEW_ITEM_MARKER) {\n line = `\\x1B[32m${newLabel}\\x1B[0m`; // Green color for \"Create new\"\n } else {\n const typedItem = item as T;\n line = labelFn(typedItem);\n if (detailFn) {\n const detail = detailFn(typedItem);\n if (detail) {\n line = `${line} \\x1B[90m${detail}\\x1B[0m`;\n }\n }\n }\n\n if (i === selectedIndex) {\n console.log(`\\x1B[7m${prefix}${line}\\x1B[0m`);\n } else {\n console.log(`${prefix}${line}`);\n }\n }\n\n if (endIdx < filtered.length) {\n console.log(` ... ${filtered.length - endIdx} more below ...`);\n }\n\n console.log('');\n console.log(` ${filtered.length} item(s)`);\n };\n\n // Set up raw mode for arrow key input\n readline.emitKeypressEvents(process.stdin);\n if (process.stdin.isTTY) {\n process.stdin.setRawMode(true);\n }\n\n render();\n\n const handleKeypress = (str: string | undefined, key: readline.Key): void => {\n const filtered = getFilteredItems();\n\n if (key.name === 'up') {\n selectedIndex = Math.max(0, selectedIndex - 1);\n render();\n } else if (key.name === 'down') {\n selectedIndex = Math.min(filtered.length - 1, selectedIndex + 1);\n render();\n } else if (key.name === 'return') {\n cleanup();\n if (filtered.length > 0 && selectedIndex < filtered.length) {\n const selected = filtered[selectedIndex]!;\n if (selected === NEW_ITEM_MARKER) {\n resolve({ item: null, isNew: true });\n } else {\n resolve({ item: selected as T, isNew: false });\n }\n } else {\n resolve({ item: null, isNew: false });\n }\n } else if (key.name === 'escape' || (key.ctrl && key.name === 'c')) {\n cleanup();\n resolve({ item: null, isNew: false });\n } else if (key.name === 'backspace') {\n filterText = filterText.slice(0, -1);\n selectedIndex = allowNew ? 0 : 0;\n render();\n } else if (str && str.length === 1 && !key.ctrl && !key.meta) {\n filterText += str;\n selectedIndex = allowNew ? 0 : 0;\n render();\n }\n };\n\n const cleanup = (): void => {\n process.stdin.removeListener('keypress', handleKeypress);\n if (process.stdin.isTTY) {\n process.stdin.setRawMode(false);\n }\n process.stdin.pause();\n process.stdout.write('\\x1B[2J\\x1B[H');\n };\n\n process.stdin.on('keypress', handleKeypress);\n process.stdin.resume();\n });\n}\n\n/**\n * Print a table of items\n */\nexport function printTable<T>(\n items: T[],\n columns: Array<{\n header: string;\n getValue: (item: T) => string;\n maxWidth?: number;\n }>,\n options: { title?: string; env?: string } = {}\n): void {\n if (!items || items.length === 0) {\n console.log('\\nNo items found.');\n return;\n }\n\n if (options.title) {\n console.log(`\\n=== ${options.title} ===`);\n }\n if (options.env) {\n console.log(`Environment: ${options.env}`);\n }\n console.log('');\n\n // Calculate column widths\n const widths = columns.map((col) => {\n const maxContent = Math.max(...items.map((item) => String(col.getValue(item) ?? '').length));\n const width = Math.max(col.header.length, maxContent);\n return col.maxWidth ? Math.min(width, col.maxWidth) : width;\n });\n\n // Print header\n const headerLine = columns.map((col, i) => col.header.padEnd(widths[i]!)).join(' ');\n console.log(headerLine);\n console.log(widths.map((w) => '-'.repeat(w)).join(' '));\n\n // Print rows\n for (const item of items) {\n const row = columns\n .map((col, i) => {\n const value = String(col.getValue(item) ?? '');\n const width = widths[i]!;\n return value.slice(0, width).padEnd(width);\n })\n .join(' ');\n console.log(row);\n }\n\n console.log('');\n console.log(`Total: ${items.length} item(s)`);\n}\n\n/**\n * Format a timestamp for display\n */\nexport function formatTimestamp(isoString: string | null | undefined): string {\n if (!isoString) return '';\n const date = new Date(isoString);\n const now = new Date();\n const diff = now.getTime() - date.getTime();\n\n if (diff < 60000) return 'just now';\n if (diff < 3600000) return `${Math.floor(diff / 60000)}m ago`;\n if (diff < 86400000) return `${Math.floor(diff / 3600000)}h ago`;\n if (diff < 604800000) return `${Math.floor(diff / 86400000)}d ago`;\n\n return date.toLocaleDateString();\n}\n\n/**\n * Wrap text to a maximum width\n */\nexport function wrapText(text: string, width: number = 70): string[] {\n const words = text.split(' ');\n const lines: string[] = [];\n let currentLine = '';\n\n for (const word of words) {\n if (currentLine.length + word.length + 1 <= width) {\n currentLine += (currentLine ? ' ' : '') + word;\n } else {\n if (currentLine) lines.push(currentLine);\n currentLine = word;\n }\n }\n if (currentLine) lines.push(currentLine);\n return lines;\n}\n\n/**\n * Print a chat message with formatting\n */\nexport function printMessage(\n content: string,\n role: 'user' | 'assistant' | 'system',\n indent: string = ' '\n): void {\n const roleColors: Record<string, string> = {\n user: '\\x1B[34m', // Blue\n assistant: '\\x1B[32m', // Green\n system: '\\x1B[90m', // Gray\n };\n const resetColor = '\\x1B[0m';\n const color = roleColors[role] || resetColor;\n\n const label = role === 'user' ? 'You' : role === 'assistant' ? 'Assistant' : 'System';\n console.log(`${indent}${color}[${label}]${resetColor}`);\n\n const lines = content.split('\\n');\n for (const line of lines) {\n const wrapped = wrapText(line, 70);\n for (const wrappedLine of wrapped) {\n console.log(`${indent} ${wrappedLine}`);\n }\n }\n console.log('');\n}\n\n/**\n * Clear the terminal screen\n */\nexport function clearScreen(): void {\n process.stdout.write('\\x1B[2J\\x1B[H');\n}\n","/**\n * AG-UI Client for CLI chat interactions\n *\n * Implements the AG-UI (Agent-User Interaction) protocol for streaming\n * chat responses. See: https://docs.ag-ui.com/concepts/events\n */\n\nimport type { ConciergeAppContextPayload } from '../lib/cli-client-context';\n\n/**\n * AG-UI event types\n */\nexport type AGUIEventType =\n | 'RUN_STARTED'\n | 'RUN_FINISHED'\n | 'RUN_ERROR'\n | 'TEXT_MESSAGE_START'\n | 'TEXT_MESSAGE_CONTENT'\n | 'TEXT_MESSAGE_END'\n | 'TOOL_CALL_START'\n | 'TOOL_CALL_ARGS'\n | 'TOOL_CALL_END'\n | 'TOOL_CALL_RESULT'\n | 'STATE_SNAPSHOT'\n | 'STATE_DELTA'\n // Lowercase variants (some backends use these)\n | 'run_started'\n | 'run_finished'\n | 'run_error'\n | 'text_message_start'\n | 'text_message_content'\n | 'text_message_end'\n | 'tool_call_start'\n | 'tool_call_args'\n | 'tool_call_end'\n | 'tool_call_result'\n | 'state_snapshot'\n | 'state_delta'\n | 'done';\n\nexport interface AGUIEvent {\n type: AGUIEventType;\n messageId?: string;\n role?: string;\n delta?: string;\n content?: string;\n message?: string;\n code?: string;\n toolCallId?: string;\n toolCallName?: string;\n result?: any;\n snapshot?: any;\n operations?: any[];\n [key: string]: any;\n}\n\nexport interface ChatMessage {\n role: 'user' | 'assistant' | 'system';\n content: string;\n}\n\nexport interface AGUIClientOptions {\n baseUrl: string;\n workspaceUuid?: string;\n chatId?: number | string; // Numeric chat id (documented) or chat uuid (accepted)\n /** Full URL override — when provided, baseUrl/workspaceUuid/chatId are ignored for POST */\n endpointUrl?: string;\n accessToken: string;\n debug?: boolean;\n /** Model field sent in request body (default: 'manager'). Set to undefined to omit. */\n model?: string;\n /** Concierge / client context forwarded to the API (e.g. CLI surface hints). */\n appContext?: ConciergeAppContextPayload;\n}\n\n/**\n * AG-UI Client for streaming chat responses\n */\nexport class AGUIClient {\n private endpointUrl: string;\n private baseUrl: string;\n private workspaceUuid: string;\n private chatId: number | string;\n private accessToken: string;\n private debug: boolean;\n private model: string | undefined;\n private appContext: ConciergeAppContextPayload | undefined;\n\n constructor(options: AGUIClientOptions) {\n this.baseUrl = options.baseUrl;\n this.workspaceUuid = options.workspaceUuid ?? '';\n this.chatId = options.chatId ?? 0;\n if (!options.endpointUrl && (!options.workspaceUuid || options.chatId === undefined)) {\n throw new Error('AGUIClient requires workspaceUuid and chatId, or endpointUrl');\n }\n this.endpointUrl =\n options.endpointUrl ??\n `${options.baseUrl}/api/v2/w/${options.workspaceUuid}/web-chat/${options.chatId}/chat/agui`;\n this.accessToken = options.accessToken;\n this.debug = options.debug ?? false;\n this.model = 'model' in options ? options.model : 'manager';\n this.appContext = options.appContext;\n }\n\n private inferenceStatusUrl(): string | null {\n // Numeric chatId: treat 0 / negative as \"no chat\" (<= 0 rather than a\n // falsy check so a deliberate sentinel of 0 doesn't mean \"valid chat\").\n // String chatId is a uuid; empty string means \"no chat\".\n const noChat = typeof this.chatId === 'number' ? this.chatId <= 0 : this.chatId.length === 0;\n if (!this.workspaceUuid || noChat) return null;\n return `${this.baseUrl}/api/v2/w/${this.workspaceUuid}/chats/${this.chatId}/inference/status`;\n }\n\n private async waitForInferenceInactive(maxWaitMs = 60_000): Promise<boolean> {\n const url = this.inferenceStatusUrl();\n if (!url) return false;\n const deadline = Date.now() + maxWaitMs;\n while (Date.now() < deadline) {\n try {\n const res = await fetch(url, {\n headers: { Authorization: `Bearer ${this.accessToken}` },\n });\n if (res.ok) {\n const body = (await res.json()) as { active?: boolean };\n if (!body.active) return true;\n }\n } catch (err) {\n // Transient network errors (DNS blips, connection resets) shouldn't\n // crash the 409-retry loop. Log under --debug and keep polling\n // until the deadline; the caller will fall back to the original\n // 409 error if we can't confirm inactive in time.\n if (this.debug) {\n console.log(\n `[DEBUG] waitForInferenceInactive fetch failed: ${\n err instanceof Error ? err.message : String(err)\n }`\n );\n }\n }\n await new Promise((r) => setTimeout(r, 2000));\n }\n return false;\n }\n\n /**\n * Send messages and stream the response\n */\n async sendMessage(\n messages: ChatMessage[],\n onEvent: (event: AGUIEvent) => void,\n options?: AguiStreamOptions\n ): Promise<void> {\n return this.streamRequest({ messages }, onEvent, options);\n }\n\n /**\n * Stream an AG-UI request (initial messages or HITL resume).\n */\n async streamRequest(\n request: AguiRequestBody,\n onEvent: (event: AGUIEvent) => void,\n options?: AguiStreamOptions\n ): Promise<void> {\n const body = JSON.stringify({\n ...(this.model ? { model: this.model } : {}),\n messages: request.messages ?? [],\n ...(this.appContext ? { appContext: this.appContext } : {}),\n ...(request.resumeValue !== undefined ? { resumeValue: request.resumeValue } : {}),\n ...(request.resumeInterruptId ? { resumeInterruptId: request.resumeInterruptId } : {}),\n ...(request.resume !== undefined ? { resume: request.resume } : {}),\n ...(options?.autoApprove ? { context: { autoApprove: true } } : {}),\n });\n\n if (this.debug) {\n console.log(`\\n[DEBUG] POST ${this.endpointUrl}`);\n console.log(\n `[DEBUG] Body: ${request.resumeValue !== undefined ? 'resume' : `${(request.messages ?? []).length} message(s)`}`\n );\n }\n\n await this.postStream(body, onEvent, options);\n }\n\n private async postStream(\n body: string,\n onEvent: (event: AGUIEvent) => void,\n options?: AguiStreamOptions,\n conflictRetries = 0\n ): Promise<void> {\n const response = await fetch(this.endpointUrl, {\n method: 'POST',\n headers: {\n Authorization: `Bearer ${this.accessToken}`,\n 'Content-Type': 'application/json',\n Accept: 'text/event-stream',\n },\n body,\n });\n\n if (this.debug) {\n console.log(`[DEBUG] Response status: ${response.status}`);\n }\n\n if (response.status === 409 && conflictRetries < 3) {\n const ready = await this.waitForInferenceInactive();\n if (ready) {\n await this.postStream(body, onEvent, options, conflictRetries + 1);\n return;\n }\n }\n\n if (!response.ok) {\n const errorText = await response.text().catch(() => '');\n if (this.debug) {\n console.log(`[DEBUG] Error response: ${errorText}`);\n }\n throw new Error(\n `Chat request failed: ${response.status}${errorText ? `: ${errorText.slice(0, 200)}` : ''}`\n );\n }\n\n await parseSseStream(response.body!, onEvent);\n }\n\n /**\n * Subscribe to the chat's persistent AG-UI event feed and surface\n * server-initiated turns that arrive while we're idle between our own turns.\n *\n * The feed at ``/chats/{chatId}/events`` replays every AG-UI event for the\n * chat across all turns (assistant events plus user-message echoes). It never\n * self-terminates — it ends only on disconnect. On reconnect we send\n * ``Last-Event-ID`` so the server replays the gap. The loop reconnects with\n * capped exponential backoff and resolves quietly once ``signal`` aborts;\n * it never throws except when required args are missing (callers gate on\n * availability, so that path is a programming error).\n */\n async subscribeToFeed(opts: {\n onEvent: (event: AGUIEvent) => void;\n signal: AbortSignal;\n onDebug?: (msg: string) => void;\n }): Promise<void> {\n const { onEvent, signal, onDebug } = opts;\n\n // Guard even though callers gate on availability: the feed URL needs a\n // real workspace + chat. Mirror inferenceStatusUrl's \"no chat\" logic.\n const noChat = typeof this.chatId === 'number' ? this.chatId <= 0 : this.chatId.length === 0;\n if (!this.baseUrl || !this.workspaceUuid || noChat) {\n throw new Error('subscribeToFeed requires baseUrl, workspaceUuid, and a chatId');\n }\n const feedUrl = `${this.baseUrl}/api/v2/w/${this.workspaceUuid}/chats/${this.chatId}/events`;\n\n let lastEventId: string | undefined;\n let backoffMs = 1000;\n const maxBackoffMs = 15_000;\n // A connection that survived this long was healthy even if the chat\n // stayed silent the whole time — keepalive comment frames are\n // stripped by the parser, so they can never count as received data.\n const healthyConnectionMs = 30_000;\n\n while (!signal.aborted) {\n let receivedData = false;\n const connectedAt = Date.now();\n try {\n const headers: Record<string, string> = {\n Authorization: `Bearer ${this.accessToken}`,\n Accept: 'text/event-stream',\n };\n if (lastEventId !== undefined) headers['Last-Event-ID'] = lastEventId;\n\n const response = await fetch(feedUrl, { method: 'GET', headers, signal });\n if (!response.ok || !response.body) {\n throw new Error(`feed request failed: ${response.status}`);\n }\n onDebug?.(`feed connected${lastEventId ? ` (resume ${lastEventId})` : ''}`);\n\n await parseSseStream(\n response.body,\n (event, eventName) => {\n receivedData = true;\n // Retention lapsed — the server couldn't replay the gap.\n // Detected via the SSE ``event: feed_reset`` name (the\n // payload type is a belt-and-suspenders duplicate). For\n // v1 we just note it; some events may have been missed.\n if (\n eventName === 'feed_reset' ||\n (typeof event.type === 'string' && event.type.toUpperCase() === 'FEED_RESET')\n ) {\n onDebug?.('feed reset — server could not replay missed events');\n return;\n }\n onEvent(event);\n },\n (id) => {\n receivedData = true;\n lastEventId = id;\n }\n );\n // Stream ended (disconnect) — fall through to reconnect with backoff.\n } catch (err) {\n if (signal.aborted) return;\n onDebug?.(`feed error: ${err instanceof Error ? err.message : String(err)}`);\n }\n\n if (signal.aborted) return;\n\n // Reset only on evidence of health (delivered frames, or a\n // long-lived idle connection); otherwise wait out the current\n // backoff and grow it for the NEXT attempt (1s, 2s, 4s … cap).\n // Healthy connections must never escalate — an earlier version\n // doubled unconditionally after the reset, so steady\n // reconnects crept toward the cap.\n const wasHealthy = receivedData || Date.now() - connectedAt >= healthyConnectionMs;\n if (wasHealthy) backoffMs = 1000;\n const completed = await abortableDelay(backoffMs, signal);\n if (!completed) return; // aborted while waiting\n if (!wasHealthy) backoffMs = Math.min(backoffMs * 2, maxBackoffMs);\n }\n }\n}\n\n/**\n * Parse a Server-Sent Events stream body into AG-UI events.\n *\n * Shared by ``AGUIClient.postStream`` (per-turn POST) and ``subscribeToFeed``\n * (persistent GET feed). Surfaces ``data:`` frames as parsed events, ``id:``\n * frames via ``onId`` (feed reconnect uses the last id as ``Last-Event-ID``),\n * and ignores SSE comment frames (``: turn-done``, keepalives). ``onId`` is\n * optional — the POST path has no use for entry ids.\n */\nexport async function parseSseStream(\n body: ReadableStream<Uint8Array>,\n onEvent: (event: AGUIEvent, eventName?: string) => void,\n onId?: (id: string) => void\n): Promise<void> {\n const reader = body.getReader();\n const decoder = new TextDecoder();\n let buffer = '';\n // Per SSE, an ``event:`` line names the dispatch it precedes (the\n // server's feed_reset signal uses this). Cleared once consumed or at\n // the blank-line frame boundary.\n let pendingEventName: string | undefined;\n\n while (true) {\n const { done, value } = await reader.read();\n if (done) break;\n\n buffer += decoder.decode(value, { stream: true });\n const lines = buffer.split('\\n');\n buffer = lines.pop() ?? '';\n\n for (const rawLine of lines) {\n // Tolerate CRLF endings without changing the \\n-split behavior.\n const line = rawLine.endsWith('\\r') ? rawLine.slice(0, -1) : rawLine;\n\n // Blank line = SSE frame boundary; the pending event name only\n // applies within its own frame.\n if (line === '') {\n pendingEventName = undefined;\n continue;\n }\n\n // SSE comment frame (turn boundaries, keepalives) — ignore.\n if (line.startsWith(':')) continue;\n\n if (line.startsWith('event:')) {\n const nameValue = line.slice(6);\n pendingEventName = nameValue.startsWith(' ') ? nameValue.slice(1) : nameValue;\n continue;\n }\n\n if (line.startsWith('id:')) {\n const idValue = line.slice(3);\n // Per SSE, a single leading space after the colon is stripped.\n onId?.(idValue.startsWith(' ') ? idValue.slice(1) : idValue);\n continue;\n }\n\n if (line.startsWith('data: ')) {\n const data = line.slice(6);\n if (data === '[DONE]') {\n onEvent({ type: 'done' }, pendingEventName);\n pendingEventName = undefined;\n continue;\n }\n try {\n onEvent(JSON.parse(data) as AGUIEvent, pendingEventName);\n } catch {\n // Ignore parse errors for malformed events.\n }\n pendingEventName = undefined;\n }\n }\n }\n}\n\n/**\n * Resolve after ``ms`` unless ``signal`` aborts first. Returns true if the delay\n * completed, false if it was aborted — lets a reconnect loop exit cleanly.\n */\nfunction abortableDelay(ms: number, signal: AbortSignal): Promise<boolean> {\n return new Promise<boolean>((resolve) => {\n if (signal.aborted) {\n resolve(false);\n return;\n }\n const onAbort = (): void => {\n clearTimeout(timer);\n resolve(false);\n };\n const timer = setTimeout(() => {\n signal.removeEventListener('abort', onAbort);\n resolve(true);\n }, ms);\n signal.addEventListener('abort', onAbort, { once: true });\n });\n}\n\nexport interface AguiStreamOptions {\n autoApprove?: boolean;\n}\n\nexport interface AguiRequestBody {\n messages?: ChatMessage[];\n /** Concierge AGUI resume fields. */\n resumeValue?: string;\n resumeInterruptId?: string;\n /** Workspace-chat HITL resume (ChatCompletionRequest.resume shape:\n * { decisions: [{type: 'approve'|'edit'|'reject', ...}], interruptId }). */\n resume?: unknown;\n}\n\n/**\n * Helper to check if an event is a text content event\n */\nexport function isTextContentEvent(event: AGUIEvent): boolean {\n const type = event.type.toLowerCase();\n return type === 'text_message_content';\n}\n\n/**\n * Helper to check if an event is an error event\n */\nexport function isErrorEvent(event: AGUIEvent): boolean {\n const type = event.type.toLowerCase();\n return type === 'run_error';\n}\n\n/**\n * Helper to extract text delta from an event\n */\nexport function getTextDelta(event: AGUIEvent): string | null {\n if (isTextContentEvent(event) && event.delta) {\n return event.delta;\n }\n return null;\n}\n\n/**\n * Helper to extract error message from an event\n */\nexport function getErrorMessage(event: AGUIEvent): string | null {\n if (isErrorEvent(event)) {\n return event.message || event.code || 'Unknown error';\n }\n return null;\n}\n"],"mappings":";AAIA,SAAS,YAAY,oBAAoB;AACzC,SAAS,SAAS,MAAM,eAAe;AAOhC,IAAM,eAAkD;AAAA,EAC5D,KAAK;AAAA,IACF,QAAQ;AAAA,IACR,aAAa;AAAA,EAChB;AAAA,EACA,MAAM;AAAA,IACH,QAAQ;AAAA,IACR,aAAa;AAAA,EAChB;AAAA,EACA,SAAS;AAAA,IACN,QAAQ;AAAA,IACR,aAAa;AAAA,EAChB;AACH;AAEO,IAAM,gBAAgB;AACtB,IAAM,gBAAgB;AACtB,IAAM,eAAe,oBAAoB,aAAa,GAAG,aAAa;AAS7E,SAAS,sBAAmE;AAEzE,MAAI,MAAM,QAAQ,QAAQ,IAAI,CAAC;AAC/B,MAAI;AACJ,SAAO,MAAM;AACV,UAAM,YAAY,KAAK,KAAK,6BAA6B;AAEzD,QAAI,WAAW,SAAS,GAAG;AACxB,qBAAe;AACf;AAAA,IACH;AACA,UAAM,SAAS,QAAQ,GAAG;AAC1B,QAAI,WAAW,IAAK;AACpB,UAAM;AAAA,EACT;AACA,MAAI,CAAC,aAAc,QAAO,CAAC;AAE3B,MAAI;AACJ,MAAI;AACD,cAAU,aAAa,cAAc,OAAO;AAAA,EAC/C,QAAQ;AACL,WAAO,CAAC;AAAA,EACX;AAGA,MAAI,CAAC,QAAQ,SAAS,mBAAmB,EAAG,QAAO,CAAC;AAKpD,MAAI;AACJ,MAAI;AACJ,aAAW,SAAS,QAAQ,SAAS,oBAAoB,GAAG;AACzD,UAAM,OAAO,SAAS,MAAM,CAAC,GAAI,EAAE;AACnC,UAAM,YAAY,SAAS,MAAM,CAAC,GAAI,EAAE;AACxC,QAAI,cAAc,OAAO,cAAc,KAAM,WAAU;AACvD,QAAI,cAAc,IAAM,gBAAe;AAAA,EAC1C;AACA,SAAO,EAAE,SAAS,aAAa;AAClC;AAEO,SAAS,qBAAqB,KAAgC;AAElE,MAAI,IAAI,WAAW,YAAY,GAAG;AAC/B,UAAM,YAAY,IAAI,MAAM,aAAa,MAAM;AAC/C,QAAI,CAAC,WAAW;AACb,YAAM,IAAI,MAAM,uEAAuE;AAAA,IAC1F;AACA,WAAO;AAAA,MACJ,QAAQ,WAAW,SAAS;AAAA,MAC5B,aAAa,WAAW,SAAS;AAAA,IACpC;AAAA,EACH;AAEA,QAAM,SAAS,aAAa,GAAG;AAC/B,MAAI,CAAC,QAAQ;AACV,UAAM,IAAI;AAAA,MACP,wBAAwB,GAAG;AAAA,IAC9B;AAAA,EACH;AAGA,QAAM,SAAS,QAAQ,IAAI,wBAAwB,OAAO;AAC1D,QAAM,cAAc,QAAQ,IAAI,6BAA6B,OAAO;AACpE,MAAI,WAAW,OAAO,UAAU,gBAAgB,OAAO,aAAa;AACjE,WAAO,EAAE,QAAQ,YAAY;AAAA,EAChC;AAGA,MAAI,QAAQ,OAAO;AAChB,UAAM,QAAQ,oBAAoB;AAClC,QAAI,MAAM,WAAW,MAAM,cAAc;AACtC,aAAO;AAAA,QACJ,QAAQ,MAAM,UAAU,gCAAgC,MAAM,OAAO,KAAK,OAAO;AAAA,QACjF,aAAa,MAAM,eACd,gCAAgC,MAAM,YAAY,KAClD,OAAO;AAAA,MACf;AAAA,IACH;AAAA,EACH;AAEA,SAAO;AACV;;;AC5GA,SAAS,oBAAoB;AAC7B,SAAS,YAAY,mBAAmB;AACxC,SAAS,YAAY;;;ACKrB;AAAA,EACG,gBAAAA;AAAA,EACA;AAAA,EACA,cAAAC;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,OACI;AACP,SAAS,QAAAC,OAAM,WAAAC,UAAS,UAAU,kBAAkB;AAE7C,IAAM,kBAAkB;AAsDxB,IAAM,qBAAN,MAAyB;AAAA,EACrB;AAAA,EACA;AAAA,EAER,YAAY,SAAiB,QAAiB;AAM3C,SAAK,WAAWD,MAAK,SAAS,SAAS;AACvC,SAAK,SAAS;AAAA,EACjB;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAOA,oBAAoB,SAAuB;AACxC,QAAI,CAAC,SAAS;AACX,YAAM,IAAI,MAAM,gCAAgC;AAAA,IACnD;AACA,QAAI,QAAQ,SAAS,IAAI,KAAK,QAAQ,WAAW,GAAG,KAAK,QAAQ,SAAS,GAAG,GAAG;AAC7E,YAAM,IAAI;AAAA,QACP,yBAAyB,OAAO;AAAA,MACnC;AAAA,IACH;AAEA,QAAI,CAAC,0CAA0C,KAAK,OAAO,GAAG;AAC3D,YAAM,IAAI;AAAA,QACP,yBAAyB,OAAO;AAAA,MAEnC;AAAA,IACH;AAAA,EACH;AAAA;AAAA;AAAA;AAAA;AAAA,EAMA,mBAAmB,UAA0B,KAAsB;AAChE,QAAI,UAAU;AACX,WAAK,oBAAoB,QAAQ;AACjC,aAAO;AAAA,IACV;AACA,UAAM,UAAU,QAAQ,IAAI;AAC5B,QAAI,SAAS;AACV,WAAK,oBAAoB,OAAO;AAChC,aAAO;AAAA,IACV;AACA,QAAI,KAAK;AACN,aAAO,KAAK,kBAAkB,GAAG;AAAA,IACpC;AACA,WAAO;AAAA,EACV;AAAA,EAEA,kBAAkB,KAAqB;AACpC,UAAM,SAAS,KAAK,UAAU,GAAG;AACjC,QAAI,CAAC,OAAQ,QAAO;AACpB,WAAO,OAAO,MAAM,kBAAkB;AAAA,EACzC;AAAA,EAEA,kBAAkB,KAAa,SAAuB;AACnD,SAAK,oBAAoB,OAAO;AAChC,UAAM,QAAQ,KAAK,UAAU,GAAG,GAAG,SAAS,KAAK,WAAW,OAAO;AACnE,QAAI,CAAC,MAAM,SAAS,OAAO,GAAG;AAC3B,YAAM,IAAI;AAAA,QACP,YAAY,OAAO,mCAAmC,GAAG,+BACzB,OAAO;AAAA,MAC1C;AAAA,IACH;AACA,UAAM,iBAAiB;AACvB,SAAK,WAAW,KAAK,KAAK;AAAA,EAC7B;AAAA,EAEA,aAAa,KAA+B;AACzC,UAAM,SAAS,KAAK,UAAU,GAAG;AACjC,QAAI,CAAC,OAAQ,QAAO,CAAC;AACrB,UAAM,QAAQ,OAAO;AACrB,UAAM,UAAU,MAAM,kBAAkB;AACxC,WAAO,OAAO,KAAK,MAAM,QAAQ,EAC7B,KAAK,EACL,IAAI,CAAC,SAAS;AACZ,YAAM,QAAQ,MAAM,SAAS,IAAI;AACjC,aAAO;AAAA,QACJ;AAAA,QACA,SAAS,SAAS;AAAA,QAClB,gBAAgB,QAAQ,MAAM,eAAe,MAAM,YAAY;AAAA,QAC/D,WAAW,MAAM;AAAA,QACjB,eAAe,MAAM;AAAA,MACxB;AAAA,IACH,CAAC;AAAA,EACP;AAAA,EAEQ,mBAAmB,KAAqB;AAQ7C,QAAI,CAAC,qBAAqB,KAAK,GAAG,GAAG;AAClC,YAAM,IAAI,MAAM,6BAA6B,GAAG,EAAE;AAAA,IACrD;AAIA,UAAM,YAAY,KAAK,qBAAqB,GAAG;AAI/C,UAAM,cAAcC,SAAQ,KAAK,QAAQ;AAMzC,UAAM,MAAM,SAAS,aAAaA,SAAQ,SAAS,CAAC;AACpD,QAAI,IAAI,WAAW,IAAI,KAAK,WAAW,GAAG,GAAG;AAC1C,YAAM,IAAI,MAAM,6BAA6B,GAAG,EAAE;AAAA,IACrD;AACA,WAAO;AAAA,EACV;AAAA,EAEQ,qBAAqB,KAAqB;AAG/C,QAAI,KAAK,QAAQ;AACd,UAAI;AACD,cAAM,MAAM,IAAI,IAAI,KAAK,MAAM;AAC/B,cAAM,OAAO,IAAI;AACjB,YAAI,QAAQ,SAAS,QAAQ,SAAS,OAAO;AAC1C,gBAAM,sBACF,IAAI,aAAa,eAAe,SAAS,UACzC,IAAI,SAAS,SAAS,kBAAkB,KAAK,SAAS;AAC1D,cAAI,CAAC,qBAAqB;AAMvB,mBAAOD,MAAK,KAAK,UAAU,eAAe,GAAG,IAAI,IAAI,OAAO;AAAA,UAC/D;AAAA,QACH;AAAA,MACH,QAAQ;AAAA,MAER;AAAA,IACH;AAKA,WAAOA,MAAK,KAAK,UAAU,eAAe,GAAG,OAAO;AAAA,EACvD;AAAA,EAEQ,WAAW,iBAAiB,iBAAoC;AACrE,WAAO,EAAE,SAAS,GAAG,gBAAgB,UAAU,CAAC,EAAE;AAAA,EACrD;AAAA,EAEQ,kBAAkB,OAAyC;AAChE,QAAI,CAAC,SAAS,OAAO,UAAU,SAAU,QAAO;AAChD,UAAM,IAAI;AAIV,UAAM,WAAW,OAAO,EAAE,aAAa,YAAY,OAAO,EAAE,iBAAiB;AAE7E,UAAM,WAAW,OAAO,EAAE,gBAAgB,YAAY,EAAE,YAAY,SAAS;AAC7E,WAAO,YAAY;AAAA,EACtB;AAAA;AAAA;AAAA;AAAA;AAAA,EAMQ,UAAU,KAAsE;AACrF,UAAM,YAAY,KAAK,mBAAmB,GAAG;AAC7C,QAAI,CAACD,YAAW,SAAS,GAAG;AACzB,aAAO;AAAA,IACV;AAEA,QAAI;AACD,YAAM,MAAM,KAAK,MAAMD,cAAa,WAAW,OAAO,CAAC;AAGvD,UAAI,IAAI,YAAY,KAAK,IAAI,YAAY,OAAO,IAAI,aAAa,UAAU;AACxE,cAAM,WAA2C,CAAC;AAClD,mBAAW,CAAC,MAAM,KAAK,KAAK,OAAO,QAAQ,IAAI,QAAmC,GAAG;AAClF,cAAI,KAAK,kBAAkB,KAAK,GAAG;AAChC,qBAAS,IAAI,IAAI;AAAA,UACpB;AAAA,QACH;AACA,cAAM,UACH,OAAO,IAAI,mBAAmB,YAAY,SAAS,IAAI,cAAc,IAChE,IAAI,iBACJ,OAAO,KAAK,QAAQ,EAAE,CAAC,KAAK;AACpC,eAAO;AAAA,UACJ,OAAO,EAAE,SAAS,GAAG,gBAAgB,SAAS,SAAS;AAAA,UACvD,WAAW;AAAA,QACd;AAAA,MACH;AAGA,UAAI,KAAK,kBAAkB,GAAG,GAAG;AAC9B,eAAO;AAAA,UACJ,OAAO;AAAA,YACJ,SAAS;AAAA,YACT,gBAAgB;AAAA,YAChB,UAAU,EAAE,CAAC,eAAe,GAAG,IAAI;AAAA,UACtC;AAAA,UACA,WAAW;AAAA,QACd;AAAA,MACH;AAGA,YAAM,gBAAiB,IAA8B;AACrD,UAAI,KAAK,kBAAkB,aAAa,GAAG;AACxC,eAAO;AAAA,UACJ,OAAO;AAAA,YACJ,SAAS;AAAA,YACT,gBAAgB;AAAA,YAChB,UAAU,EAAE,CAAC,eAAe,GAAG,cAAc;AAAA,UAChD;AAAA,UACA,WAAW;AAAA,QACd;AAAA,MACH;AAEA,aAAO;AAAA,IACV,QAAQ;AACL,aAAO;AAAA,IACV;AAAA,EACH;AAAA,EAEQ,iBAAuB;AAC5B,QAAI,CAACC,YAAW,KAAK,QAAQ,GAAG;AAC7B,gBAAU,KAAK,UAAU,EAAE,WAAW,MAAM,MAAM,IAAM,CAAC;AACzD,UAAI;AACD,kBAAU,KAAK,UAAU,GAAK;AAAA,MACjC,QAAQ;AAAA,MAER;AAAA,IACH;AAAA,EACH;AAAA,EAEQ,WAAW,KAAa,OAAgC;AAC7D,SAAK,eAAe;AACpB,UAAM,YAAY,KAAK,mBAAmB,GAAG;AAI7C,UAAM,UAAU,GAAG,SAAS;AAC5B,kBAAc,SAAS,KAAK,UAAU,OAAO,MAAM,CAAC,IAAI,MAAM,EAAE,MAAM,IAAM,CAAC;AAC7E,QAAI;AACD,gBAAU,SAAS,GAAK;AAAA,IAC3B,QAAQ;AAAA,IAER;AACA,eAAW,SAAS,SAAS;AAC7B,QAAI;AACD,gBAAU,WAAW,GAAK;AAAA,IAC7B,QAAQ;AAAA,IAER;AAAA,EACH;AAAA,EAEQ,cAAc,OAA8C;AACjE,QAAI,MAAM,WAAW;AAClB,YAAM,YAAY,IAAI,KAAK,MAAM,SAAS;AAC1C,UAAI,aAAa,oBAAI,KAAK,GAAG;AAC1B,YAAI,MAAM,cAAc;AACrB,iBAAO;AAAA,QACV;AACA,eAAO;AAAA,MACV;AAAA,IACH;AACA,WAAO;AAAA,EACV;AAAA;AAAA;AAAA;AAAA;AAAA,EAMA,KAAK,KAAa,SAAyC;AACxD,UAAM,SAAS,KAAK,UAAU,GAAG;AACjC,QAAI,CAAC,OAAQ,QAAO;AAEpB,UAAM,EAAE,OAAO,UAAU,IAAI;AAC7B,UAAM,OAAO,WAAW,MAAM,kBAAkB;AAChD,QAAI,QAAS,MAAK,oBAAoB,OAAO;AAC7C,UAAM,QAAQ,MAAM,SAAS,IAAI;AACjC,QAAI,CAAC,MAAO,QAAO;AAInB,QAAI,WAAW;AACZ,WAAK,WAAW,KAAK,KAAK;AAAA,IAC7B;AAEA,WAAO,KAAK,cAAc,KAAK;AAAA,EAClC;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAOA,KAAK,KAAa,OAAuB,SAAwB;AAC9D,QAAI,QAAS,MAAK,oBAAoB,OAAO;AAC7C,UAAM,QAAQ,KAAK,UAAU,GAAG,GAAG,SAAS,KAAK,WAAW;AAC5D,UAAM,OAAO,WAAW,MAAM,kBAAkB;AAChD,QAAI,SAAS;AAGV,YAAM,SAAS,IAAI,IAAI;AACvB,UAAI,CAAC,MAAM,SAAS,MAAM,cAAc,KAAK,OAAO,KAAK,MAAM,QAAQ,EAAE,WAAW,GAAG;AACpF,cAAM,iBAAiB;AAAA,MAC1B;AAAA,IACH,OAAO;AACJ,YAAM,SAAS,IAAI,IAAI;AACvB,UAAI,CAAC,MAAM,gBAAgB;AACxB,cAAM,iBAAiB;AAAA,MAC1B;AAAA,IACH;AACA,SAAK,WAAW,KAAK,KAAK;AAAA,EAC7B;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAOA,SAAS,KAAa,UAA0C,eAAgC;AAC7F,UAAM,QAAQ,OAAO,KAAK,QAAQ;AAClC,eAAW,QAAQ,OAAO;AACvB,WAAK,oBAAoB,IAAI;AAAA,IAChC;AACA,UAAM,QAAQ,KAAK,UAAU,GAAG,GAAG,SAAS,KAAK,WAAW;AAC5D,UAAM,WAAW,OAAO,KAAK,MAAM,QAAQ,EAAE,WAAW;AACxD,eAAW,CAAC,MAAM,KAAK,KAAK,OAAO,QAAQ,QAAQ,GAAG;AACnD,YAAM,SAAS,IAAI,IAAI;AAAA,IAC1B;AACA,QAAI,UAAU;AACX,UAAI,iBAAiB,MAAM,SAAS,aAAa,GAAG;AACjD,cAAM,iBAAiB;AAAA,MAC1B,WAAW,MAAM,SAAS,YAAY;AACnC,cAAM,iBAAiB;AAAA,MAC1B,OAAO;AACJ,cAAM,iBAAiB,MAAM,KAAK,EAAE,CAAC,KAAK;AAAA,MAC7C;AAAA,IACH;AACA,SAAK,WAAW,KAAK,KAAK;AAC1B,WAAO,MAAM;AAAA,EAChB;AAAA;AAAA;AAAA;AAAA;AAAA,EAMA,MAAM,KAAa,SAAwB;AACxC,UAAM,SAAS,KAAK,UAAU,GAAG;AACjC,QAAI,CAAC,OAAQ;AACb,UAAM,QAAQ,OAAO;AAErB,UAAM,OAAO,WAAW,MAAM,kBAAkB;AAChD,QAAI,QAAS,MAAK,oBAAoB,OAAO;AAC7C,WAAO,MAAM,SAAS,IAAI;AAE1B,QAAI,OAAO,KAAK,MAAM,QAAQ,EAAE,WAAW,GAAG;AAC3C,YAAM,YAAY,KAAK,mBAAmB,GAAG;AAC7C,UAAIA,YAAW,SAAS,GAAG;AACxB,YAAI;AACD,qBAAW,SAAS;AAAA,QACvB,QAAQ;AAAA,QAER;AAAA,MACH;AACA;AAAA,IACH;AAEA,QAAI,MAAM,mBAAmB,MAAM;AAChC,YAAM,iBAAiB,OAAO,KAAK,MAAM,QAAQ,EAAE,KAAK,EAAE,CAAC;AAAA,IAC9D;AACA,SAAK,WAAW,KAAK,KAAK;AAAA,EAC7B;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAOA,cAAc,KAAa,SAA6B,SAAqC;AAC1F,UAAM,SAAS,KAAK,UAAU,GAAG;AACjC,QAAI,CAAC,OAAQ,QAAO;AACpB,UAAM,OAAO,WAAW,OAAO,MAAM,kBAAkB;AACvD,QAAI,QAAS,MAAK,oBAAoB,OAAO;AAC7C,UAAM,QAAQ,OAAO,MAAM,SAAS,IAAI,GAAG,cAAc,OAAO;AAChE,QAAI,CAAC,OAAO,QAAS,QAAO;AAC5B,QAAI,MAAM,aAAa,IAAI,KAAK,MAAM,SAAS,KAAK,oBAAI,KAAK,EAAG,QAAO;AACvE,WAAO,MAAM;AAAA,EAChB;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAOA,cACG,KACA,SACA,SACA,SACA,WACK;AACL,UAAM,SAAS,KAAK,UAAU,GAAG;AACjC,QAAI,CAAC,OAAQ;AACb,UAAM,QAAQ,OAAO;AACrB,UAAM,OAAO,WAAW,MAAM,kBAAkB;AAChD,QAAI,QAAS,MAAK,oBAAoB,OAAO;AAC7C,UAAM,QAAQ,MAAM,SAAS,IAAI;AACjC,QAAI,CAAC,MAAO;AACZ,UAAM,cAAc;AAAA,MACjB,GAAI,MAAM,eAAe,CAAC;AAAA,MAC1B,CAAC,OAAO,GAAG,EAAE,SAAS,GAAI,YAAY,EAAE,UAAU,IAAI,CAAC,EAAG;AAAA,IAC7D;AACA,SAAK,WAAW,KAAK,KAAK;AAAA,EAC7B;AAAA,EAEA,cAAsB;AACnB,WAAO,KAAK;AAAA,EACf;AAAA;AAAA,EAGA,uBAAuB,KAAqB;AACzC,WAAO,KAAK,mBAAmB,GAAG;AAAA,EACrC;AACH;;;AD3eA,SAAS,OAAO,KAAmB;AAChC,UAAQ,OAAO,MAAM,MAAM,IAAI;AAClC;AAMA,SAAS,aAAa,MAAc,WAA4B;AAC7D,MAAI;AACD,UAAM,SAAS,KAAK,MAAM,IAAI;AAC9B,QAAI,OAAO,UAAU,UAAW,QAAO;AAAA,EAC1C,QAAQ;AAAA,EAER;AACA,SAAO,KAAK,SAAS,SAAS;AACjC;AAMA,SAAS,sBAAsB,WAI7B;AACC,MAAI,CAAC,UAAU,gBAAgB,OAAO,UAAU,iBAAiB,UAAU;AACxE,UAAM,IAAI,MAAM,qCAAqC;AAAA,EACxD;AAEA,MAAI,UAAU,cAAc,OAAO,UAAU,UAAU,EAAE,YAAY,MAAM,UAAU;AAClF,UAAM,IAAI,MAAM,2BAA2B,UAAU,UAAU,EAAE;AAAA,EACpE;AAEA,MAAI,YAAY;AAChB,MAAI,UAAU,cAAc,MAAM;AAC/B,UAAM,MAAM,OAAO,UAAU,UAAU;AACvC,QAAI,CAAC,OAAO,SAAS,GAAG,KAAK,MAAM,MAAM,MAAM,SAAU;AACtD,aAAO,wCAAwC,UAAU,UAAU,kBAAkB;AAAA,IACxF,OAAO;AACJ,kBAAY;AAAA,IACf;AAAA,EACH;AAEA,SAAO;AAAA,IACJ,aAAa,UAAU;AAAA,IACvB,cACG,OAAO,UAAU,kBAAkB,WAAW,UAAU,gBAAgB;AAAA,IAC3E;AAAA,EACH;AACH;AAKO,SAAS,eAAgE;AAC7E,QAAM,eAAe,YAAY,EAAE,EAAE,SAAS,WAAW,EAAE,MAAM,GAAG,GAAG;AACvE,QAAM,gBAAgB,WAAW,QAAQ,EAAE,OAAO,YAAY,EAAE,OAAO,WAAW;AAClF,SAAO,EAAE,cAAc,cAAc;AACxC;AAKO,SAAS,YAAY,KAAmB;AAC5C,QAAM,WAAW,QAAQ;AACzB,MAAI;AACJ,MAAI,aAAa,UAAU;AACxB,UAAM,SAAS,GAAG;AAAA,EACrB,WAAW,aAAa,SAAS;AAC9B,UAAM,aAAa,GAAG;AAAA,EACzB,OAAO;AACJ,UAAM,aAAa,GAAG;AAAA,EACzB;AAEA,OAAK,KAAK,CAAC,QAAQ;AAChB,QAAI,KAAK;AACN,aAAO,yCAAyC;AAAA,IACnD;AAAA,EACH,CAAC;AACJ;AAKO,SAAS,sBAAgE;AAC7E,SAAO,IAAI,QAAQ,CAACG,UAAS,WAAW;AACrC,QAAI,WAA0B;AAC9B,QAAI,QAAuB;AAC3B,QAAI,gBAA+B;AAEnC,UAAM,SAAS,aAAa,CAAC,KAAK,QAAQ;AACvC,YAAM,MAAM,IAAI,IAAI,IAAI,KAAM,oBAAoB,aAAa,EAAE;AAEjE,UAAI,IAAI,aAAa,eAAe;AACjC,YAAI,UAAU,GAAG;AACjB,YAAI,IAAI,WAAW;AACnB;AAAA,MACH;AAEA,UAAI,IAAI,aAAa,IAAI,OAAO,GAAG;AAChC,gBAAQ,IAAI,aAAa,IAAI,OAAO;AACpC,cAAM,YAAY,IAAI,aAAa,IAAI,mBAAmB,KAAK;AAC/D,YAAI,UAAU,KAAK,EAAE,gBAAgB,YAAY,CAAC;AAClD,YAAI,IAAI;AAAA;AAAA;AAAA;AAAA;AAAA,iBAKH,SAAS;AAAA;AAAA;AAAA;AAAA,SAIjB;AACG,eAAO,MAAM;AACb,eAAO,IAAI,MAAM,yBAAyB,KAAK,EAAE,CAAC;AAAA,MACrD,WAAW,IAAI,aAAa,IAAI,MAAM,GAAG;AACtC,mBAAW,IAAI,aAAa,IAAI,MAAM;AACtC,wBAAgB,IAAI,aAAa,IAAI,OAAO;AAC5C,YAAI,UAAU,KAAK,EAAE,gBAAgB,YAAY,CAAC;AAClD,YAAI,IAAI;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,SASX;AACG,eAAO,MAAM;AACb,QAAAA,SAAQ,EAAE,MAAM,UAAU,OAAO,cAAc,CAAC;AAAA,MACnD,OAAO;AACJ,YAAI,UAAU,GAAG;AACjB,YAAI,IAAI,wBAAwB;AAAA,MACnC;AAAA,IACH,CAAC;AAED,WAAO,OAAO,eAAe,aAAa,MAAM;AAAA,IAEhD,CAAC;AAGD,UAAM,UAAU;AAAA,MACb,MAAM;AACH,YAAI,CAAC,YAAY,CAAC,OAAO;AACtB,iBAAO,MAAM;AACb,iBAAO,IAAI,MAAM,8CAA8C,CAAC;AAAA,QACnE;AAAA,MACH;AAAA,MACA,IAAI,KAAK;AAAA,IACZ;AACA,YAAQ,MAAM;AAAA,EACjB,CAAC;AACJ;AAKA,eAAe,0BACZ,WACA,aAAqB,eACiC;AACtD,SAAO,+BAA+B;AAEtC,QAAM,kBAAkB,GAAG,UAAU,MAAM;AAE3C,QAAM,mBAAmB;AAAA,IACtB,aAAa;AAAA,IACb,eAAe,CAAC,YAAY;AAAA,IAC5B,aAAa,CAAC,sBAAsB,eAAe;AAAA,IACnD,gBAAgB,CAAC,MAAM;AAAA,IACvB,4BAA4B;AAAA,IAC5B,OAAO;AAAA,EACV;AAEA,QAAM,WAAW,MAAM,MAAM,iBAAiB;AAAA,IAC3C,QAAQ;AAAA,IACR,SAAS,EAAE,gBAAgB,mBAAmB;AAAA,IAC9C,MAAM,KAAK,UAAU,gBAAgB;AAAA,EACxC,CAAC;AAED,MAAI,CAAC,SAAS,IAAI;AACf,UAAM,IAAI,MAAM,+BAA+B,SAAS,MAAM,MAAM,MAAM,SAAS,KAAK,CAAC,EAAE;AAAA,EAC9F;AAEA,SAAQ,MAAM,SAAS,KAAK;AAC/B;AAkBA,eAAsB,iBAAiB,SAAgD;AACpF,QAAM,EAAE,KAAK,WAAW,oBAAoB,aAAa,eAAe,QAAQ,IAAI;AACpF,QAAM,cAAc,mBAAmB,mBAAmB,SAAS,GAAG;AACtE,MAAI,aAAa;AAEjB,SAAO,MAAM;AAEV,QAAI,QAAQ,mBAAmB,KAAK,KAAK,WAAW;AACpD,QAAI,CAAC,SAAS,CAAC,MAAM,YAAY,CAAC,MAAM,cAAc;AACnD,YAAM,eAAe,MAAM,0BAA0B,WAAW,UAAU;AAC1E,cAAQ;AAAA,QACL,UAAU,aAAa;AAAA,QACvB,cAAc,aAAa;AAAA,MAC9B;AACA,yBAAmB,KAAK,KAAK,OAAO,WAAW;AAAA,IAClD,OAAO;AACJ,aAAO,mCAAmC;AAAA,IAC7C;AAGA,QAAI,CAAC,MAAM,YAAY,CAAC,MAAM,cAAc;AACzC,YAAM,IAAI,MAAM,qDAAqD;AAAA,IACxE;AACA,UAAM,WAAW,MAAM;AACvB,UAAM,eAAe,MAAM;AAE3B,UAAM,EAAE,cAAc,cAAc,IAAI,aAAa;AACrD,UAAM,QAAQ,YAAY,EAAE,EAAE,SAAS,WAAW;AAElD,UAAM,aAAa,IAAI,gBAAgB;AAAA,MACpC,eAAe;AAAA,MACf,WAAW;AAAA,MACX,cAAc;AAAA,MACd,OAAO;AAAA,MACP;AAAA,MACA,gBAAgB;AAAA,MAChB,uBAAuB;AAAA,IAC1B,CAAC;AAED,UAAM,UAAU,GAAG,UAAU,MAAM,2BAA2B,UAAU;AAExE,UAAM,kBAAkB,oBAAoB;AAE5C,WAAO,0CAA0C;AACjD,WAAO,cAAc,WAAW,EAAE;AAClC,WAAO;AAAA,IAAwC,OAAO;AAAA,CAAI;AAC1D,gBAAY,OAAO;AAEnB,WAAO,qDAAqD;AAC5D,QAAI;AACJ,QAAI;AACJ,QAAI;AACD,OAAC,EAAE,MAAM,OAAO,cAAc,IAAI,MAAM;AAAA,IAC3C,SAAS,KAAK;AACX,YAAM,MAAM,eAAe,QAAQ,IAAI,UAAU,OAAO,GAAG;AAC3D,UAAI,CAAC,cAAc,aAAa,KAAK,gBAAgB,GAAG;AACrD,eAAO,wDAAwD;AAC/D,2BAAmB,MAAM,KAAK,WAAW;AACzC,qBAAa;AACb;AAAA,MACH;AACA,YAAM;AAAA,IACT;AAEA,QAAI,kBAAkB,OAAO;AAC1B,YAAM,IAAI,MAAM,uCAAuC;AAAA,IAC1D;AAEA,WAAO,gCAAgC;AACvC,WAAO,iCAAiC;AAExC,UAAM,WAAW,GAAG,UAAU,MAAM;AACpC,UAAM,aAAa,OAAO,KAAK,GAAG,QAAQ,IAAI,YAAY,EAAE,EAAE,SAAS,QAAQ;AAE/E,UAAM,gBAAgB,MAAM,MAAM,UAAU;AAAA,MACzC,QAAQ;AAAA,MACR,SAAS;AAAA,QACN,eAAe,SAAS,UAAU;AAAA,QAClC,gBAAgB;AAAA,MACnB;AAAA,MACA,MAAM,IAAI,gBAAgB;AAAA,QACvB,YAAY;AAAA,QACZ;AAAA,QACA,cAAc;AAAA,QACd,eAAe;AAAA,MAClB,CAAC;AAAA,IACJ,CAAC;AAED,QAAI,CAAC,cAAc,IAAI;AACpB,YAAM,OAAO,MAAM,cAAc,KAAK;AACtC,UAAI,CAAC,cAAc,aAAa,MAAM,gBAAgB,GAAG;AACtD,eAAO,wDAAwD;AAC/D,2BAAmB,MAAM,KAAK,WAAW;AACzC,qBAAa;AACb;AAAA,MACH;AACA,YAAM,IAAI,MAAM,0BAA0B,cAAc,MAAM,MAAM,IAAI,EAAE;AAAA,IAC7E;AAEA,UAAM,YAAa,MAAM,cAAc,KAAK;AAC5C,UAAM,EAAE,aAAa,cAAc,UAAU,IAAI,sBAAsB,SAAS;AAEhF,UAAM,cAAc;AACpB,UAAM,eAAe,gBAAgB,MAAM;AAC3C,UAAM,YAAY,IAAI,KAAK,KAAK,IAAI,IAAI,YAAY,GAAI,EAAE,YAAY;AAEtE,uBAAmB,KAAK,KAAK,OAAO,WAAW;AAC/C,uBAAmB,kBAAkB,KAAK,WAAW;AACrD,WAAO,8BAA8B;AAErC,WAAO,EAAE,aAAa,aAAa,MAAM;AAAA,EAC5C;AACH;AAOA,eAAsB,mBACnB,WACA,OACA,oBACA,KACA,SAC+B;AAC/B,MAAI,CAAC,MAAM,gBAAgB,CAAC,MAAM,YAAY,CAAC,MAAM,cAAc;AAChE,WAAO,2DAA2D;AAClE,WAAO;AAAA,EACV;AAEA,QAAM,cAAc,mBAAmB,mBAAmB,SAAS,GAAG;AACtE,QAAM,WAAW,GAAG,UAAU,MAAM;AACpC,QAAM,aAAa,OAAO,KAAK,GAAG,MAAM,QAAQ,IAAI,MAAM,YAAY,EAAE,EAAE,SAAS,QAAQ;AAE3F,MAAI;AACD,UAAM,WAAW,MAAM,MAAM,UAAU;AAAA,MACpC,QAAQ;AAAA,MACR,SAAS;AAAA,QACN,eAAe,SAAS,UAAU;AAAA,QAClC,gBAAgB;AAAA,MACnB;AAAA,MACA,MAAM,IAAI,gBAAgB;AAAA,QACvB,YAAY;AAAA,QACZ,eAAe,MAAM;AAAA,MACxB,CAAC;AAAA,IACJ,CAAC;AAED,QAAI,CAAC,SAAS,IAAI;AACf,YAAM,OAAO,MAAM,SAAS,KAAK;AACjC,YAAM,mBAAmB,aAAa,MAAM,eAAe;AAC3D,UAAI,kBAAkB;AACnB,eAAO,4CAA4C;AAAA,MACtD,OAAO;AACJ,eAAO,2BAA2B,SAAS,MAAM,yBAAyB;AAAA,MAC7E;AACA,yBAAmB,MAAM,KAAK,WAAW;AACzC,aAAO;AAAA,IACV;AAEA,UAAM,YAAa,MAAM,SAAS,KAAK;AACvC,UAAM,EAAE,aAAa,cAAc,UAAU,IAAI,sBAAsB,SAAS;AAEhF,UAAM,UAA0B;AAAA,MAC7B,GAAG;AAAA,MACH;AAAA,MACA,cAAc,gBAAgB,MAAM;AAAA,MACpC,WAAW,IAAI,KAAK,KAAK,IAAI,IAAI,YAAY,GAAI,EAAE,YAAY;AAAA,IAClE;AAEA,uBAAmB,KAAK,KAAK,SAAS,WAAW;AACjD,WAAO;AAAA,EACV,SAAS,KAAK;AACX,WAAO,0BAA0B,eAAe,QAAQ,IAAI,UAAU,SAAS,EAAE;AACjF,uBAAmB,MAAM,KAAK,WAAW;AACzC,WAAO;AAAA,EACV;AACH;;;AEvZA,YAAY,cAAc;AAuB1B,IAAM,kBAAkB,uBAAO,UAAU;AAKzC,eAAsB,eACnB,OACA,UAAoC,CAAC,GACZ;AACzB,QAAM;AAAA,IACH,QAAQ;AAAA,IACR,UAAU,CAAC,SAAY,OAAQ,KAAa,QAAS,KAAa,SAAS,IAAI;AAAA,IAC/E,WAAW;AAAA,IACX,MAAM;AAAA,IACN,eAAe;AAAA,IACf,WAAW;AAAA,IACX,WAAW;AAAA,EACd,IAAI;AAEJ,OAAK,CAAC,SAAS,MAAM,WAAW,MAAM,CAAC,UAAU;AAC9C,YAAQ,IAAI;AAAA,IAAO,YAAY,EAAE;AACjC,WAAO,EAAE,MAAM,MAAM,OAAO,MAAM;AAAA,EACrC;AAGA,QAAM,eAA+C,WAChD,CAAC,iBAAiB,GAAG,KAAK,IAC1B;AAEL,SAAO,IAAI,QAAQ,CAACC,aAAY;AAC7B,QAAI,gBAAgB,WAAW,IAAI;AACnC,QAAI,aAAa;AAEjB,UAAM,mBAAmB,MAAsC;AAC5D,UAAI,CAAC,WAAY,QAAO;AACxB,YAAM,QAAQ,WAAW,YAAY;AACrC,aAAO,aAAa,OAAO,CAAC,SAAS;AAClC,YAAI,SAAS,gBAAiB,QAAO;AACrC,cAAM,QAAQ,QAAQ,IAAI;AAC1B,eAAO,MAAM,YAAY,EAAE,SAAS,KAAK;AAAA,MAC5C,CAAC;AAAA,IACJ;AAEA,UAAM,SAAS,MAAY;AACxB,YAAM,WAAW,iBAAiB;AAGlC,cAAQ,OAAO,MAAM,eAAe;AAEpC,cAAQ,IAAI,IAAI,OAAO,EAAE,CAAC;AAC1B,cAAQ,IAAI,GAAG,KAAK,0DAAgD;AACpE,cAAQ,IAAI,IAAI,OAAO,EAAE,CAAC;AAC1B,UAAI,KAAK;AACN,gBAAQ,IAAI,gBAAgB,GAAG,EAAE;AAAA,MACpC;AACA,cAAQ,IAAI,WAAW,UAAU,GAAG,aAAa,KAAK,kBAAkB,EAAE;AAC1E,cAAQ,IAAI,EAAE;AAEd,UAAI,SAAS,WAAW,GAAG;AACxB,gBAAQ,IAAI,KAAK,YAAY,EAAE;AAC/B,gBAAQ,IAAI,EAAE;AACd;AAAA,MACH;AAGA,YAAM,aAAa;AACnB,UAAI,WAAW,KAAK,IAAI,GAAG,gBAAgB,KAAK,MAAM,aAAa,CAAC,CAAC;AACrE,UAAI,SAAS,KAAK,IAAI,SAAS,QAAQ,WAAW,UAAU;AAC5D,UAAI,SAAS,WAAW,cAAc,WAAW,GAAG;AACjD,mBAAW,KAAK,IAAI,GAAG,SAAS,UAAU;AAAA,MAC7C;AAEA,UAAI,WAAW,GAAG;AACf,gBAAQ,IAAI,SAAS,QAAQ,iBAAiB;AAAA,MACjD;AAEA,eAAS,IAAI,UAAU,IAAI,QAAQ,KAAK;AACrC,cAAM,OAAO,SAAS,CAAC;AACvB,cAAM,SAAS,MAAM,gBAAgB,OAAO;AAE5C,YAAI;AACJ,YAAI,SAAS,iBAAiB;AAC3B,iBAAO,WAAW,QAAQ;AAAA,QAC7B,OAAO;AACJ,gBAAM,YAAY;AAClB,iBAAO,QAAQ,SAAS;AACxB,cAAI,UAAU;AACX,kBAAM,SAAS,SAAS,SAAS;AACjC,gBAAI,QAAQ;AACT,qBAAO,GAAG,IAAI,aAAa,MAAM;AAAA,YACpC;AAAA,UACH;AAAA,QACH;AAEA,YAAI,MAAM,eAAe;AACtB,kBAAQ,IAAI,UAAU,MAAM,GAAG,IAAI,SAAS;AAAA,QAC/C,OAAO;AACJ,kBAAQ,IAAI,GAAG,MAAM,GAAG,IAAI,EAAE;AAAA,QACjC;AAAA,MACH;AAEA,UAAI,SAAS,SAAS,QAAQ;AAC3B,gBAAQ,IAAI,SAAS,SAAS,SAAS,MAAM,iBAAiB;AAAA,MACjE;AAEA,cAAQ,IAAI,EAAE;AACd,cAAQ,IAAI,KAAK,SAAS,MAAM,UAAU;AAAA,IAC7C;AAGA,IAAS,4BAAmB,QAAQ,KAAK;AACzC,QAAI,QAAQ,MAAM,OAAO;AACtB,cAAQ,MAAM,WAAW,IAAI;AAAA,IAChC;AAEA,WAAO;AAEP,UAAM,iBAAiB,CAAC,KAAyB,QAA4B;AAC1E,YAAM,WAAW,iBAAiB;AAElC,UAAI,IAAI,SAAS,MAAM;AACpB,wBAAgB,KAAK,IAAI,GAAG,gBAAgB,CAAC;AAC7C,eAAO;AAAA,MACV,WAAW,IAAI,SAAS,QAAQ;AAC7B,wBAAgB,KAAK,IAAI,SAAS,SAAS,GAAG,gBAAgB,CAAC;AAC/D,eAAO;AAAA,MACV,WAAW,IAAI,SAAS,UAAU;AAC/B,gBAAQ;AACR,YAAI,SAAS,SAAS,KAAK,gBAAgB,SAAS,QAAQ;AACzD,gBAAM,WAAW,SAAS,aAAa;AACvC,cAAI,aAAa,iBAAiB;AAC/B,YAAAA,SAAQ,EAAE,MAAM,MAAM,OAAO,KAAK,CAAC;AAAA,UACtC,OAAO;AACJ,YAAAA,SAAQ,EAAE,MAAM,UAAe,OAAO,MAAM,CAAC;AAAA,UAChD;AAAA,QACH,OAAO;AACJ,UAAAA,SAAQ,EAAE,MAAM,MAAM,OAAO,MAAM,CAAC;AAAA,QACvC;AAAA,MACH,WAAW,IAAI,SAAS,YAAa,IAAI,QAAQ,IAAI,SAAS,KAAM;AACjE,gBAAQ;AACR,QAAAA,SAAQ,EAAE,MAAM,MAAM,OAAO,MAAM,CAAC;AAAA,MACvC,WAAW,IAAI,SAAS,aAAa;AAClC,qBAAa,WAAW,MAAM,GAAG,EAAE;AACnC,wBAAgB,WAAW,IAAI;AAC/B,eAAO;AAAA,MACV,WAAW,OAAO,IAAI,WAAW,KAAK,CAAC,IAAI,QAAQ,CAAC,IAAI,MAAM;AAC3D,sBAAc;AACd,wBAAgB,WAAW,IAAI;AAC/B,eAAO;AAAA,MACV;AAAA,IACH;AAEA,UAAM,UAAU,MAAY;AACzB,cAAQ,MAAM,eAAe,YAAY,cAAc;AACvD,UAAI,QAAQ,MAAM,OAAO;AACtB,gBAAQ,MAAM,WAAW,KAAK;AAAA,MACjC;AACA,cAAQ,MAAM,MAAM;AACpB,cAAQ,OAAO,MAAM,eAAe;AAAA,IACvC;AAEA,YAAQ,MAAM,GAAG,YAAY,cAAc;AAC3C,YAAQ,MAAM,OAAO;AAAA,EACxB,CAAC;AACJ;AAKO,SAAS,WACb,OACA,SAKA,UAA4C,CAAC,GACxC;AACL,MAAI,CAAC,SAAS,MAAM,WAAW,GAAG;AAC/B,YAAQ,IAAI,mBAAmB;AAC/B;AAAA,EACH;AAEA,MAAI,QAAQ,OAAO;AAChB,YAAQ,IAAI;AAAA,MAAS,QAAQ,KAAK,MAAM;AAAA,EAC3C;AACA,MAAI,QAAQ,KAAK;AACd,YAAQ,IAAI,gBAAgB,QAAQ,GAAG,EAAE;AAAA,EAC5C;AACA,UAAQ,IAAI,EAAE;AAGd,QAAM,SAAS,QAAQ,IAAI,CAAC,QAAQ;AACjC,UAAM,aAAa,KAAK,IAAI,GAAG,MAAM,IAAI,CAAC,SAAS,OAAO,IAAI,SAAS,IAAI,KAAK,EAAE,EAAE,MAAM,CAAC;AAC3F,UAAM,QAAQ,KAAK,IAAI,IAAI,OAAO,QAAQ,UAAU;AACpD,WAAO,IAAI,WAAW,KAAK,IAAI,OAAO,IAAI,QAAQ,IAAI;AAAA,EACzD,CAAC;AAGD,QAAM,aAAa,QAAQ,IAAI,CAAC,KAAK,MAAM,IAAI,OAAO,OAAO,OAAO,CAAC,CAAE,CAAC,EAAE,KAAK,IAAI;AACnF,UAAQ,IAAI,UAAU;AACtB,UAAQ,IAAI,OAAO,IAAI,CAAC,MAAM,IAAI,OAAO,CAAC,CAAC,EAAE,KAAK,IAAI,CAAC;AAGvD,aAAW,QAAQ,OAAO;AACvB,UAAM,MAAM,QACR,IAAI,CAAC,KAAK,MAAM;AACd,YAAM,QAAQ,OAAO,IAAI,SAAS,IAAI,KAAK,EAAE;AAC7C,YAAM,QAAQ,OAAO,CAAC;AACtB,aAAO,MAAM,MAAM,GAAG,KAAK,EAAE,OAAO,KAAK;AAAA,IAC5C,CAAC,EACA,KAAK,IAAI;AACb,YAAQ,IAAI,GAAG;AAAA,EAClB;AAEA,UAAQ,IAAI,EAAE;AACd,UAAQ,IAAI,UAAU,MAAM,MAAM,UAAU;AAC/C;AAKO,SAAS,gBAAgB,WAA8C;AAC3E,MAAI,CAAC,UAAW,QAAO;AACvB,QAAM,OAAO,IAAI,KAAK,SAAS;AAC/B,QAAM,MAAM,oBAAI,KAAK;AACrB,QAAM,OAAO,IAAI,QAAQ,IAAI,KAAK,QAAQ;AAE1C,MAAI,OAAO,IAAO,QAAO;AACzB,MAAI,OAAO,KAAS,QAAO,GAAG,KAAK,MAAM,OAAO,GAAK,CAAC;AACtD,MAAI,OAAO,MAAU,QAAO,GAAG,KAAK,MAAM,OAAO,IAAO,CAAC;AACzD,MAAI,OAAO,OAAW,QAAO,GAAG,KAAK,MAAM,OAAO,KAAQ,CAAC;AAE3D,SAAO,KAAK,mBAAmB;AAClC;AAKO,SAAS,SAAS,MAAc,QAAgB,IAAc;AAClE,QAAM,QAAQ,KAAK,MAAM,GAAG;AAC5B,QAAM,QAAkB,CAAC;AACzB,MAAI,cAAc;AAElB,aAAW,QAAQ,OAAO;AACvB,QAAI,YAAY,SAAS,KAAK,SAAS,KAAK,OAAO;AAChD,sBAAgB,cAAc,MAAM,MAAM;AAAA,IAC7C,OAAO;AACJ,UAAI,YAAa,OAAM,KAAK,WAAW;AACvC,oBAAc;AAAA,IACjB;AAAA,EACH;AACA,MAAI,YAAa,OAAM,KAAK,WAAW;AACvC,SAAO;AACV;AAKO,SAAS,aACb,SACA,MACA,SAAiB,MACZ;AACL,QAAM,aAAqC;AAAA,IACxC,MAAM;AAAA;AAAA,IACN,WAAW;AAAA;AAAA,IACX,QAAQ;AAAA;AAAA,EACX;AACA,QAAM,aAAa;AACnB,QAAM,QAAQ,WAAW,IAAI,KAAK;AAElC,QAAM,QAAQ,SAAS,SAAS,QAAQ,SAAS,cAAc,cAAc;AAC7E,UAAQ,IAAI,GAAG,MAAM,GAAG,KAAK,IAAI,KAAK,IAAI,UAAU,EAAE;AAEtD,QAAM,QAAQ,QAAQ,MAAM,IAAI;AAChC,aAAW,QAAQ,OAAO;AACvB,UAAM,UAAU,SAAS,MAAM,EAAE;AACjC,eAAW,eAAe,SAAS;AAChC,cAAQ,IAAI,GAAG,MAAM,KAAK,WAAW,EAAE;AAAA,IAC1C;AAAA,EACH;AACA,UAAQ,IAAI,EAAE;AACjB;AAKO,SAAS,cAAoB;AACjC,UAAQ,OAAO,MAAM,eAAe;AACvC;;;ACjPO,IAAM,aAAN,MAAiB;AAAA,EACb;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EAER,YAAY,SAA4B;AACrC,SAAK,UAAU,QAAQ;AACvB,SAAK,gBAAgB,QAAQ,iBAAiB;AAC9C,SAAK,SAAS,QAAQ,UAAU;AAChC,QAAI,CAAC,QAAQ,gBAAgB,CAAC,QAAQ,iBAAiB,QAAQ,WAAW,SAAY;AACnF,YAAM,IAAI,MAAM,8DAA8D;AAAA,IACjF;AACA,SAAK,cACF,QAAQ,eACR,GAAG,QAAQ,OAAO,aAAa,QAAQ,aAAa,aAAa,QAAQ,MAAM;AAClF,SAAK,cAAc,QAAQ;AAC3B,SAAK,QAAQ,QAAQ,SAAS;AAC9B,SAAK,QAAQ,WAAW,UAAU,QAAQ,QAAQ;AAClD,SAAK,aAAa,QAAQ;AAAA,EAC7B;AAAA,EAEQ,qBAAoC;AAIzC,UAAM,SAAS,OAAO,KAAK,WAAW,WAAW,KAAK,UAAU,IAAI,KAAK,OAAO,WAAW;AAC3F,QAAI,CAAC,KAAK,iBAAiB,OAAQ,QAAO;AAC1C,WAAO,GAAG,KAAK,OAAO,aAAa,KAAK,aAAa,UAAU,KAAK,MAAM;AAAA,EAC7E;AAAA,EAEA,MAAc,yBAAyB,YAAY,KAA0B;AAC1E,UAAM,MAAM,KAAK,mBAAmB;AACpC,QAAI,CAAC,IAAK,QAAO;AACjB,UAAM,WAAW,KAAK,IAAI,IAAI;AAC9B,WAAO,KAAK,IAAI,IAAI,UAAU;AAC3B,UAAI;AACD,cAAM,MAAM,MAAM,MAAM,KAAK;AAAA,UAC1B,SAAS,EAAE,eAAe,UAAU,KAAK,WAAW,GAAG;AAAA,QAC1D,CAAC;AACD,YAAI,IAAI,IAAI;AACT,gBAAM,OAAQ,MAAM,IAAI,KAAK;AAC7B,cAAI,CAAC,KAAK,OAAQ,QAAO;AAAA,QAC5B;AAAA,MACH,SAAS,KAAK;AAKX,YAAI,KAAK,OAAO;AACb,kBAAQ;AAAA,YACL,kDACG,eAAe,QAAQ,IAAI,UAAU,OAAO,GAAG,CAClD;AAAA,UACH;AAAA,QACH;AAAA,MACH;AACA,YAAM,IAAI,QAAQ,CAAC,MAAM,WAAW,GAAG,GAAI,CAAC;AAAA,IAC/C;AACA,WAAO;AAAA,EACV;AAAA;AAAA;AAAA;AAAA,EAKA,MAAM,YACH,UACA,SACA,SACc;AACd,WAAO,KAAK,cAAc,EAAE,SAAS,GAAG,SAAS,OAAO;AAAA,EAC3D;AAAA;AAAA;AAAA;AAAA,EAKA,MAAM,cACH,SACA,SACA,SACc;AACd,UAAM,OAAO,KAAK,UAAU;AAAA,MACzB,GAAI,KAAK,QAAQ,EAAE,OAAO,KAAK,MAAM,IAAI,CAAC;AAAA,MAC1C,UAAU,QAAQ,YAAY,CAAC;AAAA,MAC/B,GAAI,KAAK,aAAa,EAAE,YAAY,KAAK,WAAW,IAAI,CAAC;AAAA,MACzD,GAAI,QAAQ,gBAAgB,SAAY,EAAE,aAAa,QAAQ,YAAY,IAAI,CAAC;AAAA,MAChF,GAAI,QAAQ,oBAAoB,EAAE,mBAAmB,QAAQ,kBAAkB,IAAI,CAAC;AAAA,MACpF,GAAI,QAAQ,WAAW,SAAY,EAAE,QAAQ,QAAQ,OAAO,IAAI,CAAC;AAAA,MACjE,GAAI,SAAS,cAAc,EAAE,SAAS,EAAE,aAAa,KAAK,EAAE,IAAI,CAAC;AAAA,IACpE,CAAC;AAED,QAAI,KAAK,OAAO;AACb,cAAQ,IAAI;AAAA,eAAkB,KAAK,WAAW,EAAE;AAChD,cAAQ;AAAA,QACL,iBAAiB,QAAQ,gBAAgB,SAAY,WAAW,IAAI,QAAQ,YAAY,CAAC,GAAG,MAAM,aAAa;AAAA,MAClH;AAAA,IACH;AAEA,UAAM,KAAK,WAAW,MAAM,SAAS,OAAO;AAAA,EAC/C;AAAA,EAEA,MAAc,WACX,MACA,SACA,SACA,kBAAkB,GACJ;AACd,UAAM,WAAW,MAAM,MAAM,KAAK,aAAa;AAAA,MAC5C,QAAQ;AAAA,MACR,SAAS;AAAA,QACN,eAAe,UAAU,KAAK,WAAW;AAAA,QACzC,gBAAgB;AAAA,QAChB,QAAQ;AAAA,MACX;AAAA,MACA;AAAA,IACH,CAAC;AAED,QAAI,KAAK,OAAO;AACb,cAAQ,IAAI,4BAA4B,SAAS,MAAM,EAAE;AAAA,IAC5D;AAEA,QAAI,SAAS,WAAW,OAAO,kBAAkB,GAAG;AACjD,YAAM,QAAQ,MAAM,KAAK,yBAAyB;AAClD,UAAI,OAAO;AACR,cAAM,KAAK,WAAW,MAAM,SAAS,SAAS,kBAAkB,CAAC;AACjE;AAAA,MACH;AAAA,IACH;AAEA,QAAI,CAAC,SAAS,IAAI;AACf,YAAM,YAAY,MAAM,SAAS,KAAK,EAAE,MAAM,MAAM,EAAE;AACtD,UAAI,KAAK,OAAO;AACb,gBAAQ,IAAI,2BAA2B,SAAS,EAAE;AAAA,MACrD;AACA,YAAM,IAAI;AAAA,QACP,wBAAwB,SAAS,MAAM,GAAG,YAAY,KAAK,UAAU,MAAM,GAAG,GAAG,CAAC,KAAK,EAAE;AAAA,MAC5F;AAAA,IACH;AAEA,UAAM,eAAe,SAAS,MAAO,OAAO;AAAA,EAC/C;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAcA,MAAM,gBAAgB,MAIJ;AACf,UAAM,EAAE,SAAS,QAAQ,QAAQ,IAAI;AAIrC,UAAM,SAAS,OAAO,KAAK,WAAW,WAAW,KAAK,UAAU,IAAI,KAAK,OAAO,WAAW;AAC3F,QAAI,CAAC,KAAK,WAAW,CAAC,KAAK,iBAAiB,QAAQ;AACjD,YAAM,IAAI,MAAM,+DAA+D;AAAA,IAClF;AACA,UAAM,UAAU,GAAG,KAAK,OAAO,aAAa,KAAK,aAAa,UAAU,KAAK,MAAM;AAEnF,QAAI;AACJ,QAAI,YAAY;AAChB,UAAM,eAAe;AAIrB,UAAM,sBAAsB;AAE5B,WAAO,CAAC,OAAO,SAAS;AACrB,UAAI,eAAe;AACnB,YAAM,cAAc,KAAK,IAAI;AAC7B,UAAI;AACD,cAAM,UAAkC;AAAA,UACrC,eAAe,UAAU,KAAK,WAAW;AAAA,UACzC,QAAQ;AAAA,QACX;AACA,YAAI,gBAAgB,OAAW,SAAQ,eAAe,IAAI;AAE1D,cAAM,WAAW,MAAM,MAAM,SAAS,EAAE,QAAQ,OAAO,SAAS,OAAO,CAAC;AACxE,YAAI,CAAC,SAAS,MAAM,CAAC,SAAS,MAAM;AACjC,gBAAM,IAAI,MAAM,wBAAwB,SAAS,MAAM,EAAE;AAAA,QAC5D;AACA,kBAAU,iBAAiB,cAAc,YAAY,WAAW,MAAM,EAAE,EAAE;AAE1E,cAAM;AAAA,UACH,SAAS;AAAA,UACT,CAAC,OAAO,cAAc;AACnB,2BAAe;AAKf,gBACG,cAAc,gBACb,OAAO,MAAM,SAAS,YAAY,MAAM,KAAK,YAAY,MAAM,cACjE;AACC,wBAAU,yDAAoD;AAC9D;AAAA,YACH;AACA,oBAAQ,KAAK;AAAA,UAChB;AAAA,UACA,CAAC,OAAO;AACL,2BAAe;AACf,0BAAc;AAAA,UACjB;AAAA,QACH;AAAA,MAEH,SAAS,KAAK;AACX,YAAI,OAAO,QAAS;AACpB,kBAAU,eAAe,eAAe,QAAQ,IAAI,UAAU,OAAO,GAAG,CAAC,EAAE;AAAA,MAC9E;AAEA,UAAI,OAAO,QAAS;AAQpB,YAAM,aAAa,gBAAgB,KAAK,IAAI,IAAI,eAAe;AAC/D,UAAI,WAAY,aAAY;AAC5B,YAAM,YAAY,MAAM,eAAe,WAAW,MAAM;AACxD,UAAI,CAAC,UAAW;AAChB,UAAI,CAAC,WAAY,aAAY,KAAK,IAAI,YAAY,GAAG,YAAY;AAAA,IACpE;AAAA,EACH;AACH;AAWA,eAAsB,eACnB,MACA,SACA,MACc;AACd,QAAM,SAAS,KAAK,UAAU;AAC9B,QAAM,UAAU,IAAI,YAAY;AAChC,MAAI,SAAS;AAIb,MAAI;AAEJ,SAAO,MAAM;AACV,UAAM,EAAE,MAAM,MAAM,IAAI,MAAM,OAAO,KAAK;AAC1C,QAAI,KAAM;AAEV,cAAU,QAAQ,OAAO,OAAO,EAAE,QAAQ,KAAK,CAAC;AAChD,UAAM,QAAQ,OAAO,MAAM,IAAI;AAC/B,aAAS,MAAM,IAAI,KAAK;AAExB,eAAW,WAAW,OAAO;AAE1B,YAAM,OAAO,QAAQ,SAAS,IAAI,IAAI,QAAQ,MAAM,GAAG,EAAE,IAAI;AAI7D,UAAI,SAAS,IAAI;AACd,2BAAmB;AACnB;AAAA,MACH;AAGA,UAAI,KAAK,WAAW,GAAG,EAAG;AAE1B,UAAI,KAAK,WAAW,QAAQ,GAAG;AAC5B,cAAM,YAAY,KAAK,MAAM,CAAC;AAC9B,2BAAmB,UAAU,WAAW,GAAG,IAAI,UAAU,MAAM,CAAC,IAAI;AACpE;AAAA,MACH;AAEA,UAAI,KAAK,WAAW,KAAK,GAAG;AACzB,cAAM,UAAU,KAAK,MAAM,CAAC;AAE5B,eAAO,QAAQ,WAAW,GAAG,IAAI,QAAQ,MAAM,CAAC,IAAI,OAAO;AAC3D;AAAA,MACH;AAEA,UAAI,KAAK,WAAW,QAAQ,GAAG;AAC5B,cAAM,OAAO,KAAK,MAAM,CAAC;AACzB,YAAI,SAAS,UAAU;AACpB,kBAAQ,EAAE,MAAM,OAAO,GAAG,gBAAgB;AAC1C,6BAAmB;AACnB;AAAA,QACH;AACA,YAAI;AACD,kBAAQ,KAAK,MAAM,IAAI,GAAgB,gBAAgB;AAAA,QAC1D,QAAQ;AAAA,QAER;AACA,2BAAmB;AAAA,MACtB;AAAA,IACH;AAAA,EACH;AACH;AAMA,SAAS,eAAe,IAAY,QAAuC;AACxE,SAAO,IAAI,QAAiB,CAACC,aAAY;AACtC,QAAI,OAAO,SAAS;AACjB,MAAAA,SAAQ,KAAK;AACb;AAAA,IACH;AACA,UAAM,UAAU,MAAY;AACzB,mBAAa,KAAK;AAClB,MAAAA,SAAQ,KAAK;AAAA,IAChB;AACA,UAAM,QAAQ,WAAW,MAAM;AAC5B,aAAO,oBAAoB,SAAS,OAAO;AAC3C,MAAAA,SAAQ,IAAI;AAAA,IACf,GAAG,EAAE;AACL,WAAO,iBAAiB,SAAS,SAAS,EAAE,MAAM,KAAK,CAAC;AAAA,EAC3D,CAAC;AACJ;AAmBO,SAAS,mBAAmB,OAA2B;AAC3D,QAAM,OAAO,MAAM,KAAK,YAAY;AACpC,SAAO,SAAS;AACnB;AAKO,SAAS,aAAa,OAA2B;AACrD,QAAM,OAAO,MAAM,KAAK,YAAY;AACpC,SAAO,SAAS;AACnB;AAKO,SAAS,aAAa,OAAiC;AAC3D,MAAI,mBAAmB,KAAK,KAAK,MAAM,OAAO;AAC3C,WAAO,MAAM;AAAA,EAChB;AACA,SAAO;AACV;AAKO,SAAS,gBAAgB,OAAiC;AAC9D,MAAI,aAAa,KAAK,GAAG;AACtB,WAAO,MAAM,WAAW,MAAM,QAAQ;AAAA,EACzC;AACA,SAAO;AACV;","names":["readFileSync","existsSync","join","resolve","resolve","resolve","resolve"]}
@@ -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 if (result.error) {\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 detail = (result.stderr || '').trim() || `jq exited ${result.status}`;\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","import { GravityRailClient } from '@gravity-rail/sdk';\nimport {\n CredentialsManager,\n getEnvironmentConfig,\n refreshAccessToken,\n type CLICredentials,\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\n/** Try to silently refresh an expired access token. Returns an AuthenticatedContext or null. */\nasync function tryTokenRefresh(\n ctx: CommandContext,\n creds: CLICredentials\n): Promise<AuthenticatedContext | null> {\n if (!creds.refreshToken) return null;\n const refreshed = await refreshAccessToken(\n ctx.envConfig,\n creds,\n ctx.credentialsManager,\n ctx.env,\n ctx.profile\n );\n if (!refreshed?.accessToken) return null;\n const apiClient = makeApiClient(\n refreshed.accessToken,\n ctx.envConfig.apiUrl,\n undefined,\n interactiveOrgAuth(ctx)\n );\n return {\n ...ctx,\n accessToken: refreshed.accessToken,\n apiClient,\n profileWorkspace: refreshed.workspaceUuid ?? creds.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}\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}\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 baseConfig = getEnvironmentConfig(opts.env);\n const apiUrl = opts.apiUrl || process.env.GRAVITY_RAIL_API_URL || baseConfig.apiUrl;\n const envConfig = apiUrl === baseConfig.apiUrl ? baseConfig : { ...baseConfig, apiUrl };\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 // Try GRAVITY_RAIL_API_KEY first (process env; never persisted to the profile store)\n const apiKey = process.env.GRAVITY_RAIL_API_KEY;\n if (apiKey) {\n const apiClient = makeApiClient(apiKey, ctx.envConfig.apiUrl);\n return { ...ctx, accessToken: apiKey, apiClient };\n }\n\n // Try cached credentials for the resolved profile (login / import-dev)\n const creds = ctx.credentialsManager.load(ctx.env, ctx.profile);\n if (creds?.accessToken) {\n const buffer = 5 * 60 * 1000;\n const notExpired =\n !creds.expiresAt || new Date(creds.expiresAt) > new Date(Date.now() + buffer);\n if (notExpired) {\n const apiClient = makeApiClient(\n creds.accessToken,\n ctx.envConfig.apiUrl,\n undefined,\n interactiveOrgAuth(ctx)\n );\n return {\n ...ctx,\n accessToken: creds.accessToken,\n apiClient,\n profileWorkspace: creds.workspaceUuid,\n };\n }\n\n // Token expired — try refresh (OAuth profiles only)\n const refreshed = await tryTokenRefresh(ctx, creds);\n if (refreshed) return refreshed;\n }\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 = opts.apiUrl\n ? {\n apiUrl: opts.apiUrl,\n frontendUrl:\n opts.frontendUrl ||\n process.env.GRAVITY_RAIL_FRONTEND_URL ||\n 'https://app.gravityrail.com',\n }\n : getEnvironmentConfig(env);\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 // Process env only — not written into ~/.gr-cli (see credentials-manager security notes).\n const apiKey = process.env.GRAVITY_RAIL_API_KEY;\n if (apiKey) {\n const apiClient = makeApiClient(apiKey, ctx.envConfig.apiUrl);\n return { ...ctx, accessToken: apiKey, apiClient };\n }\n\n const creds = ctx.credentialsManager.load(ctx.env, ctx.profile);\n if (creds?.accessToken) {\n const buffer = 5 * 60 * 1000;\n const notExpired =\n !creds.expiresAt || new Date(creds.expiresAt) > new Date(Date.now() + buffer);\n if (notExpired) {\n const apiClient = makeApiClient(\n creds.accessToken,\n ctx.envConfig.apiUrl,\n undefined,\n interactiveOrgAuth(ctx)\n );\n return {\n ...ctx,\n accessToken: creds.accessToken,\n apiClient,\n profileWorkspace: creds.workspaceUuid,\n };\n }\n\n // Token expired — try refresh\n const refreshed = await tryTokenRefresh(ctx, creds);\n if (refreshed) return refreshed;\n }\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"]}