olakai-cli 0.3.0 → 0.4.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/dist/index.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/index.ts","../src/commands/login.ts","../src/lib/config.ts","../src/lib/auth.ts","../src/lib/api.ts","../src/commands/logout.ts","../src/commands/whoami.ts","../src/commands/agents.ts","../src/commands/workflows.ts","../src/commands/kpis.ts","../src/commands/custom-data.ts","../src/commands/activity.ts","../src/commands/monitor.ts","../src/commands/monitor-transcript.ts","../src/commands/monitor-state.ts"],"sourcesContent":["#!/usr/bin/env node\n\nimport { createRequire } from \"module\";\nimport { Command } from \"commander\";\nimport { loginCommand } from \"./commands/login.js\";\nimport { logoutCommand } from \"./commands/logout.js\";\nimport { whoamiCommand } from \"./commands/whoami.js\";\nimport { registerAgentsCommand } from \"./commands/agents.js\";\nimport { registerWorkflowsCommand } from \"./commands/workflows.js\";\nimport { registerKpisCommand } from \"./commands/kpis.js\";\nimport { registerCustomDataCommand } from \"./commands/custom-data.js\";\nimport { registerActivityCommand } from \"./commands/activity.js\";\nimport { registerMonitorCommand } from \"./commands/monitor.js\";\nimport {\n setEnvironment,\n isValidEnvironment,\n getValidEnvironments,\n type Environment,\n} from \"./lib/config.js\";\n\nconst require = createRequire(import.meta.url);\nconst packageJson = require(\"../package.json\") as { version: string };\n\nconst program = new Command();\n\nprogram\n .name(\"olakai\")\n .description(\"Olakai CLI tool\")\n .version(packageJson.version)\n .option(\n \"-e, --env <environment>\",\n `Environment to use (${getValidEnvironments().join(\", \")})`,\n \"production\",\n )\n .hook(\"preAction\", (thisCommand) => {\n const options = thisCommand.opts();\n if (options.env) {\n if (!isValidEnvironment(options.env)) {\n console.error(\n `Invalid environment: ${options.env}. Valid options: ${getValidEnvironments().join(\", \")}`,\n );\n process.exit(1);\n }\n setEnvironment(options.env as Environment);\n }\n });\n\nprogram\n .command(\"login\")\n .description(\"Log in to Olakai using browser authentication\")\n .action(loginCommand);\n\nprogram\n .command(\"logout\")\n .description(\"Log out from Olakai\")\n .action(logoutCommand);\n\nprogram\n .command(\"whoami\")\n .description(\"Show current logged-in user\")\n .action(whoamiCommand);\n\n// Register subcommands for config management\nregisterAgentsCommand(program);\nregisterWorkflowsCommand(program);\nregisterKpisCommand(program);\nregisterCustomDataCommand(program);\n\n// Register subcommands for activity inspection\nregisterActivityCommand(program);\n\n// Register subcommands for local agent monitoring\nregisterMonitorCommand(program);\n\nprogram.parse();\n","import open from \"open\";\nimport { requestDeviceCode, pollForToken, getCurrentUser } from \"../lib/api.js\";\nimport { saveToken, isTokenValid } from \"../lib/auth.js\";\nimport { getEnvironment } from \"../lib/config.js\";\n\nconst POLL_INTERVAL_MS = 5000; // 5 seconds\n\n/**\n * Login command handler\n */\nexport async function loginCommand(): Promise<void> {\n // Check if already logged in\n if (isTokenValid()) {\n try {\n const user = await getCurrentUser();\n console.log(`Already logged in as ${user.email}`);\n console.log(\"Run 'olakai logout' to log out first.\");\n return;\n } catch {\n // Token is invalid, continue with login\n }\n }\n\n console.log(`Logging in to Olakai (${getEnvironment()})...\\n`);\n\n try {\n // Request device code\n const deviceCode = await requestDeviceCode();\n\n // Display instructions\n console.log(\"To complete login, visit:\");\n console.log(`\\n ${deviceCode.verification_uri_complete}\\n`);\n console.log(`Or go to ${deviceCode.verification_uri} and enter code:`);\n console.log(`\\n ${deviceCode.user_code}\\n`);\n\n // Try to open browser\n console.log(\"Opening browser...\");\n try {\n await open(deviceCode.verification_uri_complete);\n } catch {\n console.log(\"(Could not open browser automatically)\");\n }\n\n console.log(\"\\nWaiting for authorization...\");\n\n // Poll for token\n const expiresAt = Date.now() + deviceCode.expires_in * 1000;\n\n while (Date.now() < expiresAt) {\n await sleep(POLL_INTERVAL_MS);\n\n try {\n const tokenResponse = await pollForToken(deviceCode.device_code);\n\n if (tokenResponse) {\n // Save token\n saveToken(tokenResponse.access_token, tokenResponse.expires_in);\n\n // Get user info\n const user = await getCurrentUser();\n\n console.log(`\\nLogged in as ${user.email}`);\n console.log(`Account: ${user.accountId}`);\n console.log(`Role: ${user.role}`);\n return;\n }\n\n // Still pending, show spinner\n process.stdout.write(\".\");\n } catch (error) {\n if (error instanceof Error) {\n console.error(`\\nLogin failed: ${error.message}`);\n } else {\n console.error(\"\\nLogin failed: Unknown error\");\n }\n process.exit(1);\n }\n }\n\n console.error(\"\\nLogin timed out. Please try again.\");\n process.exit(1);\n } catch (error) {\n if (error instanceof Error) {\n console.error(`Login failed: ${error.message}`);\n } else {\n console.error(\"Login failed: Unknown error\");\n }\n process.exit(1);\n }\n}\n\nfunction sleep(ms: number): Promise<void> {\n return new Promise((resolve) => setTimeout(resolve, ms));\n}\n","export type Environment = \"production\" | \"staging\" | \"local\";\n\nconst HOSTS: Record<Environment, string> = {\n production: \"https://app.olakai.ai\",\n staging: \"https://staging.app.olakai.ai\",\n local: \"http://localhost:3000\",\n};\n\n// CLI client identifier\nexport const CLIENT_ID = \"olakai-cli\";\n\nlet currentEnvironment: Environment = \"production\";\n\n/**\n * Set the current environment\n */\nexport function setEnvironment(env: Environment): void {\n currentEnvironment = env;\n}\n\n/**\n * Get the current environment from:\n * 1. Environment variable OLAKAI_ENV\n * 2. Programmatically set value\n * 3. Default to \"production\"\n */\nexport function getEnvironment(): Environment {\n const envVar = process.env.OLAKAI_ENV as Environment | undefined;\n if (envVar && isValidEnvironment(envVar)) {\n return envVar;\n }\n return currentEnvironment;\n}\n\n/**\n * Get the API base URL for the current environment\n */\nexport function getBaseUrl(): string {\n return HOSTS[getEnvironment()];\n}\n\n/**\n * Check if a string is a valid environment\n */\nexport function isValidEnvironment(env: string): env is Environment {\n return env === \"production\" || env === \"staging\" || env === \"local\";\n}\n\n/**\n * Get list of valid environments for CLI help\n */\nexport function getValidEnvironments(): Environment[] {\n return [\"production\", \"staging\", \"local\"];\n}\n","import * as fs from \"node:fs\";\nimport * as path from \"node:path\";\nimport * as os from \"node:os\";\nimport { type Environment, getEnvironment } from \"./config.js\";\n\ninterface StoredCredentials {\n token: string;\n expiresAt: number; // Unix timestamp in seconds\n environment: Environment;\n}\n\n/**\n * Get the credentials file path\n */\nfunction getCredentialsPath(): string {\n const configDir = path.join(os.homedir(), \".config\", \"olakai\");\n return path.join(configDir, \"credentials.json\");\n}\n\n/**\n * Ensure the config directory exists\n */\nfunction ensureConfigDir(): void {\n const configDir = path.dirname(getCredentialsPath());\n if (!fs.existsSync(configDir)) {\n fs.mkdirSync(configDir, { recursive: true, mode: 0o700 });\n }\n}\n\n/**\n * Save an access token to disk\n */\nexport function saveToken(token: string, expiresIn: number): void {\n ensureConfigDir();\n\n const credentials: StoredCredentials = {\n token,\n expiresAt: Math.floor(Date.now() / 1000) + expiresIn,\n environment: getEnvironment(),\n };\n\n const credentialsPath = getCredentialsPath();\n fs.writeFileSync(credentialsPath, JSON.stringify(credentials, null, 2), {\n mode: 0o600, // Read/write for owner only\n });\n}\n\n/**\n * Load the stored token\n */\nexport function loadToken(): StoredCredentials | null {\n const credentialsPath = getCredentialsPath();\n\n if (!fs.existsSync(credentialsPath)) {\n return null;\n }\n\n try {\n const content = fs.readFileSync(credentialsPath, \"utf-8\");\n const credentials = JSON.parse(content) as StoredCredentials;\n return credentials;\n } catch {\n return null;\n }\n}\n\n/**\n * Clear stored credentials\n */\nexport function clearToken(): void {\n const credentialsPath = getCredentialsPath();\n\n if (fs.existsSync(credentialsPath)) {\n fs.unlinkSync(credentialsPath);\n }\n}\n\n/**\n * Check if the stored token is valid (exists and not expired)\n */\nexport function isTokenValid(): boolean {\n const credentials = loadToken();\n\n if (!credentials) {\n return false;\n }\n\n // Check if expired (with 60 second buffer)\n const now = Math.floor(Date.now() / 1000);\n if (credentials.expiresAt <= now + 60) {\n return false;\n }\n\n // Check if environment matches\n if (credentials.environment !== getEnvironment()) {\n return false;\n }\n\n return true;\n}\n\n/**\n * Get the current valid token or null\n */\nexport function getValidToken(): string | null {\n if (!isTokenValid()) {\n return null;\n }\n\n const credentials = loadToken();\n return credentials?.token ?? null;\n}\n","import { getBaseUrl, CLIENT_ID } from \"./config.js\";\nimport { getValidToken } from \"./auth.js\";\n\nexport interface DeviceCodeResponse {\n device_code: string;\n user_code: string;\n verification_uri: string;\n verification_uri_complete: string;\n expires_in: number;\n interval: number;\n}\n\nexport interface TokenResponse {\n access_token: string;\n token_type: string;\n expires_in: number;\n}\n\nexport interface TokenErrorResponse {\n error: \"authorization_pending\" | \"expired_token\" | \"access_denied\";\n error_description?: string;\n}\n\nexport interface UserMeResponse {\n id: string;\n email: string;\n firstName: string;\n lastName: string;\n role: string;\n accountId: string;\n}\n\n// Config API Types\nexport interface AgentApiKey {\n id: string;\n key?: string; // Only present on creation\n keyMasked: string;\n isActive: boolean;\n createdAt?: string;\n}\n\nexport type DefaultAggregationMethod =\n | \"SUM\"\n | \"AVERAGE\"\n | \"COUNT\"\n | \"MIN\"\n | \"MAX\"\n | \"LATEST\";\n\nexport type KpiScope = \"PROMPT_REQUEST\" | \"CHAT\" | \"DOCUMENT\";\n\nexport interface KpiDefinition {\n id: string;\n name: string;\n description: string | null;\n type: \"PREDEFINED\" | \"USER_DEFINED\";\n category: string | null;\n agentId: string | null;\n scope: KpiScope;\n calculatorId: string;\n calculatorParams: Record<string, unknown> | null;\n unit: string | null;\n defaultAggregationMethod: DefaultAggregationMethod;\n isActive: boolean;\n createdAt?: string;\n updatedAt?: string;\n}\n\nexport interface CreateKpiPayload {\n name: string;\n description?: string;\n type?: \"PREDEFINED\" | \"USER_DEFINED\";\n category?: string;\n agentId?: string;\n scope: KpiScope;\n calculatorId: string;\n calculatorParams?: Record<string, unknown>;\n unit?: string;\n defaultAggregationMethod?: DefaultAggregationMethod;\n}\n\nexport interface UpdateKpiPayload {\n name?: string;\n description?: string | null;\n type?: \"PREDEFINED\" | \"USER_DEFINED\";\n category?: string | null;\n agentId?: string | null;\n scope?: KpiScope;\n calculatorId?: string;\n calculatorParams?: Record<string, unknown>;\n unit?: string | null;\n defaultAggregationMethod?: DefaultAggregationMethod;\n isActive?: boolean;\n}\n\nexport interface ContextVariable {\n name: string;\n description: string;\n type: \"string\" | \"number\" | \"boolean\";\n sampleValue?: string | number | boolean;\n source: \"shared\" | \"custom\";\n}\n\nexport interface FormulaValidationResult {\n valid: boolean;\n error?: string;\n type?: string | null;\n charIndex?: number;\n parsedFormula?: unknown;\n}\n\nexport interface Agent {\n id: string;\n name: string;\n description: string;\n role: \"WORKER\" | \"COORDINATOR\";\n source: \"SDK\" | \"AUTOMATION_PROVIDER\";\n workflowId: string | null;\n category: string | null;\n apiKey: AgentApiKey | null;\n kpiDefinitions?: KpiDefinition[];\n workflow?: Workflow | null;\n}\n\nexport interface Workflow {\n id: string;\n name: string;\n description: string | null;\n isActive: boolean;\n agentCount: number;\n agents?: Agent[];\n createdAt?: string;\n updatedAt?: string;\n}\n\nexport interface CreateAgentPayload {\n name: string;\n description?: string;\n role?: \"WORKER\" | \"COORDINATOR\";\n workflowId?: string;\n createApiKey?: boolean;\n category?: string;\n source?: string;\n}\n\nexport interface UpdateAgentPayload {\n name?: string;\n description?: string;\n role?: \"WORKER\" | \"COORDINATOR\";\n workflowId?: string | null;\n category?: string | null;\n}\n\nexport interface CreateWorkflowPayload {\n name: string;\n description?: string;\n}\n\nexport interface UpdateWorkflowPayload {\n name?: string;\n description?: string | null;\n isActive?: boolean;\n}\n\n/**\n * Request a device code to start the login flow\n */\nexport async function requestDeviceCode(): Promise<DeviceCodeResponse> {\n const response = await fetch(`${getBaseUrl()}/api/auth/device/code`, {\n method: \"POST\",\n headers: {\n \"Content-Type\": \"application/json\",\n },\n body: JSON.stringify({ client_id: CLIENT_ID }),\n });\n\n if (!response.ok) {\n const error = (await response.json()) as { error_description?: string; error?: string };\n throw new Error(error.error_description || error.error || \"Failed to request device code\");\n }\n\n return (await response.json()) as DeviceCodeResponse;\n}\n\n/**\n * Poll for token exchange\n * Returns the token response if approved, or throws an error\n */\nexport async function pollForToken(\n deviceCode: string,\n): Promise<TokenResponse | null> {\n const response = await fetch(`${getBaseUrl()}/api/auth/device/token`, {\n method: \"POST\",\n headers: {\n \"Content-Type\": \"application/json\",\n },\n body: JSON.stringify({\n grant_type: \"urn:ietf:params:oauth:grant-type:device_code\",\n device_code: deviceCode,\n client_id: CLIENT_ID,\n }),\n });\n\n const data = (await response.json()) as TokenResponse | TokenErrorResponse;\n\n if (!response.ok) {\n if (\"error\" in data && data.error === \"authorization_pending\") {\n return null; // Still waiting for user\n }\n const errorMsg = \"error_description\" in data ? data.error_description : (\"error\" in data ? data.error : \"Token exchange failed\");\n throw new Error(errorMsg || \"Token exchange failed\");\n }\n\n return data as TokenResponse;\n}\n\n/**\n * Get current user info\n */\nexport async function getCurrentUser(): Promise<UserMeResponse> {\n const token = getValidToken();\n\n if (!token) {\n throw new Error(\"Not logged in. Run 'olakai login' first.\");\n }\n\n const response = await fetch(`${getBaseUrl()}/api/user/me`, {\n headers: {\n Authorization: `Bearer ${token}`,\n },\n });\n\n if (!response.ok) {\n if (response.status === 401) {\n throw new Error(\"Session expired. Run 'olakai login' to authenticate again.\");\n }\n throw new Error(\"Failed to get user info\");\n }\n\n return (await response.json()) as UserMeResponse;\n}\n\n// ============================================\n// Config API - Agents\n// ============================================\n\n/**\n * List agents for the current account\n */\nexport async function listAgents(options?: {\n includeKpis?: boolean;\n}): Promise<Agent[]> {\n const token = getValidToken();\n if (!token) {\n throw new Error(\"Not logged in. Run 'olakai login' first.\");\n }\n\n const params = new URLSearchParams();\n if (options?.includeKpis) {\n params.set(\"includeKpis\", \"true\");\n }\n\n const url = `${getBaseUrl()}/api/config/agents${params.toString() ? `?${params}` : \"\"}`;\n const response = await fetch(url, {\n headers: {\n Authorization: `Bearer ${token}`,\n },\n });\n\n if (!response.ok) {\n if (response.status === 401) {\n throw new Error(\"Session expired. Run 'olakai login' to authenticate again.\");\n }\n const error = (await response.json()) as { error?: string };\n throw new Error(error.error || \"Failed to list agents\");\n }\n\n const data = (await response.json()) as { agents: Agent[] };\n return data.agents;\n}\n\n/**\n * Get a single agent by ID\n */\nexport async function getAgent(id: string): Promise<Agent> {\n const token = getValidToken();\n if (!token) {\n throw new Error(\"Not logged in. Run 'olakai login' first.\");\n }\n\n const response = await fetch(`${getBaseUrl()}/api/config/agents/${id}`, {\n headers: {\n Authorization: `Bearer ${token}`,\n },\n });\n\n if (!response.ok) {\n if (response.status === 401) {\n throw new Error(\"Session expired. Run 'olakai login' to authenticate again.\");\n }\n if (response.status === 404) {\n throw new Error(\"Agent not found\");\n }\n const error = (await response.json()) as { error?: string };\n throw new Error(error.error || \"Failed to get agent\");\n }\n\n return (await response.json()) as Agent;\n}\n\n/**\n * Create a new agent\n */\nexport async function createAgent(payload: CreateAgentPayload): Promise<Agent> {\n const token = getValidToken();\n if (!token) {\n throw new Error(\"Not logged in. Run 'olakai login' first.\");\n }\n\n const response = await fetch(`${getBaseUrl()}/api/config/agents`, {\n method: \"POST\",\n headers: {\n Authorization: `Bearer ${token}`,\n \"Content-Type\": \"application/json\",\n },\n body: JSON.stringify(payload),\n });\n\n if (!response.ok) {\n if (response.status === 401) {\n throw new Error(\"Session expired. Run 'olakai login' to authenticate again.\");\n }\n if (response.status === 409) {\n throw new Error(\"An agent with this name already exists\");\n }\n const error = (await response.json()) as { error?: string };\n throw new Error(error.error || \"Failed to create agent\");\n }\n\n return (await response.json()) as Agent;\n}\n\n/**\n * Update an agent\n */\nexport async function updateAgent(\n id: string,\n payload: UpdateAgentPayload,\n): Promise<Agent> {\n const token = getValidToken();\n if (!token) {\n throw new Error(\"Not logged in. Run 'olakai login' first.\");\n }\n\n const response = await fetch(`${getBaseUrl()}/api/config/agents/${id}`, {\n method: \"PUT\",\n headers: {\n Authorization: `Bearer ${token}`,\n \"Content-Type\": \"application/json\",\n },\n body: JSON.stringify(payload),\n });\n\n if (!response.ok) {\n if (response.status === 401) {\n throw new Error(\"Session expired. Run 'olakai login' to authenticate again.\");\n }\n if (response.status === 404) {\n throw new Error(\"Agent not found\");\n }\n if (response.status === 409) {\n throw new Error(\"An agent with this name already exists\");\n }\n const error = (await response.json()) as { error?: string };\n throw new Error(error.error || \"Failed to update agent\");\n }\n\n return (await response.json()) as Agent;\n}\n\n/**\n * Delete an agent\n */\nexport async function deleteAgent(id: string): Promise<void> {\n const token = getValidToken();\n if (!token) {\n throw new Error(\"Not logged in. Run 'olakai login' first.\");\n }\n\n const response = await fetch(`${getBaseUrl()}/api/config/agents/${id}`, {\n method: \"DELETE\",\n headers: {\n Authorization: `Bearer ${token}`,\n },\n });\n\n if (!response.ok) {\n if (response.status === 401) {\n throw new Error(\"Session expired. Run 'olakai login' to authenticate again.\");\n }\n if (response.status === 404) {\n throw new Error(\"Agent not found\");\n }\n const error = (await response.json()) as { error?: string };\n throw new Error(error.error || \"Failed to delete agent\");\n }\n}\n\n// ============================================\n// Config API - Workflows\n// ============================================\n\n/**\n * List workflows for the current account\n */\nexport async function listWorkflows(options?: {\n includeAgents?: boolean;\n includeInactive?: boolean;\n}): Promise<Workflow[]> {\n const token = getValidToken();\n if (!token) {\n throw new Error(\"Not logged in. Run 'olakai login' first.\");\n }\n\n const params = new URLSearchParams();\n if (options?.includeAgents) {\n params.set(\"includeAgents\", \"true\");\n }\n if (options?.includeInactive) {\n params.set(\"includeInactive\", \"true\");\n }\n\n const url = `${getBaseUrl()}/api/config/workflows${params.toString() ? `?${params}` : \"\"}`;\n const response = await fetch(url, {\n headers: {\n Authorization: `Bearer ${token}`,\n },\n });\n\n if (!response.ok) {\n if (response.status === 401) {\n throw new Error(\"Session expired. Run 'olakai login' to authenticate again.\");\n }\n const error = (await response.json()) as { error?: string };\n throw new Error(error.error || \"Failed to list workflows\");\n }\n\n const data = (await response.json()) as { workflows: Workflow[] };\n return data.workflows;\n}\n\n/**\n * Get a single workflow by ID\n */\nexport async function getWorkflow(id: string): Promise<Workflow> {\n const token = getValidToken();\n if (!token) {\n throw new Error(\"Not logged in. Run 'olakai login' first.\");\n }\n\n const response = await fetch(`${getBaseUrl()}/api/config/workflows/${id}`, {\n headers: {\n Authorization: `Bearer ${token}`,\n },\n });\n\n if (!response.ok) {\n if (response.status === 401) {\n throw new Error(\"Session expired. Run 'olakai login' to authenticate again.\");\n }\n if (response.status === 404) {\n throw new Error(\"Workflow not found\");\n }\n const error = (await response.json()) as { error?: string };\n throw new Error(error.error || \"Failed to get workflow\");\n }\n\n return (await response.json()) as Workflow;\n}\n\n/**\n * Create a new workflow\n */\nexport async function createWorkflow(\n payload: CreateWorkflowPayload,\n): Promise<Workflow> {\n const token = getValidToken();\n if (!token) {\n throw new Error(\"Not logged in. Run 'olakai login' first.\");\n }\n\n const response = await fetch(`${getBaseUrl()}/api/config/workflows`, {\n method: \"POST\",\n headers: {\n Authorization: `Bearer ${token}`,\n \"Content-Type\": \"application/json\",\n },\n body: JSON.stringify(payload),\n });\n\n if (!response.ok) {\n if (response.status === 401) {\n throw new Error(\"Session expired. Run 'olakai login' to authenticate again.\");\n }\n if (response.status === 409) {\n throw new Error(\"A workflow with this name already exists\");\n }\n const error = (await response.json()) as { error?: string };\n throw new Error(error.error || \"Failed to create workflow\");\n }\n\n return (await response.json()) as Workflow;\n}\n\n/**\n * Update a workflow\n */\nexport async function updateWorkflow(\n id: string,\n payload: UpdateWorkflowPayload,\n): Promise<Workflow> {\n const token = getValidToken();\n if (!token) {\n throw new Error(\"Not logged in. Run 'olakai login' first.\");\n }\n\n const response = await fetch(`${getBaseUrl()}/api/config/workflows/${id}`, {\n method: \"PUT\",\n headers: {\n Authorization: `Bearer ${token}`,\n \"Content-Type\": \"application/json\",\n },\n body: JSON.stringify(payload),\n });\n\n if (!response.ok) {\n if (response.status === 401) {\n throw new Error(\"Session expired. Run 'olakai login' to authenticate again.\");\n }\n if (response.status === 404) {\n throw new Error(\"Workflow not found\");\n }\n if (response.status === 409) {\n throw new Error(\"A workflow with this name already exists\");\n }\n const error = (await response.json()) as { error?: string };\n throw new Error(error.error || \"Failed to update workflow\");\n }\n\n return (await response.json()) as Workflow;\n}\n\n/**\n * Delete a workflow\n */\nexport async function deleteWorkflow(id: string): Promise<void> {\n const token = getValidToken();\n if (!token) {\n throw new Error(\"Not logged in. Run 'olakai login' first.\");\n }\n\n const response = await fetch(`${getBaseUrl()}/api/config/workflows/${id}`, {\n method: \"DELETE\",\n headers: {\n Authorization: `Bearer ${token}`,\n },\n });\n\n if (!response.ok) {\n if (response.status === 401) {\n throw new Error(\"Session expired. Run 'olakai login' to authenticate again.\");\n }\n if (response.status === 404) {\n throw new Error(\"Workflow not found\");\n }\n const error = (await response.json()) as { error?: string };\n throw new Error(error.error || \"Failed to delete workflow\");\n }\n}\n\n// ============================================\n// Config API - KPIs\n// ============================================\n\n/**\n * List KPI definitions for the current account\n */\nexport async function listKpis(options?: {\n agentId?: string;\n includeInactive?: boolean;\n}): Promise<KpiDefinition[]> {\n const token = getValidToken();\n if (!token) {\n throw new Error(\"Not logged in. Run 'olakai login' first.\");\n }\n\n const params = new URLSearchParams();\n if (options?.agentId) {\n params.set(\"agentId\", options.agentId);\n }\n if (options?.includeInactive) {\n params.set(\"includeInactive\", \"true\");\n }\n\n const url = `${getBaseUrl()}/api/config/kpis${params.toString() ? `?${params}` : \"\"}`;\n const response = await fetch(url, {\n headers: {\n Authorization: `Bearer ${token}`,\n },\n });\n\n if (!response.ok) {\n if (response.status === 401) {\n throw new Error(\"Session expired. Run 'olakai login' to authenticate again.\");\n }\n const error = (await response.json()) as { error?: string };\n throw new Error(error.error || \"Failed to list KPIs\");\n }\n\n const data = (await response.json()) as { kpiDefinitions: KpiDefinition[] };\n return data.kpiDefinitions;\n}\n\n/**\n * Get a single KPI definition by ID\n */\nexport async function getKpi(id: string): Promise<KpiDefinition> {\n const token = getValidToken();\n if (!token) {\n throw new Error(\"Not logged in. Run 'olakai login' first.\");\n }\n\n const response = await fetch(`${getBaseUrl()}/api/config/kpis/${id}`, {\n headers: {\n Authorization: `Bearer ${token}`,\n },\n });\n\n if (!response.ok) {\n if (response.status === 401) {\n throw new Error(\"Session expired. Run 'olakai login' to authenticate again.\");\n }\n if (response.status === 404) {\n throw new Error(\"KPI definition not found\");\n }\n const error = (await response.json()) as { error?: string };\n throw new Error(error.error || \"Failed to get KPI\");\n }\n\n return (await response.json()) as KpiDefinition;\n}\n\n/**\n * Create a new KPI definition\n */\nexport async function createKpi(payload: CreateKpiPayload): Promise<KpiDefinition> {\n const token = getValidToken();\n if (!token) {\n throw new Error(\"Not logged in. Run 'olakai login' first.\");\n }\n\n const response = await fetch(`${getBaseUrl()}/api/config/kpis`, {\n method: \"POST\",\n headers: {\n Authorization: `Bearer ${token}`,\n \"Content-Type\": \"application/json\",\n },\n body: JSON.stringify(payload),\n });\n\n if (!response.ok) {\n if (response.status === 401) {\n throw new Error(\"Session expired. Run 'olakai login' to authenticate again.\");\n }\n if (response.status === 409) {\n throw new Error(\"A KPI definition with this name already exists\");\n }\n const error = (await response.json()) as { error?: string };\n throw new Error(error.error || \"Failed to create KPI\");\n }\n\n return (await response.json()) as KpiDefinition;\n}\n\n/**\n * Update a KPI definition\n */\nexport async function updateKpi(\n id: string,\n payload: UpdateKpiPayload,\n): Promise<KpiDefinition> {\n const token = getValidToken();\n if (!token) {\n throw new Error(\"Not logged in. Run 'olakai login' first.\");\n }\n\n const response = await fetch(`${getBaseUrl()}/api/config/kpis/${id}`, {\n method: \"PUT\",\n headers: {\n Authorization: `Bearer ${token}`,\n \"Content-Type\": \"application/json\",\n },\n body: JSON.stringify(payload),\n });\n\n if (!response.ok) {\n if (response.status === 401) {\n throw new Error(\"Session expired. Run 'olakai login' to authenticate again.\");\n }\n if (response.status === 404) {\n throw new Error(\"KPI definition not found\");\n }\n if (response.status === 409) {\n throw new Error(\"A KPI definition with this name already exists\");\n }\n const error = (await response.json()) as { error?: string };\n throw new Error(error.error || \"Failed to update KPI\");\n }\n\n return (await response.json()) as KpiDefinition;\n}\n\n/**\n * Delete a KPI definition\n */\nexport async function deleteKpi(id: string): Promise<void> {\n const token = getValidToken();\n if (!token) {\n throw new Error(\"Not logged in. Run 'olakai login' first.\");\n }\n\n const response = await fetch(`${getBaseUrl()}/api/config/kpis/${id}`, {\n method: \"DELETE\",\n headers: {\n Authorization: `Bearer ${token}`,\n },\n });\n\n if (!response.ok) {\n if (response.status === 401) {\n throw new Error(\"Session expired. Run 'olakai login' to authenticate again.\");\n }\n if (response.status === 404) {\n throw new Error(\"KPI definition not found\");\n }\n const error = (await response.json()) as { error?: string };\n throw new Error(error.error || \"Failed to delete KPI\");\n }\n}\n\n/**\n * Get available context variables for KPI formulas\n */\nexport async function getKpiContextVariables(\n agentId?: string,\n scope?: KpiScope,\n): Promise<ContextVariable[]> {\n const token = getValidToken();\n if (!token) {\n throw new Error(\"Not logged in. Run 'olakai login' first.\");\n }\n\n const params = new URLSearchParams();\n if (agentId) {\n params.set(\"agentId\", agentId);\n }\n if (scope) {\n params.set(\"scope\", scope);\n }\n\n const url = `${getBaseUrl()}/api/config/kpis/context-variables${params.toString() ? `?${params}` : \"\"}`;\n const response = await fetch(url, {\n headers: {\n Authorization: `Bearer ${token}`,\n },\n });\n\n if (!response.ok) {\n if (response.status === 401) {\n throw new Error(\"Session expired. Run 'olakai login' to authenticate again.\");\n }\n const error = (await response.json()) as { error?: string };\n throw new Error(error.error || \"Failed to get context variables\");\n }\n\n const data = (await response.json()) as { contextVariables: ContextVariable[] };\n return data.contextVariables;\n}\n\n/**\n * Validate a KPI formula expression\n */\nexport async function validateKpiFormula(\n formula: string,\n agentId?: string,\n scope?: KpiScope,\n): Promise<FormulaValidationResult> {\n const token = getValidToken();\n if (!token) {\n throw new Error(\"Not logged in. Run 'olakai login' first.\");\n }\n\n const body: Record<string, string | undefined> = { formula, agentId };\n if (scope) {\n body.scope = scope;\n }\n\n const response = await fetch(`${getBaseUrl()}/api/config/kpis/validate`, {\n method: \"POST\",\n headers: {\n Authorization: `Bearer ${token}`,\n \"Content-Type\": \"application/json\",\n },\n body: JSON.stringify(body),\n });\n\n if (!response.ok) {\n if (response.status === 401) {\n throw new Error(\"Session expired. Run 'olakai login' to authenticate again.\");\n }\n const error = (await response.json()) as { error?: string };\n throw new Error(error.error || \"Failed to validate formula\");\n }\n\n return (await response.json()) as FormulaValidationResult;\n}\n\n// ============================================\n// Activity API - Prompt Inspection\n// ============================================\n\nexport interface ActivityPrompt {\n id: string;\n createdAt: string;\n agentId: string | null;\n agentName?: string | null;\n workflowId: string | null;\n workflowName?: string | null;\n taskExecutionId?: string | null;\n app: string;\n modelType: string | null;\n modelId: string | null;\n tokens: number;\n requestTime: number;\n isHighRisk: boolean;\n blocked: boolean;\n decorationStatus: string;\n sensitivity: string[];\n prompt?: string;\n response?: string;\n analytics?: {\n task: string | null;\n subtask: string | null;\n timesaved_minutes: number | null;\n riskassessment_dangerousity: number | null;\n };\n kpiData?: Record<string, unknown>;\n}\n\nexport interface ActivityListResponse {\n prompts: ActivityPrompt[];\n total: number;\n limit: number;\n offset: number;\n hasMore: boolean;\n}\n\nexport interface ActivityListOptions {\n agentId?: string;\n workflowId?: string;\n since?: string;\n until?: string;\n limit?: number;\n offset?: number;\n includeContent?: boolean;\n includeAnalytics?: boolean;\n}\n\nexport interface CoreKpiValue {\n name: string;\n value: number;\n measurement: \"count\" | \"ratio\" | \"sum\";\n unitPrefix?: string;\n unitSuffix?: string;\n}\n\nexport interface AggregatedKpi {\n kpiDefinitionId: string;\n name: string;\n value: number | null;\n aggregationMethod: string;\n unit: string | null;\n dataPointCount: number;\n}\n\nexport interface PeriodKpiData {\n periodStart: string;\n periodEnd: string;\n coreKpis: CoreKpiValue[];\n}\n\nexport interface KpiAtom {\n promptRequestId: string;\n createdAt: string;\n kpis: Record<string, unknown>;\n}\n\nexport interface ActivityKpisResponse {\n coreKpis: CoreKpiValue[];\n kpis: AggregatedKpi[];\n periodData?: PeriodKpiData[];\n atoms?: KpiAtom[];\n}\n\nexport interface ActivityKpisOptions {\n agentId?: string;\n workflowId?: string;\n since?: string;\n until?: string;\n period?: \"hourly\" | \"daily\" | \"weekly\";\n includeAtoms?: boolean;\n}\n\n/**\n * List activity prompts with filters\n */\nexport async function listActivity(\n options: ActivityListOptions = {}\n): Promise<ActivityListResponse> {\n const token = getValidToken();\n if (!token) {\n throw new Error(\"Not logged in. Run 'olakai login' first.\");\n }\n\n const params = new URLSearchParams();\n if (options.agentId) params.set(\"agentId\", options.agentId);\n if (options.workflowId) params.set(\"workflowId\", options.workflowId);\n if (options.since) params.set(\"since\", options.since);\n if (options.until) params.set(\"until\", options.until);\n if (options.limit !== undefined) params.set(\"limit\", String(options.limit));\n if (options.offset !== undefined) params.set(\"offset\", String(options.offset));\n if (options.includeContent) params.set(\"includeContent\", \"true\");\n if (options.includeAnalytics) params.set(\"includeAnalytics\", \"true\");\n\n const url = `${getBaseUrl()}/api/activity/prompts${params.toString() ? `?${params}` : \"\"}`;\n const response = await fetch(url, {\n headers: {\n Authorization: `Bearer ${token}`,\n },\n });\n\n if (!response.ok) {\n if (response.status === 401) {\n throw new Error(\"Session expired. Run 'olakai login' to authenticate again.\");\n }\n const error = (await response.json()) as { error?: string };\n throw new Error(error.error || \"Failed to list activity\");\n }\n\n return (await response.json()) as ActivityListResponse;\n}\n\n/**\n * Get a single activity prompt by ID\n */\nexport async function getActivity(\n id: string,\n includeContent?: boolean\n): Promise<ActivityPrompt> {\n const token = getValidToken();\n if (!token) {\n throw new Error(\"Not logged in. Run 'olakai login' first.\");\n }\n\n const params = new URLSearchParams();\n if (includeContent) params.set(\"includeContent\", \"true\");\n\n const url = `${getBaseUrl()}/api/activity/prompts/${id}${params.toString() ? `?${params}` : \"\"}`;\n const response = await fetch(url, {\n headers: {\n Authorization: `Bearer ${token}`,\n },\n });\n\n if (!response.ok) {\n if (response.status === 401) {\n throw new Error(\"Session expired. Run 'olakai login' to authenticate again.\");\n }\n if (response.status === 404) {\n throw new Error(\"Prompt request not found\");\n }\n const error = (await response.json()) as { error?: string };\n throw new Error(error.error || \"Failed to get activity\");\n }\n\n return (await response.json()) as ActivityPrompt;\n}\n\n/**\n * Get aggregated KPI values for an agent or workflow\n */\nexport async function getActivityKpis(\n options: ActivityKpisOptions\n): Promise<ActivityKpisResponse> {\n const token = getValidToken();\n if (!token) {\n throw new Error(\"Not logged in. Run 'olakai login' first.\");\n }\n\n if (!options.agentId && !options.workflowId) {\n throw new Error(\"Either agentId or workflowId is required\");\n }\n\n const params = new URLSearchParams();\n if (options.agentId) params.set(\"agentId\", options.agentId);\n if (options.workflowId) params.set(\"workflowId\", options.workflowId);\n if (options.since) params.set(\"since\", options.since);\n if (options.until) params.set(\"until\", options.until);\n if (options.period) params.set(\"period\", options.period);\n if (options.includeAtoms) params.set(\"includeAtoms\", \"true\");\n\n const url = `${getBaseUrl()}/api/activity/kpis${params.toString() ? `?${params}` : \"\"}`;\n const response = await fetch(url, {\n headers: {\n Authorization: `Bearer ${token}`,\n },\n });\n\n if (!response.ok) {\n if (response.status === 401) {\n throw new Error(\"Session expired. Run 'olakai login' to authenticate again.\");\n }\n const error = (await response.json()) as { error?: string };\n throw new Error(error.error || \"Failed to get activity KPIs\");\n }\n\n return (await response.json()) as ActivityKpisResponse;\n}\n\n// ============================================\n// Activity API - Session Diagnostics\n// ============================================\n\nexport interface SessionDiagnostic {\n id: string;\n createdAt: string;\n agentId: string | null;\n decorationStatus: string;\n decorationDate: string | null;\n decorationCandidate: boolean;\n decorationError: string | null;\n decorationErrorStreak: number;\n decoratorVersion: string | null;\n hasKpiData: boolean;\n}\n\nexport interface SessionsListResponse {\n sessions: SessionDiagnostic[];\n summary: {\n sessionCount: number;\n byStatus: Record<string, number>;\n };\n total: number;\n limit: number;\n offset: number;\n hasMore: boolean;\n}\n\nexport interface SessionsListOptions {\n agentId: string;\n since?: string;\n until?: string;\n limit?: number;\n offset?: number;\n}\n\n/**\n * List session diagnostics for an agent\n */\nexport async function listSessions(\n options: SessionsListOptions,\n): Promise<SessionsListResponse> {\n const token = getValidToken();\n if (!token) {\n throw new Error(\"Not logged in. Run 'olakai login' first.\");\n }\n\n const params = new URLSearchParams();\n params.set(\"agentId\", options.agentId);\n if (options.since) params.set(\"since\", options.since);\n if (options.until) params.set(\"until\", options.until);\n if (options.limit !== undefined) params.set(\"limit\", String(options.limit));\n if (options.offset !== undefined) params.set(\"offset\", String(options.offset));\n\n const url = `${getBaseUrl()}/api/activity/sessions?${params}`;\n const response = await fetch(url, {\n headers: {\n Authorization: `Bearer ${token}`,\n },\n });\n\n if (!response.ok) {\n if (response.status === 401) {\n throw new Error(\"Session expired. Run 'olakai login' to authenticate again.\");\n }\n const error = (await response.json()) as { error?: string };\n throw new Error(error.error || \"Failed to list sessions\");\n }\n\n return (await response.json()) as SessionsListResponse;\n}\n\n// Custom Data Config Types\nexport type CustomDataType = \"STRING\" | \"NUMBER\" | \"BOOLEAN\";\n\nexport interface CustomDataConfig {\n id: string;\n accountId: string;\n agentId: string | null; // NULL means legacy account-level config\n name: string;\n description: string | null;\n type: CustomDataType;\n createdAt?: string;\n updatedAt?: string;\n}\n\nexport interface CreateCustomDataPayload {\n agentId: string; // Required for new configs\n name: string;\n description?: string | null;\n type: CustomDataType;\n}\n\nexport interface UpdateCustomDataPayload {\n name?: string;\n description?: string | null;\n type?: CustomDataType;\n // Note: agentId is not updatable after creation\n}\n\n/**\n * List custom data configurations\n * @param agentId - Optional agent ID to filter by. If provided, returns agent-specific configs\n * merged with legacy account-level configs. If omitted, returns all account configs.\n */\nexport async function listCustomDataConfigs(agentId?: string): Promise<CustomDataConfig[]> {\n const token = getValidToken();\n if (!token) {\n throw new Error(\"Not logged in. Run 'olakai login' first.\");\n }\n\n const params = new URLSearchParams();\n if (agentId) {\n params.set(\"agentId\", agentId);\n }\n\n const url = `${getBaseUrl()}/api/config/custom-data${params.toString() ? `?${params}` : \"\"}`;\n const response = await fetch(url, {\n headers: {\n Authorization: `Bearer ${token}`,\n },\n });\n\n if (!response.ok) {\n if (response.status === 401) {\n throw new Error(\"Session expired. Run 'olakai login' to authenticate again.\");\n }\n const error = (await response.json()) as { error?: string };\n throw new Error(error.error || \"Failed to list custom data configurations\");\n }\n\n const data = (await response.json()) as { customDataConfigs: CustomDataConfig[] };\n return data.customDataConfigs;\n}\n\n/**\n * Get a single custom data configuration\n */\nexport async function getCustomDataConfig(id: string): Promise<CustomDataConfig> {\n const token = getValidToken();\n if (!token) {\n throw new Error(\"Not logged in. Run 'olakai login' first.\");\n }\n\n const url = `${getBaseUrl()}/api/config/custom-data/${encodeURIComponent(id)}`;\n const response = await fetch(url, {\n headers: {\n Authorization: `Bearer ${token}`,\n },\n });\n\n if (!response.ok) {\n if (response.status === 401) {\n throw new Error(\"Session expired. Run 'olakai login' to authenticate again.\");\n }\n if (response.status === 404) {\n throw new Error(\"Custom data configuration not found\");\n }\n const error = (await response.json()) as { error?: string };\n throw new Error(error.error || \"Failed to get custom data configuration\");\n }\n\n return (await response.json()) as CustomDataConfig;\n}\n\n/**\n * Create a new custom data configuration\n */\nexport async function createCustomDataConfig(\n payload: CreateCustomDataPayload\n): Promise<CustomDataConfig> {\n const token = getValidToken();\n if (!token) {\n throw new Error(\"Not logged in. Run 'olakai login' first.\");\n }\n\n const url = `${getBaseUrl()}/api/config/custom-data`;\n const response = await fetch(url, {\n method: \"POST\",\n headers: {\n Authorization: `Bearer ${token}`,\n \"Content-Type\": \"application/json\",\n },\n body: JSON.stringify(payload),\n });\n\n if (!response.ok) {\n if (response.status === 401) {\n throw new Error(\"Session expired. Run 'olakai login' to authenticate again.\");\n }\n if (response.status === 409) {\n throw new Error(\"A custom data configuration with this name already exists\");\n }\n const error = (await response.json()) as { error?: string };\n throw new Error(error.error || \"Failed to create custom data configuration\");\n }\n\n return (await response.json()) as CustomDataConfig;\n}\n\n/**\n * Update a custom data configuration\n */\nexport async function updateCustomDataConfig(\n id: string,\n payload: UpdateCustomDataPayload\n): Promise<CustomDataConfig> {\n const token = getValidToken();\n if (!token) {\n throw new Error(\"Not logged in. Run 'olakai login' first.\");\n }\n\n const url = `${getBaseUrl()}/api/config/custom-data/${encodeURIComponent(id)}`;\n const response = await fetch(url, {\n method: \"PUT\",\n headers: {\n Authorization: `Bearer ${token}`,\n \"Content-Type\": \"application/json\",\n },\n body: JSON.stringify(payload),\n });\n\n if (!response.ok) {\n if (response.status === 401) {\n throw new Error(\"Session expired. Run 'olakai login' to authenticate again.\");\n }\n if (response.status === 404) {\n throw new Error(\"Custom data configuration not found\");\n }\n if (response.status === 409) {\n throw new Error(\"A custom data configuration with this name already exists\");\n }\n const error = (await response.json()) as { error?: string };\n throw new Error(error.error || \"Failed to update custom data configuration\");\n }\n\n return (await response.json()) as CustomDataConfig;\n}\n\n/**\n * Delete a custom data configuration\n */\nexport async function deleteCustomDataConfig(id: string): Promise<void> {\n const token = getValidToken();\n if (!token) {\n throw new Error(\"Not logged in. Run 'olakai login' first.\");\n }\n\n const url = `${getBaseUrl()}/api/config/custom-data/${encodeURIComponent(id)}`;\n const response = await fetch(url, {\n method: \"DELETE\",\n headers: {\n Authorization: `Bearer ${token}`,\n },\n });\n\n if (!response.ok) {\n if (response.status === 401) {\n throw new Error(\"Session expired. Run 'olakai login' to authenticate again.\");\n }\n if (response.status === 404) {\n throw new Error(\"Custom data configuration not found\");\n }\n const error = (await response.json()) as { error?: string };\n throw new Error(error.error || \"Failed to delete custom data configuration\");\n }\n}\n","import { clearToken, isTokenValid } from \"../lib/auth.js\";\n\n/**\n * Logout command handler\n */\nexport function logoutCommand(): void {\n if (!isTokenValid()) {\n console.log(\"Not currently logged in.\");\n return;\n }\n\n clearToken();\n console.log(\"Logged out successfully.\");\n}\n","import { getCurrentUser } from \"../lib/api.js\";\nimport { isTokenValid } from \"../lib/auth.js\";\nimport { getEnvironment } from \"../lib/config.js\";\n\n/**\n * Whoami command handler\n */\nexport async function whoamiCommand(): Promise<void> {\n if (!isTokenValid()) {\n console.log(\"Not logged in. Run 'olakai login' to authenticate.\");\n process.exit(1);\n }\n\n try {\n const user = await getCurrentUser();\n\n console.log(`Email: ${user.email}`);\n console.log(`Name: ${user.firstName} ${user.lastName}`);\n console.log(`Role: ${user.role}`);\n console.log(`Account ID: ${user.accountId}`);\n console.log(`Environment: ${getEnvironment()}`);\n } catch (error) {\n if (error instanceof Error) {\n console.error(`Error: ${error.message}`);\n } else {\n console.error(\"Failed to get user info\");\n }\n process.exit(1);\n }\n}\n","import { Command } from \"commander\";\nimport {\n listAgents,\n getAgent,\n createAgent,\n updateAgent,\n deleteAgent,\n type Agent,\n} from \"../lib/api.js\";\n\nfunction formatAgentTable(agents: Agent[]): void {\n if (agents.length === 0) {\n console.log(\"No agents found.\");\n return;\n }\n\n // Calculate column widths\n const headers = [\"ID\", \"NAME\", \"ROLE\", \"WORKFLOW\", \"API KEY\"];\n const rows = agents.map((agent) => [\n agent.id.slice(0, 12) + \"...\",\n agent.name.slice(0, 30),\n agent.role,\n agent.workflowId ? agent.workflowId.slice(0, 12) + \"...\" : \"-\",\n agent.apiKey ? (agent.apiKey.isActive ? \"Active\" : \"Inactive\") : \"None\",\n ]);\n\n const widths = headers.map((h, i) =>\n Math.max(h.length, ...rows.map((r) => r[i].length))\n );\n\n // Print header\n console.log(headers.map((h, i) => h.padEnd(widths[i])).join(\" \"));\n console.log(widths.map((w) => \"-\".repeat(w)).join(\" \"));\n\n // Print rows\n for (const row of rows) {\n console.log(row.map((cell, i) => cell.padEnd(widths[i])).join(\" \"));\n }\n}\n\nfunction formatAgentDetail(agent: Agent): void {\n console.log(`ID: ${agent.id}`);\n console.log(`Name: ${agent.name}`);\n console.log(`Description: ${agent.description || \"-\"}`);\n console.log(`Role: ${agent.role}`);\n console.log(`Source: ${agent.source}`);\n console.log(`Category: ${agent.category || \"-\"}`);\n console.log(`Workflow ID: ${agent.workflowId || \"-\"}`);\n\n if (agent.workflow) {\n console.log(`Workflow: ${agent.workflow.name}`);\n }\n\n console.log(\"\");\n console.log(\"API Key:\");\n if (agent.apiKey) {\n console.log(` ID: ${agent.apiKey.id}`);\n if (agent.apiKey.key) {\n console.log(` Key: ${agent.apiKey.key}`);\n } else {\n console.log(` Key: ${agent.apiKey.keyMasked}`);\n }\n console.log(` Status: ${agent.apiKey.isActive ? \"Active\" : \"Inactive\"}`);\n } else {\n console.log(\" None\");\n }\n\n if (agent.kpiDefinitions && agent.kpiDefinitions.length > 0) {\n console.log(\"\");\n console.log(\"KPI Definitions:\");\n for (const kpi of agent.kpiDefinitions) {\n console.log(` - ${kpi.name} (${kpi.type})`);\n }\n }\n}\n\nasync function listCommand(options: {\n json?: boolean;\n includeKpis?: boolean;\n}): Promise<void> {\n try {\n const agents = await listAgents({ includeKpis: options.includeKpis });\n\n if (options.json) {\n console.log(JSON.stringify(agents, null, 2));\n } else {\n formatAgentTable(agents);\n }\n } catch (error) {\n console.error(\n `Error: ${error instanceof Error ? error.message : \"Unknown error\"}`\n );\n process.exit(1);\n }\n}\n\nasync function getCommand(id: string, options: { json?: boolean }): Promise<void> {\n try {\n const agent = await getAgent(id);\n\n if (options.json) {\n console.log(JSON.stringify(agent, null, 2));\n } else {\n formatAgentDetail(agent);\n }\n } catch (error) {\n console.error(\n `Error: ${error instanceof Error ? error.message : \"Unknown error\"}`\n );\n process.exit(1);\n }\n}\n\nasync function createCommand(options: {\n name: string;\n description?: string;\n role?: string;\n workflow?: string;\n withApiKey?: boolean;\n category?: string;\n json?: boolean;\n}): Promise<void> {\n try {\n if (!options.name) {\n console.error(\"Error: --name is required\");\n process.exit(1);\n }\n\n const agent = await createAgent({\n name: options.name,\n description: options.description || \"\",\n role: (options.role as \"WORKER\" | \"COORDINATOR\") || \"WORKER\",\n workflowId: options.workflow,\n createApiKey: options.withApiKey || false,\n category: options.category,\n });\n\n if (options.json) {\n console.log(JSON.stringify(agent, null, 2));\n } else {\n console.log(\"Agent created successfully!\");\n console.log(\"\");\n formatAgentDetail(agent);\n\n if (agent.apiKey?.key) {\n console.log(\"\");\n console.log(\n \"IMPORTANT: Save your API key now. It will not be shown again.\"\n );\n }\n }\n } catch (error) {\n console.error(\n `Error: ${error instanceof Error ? error.message : \"Unknown error\"}`\n );\n process.exit(1);\n }\n}\n\nasync function updateCommand(\n id: string,\n options: {\n name?: string;\n description?: string;\n role?: string;\n workflow?: string;\n category?: string;\n json?: boolean;\n }\n): Promise<void> {\n try {\n const payload: {\n name?: string;\n description?: string;\n role?: \"WORKER\" | \"COORDINATOR\";\n workflowId?: string | null;\n category?: string | null;\n } = {};\n\n if (options.name !== undefined) payload.name = options.name;\n if (options.description !== undefined)\n payload.description = options.description;\n if (options.role !== undefined)\n payload.role = options.role as \"WORKER\" | \"COORDINATOR\";\n if (options.workflow !== undefined) payload.workflowId = options.workflow;\n if (options.category !== undefined) payload.category = options.category;\n\n if (Object.keys(payload).length === 0) {\n console.error(\"Error: At least one field to update is required\");\n process.exit(1);\n }\n\n const agent = await updateAgent(id, payload);\n\n if (options.json) {\n console.log(JSON.stringify(agent, null, 2));\n } else {\n console.log(\"Agent updated successfully!\");\n console.log(\"\");\n formatAgentDetail(agent);\n }\n } catch (error) {\n console.error(\n `Error: ${error instanceof Error ? error.message : \"Unknown error\"}`\n );\n process.exit(1);\n }\n}\n\nasync function deleteCommand(\n id: string,\n options: { force?: boolean }\n): Promise<void> {\n try {\n if (!options.force) {\n // In a real CLI, we'd use readline for confirmation\n // For now, require --force flag\n console.log(\"Are you sure you want to delete this agent?\");\n console.log(\"Use --force to confirm deletion.\");\n process.exit(1);\n }\n\n await deleteAgent(id);\n console.log(\"Agent deleted successfully.\");\n } catch (error) {\n console.error(\n `Error: ${error instanceof Error ? error.message : \"Unknown error\"}`\n );\n process.exit(1);\n }\n}\n\nexport function registerAgentsCommand(program: Command): void {\n const agents = program\n .command(\"agents\")\n .description(\"Manage agents\");\n\n agents\n .command(\"list\")\n .description(\"List all agents\")\n .option(\"--json\", \"Output as JSON\")\n .option(\"--include-kpis\", \"Include KPI definitions\")\n .action(listCommand);\n\n agents\n .command(\"get <id>\")\n .description(\"Get agent details\")\n .option(\"--json\", \"Output as JSON\")\n .action(getCommand);\n\n agents\n .command(\"create\")\n .description(\"Create a new agent\")\n .requiredOption(\"--name <name>\", \"Agent name\")\n .option(\"--description <description>\", \"Agent description\")\n .option(\"--role <role>\", \"Agent role (WORKER or COORDINATOR)\", \"WORKER\")\n .option(\"--workflow <id>\", \"Workflow ID to assign\")\n .option(\"--with-api-key\", \"Create an API key for this agent\")\n .option(\"--category <category>\", \"Agent category\")\n .option(\"--json\", \"Output as JSON\")\n .action(createCommand);\n\n agents\n .command(\"update <id>\")\n .description(\"Update an agent\")\n .option(\"--name <name>\", \"Agent name\")\n .option(\"--description <description>\", \"Agent description\")\n .option(\"--role <role>\", \"Agent role (WORKER or COORDINATOR)\")\n .option(\"--workflow <id>\", \"Workflow ID to assign\")\n .option(\"--category <category>\", \"Agent category\")\n .option(\"--json\", \"Output as JSON\")\n .action(updateCommand);\n\n agents\n .command(\"delete <id>\")\n .description(\"Delete an agent\")\n .option(\"--force\", \"Skip confirmation\")\n .action(deleteCommand);\n}\n","import { Command } from \"commander\";\nimport {\n listWorkflows,\n getWorkflow,\n createWorkflow,\n updateWorkflow,\n deleteWorkflow,\n type Workflow,\n} from \"../lib/api.js\";\n\nfunction formatWorkflowTable(workflows: Workflow[]): void {\n if (workflows.length === 0) {\n console.log(\"No workflows found.\");\n return;\n }\n\n // Calculate column widths\n const headers = [\"ID\", \"NAME\", \"AGENTS\", \"STATUS\"];\n const rows = workflows.map((wf) => [\n wf.id.slice(0, 12) + \"...\",\n wf.name.slice(0, 30),\n wf.agentCount.toString(),\n wf.isActive ? \"Active\" : \"Inactive\",\n ]);\n\n const widths = headers.map((h, i) =>\n Math.max(h.length, ...rows.map((r) => r[i].length))\n );\n\n // Print header\n console.log(headers.map((h, i) => h.padEnd(widths[i])).join(\" \"));\n console.log(widths.map((w) => \"-\".repeat(w)).join(\" \"));\n\n // Print rows\n for (const row of rows) {\n console.log(row.map((cell, i) => cell.padEnd(widths[i])).join(\" \"));\n }\n}\n\nfunction formatWorkflowDetail(workflow: Workflow): void {\n console.log(`ID: ${workflow.id}`);\n console.log(`Name: ${workflow.name}`);\n console.log(`Description: ${workflow.description || \"-\"}`);\n console.log(`Status: ${workflow.isActive ? \"Active\" : \"Inactive\"}`);\n console.log(`Agents: ${workflow.agentCount}`);\n if (workflow.createdAt) {\n console.log(`Created: ${new Date(workflow.createdAt).toISOString()}`);\n }\n if (workflow.updatedAt) {\n console.log(`Updated: ${new Date(workflow.updatedAt).toISOString()}`);\n }\n\n if (workflow.agents && workflow.agents.length > 0) {\n console.log(\"\");\n console.log(\"Agents:\");\n for (const agent of workflow.agents) {\n const apiKeyStatus = agent.apiKey\n ? agent.apiKey.isActive\n ? \"API Key: Active\"\n : \"API Key: Inactive\"\n : \"No API Key\";\n console.log(` - ${agent.name} (${agent.role}) - ${apiKeyStatus}`);\n }\n }\n}\n\nasync function listCommand(options: {\n json?: boolean;\n includeAgents?: boolean;\n includeInactive?: boolean;\n}): Promise<void> {\n try {\n const workflows = await listWorkflows({\n includeAgents: options.includeAgents,\n includeInactive: options.includeInactive,\n });\n\n if (options.json) {\n console.log(JSON.stringify(workflows, null, 2));\n } else {\n formatWorkflowTable(workflows);\n }\n } catch (error) {\n console.error(\n `Error: ${error instanceof Error ? error.message : \"Unknown error\"}`\n );\n process.exit(1);\n }\n}\n\nasync function getCommand(id: string, options: { json?: boolean }): Promise<void> {\n try {\n const workflow = await getWorkflow(id);\n\n if (options.json) {\n console.log(JSON.stringify(workflow, null, 2));\n } else {\n formatWorkflowDetail(workflow);\n }\n } catch (error) {\n console.error(\n `Error: ${error instanceof Error ? error.message : \"Unknown error\"}`\n );\n process.exit(1);\n }\n}\n\nasync function createCommand(options: {\n name: string;\n description?: string;\n json?: boolean;\n}): Promise<void> {\n try {\n if (!options.name) {\n console.error(\"Error: --name is required\");\n process.exit(1);\n }\n\n const workflow = await createWorkflow({\n name: options.name,\n description: options.description,\n });\n\n if (options.json) {\n console.log(JSON.stringify(workflow, null, 2));\n } else {\n console.log(\"Workflow created successfully!\");\n console.log(\"\");\n formatWorkflowDetail(workflow);\n }\n } catch (error) {\n console.error(\n `Error: ${error instanceof Error ? error.message : \"Unknown error\"}`\n );\n process.exit(1);\n }\n}\n\nasync function updateCommand(\n id: string,\n options: {\n name?: string;\n description?: string;\n active?: boolean;\n inactive?: boolean;\n json?: boolean;\n }\n): Promise<void> {\n try {\n const payload: {\n name?: string;\n description?: string | null;\n isActive?: boolean;\n } = {};\n\n if (options.name !== undefined) payload.name = options.name;\n if (options.description !== undefined)\n payload.description = options.description;\n if (options.active) payload.isActive = true;\n if (options.inactive) payload.isActive = false;\n\n if (Object.keys(payload).length === 0) {\n console.error(\"Error: At least one field to update is required\");\n process.exit(1);\n }\n\n const workflow = await updateWorkflow(id, payload);\n\n if (options.json) {\n console.log(JSON.stringify(workflow, null, 2));\n } else {\n console.log(\"Workflow updated successfully!\");\n console.log(\"\");\n formatWorkflowDetail(workflow);\n }\n } catch (error) {\n console.error(\n `Error: ${error instanceof Error ? error.message : \"Unknown error\"}`\n );\n process.exit(1);\n }\n}\n\nasync function deleteCommand(\n id: string,\n options: { force?: boolean }\n): Promise<void> {\n try {\n if (!options.force) {\n // In a real CLI, we'd use readline for confirmation\n // For now, require --force flag\n console.log(\"Are you sure you want to delete this workflow?\");\n console.log(\"Use --force to confirm deletion.\");\n process.exit(1);\n }\n\n await deleteWorkflow(id);\n console.log(\"Workflow deleted successfully.\");\n } catch (error) {\n console.error(\n `Error: ${error instanceof Error ? error.message : \"Unknown error\"}`\n );\n process.exit(1);\n }\n}\n\nexport function registerWorkflowsCommand(program: Command): void {\n const workflows = program\n .command(\"workflows\")\n .description(\"Manage workflows\");\n\n workflows\n .command(\"list\")\n .description(\"List all workflows\")\n .option(\"--json\", \"Output as JSON\")\n .option(\"--include-agents\", \"Include agent details\")\n .option(\"--include-inactive\", \"Include inactive workflows\")\n .action(listCommand);\n\n workflows\n .command(\"get <id>\")\n .description(\"Get workflow details\")\n .option(\"--json\", \"Output as JSON\")\n .action(getCommand);\n\n workflows\n .command(\"create\")\n .description(\"Create a new workflow\")\n .requiredOption(\"--name <name>\", \"Workflow name\")\n .option(\"--description <description>\", \"Workflow description\")\n .option(\"--json\", \"Output as JSON\")\n .action(createCommand);\n\n workflows\n .command(\"update <id>\")\n .description(\"Update a workflow\")\n .option(\"--name <name>\", \"Workflow name\")\n .option(\"--description <description>\", \"Workflow description\")\n .option(\"--active\", \"Set workflow as active\")\n .option(\"--inactive\", \"Set workflow as inactive\")\n .option(\"--json\", \"Output as JSON\")\n .action(updateCommand);\n\n workflows\n .command(\"delete <id>\")\n .description(\"Delete a workflow\")\n .option(\"--force\", \"Skip confirmation\")\n .action(deleteCommand);\n}\n","import { Command } from \"commander\";\nimport {\n listKpis,\n getKpi,\n createKpi,\n updateKpi,\n deleteKpi,\n getKpiContextVariables,\n validateKpiFormula,\n type KpiDefinition,\n type KpiScope,\n type ContextVariable,\n type CreateKpiPayload,\n type DefaultAggregationMethod,\n} from \"../lib/api.js\";\n\nconst AGGREGATION_METHODS: DefaultAggregationMethod[] = [\n \"SUM\",\n \"AVERAGE\",\n \"COUNT\",\n \"MIN\",\n \"MAX\",\n \"LATEST\",\n];\n\nconst CALCULATOR_IDS = [\"formula\", \"classifier\", \"llm-data\"];\n\nconst KPI_SCOPES: KpiScope[] = [\"PROMPT_REQUEST\", \"CHAT\", \"DOCUMENT\"];\n\n// Classifier template definitions — mirrors CLASSIFIER_TEMPLATES from\n// localnode-app/packages/config/classifier-templates.ts\ntype OutputClassOption = { label: string; value: number };\n\ntype ClassifierTemplate = {\n id: string;\n name: string;\n description: string;\n promptTemplate: string;\n defaultUnit: string;\n defaultOutputClasses: OutputClassOption[];\n};\n\nconst CLASSIFIER_TEMPLATES: ClassifierTemplate[] = [\n {\n id: \"sentiment_scorer\",\n name: \"Sentiment Scorer\",\n description:\n \"Scores the overall emotional tone and user satisfaction of a conversation\",\n defaultUnit: \"score\",\n promptTemplate: `Analyze the overall sentiment of the following AI assistant conversation. Consider the user's tone, satisfaction level, and emotional state throughout the interaction.\n\nConversation:\n{{Complete exchange}}\n\nRate the sentiment using exactly one of these numeric scores:\n{{outputClassDescriptions}}\n\nRespond with only the numeric score.`,\n defaultOutputClasses: [\n { label: \"Very Negative\", value: 1 },\n { label: \"Negative\", value: 2 },\n { label: \"Neutral\", value: 3 },\n { label: \"Positive\", value: 4 },\n { label: \"Very Positive\", value: 5 },\n ],\n },\n {\n id: \"time_saved_estimator\",\n name: \"Time Saved Estimator\",\n description:\n \"Estimates how much time the AI interaction saved compared to manual effort\",\n defaultUnit: \"minutes\",\n promptTemplate: `Estimate how much time this AI assistant interaction saved the user compared to completing the task manually without AI assistance. Consider the complexity of the request, the completeness of the response, and typical human effort for similar tasks.\n\nConversation:\n{{Complete exchange}}\n\nClassify the estimated time saved using exactly one of these values (in minutes):\n{{outputClassDescriptions}}\n\nRespond with only the numeric value.`,\n defaultOutputClasses: [\n { label: \"No time saved\", value: 0 },\n { label: \"A few minutes\", value: 3 },\n { label: \"Moderate time\", value: 10 },\n { label: \"Significant time\", value: 30 },\n { label: \"Major time savings\", value: 60 },\n ],\n },\n];\n\nfunction resolveOutputClassDescriptions(classes: OutputClassOption[]): string {\n return classes.map((c) => `${c.value} = ${c.label}`).join(\"\\n\");\n}\n\nfunction resolveTemplatePrompt(\n template: ClassifierTemplate,\n classes: OutputClassOption[],\n): string {\n return template.promptTemplate.replace(\n \"{{outputClassDescriptions}}\",\n resolveOutputClassDescriptions(classes),\n );\n}\n\nfunction formatKpiTable(kpis: KpiDefinition[]): void {\n if (kpis.length === 0) {\n console.log(\"No KPI definitions found.\");\n return;\n }\n\n // Calculate column widths\n const headers = [\"ID\", \"NAME\", \"SCOPE\", \"CALCULATOR\", \"AGGREGATION\", \"STATUS\"];\n const rows = kpis.map((kpi) => [\n kpi.id.slice(0, 12) + \"...\",\n kpi.name.slice(0, 25),\n kpi.scope || \"PROMPT_REQUEST\",\n kpi.calculatorId,\n kpi.defaultAggregationMethod,\n kpi.isActive ? \"Active\" : \"Inactive\",\n ]);\n\n const widths = headers.map((h, i) =>\n Math.max(h.length, ...rows.map((r) => r[i].length))\n );\n\n // Print header\n console.log(headers.map((h, i) => h.padEnd(widths[i])).join(\" \"));\n console.log(widths.map((w) => \"-\".repeat(w)).join(\" \"));\n\n // Print rows\n for (const row of rows) {\n console.log(row.map((cell, i) => cell.padEnd(widths[i])).join(\" \"));\n }\n}\n\nfunction formatKpiDetail(kpi: KpiDefinition): void {\n console.log(`ID: ${kpi.id}`);\n console.log(`Name: ${kpi.name}`);\n console.log(`Description: ${kpi.description || \"-\"}`);\n console.log(`Type: ${kpi.type}`);\n console.log(`Category: ${kpi.category || \"-\"}`);\n console.log(`Agent ID: ${kpi.agentId || \"-\"}`);\n console.log(`Scope: ${kpi.scope || \"PROMPT_REQUEST\"}`);\n console.log(`Calculator: ${kpi.calculatorId}`);\n console.log(`Aggregation: ${kpi.defaultAggregationMethod}`);\n console.log(`Unit: ${kpi.unit || \"-\"}`);\n console.log(`Status: ${kpi.isActive ? \"Active\" : \"Inactive\"}`);\n\n if (kpi.calculatorParams) {\n console.log(\"\");\n console.log(\"Calculator Parameters:\");\n console.log(JSON.stringify(kpi.calculatorParams, null, 2));\n }\n\n if (kpi.createdAt) {\n console.log(\"\");\n console.log(`Created: ${new Date(kpi.createdAt).toISOString()}`);\n }\n if (kpi.updatedAt) {\n console.log(`Updated: ${new Date(kpi.updatedAt).toISOString()}`);\n }\n}\n\nfunction formatContextVariablesTable(variables: ContextVariable[]): void {\n if (variables.length === 0) {\n console.log(\"No context variables found.\");\n return;\n }\n\n // Calculate column widths\n const headers = [\"NAME\", \"TYPE\", \"SOURCE\", \"DESCRIPTION\"];\n const rows = variables.map((v) => [\n v.name,\n v.type,\n v.source,\n v.description.slice(0, 50),\n ]);\n\n const widths = headers.map((h, i) =>\n Math.max(h.length, ...rows.map((r) => r[i].length))\n );\n\n // Print header\n console.log(headers.map((h, i) => h.padEnd(widths[i])).join(\" \"));\n console.log(widths.map((w) => \"-\".repeat(w)).join(\" \"));\n\n // Print rows\n for (const row of rows) {\n console.log(row.map((cell, i) => cell.padEnd(widths[i])).join(\" \"));\n }\n}\n\nasync function listCommand(options: {\n json?: boolean;\n agentId?: string;\n includeInactive?: boolean;\n}): Promise<void> {\n try {\n const kpis = await listKpis({\n agentId: options.agentId,\n includeInactive: options.includeInactive,\n });\n\n if (options.json) {\n console.log(JSON.stringify(kpis, null, 2));\n } else {\n formatKpiTable(kpis);\n }\n } catch (error) {\n console.error(\n `Error: ${error instanceof Error ? error.message : \"Unknown error\"}`\n );\n process.exit(1);\n }\n}\n\nasync function getCommand(\n id: string,\n options: { json?: boolean }\n): Promise<void> {\n try {\n const kpi = await getKpi(id);\n\n if (options.json) {\n console.log(JSON.stringify(kpi, null, 2));\n } else {\n formatKpiDetail(kpi);\n }\n } catch (error) {\n console.error(\n `Error: ${error instanceof Error ? error.message : \"Unknown error\"}`\n );\n process.exit(1);\n }\n}\n\nasync function createCommand(options: {\n name: string;\n calculatorId: string;\n scope: string;\n description?: string;\n type?: string;\n category?: string;\n agentId?: string;\n formula?: string;\n templateId?: string;\n outputClasses?: string;\n outputLabels?: string;\n samplingFactor?: string;\n unit?: string;\n aggregation?: string;\n json?: boolean;\n}): Promise<void> {\n try {\n if (!options.name) {\n console.error(\"Error: --name is required\");\n process.exit(1);\n }\n\n if (!options.calculatorId) {\n console.error(\"Error: --calculator-id is required\");\n console.error(`Valid values: ${CALCULATOR_IDS.join(\", \")}`);\n process.exit(1);\n }\n\n if (!CALCULATOR_IDS.includes(options.calculatorId)) {\n console.error(`Error: Invalid calculator ID \"${options.calculatorId}\"`);\n console.error(`Valid values: ${CALCULATOR_IDS.join(\", \")}`);\n process.exit(1);\n }\n\n // Validate scope\n const upperScope = options.scope.toUpperCase() as KpiScope;\n if (!KPI_SCOPES.includes(upperScope)) {\n console.error(`Error: Invalid scope \"${options.scope}\"`);\n console.error(`Valid values: ${KPI_SCOPES.join(\", \")}`);\n process.exit(1);\n }\n\n // Build calculator params\n let calculatorParams: Record<string, unknown> | undefined;\n let resolvedUnit = options.unit;\n\n if (options.calculatorId === \"formula\") {\n if (!options.formula) {\n console.error(\n \"Error: --formula is required when calculator-id is 'formula'\"\n );\n process.exit(1);\n }\n // Validate and parse the formula using the API\n const validation = await validateKpiFormula(options.formula, options.agentId, upperScope);\n if (!validation.valid) {\n console.error(`Error: Invalid formula: ${validation.error}`);\n process.exit(1);\n }\n // Use the parsed formula AST, not the raw string\n calculatorParams = { formula: validation.parsedFormula };\n } else if (options.calculatorId === \"classifier\") {\n if (!options.templateId) {\n console.error(\n \"Error: Classifier KPIs require --template-id. Run `olakai kpis templates` to see available templates.\"\n );\n process.exit(1);\n }\n\n const templateIds = CLASSIFIER_TEMPLATES.map((t) => t.id);\n const template = CLASSIFIER_TEMPLATES.find(\n (t) => t.id === options.templateId,\n );\n if (!template) {\n console.error(\n `Error: Unknown template \"${options.templateId}\". Valid templates: ${templateIds.join(\", \")}`\n );\n process.exit(1);\n }\n\n // Resolve output classes — use overrides if provided, else template defaults\n let outputClasses = template.defaultOutputClasses;\n if (options.outputClasses || options.outputLabels) {\n const rawValues = options.outputClasses\n ? options.outputClasses.split(\",\").map((v) => v.trim())\n : template.defaultOutputClasses.map((c) => String(c.value));\n const rawLabels = options.outputLabels\n ? options.outputLabels.split(\",\").map((l) => l.trim())\n : template.defaultOutputClasses.map((c) => c.label);\n\n if (rawValues.length !== rawLabels.length) {\n console.error(\n `Error: --output-classes (${rawValues.length} values) and --output-labels (${rawLabels.length} labels) must have the same count.`\n );\n process.exit(1);\n }\n\n outputClasses = rawValues.map((v, i) => ({\n label: rawLabels[i],\n value: Number(v),\n }));\n }\n\n // Resolve prompt with output class descriptions\n const promptTemplate = resolveTemplatePrompt(template, outputClasses);\n\n calculatorParams = {\n promptTemplate,\n outputClasses: outputClasses.map((c) => c.value),\n outputClassLabels: outputClasses.map((c) => c.label),\n classifierTemplateId: template.id,\n };\n\n // Parse sampling factor if provided\n if (options.samplingFactor !== undefined) {\n const factor = Number(options.samplingFactor);\n if (isNaN(factor) || factor < 0 || factor > 1) {\n console.error(\"Error: --sampling-factor must be a number between 0 and 1.\");\n process.exit(1);\n }\n calculatorParams.samplingFactor = factor;\n }\n\n // Use template default unit unless explicitly overridden\n if (!resolvedUnit) {\n resolvedUnit = template.defaultUnit;\n }\n }\n\n // Validate aggregation method\n let aggregation: DefaultAggregationMethod | undefined;\n if (options.aggregation) {\n const upperAggregation =\n options.aggregation.toUpperCase() as DefaultAggregationMethod;\n if (!AGGREGATION_METHODS.includes(upperAggregation)) {\n console.error(`Error: Invalid aggregation method \"${options.aggregation}\"`);\n console.error(`Valid values: ${AGGREGATION_METHODS.join(\", \")}`);\n process.exit(1);\n }\n aggregation = upperAggregation;\n }\n\n const payload: CreateKpiPayload = {\n name: options.name,\n calculatorId: options.calculatorId,\n scope: upperScope,\n description: options.description,\n type:\n options.type === \"PREDEFINED\" ? \"PREDEFINED\" : \"USER_DEFINED\",\n category: options.category,\n agentId: options.agentId,\n calculatorParams,\n unit: resolvedUnit,\n defaultAggregationMethod: aggregation,\n };\n\n const kpi = await createKpi(payload);\n\n if (options.json) {\n console.log(JSON.stringify(kpi, null, 2));\n } else {\n console.log(\"KPI definition created successfully!\");\n console.log(\"\");\n formatKpiDetail(kpi);\n }\n } catch (error) {\n console.error(\n `Error: ${error instanceof Error ? error.message : \"Unknown error\"}`\n );\n process.exit(1);\n }\n}\n\nasync function updateCommand(\n id: string,\n options: {\n name?: string;\n description?: string;\n category?: string;\n agentId?: string;\n scope?: string;\n calculatorId?: string;\n formula?: string;\n unit?: string;\n aggregation?: string;\n active?: boolean;\n inactive?: boolean;\n json?: boolean;\n }\n): Promise<void> {\n try {\n const payload: Record<string, unknown> = {};\n\n if (options.name !== undefined) payload.name = options.name;\n if (options.description !== undefined)\n payload.description = options.description;\n if (options.category !== undefined) payload.category = options.category;\n if (options.agentId !== undefined) payload.agentId = options.agentId;\n if (options.calculatorId !== undefined)\n payload.calculatorId = options.calculatorId;\n if (options.unit !== undefined) payload.unit = options.unit;\n if (options.active) payload.isActive = true;\n if (options.inactive) payload.isActive = false;\n\n // Validate and set scope\n let validatedScope: KpiScope | undefined;\n if (options.scope !== undefined) {\n const upperScope = options.scope.toUpperCase() as KpiScope;\n if (!KPI_SCOPES.includes(upperScope)) {\n console.error(`Error: Invalid scope \"${options.scope}\"`);\n console.error(`Valid values: ${KPI_SCOPES.join(\", \")}`);\n process.exit(1);\n }\n payload.scope = upperScope;\n validatedScope = upperScope;\n }\n\n // Handle formula update - validate and parse before storing\n if (options.formula !== undefined) {\n const validation = await validateKpiFormula(options.formula, options.agentId, validatedScope);\n if (!validation.valid) {\n console.error(`Error: Invalid formula: ${validation.error}`);\n process.exit(1);\n }\n // Use the parsed formula AST, not the raw string\n payload.calculatorParams = { formula: validation.parsedFormula };\n }\n\n // Validate and set aggregation method\n if (options.aggregation) {\n const upperAggregation =\n options.aggregation.toUpperCase() as DefaultAggregationMethod;\n if (!AGGREGATION_METHODS.includes(upperAggregation)) {\n console.error(`Error: Invalid aggregation method \"${options.aggregation}\"`);\n console.error(`Valid values: ${AGGREGATION_METHODS.join(\", \")}`);\n process.exit(1);\n }\n payload.defaultAggregationMethod = upperAggregation;\n }\n\n if (Object.keys(payload).length === 0) {\n console.error(\"Error: At least one field to update is required\");\n process.exit(1);\n }\n\n const kpi = await updateKpi(id, payload);\n\n if (options.json) {\n console.log(JSON.stringify(kpi, null, 2));\n } else {\n console.log(\"KPI definition updated successfully!\");\n console.log(\"\");\n formatKpiDetail(kpi);\n }\n } catch (error) {\n console.error(\n `Error: ${error instanceof Error ? error.message : \"Unknown error\"}`\n );\n process.exit(1);\n }\n}\n\nasync function deleteCommand(\n id: string,\n options: { force?: boolean }\n): Promise<void> {\n try {\n if (!options.force) {\n console.log(\"Are you sure you want to delete this KPI definition?\");\n console.log(\"Use --force to confirm deletion.\");\n process.exit(1);\n }\n\n await deleteKpi(id);\n console.log(\"KPI definition deleted successfully.\");\n } catch (error) {\n console.error(\n `Error: ${error instanceof Error ? error.message : \"Unknown error\"}`\n );\n process.exit(1);\n }\n}\n\nasync function contextVariablesCommand(options: {\n json?: boolean;\n agentId?: string;\n scope?: string;\n}): Promise<void> {\n try {\n // Validate scope if provided\n let validatedScope: KpiScope | undefined;\n if (options.scope) {\n const upperScope = options.scope.toUpperCase() as KpiScope;\n if (!KPI_SCOPES.includes(upperScope)) {\n console.error(`Error: Invalid scope \"${options.scope}\"`);\n console.error(`Valid values: ${KPI_SCOPES.join(\", \")}`);\n process.exit(1);\n }\n validatedScope = upperScope;\n }\n\n const variables = await getKpiContextVariables(options.agentId, validatedScope);\n\n if (options.json) {\n console.log(JSON.stringify(variables, null, 2));\n } else {\n console.log(\"Available context variables for KPI formulas:\");\n console.log(\"\");\n formatContextVariablesTable(variables);\n console.log(\"\");\n console.log(\n \"Use these variable names in your formula expressions, e.g.:\"\n );\n console.log(' IF(PII detected, 1, 0)');\n console.log(' Documents count * 10');\n console.log(' IF(CODE detected AND SECRET detected, \"high-risk\", \"normal\")');\n }\n } catch (error) {\n console.error(\n `Error: ${error instanceof Error ? error.message : \"Unknown error\"}`\n );\n process.exit(1);\n }\n}\n\nasync function validateCommand(options: {\n formula: string;\n agentId?: string;\n scope?: string;\n json?: boolean;\n}): Promise<void> {\n try {\n if (!options.formula) {\n console.error(\"Error: --formula is required\");\n process.exit(1);\n }\n\n // Validate scope if provided\n let validatedScope: KpiScope | undefined;\n if (options.scope) {\n const upperScope = options.scope.toUpperCase() as KpiScope;\n if (!KPI_SCOPES.includes(upperScope)) {\n console.error(`Error: Invalid scope \"${options.scope}\"`);\n console.error(`Valid values: ${KPI_SCOPES.join(\", \")}`);\n process.exit(1);\n }\n validatedScope = upperScope;\n }\n\n const result = await validateKpiFormula(options.formula, options.agentId, validatedScope);\n\n if (options.json) {\n console.log(JSON.stringify(result, null, 2));\n } else {\n if (result.valid) {\n console.log(\"Formula is valid!\");\n console.log(`Result type: ${result.type || \"unknown\"}`);\n } else {\n console.error(\"Formula is invalid:\");\n console.error(` ${result.error}`);\n if (result.charIndex !== undefined) {\n console.error(` Position: character ${result.charIndex}`);\n }\n process.exit(1);\n }\n }\n } catch (error) {\n console.error(\n `Error: ${error instanceof Error ? error.message : \"Unknown error\"}`\n );\n process.exit(1);\n }\n}\n\nfunction templatesCommand(options: { json?: boolean }): void {\n if (options.json) {\n console.log(\n JSON.stringify(\n CLASSIFIER_TEMPLATES.map((t) => ({\n id: t.id,\n name: t.name,\n description: t.description,\n defaultUnit: t.defaultUnit,\n outputClasses: t.defaultOutputClasses,\n })),\n null,\n 2,\n ),\n );\n } else {\n console.log(\"Available Classifier Templates:\");\n console.log(\"\");\n for (const t of CLASSIFIER_TEMPLATES) {\n console.log(` ${t.id.padEnd(24)} ${t.description}`);\n const classRange = t.defaultOutputClasses;\n console.log(\n `${\"\".padEnd(26)}Classes: ${classRange.map((c) => `${c.value} (${c.label})`).join(\", \")}`,\n );\n console.log(\n `${\"\".padEnd(26)}Default unit: ${t.defaultUnit}`,\n );\n console.log(\"\");\n }\n console.log(\"Usage:\");\n console.log(\n ' olakai kpis create --name \"User Satisfaction\" --calculator-id classifier --template-id sentiment_scorer --scope CHAT',\n );\n }\n}\n\nexport function registerKpisCommand(program: Command): void {\n const kpis = program\n .command(\"kpis\")\n .description(\"Manage KPI definitions\");\n\n kpis\n .command(\"list\")\n .description(\"List all KPI definitions\")\n .option(\"--json\", \"Output as JSON\")\n .option(\"--agent-id <id>\", \"Filter by agent ID\")\n .option(\"--include-inactive\", \"Include inactive KPI definitions\")\n .action(listCommand);\n\n kpis\n .command(\"get <id>\")\n .description(\"Get KPI definition details\")\n .option(\"--json\", \"Output as JSON\")\n .action(getCommand);\n\n kpis\n .command(\"create\")\n .description(\"Create a new KPI definition\")\n .requiredOption(\"--name <name>\", \"KPI name\")\n .requiredOption(\n \"--calculator-id <id>\",\n \"Calculator type: formula, classifier, or llm-data\"\n )\n .requiredOption(\n \"--scope <scope>\",\n \"KPI scope: PROMPT_REQUEST, CHAT, or DOCUMENT\"\n )\n .option(\"--description <description>\", \"KPI description\")\n .option(\"--type <type>\", \"KPI type: PREDEFINED or USER_DEFINED (default)\")\n .option(\"--category <category>\", \"KPI category for grouping\")\n .option(\"--agent-id <id>\", \"Associate KPI with a specific agent\")\n .option(\"--formula <formula>\", \"Formula expression (required for formula calculator)\")\n .option(\"--template-id <id>\", \"Classifier template: sentiment_scorer, time_saved_estimator\")\n .option(\"--output-classes <values>\", \"Override output class values (comma-separated numbers)\")\n .option(\"--output-labels <labels>\", \"Override output class labels (comma-separated)\")\n .option(\"--sampling-factor <factor>\", \"Fraction of events to classify, 0-1 (cost control)\")\n .option(\"--unit <unit>\", 'Display unit (e.g., \"ms\", \"%\", \"count\")')\n .option(\n \"--aggregation <method>\",\n \"Default aggregation: SUM, AVERAGE, COUNT, MIN, MAX, LATEST (default)\"\n )\n .option(\"--json\", \"Output as JSON\")\n .action(createCommand);\n\n kpis\n .command(\"templates\")\n .description(\"List available classifier templates\")\n .option(\"--json\", \"Output as JSON\")\n .action(templatesCommand);\n\n kpis\n .command(\"update <id>\")\n .description(\"Update a KPI definition\")\n .option(\"--name <name>\", \"KPI name\")\n .option(\"--description <description>\", \"KPI description\")\n .option(\"--category <category>\", \"KPI category\")\n .option(\"--agent-id <id>\", \"Associate with agent\")\n .option(\"--scope <scope>\", \"KPI scope: PROMPT_REQUEST, CHAT, or DOCUMENT\")\n .option(\"--calculator-id <id>\", \"Calculator type\")\n .option(\"--formula <formula>\", \"Formula expression\")\n .option(\"--unit <unit>\", \"Display unit\")\n .option(\"--aggregation <method>\", \"Default aggregation method\")\n .option(\"--active\", \"Set KPI as active\")\n .option(\"--inactive\", \"Set KPI as inactive\")\n .option(\"--json\", \"Output as JSON\")\n .action(updateCommand);\n\n kpis\n .command(\"delete <id>\")\n .description(\"Delete a KPI definition\")\n .option(\"--force\", \"Skip confirmation\")\n .action(deleteCommand);\n\n kpis\n .command(\"context-variables\")\n .description(\"List available context variables for formulas\")\n .option(\"--json\", \"Output as JSON\")\n .option(\"--agent-id <id>\", \"Include agent-specific variables\")\n .option(\"--scope <scope>\", \"Filter variables by scope: PROMPT_REQUEST, CHAT, or DOCUMENT\")\n .action(contextVariablesCommand);\n\n kpis\n .command(\"validate\")\n .description(\"Validate a KPI formula expression\")\n .requiredOption(\"--formula <formula>\", \"Formula expression to validate\")\n .option(\"--agent-id <id>\", \"Include agent-specific context\")\n .option(\"--scope <scope>\", \"Validate against scope: PROMPT_REQUEST, CHAT, or DOCUMENT\")\n .option(\"--json\", \"Output as JSON\")\n .action(validateCommand);\n}\n","import { Command } from \"commander\";\nimport {\n listCustomDataConfigs,\n getCustomDataConfig,\n createCustomDataConfig,\n updateCustomDataConfig,\n deleteCustomDataConfig,\n type CustomDataConfig,\n type CustomDataType,\n} from \"../lib/api.js\";\n\nconst DATA_TYPES: CustomDataType[] = [\"STRING\", \"NUMBER\", \"BOOLEAN\"];\n\nfunction formatTable(configs: CustomDataConfig[]): void {\n if (configs.length === 0) {\n console.log(\"No custom data configurations found.\");\n return;\n }\n\n // Calculate column widths\n const headers = [\"ID\", \"NAME\", \"TYPE\", \"AGENT ID\", \"DESCRIPTION\"];\n const rows = configs.map((config) => [\n config.id.slice(0, 12) + \"...\",\n config.name.slice(0, 25),\n config.type,\n config.agentId ? config.agentId.slice(0, 12) + \"...\" : \"(account-level)\",\n (config.description || \"-\").slice(0, 30),\n ]);\n\n const widths = headers.map((h, i) =>\n Math.max(h.length, ...rows.map((r) => r[i].length))\n );\n\n // Print header\n console.log(headers.map((h, i) => h.padEnd(widths[i])).join(\" \"));\n console.log(widths.map((w) => \"-\".repeat(w)).join(\" \"));\n\n // Print rows\n for (const row of rows) {\n console.log(row.map((cell, i) => cell.padEnd(widths[i])).join(\" \"));\n }\n}\n\nfunction formatDetail(config: CustomDataConfig): void {\n console.log(`ID: ${config.id}`);\n console.log(`Name: ${config.name}`);\n console.log(`Type: ${config.type}`);\n console.log(`Agent ID: ${config.agentId || \"(account-level / legacy)\"}`);\n console.log(`Description: ${config.description || \"-\"}`);\n if (config.createdAt) {\n console.log(`Created: ${new Date(config.createdAt).toISOString()}`);\n }\n if (config.updatedAt) {\n console.log(`Updated: ${new Date(config.updatedAt).toISOString()}`);\n }\n}\n\nasync function listCommand(options: { agentId?: string; json?: boolean }): Promise<void> {\n try {\n const configs = await listCustomDataConfigs(options.agentId);\n\n if (options.json) {\n console.log(JSON.stringify(configs, null, 2));\n } else {\n formatTable(configs);\n }\n } catch (error) {\n console.error(\n `Error: ${error instanceof Error ? error.message : \"Unknown error\"}`\n );\n process.exit(1);\n }\n}\n\nasync function getCommand(\n id: string,\n options: { json?: boolean }\n): Promise<void> {\n try {\n const config = await getCustomDataConfig(id);\n\n if (options.json) {\n console.log(JSON.stringify(config, null, 2));\n } else {\n formatDetail(config);\n }\n } catch (error) {\n console.error(\n `Error: ${error instanceof Error ? error.message : \"Unknown error\"}`\n );\n process.exit(1);\n }\n}\n\nasync function createCommand(options: {\n agentId: string;\n name: string;\n type: string;\n description?: string;\n json?: boolean;\n}): Promise<void> {\n try {\n if (!options.agentId) {\n console.error(\"Error: --agent-id is required\");\n console.error(\"Custom data configurations must be associated with an agent.\");\n process.exit(1);\n }\n\n if (!options.name) {\n console.error(\"Error: --name is required\");\n process.exit(1);\n }\n\n if (!options.type) {\n console.error(\"Error: --type is required\");\n console.error(`Valid values: ${DATA_TYPES.join(\", \")}`);\n process.exit(1);\n }\n\n const upperType = options.type.toUpperCase() as CustomDataType;\n if (!DATA_TYPES.includes(upperType)) {\n console.error(`Error: Invalid type \"${options.type}\"`);\n console.error(`Valid values: ${DATA_TYPES.join(\", \")}`);\n process.exit(1);\n }\n\n const config = await createCustomDataConfig({\n agentId: options.agentId,\n name: options.name,\n type: upperType,\n description: options.description ?? null,\n });\n\n if (options.json) {\n console.log(JSON.stringify(config, null, 2));\n } else {\n console.log(\"Custom data configuration created successfully!\");\n console.log(\"\");\n formatDetail(config);\n }\n } catch (error) {\n console.error(\n `Error: ${error instanceof Error ? error.message : \"Unknown error\"}`\n );\n process.exit(1);\n }\n}\n\nasync function updateCommand(\n id: string,\n options: {\n name?: string;\n type?: string;\n description?: string;\n json?: boolean;\n }\n): Promise<void> {\n try {\n const payload: {\n name?: string;\n type?: CustomDataType;\n description?: string | null;\n } = {};\n\n if (options.name !== undefined) payload.name = options.name;\n if (options.description !== undefined)\n payload.description = options.description || null;\n\n if (options.type !== undefined) {\n const upperType = options.type.toUpperCase() as CustomDataType;\n if (!DATA_TYPES.includes(upperType)) {\n console.error(`Error: Invalid type \"${options.type}\"`);\n console.error(`Valid values: ${DATA_TYPES.join(\", \")}`);\n process.exit(1);\n }\n payload.type = upperType;\n }\n\n if (Object.keys(payload).length === 0) {\n console.error(\"Error: At least one field to update is required\");\n process.exit(1);\n }\n\n const config = await updateCustomDataConfig(id, payload);\n\n if (options.json) {\n console.log(JSON.stringify(config, null, 2));\n } else {\n console.log(\"Custom data configuration updated successfully!\");\n console.log(\"\");\n formatDetail(config);\n }\n } catch (error) {\n console.error(\n `Error: ${error instanceof Error ? error.message : \"Unknown error\"}`\n );\n process.exit(1);\n }\n}\n\nasync function deleteCommand(\n id: string,\n options: { force?: boolean }\n): Promise<void> {\n try {\n if (!options.force) {\n console.log(\n \"Are you sure you want to delete this custom data configuration?\"\n );\n console.log(\"Use --force to confirm deletion.\");\n process.exit(1);\n }\n\n await deleteCustomDataConfig(id);\n console.log(\"Custom data configuration deleted successfully.\");\n } catch (error) {\n console.error(\n `Error: ${error instanceof Error ? error.message : \"Unknown error\"}`\n );\n process.exit(1);\n }\n}\n\nexport function registerCustomDataCommand(program: Command): void {\n const customData = program\n .command(\"custom-data\")\n .description(\"Manage custom data configurations for KPI formulas\");\n\n customData\n .command(\"list\")\n .description(\"List custom data configurations\")\n .option(\"--agent-id <agentId>\", \"Filter by agent ID (omit to list all account configs)\")\n .option(\"--json\", \"Output as JSON\")\n .action(listCommand);\n\n customData\n .command(\"get <id>\")\n .description(\"Get custom data configuration details\")\n .option(\"--json\", \"Output as JSON\")\n .action(getCommand);\n\n customData\n .command(\"create\")\n .description(\"Create a new custom data configuration for an agent\")\n .requiredOption(\"--agent-id <agentId>\", \"Agent ID (required)\")\n .requiredOption(\"--name <name>\", \"Configuration name (used in KPI formulas)\")\n .requiredOption(\n \"--type <type>\",\n \"Data type: STRING, NUMBER, or BOOLEAN\"\n )\n .option(\"--description <description>\", \"Configuration description\")\n .option(\"--json\", \"Output as JSON\")\n .action(createCommand);\n\n customData\n .command(\"update <id>\")\n .description(\"Update a custom data configuration\")\n .option(\"--name <name>\", \"Configuration name\")\n .option(\"--type <type>\", \"Data type: STRING, NUMBER, or BOOLEAN\")\n .option(\"--description <description>\", \"Configuration description\")\n .option(\"--json\", \"Output as JSON\")\n .action(updateCommand);\n\n customData\n .command(\"delete <id>\")\n .description(\"Delete a custom data configuration\")\n .option(\"--force\", \"Skip confirmation\")\n .action(deleteCommand);\n}\n","import { Command } from \"commander\";\nimport {\n listActivity,\n getActivity,\n getActivityKpis,\n listSessions,\n type ActivityPrompt,\n type ActivityListResponse,\n type ActivityKpisResponse,\n type CoreKpiValue,\n type SessionsListResponse,\n} from \"../lib/api.js\";\n\nfunction formatActivityTable(data: ActivityListResponse): void {\n if (data.prompts.length === 0) {\n console.log(\"No activity found.\");\n return;\n }\n\n // Calculate column widths\n const headers = [\"ID\", \"AGENT\", \"APP\", \"MODEL\", \"TOKENS\", \"TIME(ms)\", \"RISK\", \"STATUS\"];\n const rows = data.prompts.map((prompt) => [\n prompt.id.slice(0, 12) + \"...\",\n prompt.agentName || (prompt.agentId ? prompt.agentId.slice(0, 12) + \"...\" : \"-\"),\n prompt.app.slice(0, 12),\n prompt.modelId?.slice(0, 15) || \"-\",\n String(prompt.tokens),\n String(prompt.requestTime),\n prompt.isHighRisk ? \"Yes\" : \"No\",\n prompt.decorationStatus.slice(0, 10),\n ]);\n\n const widths = headers.map((h, i) =>\n Math.max(h.length, ...rows.map((r) => r[i].length))\n );\n\n // Print header\n console.log(headers.map((h, i) => h.padEnd(widths[i])).join(\" \"));\n console.log(widths.map((w) => \"-\".repeat(w)).join(\" \"));\n\n // Print rows\n for (const row of rows) {\n console.log(row.map((cell, i) => cell.padEnd(widths[i])).join(\" \"));\n }\n\n // Print pagination info\n console.log(\"\");\n console.log(`Showing ${data.prompts.length} of ${data.total} results (offset: ${data.offset})`);\n if (data.hasMore) {\n console.log(`Use --offset ${data.offset + data.limit} to see more results`);\n }\n}\n\nfunction formatActivityDetail(prompt: ActivityPrompt): void {\n console.log(`ID: ${prompt.id}`);\n console.log(`Created: ${prompt.createdAt}`);\n console.log(`Agent: ${prompt.agentName || \"-\"} (${prompt.agentId || \"-\"})`);\n console.log(`Workflow: ${prompt.workflowName || \"-\"} (${prompt.workflowId || \"-\"})`);\n if (prompt.taskExecutionId) {\n console.log(`Task Exec ID: ${prompt.taskExecutionId}`);\n }\n console.log(`App: ${prompt.app}`);\n console.log(`Model: ${prompt.modelId || \"-\"} (${prompt.modelType || \"-\"})`);\n console.log(`Tokens: ${prompt.tokens}`);\n console.log(`Request Time: ${prompt.requestTime}ms`);\n console.log(`High Risk: ${prompt.isHighRisk ? \"Yes\" : \"No\"}`);\n console.log(`Blocked: ${prompt.blocked ? \"Yes\" : \"No\"}`);\n console.log(`Status: ${prompt.decorationStatus}`);\n\n if (prompt.sensitivity && prompt.sensitivity.length > 0) {\n console.log(`Sensitivity: ${prompt.sensitivity.join(\", \")}`);\n }\n\n if (prompt.analytics) {\n console.log(\"\");\n console.log(\"Analytics:\");\n console.log(` Task: ${prompt.analytics.task || \"-\"}`);\n console.log(` Subtask: ${prompt.analytics.subtask || \"-\"}`);\n console.log(` Time Saved: ${prompt.analytics.timesaved_minutes ?? \"-\"} minutes`);\n console.log(` Risk Score: ${prompt.analytics.riskassessment_dangerousity ?? \"-\"}`);\n }\n\n if (prompt.kpiData && Object.keys(prompt.kpiData).length > 0) {\n console.log(\"\");\n console.log(\"KPIs:\");\n for (const [key, value] of Object.entries(prompt.kpiData)) {\n console.log(` ${key}: ${value}`);\n }\n }\n\n if (prompt.prompt !== undefined) {\n console.log(\"\");\n console.log(\"Prompt:\");\n console.log(\"---\");\n console.log(prompt.prompt.slice(0, 1000) + (prompt.prompt.length > 1000 ? \"...\" : \"\"));\n console.log(\"---\");\n }\n\n if (prompt.response !== undefined) {\n console.log(\"\");\n console.log(\"Response:\");\n console.log(\"---\");\n console.log(prompt.response.slice(0, 1000) + (prompt.response.length > 1000 ? \"...\" : \"\"));\n console.log(\"---\");\n }\n}\n\nfunction formatCoreKpi(kpi: CoreKpiValue): string {\n const prefix = kpi.unitPrefix || \"\";\n const suffix = kpi.unitSuffix || \"\";\n return `${prefix}${kpi.value}${suffix}`;\n}\n\nfunction formatKpisResponse(data: ActivityKpisResponse): void {\n // Core KPIs\n console.log(\"Core KPIs:\");\n for (const kpi of data.coreKpis) {\n console.log(` ${kpi.name.padEnd(25)} ${formatCoreKpi(kpi)}`);\n }\n\n // Custom KPIs\n if (data.kpis.length > 0) {\n console.log(\"\");\n console.log(\"Custom KPIs:\");\n const headers = [\"NAME\", \"VALUE\", \"UNIT\", \"AGGREGATION\", \"DATA POINTS\"];\n const rows = data.kpis.map((kpi) => [\n kpi.name.slice(0, 25),\n kpi.value !== null ? String(kpi.value) : \"-\",\n kpi.unit || \"-\",\n kpi.aggregationMethod,\n String(kpi.dataPointCount),\n ]);\n\n const widths = headers.map((h, i) =>\n Math.max(h.length, ...rows.map((r) => r[i].length))\n );\n\n console.log(\" \" + headers.map((h, i) => h.padEnd(widths[i])).join(\" \"));\n console.log(\" \" + widths.map((w) => \"-\".repeat(w)).join(\" \"));\n\n for (const row of rows) {\n console.log(\" \" + row.map((cell, i) => cell.padEnd(widths[i])).join(\" \"));\n }\n }\n\n // Period data\n if (data.periodData && data.periodData.length > 0) {\n console.log(\"\");\n console.log(\"Period Breakdown:\");\n for (const period of data.periodData) {\n console.log(` ${period.periodStart} - ${period.periodEnd}`);\n for (const kpi of period.coreKpis) {\n console.log(` ${kpi.name}: ${formatCoreKpi(kpi)}`);\n }\n }\n }\n\n // Atoms summary\n if (data.atoms && data.atoms.length > 0) {\n console.log(\"\");\n console.log(`Per-Prompt KPI Atoms: ${data.atoms.length} records`);\n console.log(\" (Use --json for full atom data)\");\n }\n}\n\nasync function listCommand(options: {\n agentId?: string;\n workflowId?: string;\n since?: string;\n until?: string;\n limit?: string;\n offset?: string;\n includeContent?: boolean;\n includeAnalytics?: boolean;\n json?: boolean;\n}): Promise<void> {\n try {\n const data = await listActivity({\n agentId: options.agentId,\n workflowId: options.workflowId,\n since: options.since,\n until: options.until,\n limit: options.limit ? parseInt(options.limit, 10) : undefined,\n offset: options.offset ? parseInt(options.offset, 10) : undefined,\n includeContent: options.includeContent,\n includeAnalytics: options.includeAnalytics,\n });\n\n if (options.json) {\n console.log(JSON.stringify(data, null, 2));\n } else {\n formatActivityTable(data);\n }\n } catch (error) {\n console.error(\n `Error: ${error instanceof Error ? error.message : \"Unknown error\"}`\n );\n process.exit(1);\n }\n}\n\nasync function getCommand(\n id: string,\n options: { includeContent?: boolean; json?: boolean }\n): Promise<void> {\n try {\n const prompt = await getActivity(id, options.includeContent);\n\n if (options.json) {\n console.log(JSON.stringify(prompt, null, 2));\n } else {\n formatActivityDetail(prompt);\n }\n } catch (error) {\n console.error(\n `Error: ${error instanceof Error ? error.message : \"Unknown error\"}`\n );\n process.exit(1);\n }\n}\n\nasync function kpisCommand(options: {\n agentId?: string;\n workflowId?: string;\n since?: string;\n until?: string;\n period?: string;\n includeAtoms?: boolean;\n json?: boolean;\n}): Promise<void> {\n try {\n if (!options.agentId && !options.workflowId) {\n console.error(\"Error: Either --agent-id or --workflow-id is required\");\n process.exit(1);\n }\n\n const data = await getActivityKpis({\n agentId: options.agentId,\n workflowId: options.workflowId,\n since: options.since,\n until: options.until,\n period: options.period as \"hourly\" | \"daily\" | \"weekly\" | undefined,\n includeAtoms: options.includeAtoms,\n });\n\n if (options.json) {\n console.log(JSON.stringify(data, null, 2));\n } else {\n formatKpisResponse(data);\n }\n } catch (error) {\n console.error(\n `Error: ${error instanceof Error ? error.message : \"Unknown error\"}`\n );\n process.exit(1);\n }\n}\n\nfunction formatSessionsTable(data: SessionsListResponse): void {\n // Summary\n console.log(\"Session Decoration Status\");\n console.log(\"\");\n console.log(\"Summary:\");\n console.log(` Total Sessions: ${data.summary.sessionCount}`);\n\n const statuses = [\"DECORATED\", \"NEW\", \"DECORATION_FAILED\", \"DECORATION_OUTDATED\", \"SKIPPED\"];\n for (const status of statuses) {\n const count = data.summary.byStatus[status] || 0;\n const pct = data.summary.sessionCount > 0 ? ((count / data.summary.sessionCount) * 100).toFixed(1) : \"0.0\";\n const label = status.charAt(0) + status.slice(1).toLowerCase().replace(/_/g, \" \");\n console.log(` ${label.padEnd(17)} ${String(count).padStart(4)} (${pct}%)`);\n }\n\n if (data.sessions.length === 0) {\n console.log(\"\");\n console.log(\"No sessions found.\");\n return;\n }\n\n console.log(\"\");\n\n // Table\n const headers = [\"ID\", \"STATUS\", \"DATE\", \"CANDIDATE\", \"ERRORS\", \"KPI DATA\", \"VERSION\"];\n const rows = data.sessions.map((s) => [\n s.id.slice(0, 15) + \"...\",\n s.decorationStatus,\n s.decorationDate || \"-\",\n s.decorationCandidate ? \"Yes\" : \"No\",\n String(s.decorationErrorStreak),\n s.hasKpiData ? \"Yes\" : \"No\",\n s.decoratorVersion || \"-\",\n ]);\n\n const widths = headers.map((h, i) =>\n Math.max(h.length, ...rows.map((r) => r[i].length))\n );\n\n console.log(headers.map((h, i) => h.padEnd(widths[i])).join(\" \"));\n console.log(widths.map((w) => \"-\".repeat(w)).join(\" \"));\n\n for (const row of rows) {\n console.log(row.map((cell, i) => cell.padEnd(widths[i])).join(\" \"));\n }\n\n console.log(\"\");\n console.log(`Showing ${data.sessions.length} of ${data.total} results (offset: ${data.offset})`);\n if (data.hasMore) {\n console.log(`Use --offset ${data.offset + data.limit} to see more results`);\n }\n}\n\nasync function sessionsCommand(options: {\n agentId: string;\n since?: string;\n until?: string;\n limit?: string;\n offset?: string;\n json?: boolean;\n}): Promise<void> {\n try {\n const data = await listSessions({\n agentId: options.agentId,\n since: options.since,\n until: options.until,\n limit: options.limit ? parseInt(options.limit, 10) : undefined,\n offset: options.offset ? parseInt(options.offset, 10) : undefined,\n });\n\n if (options.json) {\n console.log(JSON.stringify(data, null, 2));\n } else {\n formatSessionsTable(data);\n }\n } catch (error) {\n console.error(\n `Error: ${error instanceof Error ? error.message : \"Unknown error\"}`\n );\n process.exit(1);\n }\n}\n\nexport function registerActivityCommand(program: Command): void {\n const activity = program\n .command(\"activity\")\n .description(\"Inspect AI activity and prompts\");\n\n activity\n .command(\"list\")\n .description(\"List prompt requests with filters\")\n .option(\"--agent-id <id>\", \"Filter by agent ID\")\n .option(\"--workflow-id <id>\", \"Filter by workflow ID\")\n .option(\"--since <date>\", \"Start date (ISO format)\")\n .option(\"--until <date>\", \"End date (ISO format)\")\n .option(\"--limit <n>\", \"Results per page\", \"20\")\n .option(\"--offset <n>\", \"Skip first N results\", \"0\")\n .option(\"--include-content\", \"Include prompt/response content\")\n .option(\"--include-analytics\", \"Include advanced analytics\")\n .option(\"--json\", \"Output as JSON\")\n .action(listCommand);\n\n activity\n .command(\"get <id>\")\n .description(\"Get prompt request details\")\n .option(\"--include-content\", \"Include prompt/response content\")\n .option(\"--json\", \"Output as JSON\")\n .action(getCommand);\n\n activity\n .command(\"kpis\")\n .description(\"Get aggregated KPI values\")\n .option(\"--agent-id <id>\", \"Agent ID\")\n .option(\"--workflow-id <id>\", \"Workflow ID\")\n .option(\"--since <date>\", \"Period start (ISO format)\")\n .option(\"--until <date>\", \"Period end (ISO format)\")\n .option(\"--period <type>\", \"Aggregation period (hourly, daily, weekly)\")\n .option(\"--include-atoms\", \"Include per-prompt KPI data\")\n .option(\"--json\", \"Output as JSON\")\n .action(kpisCommand);\n\n activity\n .command(\"sessions\")\n .description(\"Inspect chat/session decoration status for troubleshooting\")\n .requiredOption(\"--agent-id <id>\", \"Agent ID (required)\")\n .option(\"--since <date>\", \"Start date (ISO format)\")\n .option(\"--until <date>\", \"End date (ISO format)\")\n .option(\"--limit <n>\", \"Results per page\", \"20\")\n .option(\"--offset <n>\", \"Skip first N results\", \"0\")\n .option(\"--json\", \"Output as JSON\")\n .action(sessionsCommand);\n}\n","import * as fs from \"node:fs\";\nimport * as path from \"node:path\";\nimport * as readline from \"node:readline\";\nimport { Command } from \"commander\";\nimport {\n listAgents,\n createAgent,\n getAgent,\n type Agent,\n} from \"../lib/api.js\";\nimport { getValidToken } from \"../lib/auth.js\";\nimport { getBaseUrl } from \"../lib/config.js\";\nimport {\n parseTranscript,\n type ExtractedTranscriptData,\n} from \"./monitor-transcript.js\";\nimport {\n loadSessionState,\n saveSessionState,\n setDebugLogger,\n shouldReportTurn,\n} from \"./monitor-state.js\";\n\n// ---------------------------------------------------------------------------\n// Types\n// ---------------------------------------------------------------------------\n\nexport interface MonitorConfig {\n agentId: string;\n apiKey: string;\n agentName: string;\n source: string;\n createdAt: string;\n monitoringEndpoint: string;\n}\n\ninterface ClaudeSettings {\n hooks?: Record<string, HookMatcherEntry[]>;\n [key: string]: unknown;\n}\n\nexport interface HookMatcherEntry {\n matcher: string;\n hooks: HookCommand[];\n}\n\nexport interface HookCommand {\n type: string;\n command: string;\n}\n\n/**\n * Claude Code hook event payloads.\n *\n * The Stop / SubagentStop hooks send ONLY the fields below — the\n * conversation data (prompt, response, tokens, model, etc.) is NOT in\n * the hook JSON. To get that data we must read the transcript file at\n * `transcript_path`.\n *\n * The exact field that carries the subagent name is not formally\n * documented, so we accept several candidates (`agent_name`,\n * `agent_type`, `subagent_type`) and fall back to the `tool_input`\n * shape that the Agent tool_use block uses.\n */\nexport interface ClaudeHookEvent {\n session_id?: string;\n transcript_path?: string;\n hook_event_name?: string; // \"Stop\" | \"SubagentStop\"\n stop_hook_active?: boolean;\n cwd?: string;\n agent_name?: string;\n agent_type?: string;\n subagent_type?: string;\n tool_input?: {\n subagent_type?: string;\n description?: string;\n };\n /**\n * Claude Code's up-to-date final text block for the current turn,\n * taken from its in-memory state at hook-fire time. Preferred over\n * transcript-file parsing for the response because the on-disk\n * JSONL can lag the in-memory state when the hook fires mid-flush.\n * Undefined on older Claude Code versions or non-Stop hooks.\n */\n last_assistant_message?: string;\n}\n\n// ---------------------------------------------------------------------------\n// Constants\n// ---------------------------------------------------------------------------\n\nconst CLAUDE_DIR = \".claude\";\nconst SETTINGS_FILE = \"settings.json\";\nconst MONITOR_CONFIG_FILE = \"olakai-monitor.json\";\n\nconst OLAKAI_HOOK_MARKER = \"olakai monitor hook\";\n\nconst HOOK_DEFINITIONS: Record<string, HookMatcherEntry[]> = {\n Stop: [\n {\n matcher: \"\",\n hooks: [\n {\n type: \"command\",\n command: \"olakai monitor hook stop\",\n },\n ],\n },\n ],\n SubagentStop: [\n {\n matcher: \"\",\n hooks: [\n {\n type: \"command\",\n command: \"olakai monitor hook subagent-stop\",\n },\n ],\n },\n ],\n};\n\n/**\n * Produce the `hooks` block for a Claude Code settings.json by layering\n * the Olakai defaults on top of an existing hooks block.\n *\n * Rules:\n * - For each event in HOOK_DEFINITIONS: if the existing block already\n * has an Olakai-marker entry for that event, keep the existing\n * entries verbatim (user-customized command strings such as\n * `OLAKAI_MONITOR_DEBUG=1 olakai monitor hook stop` survive).\n * - If it doesn't, append the default Olakai entries, preserving any\n * non-Olakai entries already configured on that event.\n * - Events we don't manage (`PreToolUse`, `UserPromptSubmit`, ...)\n * pass through untouched.\n *\n * Exported for unit tests.\n */\nexport function mergeHooksSettings(\n existing: Record<string, HookMatcherEntry[]> | undefined,\n definitions: Record<string, HookMatcherEntry[]> = HOOK_DEFINITIONS,\n): Record<string, HookMatcherEntry[]> {\n const merged: Record<string, HookMatcherEntry[]> = {\n ...(existing ?? {}),\n };\n\n for (const [event, defaultEntries] of Object.entries(definitions)) {\n const existingEntries = merged[event] ?? [];\n const hasOlakaiHook = existingEntries.some((e) =>\n e.hooks.some((h) => h.command.includes(OLAKAI_HOOK_MARKER)),\n );\n\n if (hasOlakaiHook) {\n merged[event] = existingEntries;\n } else {\n merged[event] = [...existingEntries, ...defaultEntries];\n }\n }\n\n return merged;\n}\n\n// ---------------------------------------------------------------------------\n// Helpers\n// ---------------------------------------------------------------------------\n\nfunction prompt(question: string): Promise<string> {\n const rl = readline.createInterface({\n input: process.stdin,\n output: process.stdout,\n });\n return new Promise((resolve) => {\n rl.question(question, (answer) => {\n rl.close();\n resolve(answer.trim());\n });\n });\n}\n\n/**\n * Find the project root by walking up from cwd looking for a `.claude/`\n * directory. Used by `olakai monitor init` and related write-side paths\n * that need to know where to CREATE config. Stops at the first `.claude/`\n * it finds (regardless of whether the config file exists).\n *\n * Falls back to cwd if none found.\n */\nexport function findProjectRoot(startDir?: string): string {\n let dir = startDir ?? process.cwd();\n while (true) {\n if (fs.existsSync(path.join(dir, CLAUDE_DIR))) {\n return dir;\n }\n const parent = path.dirname(dir);\n if (parent === dir) break; // reached filesystem root\n dir = parent;\n }\n // Fall back to cwd (init will create .claude/)\n return startDir ?? process.cwd();\n}\n\n/**\n * Find the nearest ancestor directory that contains\n * `.claude/olakai-monitor.json`. Used by the hook path specifically —\n * we need the directory where the config FILE lives, not just any\n * `.claude/` directory.\n *\n * Why this matters (refinement of INV-002): a subrepo like\n * `/workspace/olakai-cli` can have its own `.claude/` (worktrees,\n * settings.local.json, etc.) without an `olakai-monitor.json`. The\n * parent workspace `/workspace` has both `.claude/` AND\n * `olakai-monitor.json`. `findProjectRoot` stops at the subrepo's\n * `.claude/`, so the hook would read from the wrong directory and\n * silent-exit. This walker keeps going until it finds the actual\n * config file or hits filesystem root.\n *\n * Returns null when no configured project is found in the ancestry,\n * so callers can emit a diagnostic and silent-exit cleanly.\n */\nexport function findConfiguredProjectRoot(startDir?: string): string | null {\n let dir = startDir ?? process.cwd();\n while (true) {\n if (\n fs.existsSync(path.join(dir, CLAUDE_DIR, MONITOR_CONFIG_FILE))\n ) {\n return dir;\n }\n const parent = path.dirname(dir);\n if (parent === dir) break; // reached filesystem root\n dir = parent;\n }\n return null;\n}\n\n/**\n * Resolve the configured-project directory from a Claude Code hook\n * payload, falling back to `fallbackCwd` when the payload doesn't\n * carry a usable `cwd` field. Returns null when no configured project\n * is found in the ancestry, letting the hook silent-exit cleanly.\n *\n * Background (INV-002): Claude Code sometimes invokes Stop /\n * SubagentStop hooks from a CWD that isn't under the workspace (e.g.\n * `/tmp`, `$HOME`) — or reports a subrepo CWD (e.g.\n * `/workspace/olakai-cli`) that has its own `.claude/` without the\n * monitor config. Either case used to make the hook silent-exit.\n *\n * We seed the ancestor walk with `payload.cwd` when present (reflects\n * the workspace Claude Code thinks it's in), and look for the actual\n * `.claude/olakai-monitor.json` file — not just any `.claude/`\n * directory — so stray `.claude/` dirs in subrepos don't trap the\n * search short of the real configured workspace.\n *\n * Exported as a pure function so unit tests can exercise it without\n * mocking `process.cwd()`.\n */\nexport function resolveProjectRootFromPayload(\n eventData: ClaudeHookEvent,\n fallbackCwd: string,\n): string | null {\n const payloadCwd =\n typeof eventData.cwd === \"string\" && eventData.cwd.trim()\n ? eventData.cwd\n : fallbackCwd;\n return findConfiguredProjectRoot(payloadCwd);\n}\n\nfunction getClaudeDir(projectRoot: string): string {\n return path.join(projectRoot, CLAUDE_DIR);\n}\n\nfunction getSettingsPath(projectRoot: string): string {\n return path.join(getClaudeDir(projectRoot), SETTINGS_FILE);\n}\n\nfunction getMonitorConfigPath(projectRoot: string): string {\n return path.join(getClaudeDir(projectRoot), MONITOR_CONFIG_FILE);\n}\n\nfunction readJsonFile<T>(filePath: string): T | null {\n try {\n if (!fs.existsSync(filePath)) return null;\n const content = fs.readFileSync(filePath, \"utf-8\");\n return JSON.parse(content) as T;\n } catch {\n return null;\n }\n}\n\nfunction writeJsonFile(filePath: string, data: unknown): void {\n const dir = path.dirname(filePath);\n if (!fs.existsSync(dir)) {\n fs.mkdirSync(dir, { recursive: true });\n }\n fs.writeFileSync(filePath, JSON.stringify(data, null, 2) + \"\\n\", \"utf-8\");\n}\n\nfunction loadMonitorConfig(projectRoot?: string): MonitorConfig | null {\n const root = projectRoot ?? findProjectRoot();\n return readJsonFile<MonitorConfig>(getMonitorConfigPath(root));\n}\n\n/**\n * Read stdin with a timeout. Returns empty string if stdin has no data\n * or times out.\n */\nfunction readStdin(timeoutMs: number = 3000): Promise<string> {\n return new Promise((resolve) => {\n // If stdin is a TTY (no piped data), return immediately\n if (process.stdin.isTTY) {\n resolve(\"\");\n return;\n }\n\n let data = \"\";\n const timer = setTimeout(() => {\n process.stdin.removeAllListeners();\n process.stdin.destroy();\n resolve(data);\n }, timeoutMs);\n\n process.stdin.setEncoding(\"utf-8\");\n process.stdin.on(\"data\", (chunk: string) => {\n data += chunk;\n });\n process.stdin.on(\"end\", () => {\n clearTimeout(timer);\n resolve(data);\n });\n process.stdin.on(\"error\", () => {\n clearTimeout(timer);\n resolve(data);\n });\n });\n}\n\n// ---------------------------------------------------------------------------\n// Subcommands\n// ---------------------------------------------------------------------------\n\n/**\n * olakai monitor init\n *\n * Interactive setup: create/select agent, write hooks, save config.\n */\nasync function initCommand(): Promise<void> {\n // 1. Check authentication\n const token = getValidToken();\n if (!token) {\n console.error(\"Not logged in. Run 'olakai login' first.\");\n process.exit(1);\n }\n\n console.log(\"Setting up Claude Code monitoring for this workspace...\\n\");\n\n const projectRoot = process.cwd();\n const dirName = path.basename(projectRoot);\n\n // 2. Create or select an agent\n let agent: Agent;\n const choice = await prompt(\n \"Create a new agent or use an existing one? (new/existing) [new]: \",\n );\n\n if (choice.toLowerCase() === \"existing\" || choice.toLowerCase() === \"e\") {\n // List agents and let user pick\n const agents = await listAgents();\n if (agents.length === 0) {\n console.log(\"No agents found. Creating a new one instead.\\n\");\n agent = await createNewAgent(dirName);\n } else {\n console.log(\"\\nAvailable agents:\");\n for (let i = 0; i < agents.length; i++) {\n console.log(` ${i + 1}. ${agents[i].name} (${agents[i].id.slice(0, 12)}...)`);\n }\n\n const selection = await prompt(`\\nSelect agent (1-${agents.length}): `);\n const idx = parseInt(selection, 10) - 1;\n\n if (isNaN(idx) || idx < 0 || idx >= agents.length) {\n console.error(\"Invalid selection.\");\n process.exit(1);\n }\n\n // Fetch full agent detail (may include API key info)\n agent = await getAgent(agents[idx].id);\n\n // If agent doesn't have an active API key, we need to create one.\n // The CLI create endpoint generates one with --with-api-key but there's\n // no standalone \"create API key\" endpoint exposed in the CLI API module.\n // So we warn and ask user to use an agent that already has one, or create new.\n if (!agent.apiKey?.key && !agent.apiKey?.isActive) {\n console.log(\n \"\\nThis agent has no active API key. Please create a new agent instead,\",\n );\n console.log(\"or generate an API key via the Olakai dashboard.\\n\");\n const createNew = await prompt(\"Create a new agent? (y/n) [y]: \");\n if (createNew.toLowerCase() !== \"n\") {\n agent = await createNewAgent(dirName);\n } else {\n process.exit(1);\n }\n }\n }\n } else {\n agent = await createNewAgent(dirName);\n }\n\n // Resolve the API key. For newly created agents, agent.apiKey.key is populated.\n // For existing agents, the key is masked — we can't get the plaintext back.\n // In that case, prompt for it.\n let apiKey = agent.apiKey?.key;\n if (!apiKey) {\n console.log(\n \"\\nThe API key for this agent is not available (it is only shown once at creation).\",\n );\n apiKey = await prompt(\"Paste the API key for this agent: \");\n if (!apiKey) {\n console.error(\"API key is required for monitoring.\");\n process.exit(1);\n }\n }\n\n // 3. Write Claude Code hooks\n const claudeDir = getClaudeDir(projectRoot);\n if (!fs.existsSync(claudeDir)) {\n fs.mkdirSync(claudeDir, { recursive: true });\n }\n\n const settingsPath = getSettingsPath(projectRoot);\n const existingSettings = readJsonFile<ClaudeSettings>(settingsPath) ?? {};\n\n const mergedHooks = mergeHooksSettings(existingSettings.hooks);\n\n const updatedSettings: ClaudeSettings = {\n ...existingSettings,\n hooks: mergedHooks,\n };\n\n writeJsonFile(settingsPath, updatedSettings);\n\n // 4. Save monitor config\n const monitoringEndpoint = `${getBaseUrl()}/api/monitoring/prompt`;\n const monitorConfig: MonitorConfig = {\n agentId: agent.id,\n apiKey,\n agentName: agent.name,\n source: \"claude-code\",\n createdAt: new Date().toISOString(),\n monitoringEndpoint,\n };\n\n const monitorConfigPath = getMonitorConfigPath(projectRoot);\n writeJsonFile(monitorConfigPath, monitorConfig);\n // Restrict permissions — file contains a plaintext API key\n fs.chmodSync(monitorConfigPath, 0o600);\n\n // 5. Success message\n console.log(\"\");\n console.log(`\\u2713 Agent \"${agent.name}\" configured (ID: ${agent.id})`);\n if (agent.apiKey?.key) {\n console.log(\"\\u2713 API key generated\");\n }\n console.log(`\\u2713 Claude Code hooks configured in ${CLAUDE_DIR}/${SETTINGS_FILE}`);\n console.log(`\\u2713 Monitor config saved to ${CLAUDE_DIR}/${MONITOR_CONFIG_FILE}`);\n console.log(\"\");\n console.log(\n \"Monitoring is now active. Claude Code will report activity to Olakai\",\n );\n console.log(\n `on each turn. View activity at: ${getBaseUrl()}/dashboard`,\n );\n console.log(\"\");\n console.log(\n `\\u26A0 Ensure ${CLAUDE_DIR}/${MONITOR_CONFIG_FILE} is in your .gitignore (it contains your API key)`,\n );\n console.log(\"\");\n console.log(\"To check status: olakai monitor status\");\n console.log(\"To disable: olakai monitor disable\");\n}\n\nasync function createNewAgent(defaultName: string): Promise<Agent> {\n const nameInput = await prompt(\n `Agent name [${defaultName}]: `,\n );\n const agentName = nameInput || defaultName;\n\n const agent = await createAgent({\n name: agentName,\n description: `Claude Code local agent for ${agentName}`,\n role: \"WORKER\",\n createApiKey: true,\n category: \"CODING\",\n source: \"CLAUDE_CODE\",\n });\n\n return agent;\n}\n\n/**\n * Debug logger. Only writes when OLAKAI_MONITOR_DEBUG=1.\n * Errors are swallowed — debug logging must never break the hook.\n */\nfunction debugLog(label: string, data: unknown): void {\n if (process.env.OLAKAI_MONITOR_DEBUG !== \"1\") return;\n try {\n const logPath = `/tmp/olakai-monitor-debug-${process.pid}.log`;\n const line = `[${new Date().toISOString()}] ${label}: ${\n typeof data === \"string\" ? data : JSON.stringify(data, null, 2)\n }\\n`;\n fs.appendFileSync(logPath, line, \"utf-8\");\n } catch {\n // Ignore debug-log failures\n }\n}\n\n/**\n * Load a transcript JSONL from disk and extract the data we want to\n * report. Any failure (missing file, malformed JSON, unexpected shape)\n * is swallowed and we return a best-effort partial result. Parsing\n * itself lives in `monitor-transcript.ts` so it can be unit-tested.\n */\nfunction extractFromTranscript(\n transcriptPath: string | undefined,\n): ExtractedTranscriptData {\n const empty: ExtractedTranscriptData = {\n prompt: \"\",\n response: \"\",\n tokens: 0,\n inputTokens: 0,\n outputTokens: 0,\n modelName: null,\n numTurns: 0,\n toolCallCount: 0,\n filesEditedCount: 0,\n bashCommandCount: 0,\n };\n\n if (!transcriptPath) return empty;\n\n let raw: string;\n try {\n raw = fs.readFileSync(transcriptPath, \"utf-8\");\n } catch (err) {\n debugLog(\"transcript-read-failed\", {\n transcriptPath,\n error: (err as Error).message,\n });\n return empty;\n }\n\n return parseTranscript(raw);\n}\n\n/**\n * Best-effort extraction of the subagent name from a SubagentStop hook\n * payload. Claude Code's payload shape for this hook isn't fully\n * documented, so we probe several candidate fields in order of\n * likelihood and fall back to undefined when nothing is found.\n */\nfunction extractSubagentName(event: ClaudeHookEvent): string | undefined {\n const candidates = [\n event.agent_name,\n event.subagent_type,\n event.agent_type,\n event.tool_input?.subagent_type,\n ];\n for (const value of candidates) {\n if (typeof value === \"string\" && value.trim()) {\n return value.trim();\n }\n }\n return undefined;\n}\n\n/**\n * olakai monitor hook <event>\n *\n * Fire-and-forget handler called by Claude Code hooks.\n * Reads event JSON from stdin, POSTs to monitoring endpoint.\n * MUST NOT produce stderr output or exit non-zero.\n *\n * IMPORTANT ordering (INV-002): we read stdin BEFORE looking up the\n * monitor config. Claude Code sometimes invokes the hook with\n * `process.cwd()` set to an unrelated directory (e.g. `/tmp`), but it\n * always passes the workspace root in the hook payload's `cwd` field.\n * Using `payload.cwd` as the seed for `findProjectRoot` keeps the hook\n * working regardless of how Claude Code spawned it.\n */\nasync function hookCommand(event: string): Promise<void> {\n // Route monitor-state debug logs through our existing debugLog so all\n // breadcrumbs land in the same /tmp file under OLAKAI_MONITOR_DEBUG=1.\n setDebugLogger(debugLog);\n\n try {\n // 1. Read stdin first.\n const stdinData = await readStdin(3000);\n debugLog(\"stdin-raw\", stdinData);\n\n // 2. Parse payload. On failure, keep eventData as an empty object so\n // we still try a project-root lookup from process.cwd() as a\n // fallback instead of silently exiting.\n let eventData: ClaudeHookEvent = {};\n if (stdinData) {\n try {\n eventData = JSON.parse(stdinData) as ClaudeHookEvent;\n } catch {\n debugLog(\"stdin-parse-failed\", stdinData);\n // Deliberately fall through — empty eventData + process.cwd()\n // still gives us a reasonable chance of locating a config.\n }\n }\n\n debugLog(\"event-parsed\", { event, eventData });\n\n // 3. Resolve project root using payload.cwd (with process.cwd() as\n // a fallback), walking ancestors until we find a `.claude/\n // olakai-monitor.json`. Returns null when no configured workspace\n // is in the ancestry.\n const projectRoot = resolveProjectRootFromPayload(\n eventData,\n process.cwd(),\n );\n if (!projectRoot) {\n // No configured workspace in the ancestry of payload.cwd or\n // process.cwd(). Emit a breadcrumb so future \"why didn't my\n // hook fire?\" investigations are one grep away.\n debugLog(\"config-not-found\", {\n startDir:\n typeof eventData.cwd === \"string\" && eventData.cwd.trim()\n ? eventData.cwd\n : process.cwd(),\n });\n return;\n }\n const config = loadMonitorConfig(projectRoot);\n if (!config) {\n // Edge case: the monitor config file existed when findConfigured-\n // ProjectRoot checked, but became unreadable/malformed by the\n // time we tried to load it. Treat the same as no config.\n debugLog(\"config-load-failed\", { projectRoot });\n return;\n }\n\n // 4. Build monitoring payload from the transcript.\n const payload = buildPayload(event, eventData, config);\n if (!payload) {\n // Nothing meaningful to report\n return;\n }\n\n debugLog(\"payload-built\", payload);\n\n // 5. Per-session turn dedup (INV-004).\n //\n // When Claude Code fires Stop twice for a single user turn, the CLI\n // sees the same `userTurnTimestamp` on both firings — parseTranscript\n // always emits the latest user+assistant pair. Skip the POST when\n // the timestamp matches what we last reported for this session.\n const sessionId =\n (typeof eventData.session_id === \"string\" && eventData.session_id) ||\n undefined;\n\n // Re-extract so we can key dedup state on the same value that\n // drove the payload. This re-reads the transcript — cheap (<10ms\n // on the transcripts we observe in production) and avoids\n // threading `ExtractedTranscriptData` out of `buildPayload`.\n const extracted = extractFromTranscript(eventData.transcript_path);\n const userTurnTimestamp = extracted.userTurnTimestamp;\n\n if (sessionId) {\n const existingState = loadSessionState(sessionId);\n if (!shouldReportTurn(existingState, userTurnTimestamp)) {\n debugLog(\"turn-dedup-skip\", {\n sessionId,\n userTurnTimestamp,\n });\n return;\n }\n }\n\n // 6. POST to monitoring endpoint with a 5-second timeout.\n const controller = new AbortController();\n const timeoutId = setTimeout(() => controller.abort(), 5000);\n\n try {\n const res = await fetch(config.monitoringEndpoint, {\n method: \"POST\",\n headers: {\n \"x-api-key\": config.apiKey,\n \"Content-Type\": \"application/json\",\n },\n body: JSON.stringify([payload]),\n signal: controller.signal,\n });\n debugLog(\"response-status\", {\n status: res.status,\n ok: res.ok,\n });\n } finally {\n clearTimeout(timeoutId);\n }\n\n // 7. Always save state after attempting the POST, even on failure.\n // Rationale: a dropped event is recoverable from the transcript\n // (or by operator action), but a retry storm during an Olakai\n // outage is not. We'd rather drop one event than send the same\n // duplicate ten times from a client that keeps retrying.\n if (sessionId && userTurnTimestamp) {\n saveSessionState(sessionId, {\n lastUserTimestamp: userTurnTimestamp,\n lastReportedAt: new Date().toISOString(),\n numTurnsAtLastReport: extracted.numTurns,\n });\n debugLog(\"state-saved\", {\n sessionId,\n userTurnTimestamp,\n numTurns: extracted.numTurns,\n });\n }\n } catch (err) {\n // Silently swallow ALL errors. Hook failures must not break Claude Code.\n debugLog(\"hook-exception\", (err as Error).message);\n }\n}\n\n/**\n * Build a MonitorPayload from the Claude Code hook event data.\n *\n * For Stop / SubagentStop events, the hook JSON contains only\n * session_id + transcript_path — the actual conversation data is\n * extracted from the transcript JSONL file.\n *\n * Exported for unit tests.\n */\nexport function buildPayload(\n event: string,\n eventData: ClaudeHookEvent,\n config: MonitorConfig,\n): Record<string, unknown> | null {\n const sessionId = eventData.session_id ?? `claude-code-${Date.now()}`;\n\n switch (event) {\n case \"stop\":\n case \"subagent-stop\": {\n const extracted = extractFromTranscript(eventData.transcript_path);\n const isSubagent = event === \"subagent-stop\";\n\n const customData: Record<string, unknown> = {\n hookEvent:\n eventData.hook_event_name ??\n (isSubagent ? \"SubagentStop\" : \"Stop\"),\n sessionId,\n transcriptPath: eventData.transcript_path ?? \"\",\n cwd: eventData.cwd ?? \"\",\n stopHookActive: eventData.stop_hook_active ?? false,\n inputTokens: extracted.inputTokens,\n outputTokens: extracted.outputTokens,\n numTurns: extracted.numTurns,\n // Per-turn work signals for the Claude Code classifier (D-027).\n // Always emitted as JSON numbers — the backend classifier and\n // future KPI formulas must see numeric 0, not missing keys or\n // strings. File paths and bash command strings are deliberately\n // NOT emitted; only the cardinality is privacy-safe to ship.\n toolCallCount: extracted.toolCallCount,\n filesEditedCount: extracted.filesEditedCount,\n bashCommandCount: extracted.bashCommandCount,\n };\n\n if (typeof extracted.latencyMs === \"number\") {\n customData.latencyMs = extracted.latencyMs;\n }\n\n if (isSubagent) {\n const subagent = extractSubagentName(eventData);\n if (subagent) {\n customData.subagent = subagent;\n }\n } else if (extracted.skill) {\n // Skill detection only applies to main-agent Stop events. The\n // subagent's first \"user\" message is the spawning prompt, not a\n // human slash-command.\n customData.skill = extracted.skill;\n }\n\n // Prefer the hook payload's last_assistant_message — Claude Code\n // ships it from in-memory state at hook-fire time, so it reflects\n // the final text block of the turn even when the transcript\n // JSONL hasn't been flushed to disk yet. Fall back to the\n // transcript parse when the payload field is missing or empty\n // (older Claude Code versions, or some edge hook payloads).\n const payloadAssistant = eventData.last_assistant_message;\n const response =\n typeof payloadAssistant === \"string\" && payloadAssistant.trim()\n ? payloadAssistant\n : extracted.response;\n\n return {\n prompt: extracted.prompt,\n response,\n chatId: sessionId,\n // Top-level source so the backend ExternalPromptRequestSchema\n // picks it up (matches regex ^[a-z0-9_-]+$).\n source: config.source,\n modelName: extracted.modelName ?? undefined,\n tokens: extracted.tokens,\n customData,\n };\n }\n\n default:\n return null;\n }\n}\n\n/**\n * olakai monitor status\n *\n * Show current monitoring configuration and recent activity.\n */\nasync function statusCommand(options: { json?: boolean }): Promise<void> {\n const projectRoot = findProjectRoot();\n const config = loadMonitorConfig(projectRoot);\n\n if (!config) {\n console.log(\"Monitoring is not configured for this workspace.\");\n console.log(\"Run 'olakai monitor init' to set up monitoring.\");\n process.exit(1);\n }\n\n // Check if hooks are still present in settings.json\n const settings = readJsonFile<ClaudeSettings>(getSettingsPath(projectRoot));\n const hooksPresent = settings?.hooks\n ? Object.values(settings.hooks).some((entries) =>\n entries.some((e) =>\n e.hooks.some((h) => h.command.includes(OLAKAI_HOOK_MARKER)),\n ),\n )\n : false;\n\n if (options.json) {\n console.log(\n JSON.stringify(\n {\n ...config,\n apiKey: config.apiKey.slice(0, 12) + \"...\",\n hooksConfigured: hooksPresent,\n },\n null,\n 2,\n ),\n );\n return;\n }\n\n console.log(\"Olakai Monitor Status\");\n console.log(\"=====================\");\n console.log(`Agent: ${config.agentName}`);\n console.log(`Agent ID: ${config.agentId}`);\n console.log(`API Key: ${config.apiKey.slice(0, 12)}...`);\n console.log(`Endpoint: ${config.monitoringEndpoint}`);\n console.log(`Source: ${config.source}`);\n console.log(`Configured: ${config.createdAt}`);\n console.log(`Hooks: ${hooksPresent ? \"Active\" : \"Missing (run 'olakai monitor init' to restore)\"}`);\n\n // Try to show recent activity\n try {\n const token = getValidToken();\n if (token) {\n const params = new URLSearchParams({\n agentId: config.agentId,\n limit: \"5\",\n });\n const response = await fetch(\n `${getBaseUrl()}/api/activity/prompts?${params}`,\n {\n headers: { Authorization: `Bearer ${token}` },\n },\n );\n if (response.ok) {\n const data = (await response.json()) as {\n prompts: Array<{ id: string; createdAt: string }>;\n };\n if (data.prompts && data.prompts.length > 0) {\n console.log(\"\");\n console.log(\"Recent Activity:\");\n for (const p of data.prompts) {\n console.log(` ${p.createdAt} ${p.id.slice(0, 12)}...`);\n }\n } else {\n console.log(\"\");\n console.log(\"No activity recorded yet.\");\n }\n }\n }\n } catch {\n // Activity check is optional — don't fail\n }\n}\n\n/**\n * olakai monitor disable\n *\n * Remove Olakai hooks from settings.json and optionally remove config.\n */\nasync function disableCommand(options: {\n keepConfig?: boolean;\n}): Promise<void> {\n const projectRoot = findProjectRoot();\n\n // 1. Remove hooks from settings.json\n const settingsPath = getSettingsPath(projectRoot);\n const settings = readJsonFile<ClaudeSettings>(settingsPath);\n\n if (settings?.hooks) {\n const cleanedHooks: Record<string, HookMatcherEntry[]> = {};\n\n for (const [event, entries] of Object.entries(settings.hooks)) {\n const filtered = entries.filter(\n (e) =>\n !e.hooks.some((h) => h.command.includes(OLAKAI_HOOK_MARKER)),\n );\n if (filtered.length > 0) {\n cleanedHooks[event] = filtered;\n }\n }\n\n if (Object.keys(cleanedHooks).length > 0) {\n settings.hooks = cleanedHooks;\n } else {\n delete settings.hooks;\n }\n\n writeJsonFile(settingsPath, settings);\n console.log(`\\u2713 Olakai hooks removed from ${CLAUDE_DIR}/${SETTINGS_FILE}`);\n } else {\n console.log(\"No hooks found in settings.json.\");\n }\n\n // 2. Remove or keep monitor config\n if (!options.keepConfig) {\n const configPath = getMonitorConfigPath(projectRoot);\n if (fs.existsSync(configPath)) {\n fs.unlinkSync(configPath);\n console.log(`\\u2713 Monitor config removed (${CLAUDE_DIR}/${MONITOR_CONFIG_FILE})`);\n }\n } else {\n console.log(\n `Monitor config retained at ${CLAUDE_DIR}/${MONITOR_CONFIG_FILE}`,\n );\n }\n\n console.log(\"\");\n console.log(\"Monitoring disabled. Run 'olakai monitor init' to re-enable.\");\n}\n\n// ---------------------------------------------------------------------------\n// Command registration\n// ---------------------------------------------------------------------------\n\nexport function registerMonitorCommand(program: Command): void {\n const monitor = program\n .command(\"monitor\")\n .description(\"Monitor Claude Code sessions with Olakai\");\n\n monitor\n .command(\"init\")\n .description(\n \"Set up Olakai monitoring for this Claude Code workspace\",\n )\n .action(initCommand);\n\n monitor\n .command(\"hook <event>\")\n .description(\"Hook handler called by Claude Code (internal use)\")\n .action(hookCommand);\n\n monitor\n .command(\"status\")\n .description(\"Show monitoring status for this workspace\")\n .option(\"--json\", \"Output as JSON\")\n .action(statusCommand);\n\n monitor\n .command(\"disable\")\n .description(\"Remove Olakai monitoring from this workspace\")\n .option(\n \"--keep-config\",\n \"Keep the monitor config file (only remove hooks)\",\n )\n .action(disableCommand);\n}\n","/**\n * Transcript parsing for Claude Code Stop-hook monitoring.\n *\n * The Stop hook passes only a `transcript_path` pointing at a JSONL file.\n * This module is the single place we extract the per-turn data we report\n * to Olakai (prompt, response, tokens, model, latency, skill invocation).\n *\n * The code here is intentionally pure and exports named helpers so it can\n * be unit-tested without touching the filesystem or HTTP layer.\n */\n\n/**\n * Shape of a single line in a Claude Code transcript JSONL file.\n * Each line is a standalone JSON object. We only care about `user` and\n * `assistant` entries; other types (`system`, `file-history-snapshot`,\n * `progress`, compaction markers, ...) are ignored.\n */\nexport interface TranscriptLine {\n type?: string;\n subtype?: string;\n isMeta?: boolean;\n isSidechain?: boolean;\n timestamp?: string;\n message?: {\n role?: string;\n model?: string;\n content?: string | TranscriptContentBlock[];\n usage?: {\n input_tokens?: number;\n output_tokens?: number;\n cache_creation_input_tokens?: number;\n cache_read_input_tokens?: number;\n };\n };\n}\n\nexport interface TranscriptContentBlock {\n type?: string;\n text?: string;\n /**\n * For `tool_use` blocks. Name of the tool the assistant invoked\n * (e.g. `\"Edit\"`, `\"Write\"`, `\"MultiEdit\"`, `\"Bash\"`).\n */\n name?: string;\n /**\n * For `tool_use` blocks. Tool-specific input object. We read\n * `input.file_path` for `Edit`/`Write`/`MultiEdit` to count\n * distinct edited files. Typed as `unknown` because each tool\n * uses a different shape and we only probe `file_path` defensively.\n */\n input?: unknown;\n}\n\nexport interface ExtractedTranscriptData {\n prompt: string;\n response: string;\n tokens: number;\n inputTokens: number;\n outputTokens: number;\n modelName: string | null;\n numTurns: number;\n /**\n * Latency in milliseconds between the current turn's user message and\n * its final assistant response. Undefined when latency could not be\n * computed (first turn, missing timestamps, no user predecessor).\n */\n latencyMs?: number;\n /**\n * Leading slash-command captured from the current turn's user message\n * (e.g. `\"olakai-create-agent\"` for `/olakai-create-agent do X`).\n * Undefined when the user message did not start with a slash-command.\n */\n skill?: string;\n /**\n * ISO 8601 timestamp of the current turn's user message (the last\n * non-meta, non-sidechain user entry in the transcript). Used by the\n * hook layer to dedup duplicate Stop firings for the same user turn.\n * Undefined when no usable user entry is present or the timestamp\n * is missing/unparseable.\n */\n userTurnTimestamp?: string;\n /**\n * Count of `tool_use` content blocks in the current turn's assistant\n * messages. Used as a signal for the Claude Code work classifier\n * (D-027). Always an integer; `0` when the turn contained no tool\n * calls (explicit zero beats missing key). Per-turn, not per-session —\n * the chat decorator aggregates across turns server-side.\n */\n toolCallCount: number;\n /**\n * Count of distinct `file_path` values across `Edit`, `Write`, and\n * `MultiEdit` `tool_use` blocks in the current turn. Counted as the\n * size of a `Set<string>` so duplicate paths within the same turn\n * collapse to one. File paths themselves are NOT emitted — only the\n * cardinality is privacy-safe to report.\n */\n filesEditedCount: number;\n /**\n * Count of `tool_use` blocks with `name === \"Bash\"` in the current\n * turn. Bash command strings are NOT emitted — only the count.\n */\n bashCommandCount: number;\n}\n\n/**\n * Tool names whose invocations we count toward `filesEditedCount`.\n * Kept as a typed constant so both the per-block switch and any\n * future backend-side mirror can reference the same list.\n */\nconst FILE_EDITING_TOOL_NAMES = new Set<string>([\n \"Edit\",\n \"Write\",\n \"MultiEdit\",\n]);\n\n/**\n * Tool-name marker for Bash invocations. Hoisted to a constant so we\n * don't sprinkle the string literal through the parser.\n */\nconst BASH_TOOL_NAME = \"Bash\";\n\n/**\n * Match a slash-command at the start of a message. Leading whitespace is\n * trimmed before matching. The captured group is the skill name.\n *\n * Examples (match):\n * \"/foo\" -> \"foo\"\n * \"/foo-bar\" -> \"foo-bar\"\n * \"/foo some args\" -> \"foo\"\n *\n * Examples (no match):\n * \"Not a skill: /path/file\" — slash is not at the start\n * \"/path/file\" — second segment, name contains a slash\n * \"\" — empty\n */\nconst SKILL_REGEX = /^\\/([\\w-]+)(?:\\s|$)/;\n\nexport function detectSkill(userMessage: string | undefined): string | undefined {\n if (typeof userMessage !== \"string\") return undefined;\n const trimmed = userMessage.trimStart();\n if (!trimmed) return undefined;\n const match = SKILL_REGEX.exec(trimmed);\n if (!match) return undefined;\n return match[1];\n}\n\n/**\n * Extract plain text from a transcript message's `content` field.\n * Content may be a string or an array of content blocks.\n * Only `text` blocks contribute — `thinking`, `tool_use`, `tool_result`,\n * and `image` blocks are ignored.\n */\nexport function extractTextContent(\n content: string | TranscriptContentBlock[] | undefined,\n): string {\n if (typeof content === \"string\") return content;\n if (!Array.isArray(content)) return \"\";\n const parts: string[] = [];\n for (const block of content) {\n if (block?.type === \"text\" && typeof block.text === \"string\") {\n parts.push(block.text);\n }\n }\n return parts.join(\"\\n\").trim();\n}\n\n/**\n * Heuristic: is this a \"meta\" user message that should not be treated\n * as a real prompt? These include slash-command invocations and local\n * command caveats injected by Claude Code itself. Note that these are\n * separate `type: \"system\"` entries — regular `type: \"user\"` entries\n * carrying a typed slash-command still come through here and are NOT\n * skipped.\n */\nexport function isMetaUserMessage(line: TranscriptLine, text: string): boolean {\n if (line.isMeta === true) return true;\n if (!text) return true;\n return (\n text.includes(\"<command-name>\") ||\n text.includes(\"<local-command-caveat>\") ||\n text.includes(\"<command-message>\")\n );\n}\n\n/**\n * Parse an ISO 8601 timestamp to epoch milliseconds.\n * Returns NaN for invalid/undefined input.\n */\nfunction parseTimestamp(ts: string | undefined): number {\n if (typeof ts !== \"string\" || !ts) return NaN;\n return Date.parse(ts);\n}\n\n/**\n * Compaction markers interleaved in the transcript that should be\n * skipped when computing per-turn latency. The exact subtype strings\n * come from Claude Code's own PreCompact / PostCompact hook events\n * (recorded as `type: \"system\"` entries in the transcript).\n */\nfunction isCompactionEntry(line: TranscriptLine): boolean {\n if (line.type !== \"system\") return false;\n const subtype = line.subtype ?? \"\";\n return (\n subtype === \"compact_boundary\" ||\n subtype === \"pre_compact\" ||\n subtype === \"post_compact\" ||\n /compact/i.test(subtype)\n );\n}\n\n/**\n * Parse the transcript JSONL contents and extract the data we want to\n * report: last user prompt, last assistant response, usage totals for\n * the most recent assistant turn, model name, number of assistant\n * turns, latency for the most recent turn, and slash-command (skill)\n * detected on the current turn's user message.\n *\n * `raw` is the full UTF-8 contents of the transcript file. This entry\n * point is pure — no filesystem I/O — so it's trivial to unit test.\n */\nexport function parseTranscript(raw: string): ExtractedTranscriptData {\n const empty: ExtractedTranscriptData = {\n prompt: \"\",\n response: \"\",\n tokens: 0,\n inputTokens: 0,\n outputTokens: 0,\n modelName: null,\n numTurns: 0,\n toolCallCount: 0,\n filesEditedCount: 0,\n bashCommandCount: 0,\n };\n\n if (!raw) return empty;\n\n const lines = raw.split(\"\\n\");\n let lastUserText = \"\";\n let lastUserTimestamp: number = NaN;\n // Original ISO string of the current turn's user message, preserved so\n // the hook layer can use it as a per-session dedup key across\n // duplicate Stop firings. Kept separate from the numeric timestamp\n // because round-tripping Date.parse back through new Date().toISOString()\n // drops sub-ms precision and normalizes timezone formatting.\n let lastUserTimestampRaw: string | undefined;\n let lastAssistantText = \"\";\n let lastAssistantTimestamp: number = NaN;\n let lastAssistantModel: string | null = null;\n let lastAssistantInputTokens = 0;\n let lastAssistantOutputTokens = 0;\n let numTurns = 0;\n // Tracks whether we have seen a new user message since the last\n // assistant-latency update. Ensures latency is always measured\n // relative to the user that preceded the final assistant in the\n // current turn — not across turns.\n let currentTurnUserTimestamp: number = NaN;\n\n // Per-turn work-signal accumulators (D-027 / D.S2). Reset every time\n // we cross a new top-level user message so counts reflect only the\n // current turn window — the assistant messages between the last user\n // message and Stop. Aggregation across turns happens server-side in\n // the chat decorator, not here.\n let toolCallCount = 0;\n let bashCommandCount = 0;\n let editedFilePaths = new Set<string>();\n\n for (const rawLine of lines) {\n if (!rawLine) continue;\n let parsed: TranscriptLine;\n try {\n parsed = JSON.parse(rawLine) as TranscriptLine;\n } catch {\n continue; // skip malformed lines\n }\n\n // Skip compaction markers so they don't break the user->assistant\n // pairing used for latency.\n if (isCompactionEntry(parsed)) continue;\n\n // Skip sidechain (subagent) entries — we want the top-level session\n // conversation. If a transcript only has sidechain entries, the\n // loop below will leave us with empty strings.\n if (parsed.isSidechain === true) continue;\n\n if (parsed.type === \"user\" && parsed.message) {\n const text = extractTextContent(parsed.message.content);\n if (isMetaUserMessage(parsed, text)) continue;\n lastUserText = text;\n lastUserTimestamp = parseTimestamp(parsed.timestamp);\n currentTurnUserTimestamp = lastUserTimestamp;\n // Reset per-turn work-signal accumulators: we've just crossed\n // into a new turn window, so counts from previous turns must\n // not bleed into this one. The chat decorator aggregates across\n // turns server-side (D.S3); here we only emit per-PR counts.\n toolCallCount = 0;\n bashCommandCount = 0;\n editedFilePaths = new Set<string>();\n // Preserve the raw ISO string (only when it's actually a string)\n // for use as a dedup key. Unparseable timestamps are still kept\n // verbatim so upstream can match on exact-string equality.\n lastUserTimestampRaw =\n typeof parsed.timestamp === \"string\" && parsed.timestamp\n ? parsed.timestamp\n : undefined;\n } else if (parsed.type === \"assistant\" && parsed.message) {\n const text = extractTextContent(parsed.message.content);\n // Count every assistant entry (each represents one model response\n // turn, even if it contains only a tool_use or thinking block).\n numTurns += 1;\n if (text) lastAssistantText = text;\n if (typeof parsed.message.model === \"string\") {\n lastAssistantModel = parsed.message.model;\n }\n // Accumulate per-turn work signals. Each tool_use block\n // increments the total, Edit/Write/MultiEdit contribute their\n // file_path to a Set (distinct-path count is what we emit), and\n // Bash tool calls bump their own counter. Individual-block\n // parse failures are swallowed so one malformed entry cannot\n // zero out the whole turn's counts.\n const content = parsed.message.content;\n if (Array.isArray(content)) {\n for (const block of content) {\n try {\n if (!block || block.type !== \"tool_use\") continue;\n toolCallCount += 1;\n const name = typeof block.name === \"string\" ? block.name : \"\";\n if (name === BASH_TOOL_NAME) {\n bashCommandCount += 1;\n continue;\n }\n if (FILE_EDITING_TOOL_NAMES.has(name)) {\n const input = block.input;\n if (\n input !== null &&\n typeof input === \"object\" &&\n \"file_path\" in input\n ) {\n const filePath = (input as { file_path?: unknown }).file_path;\n if (typeof filePath === \"string\" && filePath) {\n editedFilePaths.add(filePath);\n }\n }\n }\n } catch {\n // Malformed block — skip it without failing the whole\n // transcript walk. Partial counts are better than zero.\n }\n }\n }\n const usage = parsed.message.usage;\n if (usage) {\n // Overwrite with the most recent turn's usage. Include cache\n // tokens in the input total so total token count reflects real\n // billable input.\n const input =\n (usage.input_tokens ?? 0) +\n (usage.cache_creation_input_tokens ?? 0) +\n (usage.cache_read_input_tokens ?? 0);\n const output = usage.output_tokens ?? 0;\n lastAssistantInputTokens = input;\n lastAssistantOutputTokens = output;\n }\n const ts = parseTimestamp(parsed.timestamp);\n if (!Number.isNaN(ts)) {\n lastAssistantTimestamp = ts;\n }\n }\n }\n\n const result: ExtractedTranscriptData = {\n prompt: lastUserText,\n response: lastAssistantText,\n tokens: lastAssistantInputTokens + lastAssistantOutputTokens,\n inputTokens: lastAssistantInputTokens,\n outputTokens: lastAssistantOutputTokens,\n modelName: lastAssistantModel,\n numTurns,\n toolCallCount,\n filesEditedCount: editedFilePaths.size,\n bashCommandCount,\n };\n\n if (\n !Number.isNaN(currentTurnUserTimestamp) &&\n !Number.isNaN(lastAssistantTimestamp) &&\n lastAssistantTimestamp >= currentTurnUserTimestamp\n ) {\n result.latencyMs = Math.round(\n lastAssistantTimestamp - currentTurnUserTimestamp,\n );\n }\n\n const skill = detectSkill(lastUserText);\n if (skill) {\n result.skill = skill;\n }\n\n if (lastUserTimestampRaw) {\n result.userTurnTimestamp = lastUserTimestampRaw;\n }\n\n return result;\n}\n","/**\n * Per-session dedup state for the Claude Code Stop / SubagentStop hook.\n *\n * Problem (INV-004): Claude Code occasionally fires the Stop hook twice\n * for a single user turn, a few seconds apart. Each firing calls the\n * CLI, which parses the transcript and emits the LATEST user+assistant\n * pair — so two firings on one turn produce two PromptRequests with an\n * identical `prompt` and a slightly different `response`.\n *\n * Fix: keep a small sidecar file per session id under\n * `~/.olakai/monitor-state/<sessionId>.json`, keyed by the current\n * turn's user-message timestamp. If the current Stop firing sees the\n * same user-turn timestamp as the last one we reported, skip the POST.\n *\n * The module is pure w.r.t. process state — callers pass `sessionId`\n * and (optionally) a `homeDir` override for testability. All filesystem\n * errors are swallowed and surfaced via `debugLog` callbacks supplied\n * by the caller; the hook MUST NOT break Claude Code.\n */\n\nimport * as fs from \"node:fs\";\nimport * as os from \"node:os\";\nimport * as path from \"node:path\";\n\n/**\n * State persisted per session id. `numTurnsAtLastReport` is informational\n * only — dedup decisions use `lastUserTimestamp`.\n */\nexport interface SessionMonitorState {\n lastUserTimestamp: string;\n lastReportedAt: string;\n numTurnsAtLastReport: number;\n}\n\nconst STATE_DIR_SEGMENTS = [\".olakai\", \"monitor-state\"];\n\n/**\n * Resolve the directory that holds per-session state files. Exposed\n * indirectly through the `homeDir` parameter on the public API so tests\n * can point it at a tmp dir.\n */\nfunction getStateDir(homeDir: string): string {\n return path.join(homeDir, ...STATE_DIR_SEGMENTS);\n}\n\nfunction getStateFile(sessionId: string, homeDir: string): string {\n return path.join(getStateDir(homeDir), `${sessionId}.json`);\n}\n\n/**\n * Optional debug logger. Kept as a module-level mutable hook so the\n * caller (monitor.ts) can wire in its own `debugLog` without this file\n * importing it (avoiding circular deps).\n */\ntype DebugLogger = (label: string, data: unknown) => void;\nlet debugLogger: DebugLogger | null = null;\n\nexport function setDebugLogger(logger: DebugLogger | null): void {\n debugLogger = logger;\n}\n\nfunction log(label: string, data: unknown): void {\n if (debugLogger) {\n try {\n debugLogger(label, data);\n } catch {\n // Debug logging must never break the hook.\n }\n }\n}\n\n/**\n * Load persisted state for `sessionId`. Returns null when the file is\n * absent, unreadable, or contains malformed JSON. Never throws.\n */\nexport function loadSessionState(\n sessionId: string,\n homeDir: string = os.homedir(),\n): SessionMonitorState | null {\n if (!sessionId) return null;\n const filePath = getStateFile(sessionId, homeDir);\n try {\n if (!fs.existsSync(filePath)) return null;\n const raw = fs.readFileSync(filePath, \"utf-8\");\n const parsed = JSON.parse(raw) as Partial<SessionMonitorState>;\n if (\n typeof parsed?.lastUserTimestamp !== \"string\" ||\n typeof parsed?.lastReportedAt !== \"string\" ||\n typeof parsed?.numTurnsAtLastReport !== \"number\"\n ) {\n // Malformed shape — treat as missing so we don't skip a real\n // report based on garbage state.\n return null;\n }\n return {\n lastUserTimestamp: parsed.lastUserTimestamp,\n lastReportedAt: parsed.lastReportedAt,\n numTurnsAtLastReport: parsed.numTurnsAtLastReport,\n };\n } catch (err) {\n log(\"state-load-failed\", {\n sessionId,\n error: (err as Error).message,\n });\n return null;\n }\n}\n\n/**\n * Persist state for `sessionId`. Creates the state directory on first\n * write. Filesystem errors are logged via `debugLog` and swallowed.\n */\nexport function saveSessionState(\n sessionId: string,\n state: SessionMonitorState,\n homeDir: string = os.homedir(),\n): void {\n if (!sessionId) return;\n const dir = getStateDir(homeDir);\n const filePath = getStateFile(sessionId, homeDir);\n try {\n if (!fs.existsSync(dir)) {\n fs.mkdirSync(dir, { recursive: true });\n }\n fs.writeFileSync(filePath, JSON.stringify(state, null, 2) + \"\\n\", \"utf-8\");\n } catch (err) {\n log(\"state-save-failed\", {\n sessionId,\n error: (err as Error).message,\n });\n }\n}\n\n/**\n * Decide whether to report the current turn given the last-reported\n * state and the current turn's user timestamp.\n *\n * Rules:\n * - currentUserTimestamp missing/empty → report (can't dedup).\n * - no existing state → report (first turn for this session).\n * - currentUserTimestamp === existing.lastUserTimestamp → SKIP.\n * - otherwise → report (a new user turn).\n */\nexport function shouldReportTurn(\n existing: SessionMonitorState | null,\n currentUserTimestamp: string | undefined,\n): boolean {\n if (!currentUserTimestamp) return true;\n if (!existing) return true;\n return existing.lastUserTimestamp !== currentUserTimestamp;\n}\n"],"mappings":"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","names":["program","listCommand","getCommand","createCommand","updateCommand","deleteCommand","program","listCommand","getCommand","createCommand","updateCommand","deleteCommand","program","listCommand","getCommand","createCommand","updateCommand","deleteCommand","program","prompt","listCommand","getCommand","program","fs","path","fs","os","path","program","require"]}
1
+ {"version":3,"sources":["../src/index.ts","../src/commands/login.ts","../src/lib/api.ts","../src/commands/logout.ts","../src/commands/whoami.ts","../src/commands/agents.ts","../src/commands/workflows.ts","../src/commands/kpis.ts","../src/commands/custom-data.ts","../src/commands/activity.ts","../src/commands/monitor.ts","../src/monitor/plugins/claude-code/index.ts","../src/monitor/plugin.ts","../src/commands/monitor-state.ts","../src/monitor/plugins/claude-code/install.ts","../src/monitor/prompt.ts","../src/monitor/validate-pasted-key.ts","../src/monitor/plugins/claude-code/hook.ts","../src/commands/monitor-transcript.ts","../src/monitor/plugins/codex/index.ts","../src/monitor/plugins/codex/install.ts","../src/monitor/plugins/codex/paths.ts","../src/monitor/plugins/codex/hooks.ts","../src/monitor/plugins/codex/config.ts","../src/monitor/plugins/codex/status.ts","../src/monitor/plugins/codex/transcript.ts","../src/monitor/plugins/codex/hook.ts","../src/monitor/plugins/cursor/index.ts","../src/monitor/plugins/cursor/install.ts","../src/monitor/plugins/cursor/config.ts","../src/monitor/plugins/cursor/paths.ts","../src/monitor/plugins/cursor/hooks-config.ts","../src/monitor/plugins/cursor/status.ts","../src/monitor/plugins/cursor/hook.ts","../src/monitor/plugins/cursor/pairing-state.ts"],"sourcesContent":["#!/usr/bin/env node\n\nimport { createRequire } from \"module\";\nimport { Command } from \"commander\";\nimport { loginCommand } from \"./commands/login.js\";\nimport { logoutCommand } from \"./commands/logout.js\";\nimport { whoamiCommand } from \"./commands/whoami.js\";\nimport { registerAgentsCommand } from \"./commands/agents.js\";\nimport { registerWorkflowsCommand } from \"./commands/workflows.js\";\nimport { registerKpisCommand } from \"./commands/kpis.js\";\nimport { registerCustomDataCommand } from \"./commands/custom-data.js\";\nimport { registerActivityCommand } from \"./commands/activity.js\";\nimport { registerMonitorCommand } from \"./commands/monitor.js\";\nimport {\n setEnvironment,\n isValidEnvironment,\n getValidEnvironments,\n type Environment,\n} from \"./lib/config.js\";\n\nconst require = createRequire(import.meta.url);\nconst packageJson = require(\"../package.json\") as { version: string };\n\nconst program = new Command();\n\nprogram\n .name(\"olakai\")\n .description(\"Olakai CLI tool\")\n .version(packageJson.version)\n .option(\n \"-e, --env <environment>\",\n `Environment to use (${getValidEnvironments().join(\", \")})`,\n \"production\",\n )\n .hook(\"preAction\", (thisCommand) => {\n const options = thisCommand.opts();\n if (options.env) {\n if (!isValidEnvironment(options.env)) {\n console.error(\n `Invalid environment: ${options.env}. Valid options: ${getValidEnvironments().join(\", \")}`,\n );\n process.exit(1);\n }\n setEnvironment(options.env as Environment);\n }\n });\n\nprogram\n .command(\"login\")\n .description(\"Log in to Olakai using browser authentication\")\n .action(loginCommand);\n\nprogram\n .command(\"logout\")\n .description(\"Log out from Olakai\")\n .action(logoutCommand);\n\nprogram\n .command(\"whoami\")\n .description(\"Show current logged-in user\")\n .action(whoamiCommand);\n\n// Register subcommands for config management\nregisterAgentsCommand(program);\nregisterWorkflowsCommand(program);\nregisterKpisCommand(program);\nregisterCustomDataCommand(program);\n\n// Register subcommands for activity inspection\nregisterActivityCommand(program);\n\n// Register subcommands for local agent monitoring\nregisterMonitorCommand(program);\n\nprogram.parse();\n","import open from \"open\";\nimport { requestDeviceCode, pollForToken, getCurrentUser } from \"../lib/api.js\";\nimport { saveToken, isTokenValid } from \"../lib/auth.js\";\nimport { getEnvironment } from \"../lib/config.js\";\n\nconst POLL_INTERVAL_MS = 5000; // 5 seconds\n\n/**\n * Login command handler\n */\nexport async function loginCommand(): Promise<void> {\n // Check if already logged in\n if (isTokenValid()) {\n try {\n const user = await getCurrentUser();\n console.log(`Already logged in as ${user.email}`);\n console.log(\"Run 'olakai logout' to log out first.\");\n return;\n } catch {\n // Token is invalid, continue with login\n }\n }\n\n console.log(`Logging in to Olakai (${getEnvironment()})...\\n`);\n\n try {\n // Request device code\n const deviceCode = await requestDeviceCode();\n\n // Display instructions\n console.log(\"To complete login, visit:\");\n console.log(`\\n ${deviceCode.verification_uri_complete}\\n`);\n console.log(`Or go to ${deviceCode.verification_uri} and enter code:`);\n console.log(`\\n ${deviceCode.user_code}\\n`);\n\n // Try to open browser\n console.log(\"Opening browser...\");\n try {\n await open(deviceCode.verification_uri_complete);\n } catch {\n console.log(\"(Could not open browser automatically)\");\n }\n\n console.log(\"\\nWaiting for authorization...\");\n\n // Poll for token\n const expiresAt = Date.now() + deviceCode.expires_in * 1000;\n\n while (Date.now() < expiresAt) {\n await sleep(POLL_INTERVAL_MS);\n\n try {\n const tokenResponse = await pollForToken(deviceCode.device_code);\n\n if (tokenResponse) {\n // Save token\n saveToken(tokenResponse.access_token, tokenResponse.expires_in);\n\n // Get user info\n const user = await getCurrentUser();\n\n console.log(`\\nLogged in as ${user.email}`);\n console.log(`Account: ${user.accountId}`);\n console.log(`Role: ${user.role}`);\n return;\n }\n\n // Still pending, show spinner\n process.stdout.write(\".\");\n } catch (error) {\n if (error instanceof Error) {\n console.error(`\\nLogin failed: ${error.message}`);\n } else {\n console.error(\"\\nLogin failed: Unknown error\");\n }\n process.exit(1);\n }\n }\n\n console.error(\"\\nLogin timed out. Please try again.\");\n process.exit(1);\n } catch (error) {\n if (error instanceof Error) {\n console.error(`Login failed: ${error.message}`);\n } else {\n console.error(\"Login failed: Unknown error\");\n }\n process.exit(1);\n }\n}\n\nfunction sleep(ms: number): Promise<void> {\n return new Promise((resolve) => setTimeout(resolve, ms));\n}\n","import { getBaseUrl, CLIENT_ID } from \"./config.js\";\nimport { getValidToken } from \"./auth.js\";\n\nexport interface DeviceCodeResponse {\n device_code: string;\n user_code: string;\n verification_uri: string;\n verification_uri_complete: string;\n expires_in: number;\n interval: number;\n}\n\nexport interface TokenResponse {\n access_token: string;\n token_type: string;\n expires_in: number;\n}\n\nexport interface TokenErrorResponse {\n error: \"authorization_pending\" | \"expired_token\" | \"access_denied\";\n error_description?: string;\n}\n\nexport interface UserMeResponse {\n id: string;\n email: string;\n firstName: string;\n lastName: string;\n role: string;\n accountId: string;\n}\n\n// Config API Types\nexport interface AgentApiKey {\n id: string;\n key?: string; // Only present on creation\n keyMasked: string;\n isActive: boolean;\n createdAt?: string;\n}\n\nexport type DefaultAggregationMethod =\n | \"SUM\"\n | \"AVERAGE\"\n | \"COUNT\"\n | \"MIN\"\n | \"MAX\"\n | \"LATEST\";\n\nexport type KpiScope = \"PROMPT_REQUEST\" | \"CHAT\" | \"DOCUMENT\";\n\nexport interface KpiDefinition {\n id: string;\n name: string;\n description: string | null;\n type: \"PREDEFINED\" | \"USER_DEFINED\";\n category: string | null;\n agentId: string | null;\n scope: KpiScope;\n calculatorId: string;\n calculatorParams: Record<string, unknown> | null;\n unit: string | null;\n defaultAggregationMethod: DefaultAggregationMethod;\n isActive: boolean;\n createdAt?: string;\n updatedAt?: string;\n}\n\nexport interface CreateKpiPayload {\n name: string;\n description?: string;\n type?: \"PREDEFINED\" | \"USER_DEFINED\";\n category?: string;\n agentId?: string;\n scope: KpiScope;\n calculatorId: string;\n calculatorParams?: Record<string, unknown>;\n unit?: string;\n defaultAggregationMethod?: DefaultAggregationMethod;\n}\n\nexport interface UpdateKpiPayload {\n name?: string;\n description?: string | null;\n type?: \"PREDEFINED\" | \"USER_DEFINED\";\n category?: string | null;\n agentId?: string | null;\n scope?: KpiScope;\n calculatorId?: string;\n calculatorParams?: Record<string, unknown>;\n unit?: string | null;\n defaultAggregationMethod?: DefaultAggregationMethod;\n isActive?: boolean;\n}\n\nexport interface ContextVariable {\n name: string;\n description: string;\n type: \"string\" | \"number\" | \"boolean\";\n sampleValue?: string | number | boolean;\n source: \"shared\" | \"custom\";\n}\n\nexport interface FormulaValidationResult {\n valid: boolean;\n error?: string;\n type?: string | null;\n charIndex?: number;\n parsedFormula?: unknown;\n}\n\nexport interface Agent {\n id: string;\n name: string;\n description: string;\n role: \"WORKER\" | \"COORDINATOR\";\n source: \"SDK\" | \"AUTOMATION_PROVIDER\";\n workflowId: string | null;\n category: string | null;\n apiKey: AgentApiKey | null;\n kpiDefinitions?: KpiDefinition[];\n workflow?: Workflow | null;\n}\n\nexport interface Workflow {\n id: string;\n name: string;\n description: string | null;\n isActive: boolean;\n agentCount: number;\n agents?: Agent[];\n createdAt?: string;\n updatedAt?: string;\n}\n\nexport interface CreateAgentPayload {\n name: string;\n description?: string;\n role?: \"WORKER\" | \"COORDINATOR\";\n workflowId?: string;\n createApiKey?: boolean;\n category?: string;\n source?: string;\n}\n\nexport interface UpdateAgentPayload {\n name?: string;\n description?: string;\n role?: \"WORKER\" | \"COORDINATOR\";\n workflowId?: string | null;\n category?: string | null;\n}\n\nexport interface CreateWorkflowPayload {\n name: string;\n description?: string;\n}\n\nexport interface UpdateWorkflowPayload {\n name?: string;\n description?: string | null;\n isActive?: boolean;\n}\n\n/**\n * Request a device code to start the login flow\n */\nexport async function requestDeviceCode(): Promise<DeviceCodeResponse> {\n const response = await fetch(`${getBaseUrl()}/api/auth/device/code`, {\n method: \"POST\",\n headers: {\n \"Content-Type\": \"application/json\",\n },\n body: JSON.stringify({ client_id: CLIENT_ID }),\n });\n\n if (!response.ok) {\n const error = (await response.json()) as { error_description?: string; error?: string };\n throw new Error(error.error_description || error.error || \"Failed to request device code\");\n }\n\n return (await response.json()) as DeviceCodeResponse;\n}\n\n/**\n * Poll for token exchange\n * Returns the token response if approved, or throws an error\n */\nexport async function pollForToken(\n deviceCode: string,\n): Promise<TokenResponse | null> {\n const response = await fetch(`${getBaseUrl()}/api/auth/device/token`, {\n method: \"POST\",\n headers: {\n \"Content-Type\": \"application/json\",\n },\n body: JSON.stringify({\n grant_type: \"urn:ietf:params:oauth:grant-type:device_code\",\n device_code: deviceCode,\n client_id: CLIENT_ID,\n }),\n });\n\n const data = (await response.json()) as TokenResponse | TokenErrorResponse;\n\n if (!response.ok) {\n if (\"error\" in data && data.error === \"authorization_pending\") {\n return null; // Still waiting for user\n }\n const errorMsg = \"error_description\" in data ? data.error_description : (\"error\" in data ? data.error : \"Token exchange failed\");\n throw new Error(errorMsg || \"Token exchange failed\");\n }\n\n return data as TokenResponse;\n}\n\n/**\n * Get current user info\n */\nexport async function getCurrentUser(): Promise<UserMeResponse> {\n const token = getValidToken();\n\n if (!token) {\n throw new Error(\"Not logged in. Run 'olakai login' first.\");\n }\n\n const response = await fetch(`${getBaseUrl()}/api/user/me`, {\n headers: {\n Authorization: `Bearer ${token}`,\n },\n });\n\n if (!response.ok) {\n if (response.status === 401) {\n throw new Error(\"Session expired. Run 'olakai login' to authenticate again.\");\n }\n throw new Error(\"Failed to get user info\");\n }\n\n return (await response.json()) as UserMeResponse;\n}\n\n// ============================================\n// Config API - Agents\n// ============================================\n\n/**\n * List agents for the current account\n */\nexport async function listAgents(options?: {\n includeKpis?: boolean;\n}): Promise<Agent[]> {\n const token = getValidToken();\n if (!token) {\n throw new Error(\"Not logged in. Run 'olakai login' first.\");\n }\n\n const params = new URLSearchParams();\n if (options?.includeKpis) {\n params.set(\"includeKpis\", \"true\");\n }\n\n const url = `${getBaseUrl()}/api/config/agents${params.toString() ? `?${params}` : \"\"}`;\n const response = await fetch(url, {\n headers: {\n Authorization: `Bearer ${token}`,\n },\n });\n\n if (!response.ok) {\n if (response.status === 401) {\n throw new Error(\"Session expired. Run 'olakai login' to authenticate again.\");\n }\n const error = (await response.json()) as { error?: string };\n throw new Error(error.error || \"Failed to list agents\");\n }\n\n const data = (await response.json()) as { agents: Agent[] };\n return data.agents;\n}\n\n/**\n * Get a single agent by ID\n */\nexport async function getAgent(id: string): Promise<Agent> {\n const token = getValidToken();\n if (!token) {\n throw new Error(\"Not logged in. Run 'olakai login' first.\");\n }\n\n const response = await fetch(`${getBaseUrl()}/api/config/agents/${id}`, {\n headers: {\n Authorization: `Bearer ${token}`,\n },\n });\n\n if (!response.ok) {\n if (response.status === 401) {\n throw new Error(\"Session expired. Run 'olakai login' to authenticate again.\");\n }\n if (response.status === 404) {\n throw new Error(\"Agent not found\");\n }\n const error = (await response.json()) as { error?: string };\n throw new Error(error.error || \"Failed to get agent\");\n }\n\n return (await response.json()) as Agent;\n}\n\n/**\n * Create a new agent\n */\nexport async function createAgent(payload: CreateAgentPayload): Promise<Agent> {\n const token = getValidToken();\n if (!token) {\n throw new Error(\"Not logged in. Run 'olakai login' first.\");\n }\n\n const response = await fetch(`${getBaseUrl()}/api/config/agents`, {\n method: \"POST\",\n headers: {\n Authorization: `Bearer ${token}`,\n \"Content-Type\": \"application/json\",\n },\n body: JSON.stringify(payload),\n });\n\n if (!response.ok) {\n if (response.status === 401) {\n throw new Error(\"Session expired. Run 'olakai login' to authenticate again.\");\n }\n if (response.status === 409) {\n throw new Error(\"An agent with this name already exists\");\n }\n const error = (await response.json()) as { error?: string };\n throw new Error(error.error || \"Failed to create agent\");\n }\n\n return (await response.json()) as Agent;\n}\n\n/**\n * Update an agent\n */\nexport async function updateAgent(\n id: string,\n payload: UpdateAgentPayload,\n): Promise<Agent> {\n const token = getValidToken();\n if (!token) {\n throw new Error(\"Not logged in. Run 'olakai login' first.\");\n }\n\n const response = await fetch(`${getBaseUrl()}/api/config/agents/${id}`, {\n method: \"PUT\",\n headers: {\n Authorization: `Bearer ${token}`,\n \"Content-Type\": \"application/json\",\n },\n body: JSON.stringify(payload),\n });\n\n if (!response.ok) {\n if (response.status === 401) {\n throw new Error(\"Session expired. Run 'olakai login' to authenticate again.\");\n }\n if (response.status === 404) {\n throw new Error(\"Agent not found\");\n }\n if (response.status === 409) {\n throw new Error(\"An agent with this name already exists\");\n }\n const error = (await response.json()) as { error?: string };\n throw new Error(error.error || \"Failed to update agent\");\n }\n\n return (await response.json()) as Agent;\n}\n\n/**\n * Delete an agent\n */\nexport async function deleteAgent(id: string): Promise<void> {\n const token = getValidToken();\n if (!token) {\n throw new Error(\"Not logged in. Run 'olakai login' first.\");\n }\n\n const response = await fetch(`${getBaseUrl()}/api/config/agents/${id}`, {\n method: \"DELETE\",\n headers: {\n Authorization: `Bearer ${token}`,\n },\n });\n\n if (!response.ok) {\n if (response.status === 401) {\n throw new Error(\"Session expired. Run 'olakai login' to authenticate again.\");\n }\n if (response.status === 404) {\n throw new Error(\"Agent not found\");\n }\n const error = (await response.json()) as { error?: string };\n throw new Error(error.error || \"Failed to delete agent\");\n }\n}\n\n// ============================================\n// Config API - Workflows\n// ============================================\n\n/**\n * List workflows for the current account\n */\nexport async function listWorkflows(options?: {\n includeAgents?: boolean;\n includeInactive?: boolean;\n}): Promise<Workflow[]> {\n const token = getValidToken();\n if (!token) {\n throw new Error(\"Not logged in. Run 'olakai login' first.\");\n }\n\n const params = new URLSearchParams();\n if (options?.includeAgents) {\n params.set(\"includeAgents\", \"true\");\n }\n if (options?.includeInactive) {\n params.set(\"includeInactive\", \"true\");\n }\n\n const url = `${getBaseUrl()}/api/config/workflows${params.toString() ? `?${params}` : \"\"}`;\n const response = await fetch(url, {\n headers: {\n Authorization: `Bearer ${token}`,\n },\n });\n\n if (!response.ok) {\n if (response.status === 401) {\n throw new Error(\"Session expired. Run 'olakai login' to authenticate again.\");\n }\n const error = (await response.json()) as { error?: string };\n throw new Error(error.error || \"Failed to list workflows\");\n }\n\n const data = (await response.json()) as { workflows: Workflow[] };\n return data.workflows;\n}\n\n/**\n * Get a single workflow by ID\n */\nexport async function getWorkflow(id: string): Promise<Workflow> {\n const token = getValidToken();\n if (!token) {\n throw new Error(\"Not logged in. Run 'olakai login' first.\");\n }\n\n const response = await fetch(`${getBaseUrl()}/api/config/workflows/${id}`, {\n headers: {\n Authorization: `Bearer ${token}`,\n },\n });\n\n if (!response.ok) {\n if (response.status === 401) {\n throw new Error(\"Session expired. Run 'olakai login' to authenticate again.\");\n }\n if (response.status === 404) {\n throw new Error(\"Workflow not found\");\n }\n const error = (await response.json()) as { error?: string };\n throw new Error(error.error || \"Failed to get workflow\");\n }\n\n return (await response.json()) as Workflow;\n}\n\n/**\n * Create a new workflow\n */\nexport async function createWorkflow(\n payload: CreateWorkflowPayload,\n): Promise<Workflow> {\n const token = getValidToken();\n if (!token) {\n throw new Error(\"Not logged in. Run 'olakai login' first.\");\n }\n\n const response = await fetch(`${getBaseUrl()}/api/config/workflows`, {\n method: \"POST\",\n headers: {\n Authorization: `Bearer ${token}`,\n \"Content-Type\": \"application/json\",\n },\n body: JSON.stringify(payload),\n });\n\n if (!response.ok) {\n if (response.status === 401) {\n throw new Error(\"Session expired. Run 'olakai login' to authenticate again.\");\n }\n if (response.status === 409) {\n throw new Error(\"A workflow with this name already exists\");\n }\n const error = (await response.json()) as { error?: string };\n throw new Error(error.error || \"Failed to create workflow\");\n }\n\n return (await response.json()) as Workflow;\n}\n\n/**\n * Update a workflow\n */\nexport async function updateWorkflow(\n id: string,\n payload: UpdateWorkflowPayload,\n): Promise<Workflow> {\n const token = getValidToken();\n if (!token) {\n throw new Error(\"Not logged in. Run 'olakai login' first.\");\n }\n\n const response = await fetch(`${getBaseUrl()}/api/config/workflows/${id}`, {\n method: \"PUT\",\n headers: {\n Authorization: `Bearer ${token}`,\n \"Content-Type\": \"application/json\",\n },\n body: JSON.stringify(payload),\n });\n\n if (!response.ok) {\n if (response.status === 401) {\n throw new Error(\"Session expired. Run 'olakai login' to authenticate again.\");\n }\n if (response.status === 404) {\n throw new Error(\"Workflow not found\");\n }\n if (response.status === 409) {\n throw new Error(\"A workflow with this name already exists\");\n }\n const error = (await response.json()) as { error?: string };\n throw new Error(error.error || \"Failed to update workflow\");\n }\n\n return (await response.json()) as Workflow;\n}\n\n/**\n * Delete a workflow\n */\nexport async function deleteWorkflow(id: string): Promise<void> {\n const token = getValidToken();\n if (!token) {\n throw new Error(\"Not logged in. Run 'olakai login' first.\");\n }\n\n const response = await fetch(`${getBaseUrl()}/api/config/workflows/${id}`, {\n method: \"DELETE\",\n headers: {\n Authorization: `Bearer ${token}`,\n },\n });\n\n if (!response.ok) {\n if (response.status === 401) {\n throw new Error(\"Session expired. Run 'olakai login' to authenticate again.\");\n }\n if (response.status === 404) {\n throw new Error(\"Workflow not found\");\n }\n const error = (await response.json()) as { error?: string };\n throw new Error(error.error || \"Failed to delete workflow\");\n }\n}\n\n// ============================================\n// Config API - KPIs\n// ============================================\n\n/**\n * List KPI definitions for the current account\n */\nexport async function listKpis(options?: {\n agentId?: string;\n includeInactive?: boolean;\n}): Promise<KpiDefinition[]> {\n const token = getValidToken();\n if (!token) {\n throw new Error(\"Not logged in. Run 'olakai login' first.\");\n }\n\n const params = new URLSearchParams();\n if (options?.agentId) {\n params.set(\"agentId\", options.agentId);\n }\n if (options?.includeInactive) {\n params.set(\"includeInactive\", \"true\");\n }\n\n const url = `${getBaseUrl()}/api/config/kpis${params.toString() ? `?${params}` : \"\"}`;\n const response = await fetch(url, {\n headers: {\n Authorization: `Bearer ${token}`,\n },\n });\n\n if (!response.ok) {\n if (response.status === 401) {\n throw new Error(\"Session expired. Run 'olakai login' to authenticate again.\");\n }\n const error = (await response.json()) as { error?: string };\n throw new Error(error.error || \"Failed to list KPIs\");\n }\n\n const data = (await response.json()) as { kpiDefinitions: KpiDefinition[] };\n return data.kpiDefinitions;\n}\n\n/**\n * Get a single KPI definition by ID\n */\nexport async function getKpi(id: string): Promise<KpiDefinition> {\n const token = getValidToken();\n if (!token) {\n throw new Error(\"Not logged in. Run 'olakai login' first.\");\n }\n\n const response = await fetch(`${getBaseUrl()}/api/config/kpis/${id}`, {\n headers: {\n Authorization: `Bearer ${token}`,\n },\n });\n\n if (!response.ok) {\n if (response.status === 401) {\n throw new Error(\"Session expired. Run 'olakai login' to authenticate again.\");\n }\n if (response.status === 404) {\n throw new Error(\"KPI definition not found\");\n }\n const error = (await response.json()) as { error?: string };\n throw new Error(error.error || \"Failed to get KPI\");\n }\n\n return (await response.json()) as KpiDefinition;\n}\n\n/**\n * Create a new KPI definition\n */\nexport async function createKpi(payload: CreateKpiPayload): Promise<KpiDefinition> {\n const token = getValidToken();\n if (!token) {\n throw new Error(\"Not logged in. Run 'olakai login' first.\");\n }\n\n const response = await fetch(`${getBaseUrl()}/api/config/kpis`, {\n method: \"POST\",\n headers: {\n Authorization: `Bearer ${token}`,\n \"Content-Type\": \"application/json\",\n },\n body: JSON.stringify(payload),\n });\n\n if (!response.ok) {\n if (response.status === 401) {\n throw new Error(\"Session expired. Run 'olakai login' to authenticate again.\");\n }\n if (response.status === 409) {\n throw new Error(\"A KPI definition with this name already exists\");\n }\n const error = (await response.json()) as { error?: string };\n throw new Error(error.error || \"Failed to create KPI\");\n }\n\n return (await response.json()) as KpiDefinition;\n}\n\n/**\n * Update a KPI definition\n */\nexport async function updateKpi(\n id: string,\n payload: UpdateKpiPayload,\n): Promise<KpiDefinition> {\n const token = getValidToken();\n if (!token) {\n throw new Error(\"Not logged in. Run 'olakai login' first.\");\n }\n\n const response = await fetch(`${getBaseUrl()}/api/config/kpis/${id}`, {\n method: \"PUT\",\n headers: {\n Authorization: `Bearer ${token}`,\n \"Content-Type\": \"application/json\",\n },\n body: JSON.stringify(payload),\n });\n\n if (!response.ok) {\n if (response.status === 401) {\n throw new Error(\"Session expired. Run 'olakai login' to authenticate again.\");\n }\n if (response.status === 404) {\n throw new Error(\"KPI definition not found\");\n }\n if (response.status === 409) {\n throw new Error(\"A KPI definition with this name already exists\");\n }\n const error = (await response.json()) as { error?: string };\n throw new Error(error.error || \"Failed to update KPI\");\n }\n\n return (await response.json()) as KpiDefinition;\n}\n\n/**\n * Delete a KPI definition\n */\nexport async function deleteKpi(id: string): Promise<void> {\n const token = getValidToken();\n if (!token) {\n throw new Error(\"Not logged in. Run 'olakai login' first.\");\n }\n\n const response = await fetch(`${getBaseUrl()}/api/config/kpis/${id}`, {\n method: \"DELETE\",\n headers: {\n Authorization: `Bearer ${token}`,\n },\n });\n\n if (!response.ok) {\n if (response.status === 401) {\n throw new Error(\"Session expired. Run 'olakai login' to authenticate again.\");\n }\n if (response.status === 404) {\n throw new Error(\"KPI definition not found\");\n }\n const error = (await response.json()) as { error?: string };\n throw new Error(error.error || \"Failed to delete KPI\");\n }\n}\n\n/**\n * Get available context variables for KPI formulas\n */\nexport async function getKpiContextVariables(\n agentId?: string,\n scope?: KpiScope,\n): Promise<ContextVariable[]> {\n const token = getValidToken();\n if (!token) {\n throw new Error(\"Not logged in. Run 'olakai login' first.\");\n }\n\n const params = new URLSearchParams();\n if (agentId) {\n params.set(\"agentId\", agentId);\n }\n if (scope) {\n params.set(\"scope\", scope);\n }\n\n const url = `${getBaseUrl()}/api/config/kpis/context-variables${params.toString() ? `?${params}` : \"\"}`;\n const response = await fetch(url, {\n headers: {\n Authorization: `Bearer ${token}`,\n },\n });\n\n if (!response.ok) {\n if (response.status === 401) {\n throw new Error(\"Session expired. Run 'olakai login' to authenticate again.\");\n }\n const error = (await response.json()) as { error?: string };\n throw new Error(error.error || \"Failed to get context variables\");\n }\n\n const data = (await response.json()) as { contextVariables: ContextVariable[] };\n return data.contextVariables;\n}\n\n/**\n * Validate a KPI formula expression\n */\nexport async function validateKpiFormula(\n formula: string,\n agentId?: string,\n scope?: KpiScope,\n): Promise<FormulaValidationResult> {\n const token = getValidToken();\n if (!token) {\n throw new Error(\"Not logged in. Run 'olakai login' first.\");\n }\n\n const body: Record<string, string | undefined> = { formula, agentId };\n if (scope) {\n body.scope = scope;\n }\n\n const response = await fetch(`${getBaseUrl()}/api/config/kpis/validate`, {\n method: \"POST\",\n headers: {\n Authorization: `Bearer ${token}`,\n \"Content-Type\": \"application/json\",\n },\n body: JSON.stringify(body),\n });\n\n if (!response.ok) {\n if (response.status === 401) {\n throw new Error(\"Session expired. Run 'olakai login' to authenticate again.\");\n }\n const error = (await response.json()) as { error?: string };\n throw new Error(error.error || \"Failed to validate formula\");\n }\n\n return (await response.json()) as FormulaValidationResult;\n}\n\n// ============================================\n// Monitoring API - API Key Validation\n// ============================================\n\nexport interface ApiKeyValidationResult {\n apiKeyId: string;\n accountId: string;\n}\n\n/**\n * Validates a monitoring API key by calling /api/monitoring/prompt/me.\n * Returns the apiKeyId + accountId the key resolves to, or null if the\n * key is invalid (any non-2xx) or the request fails for any reason.\n *\n * Used by `monitor init` to verify the user pasted a key that belongs\n * to the agent they picked. The endpoint is derived from the monitoring\n * endpoint by appending \"/me\".\n */\nexport async function validateMonitoringApiKey(\n monitoringEndpoint: string,\n apiKey: string,\n): Promise<ApiKeyValidationResult | null> {\n // Strip a single trailing slash before appending \"/me\" so we don't\n // produce a double slash in the resolved URL.\n const normalizedEndpoint = monitoringEndpoint.replace(/\\/+$/, \"\");\n const url = `${normalizedEndpoint}/me`;\n\n const controller = new AbortController();\n const timeout = setTimeout(() => controller.abort(), 5000);\n\n try {\n const response = await fetch(url, {\n method: \"GET\",\n headers: {\n \"x-api-key\": apiKey,\n },\n signal: controller.signal,\n });\n\n if (!response.ok) {\n return null;\n }\n\n const data = (await response.json()) as Partial<ApiKeyValidationResult>;\n if (\n typeof data?.accountId !== \"string\" ||\n typeof data?.apiKeyId !== \"string\"\n ) {\n return null;\n }\n\n return { accountId: data.accountId, apiKeyId: data.apiKeyId };\n } catch {\n // Network failure, abort timeout, JSON parse error — any failure\n // soft-fails to null so callers can decide how to surface it.\n return null;\n } finally {\n clearTimeout(timeout);\n }\n}\n\n// ============================================\n// Activity API - Prompt Inspection\n// ============================================\n\nexport interface ActivityPrompt {\n id: string;\n createdAt: string;\n agentId: string | null;\n agentName?: string | null;\n workflowId: string | null;\n workflowName?: string | null;\n taskExecutionId?: string | null;\n app: string;\n modelType: string | null;\n modelId: string | null;\n tokens: number;\n requestTime: number;\n isHighRisk: boolean;\n blocked: boolean;\n decorationStatus: string;\n sensitivity: string[];\n prompt?: string;\n response?: string;\n analytics?: {\n task: string | null;\n subtask: string | null;\n timesaved_minutes: number | null;\n riskassessment_dangerousity: number | null;\n };\n kpiData?: Record<string, unknown>;\n}\n\nexport interface ActivityListResponse {\n prompts: ActivityPrompt[];\n total: number;\n limit: number;\n offset: number;\n hasMore: boolean;\n}\n\nexport interface ActivityListOptions {\n agentId?: string;\n workflowId?: string;\n since?: string;\n until?: string;\n limit?: number;\n offset?: number;\n includeContent?: boolean;\n includeAnalytics?: boolean;\n}\n\nexport interface CoreKpiValue {\n name: string;\n value: number;\n measurement: \"count\" | \"ratio\" | \"sum\";\n unitPrefix?: string;\n unitSuffix?: string;\n}\n\nexport interface AggregatedKpi {\n kpiDefinitionId: string;\n name: string;\n value: number | null;\n aggregationMethod: string;\n unit: string | null;\n dataPointCount: number;\n}\n\nexport interface PeriodKpiData {\n periodStart: string;\n periodEnd: string;\n coreKpis: CoreKpiValue[];\n}\n\nexport interface KpiAtom {\n promptRequestId: string;\n createdAt: string;\n kpis: Record<string, unknown>;\n}\n\nexport interface ActivityKpisResponse {\n coreKpis: CoreKpiValue[];\n kpis: AggregatedKpi[];\n periodData?: PeriodKpiData[];\n atoms?: KpiAtom[];\n}\n\nexport interface ActivityKpisOptions {\n agentId?: string;\n workflowId?: string;\n since?: string;\n until?: string;\n period?: \"hourly\" | \"daily\" | \"weekly\";\n includeAtoms?: boolean;\n}\n\n/**\n * List activity prompts with filters\n */\nexport async function listActivity(\n options: ActivityListOptions = {}\n): Promise<ActivityListResponse> {\n const token = getValidToken();\n if (!token) {\n throw new Error(\"Not logged in. Run 'olakai login' first.\");\n }\n\n const params = new URLSearchParams();\n if (options.agentId) params.set(\"agentId\", options.agentId);\n if (options.workflowId) params.set(\"workflowId\", options.workflowId);\n if (options.since) params.set(\"since\", options.since);\n if (options.until) params.set(\"until\", options.until);\n if (options.limit !== undefined) params.set(\"limit\", String(options.limit));\n if (options.offset !== undefined) params.set(\"offset\", String(options.offset));\n if (options.includeContent) params.set(\"includeContent\", \"true\");\n if (options.includeAnalytics) params.set(\"includeAnalytics\", \"true\");\n\n const url = `${getBaseUrl()}/api/activity/prompts${params.toString() ? `?${params}` : \"\"}`;\n const response = await fetch(url, {\n headers: {\n Authorization: `Bearer ${token}`,\n },\n });\n\n if (!response.ok) {\n if (response.status === 401) {\n throw new Error(\"Session expired. Run 'olakai login' to authenticate again.\");\n }\n const error = (await response.json()) as { error?: string };\n throw new Error(error.error || \"Failed to list activity\");\n }\n\n return (await response.json()) as ActivityListResponse;\n}\n\n/**\n * Get a single activity prompt by ID\n */\nexport async function getActivity(\n id: string,\n includeContent?: boolean\n): Promise<ActivityPrompt> {\n const token = getValidToken();\n if (!token) {\n throw new Error(\"Not logged in. Run 'olakai login' first.\");\n }\n\n const params = new URLSearchParams();\n if (includeContent) params.set(\"includeContent\", \"true\");\n\n const url = `${getBaseUrl()}/api/activity/prompts/${id}${params.toString() ? `?${params}` : \"\"}`;\n const response = await fetch(url, {\n headers: {\n Authorization: `Bearer ${token}`,\n },\n });\n\n if (!response.ok) {\n if (response.status === 401) {\n throw new Error(\"Session expired. Run 'olakai login' to authenticate again.\");\n }\n if (response.status === 404) {\n throw new Error(\"Prompt request not found\");\n }\n const error = (await response.json()) as { error?: string };\n throw new Error(error.error || \"Failed to get activity\");\n }\n\n return (await response.json()) as ActivityPrompt;\n}\n\n/**\n * Get aggregated KPI values for an agent or workflow\n */\nexport async function getActivityKpis(\n options: ActivityKpisOptions\n): Promise<ActivityKpisResponse> {\n const token = getValidToken();\n if (!token) {\n throw new Error(\"Not logged in. Run 'olakai login' first.\");\n }\n\n if (!options.agentId && !options.workflowId) {\n throw new Error(\"Either agentId or workflowId is required\");\n }\n\n const params = new URLSearchParams();\n if (options.agentId) params.set(\"agentId\", options.agentId);\n if (options.workflowId) params.set(\"workflowId\", options.workflowId);\n if (options.since) params.set(\"since\", options.since);\n if (options.until) params.set(\"until\", options.until);\n if (options.period) params.set(\"period\", options.period);\n if (options.includeAtoms) params.set(\"includeAtoms\", \"true\");\n\n const url = `${getBaseUrl()}/api/activity/kpis${params.toString() ? `?${params}` : \"\"}`;\n const response = await fetch(url, {\n headers: {\n Authorization: `Bearer ${token}`,\n },\n });\n\n if (!response.ok) {\n if (response.status === 401) {\n throw new Error(\"Session expired. Run 'olakai login' to authenticate again.\");\n }\n const error = (await response.json()) as { error?: string };\n throw new Error(error.error || \"Failed to get activity KPIs\");\n }\n\n return (await response.json()) as ActivityKpisResponse;\n}\n\n// ============================================\n// Activity API - Session Diagnostics\n// ============================================\n\nexport interface SessionDiagnostic {\n id: string;\n createdAt: string;\n agentId: string | null;\n decorationStatus: string;\n decorationDate: string | null;\n decorationCandidate: boolean;\n decorationError: string | null;\n decorationErrorStreak: number;\n decoratorVersion: string | null;\n hasKpiData: boolean;\n}\n\nexport interface SessionsListResponse {\n sessions: SessionDiagnostic[];\n summary: {\n sessionCount: number;\n byStatus: Record<string, number>;\n };\n total: number;\n limit: number;\n offset: number;\n hasMore: boolean;\n}\n\nexport interface SessionsListOptions {\n agentId: string;\n since?: string;\n until?: string;\n limit?: number;\n offset?: number;\n}\n\n/**\n * List session diagnostics for an agent\n */\nexport async function listSessions(\n options: SessionsListOptions,\n): Promise<SessionsListResponse> {\n const token = getValidToken();\n if (!token) {\n throw new Error(\"Not logged in. Run 'olakai login' first.\");\n }\n\n const params = new URLSearchParams();\n params.set(\"agentId\", options.agentId);\n if (options.since) params.set(\"since\", options.since);\n if (options.until) params.set(\"until\", options.until);\n if (options.limit !== undefined) params.set(\"limit\", String(options.limit));\n if (options.offset !== undefined) params.set(\"offset\", String(options.offset));\n\n const url = `${getBaseUrl()}/api/activity/sessions?${params}`;\n const response = await fetch(url, {\n headers: {\n Authorization: `Bearer ${token}`,\n },\n });\n\n if (!response.ok) {\n if (response.status === 401) {\n throw new Error(\"Session expired. Run 'olakai login' to authenticate again.\");\n }\n const error = (await response.json()) as { error?: string };\n throw new Error(error.error || \"Failed to list sessions\");\n }\n\n return (await response.json()) as SessionsListResponse;\n}\n\n// Custom Data Config Types\nexport type CustomDataType = \"STRING\" | \"NUMBER\" | \"BOOLEAN\";\n\nexport interface CustomDataConfig {\n id: string;\n accountId: string;\n agentId: string | null; // NULL means legacy account-level config\n name: string;\n description: string | null;\n type: CustomDataType;\n createdAt?: string;\n updatedAt?: string;\n}\n\nexport interface CreateCustomDataPayload {\n agentId: string; // Required for new configs\n name: string;\n description?: string | null;\n type: CustomDataType;\n}\n\nexport interface UpdateCustomDataPayload {\n name?: string;\n description?: string | null;\n type?: CustomDataType;\n // Note: agentId is not updatable after creation\n}\n\n/**\n * List custom data configurations\n * @param agentId - Optional agent ID to filter by. If provided, returns agent-specific configs\n * merged with legacy account-level configs. If omitted, returns all account configs.\n */\nexport async function listCustomDataConfigs(agentId?: string): Promise<CustomDataConfig[]> {\n const token = getValidToken();\n if (!token) {\n throw new Error(\"Not logged in. Run 'olakai login' first.\");\n }\n\n const params = new URLSearchParams();\n if (agentId) {\n params.set(\"agentId\", agentId);\n }\n\n const url = `${getBaseUrl()}/api/config/custom-data${params.toString() ? `?${params}` : \"\"}`;\n const response = await fetch(url, {\n headers: {\n Authorization: `Bearer ${token}`,\n },\n });\n\n if (!response.ok) {\n if (response.status === 401) {\n throw new Error(\"Session expired. Run 'olakai login' to authenticate again.\");\n }\n const error = (await response.json()) as { error?: string };\n throw new Error(error.error || \"Failed to list custom data configurations\");\n }\n\n const data = (await response.json()) as { customDataConfigs: CustomDataConfig[] };\n return data.customDataConfigs;\n}\n\n/**\n * Get a single custom data configuration\n */\nexport async function getCustomDataConfig(id: string): Promise<CustomDataConfig> {\n const token = getValidToken();\n if (!token) {\n throw new Error(\"Not logged in. Run 'olakai login' first.\");\n }\n\n const url = `${getBaseUrl()}/api/config/custom-data/${encodeURIComponent(id)}`;\n const response = await fetch(url, {\n headers: {\n Authorization: `Bearer ${token}`,\n },\n });\n\n if (!response.ok) {\n if (response.status === 401) {\n throw new Error(\"Session expired. Run 'olakai login' to authenticate again.\");\n }\n if (response.status === 404) {\n throw new Error(\"Custom data configuration not found\");\n }\n const error = (await response.json()) as { error?: string };\n throw new Error(error.error || \"Failed to get custom data configuration\");\n }\n\n return (await response.json()) as CustomDataConfig;\n}\n\n/**\n * Create a new custom data configuration\n */\nexport async function createCustomDataConfig(\n payload: CreateCustomDataPayload\n): Promise<CustomDataConfig> {\n const token = getValidToken();\n if (!token) {\n throw new Error(\"Not logged in. Run 'olakai login' first.\");\n }\n\n const url = `${getBaseUrl()}/api/config/custom-data`;\n const response = await fetch(url, {\n method: \"POST\",\n headers: {\n Authorization: `Bearer ${token}`,\n \"Content-Type\": \"application/json\",\n },\n body: JSON.stringify(payload),\n });\n\n if (!response.ok) {\n if (response.status === 401) {\n throw new Error(\"Session expired. Run 'olakai login' to authenticate again.\");\n }\n if (response.status === 409) {\n throw new Error(\"A custom data configuration with this name already exists\");\n }\n const error = (await response.json()) as { error?: string };\n throw new Error(error.error || \"Failed to create custom data configuration\");\n }\n\n return (await response.json()) as CustomDataConfig;\n}\n\n/**\n * Update a custom data configuration\n */\nexport async function updateCustomDataConfig(\n id: string,\n payload: UpdateCustomDataPayload\n): Promise<CustomDataConfig> {\n const token = getValidToken();\n if (!token) {\n throw new Error(\"Not logged in. Run 'olakai login' first.\");\n }\n\n const url = `${getBaseUrl()}/api/config/custom-data/${encodeURIComponent(id)}`;\n const response = await fetch(url, {\n method: \"PUT\",\n headers: {\n Authorization: `Bearer ${token}`,\n \"Content-Type\": \"application/json\",\n },\n body: JSON.stringify(payload),\n });\n\n if (!response.ok) {\n if (response.status === 401) {\n throw new Error(\"Session expired. Run 'olakai login' to authenticate again.\");\n }\n if (response.status === 404) {\n throw new Error(\"Custom data configuration not found\");\n }\n if (response.status === 409) {\n throw new Error(\"A custom data configuration with this name already exists\");\n }\n const error = (await response.json()) as { error?: string };\n throw new Error(error.error || \"Failed to update custom data configuration\");\n }\n\n return (await response.json()) as CustomDataConfig;\n}\n\n/**\n * Delete a custom data configuration\n */\nexport async function deleteCustomDataConfig(id: string): Promise<void> {\n const token = getValidToken();\n if (!token) {\n throw new Error(\"Not logged in. Run 'olakai login' first.\");\n }\n\n const url = `${getBaseUrl()}/api/config/custom-data/${encodeURIComponent(id)}`;\n const response = await fetch(url, {\n method: \"DELETE\",\n headers: {\n Authorization: `Bearer ${token}`,\n },\n });\n\n if (!response.ok) {\n if (response.status === 401) {\n throw new Error(\"Session expired. Run 'olakai login' to authenticate again.\");\n }\n if (response.status === 404) {\n throw new Error(\"Custom data configuration not found\");\n }\n const error = (await response.json()) as { error?: string };\n throw new Error(error.error || \"Failed to delete custom data configuration\");\n }\n}\n","import { clearToken, isTokenValid } from \"../lib/auth.js\";\n\n/**\n * Logout command handler\n */\nexport function logoutCommand(): void {\n if (!isTokenValid()) {\n console.log(\"Not currently logged in.\");\n return;\n }\n\n clearToken();\n console.log(\"Logged out successfully.\");\n}\n","import { getCurrentUser } from \"../lib/api.js\";\nimport { isTokenValid } from \"../lib/auth.js\";\nimport { getEnvironment } from \"../lib/config.js\";\n\n/**\n * Whoami command handler\n */\nexport async function whoamiCommand(): Promise<void> {\n if (!isTokenValid()) {\n console.log(\"Not logged in. Run 'olakai login' to authenticate.\");\n process.exit(1);\n }\n\n try {\n const user = await getCurrentUser();\n\n console.log(`Email: ${user.email}`);\n console.log(`Name: ${user.firstName} ${user.lastName}`);\n console.log(`Role: ${user.role}`);\n console.log(`Account ID: ${user.accountId}`);\n console.log(`Environment: ${getEnvironment()}`);\n } catch (error) {\n if (error instanceof Error) {\n console.error(`Error: ${error.message}`);\n } else {\n console.error(\"Failed to get user info\");\n }\n process.exit(1);\n }\n}\n","import { Command } from \"commander\";\nimport {\n listAgents,\n getAgent,\n createAgent,\n updateAgent,\n deleteAgent,\n type Agent,\n} from \"../lib/api.js\";\n\nfunction formatAgentTable(agents: Agent[]): void {\n if (agents.length === 0) {\n console.log(\"No agents found.\");\n return;\n }\n\n // Calculate column widths\n const headers = [\"ID\", \"NAME\", \"ROLE\", \"WORKFLOW\", \"API KEY\"];\n const rows = agents.map((agent) => [\n agent.id.slice(0, 12) + \"...\",\n agent.name.slice(0, 30),\n agent.role,\n agent.workflowId ? agent.workflowId.slice(0, 12) + \"...\" : \"-\",\n agent.apiKey ? (agent.apiKey.isActive ? \"Active\" : \"Inactive\") : \"None\",\n ]);\n\n const widths = headers.map((h, i) =>\n Math.max(h.length, ...rows.map((r) => r[i].length))\n );\n\n // Print header\n console.log(headers.map((h, i) => h.padEnd(widths[i])).join(\" \"));\n console.log(widths.map((w) => \"-\".repeat(w)).join(\" \"));\n\n // Print rows\n for (const row of rows) {\n console.log(row.map((cell, i) => cell.padEnd(widths[i])).join(\" \"));\n }\n}\n\nfunction formatAgentDetail(agent: Agent): void {\n console.log(`ID: ${agent.id}`);\n console.log(`Name: ${agent.name}`);\n console.log(`Description: ${agent.description || \"-\"}`);\n console.log(`Role: ${agent.role}`);\n console.log(`Source: ${agent.source}`);\n console.log(`Category: ${agent.category || \"-\"}`);\n console.log(`Workflow ID: ${agent.workflowId || \"-\"}`);\n\n if (agent.workflow) {\n console.log(`Workflow: ${agent.workflow.name}`);\n }\n\n console.log(\"\");\n console.log(\"API Key:\");\n if (agent.apiKey) {\n console.log(` ID: ${agent.apiKey.id}`);\n if (agent.apiKey.key) {\n console.log(` Key: ${agent.apiKey.key}`);\n } else {\n console.log(` Key: ${agent.apiKey.keyMasked}`);\n }\n console.log(` Status: ${agent.apiKey.isActive ? \"Active\" : \"Inactive\"}`);\n } else {\n console.log(\" None\");\n }\n\n if (agent.kpiDefinitions && agent.kpiDefinitions.length > 0) {\n console.log(\"\");\n console.log(\"KPI Definitions:\");\n for (const kpi of agent.kpiDefinitions) {\n console.log(` - ${kpi.name} (${kpi.type})`);\n }\n }\n}\n\nasync function listCommand(options: {\n json?: boolean;\n includeKpis?: boolean;\n}): Promise<void> {\n try {\n const agents = await listAgents({ includeKpis: options.includeKpis });\n\n if (options.json) {\n console.log(JSON.stringify(agents, null, 2));\n } else {\n formatAgentTable(agents);\n }\n } catch (error) {\n console.error(\n `Error: ${error instanceof Error ? error.message : \"Unknown error\"}`\n );\n process.exit(1);\n }\n}\n\nasync function getCommand(id: string, options: { json?: boolean }): Promise<void> {\n try {\n const agent = await getAgent(id);\n\n if (options.json) {\n console.log(JSON.stringify(agent, null, 2));\n } else {\n formatAgentDetail(agent);\n }\n } catch (error) {\n console.error(\n `Error: ${error instanceof Error ? error.message : \"Unknown error\"}`\n );\n process.exit(1);\n }\n}\n\nasync function createCommand(options: {\n name: string;\n description?: string;\n role?: string;\n workflow?: string;\n withApiKey?: boolean;\n category?: string;\n json?: boolean;\n}): Promise<void> {\n try {\n if (!options.name) {\n console.error(\"Error: --name is required\");\n process.exit(1);\n }\n\n const agent = await createAgent({\n name: options.name,\n description: options.description || \"\",\n role: (options.role as \"WORKER\" | \"COORDINATOR\") || \"WORKER\",\n workflowId: options.workflow,\n createApiKey: options.withApiKey || false,\n category: options.category,\n });\n\n if (options.json) {\n console.log(JSON.stringify(agent, null, 2));\n } else {\n console.log(\"Agent created successfully!\");\n console.log(\"\");\n formatAgentDetail(agent);\n\n if (agent.apiKey?.key) {\n console.log(\"\");\n console.log(\n \"IMPORTANT: Save your API key now. It will not be shown again.\"\n );\n }\n }\n } catch (error) {\n console.error(\n `Error: ${error instanceof Error ? error.message : \"Unknown error\"}`\n );\n process.exit(1);\n }\n}\n\nasync function updateCommand(\n id: string,\n options: {\n name?: string;\n description?: string;\n role?: string;\n workflow?: string;\n category?: string;\n json?: boolean;\n }\n): Promise<void> {\n try {\n const payload: {\n name?: string;\n description?: string;\n role?: \"WORKER\" | \"COORDINATOR\";\n workflowId?: string | null;\n category?: string | null;\n } = {};\n\n if (options.name !== undefined) payload.name = options.name;\n if (options.description !== undefined)\n payload.description = options.description;\n if (options.role !== undefined)\n payload.role = options.role as \"WORKER\" | \"COORDINATOR\";\n if (options.workflow !== undefined) payload.workflowId = options.workflow;\n if (options.category !== undefined) payload.category = options.category;\n\n if (Object.keys(payload).length === 0) {\n console.error(\"Error: At least one field to update is required\");\n process.exit(1);\n }\n\n const agent = await updateAgent(id, payload);\n\n if (options.json) {\n console.log(JSON.stringify(agent, null, 2));\n } else {\n console.log(\"Agent updated successfully!\");\n console.log(\"\");\n formatAgentDetail(agent);\n }\n } catch (error) {\n console.error(\n `Error: ${error instanceof Error ? error.message : \"Unknown error\"}`\n );\n process.exit(1);\n }\n}\n\nasync function deleteCommand(\n id: string,\n options: { force?: boolean }\n): Promise<void> {\n try {\n if (!options.force) {\n // In a real CLI, we'd use readline for confirmation\n // For now, require --force flag\n console.log(\"Are you sure you want to delete this agent?\");\n console.log(\"Use --force to confirm deletion.\");\n process.exit(1);\n }\n\n await deleteAgent(id);\n console.log(\"Agent deleted successfully.\");\n } catch (error) {\n console.error(\n `Error: ${error instanceof Error ? error.message : \"Unknown error\"}`\n );\n process.exit(1);\n }\n}\n\nexport function registerAgentsCommand(program: Command): void {\n const agents = program\n .command(\"agents\")\n .description(\"Manage agents\");\n\n agents\n .command(\"list\")\n .description(\"List all agents\")\n .option(\"--json\", \"Output as JSON\")\n .option(\"--include-kpis\", \"Include KPI definitions\")\n .action(listCommand);\n\n agents\n .command(\"get <id>\")\n .description(\"Get agent details\")\n .option(\"--json\", \"Output as JSON\")\n .action(getCommand);\n\n agents\n .command(\"create\")\n .description(\"Create a new agent\")\n .requiredOption(\"--name <name>\", \"Agent name\")\n .option(\"--description <description>\", \"Agent description\")\n .option(\"--role <role>\", \"Agent role (WORKER or COORDINATOR)\", \"WORKER\")\n .option(\"--workflow <id>\", \"Workflow ID to assign\")\n .option(\"--with-api-key\", \"Create an API key for this agent\")\n .option(\"--category <category>\", \"Agent category\")\n .option(\"--json\", \"Output as JSON\")\n .action(createCommand);\n\n agents\n .command(\"update <id>\")\n .description(\"Update an agent\")\n .option(\"--name <name>\", \"Agent name\")\n .option(\"--description <description>\", \"Agent description\")\n .option(\"--role <role>\", \"Agent role (WORKER or COORDINATOR)\")\n .option(\"--workflow <id>\", \"Workflow ID to assign\")\n .option(\"--category <category>\", \"Agent category\")\n .option(\"--json\", \"Output as JSON\")\n .action(updateCommand);\n\n agents\n .command(\"delete <id>\")\n .description(\"Delete an agent\")\n .option(\"--force\", \"Skip confirmation\")\n .action(deleteCommand);\n}\n","import { Command } from \"commander\";\nimport {\n listWorkflows,\n getWorkflow,\n createWorkflow,\n updateWorkflow,\n deleteWorkflow,\n type Workflow,\n} from \"../lib/api.js\";\n\nfunction formatWorkflowTable(workflows: Workflow[]): void {\n if (workflows.length === 0) {\n console.log(\"No workflows found.\");\n return;\n }\n\n // Calculate column widths\n const headers = [\"ID\", \"NAME\", \"AGENTS\", \"STATUS\"];\n const rows = workflows.map((wf) => [\n wf.id.slice(0, 12) + \"...\",\n wf.name.slice(0, 30),\n wf.agentCount.toString(),\n wf.isActive ? \"Active\" : \"Inactive\",\n ]);\n\n const widths = headers.map((h, i) =>\n Math.max(h.length, ...rows.map((r) => r[i].length))\n );\n\n // Print header\n console.log(headers.map((h, i) => h.padEnd(widths[i])).join(\" \"));\n console.log(widths.map((w) => \"-\".repeat(w)).join(\" \"));\n\n // Print rows\n for (const row of rows) {\n console.log(row.map((cell, i) => cell.padEnd(widths[i])).join(\" \"));\n }\n}\n\nfunction formatWorkflowDetail(workflow: Workflow): void {\n console.log(`ID: ${workflow.id}`);\n console.log(`Name: ${workflow.name}`);\n console.log(`Description: ${workflow.description || \"-\"}`);\n console.log(`Status: ${workflow.isActive ? \"Active\" : \"Inactive\"}`);\n console.log(`Agents: ${workflow.agentCount}`);\n if (workflow.createdAt) {\n console.log(`Created: ${new Date(workflow.createdAt).toISOString()}`);\n }\n if (workflow.updatedAt) {\n console.log(`Updated: ${new Date(workflow.updatedAt).toISOString()}`);\n }\n\n if (workflow.agents && workflow.agents.length > 0) {\n console.log(\"\");\n console.log(\"Agents:\");\n for (const agent of workflow.agents) {\n const apiKeyStatus = agent.apiKey\n ? agent.apiKey.isActive\n ? \"API Key: Active\"\n : \"API Key: Inactive\"\n : \"No API Key\";\n console.log(` - ${agent.name} (${agent.role}) - ${apiKeyStatus}`);\n }\n }\n}\n\nasync function listCommand(options: {\n json?: boolean;\n includeAgents?: boolean;\n includeInactive?: boolean;\n}): Promise<void> {\n try {\n const workflows = await listWorkflows({\n includeAgents: options.includeAgents,\n includeInactive: options.includeInactive,\n });\n\n if (options.json) {\n console.log(JSON.stringify(workflows, null, 2));\n } else {\n formatWorkflowTable(workflows);\n }\n } catch (error) {\n console.error(\n `Error: ${error instanceof Error ? error.message : \"Unknown error\"}`\n );\n process.exit(1);\n }\n}\n\nasync function getCommand(id: string, options: { json?: boolean }): Promise<void> {\n try {\n const workflow = await getWorkflow(id);\n\n if (options.json) {\n console.log(JSON.stringify(workflow, null, 2));\n } else {\n formatWorkflowDetail(workflow);\n }\n } catch (error) {\n console.error(\n `Error: ${error instanceof Error ? error.message : \"Unknown error\"}`\n );\n process.exit(1);\n }\n}\n\nasync function createCommand(options: {\n name: string;\n description?: string;\n json?: boolean;\n}): Promise<void> {\n try {\n if (!options.name) {\n console.error(\"Error: --name is required\");\n process.exit(1);\n }\n\n const workflow = await createWorkflow({\n name: options.name,\n description: options.description,\n });\n\n if (options.json) {\n console.log(JSON.stringify(workflow, null, 2));\n } else {\n console.log(\"Workflow created successfully!\");\n console.log(\"\");\n formatWorkflowDetail(workflow);\n }\n } catch (error) {\n console.error(\n `Error: ${error instanceof Error ? error.message : \"Unknown error\"}`\n );\n process.exit(1);\n }\n}\n\nasync function updateCommand(\n id: string,\n options: {\n name?: string;\n description?: string;\n active?: boolean;\n inactive?: boolean;\n json?: boolean;\n }\n): Promise<void> {\n try {\n const payload: {\n name?: string;\n description?: string | null;\n isActive?: boolean;\n } = {};\n\n if (options.name !== undefined) payload.name = options.name;\n if (options.description !== undefined)\n payload.description = options.description;\n if (options.active) payload.isActive = true;\n if (options.inactive) payload.isActive = false;\n\n if (Object.keys(payload).length === 0) {\n console.error(\"Error: At least one field to update is required\");\n process.exit(1);\n }\n\n const workflow = await updateWorkflow(id, payload);\n\n if (options.json) {\n console.log(JSON.stringify(workflow, null, 2));\n } else {\n console.log(\"Workflow updated successfully!\");\n console.log(\"\");\n formatWorkflowDetail(workflow);\n }\n } catch (error) {\n console.error(\n `Error: ${error instanceof Error ? error.message : \"Unknown error\"}`\n );\n process.exit(1);\n }\n}\n\nasync function deleteCommand(\n id: string,\n options: { force?: boolean }\n): Promise<void> {\n try {\n if (!options.force) {\n // In a real CLI, we'd use readline for confirmation\n // For now, require --force flag\n console.log(\"Are you sure you want to delete this workflow?\");\n console.log(\"Use --force to confirm deletion.\");\n process.exit(1);\n }\n\n await deleteWorkflow(id);\n console.log(\"Workflow deleted successfully.\");\n } catch (error) {\n console.error(\n `Error: ${error instanceof Error ? error.message : \"Unknown error\"}`\n );\n process.exit(1);\n }\n}\n\nexport function registerWorkflowsCommand(program: Command): void {\n const workflows = program\n .command(\"workflows\")\n .description(\"Manage workflows\");\n\n workflows\n .command(\"list\")\n .description(\"List all workflows\")\n .option(\"--json\", \"Output as JSON\")\n .option(\"--include-agents\", \"Include agent details\")\n .option(\"--include-inactive\", \"Include inactive workflows\")\n .action(listCommand);\n\n workflows\n .command(\"get <id>\")\n .description(\"Get workflow details\")\n .option(\"--json\", \"Output as JSON\")\n .action(getCommand);\n\n workflows\n .command(\"create\")\n .description(\"Create a new workflow\")\n .requiredOption(\"--name <name>\", \"Workflow name\")\n .option(\"--description <description>\", \"Workflow description\")\n .option(\"--json\", \"Output as JSON\")\n .action(createCommand);\n\n workflows\n .command(\"update <id>\")\n .description(\"Update a workflow\")\n .option(\"--name <name>\", \"Workflow name\")\n .option(\"--description <description>\", \"Workflow description\")\n .option(\"--active\", \"Set workflow as active\")\n .option(\"--inactive\", \"Set workflow as inactive\")\n .option(\"--json\", \"Output as JSON\")\n .action(updateCommand);\n\n workflows\n .command(\"delete <id>\")\n .description(\"Delete a workflow\")\n .option(\"--force\", \"Skip confirmation\")\n .action(deleteCommand);\n}\n","import { Command } from \"commander\";\nimport {\n listKpis,\n getKpi,\n createKpi,\n updateKpi,\n deleteKpi,\n getKpiContextVariables,\n validateKpiFormula,\n type KpiDefinition,\n type KpiScope,\n type ContextVariable,\n type CreateKpiPayload,\n type DefaultAggregationMethod,\n} from \"../lib/api.js\";\n\nconst AGGREGATION_METHODS: DefaultAggregationMethod[] = [\n \"SUM\",\n \"AVERAGE\",\n \"COUNT\",\n \"MIN\",\n \"MAX\",\n \"LATEST\",\n];\n\nconst CALCULATOR_IDS = [\"formula\", \"classifier\", \"llm-data\"];\n\nconst KPI_SCOPES: KpiScope[] = [\"PROMPT_REQUEST\", \"CHAT\", \"DOCUMENT\"];\n\n// Classifier template definitions — mirrors CLASSIFIER_TEMPLATES from\n// localnode-app/packages/config/classifier-templates.ts\ntype OutputClassOption = { label: string; value: number };\n\ntype ClassifierTemplate = {\n id: string;\n name: string;\n description: string;\n promptTemplate: string;\n defaultUnit: string;\n defaultOutputClasses: OutputClassOption[];\n};\n\nconst CLASSIFIER_TEMPLATES: ClassifierTemplate[] = [\n {\n id: \"sentiment_scorer\",\n name: \"Sentiment Scorer\",\n description:\n \"Scores the overall emotional tone and user satisfaction of a conversation\",\n defaultUnit: \"score\",\n promptTemplate: `Analyze the overall sentiment of the following AI assistant conversation. Consider the user's tone, satisfaction level, and emotional state throughout the interaction.\n\nConversation:\n{{Complete exchange}}\n\nRate the sentiment using exactly one of these numeric scores:\n{{outputClassDescriptions}}\n\nRespond with only the numeric score.`,\n defaultOutputClasses: [\n { label: \"Very Negative\", value: 1 },\n { label: \"Negative\", value: 2 },\n { label: \"Neutral\", value: 3 },\n { label: \"Positive\", value: 4 },\n { label: \"Very Positive\", value: 5 },\n ],\n },\n {\n id: \"time_saved_estimator\",\n name: \"Time Saved Estimator\",\n description:\n \"Estimates how much time the AI interaction saved compared to manual effort\",\n defaultUnit: \"minutes\",\n promptTemplate: `Estimate how much time this AI assistant interaction saved the user compared to completing the task manually without AI assistance. Consider the complexity of the request, the completeness of the response, and typical human effort for similar tasks.\n\nConversation:\n{{Complete exchange}}\n\nClassify the estimated time saved using exactly one of these values (in minutes):\n{{outputClassDescriptions}}\n\nRespond with only the numeric value.`,\n defaultOutputClasses: [\n { label: \"No time saved\", value: 0 },\n { label: \"A few minutes\", value: 3 },\n { label: \"Moderate time\", value: 10 },\n { label: \"Significant time\", value: 30 },\n { label: \"Major time savings\", value: 60 },\n ],\n },\n];\n\nfunction resolveOutputClassDescriptions(classes: OutputClassOption[]): string {\n return classes.map((c) => `${c.value} = ${c.label}`).join(\"\\n\");\n}\n\nfunction resolveTemplatePrompt(\n template: ClassifierTemplate,\n classes: OutputClassOption[],\n): string {\n return template.promptTemplate.replace(\n \"{{outputClassDescriptions}}\",\n resolveOutputClassDescriptions(classes),\n );\n}\n\nfunction formatKpiTable(kpis: KpiDefinition[]): void {\n if (kpis.length === 0) {\n console.log(\"No KPI definitions found.\");\n return;\n }\n\n // Calculate column widths\n const headers = [\"ID\", \"NAME\", \"SCOPE\", \"CALCULATOR\", \"AGGREGATION\", \"STATUS\"];\n const rows = kpis.map((kpi) => [\n kpi.id.slice(0, 12) + \"...\",\n kpi.name.slice(0, 25),\n kpi.scope || \"PROMPT_REQUEST\",\n kpi.calculatorId,\n kpi.defaultAggregationMethod,\n kpi.isActive ? \"Active\" : \"Inactive\",\n ]);\n\n const widths = headers.map((h, i) =>\n Math.max(h.length, ...rows.map((r) => r[i].length))\n );\n\n // Print header\n console.log(headers.map((h, i) => h.padEnd(widths[i])).join(\" \"));\n console.log(widths.map((w) => \"-\".repeat(w)).join(\" \"));\n\n // Print rows\n for (const row of rows) {\n console.log(row.map((cell, i) => cell.padEnd(widths[i])).join(\" \"));\n }\n}\n\nfunction formatKpiDetail(kpi: KpiDefinition): void {\n console.log(`ID: ${kpi.id}`);\n console.log(`Name: ${kpi.name}`);\n console.log(`Description: ${kpi.description || \"-\"}`);\n console.log(`Type: ${kpi.type}`);\n console.log(`Category: ${kpi.category || \"-\"}`);\n console.log(`Agent ID: ${kpi.agentId || \"-\"}`);\n console.log(`Scope: ${kpi.scope || \"PROMPT_REQUEST\"}`);\n console.log(`Calculator: ${kpi.calculatorId}`);\n console.log(`Aggregation: ${kpi.defaultAggregationMethod}`);\n console.log(`Unit: ${kpi.unit || \"-\"}`);\n console.log(`Status: ${kpi.isActive ? \"Active\" : \"Inactive\"}`);\n\n if (kpi.calculatorParams) {\n console.log(\"\");\n console.log(\"Calculator Parameters:\");\n console.log(JSON.stringify(kpi.calculatorParams, null, 2));\n }\n\n if (kpi.createdAt) {\n console.log(\"\");\n console.log(`Created: ${new Date(kpi.createdAt).toISOString()}`);\n }\n if (kpi.updatedAt) {\n console.log(`Updated: ${new Date(kpi.updatedAt).toISOString()}`);\n }\n}\n\nfunction formatContextVariablesTable(variables: ContextVariable[]): void {\n if (variables.length === 0) {\n console.log(\"No context variables found.\");\n return;\n }\n\n // Calculate column widths\n const headers = [\"NAME\", \"TYPE\", \"SOURCE\", \"DESCRIPTION\"];\n const rows = variables.map((v) => [\n v.name,\n v.type,\n v.source,\n v.description.slice(0, 50),\n ]);\n\n const widths = headers.map((h, i) =>\n Math.max(h.length, ...rows.map((r) => r[i].length))\n );\n\n // Print header\n console.log(headers.map((h, i) => h.padEnd(widths[i])).join(\" \"));\n console.log(widths.map((w) => \"-\".repeat(w)).join(\" \"));\n\n // Print rows\n for (const row of rows) {\n console.log(row.map((cell, i) => cell.padEnd(widths[i])).join(\" \"));\n }\n}\n\nasync function listCommand(options: {\n json?: boolean;\n agentId?: string;\n includeInactive?: boolean;\n}): Promise<void> {\n try {\n const kpis = await listKpis({\n agentId: options.agentId,\n includeInactive: options.includeInactive,\n });\n\n if (options.json) {\n console.log(JSON.stringify(kpis, null, 2));\n } else {\n formatKpiTable(kpis);\n }\n } catch (error) {\n console.error(\n `Error: ${error instanceof Error ? error.message : \"Unknown error\"}`\n );\n process.exit(1);\n }\n}\n\nasync function getCommand(\n id: string,\n options: { json?: boolean }\n): Promise<void> {\n try {\n const kpi = await getKpi(id);\n\n if (options.json) {\n console.log(JSON.stringify(kpi, null, 2));\n } else {\n formatKpiDetail(kpi);\n }\n } catch (error) {\n console.error(\n `Error: ${error instanceof Error ? error.message : \"Unknown error\"}`\n );\n process.exit(1);\n }\n}\n\nasync function createCommand(options: {\n name: string;\n calculatorId: string;\n scope: string;\n description?: string;\n type?: string;\n category?: string;\n agentId?: string;\n formula?: string;\n templateId?: string;\n outputClasses?: string;\n outputLabels?: string;\n samplingFactor?: string;\n unit?: string;\n aggregation?: string;\n json?: boolean;\n}): Promise<void> {\n try {\n if (!options.name) {\n console.error(\"Error: --name is required\");\n process.exit(1);\n }\n\n if (!options.calculatorId) {\n console.error(\"Error: --calculator-id is required\");\n console.error(`Valid values: ${CALCULATOR_IDS.join(\", \")}`);\n process.exit(1);\n }\n\n if (!CALCULATOR_IDS.includes(options.calculatorId)) {\n console.error(`Error: Invalid calculator ID \"${options.calculatorId}\"`);\n console.error(`Valid values: ${CALCULATOR_IDS.join(\", \")}`);\n process.exit(1);\n }\n\n // Validate scope\n const upperScope = options.scope.toUpperCase() as KpiScope;\n if (!KPI_SCOPES.includes(upperScope)) {\n console.error(`Error: Invalid scope \"${options.scope}\"`);\n console.error(`Valid values: ${KPI_SCOPES.join(\", \")}`);\n process.exit(1);\n }\n\n // Build calculator params\n let calculatorParams: Record<string, unknown> | undefined;\n let resolvedUnit = options.unit;\n\n if (options.calculatorId === \"formula\") {\n if (!options.formula) {\n console.error(\n \"Error: --formula is required when calculator-id is 'formula'\"\n );\n process.exit(1);\n }\n // Validate and parse the formula using the API\n const validation = await validateKpiFormula(options.formula, options.agentId, upperScope);\n if (!validation.valid) {\n console.error(`Error: Invalid formula: ${validation.error}`);\n process.exit(1);\n }\n // Use the parsed formula AST, not the raw string\n calculatorParams = { formula: validation.parsedFormula };\n } else if (options.calculatorId === \"classifier\") {\n if (!options.templateId) {\n console.error(\n \"Error: Classifier KPIs require --template-id. Run `olakai kpis templates` to see available templates.\"\n );\n process.exit(1);\n }\n\n const templateIds = CLASSIFIER_TEMPLATES.map((t) => t.id);\n const template = CLASSIFIER_TEMPLATES.find(\n (t) => t.id === options.templateId,\n );\n if (!template) {\n console.error(\n `Error: Unknown template \"${options.templateId}\". Valid templates: ${templateIds.join(\", \")}`\n );\n process.exit(1);\n }\n\n // Resolve output classes — use overrides if provided, else template defaults\n let outputClasses = template.defaultOutputClasses;\n if (options.outputClasses || options.outputLabels) {\n const rawValues = options.outputClasses\n ? options.outputClasses.split(\",\").map((v) => v.trim())\n : template.defaultOutputClasses.map((c) => String(c.value));\n const rawLabels = options.outputLabels\n ? options.outputLabels.split(\",\").map((l) => l.trim())\n : template.defaultOutputClasses.map((c) => c.label);\n\n if (rawValues.length !== rawLabels.length) {\n console.error(\n `Error: --output-classes (${rawValues.length} values) and --output-labels (${rawLabels.length} labels) must have the same count.`\n );\n process.exit(1);\n }\n\n outputClasses = rawValues.map((v, i) => ({\n label: rawLabels[i],\n value: Number(v),\n }));\n }\n\n // Resolve prompt with output class descriptions\n const promptTemplate = resolveTemplatePrompt(template, outputClasses);\n\n calculatorParams = {\n promptTemplate,\n outputClasses: outputClasses.map((c) => c.value),\n outputClassLabels: outputClasses.map((c) => c.label),\n classifierTemplateId: template.id,\n };\n\n // Parse sampling factor if provided\n if (options.samplingFactor !== undefined) {\n const factor = Number(options.samplingFactor);\n if (isNaN(factor) || factor < 0 || factor > 1) {\n console.error(\"Error: --sampling-factor must be a number between 0 and 1.\");\n process.exit(1);\n }\n calculatorParams.samplingFactor = factor;\n }\n\n // Use template default unit unless explicitly overridden\n if (!resolvedUnit) {\n resolvedUnit = template.defaultUnit;\n }\n }\n\n // Validate aggregation method\n let aggregation: DefaultAggregationMethod | undefined;\n if (options.aggregation) {\n const upperAggregation =\n options.aggregation.toUpperCase() as DefaultAggregationMethod;\n if (!AGGREGATION_METHODS.includes(upperAggregation)) {\n console.error(`Error: Invalid aggregation method \"${options.aggregation}\"`);\n console.error(`Valid values: ${AGGREGATION_METHODS.join(\", \")}`);\n process.exit(1);\n }\n aggregation = upperAggregation;\n }\n\n const payload: CreateKpiPayload = {\n name: options.name,\n calculatorId: options.calculatorId,\n scope: upperScope,\n description: options.description,\n type:\n options.type === \"PREDEFINED\" ? \"PREDEFINED\" : \"USER_DEFINED\",\n category: options.category,\n agentId: options.agentId,\n calculatorParams,\n unit: resolvedUnit,\n defaultAggregationMethod: aggregation,\n };\n\n const kpi = await createKpi(payload);\n\n if (options.json) {\n console.log(JSON.stringify(kpi, null, 2));\n } else {\n console.log(\"KPI definition created successfully!\");\n console.log(\"\");\n formatKpiDetail(kpi);\n }\n } catch (error) {\n console.error(\n `Error: ${error instanceof Error ? error.message : \"Unknown error\"}`\n );\n process.exit(1);\n }\n}\n\nasync function updateCommand(\n id: string,\n options: {\n name?: string;\n description?: string;\n category?: string;\n agentId?: string;\n scope?: string;\n calculatorId?: string;\n formula?: string;\n unit?: string;\n aggregation?: string;\n active?: boolean;\n inactive?: boolean;\n json?: boolean;\n }\n): Promise<void> {\n try {\n const payload: Record<string, unknown> = {};\n\n if (options.name !== undefined) payload.name = options.name;\n if (options.description !== undefined)\n payload.description = options.description;\n if (options.category !== undefined) payload.category = options.category;\n if (options.agentId !== undefined) payload.agentId = options.agentId;\n if (options.calculatorId !== undefined)\n payload.calculatorId = options.calculatorId;\n if (options.unit !== undefined) payload.unit = options.unit;\n if (options.active) payload.isActive = true;\n if (options.inactive) payload.isActive = false;\n\n // Validate and set scope\n let validatedScope: KpiScope | undefined;\n if (options.scope !== undefined) {\n const upperScope = options.scope.toUpperCase() as KpiScope;\n if (!KPI_SCOPES.includes(upperScope)) {\n console.error(`Error: Invalid scope \"${options.scope}\"`);\n console.error(`Valid values: ${KPI_SCOPES.join(\", \")}`);\n process.exit(1);\n }\n payload.scope = upperScope;\n validatedScope = upperScope;\n }\n\n // Handle formula update - validate and parse before storing\n if (options.formula !== undefined) {\n const validation = await validateKpiFormula(options.formula, options.agentId, validatedScope);\n if (!validation.valid) {\n console.error(`Error: Invalid formula: ${validation.error}`);\n process.exit(1);\n }\n // Use the parsed formula AST, not the raw string\n payload.calculatorParams = { formula: validation.parsedFormula };\n }\n\n // Validate and set aggregation method\n if (options.aggregation) {\n const upperAggregation =\n options.aggregation.toUpperCase() as DefaultAggregationMethod;\n if (!AGGREGATION_METHODS.includes(upperAggregation)) {\n console.error(`Error: Invalid aggregation method \"${options.aggregation}\"`);\n console.error(`Valid values: ${AGGREGATION_METHODS.join(\", \")}`);\n process.exit(1);\n }\n payload.defaultAggregationMethod = upperAggregation;\n }\n\n if (Object.keys(payload).length === 0) {\n console.error(\"Error: At least one field to update is required\");\n process.exit(1);\n }\n\n const kpi = await updateKpi(id, payload);\n\n if (options.json) {\n console.log(JSON.stringify(kpi, null, 2));\n } else {\n console.log(\"KPI definition updated successfully!\");\n console.log(\"\");\n formatKpiDetail(kpi);\n }\n } catch (error) {\n console.error(\n `Error: ${error instanceof Error ? error.message : \"Unknown error\"}`\n );\n process.exit(1);\n }\n}\n\nasync function deleteCommand(\n id: string,\n options: { force?: boolean }\n): Promise<void> {\n try {\n if (!options.force) {\n console.log(\"Are you sure you want to delete this KPI definition?\");\n console.log(\"Use --force to confirm deletion.\");\n process.exit(1);\n }\n\n await deleteKpi(id);\n console.log(\"KPI definition deleted successfully.\");\n } catch (error) {\n console.error(\n `Error: ${error instanceof Error ? error.message : \"Unknown error\"}`\n );\n process.exit(1);\n }\n}\n\nasync function contextVariablesCommand(options: {\n json?: boolean;\n agentId?: string;\n scope?: string;\n}): Promise<void> {\n try {\n // Validate scope if provided\n let validatedScope: KpiScope | undefined;\n if (options.scope) {\n const upperScope = options.scope.toUpperCase() as KpiScope;\n if (!KPI_SCOPES.includes(upperScope)) {\n console.error(`Error: Invalid scope \"${options.scope}\"`);\n console.error(`Valid values: ${KPI_SCOPES.join(\", \")}`);\n process.exit(1);\n }\n validatedScope = upperScope;\n }\n\n const variables = await getKpiContextVariables(options.agentId, validatedScope);\n\n if (options.json) {\n console.log(JSON.stringify(variables, null, 2));\n } else {\n console.log(\"Available context variables for KPI formulas:\");\n console.log(\"\");\n formatContextVariablesTable(variables);\n console.log(\"\");\n console.log(\n \"Use these variable names in your formula expressions, e.g.:\"\n );\n console.log(' IF(PII detected, 1, 0)');\n console.log(' Documents count * 10');\n console.log(' IF(CODE detected AND SECRET detected, \"high-risk\", \"normal\")');\n }\n } catch (error) {\n console.error(\n `Error: ${error instanceof Error ? error.message : \"Unknown error\"}`\n );\n process.exit(1);\n }\n}\n\nasync function validateCommand(options: {\n formula: string;\n agentId?: string;\n scope?: string;\n json?: boolean;\n}): Promise<void> {\n try {\n if (!options.formula) {\n console.error(\"Error: --formula is required\");\n process.exit(1);\n }\n\n // Validate scope if provided\n let validatedScope: KpiScope | undefined;\n if (options.scope) {\n const upperScope = options.scope.toUpperCase() as KpiScope;\n if (!KPI_SCOPES.includes(upperScope)) {\n console.error(`Error: Invalid scope \"${options.scope}\"`);\n console.error(`Valid values: ${KPI_SCOPES.join(\", \")}`);\n process.exit(1);\n }\n validatedScope = upperScope;\n }\n\n const result = await validateKpiFormula(options.formula, options.agentId, validatedScope);\n\n if (options.json) {\n console.log(JSON.stringify(result, null, 2));\n } else {\n if (result.valid) {\n console.log(\"Formula is valid!\");\n console.log(`Result type: ${result.type || \"unknown\"}`);\n } else {\n console.error(\"Formula is invalid:\");\n console.error(` ${result.error}`);\n if (result.charIndex !== undefined) {\n console.error(` Position: character ${result.charIndex}`);\n }\n process.exit(1);\n }\n }\n } catch (error) {\n console.error(\n `Error: ${error instanceof Error ? error.message : \"Unknown error\"}`\n );\n process.exit(1);\n }\n}\n\nfunction templatesCommand(options: { json?: boolean }): void {\n if (options.json) {\n console.log(\n JSON.stringify(\n CLASSIFIER_TEMPLATES.map((t) => ({\n id: t.id,\n name: t.name,\n description: t.description,\n defaultUnit: t.defaultUnit,\n outputClasses: t.defaultOutputClasses,\n })),\n null,\n 2,\n ),\n );\n } else {\n console.log(\"Available Classifier Templates:\");\n console.log(\"\");\n for (const t of CLASSIFIER_TEMPLATES) {\n console.log(` ${t.id.padEnd(24)} ${t.description}`);\n const classRange = t.defaultOutputClasses;\n console.log(\n `${\"\".padEnd(26)}Classes: ${classRange.map((c) => `${c.value} (${c.label})`).join(\", \")}`,\n );\n console.log(\n `${\"\".padEnd(26)}Default unit: ${t.defaultUnit}`,\n );\n console.log(\"\");\n }\n console.log(\"Usage:\");\n console.log(\n ' olakai kpis create --name \"User Satisfaction\" --calculator-id classifier --template-id sentiment_scorer --scope CHAT',\n );\n }\n}\n\nexport function registerKpisCommand(program: Command): void {\n const kpis = program\n .command(\"kpis\")\n .description(\"Manage KPI definitions\");\n\n kpis\n .command(\"list\")\n .description(\"List all KPI definitions\")\n .option(\"--json\", \"Output as JSON\")\n .option(\"--agent-id <id>\", \"Filter by agent ID\")\n .option(\"--include-inactive\", \"Include inactive KPI definitions\")\n .action(listCommand);\n\n kpis\n .command(\"get <id>\")\n .description(\"Get KPI definition details\")\n .option(\"--json\", \"Output as JSON\")\n .action(getCommand);\n\n kpis\n .command(\"create\")\n .description(\"Create a new KPI definition\")\n .requiredOption(\"--name <name>\", \"KPI name\")\n .requiredOption(\n \"--calculator-id <id>\",\n \"Calculator type: formula, classifier, or llm-data\"\n )\n .requiredOption(\n \"--scope <scope>\",\n \"KPI scope: PROMPT_REQUEST, CHAT, or DOCUMENT\"\n )\n .option(\"--description <description>\", \"KPI description\")\n .option(\"--type <type>\", \"KPI type: PREDEFINED or USER_DEFINED (default)\")\n .option(\"--category <category>\", \"KPI category for grouping\")\n .option(\"--agent-id <id>\", \"Associate KPI with a specific agent\")\n .option(\"--formula <formula>\", \"Formula expression (required for formula calculator)\")\n .option(\"--template-id <id>\", \"Classifier template: sentiment_scorer, time_saved_estimator\")\n .option(\"--output-classes <values>\", \"Override output class values (comma-separated numbers)\")\n .option(\"--output-labels <labels>\", \"Override output class labels (comma-separated)\")\n .option(\"--sampling-factor <factor>\", \"Fraction of events to classify, 0-1 (cost control)\")\n .option(\"--unit <unit>\", 'Display unit (e.g., \"ms\", \"%\", \"count\")')\n .option(\n \"--aggregation <method>\",\n \"Default aggregation: SUM, AVERAGE, COUNT, MIN, MAX, LATEST (default)\"\n )\n .option(\"--json\", \"Output as JSON\")\n .action(createCommand);\n\n kpis\n .command(\"templates\")\n .description(\"List available classifier templates\")\n .option(\"--json\", \"Output as JSON\")\n .action(templatesCommand);\n\n kpis\n .command(\"update <id>\")\n .description(\"Update a KPI definition\")\n .option(\"--name <name>\", \"KPI name\")\n .option(\"--description <description>\", \"KPI description\")\n .option(\"--category <category>\", \"KPI category\")\n .option(\"--agent-id <id>\", \"Associate with agent\")\n .option(\"--scope <scope>\", \"KPI scope: PROMPT_REQUEST, CHAT, or DOCUMENT\")\n .option(\"--calculator-id <id>\", \"Calculator type\")\n .option(\"--formula <formula>\", \"Formula expression\")\n .option(\"--unit <unit>\", \"Display unit\")\n .option(\"--aggregation <method>\", \"Default aggregation method\")\n .option(\"--active\", \"Set KPI as active\")\n .option(\"--inactive\", \"Set KPI as inactive\")\n .option(\"--json\", \"Output as JSON\")\n .action(updateCommand);\n\n kpis\n .command(\"delete <id>\")\n .description(\"Delete a KPI definition\")\n .option(\"--force\", \"Skip confirmation\")\n .action(deleteCommand);\n\n kpis\n .command(\"context-variables\")\n .description(\"List available context variables for formulas\")\n .option(\"--json\", \"Output as JSON\")\n .option(\"--agent-id <id>\", \"Include agent-specific variables\")\n .option(\"--scope <scope>\", \"Filter variables by scope: PROMPT_REQUEST, CHAT, or DOCUMENT\")\n .action(contextVariablesCommand);\n\n kpis\n .command(\"validate\")\n .description(\"Validate a KPI formula expression\")\n .requiredOption(\"--formula <formula>\", \"Formula expression to validate\")\n .option(\"--agent-id <id>\", \"Include agent-specific context\")\n .option(\"--scope <scope>\", \"Validate against scope: PROMPT_REQUEST, CHAT, or DOCUMENT\")\n .option(\"--json\", \"Output as JSON\")\n .action(validateCommand);\n}\n","import { Command } from \"commander\";\nimport {\n listCustomDataConfigs,\n getCustomDataConfig,\n createCustomDataConfig,\n updateCustomDataConfig,\n deleteCustomDataConfig,\n type CustomDataConfig,\n type CustomDataType,\n} from \"../lib/api.js\";\n\nconst DATA_TYPES: CustomDataType[] = [\"STRING\", \"NUMBER\", \"BOOLEAN\"];\n\nfunction formatTable(configs: CustomDataConfig[]): void {\n if (configs.length === 0) {\n console.log(\"No custom data configurations found.\");\n return;\n }\n\n // Calculate column widths\n const headers = [\"ID\", \"NAME\", \"TYPE\", \"AGENT ID\", \"DESCRIPTION\"];\n const rows = configs.map((config) => [\n config.id.slice(0, 12) + \"...\",\n config.name.slice(0, 25),\n config.type,\n config.agentId ? config.agentId.slice(0, 12) + \"...\" : \"(account-level)\",\n (config.description || \"-\").slice(0, 30),\n ]);\n\n const widths = headers.map((h, i) =>\n Math.max(h.length, ...rows.map((r) => r[i].length))\n );\n\n // Print header\n console.log(headers.map((h, i) => h.padEnd(widths[i])).join(\" \"));\n console.log(widths.map((w) => \"-\".repeat(w)).join(\" \"));\n\n // Print rows\n for (const row of rows) {\n console.log(row.map((cell, i) => cell.padEnd(widths[i])).join(\" \"));\n }\n}\n\nfunction formatDetail(config: CustomDataConfig): void {\n console.log(`ID: ${config.id}`);\n console.log(`Name: ${config.name}`);\n console.log(`Type: ${config.type}`);\n console.log(`Agent ID: ${config.agentId || \"(account-level / legacy)\"}`);\n console.log(`Description: ${config.description || \"-\"}`);\n if (config.createdAt) {\n console.log(`Created: ${new Date(config.createdAt).toISOString()}`);\n }\n if (config.updatedAt) {\n console.log(`Updated: ${new Date(config.updatedAt).toISOString()}`);\n }\n}\n\nasync function listCommand(options: { agentId?: string; json?: boolean }): Promise<void> {\n try {\n const configs = await listCustomDataConfigs(options.agentId);\n\n if (options.json) {\n console.log(JSON.stringify(configs, null, 2));\n } else {\n formatTable(configs);\n }\n } catch (error) {\n console.error(\n `Error: ${error instanceof Error ? error.message : \"Unknown error\"}`\n );\n process.exit(1);\n }\n}\n\nasync function getCommand(\n id: string,\n options: { json?: boolean }\n): Promise<void> {\n try {\n const config = await getCustomDataConfig(id);\n\n if (options.json) {\n console.log(JSON.stringify(config, null, 2));\n } else {\n formatDetail(config);\n }\n } catch (error) {\n console.error(\n `Error: ${error instanceof Error ? error.message : \"Unknown error\"}`\n );\n process.exit(1);\n }\n}\n\nasync function createCommand(options: {\n agentId: string;\n name: string;\n type: string;\n description?: string;\n json?: boolean;\n}): Promise<void> {\n try {\n if (!options.agentId) {\n console.error(\"Error: --agent-id is required\");\n console.error(\"Custom data configurations must be associated with an agent.\");\n process.exit(1);\n }\n\n if (!options.name) {\n console.error(\"Error: --name is required\");\n process.exit(1);\n }\n\n if (!options.type) {\n console.error(\"Error: --type is required\");\n console.error(`Valid values: ${DATA_TYPES.join(\", \")}`);\n process.exit(1);\n }\n\n const upperType = options.type.toUpperCase() as CustomDataType;\n if (!DATA_TYPES.includes(upperType)) {\n console.error(`Error: Invalid type \"${options.type}\"`);\n console.error(`Valid values: ${DATA_TYPES.join(\", \")}`);\n process.exit(1);\n }\n\n const config = await createCustomDataConfig({\n agentId: options.agentId,\n name: options.name,\n type: upperType,\n description: options.description ?? null,\n });\n\n if (options.json) {\n console.log(JSON.stringify(config, null, 2));\n } else {\n console.log(\"Custom data configuration created successfully!\");\n console.log(\"\");\n formatDetail(config);\n }\n } catch (error) {\n console.error(\n `Error: ${error instanceof Error ? error.message : \"Unknown error\"}`\n );\n process.exit(1);\n }\n}\n\nasync function updateCommand(\n id: string,\n options: {\n name?: string;\n type?: string;\n description?: string;\n json?: boolean;\n }\n): Promise<void> {\n try {\n const payload: {\n name?: string;\n type?: CustomDataType;\n description?: string | null;\n } = {};\n\n if (options.name !== undefined) payload.name = options.name;\n if (options.description !== undefined)\n payload.description = options.description || null;\n\n if (options.type !== undefined) {\n const upperType = options.type.toUpperCase() as CustomDataType;\n if (!DATA_TYPES.includes(upperType)) {\n console.error(`Error: Invalid type \"${options.type}\"`);\n console.error(`Valid values: ${DATA_TYPES.join(\", \")}`);\n process.exit(1);\n }\n payload.type = upperType;\n }\n\n if (Object.keys(payload).length === 0) {\n console.error(\"Error: At least one field to update is required\");\n process.exit(1);\n }\n\n const config = await updateCustomDataConfig(id, payload);\n\n if (options.json) {\n console.log(JSON.stringify(config, null, 2));\n } else {\n console.log(\"Custom data configuration updated successfully!\");\n console.log(\"\");\n formatDetail(config);\n }\n } catch (error) {\n console.error(\n `Error: ${error instanceof Error ? error.message : \"Unknown error\"}`\n );\n process.exit(1);\n }\n}\n\nasync function deleteCommand(\n id: string,\n options: { force?: boolean }\n): Promise<void> {\n try {\n if (!options.force) {\n console.log(\n \"Are you sure you want to delete this custom data configuration?\"\n );\n console.log(\"Use --force to confirm deletion.\");\n process.exit(1);\n }\n\n await deleteCustomDataConfig(id);\n console.log(\"Custom data configuration deleted successfully.\");\n } catch (error) {\n console.error(\n `Error: ${error instanceof Error ? error.message : \"Unknown error\"}`\n );\n process.exit(1);\n }\n}\n\nexport function registerCustomDataCommand(program: Command): void {\n const customData = program\n .command(\"custom-data\")\n .description(\"Manage custom data configurations for KPI formulas\");\n\n customData\n .command(\"list\")\n .description(\"List custom data configurations\")\n .option(\"--agent-id <agentId>\", \"Filter by agent ID (omit to list all account configs)\")\n .option(\"--json\", \"Output as JSON\")\n .action(listCommand);\n\n customData\n .command(\"get <id>\")\n .description(\"Get custom data configuration details\")\n .option(\"--json\", \"Output as JSON\")\n .action(getCommand);\n\n customData\n .command(\"create\")\n .description(\"Create a new custom data configuration for an agent\")\n .requiredOption(\"--agent-id <agentId>\", \"Agent ID (required)\")\n .requiredOption(\"--name <name>\", \"Configuration name (used in KPI formulas)\")\n .requiredOption(\n \"--type <type>\",\n \"Data type: STRING, NUMBER, or BOOLEAN\"\n )\n .option(\"--description <description>\", \"Configuration description\")\n .option(\"--json\", \"Output as JSON\")\n .action(createCommand);\n\n customData\n .command(\"update <id>\")\n .description(\"Update a custom data configuration\")\n .option(\"--name <name>\", \"Configuration name\")\n .option(\"--type <type>\", \"Data type: STRING, NUMBER, or BOOLEAN\")\n .option(\"--description <description>\", \"Configuration description\")\n .option(\"--json\", \"Output as JSON\")\n .action(updateCommand);\n\n customData\n .command(\"delete <id>\")\n .description(\"Delete a custom data configuration\")\n .option(\"--force\", \"Skip confirmation\")\n .action(deleteCommand);\n}\n","import { Command } from \"commander\";\nimport {\n listActivity,\n getActivity,\n getActivityKpis,\n listSessions,\n type ActivityPrompt,\n type ActivityListResponse,\n type ActivityKpisResponse,\n type CoreKpiValue,\n type SessionsListResponse,\n} from \"../lib/api.js\";\n\nfunction formatActivityTable(data: ActivityListResponse): void {\n if (data.prompts.length === 0) {\n console.log(\"No activity found.\");\n return;\n }\n\n // Calculate column widths\n const headers = [\"ID\", \"AGENT\", \"APP\", \"MODEL\", \"TOKENS\", \"TIME(ms)\", \"RISK\", \"STATUS\"];\n const rows = data.prompts.map((prompt) => [\n prompt.id.slice(0, 12) + \"...\",\n prompt.agentName || (prompt.agentId ? prompt.agentId.slice(0, 12) + \"...\" : \"-\"),\n prompt.app.slice(0, 12),\n prompt.modelId?.slice(0, 15) || \"-\",\n String(prompt.tokens),\n String(prompt.requestTime),\n prompt.isHighRisk ? \"Yes\" : \"No\",\n prompt.decorationStatus.slice(0, 10),\n ]);\n\n const widths = headers.map((h, i) =>\n Math.max(h.length, ...rows.map((r) => r[i].length))\n );\n\n // Print header\n console.log(headers.map((h, i) => h.padEnd(widths[i])).join(\" \"));\n console.log(widths.map((w) => \"-\".repeat(w)).join(\" \"));\n\n // Print rows\n for (const row of rows) {\n console.log(row.map((cell, i) => cell.padEnd(widths[i])).join(\" \"));\n }\n\n // Print pagination info\n console.log(\"\");\n console.log(`Showing ${data.prompts.length} of ${data.total} results (offset: ${data.offset})`);\n if (data.hasMore) {\n console.log(`Use --offset ${data.offset + data.limit} to see more results`);\n }\n}\n\nfunction formatActivityDetail(prompt: ActivityPrompt): void {\n console.log(`ID: ${prompt.id}`);\n console.log(`Created: ${prompt.createdAt}`);\n console.log(`Agent: ${prompt.agentName || \"-\"} (${prompt.agentId || \"-\"})`);\n console.log(`Workflow: ${prompt.workflowName || \"-\"} (${prompt.workflowId || \"-\"})`);\n if (prompt.taskExecutionId) {\n console.log(`Task Exec ID: ${prompt.taskExecutionId}`);\n }\n console.log(`App: ${prompt.app}`);\n console.log(`Model: ${prompt.modelId || \"-\"} (${prompt.modelType || \"-\"})`);\n console.log(`Tokens: ${prompt.tokens}`);\n console.log(`Request Time: ${prompt.requestTime}ms`);\n console.log(`High Risk: ${prompt.isHighRisk ? \"Yes\" : \"No\"}`);\n console.log(`Blocked: ${prompt.blocked ? \"Yes\" : \"No\"}`);\n console.log(`Status: ${prompt.decorationStatus}`);\n\n if (prompt.sensitivity && prompt.sensitivity.length > 0) {\n console.log(`Sensitivity: ${prompt.sensitivity.join(\", \")}`);\n }\n\n if (prompt.analytics) {\n console.log(\"\");\n console.log(\"Analytics:\");\n console.log(` Task: ${prompt.analytics.task || \"-\"}`);\n console.log(` Subtask: ${prompt.analytics.subtask || \"-\"}`);\n console.log(` Time Saved: ${prompt.analytics.timesaved_minutes ?? \"-\"} minutes`);\n console.log(` Risk Score: ${prompt.analytics.riskassessment_dangerousity ?? \"-\"}`);\n }\n\n if (prompt.kpiData && Object.keys(prompt.kpiData).length > 0) {\n console.log(\"\");\n console.log(\"KPIs:\");\n for (const [key, value] of Object.entries(prompt.kpiData)) {\n console.log(` ${key}: ${value}`);\n }\n }\n\n if (prompt.prompt !== undefined) {\n console.log(\"\");\n console.log(\"Prompt:\");\n console.log(\"---\");\n console.log(prompt.prompt.slice(0, 1000) + (prompt.prompt.length > 1000 ? \"...\" : \"\"));\n console.log(\"---\");\n }\n\n if (prompt.response !== undefined) {\n console.log(\"\");\n console.log(\"Response:\");\n console.log(\"---\");\n console.log(prompt.response.slice(0, 1000) + (prompt.response.length > 1000 ? \"...\" : \"\"));\n console.log(\"---\");\n }\n}\n\nfunction formatCoreKpi(kpi: CoreKpiValue): string {\n const prefix = kpi.unitPrefix || \"\";\n const suffix = kpi.unitSuffix || \"\";\n return `${prefix}${kpi.value}${suffix}`;\n}\n\nfunction formatKpisResponse(data: ActivityKpisResponse): void {\n // Core KPIs\n console.log(\"Core KPIs:\");\n for (const kpi of data.coreKpis) {\n console.log(` ${kpi.name.padEnd(25)} ${formatCoreKpi(kpi)}`);\n }\n\n // Custom KPIs\n if (data.kpis.length > 0) {\n console.log(\"\");\n console.log(\"Custom KPIs:\");\n const headers = [\"NAME\", \"VALUE\", \"UNIT\", \"AGGREGATION\", \"DATA POINTS\"];\n const rows = data.kpis.map((kpi) => [\n kpi.name.slice(0, 25),\n kpi.value !== null ? String(kpi.value) : \"-\",\n kpi.unit || \"-\",\n kpi.aggregationMethod,\n String(kpi.dataPointCount),\n ]);\n\n const widths = headers.map((h, i) =>\n Math.max(h.length, ...rows.map((r) => r[i].length))\n );\n\n console.log(\" \" + headers.map((h, i) => h.padEnd(widths[i])).join(\" \"));\n console.log(\" \" + widths.map((w) => \"-\".repeat(w)).join(\" \"));\n\n for (const row of rows) {\n console.log(\" \" + row.map((cell, i) => cell.padEnd(widths[i])).join(\" \"));\n }\n }\n\n // Period data\n if (data.periodData && data.periodData.length > 0) {\n console.log(\"\");\n console.log(\"Period Breakdown:\");\n for (const period of data.periodData) {\n console.log(` ${period.periodStart} - ${period.periodEnd}`);\n for (const kpi of period.coreKpis) {\n console.log(` ${kpi.name}: ${formatCoreKpi(kpi)}`);\n }\n }\n }\n\n // Atoms summary\n if (data.atoms && data.atoms.length > 0) {\n console.log(\"\");\n console.log(`Per-Prompt KPI Atoms: ${data.atoms.length} records`);\n console.log(\" (Use --json for full atom data)\");\n }\n}\n\nasync function listCommand(options: {\n agentId?: string;\n workflowId?: string;\n since?: string;\n until?: string;\n limit?: string;\n offset?: string;\n includeContent?: boolean;\n includeAnalytics?: boolean;\n json?: boolean;\n}): Promise<void> {\n try {\n const data = await listActivity({\n agentId: options.agentId,\n workflowId: options.workflowId,\n since: options.since,\n until: options.until,\n limit: options.limit ? parseInt(options.limit, 10) : undefined,\n offset: options.offset ? parseInt(options.offset, 10) : undefined,\n includeContent: options.includeContent,\n includeAnalytics: options.includeAnalytics,\n });\n\n if (options.json) {\n console.log(JSON.stringify(data, null, 2));\n } else {\n formatActivityTable(data);\n }\n } catch (error) {\n console.error(\n `Error: ${error instanceof Error ? error.message : \"Unknown error\"}`\n );\n process.exit(1);\n }\n}\n\nasync function getCommand(\n id: string,\n options: { includeContent?: boolean; json?: boolean }\n): Promise<void> {\n try {\n const prompt = await getActivity(id, options.includeContent);\n\n if (options.json) {\n console.log(JSON.stringify(prompt, null, 2));\n } else {\n formatActivityDetail(prompt);\n }\n } catch (error) {\n console.error(\n `Error: ${error instanceof Error ? error.message : \"Unknown error\"}`\n );\n process.exit(1);\n }\n}\n\nasync function kpisCommand(options: {\n agentId?: string;\n workflowId?: string;\n since?: string;\n until?: string;\n period?: string;\n includeAtoms?: boolean;\n json?: boolean;\n}): Promise<void> {\n try {\n if (!options.agentId && !options.workflowId) {\n console.error(\"Error: Either --agent-id or --workflow-id is required\");\n process.exit(1);\n }\n\n const data = await getActivityKpis({\n agentId: options.agentId,\n workflowId: options.workflowId,\n since: options.since,\n until: options.until,\n period: options.period as \"hourly\" | \"daily\" | \"weekly\" | undefined,\n includeAtoms: options.includeAtoms,\n });\n\n if (options.json) {\n console.log(JSON.stringify(data, null, 2));\n } else {\n formatKpisResponse(data);\n }\n } catch (error) {\n console.error(\n `Error: ${error instanceof Error ? error.message : \"Unknown error\"}`\n );\n process.exit(1);\n }\n}\n\nfunction formatSessionsTable(data: SessionsListResponse): void {\n // Summary\n console.log(\"Session Decoration Status\");\n console.log(\"\");\n console.log(\"Summary:\");\n console.log(` Total Sessions: ${data.summary.sessionCount}`);\n\n const statuses = [\"DECORATED\", \"NEW\", \"DECORATION_FAILED\", \"DECORATION_OUTDATED\", \"SKIPPED\"];\n for (const status of statuses) {\n const count = data.summary.byStatus[status] || 0;\n const pct = data.summary.sessionCount > 0 ? ((count / data.summary.sessionCount) * 100).toFixed(1) : \"0.0\";\n const label = status.charAt(0) + status.slice(1).toLowerCase().replace(/_/g, \" \");\n console.log(` ${label.padEnd(17)} ${String(count).padStart(4)} (${pct}%)`);\n }\n\n if (data.sessions.length === 0) {\n console.log(\"\");\n console.log(\"No sessions found.\");\n return;\n }\n\n console.log(\"\");\n\n // Table\n const headers = [\"ID\", \"STATUS\", \"DATE\", \"CANDIDATE\", \"ERRORS\", \"KPI DATA\", \"VERSION\"];\n const rows = data.sessions.map((s) => [\n s.id.slice(0, 15) + \"...\",\n s.decorationStatus,\n s.decorationDate || \"-\",\n s.decorationCandidate ? \"Yes\" : \"No\",\n String(s.decorationErrorStreak),\n s.hasKpiData ? \"Yes\" : \"No\",\n s.decoratorVersion || \"-\",\n ]);\n\n const widths = headers.map((h, i) =>\n Math.max(h.length, ...rows.map((r) => r[i].length))\n );\n\n console.log(headers.map((h, i) => h.padEnd(widths[i])).join(\" \"));\n console.log(widths.map((w) => \"-\".repeat(w)).join(\" \"));\n\n for (const row of rows) {\n console.log(row.map((cell, i) => cell.padEnd(widths[i])).join(\" \"));\n }\n\n console.log(\"\");\n console.log(`Showing ${data.sessions.length} of ${data.total} results (offset: ${data.offset})`);\n if (data.hasMore) {\n console.log(`Use --offset ${data.offset + data.limit} to see more results`);\n }\n}\n\nasync function sessionsCommand(options: {\n agentId: string;\n since?: string;\n until?: string;\n limit?: string;\n offset?: string;\n json?: boolean;\n}): Promise<void> {\n try {\n const data = await listSessions({\n agentId: options.agentId,\n since: options.since,\n until: options.until,\n limit: options.limit ? parseInt(options.limit, 10) : undefined,\n offset: options.offset ? parseInt(options.offset, 10) : undefined,\n });\n\n if (options.json) {\n console.log(JSON.stringify(data, null, 2));\n } else {\n formatSessionsTable(data);\n }\n } catch (error) {\n console.error(\n `Error: ${error instanceof Error ? error.message : \"Unknown error\"}`\n );\n process.exit(1);\n }\n}\n\nexport function registerActivityCommand(program: Command): void {\n const activity = program\n .command(\"activity\")\n .description(\"Inspect AI activity and prompts\");\n\n activity\n .command(\"list\")\n .description(\"List prompt requests with filters\")\n .option(\"--agent-id <id>\", \"Filter by agent ID\")\n .option(\"--workflow-id <id>\", \"Filter by workflow ID\")\n .option(\"--since <date>\", \"Start date (ISO format)\")\n .option(\"--until <date>\", \"End date (ISO format)\")\n .option(\"--limit <n>\", \"Results per page\", \"20\")\n .option(\"--offset <n>\", \"Skip first N results\", \"0\")\n .option(\"--include-content\", \"Include prompt/response content\")\n .option(\"--include-analytics\", \"Include advanced analytics\")\n .option(\"--json\", \"Output as JSON\")\n .action(listCommand);\n\n activity\n .command(\"get <id>\")\n .description(\"Get prompt request details\")\n .option(\"--include-content\", \"Include prompt/response content\")\n .option(\"--json\", \"Output as JSON\")\n .action(getCommand);\n\n activity\n .command(\"kpis\")\n .description(\"Get aggregated KPI values\")\n .option(\"--agent-id <id>\", \"Agent ID\")\n .option(\"--workflow-id <id>\", \"Workflow ID\")\n .option(\"--since <date>\", \"Period start (ISO format)\")\n .option(\"--until <date>\", \"Period end (ISO format)\")\n .option(\"--period <type>\", \"Aggregation period (hourly, daily, weekly)\")\n .option(\"--include-atoms\", \"Include per-prompt KPI data\")\n .option(\"--json\", \"Output as JSON\")\n .action(kpisCommand);\n\n activity\n .command(\"sessions\")\n .description(\"Inspect chat/session decoration status for troubleshooting\")\n .requiredOption(\"--agent-id <id>\", \"Agent ID (required)\")\n .option(\"--since <date>\", \"Start date (ISO format)\")\n .option(\"--until <date>\", \"End date (ISO format)\")\n .option(\"--limit <n>\", \"Results per page\", \"20\")\n .option(\"--offset <n>\", \"Skip first N results\", \"0\")\n .option(\"--json\", \"Output as JSON\")\n .action(sessionsCommand);\n}\n","import * as fs from \"node:fs\";\nimport { Command } from \"commander\";\nimport \"../monitor/plugins/index.js\";\nimport {\n TOOL_IDS,\n getPlugin,\n isToolId,\n listPlugins,\n type HookResult,\n type ToolId,\n type ToolMonitorPlugin,\n} from \"../monitor/plugin.js\";\nimport { isInteractive, promptUser } from \"../monitor/prompt.js\";\n\n// Pre-Stage-2 `monitor.ts` exposed these symbols directly; downstream\n// tests and possibly external scripts import them from this module.\n// Re-export so the public surface is unchanged after the plugin split.\nexport {\n mergeHooksSettings,\n type HookMatcherEntry,\n type HookCommand,\n} from \"../monitor/plugins/claude-code/settings.js\";\nexport {\n buildClaudeCodePayload as buildPayload,\n type ClaudeHookEvent,\n} from \"../monitor/plugins/claude-code/hook.js\";\nexport { resolveProjectRootFromPayload } from \"../monitor/plugins/claude-code/index.js\";\nexport { type MonitorConfig } from \"../monitor/plugins/claude-code/config.js\";\n\nfunction readStdin(timeoutMs: number = 3000): Promise<string> {\n return new Promise((resolve) => {\n if (process.stdin.isTTY) {\n resolve(\"\");\n return;\n }\n\n let data = \"\";\n const timer = setTimeout(() => {\n process.stdin.removeAllListeners();\n process.stdin.destroy();\n resolve(data);\n }, timeoutMs);\n\n process.stdin.setEncoding(\"utf-8\");\n process.stdin.on(\"data\", (chunk: string) => {\n data += chunk;\n });\n process.stdin.on(\"end\", () => {\n clearTimeout(timer);\n resolve(data);\n });\n process.stdin.on(\"error\", () => {\n clearTimeout(timer);\n resolve(data);\n });\n });\n}\n\n// D-002 surface: in non-interactive contexts (CI, scripts) `--tool` is\n// optional and defaults to claude-code with a deprecation notice — this\n// keeps pre-Stage-2 automation working while signalling that the flag\n// is the way forward. Interactive contexts always prompt when the flag\n// is absent.\nconst DEFAULT_NON_INTERACTIVE_TOOL: ToolId = \"claude-code\";\n\nasync function resolveToolFromOptions(\n flag: string | undefined,\n context: \"init\" | \"status\" | \"disable\",\n): Promise<ToolId> {\n if (typeof flag === \"string\" && flag.length > 0) {\n if (!isToolId(flag)) {\n console.error(\n `Unknown --tool \"${flag}\". Supported: ${TOOL_IDS.join(\", \")}`,\n );\n process.exit(1);\n }\n return flag;\n }\n\n if (!isInteractive()) {\n console.error(\n `[olakai] --tool not provided; defaulting to \"${DEFAULT_NON_INTERACTIVE_TOOL}\". This default will be removed in a future version — please pass --tool <tool> explicitly.`,\n );\n return DEFAULT_NON_INTERACTIVE_TOOL;\n }\n\n return promptForTool(context);\n}\n\nasync function promptForTool(\n context: \"init\" | \"status\" | \"disable\",\n): Promise<ToolId> {\n const plugins = listPlugins();\n const detected: ToolId[] = [];\n for (const p of plugins) {\n try {\n if (await p.detectInstalled()) detected.push(p.id);\n } catch {\n // detectInstalled is best-effort\n }\n }\n\n console.log(\"Which coding tool do you want to monitor?\");\n for (let i = 0; i < plugins.length; i++) {\n const p = plugins[i];\n const flag = detected.includes(p.id) ? \" (detected)\" : \"\";\n console.log(` ${i + 1}. ${p.displayName} [${p.id}]${flag}`);\n }\n\n const defaultIdx = plugins.findIndex((p) => detected.includes(p.id));\n const defaultLabel = defaultIdx >= 0 ? `${defaultIdx + 1}` : \"1\";\n const answer = await promptUser(\n `Select a tool to ${context} (1-${plugins.length}) [${defaultLabel}]: `,\n );\n\n const choice = answer.trim() === \"\" ? defaultLabel : answer.trim();\n const idx = parseInt(choice, 10) - 1;\n if (isNaN(idx) || idx < 0 || idx >= plugins.length) {\n console.error(\"Invalid selection.\");\n process.exit(1);\n }\n return plugins[idx].id;\n}\n\ninterface ToolFlag {\n tool?: string;\n}\n\nasync function initCommand(options: ToolFlag): Promise<void> {\n const toolId = await resolveToolFromOptions(options.tool, \"init\");\n const plugin = getPlugin(toolId);\n await runPluginAction(plugin, () =>\n plugin.install({ projectRoot: process.cwd(), interactive: true }),\n );\n}\n\nasync function statusCommand(\n options: ToolFlag & { json?: boolean },\n): Promise<void> {\n const toolId = await resolveToolFromOptions(options.tool, \"status\");\n const plugin = getPlugin(toolId);\n\n if (options.json) {\n const report = await plugin.status({ projectRoot: process.cwd() });\n console.log(JSON.stringify(report, null, 2));\n return;\n }\n\n // For non-JSON Claude Code we keep the rich human formatter from\n // pre-Stage-2 (recent activity table). Other plugins ship their own\n // pretty printer in S3/S4; until then, surface their `notes` array\n // as one line per note so a user running `olakai monitor status\n // --tool codex` today sees the \"coming soon\" message rather than\n // raw JSON.\n if (plugin.id === \"claude-code\") {\n const { printClaudeCodeStatus } = await import(\n \"../monitor/plugins/claude-code/status.js\"\n );\n await printClaudeCodeStatus({ projectRoot: process.cwd() });\n return;\n }\n\n const report = await plugin.status({ projectRoot: process.cwd() });\n if (report.notes && report.notes.length > 0) {\n for (const note of report.notes) {\n console.log(note);\n }\n return;\n }\n // No notes to surface — fall through to JSON so the user sees\n // something rather than nothing.\n console.log(JSON.stringify(report, null, 2));\n}\n\nasync function disableCommand(\n options: ToolFlag & { keepConfig?: boolean },\n): Promise<void> {\n const toolId = await resolveToolFromOptions(options.tool, \"disable\");\n const plugin = getPlugin(toolId);\n await runPluginAction(plugin, () =>\n plugin.uninstall({\n projectRoot: process.cwd(),\n keepConfig: options.keepConfig,\n }),\n );\n}\n\nasync function runPluginAction<T>(\n plugin: ToolMonitorPlugin,\n fn: () => Promise<T>,\n): Promise<T | void> {\n try {\n return await fn();\n } catch (err) {\n const e = err as Error;\n if (e.name === \"NotImplementedError\") {\n console.error(`${plugin.displayName}: ${e.message}`);\n process.exit(1);\n }\n throw err;\n }\n}\n\n/**\n * Fire-and-forget hook handler invoked by the tool's hook system. MUST\n * NOT produce stderr or exit non-zero — hook failures must never break\n * the host tool. `--tool` defaults to claude-code only when the flag\n * is *absent entirely* (back-compat with pre-Stage-2 hook commands\n * installed in existing workspaces' `.claude/settings.json`). When the\n * flag is present-but-invalid (typo like `--tool clade-code`), we\n * silent-exit rather than route to claude-code, to avoid silently\n * misrouting hooks for the wrong tool.\n */\nasync function hookCommand(\n event: string,\n options: ToolFlag,\n command: Command,\n): Promise<void> {\n try {\n // Distinguish \"flag absent\" from \"flag present but invalid\" via\n // Commander's `getOptionValueSource`. Source `undefined` means the\n // user didn't pass `--tool`; any other source means they did.\n const flagPresent =\n command.getOptionValueSource(\"tool\") !== undefined;\n\n let toolId: ToolId;\n if (flagPresent) {\n if (!options.tool || !isToolId(options.tool)) {\n // Invalid value supplied — silent-exit so hook failures don't\n // break the host tool. Debug-log so it's not totally invisible.\n debugInvalidToolFlag(options.tool, event);\n return;\n }\n toolId = options.tool;\n } else {\n toolId = \"claude-code\";\n }\n const plugin = getPlugin(toolId);\n\n const stdinData = await readStdin(3000);\n let payloadJson: unknown = {};\n if (stdinData) {\n try {\n payloadJson = JSON.parse(stdinData);\n } catch {\n // Plugins decide what to do with a bare event (the Claude Code\n // plugin silent-exits when transcript_path is missing).\n }\n }\n\n const result = await plugin.handleHook(event, payloadJson);\n if (!result) return;\n\n // The plugin already resolved workspace + transport inside\n // handleHook (where dedup/state writes happen). Use those values\n // directly — re-resolving here would race against `monitor disable`\n // and could disagree on CWD between the plugin and dispatcher.\n await postMonitoringPayload(result);\n } catch {\n // Silently swallow ALL errors. Hook failures must not break the\n // host tool.\n }\n}\n\nfunction debugInvalidToolFlag(\n value: string | undefined,\n event: string,\n): void {\n if (process.env.OLAKAI_MONITOR_DEBUG !== \"1\") return;\n try {\n // Mirror the claude-code plugin's debug-log location so users have\n // a single place to look for hook-path diagnostics.\n const logPath = `/tmp/olakai-monitor-debug-${process.pid}.log`;\n const line = `[${new Date().toISOString()}] hook-invalid-tool-flag: ${JSON.stringify(\n { event, tool: value ?? null },\n )}\\n`;\n fs.appendFileSync(logPath, line, \"utf-8\");\n } catch {\n // Ignore debug-log failures — never break the hook path.\n }\n}\n\nasync function postMonitoringPayload(result: HookResult): Promise<void> {\n const controller = new AbortController();\n const timeoutId = setTimeout(() => controller.abort(), 5000);\n const debug = process.env.OLAKAI_MONITOR_DEBUG === \"1\";\n const logPath = `/tmp/olakai-monitor-debug-${process.pid}.log`;\n const log = (event: string, data: unknown) => {\n if (!debug) return;\n try {\n fs.appendFileSync(\n logPath,\n `[${new Date().toISOString()}] dispatcher/${event}: ${JSON.stringify(data)}\\n`,\n \"utf-8\",\n );\n } catch {\n // Never let a debug-log failure break the hook path.\n }\n };\n try {\n log(\"posting\", {\n endpoint: result.transport.endpoint,\n apiKeyPresent: Boolean(result.transport.apiKey),\n apiKeyPrefix: result.transport.apiKey\n ? result.transport.apiKey.slice(0, 8) + \"...\"\n : null,\n bodyBytes: JSON.stringify([result.payload]).length,\n });\n const response = await fetch(result.transport.endpoint, {\n method: \"POST\",\n headers: {\n \"x-api-key\": result.transport.apiKey,\n \"Content-Type\": \"application/json\",\n },\n body: JSON.stringify([result.payload]),\n signal: controller.signal,\n });\n let bodyPreview: string | null = null;\n try {\n bodyPreview = (await response.text()).slice(0, 500);\n } catch {\n // Body read failures are not actionable here.\n }\n log(\"posted\", { status: response.status, bodyPreview });\n } catch (err) {\n log(\"post-error\", {\n name: err instanceof Error ? err.name : \"unknown\",\n message: err instanceof Error ? err.message : String(err),\n });\n throw err;\n } finally {\n clearTimeout(timeoutId);\n }\n}\n\nexport function registerMonitorCommand(program: Command): void {\n const monitor = program\n .command(\"monitor\")\n .description(\n \"Monitor local coding agents (Claude Code, Codex, Cursor) with Olakai\",\n );\n\n monitor\n .command(\"init\")\n .description(\"Set up Olakai monitoring for this workspace\")\n .option(\n \"--tool <tool>\",\n `Tool to configure (${TOOL_IDS.join(\"|\")}). Prompts when omitted in interactive mode.`,\n )\n .action(initCommand);\n\n monitor\n .command(\"hook <event>\")\n .description(\"Hook handler invoked by the tool's hook system (internal)\")\n .option(\n \"--tool <tool>\",\n `Tool whose hook is firing (defaults to claude-code for back-compat)`,\n )\n .action(hookCommand);\n\n monitor\n .command(\"status\")\n .description(\"Show monitoring status for this workspace\")\n .option(\n \"--tool <tool>\",\n `Tool to inspect (${TOOL_IDS.join(\"|\")}). Prompts when omitted in interactive mode.`,\n )\n .option(\"--json\", \"Output as JSON\")\n .action(statusCommand);\n\n monitor\n .command(\"disable\")\n .description(\"Remove Olakai monitoring from this workspace\")\n .option(\n \"--tool <tool>\",\n `Tool to disable (${TOOL_IDS.join(\"|\")}). Prompts when omitted in interactive mode.`,\n )\n .option(\n \"--keep-config\",\n \"Keep the monitor config file (only remove hooks)\",\n )\n .action(disableCommand);\n\n // Allow plugins to register tool-specific subcommands (e.g. future\n // `olakai monitor claude-code transcript <path>`). Optional — most\n // plugins won't need this hook.\n for (const plugin of listPlugins()) {\n plugin.registerCommands?.(monitor);\n }\n}\n","import * as fs from \"node:fs\";\nimport {\n registerPlugin,\n type HookResult,\n type InstallOpts,\n type InstallResult,\n type StatusReport,\n type ToolMonitorPlugin,\n type UninstallOpts,\n} from \"../../plugin.js\";\nimport {\n loadSessionState,\n saveSessionState,\n setDebugLogger,\n shouldReportTurn,\n} from \"../../../commands/monitor-state.js\";\nimport { installClaudeCode, uninstallClaudeCode } from \"./install.js\";\nimport { getClaudeCodeStatus } from \"./status.js\";\nimport {\n buildClaudeCodePayload,\n extractFromTranscript,\n type ClaudeHookEvent,\n} from \"./hook.js\";\nimport { loadClaudeCodeConfig } from \"./config.js\";\nimport {\n findConfiguredWorkspace,\n getLegacyClaudeMonitorConfigPath,\n getMonitorConfigPath,\n} from \"../../paths.js\";\n\nconst TOOL_ID = \"claude-code\" as const;\nconst SUPPORTED_HOOK_EVENTS = new Set([\"stop\", \"subagent-stop\"]);\n\n/**\n * Debug logger. Mirrors the original `monitor.ts` behavior: writes\n * only when OLAKAI_MONITOR_DEBUG=1, and never throws.\n */\nfunction debugLog(label: string, data: unknown): void {\n if (process.env.OLAKAI_MONITOR_DEBUG !== \"1\") return;\n try {\n const logPath = `/tmp/olakai-monitor-debug-${process.pid}.log`;\n const line = `[${new Date().toISOString()}] ${label}: ${\n typeof data === \"string\" ? data : JSON.stringify(data, null, 2)\n }\\n`;\n fs.appendFileSync(logPath, line, \"utf-8\");\n } catch {\n // Ignore debug-log failures\n }\n}\n\n/**\n * Resolve the configured project root from a Claude Code hook payload,\n * falling back to `process.cwd()` when the payload doesn't carry a\n * usable `cwd` field. Returns null when no configured workspace is in\n * the ancestry, letting the hook dispatcher silent-exit.\n *\n * Background (INV-002): Claude Code sometimes invokes Stop /\n * SubagentStop hooks from a CWD that isn't under the workspace (e.g.\n * `/tmp`). We seed the ancestor walk with `payload.cwd` when present,\n * and look for an actual monitor config file (new or legacy path) so\n * stray `.claude/` dirs in subrepos don't trap the search.\n */\nexport function resolveProjectRootFromPayload(\n eventData: ClaudeHookEvent,\n fallbackCwd: string,\n): string | null {\n const payloadCwd =\n typeof eventData.cwd === \"string\" && eventData.cwd.trim()\n ? eventData.cwd\n : fallbackCwd;\n return findConfiguredWorkspace(payloadCwd, [TOOL_ID]);\n}\n\nconst claudeCodePlugin: ToolMonitorPlugin = {\n id: TOOL_ID,\n displayName: \"Claude Code\",\n\n install(opts: InstallOpts): Promise<InstallResult> {\n return installClaudeCode(opts);\n },\n\n uninstall(opts: UninstallOpts): Promise<void> {\n return uninstallClaudeCode(opts);\n },\n\n status(opts): Promise<StatusReport> {\n return getClaudeCodeStatus(opts);\n },\n\n async handleHook(\n eventName,\n payloadJson,\n ): Promise<HookResult | null> {\n setDebugLogger(debugLog);\n\n const event = eventName.trim();\n if (!SUPPORTED_HOOK_EVENTS.has(event)) {\n debugLog(\"hook-unknown-event\", event);\n return null;\n }\n\n const eventData = (payloadJson ?? {}) as ClaudeHookEvent;\n debugLog(\"event-parsed\", { event, eventData });\n\n const projectRoot = resolveProjectRootFromPayload(\n eventData,\n process.cwd(),\n );\n if (!projectRoot) {\n debugLog(\"config-not-found\", {\n startDir:\n typeof eventData.cwd === \"string\" && eventData.cwd.trim()\n ? eventData.cwd\n : process.cwd(),\n });\n return null;\n }\n\n const config = loadClaudeCodeConfig(projectRoot, () => {\n // Silent in the hook path — stderr would interleave with Claude\n // Code's own output. Migrations still happen; just no notice.\n });\n if (!config) {\n debugLog(\"config-load-failed\", { projectRoot });\n return null;\n }\n\n const payload = buildClaudeCodePayload(event, eventData, config);\n if (!payload) return null;\n\n debugLog(\"payload-built\", payload);\n\n // Per-session turn dedup (INV-004). Re-extract so we key on the\n // exact timestamp that drove the payload. Reading the transcript\n // again is cheap (<10ms in practice) and avoids threading parser\n // state through the plugin contract.\n const sessionId =\n (typeof eventData.session_id === \"string\" && eventData.session_id) ||\n undefined;\n const extracted = extractFromTranscript(\n eventData.transcript_path,\n debugLog,\n );\n const userTurnTimestamp = extracted.userTurnTimestamp;\n\n // Empty-parse silent-exit guard.\n //\n // If the transcript parse yielded no prompt, no response, AND no\n // turns, we have nothing to monitor — emitting a noop event would\n // just add noise to the user's activity feed and inflate counts.\n // This protects against unexpected/unparseable payloads being\n // silently emitted as empty events (e.g., a Cursor stop event\n // leaking onto the claude-code path with a transcript file the\n // parser doesn't recognize).\n //\n // All three conditions are required because token counts of 0 are\n // legitimate on fully-cached turns — only the combination of empty\n // prompt + empty response + zero turns reliably means \"the parser\n // saw nothing actionable\".\n if (\n extracted.prompt.trim() === \"\" &&\n extracted.response.trim() === \"\" &&\n extracted.numTurns === 0\n ) {\n debugLog(\"empty-parse-skip\", {\n event,\n sessionId,\n transcriptPath: eventData.transcript_path,\n });\n return null;\n }\n\n if (sessionId) {\n const existingState = loadSessionState(sessionId);\n if (!shouldReportTurn(existingState, userTurnTimestamp)) {\n debugLog(\"turn-dedup-skip\", { sessionId, userTurnTimestamp });\n return null;\n }\n }\n\n // Save dedup state before the dispatcher POSTs: a POST failure must\n // not retry the same turn (INV-004). Saving here — not after the\n // network call — guarantees retry storms during outages cannot\n // re-fire the same payload.\n if (sessionId && userTurnTimestamp) {\n saveSessionState(sessionId, {\n lastUserTimestamp: userTurnTimestamp,\n lastReportedAt: new Date().toISOString(),\n numTurnsAtLastReport: extracted.numTurns,\n });\n debugLog(\"state-saved\", {\n sessionId,\n userTurnTimestamp,\n numTurns: extracted.numTurns,\n });\n }\n\n return {\n payload,\n transport: {\n endpoint: config.monitoringEndpoint,\n apiKey: config.apiKey,\n projectRoot,\n },\n };\n },\n\n async detectInstalled(opts): Promise<boolean> {\n const projectRoot = opts?.projectRoot ?? process.cwd();\n try {\n if (fs.existsSync(getMonitorConfigPath(projectRoot, TOOL_ID))) {\n return true;\n }\n if (fs.existsSync(getLegacyClaudeMonitorConfigPath(projectRoot))) {\n return true;\n }\n return false;\n } catch {\n return false;\n }\n },\n};\n\nregisterPlugin(claudeCodePlugin);\n\nexport default claudeCodePlugin;\nexport {\n buildClaudeCodePayload,\n type ClaudeHookEvent,\n} from \"./hook.js\";\nexport { mergeHooksSettings, type HookMatcherEntry } from \"./settings.js\";\nexport { type MonitorConfig } from \"./config.js\";\n","/**\n * Plugin contract for \"Local Coding Agents\" monitoring (D-001).\n *\n * Each supported tool (Claude Code, OpenAI Codex CLI, Cursor) provides a\n * `ToolMonitorPlugin` that knows how to install hooks, parse hook\n * payloads, and report status for that tool. The CLI dispatches via the\n * registry below — `monitor.ts` is intentionally tool-agnostic so adding\n * a new tool is a matter of dropping a plugin module under\n * `plugins/<tool>/index.ts` and registering it.\n *\n * Stage 2 ships the Claude Code plugin and stubs for codex/cursor.\n * Stages 3 and 4 fill in the stubs.\n */\nimport type { Command } from \"commander\";\n\nexport type ToolId = \"claude-code\" | \"codex\" | \"cursor\";\n\nexport const TOOL_IDS: readonly ToolId[] = [\n \"claude-code\",\n \"codex\",\n \"cursor\",\n] as const;\n\n/**\n * Inputs to `install()`. `projectRoot` defaults to `process.cwd()` when\n * the caller doesn't override it (e.g. tests). `interactive` toggles\n * `prompt`-driven flows; non-interactive mode (CI, scripts) must error\n * cleanly when required inputs are missing.\n */\nexport interface InstallOpts {\n projectRoot?: string;\n interactive?: boolean;\n}\n\nexport interface InstallResult {\n agentId: string;\n agentName: string;\n source: string;\n monitoringEndpoint: string;\n}\n\nexport interface UninstallOpts {\n projectRoot?: string;\n keepConfig?: boolean;\n}\n\n/**\n * Per-tool snapshot returned by `status()`. Designed so a future\n * \"show all installed tools\" view can fan out across plugins and\n * collect the same shape.\n */\nexport interface StatusReport {\n toolId: ToolId;\n configured: boolean;\n hooksConfigured: boolean;\n agentId?: string;\n agentName?: string;\n source?: string;\n apiKeyMasked?: string;\n monitoringEndpoint?: string;\n configuredAt?: string;\n /** Path to the per-tool config file, when known. */\n configPath?: string;\n /** Free-form one-line message for human display when not in JSON mode. */\n notes?: string[];\n}\n\n/**\n * Canonical monitoring payload. Mirrors the existing Claude Code POST\n * shape against `/api/monitoring/prompt`. New tools must produce the\n * same shape so the backend doesn't need per-tool branches.\n *\n * Kept loose (`Record<string, unknown>` for `customData`) because each\n * tool emits a different feature set; the backend tolerates extra keys.\n */\nexport interface MonitoringPayload {\n prompt: string;\n response: string;\n chatId: string;\n source: string;\n modelName?: string;\n tokens: number;\n customData: Record<string, unknown>;\n}\n\n/**\n * Resolved transport metadata returned alongside the payload from\n * `handleHook`. The plugin already walked the filesystem and loaded\n * the per-tool config to build/dedup the payload — passing the\n * resolved values through to the dispatcher prevents a second resolve\n * (and the stale-config race that would create) and avoids any chance\n * the dispatcher's CWD-based lookup disagrees with the plugin's.\n */\nexport interface HookTransport {\n /** Outbound endpoint for the canonical monitoring POST. */\n endpoint: string;\n /** Bearer/x-api-key for the POST. Plugin owns secret resolution. */\n apiKey: string;\n /** Configured workspace root the plugin matched the event to. */\n projectRoot: string;\n}\n\n/**\n * Result of a plugin's `handleHook`. Payload is the canonical shape\n * the dispatcher will POST; transport carries the resolved endpoint\n * and credentials so the dispatcher does not re-walk the filesystem\n * or re-load the config (which would race against `monitor disable`).\n */\nexport interface HookResult {\n payload: MonitoringPayload;\n transport: HookTransport;\n}\n\nexport interface ToolMonitorPlugin {\n id: ToolId;\n displayName: string;\n install(opts: InstallOpts): Promise<InstallResult>;\n uninstall(opts: UninstallOpts): Promise<void>;\n status(opts?: { projectRoot?: string }): Promise<StatusReport>;\n /**\n * Transform an inbound hook event into a canonical MonitoringPayload\n * plus the resolved transport (endpoint + apiKey + projectRoot).\n * Returning `null` signals \"nothing to report for this event\" (e.g.\n * an unknown event name) — the dispatcher will silent-exit.\n *\n * The plugin owns workspace + config resolution because it already\n * walked the filesystem to dedup the turn; threading the resolved\n * values through to the dispatcher prevents a stale-config race\n * (e.g. `olakai monitor disable` mid-flight) and CWD disagreement.\n */\n handleHook(\n eventName: string,\n payloadJson: unknown,\n opts?: { projectRoot?: string },\n ): Promise<HookResult | null>;\n /**\n * Whether this tool is detectably installed on the host. Powers the\n * D-002 auto-detection path inside the interactive `init` prompt.\n * MUST be cheap and non-throwing — return `false` on any uncertainty.\n */\n detectInstalled(opts?: { projectRoot?: string }): Promise<boolean>;\n /**\n * Optional per-tool subcommand registration on the parent `monitor`\n * Commander group. Plugins can use this to expose tool-specific\n * helpers (e.g. `olakai monitor claude-code transcript`). The base\n * `init`/`status`/`disable`/`hook` commands are owned by `monitor.ts`.\n */\n registerCommands?: (parent: Command) => void;\n}\n\nexport class NotImplementedError extends Error {\n constructor(message: string) {\n super(message);\n this.name = \"NotImplementedError\";\n }\n}\n\nconst registry = new Map<ToolId, ToolMonitorPlugin>();\n\nexport function registerPlugin(plugin: ToolMonitorPlugin): void {\n registry.set(plugin.id, plugin);\n}\n\nexport function getPlugin(id: string): ToolMonitorPlugin {\n if (!isToolId(id)) {\n throw new Error(\n `Unknown tool: \"${id}\". Supported tools: ${TOOL_IDS.join(\", \")}`,\n );\n }\n const plugin = registry.get(id);\n if (!plugin) {\n throw new Error(\n `Tool \"${id}\" is not registered. This is a CLI bug — please report it.`,\n );\n }\n return plugin;\n}\n\nexport function tryGetPlugin(id: string): ToolMonitorPlugin | null {\n if (!isToolId(id)) return null;\n return registry.get(id) ?? null;\n}\n\nexport function listPlugins(): ToolMonitorPlugin[] {\n return Array.from(registry.values());\n}\n\nexport function isToolId(value: string): value is ToolId {\n return (TOOL_IDS as readonly string[]).includes(value);\n}\n\n/**\n * Test/integration hook — clears the registry. Production code must not\n * call this; only the test harness uses it to keep registrations\n * deterministic across files.\n */\nexport function __resetRegistryForTests(): void {\n registry.clear();\n}\n","/**\n * Per-session dedup state for the Claude Code Stop / SubagentStop hook.\n *\n * Problem (INV-004): Claude Code occasionally fires the Stop hook twice\n * for a single user turn, a few seconds apart. Each firing calls the\n * CLI, which parses the transcript and emits the LATEST user+assistant\n * pair — so two firings on one turn produce two PromptRequests with an\n * identical `prompt` and a slightly different `response`.\n *\n * Fix: keep a small sidecar file per session id under\n * `~/.olakai/monitor-state/<sessionId>.json`, keyed by the current\n * turn's user-message timestamp. If the current Stop firing sees the\n * same user-turn timestamp as the last one we reported, skip the POST.\n *\n * The module is pure w.r.t. process state — callers pass `sessionId`\n * and (optionally) a `homeDir` override for testability. All filesystem\n * errors are swallowed and surfaced via `debugLog` callbacks supplied\n * by the caller; the hook MUST NOT break Claude Code.\n */\n\nimport * as fs from \"node:fs\";\nimport * as os from \"node:os\";\nimport * as path from \"node:path\";\n\n/**\n * State persisted per session id. `numTurnsAtLastReport` is informational\n * only — dedup decisions use `lastUserTimestamp`.\n */\nexport interface SessionMonitorState {\n lastUserTimestamp: string;\n lastReportedAt: string;\n numTurnsAtLastReport: number;\n}\n\nconst STATE_DIR_SEGMENTS = [\".olakai\", \"monitor-state\"];\n\n/**\n * Resolve the directory that holds per-session state files. Exposed\n * indirectly through the `homeDir` parameter on the public API so tests\n * can point it at a tmp dir.\n */\nfunction getStateDir(homeDir: string): string {\n return path.join(homeDir, ...STATE_DIR_SEGMENTS);\n}\n\nfunction getStateFile(sessionId: string, homeDir: string): string {\n return path.join(getStateDir(homeDir), `${sessionId}.json`);\n}\n\n/**\n * Optional debug logger. Kept as a module-level mutable hook so the\n * caller (monitor.ts) can wire in its own `debugLog` without this file\n * importing it (avoiding circular deps).\n */\ntype DebugLogger = (label: string, data: unknown) => void;\nlet debugLogger: DebugLogger | null = null;\n\nexport function setDebugLogger(logger: DebugLogger | null): void {\n debugLogger = logger;\n}\n\nfunction log(label: string, data: unknown): void {\n if (debugLogger) {\n try {\n debugLogger(label, data);\n } catch {\n // Debug logging must never break the hook.\n }\n }\n}\n\n/**\n * Load persisted state for `sessionId`. Returns null when the file is\n * absent, unreadable, or contains malformed JSON. Never throws.\n */\nexport function loadSessionState(\n sessionId: string,\n homeDir: string = os.homedir(),\n): SessionMonitorState | null {\n if (!sessionId) return null;\n const filePath = getStateFile(sessionId, homeDir);\n try {\n if (!fs.existsSync(filePath)) return null;\n const raw = fs.readFileSync(filePath, \"utf-8\");\n const parsed = JSON.parse(raw) as Partial<SessionMonitorState>;\n if (\n typeof parsed?.lastUserTimestamp !== \"string\" ||\n typeof parsed?.lastReportedAt !== \"string\" ||\n typeof parsed?.numTurnsAtLastReport !== \"number\"\n ) {\n // Malformed shape — treat as missing so we don't skip a real\n // report based on garbage state.\n return null;\n }\n return {\n lastUserTimestamp: parsed.lastUserTimestamp,\n lastReportedAt: parsed.lastReportedAt,\n numTurnsAtLastReport: parsed.numTurnsAtLastReport,\n };\n } catch (err) {\n log(\"state-load-failed\", {\n sessionId,\n error: (err as Error).message,\n });\n return null;\n }\n}\n\n/**\n * Persist state for `sessionId`. Creates the state directory on first\n * write. Filesystem errors are logged via `debugLog` and swallowed.\n */\nexport function saveSessionState(\n sessionId: string,\n state: SessionMonitorState,\n homeDir: string = os.homedir(),\n): void {\n if (!sessionId) return;\n const dir = getStateDir(homeDir);\n const filePath = getStateFile(sessionId, homeDir);\n try {\n if (!fs.existsSync(dir)) {\n fs.mkdirSync(dir, { recursive: true });\n }\n fs.writeFileSync(filePath, JSON.stringify(state, null, 2) + \"\\n\", \"utf-8\");\n } catch (err) {\n log(\"state-save-failed\", {\n sessionId,\n error: (err as Error).message,\n });\n }\n}\n\n/**\n * Decide whether to report the current turn given the last-reported\n * state and the current turn's user timestamp.\n *\n * Rules:\n * - currentUserTimestamp missing/empty → report (can't dedup).\n * - no existing state → report (first turn for this session).\n * - currentUserTimestamp === existing.lastUserTimestamp → SKIP.\n * - otherwise → report (a new user turn).\n */\nexport function shouldReportTurn(\n existing: SessionMonitorState | null,\n currentUserTimestamp: string | undefined,\n): boolean {\n if (!currentUserTimestamp) return true;\n if (!existing) return true;\n return existing.lastUserTimestamp !== currentUserTimestamp;\n}\n","import * as fs from \"node:fs\";\nimport { listAgents, createAgent, getAgent, type Agent } from \"../../../lib/api.js\";\nimport { getValidToken } from \"../../../lib/auth.js\";\nimport { getBaseUrl } from \"../../../lib/config.js\";\nimport { promptUser } from \"../../prompt.js\";\nimport { validatePastedApiKey } from \"../../validate-pasted-key.js\";\nimport type { InstallOpts, InstallResult, UninstallOpts } from \"../../plugin.js\";\nimport {\n CLAUDE_DIR,\n OLAKAI_HOOK_MARKER,\n SETTINGS_FILE,\n getClaudeDir,\n getSettingsPath,\n mergeHooksSettings,\n readJsonFile,\n writeJsonFile,\n type ClaudeSettings,\n type HookMatcherEntry,\n} from \"./settings.js\";\nimport {\n deleteClaudeCodeConfig,\n getClaudeCodeConfigPath,\n writeClaudeCodeConfig,\n type MonitorConfig,\n} from \"./config.js\";\nimport { OLAKAI_DIR } from \"../../paths.js\";\nimport path from \"node:path\";\n\nconst CLAUDE_CODE_SOURCE = \"claude-code\";\nconst CLAUDE_CODE_AGENT_SOURCE = \"CLAUDE_CODE\";\nconst CLAUDE_CODE_AGENT_CATEGORY = \"CODING\";\n\nexport async function installClaudeCode(\n opts: InstallOpts,\n): Promise<InstallResult> {\n const projectRoot = opts.projectRoot ?? process.cwd();\n\n const token = getValidToken();\n if (!token) {\n console.error(\"Not logged in. Run 'olakai login' first.\");\n process.exit(1);\n }\n\n console.log(\"Setting up Claude Code monitoring for this workspace...\\n\");\n\n const dirName = path.basename(projectRoot);\n\n let agent: Agent;\n const choice = await promptUser(\n \"Create a new agent or use an existing one? (new/existing) [new]: \",\n );\n\n if (choice.toLowerCase() === \"existing\" || choice.toLowerCase() === \"e\") {\n const agents = await listAgents();\n if (agents.length === 0) {\n console.log(\"No agents found. Creating a new one instead.\\n\");\n agent = await createNewAgent(dirName);\n } else {\n console.log(\"\\nAvailable agents:\");\n for (let i = 0; i < agents.length; i++) {\n console.log(\n ` ${i + 1}. ${agents[i].name} (${agents[i].id.slice(0, 12)}...)`,\n );\n }\n\n const selection = await promptUser(`\\nSelect agent (1-${agents.length}): `);\n const idx = parseInt(selection, 10) - 1;\n\n if (isNaN(idx) || idx < 0 || idx >= agents.length) {\n console.error(\"Invalid selection.\");\n process.exit(1);\n }\n\n agent = await getAgent(agents[idx].id);\n\n if (!agent.apiKey?.key && !agent.apiKey?.isActive) {\n console.log(\n \"\\nThis agent has no active API key. Please create a new agent instead,\",\n );\n console.log(\"or generate an API key via the Olakai dashboard.\\n\");\n const createNew = await promptUser(\"Create a new agent? (y/n) [y]: \");\n if (createNew.toLowerCase() !== \"n\") {\n agent = await createNewAgent(dirName);\n } else {\n process.exit(1);\n }\n }\n }\n } else {\n agent = await createNewAgent(dirName);\n }\n\n const monitoringEndpoint = `${getBaseUrl()}/api/monitoring/prompt`;\n\n let apiKey = agent.apiKey?.key;\n if (!apiKey) {\n console.log(\n \"\\nThe API key for this agent is not available (it is only shown once at creation).\",\n );\n apiKey = await promptUser(\"Paste the API key for this agent: \");\n if (!apiKey) {\n console.error(\"API key is required for monitoring.\");\n process.exit(1);\n }\n\n // Pasted key — verify it actually belongs to the agent the user\n // picked. This guards against silent misattribution when a key\n // from a different agent is pasted by mistake. The create-new\n // path doesn't reach here (apiKey.key is populated inline by the\n // create response), so no validation is needed there.\n await validatePastedApiKey({\n monitoringEndpoint,\n apiKey,\n expectedAgentId: agent.id,\n expectedAgentName: agent.name,\n expectedApiKeyId: agent.apiKey?.id ?? null,\n });\n }\n\n const claudeDir = getClaudeDir(projectRoot);\n if (!fs.existsSync(claudeDir)) {\n fs.mkdirSync(claudeDir, { recursive: true });\n }\n\n const settingsPath = getSettingsPath(projectRoot);\n const existingSettings = readJsonFile<ClaudeSettings>(settingsPath) ?? {};\n const mergedHooks = mergeHooksSettings(existingSettings.hooks);\n const updatedSettings: ClaudeSettings = {\n ...existingSettings,\n hooks: mergedHooks,\n };\n writeJsonFile(settingsPath, updatedSettings);\n\n const monitorConfig: MonitorConfig = {\n agentId: agent.id,\n apiKey,\n agentName: agent.name,\n source: CLAUDE_CODE_SOURCE,\n createdAt: new Date().toISOString(),\n monitoringEndpoint,\n };\n writeClaudeCodeConfig(projectRoot, monitorConfig);\n\n const configPath = getClaudeCodeConfigPath(projectRoot);\n const configRel = path.relative(projectRoot, configPath);\n\n console.log(\"\");\n console.log(`✓ Agent \"${agent.name}\" configured (ID: ${agent.id})`);\n if (agent.apiKey?.key) {\n console.log(\"✓ API key generated\");\n }\n console.log(\n `✓ Claude Code hooks configured in ${CLAUDE_DIR}/${SETTINGS_FILE}`,\n );\n console.log(`✓ Monitor config saved to ${configRel}`);\n console.log(\"\");\n console.log(\n \"Monitoring is now active. Claude Code will report activity to Olakai\",\n );\n console.log(`on each turn. View activity at: ${getBaseUrl()}/dashboard`);\n console.log(\"\");\n console.log(\n `⚠ Ensure ${OLAKAI_DIR}/ is in your .gitignore (it contains your API key)`,\n );\n console.log(\"\");\n console.log(\"To check status: olakai monitor status --tool claude-code\");\n console.log(\"To disable: olakai monitor disable --tool claude-code\");\n\n return {\n agentId: agent.id,\n agentName: agent.name,\n source: CLAUDE_CODE_SOURCE,\n monitoringEndpoint,\n };\n}\n\nasync function createNewAgent(defaultName: string): Promise<Agent> {\n const nameInput = await promptUser(`Agent name [${defaultName}]: `);\n const agentName = nameInput || defaultName;\n return createAgent({\n name: agentName,\n description: `Claude Code local agent for ${agentName}`,\n role: \"WORKER\",\n createApiKey: true,\n category: CLAUDE_CODE_AGENT_CATEGORY,\n source: CLAUDE_CODE_AGENT_SOURCE,\n });\n}\n\nexport async function uninstallClaudeCode(opts: UninstallOpts): Promise<void> {\n const projectRoot = opts.projectRoot ?? process.cwd();\n\n const settingsPath = getSettingsPath(projectRoot);\n const settings = readJsonFile<ClaudeSettings>(settingsPath);\n\n if (settings?.hooks) {\n const cleanedHooks: Record<string, HookMatcherEntry[]> = {};\n for (const [event, entries] of Object.entries(settings.hooks)) {\n const filtered = entries.filter(\n (e) => !e.hooks.some((h) => h.command.includes(OLAKAI_HOOK_MARKER)),\n );\n if (filtered.length > 0) {\n cleanedHooks[event] = filtered;\n }\n }\n if (Object.keys(cleanedHooks).length > 0) {\n settings.hooks = cleanedHooks;\n } else {\n delete settings.hooks;\n }\n writeJsonFile(settingsPath, settings);\n console.log(\n `✓ Olakai hooks removed from ${CLAUDE_DIR}/${SETTINGS_FILE}`,\n );\n } else {\n console.log(\"No hooks found in settings.json.\");\n }\n\n if (!opts.keepConfig) {\n const configPath = getClaudeCodeConfigPath(projectRoot);\n const configRel = path.relative(projectRoot, configPath);\n if (deleteClaudeCodeConfig(projectRoot)) {\n console.log(`✓ Monitor config removed (${configRel})`);\n }\n } else {\n const configPath = getClaudeCodeConfigPath(projectRoot);\n const configRel = path.relative(projectRoot, configPath);\n console.log(`Monitor config retained at ${configRel}`);\n }\n\n console.log(\"\");\n console.log(\n \"Monitoring disabled. Run 'olakai monitor init --tool claude-code' to re-enable.\",\n );\n}\n","/**\n * Shared interactive prompt helper. Lives at the monitor module level\n * so plugin install flows don't each maintain their own copy.\n */\nimport * as readline from \"node:readline\";\n\nexport function promptUser(question: string): Promise<string> {\n const rl = readline.createInterface({\n input: process.stdin,\n output: process.stdout,\n });\n return new Promise((resolve) => {\n rl.question(question, (answer) => {\n rl.close();\n resolve(answer.trim());\n });\n });\n}\n\n/**\n * Whether the current process is running interactively (both stdin and\n * stdout are TTYs). Used to decide whether to prompt for missing\n * `--tool` selection or default with a deprecation notice.\n */\nexport function isInteractive(): boolean {\n return Boolean(process.stdin.isTTY && process.stdout.isTTY);\n}\n","/**\n * Shared helper used by every plugin's install flow to verify that a\n * pasted API key actually belongs to the agent the user just picked.\n *\n * Why: the backend attributes monitoring events by `x-api-key` only —\n * it does not cross-check against the local config's `agentId`. If the\n * user pastes a key from a different agent (easy to do when keys get\n * rotated or copy-pasted from history), every event silently lands on\n * the wrong agent. We catch that here before writing the workspace\n * config, by hitting `/api/monitoring/prompt/me` and comparing the\n * resolved `apiKeyId` against the one returned by the agent the user\n * picked.\n *\n * Soft-fails on network errors so users on offline / restricted\n * networks aren't blocked from finishing setup.\n */\nimport { validateMonitoringApiKey } from \"../lib/api.js\";\nimport { promptUser } from \"./prompt.js\";\n\nexport interface ValidatePastedApiKeyOpts {\n monitoringEndpoint: string;\n apiKey: string;\n expectedAgentId: string;\n expectedAgentName: string;\n /**\n * apiKey.id from the GET /api/agents/:id response (the agent the user\n * picked in the init flow). May be null if the agent has no key\n * configured — in that case we skip the strict mismatch check.\n */\n expectedApiKeyId: string | null;\n}\n\nexport async function validatePastedApiKey(\n opts: ValidatePastedApiKeyOpts,\n): Promise<void> {\n const validation = await validateMonitoringApiKey(\n opts.monitoringEndpoint,\n opts.apiKey,\n );\n\n if (validation === null) {\n // Soft warning — could be a transient network issue, restricted\n // egress, or a backend hiccup. Don't block the user; they may have\n // typed the right key and just have no connectivity right now.\n console.log(\n \"⚠ Could not verify the pasted API key (network or endpoint unreachable). Continuing.\",\n );\n return;\n }\n\n if (opts.expectedApiKeyId === null) {\n // The agent we picked has no apiKey.id we can compare against —\n // nothing to validate. The paste was already required to be\n // non-empty by the caller, so there's nothing more to check.\n return;\n }\n\n if (validation.apiKeyId === opts.expectedApiKeyId) {\n // Match — silently pass.\n return;\n }\n\n // Mismatch: the pasted key authenticates as a different agent on\n // this account than the one the user picked from the list. This is\n // exactly the misattribution bug we're guarding against.\n console.log(\"\");\n console.log(\n `⚠ The pasted API key does not belong to \"${opts.expectedAgentName}\" (${opts.expectedAgentId}).`,\n );\n console.log(\n ` It resolves to a different agent on this account, so monitoring events would be`,\n );\n console.log(\n ` attributed to that other agent — not \"${opts.expectedAgentName}\".`,\n );\n console.log(\"\");\n\n const proceed = await promptUser(\"Use the pasted key anyway? (y/n) [n]: \");\n if (proceed.trim().toLowerCase() !== \"y\") {\n console.log(\"Aborted. Re-run init with the correct key for this agent.\");\n process.exit(1);\n }\n}\n","/**\n * Claude Code Stop / SubagentStop hook adapter. Splits cleanly into two\n * pieces:\n *\n * - `buildClaudeCodePayload` (pure) — canonical MonitoringPayload\n * given the parsed event and resolved monitor config. Unit-testable\n * without filesystem.\n *\n * - `handleClaudeCodeHook` (effectful) — the plugin's `handleHook`\n * implementation. Resolves the workspace, parses stdin, dedups\n * against per-session state, and emits the payload. Returns the\n * payload (or null) so the dispatcher can do the actual POST.\n *\n * The split exists because the original `monitor.ts` did POST + state\n * save inside the hook handler. To keep the plugin contract clean, the\n * dispatcher (`commands/monitor.ts`) now owns the network and dedup\n * persistence; the plugin produces a payload candidate and lets the\n * dispatcher decide what to do with it.\n */\nimport * as fs from \"node:fs\";\nimport {\n parseTranscript,\n type ExtractedTranscriptData,\n} from \"./transcript.js\";\nimport type { MonitoringPayload } from \"../../plugin.js\";\nimport type { MonitorConfig } from \"./config.js\";\n\n/**\n * Claude Code hook event payloads.\n *\n * The Stop / SubagentStop hooks send ONLY the fields below — the\n * conversation data (prompt, response, tokens, model, etc.) is NOT in\n * the hook JSON. To get that data we read the transcript file at\n * `transcript_path`.\n *\n * The exact field that carries the subagent name is not formally\n * documented, so we accept several candidates (`agent_name`,\n * `agent_type`, `subagent_type`) and fall back to the `tool_input`\n * shape that the Agent tool_use block uses.\n */\nexport interface ClaudeHookEvent {\n session_id?: string;\n transcript_path?: string;\n hook_event_name?: string;\n stop_hook_active?: boolean;\n cwd?: string;\n agent_name?: string;\n agent_type?: string;\n subagent_type?: string;\n tool_input?: {\n subagent_type?: string;\n description?: string;\n };\n /**\n * Authoritative final assistant text from Claude Code's in-memory\n * state at hook-fire time. Preferred over transcript-file parsing\n * for the response — see the original docstring in `monitor.ts`.\n */\n last_assistant_message?: string;\n}\n\nexport type DebugLogger = (label: string, data: unknown) => void;\n\nconst noopDebug: DebugLogger = () => {};\n\n/**\n * Load a transcript JSONL from disk and extract the data we want to\n * report. Any failure (missing file, malformed JSON, unexpected shape)\n * is swallowed and we return a best-effort empty result. Parsing\n * itself lives in `transcript.ts` so it can be unit-tested.\n */\nexport function extractFromTranscript(\n transcriptPath: string | undefined,\n debugLog: DebugLogger = noopDebug,\n): ExtractedTranscriptData {\n const empty: ExtractedTranscriptData = {\n prompt: \"\",\n response: \"\",\n tokens: 0,\n inputTokens: 0,\n outputTokens: 0,\n modelName: null,\n numTurns: 0,\n toolCallCount: 0,\n filesEditedCount: 0,\n bashCommandCount: 0,\n };\n\n if (!transcriptPath) return empty;\n\n let raw: string;\n try {\n raw = fs.readFileSync(transcriptPath, \"utf-8\");\n } catch (err) {\n debugLog(\"transcript-read-failed\", {\n transcriptPath,\n error: (err as Error).message,\n });\n return empty;\n }\n\n return parseTranscript(raw);\n}\n\nfunction extractSubagentName(event: ClaudeHookEvent): string | undefined {\n const candidates = [\n event.agent_name,\n event.subagent_type,\n event.agent_type,\n event.tool_input?.subagent_type,\n ];\n for (const value of candidates) {\n if (typeof value === \"string\" && value.trim()) {\n return value.trim();\n }\n }\n return undefined;\n}\n\n/**\n * Build a MonitoringPayload from a Claude Code hook event.\n *\n * For Stop / SubagentStop events, the hook JSON contains only\n * session_id + transcript_path — the actual conversation data is\n * extracted from the transcript JSONL file. Other event names return\n * null (silent-exit at the dispatcher).\n */\nexport function buildClaudeCodePayload(\n event: string,\n eventData: ClaudeHookEvent,\n config: MonitorConfig,\n): MonitoringPayload | null {\n const sessionId = eventData.session_id ?? `claude-code-${Date.now()}`;\n\n switch (event) {\n case \"stop\":\n case \"subagent-stop\": {\n const extracted = extractFromTranscript(eventData.transcript_path);\n const isSubagent = event === \"subagent-stop\";\n\n const customData: Record<string, unknown> = {\n hookEvent:\n eventData.hook_event_name ??\n (isSubagent ? \"SubagentStop\" : \"Stop\"),\n sessionId,\n transcriptPath: eventData.transcript_path ?? \"\",\n cwd: eventData.cwd ?? \"\",\n stopHookActive: eventData.stop_hook_active ?? false,\n inputTokens: extracted.inputTokens,\n outputTokens: extracted.outputTokens,\n numTurns: extracted.numTurns,\n // Per-turn work signals for the Claude Code classifier (D-027).\n // Always emitted as JSON numbers — the backend classifier and\n // KPI formulas must see numeric 0, not missing keys or strings.\n toolCallCount: extracted.toolCallCount,\n filesEditedCount: extracted.filesEditedCount,\n bashCommandCount: extracted.bashCommandCount,\n };\n\n if (typeof extracted.latencyMs === \"number\") {\n customData.latencyMs = extracted.latencyMs;\n }\n\n if (isSubagent) {\n const subagent = extractSubagentName(eventData);\n if (subagent) {\n customData.subagent = subagent;\n }\n } else if (extracted.skill) {\n // Skill detection only applies to main-agent Stop events.\n customData.skill = extracted.skill;\n }\n\n // Prefer the hook payload's last_assistant_message — Claude Code\n // ships it from in-memory state at hook-fire time, so it\n // reflects the final text block of the turn even when the\n // transcript JSONL hasn't been flushed to disk yet.\n const payloadAssistant = eventData.last_assistant_message;\n const response =\n typeof payloadAssistant === \"string\" && payloadAssistant.trim()\n ? payloadAssistant\n : extracted.response;\n\n return {\n prompt: extracted.prompt,\n response,\n chatId: sessionId,\n source: config.source,\n modelName: extracted.modelName ?? undefined,\n tokens: extracted.tokens,\n customData,\n };\n }\n\n default:\n return null;\n }\n}\n","/**\n * Transcript parsing for Claude Code Stop-hook monitoring.\n *\n * The Stop hook passes only a `transcript_path` pointing at a JSONL file.\n * This module is the single place we extract the per-turn data we report\n * to Olakai (prompt, response, tokens, model, latency, skill invocation).\n *\n * The code here is intentionally pure and exports named helpers so it can\n * be unit-tested without touching the filesystem or HTTP layer.\n */\n\n/**\n * Shape of a single line in a Claude Code transcript JSONL file.\n * Each line is a standalone JSON object. We only care about `user` and\n * `assistant` entries; other types (`system`, `file-history-snapshot`,\n * `progress`, compaction markers, ...) are ignored.\n */\nexport interface TranscriptLine {\n type?: string;\n subtype?: string;\n isMeta?: boolean;\n isSidechain?: boolean;\n timestamp?: string;\n message?: {\n role?: string;\n model?: string;\n content?: string | TranscriptContentBlock[];\n usage?: {\n input_tokens?: number;\n output_tokens?: number;\n cache_creation_input_tokens?: number;\n cache_read_input_tokens?: number;\n };\n };\n}\n\nexport interface TranscriptContentBlock {\n type?: string;\n text?: string;\n /**\n * For `tool_use` blocks. Name of the tool the assistant invoked\n * (e.g. `\"Edit\"`, `\"Write\"`, `\"MultiEdit\"`, `\"Bash\"`).\n */\n name?: string;\n /**\n * For `tool_use` blocks. Tool-specific input object. We read\n * `input.file_path` for `Edit`/`Write`/`MultiEdit` to count\n * distinct edited files. Typed as `unknown` because each tool\n * uses a different shape and we only probe `file_path` defensively.\n */\n input?: unknown;\n}\n\nexport interface ExtractedTranscriptData {\n prompt: string;\n response: string;\n tokens: number;\n inputTokens: number;\n outputTokens: number;\n modelName: string | null;\n numTurns: number;\n /**\n * Latency in milliseconds between the current turn's user message and\n * its final assistant response. Undefined when latency could not be\n * computed (first turn, missing timestamps, no user predecessor).\n */\n latencyMs?: number;\n /**\n * Leading slash-command captured from the current turn's user message\n * (e.g. `\"olakai-create-agent\"` for `/olakai-create-agent do X`).\n * Undefined when the user message did not start with a slash-command.\n */\n skill?: string;\n /**\n * ISO 8601 timestamp of the current turn's user message (the last\n * non-meta, non-sidechain user entry in the transcript). Used by the\n * hook layer to dedup duplicate Stop firings for the same user turn.\n * Undefined when no usable user entry is present or the timestamp\n * is missing/unparseable.\n */\n userTurnTimestamp?: string;\n /**\n * Count of `tool_use` content blocks in the current turn's assistant\n * messages. Used as a signal for the Claude Code work classifier\n * (D-027). Always an integer; `0` when the turn contained no tool\n * calls (explicit zero beats missing key). Per-turn, not per-session —\n * the chat decorator aggregates across turns server-side.\n */\n toolCallCount: number;\n /**\n * Count of distinct `file_path` values across `Edit`, `Write`, and\n * `MultiEdit` `tool_use` blocks in the current turn. Counted as the\n * size of a `Set<string>` so duplicate paths within the same turn\n * collapse to one. File paths themselves are NOT emitted — only the\n * cardinality is privacy-safe to report.\n */\n filesEditedCount: number;\n /**\n * Count of `tool_use` blocks with `name === \"Bash\"` in the current\n * turn. Bash command strings are NOT emitted — only the count.\n */\n bashCommandCount: number;\n}\n\n/**\n * Tool names whose invocations we count toward `filesEditedCount`.\n * Kept as a typed constant so both the per-block switch and any\n * future backend-side mirror can reference the same list.\n */\nconst FILE_EDITING_TOOL_NAMES = new Set<string>([\n \"Edit\",\n \"Write\",\n \"MultiEdit\",\n]);\n\n/**\n * Tool-name marker for Bash invocations. Hoisted to a constant so we\n * don't sprinkle the string literal through the parser.\n */\nconst BASH_TOOL_NAME = \"Bash\";\n\n/**\n * Match a slash-command at the start of a message. Leading whitespace is\n * trimmed before matching. The captured group is the skill name.\n *\n * Examples (match):\n * \"/foo\" -> \"foo\"\n * \"/foo-bar\" -> \"foo-bar\"\n * \"/foo some args\" -> \"foo\"\n *\n * Examples (no match):\n * \"Not a skill: /path/file\" — slash is not at the start\n * \"/path/file\" — second segment, name contains a slash\n * \"\" — empty\n */\nconst SKILL_REGEX = /^\\/([\\w-]+)(?:\\s|$)/;\n\nexport function detectSkill(userMessage: string | undefined): string | undefined {\n if (typeof userMessage !== \"string\") return undefined;\n const trimmed = userMessage.trimStart();\n if (!trimmed) return undefined;\n const match = SKILL_REGEX.exec(trimmed);\n if (!match) return undefined;\n return match[1];\n}\n\n/**\n * Extract plain text from a transcript message's `content` field.\n * Content may be a string or an array of content blocks.\n * Only `text` blocks contribute — `thinking`, `tool_use`, `tool_result`,\n * and `image` blocks are ignored.\n */\nexport function extractTextContent(\n content: string | TranscriptContentBlock[] | undefined,\n): string {\n if (typeof content === \"string\") return content;\n if (!Array.isArray(content)) return \"\";\n const parts: string[] = [];\n for (const block of content) {\n if (block?.type === \"text\" && typeof block.text === \"string\") {\n parts.push(block.text);\n }\n }\n return parts.join(\"\\n\").trim();\n}\n\n/**\n * Heuristic: is this a \"meta\" user message that should not be treated\n * as a real prompt? These include slash-command invocations and local\n * command caveats injected by Claude Code itself. Note that these are\n * separate `type: \"system\"` entries — regular `type: \"user\"` entries\n * carrying a typed slash-command still come through here and are NOT\n * skipped.\n */\nexport function isMetaUserMessage(line: TranscriptLine, text: string): boolean {\n if (line.isMeta === true) return true;\n if (!text) return true;\n return (\n text.includes(\"<command-name>\") ||\n text.includes(\"<local-command-caveat>\") ||\n text.includes(\"<command-message>\")\n );\n}\n\n/**\n * Parse an ISO 8601 timestamp to epoch milliseconds.\n * Returns NaN for invalid/undefined input.\n */\nfunction parseTimestamp(ts: string | undefined): number {\n if (typeof ts !== \"string\" || !ts) return NaN;\n return Date.parse(ts);\n}\n\n/**\n * Compaction markers interleaved in the transcript that should be\n * skipped when computing per-turn latency. The exact subtype strings\n * come from Claude Code's own PreCompact / PostCompact hook events\n * (recorded as `type: \"system\"` entries in the transcript).\n */\nfunction isCompactionEntry(line: TranscriptLine): boolean {\n if (line.type !== \"system\") return false;\n const subtype = line.subtype ?? \"\";\n return (\n subtype === \"compact_boundary\" ||\n subtype === \"pre_compact\" ||\n subtype === \"post_compact\" ||\n /compact/i.test(subtype)\n );\n}\n\n/**\n * Parse the transcript JSONL contents and extract the data we want to\n * report: last user prompt, last assistant response, usage totals for\n * the most recent assistant turn, model name, number of assistant\n * turns, latency for the most recent turn, and slash-command (skill)\n * detected on the current turn's user message.\n *\n * `raw` is the full UTF-8 contents of the transcript file. This entry\n * point is pure — no filesystem I/O — so it's trivial to unit test.\n */\nexport function parseTranscript(raw: string): ExtractedTranscriptData {\n const empty: ExtractedTranscriptData = {\n prompt: \"\",\n response: \"\",\n tokens: 0,\n inputTokens: 0,\n outputTokens: 0,\n modelName: null,\n numTurns: 0,\n toolCallCount: 0,\n filesEditedCount: 0,\n bashCommandCount: 0,\n };\n\n if (!raw) return empty;\n\n const lines = raw.split(\"\\n\");\n let lastUserText = \"\";\n let lastUserTimestamp: number = NaN;\n // Original ISO string of the current turn's user message, preserved so\n // the hook layer can use it as a per-session dedup key across\n // duplicate Stop firings. Kept separate from the numeric timestamp\n // because round-tripping Date.parse back through new Date().toISOString()\n // drops sub-ms precision and normalizes timezone formatting.\n let lastUserTimestampRaw: string | undefined;\n let lastAssistantText = \"\";\n let lastAssistantTimestamp: number = NaN;\n let lastAssistantModel: string | null = null;\n let lastAssistantInputTokens = 0;\n let lastAssistantOutputTokens = 0;\n let numTurns = 0;\n // Tracks whether we have seen a new user message since the last\n // assistant-latency update. Ensures latency is always measured\n // relative to the user that preceded the final assistant in the\n // current turn — not across turns.\n let currentTurnUserTimestamp: number = NaN;\n\n // Per-turn work-signal accumulators (D-027 / D.S2). Reset every time\n // we cross a new top-level user message so counts reflect only the\n // current turn window — the assistant messages between the last user\n // message and Stop. Aggregation across turns happens server-side in\n // the chat decorator, not here.\n let toolCallCount = 0;\n let bashCommandCount = 0;\n let editedFilePaths = new Set<string>();\n\n for (const rawLine of lines) {\n if (!rawLine) continue;\n let parsed: TranscriptLine;\n try {\n parsed = JSON.parse(rawLine) as TranscriptLine;\n } catch {\n continue; // skip malformed lines\n }\n\n // Skip compaction markers so they don't break the user->assistant\n // pairing used for latency.\n if (isCompactionEntry(parsed)) continue;\n\n // Skip sidechain (subagent) entries — we want the top-level session\n // conversation. If a transcript only has sidechain entries, the\n // loop below will leave us with empty strings.\n if (parsed.isSidechain === true) continue;\n\n if (parsed.type === \"user\" && parsed.message) {\n const text = extractTextContent(parsed.message.content);\n if (isMetaUserMessage(parsed, text)) continue;\n lastUserText = text;\n lastUserTimestamp = parseTimestamp(parsed.timestamp);\n currentTurnUserTimestamp = lastUserTimestamp;\n // Reset per-turn work-signal accumulators: we've just crossed\n // into a new turn window, so counts from previous turns must\n // not bleed into this one. The chat decorator aggregates across\n // turns server-side (D.S3); here we only emit per-PR counts.\n toolCallCount = 0;\n bashCommandCount = 0;\n editedFilePaths = new Set<string>();\n // Preserve the raw ISO string (only when it's actually a string)\n // for use as a dedup key. Unparseable timestamps are still kept\n // verbatim so upstream can match on exact-string equality.\n lastUserTimestampRaw =\n typeof parsed.timestamp === \"string\" && parsed.timestamp\n ? parsed.timestamp\n : undefined;\n } else if (parsed.type === \"assistant\" && parsed.message) {\n const text = extractTextContent(parsed.message.content);\n // Count every assistant entry (each represents one model response\n // turn, even if it contains only a tool_use or thinking block).\n numTurns += 1;\n if (text) lastAssistantText = text;\n if (typeof parsed.message.model === \"string\") {\n lastAssistantModel = parsed.message.model;\n }\n // Accumulate per-turn work signals. Each tool_use block\n // increments the total, Edit/Write/MultiEdit contribute their\n // file_path to a Set (distinct-path count is what we emit), and\n // Bash tool calls bump their own counter. Individual-block\n // parse failures are swallowed so one malformed entry cannot\n // zero out the whole turn's counts.\n const content = parsed.message.content;\n if (Array.isArray(content)) {\n for (const block of content) {\n try {\n if (!block || block.type !== \"tool_use\") continue;\n toolCallCount += 1;\n const name = typeof block.name === \"string\" ? block.name : \"\";\n if (name === BASH_TOOL_NAME) {\n bashCommandCount += 1;\n continue;\n }\n if (FILE_EDITING_TOOL_NAMES.has(name)) {\n const input = block.input;\n if (\n input !== null &&\n typeof input === \"object\" &&\n \"file_path\" in input\n ) {\n const filePath = (input as { file_path?: unknown }).file_path;\n if (typeof filePath === \"string\" && filePath) {\n editedFilePaths.add(filePath);\n }\n }\n }\n } catch {\n // Malformed block — skip it without failing the whole\n // transcript walk. Partial counts are better than zero.\n }\n }\n }\n const usage = parsed.message.usage;\n if (usage) {\n // Overwrite with the most recent turn's usage. Include cache\n // tokens in the input total so total token count reflects real\n // billable input.\n const input =\n (usage.input_tokens ?? 0) +\n (usage.cache_creation_input_tokens ?? 0) +\n (usage.cache_read_input_tokens ?? 0);\n const output = usage.output_tokens ?? 0;\n lastAssistantInputTokens = input;\n lastAssistantOutputTokens = output;\n }\n const ts = parseTimestamp(parsed.timestamp);\n if (!Number.isNaN(ts)) {\n lastAssistantTimestamp = ts;\n }\n }\n }\n\n const result: ExtractedTranscriptData = {\n prompt: lastUserText,\n response: lastAssistantText,\n tokens: lastAssistantInputTokens + lastAssistantOutputTokens,\n inputTokens: lastAssistantInputTokens,\n outputTokens: lastAssistantOutputTokens,\n modelName: lastAssistantModel,\n numTurns,\n toolCallCount,\n filesEditedCount: editedFilePaths.size,\n bashCommandCount,\n };\n\n if (\n !Number.isNaN(currentTurnUserTimestamp) &&\n !Number.isNaN(lastAssistantTimestamp) &&\n lastAssistantTimestamp >= currentTurnUserTimestamp\n ) {\n result.latencyMs = Math.round(\n lastAssistantTimestamp - currentTurnUserTimestamp,\n );\n }\n\n const skill = detectSkill(lastUserText);\n if (skill) {\n result.skill = skill;\n }\n\n if (lastUserTimestampRaw) {\n result.userTurnTimestamp = lastUserTimestampRaw;\n }\n\n return result;\n}\n","/**\n * OpenAI Codex CLI plugin (Stage 3).\n *\n * Hooks the `Stop` event from `~/.codex/config.toml` into the canonical\n * Olakai monitoring pipeline. (Earlier versions also registered\n * `UserPromptSubmit`, but it fires pre-LLM and double-counts the\n * per-event cost baseline — `hook.ts` silent-exits any leftover legacy\n * registrations.) Mirrors the Claude\n * Code plugin's split (install / uninstall / status / hook /\n * transcript) so the dispatcher in `commands/monitor.ts` doesn't need\n * tool-specific branches beyond the existing `printCodexStatus` /\n * `printClaudeCodeStatus` formatter switch.\n *\n * Defensive parsing per D-003: every field access on the inbound\n * payload is guarded; unrecognized event types silent-exit; rollout\n * lookup failures fall back to inline payload fields where possible.\n *\n * The hook handler MUST run synchronously — Codex skips `async = true`\n * handlers with a warning. The dispatcher's fire-and-forget POST\n * (`postMonitoringPayload`) uses a 5s AbortController timeout to\n * guarantee the process exits within the hook's `timeout` window.\n */\nimport * as fs from \"node:fs\";\nimport { spawnSync } from \"node:child_process\";\nimport {\n registerPlugin,\n type HookResult,\n type InstallOpts,\n type InstallResult,\n type StatusReport,\n type ToolMonitorPlugin,\n type UninstallOpts,\n} from \"../../plugin.js\";\nimport { findConfiguredWorkspace } from \"../../paths.js\";\nimport { installCodex } from \"./install.js\";\nimport { uninstallCodex } from \"./uninstall.js\";\nimport { getCodexStatus } from \"./status.js\";\nimport { handleCodexHook, type CodexHookEvent } from \"./hook.js\";\nimport {\n getCodexConfigPath as getCodexMonitorConfigPath,\n loadCodexConfig,\n} from \"./config.js\";\nimport { getCodexConfigPath as getCodexHomeConfigPath, getCodexHomeDir } from \"./paths.js\";\n\nconst TOOL_ID = \"codex\" as const;\n\n/**\n * Debug logger gated by `OLAKAI_MONITOR_DEBUG=1`. Mirrors the\n * Claude Code plugin's debug log so users only need to look in one\n * place when diagnosing hook failures.\n */\nfunction debugLog(label: string, data: unknown): void {\n if (process.env.OLAKAI_MONITOR_DEBUG !== \"1\") return;\n try {\n const logPath = `/tmp/olakai-monitor-debug-${process.pid}.log`;\n const line = `[${new Date().toISOString()}] codex/${label}: ${\n typeof data === \"string\" ? data : JSON.stringify(data, null, 2)\n }\\n`;\n fs.appendFileSync(logPath, line, \"utf-8\");\n } catch {\n // Never break the hook path on a debug-log failure\n }\n}\n\n/**\n * Resolve the configured workspace root from a Codex hook payload.\n * Codex hooks fire from the user's terminal CWD, which the schema\n * exposes as `payload.cwd`. We walk up from there looking for any\n * `.olakai/monitor-*.json` so a developer running `codex` deep inside\n * a project's subfolder still hits their workspace's monitor config.\n *\n * Exported for unit tests.\n */\nexport function resolveCodexProjectRoot(\n eventData: CodexHookEvent,\n fallbackCwd: string,\n): string | null {\n const payloadCwd =\n typeof eventData.cwd === \"string\" && eventData.cwd.trim()\n ? eventData.cwd\n : fallbackCwd;\n return findConfiguredWorkspace(payloadCwd, [TOOL_ID]);\n}\n\nconst codexPlugin: ToolMonitorPlugin = {\n id: TOOL_ID,\n displayName: \"OpenAI Codex CLI\",\n\n install(opts: InstallOpts): Promise<InstallResult> {\n return installCodex(opts);\n },\n\n uninstall(opts: UninstallOpts): Promise<void> {\n return uninstallCodex(opts);\n },\n\n status(opts): Promise<StatusReport> {\n return getCodexStatus(opts);\n },\n\n async handleHook(\n eventName,\n payloadJson,\n ): Promise<HookResult | null> {\n const eventData = (payloadJson ?? {}) as CodexHookEvent;\n debugLog(\"hook-fired\", { eventName, hasPayload: payloadJson != null });\n\n const projectRoot = resolveCodexProjectRoot(eventData, process.cwd());\n if (!projectRoot) {\n debugLog(\"config-not-found\", {\n startDir:\n typeof eventData.cwd === \"string\" && eventData.cwd.trim()\n ? eventData.cwd\n : process.cwd(),\n });\n return null;\n }\n\n const config = loadCodexConfig(projectRoot);\n if (!config) {\n debugLog(\"monitor-config-missing\", { projectRoot });\n return null;\n }\n\n const payload = handleCodexHook(eventName, eventData, config, {\n debugLog,\n });\n if (!payload) return null;\n\n return {\n payload,\n transport: {\n endpoint: config.monitoringEndpoint,\n apiKey: config.apiKey,\n projectRoot,\n },\n };\n },\n\n async detectInstalled(opts): Promise<boolean> {\n // Two independent signals — either is enough to surface \"codex\"\n // in the interactive `init` selector:\n // 1. The user ran `olakai monitor init --tool codex` here\n // (workspace-local monitor config exists), OR\n // 2. The Codex CLI itself is installed on this host\n // (binary on PATH or `~/.codex/config.toml` present).\n //\n // The PATH probe uses `which` synchronously through\n // `child_process.spawnSync` to avoid shelling out — it's cheap\n // (<10ms) and any failure is treated as \"not installed\".\n const projectRoot = opts?.projectRoot ?? process.cwd();\n try {\n if (fs.existsSync(getCodexMonitorConfigPath(projectRoot))) {\n return true;\n }\n } catch {\n // Fall through to other checks\n }\n try {\n if (fs.existsSync(getCodexHomeConfigPath())) {\n return true;\n }\n if (fs.existsSync(getCodexHomeDir())) {\n // Even an empty ~/.codex tells us Codex has run before\n return true;\n }\n } catch {\n // Fall through\n }\n return detectCodexBinaryOnPath();\n },\n};\n\nfunction detectCodexBinaryOnPath(): boolean {\n try {\n const probe = spawnSync(\n process.platform === \"win32\" ? \"where\" : \"which\",\n [\"codex\"],\n {\n stdio: [\"ignore\", \"pipe\", \"ignore\"],\n timeout: 1000,\n },\n );\n if (probe.status === 0 && probe.stdout && probe.stdout.toString().trim()) {\n return true;\n }\n } catch {\n // Treat any failure as \"not detectable\"\n }\n return false;\n}\n\nregisterPlugin(codexPlugin);\n\nexport default codexPlugin;\nexport { type CodexHookEvent } from \"./hook.js\";\nexport { type CodexMonitorConfig } from \"./config.js\";\n","/**\n * Codex install / uninstall flow.\n *\n * Installs Olakai hook entries into `~/.codex/config.toml` (creating\n * the file when missing) and writes a per-tool monitor config under\n * `.olakai/monitor-codex.json`.\n *\n * Uninstall is the reverse: strip Olakai-marked handlers from the\n * config TOML (preserving any user-added entries) and optionally\n * remove the local monitor config file.\n *\n * The TOML round-trip uses `@iarna/toml` so user-added comments will\n * be lost — there's no comment-preserving TOML library in the JS\n * ecosystem. We surface this in the install output (\"config.toml\n * comments are not preserved\") so users aren't surprised.\n */\nimport * as fs from \"node:fs\";\nimport * as path from \"node:path\";\nimport * as TOML from \"@iarna/toml\";\nimport { createAgent, getAgent, listAgents, type Agent } from \"../../../lib/api.js\";\nimport { getValidToken } from \"../../../lib/auth.js\";\nimport { getBaseUrl } from \"../../../lib/config.js\";\nimport { promptUser } from \"../../prompt.js\";\nimport { validatePastedApiKey } from \"../../validate-pasted-key.js\";\nimport { OLAKAI_DIR } from \"../../paths.js\";\nimport type { InstallOpts, InstallResult, UninstallOpts } from \"../../plugin.js\";\nimport {\n CODEX_CONFIG_FILENAME,\n CODEX_HOME_DIRNAME,\n getCodexConfigPath as getCodexHomeConfigPath,\n getCodexHomeDir,\n} from \"./paths.js\";\nimport {\n CODEX_HOOK_TIMEOUT_SECONDS,\n hasOlakaiHooksInstalled,\n mergeCodexHooks,\n stripOlakaiHooks,\n SUPPORTED_HOOK_EVENT_NAMES,\n type CodexConfigToml,\n} from \"./hooks.js\";\nimport {\n deleteCodexConfig,\n getCodexConfigPath as getCodexMonitorConfigPath,\n writeCodexConfig,\n type CodexMonitorConfig,\n} from \"./config.js\";\n\nexport const CODEX_SOURCE = \"codex\";\nexport const CODEX_AGENT_SOURCE = \"CODEX\";\nexport const CODEX_AGENT_CATEGORY = \"CODING\";\n\nexport async function installCodex(opts: InstallOpts): Promise<InstallResult> {\n const projectRoot = opts.projectRoot ?? process.cwd();\n\n const token = getValidToken();\n if (!token) {\n console.error(\"Not logged in. Run 'olakai login' first.\");\n process.exit(1);\n }\n\n console.log(\"Setting up Codex CLI monitoring for this workspace...\\n\");\n\n const dirName = path.basename(projectRoot);\n\n let agent: Agent;\n const choice = await promptUser(\n \"Create a new agent or use an existing one? (new/existing) [new]: \",\n );\n\n if (choice.toLowerCase() === \"existing\" || choice.toLowerCase() === \"e\") {\n const agents = await listAgents();\n if (agents.length === 0) {\n console.log(\"No agents found. Creating a new one instead.\\n\");\n agent = await createNewAgent(dirName);\n } else {\n console.log(\"\\nAvailable agents:\");\n for (let i = 0; i < agents.length; i++) {\n console.log(\n ` ${i + 1}. ${agents[i].name} (${agents[i].id.slice(0, 12)}...)`,\n );\n }\n\n const selection = await promptUser(`\\nSelect agent (1-${agents.length}): `);\n const idx = parseInt(selection, 10) - 1;\n\n if (isNaN(idx) || idx < 0 || idx >= agents.length) {\n console.error(\"Invalid selection.\");\n process.exit(1);\n }\n\n agent = await getAgent(agents[idx].id);\n\n // We're checking whether an active key EXISTS, not whether we\n // received its value. The GET /api/agents/:id read endpoint omits\n // `apiKey.key` for security on existing agents — `isActive: true`\n // is the signal that a usable key exists somewhere. When we have\n // either signal, fall through to the value-retrieval block below\n // (line ~112) which prompts the user to paste the key. Only block\n // here when BOTH are missing, meaning no key is configured at all.\n if (!agent.apiKey?.key && !agent.apiKey?.isActive) {\n console.log(\n \"\\nThis agent has no active API key. Please create a new agent instead,\",\n );\n console.log(\"or generate an API key via the Olakai dashboard.\\n\");\n const createNew = await promptUser(\"Create a new agent? (y/n) [y]: \");\n if (createNew.toLowerCase() !== \"n\") {\n agent = await createNewAgent(dirName);\n } else {\n process.exit(1);\n }\n }\n }\n } else {\n agent = await createNewAgent(dirName);\n }\n\n const monitoringEndpoint = `${getBaseUrl()}/api/monitoring/prompt`;\n\n let apiKey = agent.apiKey?.key;\n if (!apiKey) {\n console.log(\n \"\\nThe API key for this agent is not available (it is only shown once at creation).\",\n );\n apiKey = await promptUser(\"Paste the API key for this agent: \");\n if (!apiKey) {\n console.error(\"API key is required for monitoring.\");\n process.exit(1);\n }\n\n // Pasted key — verify it actually belongs to the agent the user\n // picked. This guards against silent misattribution when a key\n // from a different agent is pasted by mistake. The create-new\n // path doesn't reach here (apiKey.key is populated inline by the\n // create response), so no validation is needed there.\n await validatePastedApiKey({\n monitoringEndpoint,\n apiKey,\n expectedAgentId: agent.id,\n expectedAgentName: agent.name,\n expectedApiKeyId: agent.apiKey?.id ?? null,\n });\n }\n\n // 1) Install hooks into ~/.codex/config.toml\n const { configExisted: codexConfigExisted } = installCodexHooksConfig();\n\n // 2) Write per-tool monitor config in workspace\n const monitorConfig: CodexMonitorConfig = {\n agentId: agent.id,\n apiKey,\n agentName: agent.name,\n source: CODEX_SOURCE,\n createdAt: new Date().toISOString(),\n monitoringEndpoint,\n };\n writeCodexConfig(projectRoot, monitorConfig);\n\n const configPath = getCodexMonitorConfigPath(projectRoot);\n const configRel = path.relative(projectRoot, configPath);\n\n console.log(\"\");\n console.log(`✓ Agent \"${agent.name}\" configured (ID: ${agent.id})`);\n if (agent.apiKey?.key) {\n console.log(\"✓ API key generated\");\n }\n console.log(\n `✓ Codex hooks configured in ~/${CODEX_HOME_DIRNAME}/${CODEX_CONFIG_FILENAME}`,\n );\n console.log(`✓ Monitor config saved to ${configRel}`);\n console.log(\"\");\n console.log(\n \"Monitoring is now active. Codex CLI will report activity to Olakai\",\n );\n console.log(`on each turn. View activity at: ${getBaseUrl()}/dashboard`);\n console.log(\"\");\n console.log(\n `⚠ Ensure ${OLAKAI_DIR}/ is in your .gitignore (it contains your API key).`,\n );\n console.log(\n `⚠ Codex hooks require codex >= 0.124.0. Earlier versions silently skip them.`,\n );\n if (codexConfigExisted) {\n // Only warn on rewrite — there's nothing to lose for a brand-new file.\n console.log(\n `⚠ Existing comments in ~/${CODEX_HOME_DIRNAME}/${CODEX_CONFIG_FILENAME} were not preserved (TOML serializer limitation).`,\n );\n }\n console.log(\"\");\n console.log(\"To check status: olakai monitor status --tool codex\");\n console.log(\"To disable: olakai monitor disable --tool codex\");\n\n return {\n agentId: agent.id,\n agentName: agent.name,\n source: CODEX_SOURCE,\n monitoringEndpoint,\n };\n}\n\nasync function createNewAgent(defaultName: string): Promise<Agent> {\n const nameInput = await promptUser(`Agent name [${defaultName}]: `);\n const agentName = nameInput || defaultName;\n return createAgent({\n name: agentName,\n description: `Codex CLI local agent for ${agentName}`,\n role: \"WORKER\",\n createApiKey: true,\n category: CODEX_AGENT_CATEGORY,\n source: CODEX_AGENT_SOURCE,\n });\n}\n\nexport interface InstallHooksConfigResult {\n /**\n * True when `~/.codex/config.toml` already existed before we wrote\n * to it (i.e. we performed a read-merge-write rewrite). False when\n * we created the file from scratch — callers can use this to avoid\n * surfacing a misleading \"comments not preserved\" warning on\n * brand-new files.\n */\n configExisted: boolean;\n}\n\n/**\n * Read-merge-write `~/.codex/config.toml` so our Stop handler is\n * installed alongside any user-defined config. Creates the file (and\n * parent directory) when missing.\n *\n * Only `Stop` is registered: it is the canonical capture point for a\n * turn (prompt + response + tokens via the rollout JSONL). The legacy\n * `UserPromptSubmit` registration is intentionally NOT written by new\n * installs — see `hook.ts` for the rationale (pre-LLM emit produced a\n * duplicate, response-less event that double-counted cost).\n *\n * Existing configs that still have a `UserPromptSubmit` Olakai entry\n * are not actively rewritten here, but uninstall (and a fresh init\n * round-trip) will strip them via `OLAKAI_HOOK_MARKER`.\n */\nexport function installCodexHooksConfig(): InstallHooksConfigResult {\n const homeDir = getCodexHomeDir();\n const configPath = getCodexHomeConfigPath();\n\n if (!fs.existsSync(homeDir)) {\n fs.mkdirSync(homeDir, { recursive: true });\n }\n\n const configExisted = fs.existsSync(configPath);\n\n const parsed = readCodexConfigToml(configPath);\n const merged: CodexConfigToml = {\n ...parsed,\n hooks: mergeCodexHooks(parsed.hooks, SUPPORTED_HOOK_EVENT_NAMES),\n };\n\n writeCodexConfigToml(configPath, merged);\n return { configExisted };\n}\n\nexport async function uninstallCodex(opts: UninstallOpts): Promise<void> {\n const projectRoot = opts.projectRoot ?? process.cwd();\n\n const removedHooks = stripCodexHooksConfig();\n if (removedHooks) {\n console.log(\n `✓ Olakai hooks removed from ~/${CODEX_HOME_DIRNAME}/${CODEX_CONFIG_FILENAME}`,\n );\n } else {\n console.log(\"No Olakai hooks found in Codex config.\");\n }\n\n if (!opts.keepConfig) {\n const configPath = getCodexMonitorConfigPath(projectRoot);\n const configRel = path.relative(projectRoot, configPath);\n if (deleteCodexConfig(projectRoot)) {\n console.log(`✓ Monitor config removed (${configRel})`);\n }\n } else {\n const configPath = getCodexMonitorConfigPath(projectRoot);\n const configRel = path.relative(projectRoot, configPath);\n console.log(`Monitor config retained at ${configRel}`);\n }\n\n console.log(\"\");\n console.log(\n \"Monitoring disabled. Run 'olakai monitor init --tool codex' to re-enable.\",\n );\n}\n\n/**\n * Apply the Olakai-strip transform to a parsed Codex config in\n * memory. Pure — no I/O — so it can be unit-tested directly.\n *\n * Returns a new config where:\n * - Olakai-marked handlers have been removed from `[hooks]`.\n * - If the resulting `[hooks]` block is empty, the `hooks` key is\n * OMITTED from the returned object (rather than left as an empty\n * `{}`), so the rewritten TOML doesn't carry an orphan `[hooks]`\n * header.\n * - Unrelated top-level keys and user-defined hook entries on\n * other events are preserved verbatim.\n */\nexport function applyOlakaiStripToConfig(\n parsed: CodexConfigToml,\n): CodexConfigToml {\n const cleaned = stripOlakaiHooks(parsed.hooks);\n const next: CodexConfigToml = { ...parsed };\n if (cleaned === undefined) {\n delete next.hooks;\n } else {\n next.hooks = cleaned;\n }\n return next;\n}\n\n/**\n * Strip our entries from the Codex config TOML on disk. Returns\n * true when at least one Olakai handler was present (and thus\n * removed); false when there was nothing to do.\n */\nexport function stripCodexHooksConfig(): boolean {\n const configPath = getCodexHomeConfigPath();\n if (!fs.existsSync(configPath)) return false;\n const parsed = readCodexConfigToml(configPath);\n if (!hasOlakaiHooksInstalled(parsed)) return false;\n\n const next = applyOlakaiStripToConfig(parsed);\n writeCodexConfigToml(configPath, next);\n return true;\n}\n\n/**\n * Read a Codex config.toml and parse it. Returns an empty object on\n * any I/O or parse failure — callers proceed as though the user had\n * an empty config so install can still succeed.\n */\nexport function readCodexConfigToml(configPath: string): CodexConfigToml {\n try {\n if (!fs.existsSync(configPath)) return {};\n const raw = fs.readFileSync(configPath, \"utf-8\");\n if (!raw.trim()) return {};\n return TOML.parse(raw) as CodexConfigToml;\n } catch {\n return {};\n }\n}\n\nexport function writeCodexConfigToml(\n configPath: string,\n data: CodexConfigToml,\n): void {\n const dir = path.dirname(configPath);\n if (!fs.existsSync(dir)) {\n fs.mkdirSync(dir, { recursive: true });\n }\n // `@iarna/toml` requires plain JSON-compatible objects. We pass in\n // our typed shape via `as TOML.JsonMap` since the runtime check is\n // limited to value types the library supports (string/number/bool/\n // array/object). Nested arrays-of-tables (hooks) round-trip cleanly.\n const serialized = TOML.stringify(data as TOML.JsonMap);\n fs.writeFileSync(configPath, serialized, \"utf-8\");\n}\n\n// Re-export for tests.\nexport { CODEX_HOOK_TIMEOUT_SECONDS };\n","/**\n * Codex CLI filesystem layout helpers.\n *\n * Codex stores config and per-session rollouts under a single XDG-ish\n * home directory. The paths are documented at\n * https://developers.openai.com/codex/config-reference and have been\n * stable since v0.124.0 (the release that froze the hooks API).\n *\n * Centralizing these here keeps install/uninstall/status/hook in\n * lock-step on which file they're touching.\n */\nimport * as os from \"node:os\";\nimport * as path from \"node:path\";\n\nexport const CODEX_HOME_DIRNAME = \".codex\";\nexport const CODEX_CONFIG_FILENAME = \"config.toml\";\nexport const CODEX_SESSIONS_DIRNAME = \"sessions\";\n\nexport function getCodexHomeDir(): string {\n return path.join(os.homedir(), CODEX_HOME_DIRNAME);\n}\n\nexport function getCodexConfigPath(): string {\n return path.join(getCodexHomeDir(), CODEX_CONFIG_FILENAME);\n}\n\nexport function getCodexSessionsDir(): string {\n return path.join(getCodexHomeDir(), CODEX_SESSIONS_DIRNAME);\n}\n","/**\n * Pure helpers for merging Olakai hook entries into a Codex\n * `~/.codex/config.toml`. Filesystem I/O lives in `install.ts` so these\n * can be unit-tested without touching disk.\n *\n * Codex's `[hooks]` block is a mapping of event name -> list of\n * \"matcher groups\", where each matcher group has its own list of\n * `HookHandlerConfig` records (tagged enum on `type`). The format is\n * documented in `codex-rs/config/src/hook_config.rs`:\n *\n * [[hooks.Stop]]\n * [[hooks.Stop.hooks]]\n * type = \"command\"\n * command = \"olakai monitor hook --tool codex Stop\"\n * timeout = 5\n *\n * `async = true` is intentionally NEVER set — Codex skips async hooks\n * with a warning, and our handler must run synchronously to catch\n * the per-turn data.\n */\n\n/**\n * Substring used to identify Olakai-installed hook commands. Any hook\n * entry whose `command` includes this marker is considered ours and\n * is eligible for stripping during uninstall — this matches BOTH the\n * Stop entries we still install and any legacy UserPromptSubmit\n * entries left over from earlier versions of the CLI.\n */\nexport const OLAKAI_HOOK_MARKER = \"olakai monitor hook\";\n\nexport const CODEX_HOOK_TIMEOUT_SECONDS = 5;\n\n/**\n * Events we register on a fresh install. Stop is the only canonical\n * source — see `hook.ts` for why UserPromptSubmit is no longer in\n * this list. Existing `~/.codex/config.toml` files that still have a\n * UserPromptSubmit entry will continue to fire it; the adapter\n * silent-exits, and the next `olakai monitor init --tool codex` run\n * (or any uninstall) will strip it via `OLAKAI_HOOK_MARKER`.\n */\nexport const SUPPORTED_HOOK_EVENT_NAMES = [\"Stop\"] as const;\n\n/**\n * Type-level superset that includes legacy event names we may still\n * encounter in user config files even though we don't install them\n * anymore. Used by the strip / status code paths so they can still\n * recognize and clean up legacy entries.\n */\nexport type SupportedHookEventName = \"Stop\" | \"UserPromptSubmit\";\n\nexport interface CodexHookHandler {\n type: \"command\" | \"prompt\" | \"agent\";\n command?: string;\n timeout?: number;\n /** Codex skips async handlers with a warning — we must never set this. */\n async?: boolean;\n statusMessage?: string;\n [key: string]: unknown;\n}\n\nexport interface CodexMatcherGroup {\n matcher?: string;\n hooks?: CodexHookHandler[];\n}\n\nexport type CodexHooksBlock = Partial<\n Record<SupportedHookEventName | string, CodexMatcherGroup[]>\n>;\n\nexport interface CodexConfigToml {\n hooks?: CodexHooksBlock;\n [key: string]: unknown;\n}\n\n/**\n * Build the canonical Olakai hook entry for a given event. Kept as a\n * function (not a constant) so tests can compare against the same\n * shape the installer writes.\n */\nexport function buildOlakaiHookGroup(\n event: SupportedHookEventName,\n): CodexMatcherGroup {\n return {\n hooks: [\n {\n type: \"command\",\n command: `olakai monitor hook --tool codex ${event}`,\n timeout: CODEX_HOOK_TIMEOUT_SECONDS,\n },\n ],\n };\n}\n\nfunction isOlakaiHandler(handler: CodexHookHandler): boolean {\n return (\n typeof handler.command === \"string\" &&\n handler.command.includes(OLAKAI_HOOK_MARKER)\n );\n}\n\nfunction groupContainsOlakaiHandler(group: CodexMatcherGroup): boolean {\n if (!Array.isArray(group.hooks)) return false;\n return group.hooks.some(isOlakaiHandler);\n}\n\n/**\n * Layer Olakai hook entries onto an existing `[hooks]` block.\n *\n * - Existing user entries on other events are preserved untouched.\n * - Existing user entries on Stop / UserPromptSubmit are preserved;\n * we append our matcher group only when no Olakai-marked handler\n * already exists (idempotent re-init).\n * - Existing Olakai-marked handlers are left exactly as written so\n * user customizations (e.g. a tweaked timeout) survive re-init.\n */\nexport function mergeCodexHooks(\n existing: CodexHooksBlock | undefined,\n events: readonly SupportedHookEventName[] = SUPPORTED_HOOK_EVENT_NAMES,\n): CodexHooksBlock {\n const merged: CodexHooksBlock = { ...(existing ?? {}) };\n\n for (const event of events) {\n const existingGroups = merged[event] ?? [];\n const hasOlakaiHook = existingGroups.some(groupContainsOlakaiHandler);\n if (hasOlakaiHook) {\n merged[event] = existingGroups;\n } else {\n merged[event] = [...existingGroups, buildOlakaiHookGroup(event)];\n }\n }\n\n return merged;\n}\n\n/**\n * Strip Olakai-installed entries from an existing `[hooks]` block.\n * Returns the cleaned block or `undefined` when no event keys remain\n * (so the caller can omit `[hooks]` entirely from the rewritten file).\n *\n * Within a matcher group we drop only the Olakai-marked handlers,\n * not the entire group — a user might have appended their own\n * `command` to the same group and we must preserve theirs.\n */\nexport function stripOlakaiHooks(\n existing: CodexHooksBlock | undefined,\n): CodexHooksBlock | undefined {\n if (!existing) return undefined;\n const cleaned: CodexHooksBlock = {};\n for (const [event, groups] of Object.entries(existing)) {\n if (!Array.isArray(groups)) continue;\n const filteredGroups: CodexMatcherGroup[] = [];\n for (const group of groups) {\n const handlers = Array.isArray(group.hooks) ? group.hooks : [];\n const remaining = handlers.filter((h) => !isOlakaiHandler(h));\n if (remaining.length === 0 && handlers.length > 0) {\n // Group existed only to host an Olakai hook -> drop the group.\n continue;\n }\n if (remaining.length === handlers.length) {\n // Nothing of ours in this group -> keep verbatim.\n filteredGroups.push(group);\n } else {\n filteredGroups.push({ ...group, hooks: remaining });\n }\n }\n if (filteredGroups.length > 0) {\n cleaned[event] = filteredGroups;\n }\n }\n return Object.keys(cleaned).length > 0 ? cleaned : undefined;\n}\n\n/**\n * Whether the parsed TOML contains at least one Olakai-marked handler\n * across any event. Used by `status` to surface \"hooks active\".\n */\nexport function hasOlakaiHooksInstalled(parsed: CodexConfigToml): boolean {\n const hooks = parsed.hooks;\n if (!hooks) return false;\n for (const groups of Object.values(hooks)) {\n if (!Array.isArray(groups)) continue;\n for (const group of groups) {\n if (groupContainsOlakaiHandler(group)) return true;\n }\n }\n return false;\n}\n","/**\n * Per-tool monitor config for Codex. Lives at\n * `.olakai/monitor-codex.json` next to other tools' configs.\n *\n * Mirrors the Claude Code shape so the dispatcher and any future\n * \"show all tools\" command can treat the file uniformly.\n */\nimport * as fs from \"node:fs\";\nimport * as path from \"node:path\";\nimport {\n getMonitorConfigPath as resolveMonitorConfigPath,\n getOlakaiDir,\n} from \"../../paths.js\";\n\nexport interface CodexMonitorConfig {\n agentId: string;\n apiKey: string;\n agentName: string;\n source: string;\n createdAt: string;\n monitoringEndpoint: string;\n}\n\nexport function getCodexConfigPath(projectRoot: string): string {\n return resolveMonitorConfigPath(projectRoot, \"codex\");\n}\n\nexport function loadCodexConfig(\n projectRoot: string,\n): CodexMonitorConfig | null {\n const filePath = getCodexConfigPath(projectRoot);\n try {\n if (!fs.existsSync(filePath)) return null;\n const raw = fs.readFileSync(filePath, \"utf-8\");\n return JSON.parse(raw) as CodexMonitorConfig;\n } catch {\n return null;\n }\n}\n\nexport function writeCodexConfig(\n projectRoot: string,\n config: CodexMonitorConfig,\n): void {\n const filePath = getCodexConfigPath(projectRoot);\n const dir = path.dirname(filePath);\n if (!fs.existsSync(dir)) {\n fs.mkdirSync(dir, { recursive: true });\n }\n fs.writeFileSync(filePath, JSON.stringify(config, null, 2) + \"\\n\", \"utf-8\");\n try {\n fs.chmodSync(filePath, 0o600);\n } catch {\n // Non-fatal on Windows / unusual filesystems\n }\n}\n\nexport function deleteCodexConfig(projectRoot: string): boolean {\n const filePath = getCodexConfigPath(projectRoot);\n if (!fs.existsSync(filePath)) return false;\n try {\n fs.unlinkSync(filePath);\n return true;\n } catch {\n return false;\n }\n}\n\nexport function getCodexConfigDir(projectRoot: string): string {\n return getOlakaiDir(projectRoot);\n}\n","/**\n * Status reporter for the Codex plugin. Mirrors the Claude Code\n * status output: per-tool config metadata + a hint when the global\n * Codex config is missing the Olakai hook entries (e.g. when the user\n * edited config.toml manually since `init`).\n */\nimport path from \"node:path\";\nimport * as fs from \"node:fs\";\nimport type { StatusReport } from \"../../plugin.js\";\nimport { getValidToken } from \"../../../lib/auth.js\";\nimport { getBaseUrl } from \"../../../lib/config.js\";\nimport {\n CODEX_CONFIG_FILENAME,\n CODEX_HOME_DIRNAME,\n getCodexConfigPath as getCodexHomeConfigPath,\n} from \"./paths.js\";\nimport { hasOlakaiHooksInstalled } from \"./hooks.js\";\nimport { readCodexConfigToml } from \"./install.js\";\nimport {\n getCodexConfigPath as getCodexMonitorConfigPath,\n loadCodexConfig,\n} from \"./config.js\";\n\nexport async function getCodexStatus(opts?: {\n projectRoot?: string;\n}): Promise<StatusReport> {\n const projectRoot = opts?.projectRoot ?? process.cwd();\n const configPath = getCodexMonitorConfigPath(projectRoot);\n const config = loadCodexConfig(projectRoot);\n\n const hooksConfigured = isHooksBlockInstalled();\n\n if (!config) {\n return {\n toolId: \"codex\",\n configured: false,\n hooksConfigured,\n configPath,\n notes: hooksConfigured\n ? [\n `Codex hooks present in ~/${CODEX_HOME_DIRNAME}/${CODEX_CONFIG_FILENAME} but no monitor config in this workspace — re-run init.`,\n ]\n : [],\n };\n }\n\n return {\n toolId: \"codex\",\n configured: true,\n hooksConfigured,\n agentId: config.agentId,\n agentName: config.agentName,\n source: config.source,\n apiKeyMasked: config.apiKey.slice(0, 12) + \"...\",\n monitoringEndpoint: config.monitoringEndpoint,\n configuredAt: config.createdAt,\n configPath,\n };\n}\n\nfunction isHooksBlockInstalled(): boolean {\n const homeConfig = getCodexHomeConfigPath();\n if (!fs.existsSync(homeConfig)) return false;\n const parsed = readCodexConfigToml(homeConfig);\n return hasOlakaiHooksInstalled(parsed);\n}\n\n/**\n * Pretty printer used by the dispatcher in non-JSON mode. Mirrors\n * `printClaudeCodeStatus` so the two tools render consistently.\n */\nexport async function printCodexStatus(opts?: {\n projectRoot?: string;\n}): Promise<void> {\n const projectRoot = opts?.projectRoot ?? process.cwd();\n const status = await getCodexStatus({ projectRoot });\n\n if (!status.configured) {\n console.log(\"Codex monitoring is not configured for this workspace.\");\n console.log(\n \"Run 'olakai monitor init --tool codex' to set up monitoring.\",\n );\n if (status.notes && status.notes.length > 0) {\n for (const note of status.notes) {\n console.log(note);\n }\n }\n process.exit(1);\n }\n\n const configRel = status.configPath\n ? path.relative(projectRoot, status.configPath)\n : \"(unknown)\";\n\n console.log(\"Olakai Monitor Status (Codex CLI)\");\n console.log(\"=================================\");\n console.log(`Agent: ${status.agentName}`);\n console.log(`Agent ID: ${status.agentId}`);\n console.log(`API Key: ${status.apiKeyMasked}`);\n console.log(`Endpoint: ${status.monitoringEndpoint}`);\n console.log(`Source: ${status.source}`);\n console.log(`Configured: ${status.configuredAt}`);\n console.log(`Config file: ${configRel}`);\n console.log(\n `Hooks: ${\n status.hooksConfigured\n ? \"Active\"\n : `Missing (re-run 'olakai monitor init --tool codex')`\n }`,\n );\n\n try {\n const token = getValidToken();\n if (token && status.agentId) {\n const params = new URLSearchParams({\n agentId: status.agentId,\n limit: \"5\",\n });\n const response = await fetch(\n `${getBaseUrl()}/api/activity/prompts?${params}`,\n {\n headers: { Authorization: `Bearer ${token}` },\n },\n );\n if (response.ok) {\n const data = (await response.json()) as {\n prompts: Array<{ id: string; createdAt: string }>;\n };\n if (data.prompts && data.prompts.length > 0) {\n console.log(\"\");\n console.log(\"Recent Activity:\");\n for (const p of data.prompts) {\n console.log(` ${p.createdAt} ${p.id.slice(0, 12)}...`);\n }\n } else {\n console.log(\"\");\n console.log(\"No activity recorded yet.\");\n }\n }\n }\n } catch {\n // Activity check is optional — never fail status on it\n }\n}\n","/**\n * Codex rollout JSONL reader.\n *\n * A Codex session rollout lives at one of:\n * - `~/.codex/sessions/YYYY/MM/DD/rollout-YYYY-MM-DDThh-mm-ss-<uuid>.jsonl`\n * (production layout, since the date-bucketed reorg in v0.124.0)\n * - `~/.codex/sessions/rollout-...-<uuid>.jsonl`\n * (legacy flat layout — kept for back-compat with old Codex builds)\n *\n * Test fixtures mirror the production layout under\n * `tests/fixtures/codex/sessions/YYYY/MM/DD/rollout-...jsonl` so the\n * walker is exercised the same way it is at runtime.\n *\n * We resolve the file by suffix-matching on `<session_id>.jsonl` so we\n * don't have to know which layout the user's Codex emits. The walker\n * is bounded to a small recent slice — the Stop hook fires within\n * milliseconds of the session writing the rollout, so the relevant\n * file is virtually always the newest match.\n *\n * Each line is a `RolloutLine` (`{ timestamp, type, payload }`) that\n * unwraps into one of: `session_meta`, `response_item`, `event_msg`,\n * `compacted`, `turn_context`. We read the file lazily, defensively\n * tolerate malformed lines, and return a best-effort\n * `ExtractedRollout` even when fields are missing or unrecognized.\n */\nimport * as fs from \"node:fs\";\nimport * as path from \"node:path\";\nimport {\n CODEX_SESSIONS_DIRNAME,\n getCodexHomeDir,\n getCodexSessionsDir,\n} from \"./paths.js\";\n\nexport interface ExtractedRollout {\n prompt: string;\n response: string;\n modelName: string | null;\n inputTokens: number;\n outputTokens: number;\n cachedInputTokens: number;\n reasoningOutputTokens: number;\n tokens: number;\n numTurns: number;\n /**\n * Path of the rollout file we loaded the data from, if any. Useful\n * for surfacing in customData for debugging and for status checks.\n */\n rolloutPath?: string;\n}\n\nexport function emptyRollout(): ExtractedRollout {\n return {\n prompt: \"\",\n response: \"\",\n modelName: null,\n inputTokens: 0,\n outputTokens: 0,\n cachedInputTokens: 0,\n reasoningOutputTokens: 0,\n tokens: 0,\n numTurns: 0,\n };\n}\n\ntype DebugLogger = (label: string, data: unknown) => void;\nconst noopDebug: DebugLogger = () => {};\n\ninterface RolloutScanLimits {\n /** Cap on directories scanned during the search. Hard-bounds the walk. */\n maxDirs?: number;\n /** Cap on files visited during the search. */\n maxFiles?: number;\n}\n\nconst DEFAULT_LIMITS: Required<RolloutScanLimits> = {\n maxDirs: 200,\n maxFiles: 5000,\n};\n\n/**\n * Locate the rollout JSONL for a given Codex `session_id`. Returns\n * null when nothing matches (caller should treat as \"no transcript\n * available yet\"). Search is breadth-first over the (small) set of\n * date directories Codex writes; bounded by the limits above to\n * avoid pathological scans on a long-running install.\n */\nexport function findRolloutPathForSession(\n sessionId: string,\n sessionsDir: string = getCodexSessionsDir(),\n limits: RolloutScanLimits = {},\n): string | null {\n const merged = { ...DEFAULT_LIMITS, ...limits };\n if (!sessionId) return null;\n if (!fs.existsSync(sessionsDir)) return null;\n\n const suffix = `-${sessionId}.jsonl`;\n const matches: { path: string; mtimeMs: number }[] = [];\n let dirsScanned = 0;\n let filesScanned = 0;\n\n const queue: string[] = [sessionsDir];\n while (queue.length > 0) {\n const dir = queue.shift()!;\n if (dirsScanned++ > merged.maxDirs) break;\n\n let entries: fs.Dirent[];\n try {\n entries = fs.readdirSync(dir, { withFileTypes: true });\n } catch {\n continue;\n }\n\n for (const entry of entries) {\n if (filesScanned++ > merged.maxFiles) break;\n const full = path.join(dir, entry.name);\n if (entry.isDirectory()) {\n queue.push(full);\n continue;\n }\n if (!entry.isFile()) continue;\n if (!entry.name.endsWith(suffix)) continue;\n if (!entry.name.startsWith(\"rollout-\")) continue;\n try {\n const stat = fs.statSync(full);\n matches.push({ path: full, mtimeMs: stat.mtimeMs });\n } catch {\n // ignore\n }\n }\n }\n\n if (matches.length === 0) return null;\n // Pick the freshest file — multiple matches can occur during\n // forks/resumes; the active session is always the most recent.\n matches.sort((a, b) => b.mtimeMs - a.mtimeMs);\n return matches[0].path;\n}\n\ninterface RolloutLine {\n timestamp?: string;\n type?: string;\n payload?: unknown;\n}\n\ninterface SessionMetaPayload {\n id?: unknown;\n cwd?: unknown;\n timestamp?: unknown;\n cli_version?: unknown;\n // SessionMeta is flattened into the line in older Codex builds — we\n // also accept inline fields when `payload` is missing.\n}\n\ninterface EventMsgPayload {\n type?: string;\n message?: string;\n info?: {\n last_token_usage?: TokenUsage;\n total_token_usage?: TokenUsage;\n };\n model?: string;\n}\n\ninterface TokenUsage {\n input_tokens?: number;\n cached_input_tokens?: number;\n output_tokens?: number;\n reasoning_output_tokens?: number;\n total_tokens?: number;\n}\n\ninterface ResponseItemPayload {\n type?: string;\n role?: string;\n content?: Array<{ type?: string; text?: string }>;\n}\n\n/**\n * Parse the raw bytes of a Codex rollout JSONL file into an\n * `ExtractedRollout`. Pure — no filesystem I/O — so it can be unit\n * tested directly. Malformed JSONL lines are skipped, not thrown.\n */\nexport function parseRolloutContent(\n raw: string,\n debugLog: DebugLogger = noopDebug,\n): ExtractedRollout {\n const result = emptyRollout();\n if (!raw) return result;\n\n const lines = raw.split(\"\\n\");\n let lastUserMessage = \"\";\n let lastAssistantMessage = \"\";\n let lastTokenUsage: TokenUsage | null = null;\n let totalTokenUsage: TokenUsage | null = null;\n let modelName: string | null = null;\n let userTurnCount = 0;\n\n for (const line of lines) {\n const trimmed = line.trim();\n if (!trimmed) continue;\n let parsed: RolloutLine;\n try {\n parsed = JSON.parse(trimmed) as RolloutLine;\n } catch (err) {\n debugLog(\"rollout-line-parse-failed\", {\n line: trimmed.slice(0, 120),\n error: (err as Error).message,\n });\n continue;\n }\n\n const type = parsed.type;\n const payload = parsed.payload as\n | EventMsgPayload\n | ResponseItemPayload\n | SessionMetaPayload\n | undefined;\n if (!type || !payload) continue;\n\n if (type === \"session_meta\") {\n // Older builds flattened SessionMeta directly into the line; if\n // we ever see a model name there, capture it as a fallback.\n continue;\n }\n\n if (type === \"event_msg\") {\n const ev = payload as EventMsgPayload;\n const evType = ev.type;\n if (evType === \"user_message\" && typeof ev.message === \"string\") {\n lastUserMessage = ev.message;\n userTurnCount += 1;\n } else if (evType === \"agent_message\" && typeof ev.message === \"string\") {\n lastAssistantMessage = ev.message;\n } else if (evType === \"token_count\" && ev.info) {\n if (ev.info.last_token_usage) {\n lastTokenUsage = ev.info.last_token_usage;\n }\n if (ev.info.total_token_usage) {\n totalTokenUsage = ev.info.total_token_usage;\n }\n } else if (\n evType === \"session_configured\" &&\n typeof ev.model === \"string\" &&\n ev.model\n ) {\n modelName = ev.model;\n }\n continue;\n }\n\n if (type === \"response_item\") {\n const ri = payload as ResponseItemPayload;\n if (ri.type === \"message\" && Array.isArray(ri.content)) {\n const text = extractTextFromContent(ri.content);\n if (!text) continue;\n if (ri.role === \"user\") {\n lastUserMessage = text;\n userTurnCount += 1;\n } else if (ri.role === \"assistant\") {\n lastAssistantMessage = text;\n }\n }\n continue;\n }\n // Unknown type — ignore silently. Codex may add new RolloutItem\n // variants; we don't want to throw on encounter.\n }\n\n result.prompt = lastUserMessage;\n result.response = lastAssistantMessage;\n result.modelName = modelName;\n result.numTurns = userTurnCount;\n\n // Prefer last_token_usage for per-turn metrics — it represents the\n // most recent model call. Total is a session running sum and is too\n // coarse for a single MonitoringPayload.\n const tokenSource = lastTokenUsage ?? totalTokenUsage;\n if (tokenSource) {\n result.inputTokens = numberOrZero(tokenSource.input_tokens);\n result.outputTokens = numberOrZero(tokenSource.output_tokens);\n result.cachedInputTokens = numberOrZero(tokenSource.cached_input_tokens);\n result.reasoningOutputTokens = numberOrZero(\n tokenSource.reasoning_output_tokens,\n );\n result.tokens =\n numberOrZero(tokenSource.total_tokens) ||\n result.inputTokens + result.outputTokens;\n }\n\n return result;\n}\n\nfunction extractTextFromContent(\n content: Array<{ type?: string; text?: string }>,\n): string {\n const parts: string[] = [];\n for (const block of content) {\n if (typeof block.text !== \"string\") continue;\n if (\n block.type === \"output_text\" ||\n block.type === \"input_text\" ||\n block.type === \"text\"\n ) {\n parts.push(block.text);\n }\n }\n return parts.join(\"\\n\").trim();\n}\n\nfunction numberOrZero(value: unknown): number {\n return typeof value === \"number\" && Number.isFinite(value) ? value : 0;\n}\n\n/**\n * Read the rollout JSONL for `sessionId` from disk and parse it. Any\n * I/O or parse failure returns an empty result; the caller (hook\n * adapter) treats that as \"no transcript yet\" and falls back to the\n * inline payload fields where possible.\n */\nexport function loadRolloutForSession(\n sessionId: string,\n options: { sessionsDir?: string; debugLog?: DebugLogger } = {},\n): ExtractedRollout {\n const debugLog = options.debugLog ?? noopDebug;\n const sessionsDir = options.sessionsDir ?? getCodexSessionsDir();\n const result = emptyRollout();\n\n const rolloutPath = findRolloutPathForSession(sessionId, sessionsDir);\n if (!rolloutPath) {\n debugLog(\"rollout-not-found\", {\n sessionId,\n sessionsDir,\n });\n return result;\n }\n\n let raw: string;\n try {\n raw = fs.readFileSync(rolloutPath, \"utf-8\");\n } catch (err) {\n debugLog(\"rollout-read-failed\", {\n rolloutPath,\n error: (err as Error).message,\n });\n return result;\n }\n\n const parsed = parseRolloutContent(raw, debugLog);\n parsed.rolloutPath = rolloutPath;\n return parsed;\n}\n\n/**\n * Test/debug entry point that mirrors `loadRolloutForSession` but\n * skips the codex-home lookup so callers can drop in a synthetic\n * rollout file. Exported so tests don't need to monkey-patch\n * `os.homedir()`.\n */\nexport function loadRolloutFromPath(\n rolloutPath: string,\n debugLog: DebugLogger = noopDebug,\n): ExtractedRollout {\n const result = emptyRollout();\n let raw: string;\n try {\n raw = fs.readFileSync(rolloutPath, \"utf-8\");\n } catch (err) {\n debugLog(\"rollout-read-failed\", {\n rolloutPath,\n error: (err as Error).message,\n });\n return result;\n }\n const parsed = parseRolloutContent(raw, debugLog);\n parsed.rolloutPath = rolloutPath;\n return parsed;\n}\n\n// Re-exports so consumers can grab the codex paths without a separate\n// import line in the tight modules that already import this one.\nexport { CODEX_SESSIONS_DIRNAME, getCodexHomeDir };\n","/**\n * Codex hook payload adapter. Two pure builders + one effectful\n * `handleCodexHook` that the plugin's `handleHook` method delegates to.\n *\n * The split mirrors the Claude Code adapter so tests can drive the\n * builders without touching the filesystem. Filesystem access (rollout\n * lookup, dedup state) lives in `handleCodexHook` and is exercised\n * via integration-style tests where a synthetic rollout file is laid\n * down ahead of time.\n *\n * Codex hook events the v1 plugin handles:\n * - `Stop` — final response per turn (canonical capture\n * via the rollout JSONL: prompt + response +\n * tokens for the turn)\n * - `UserPromptSubmit` — RECOGNIZED but always silent-exits. Codex\n * fires this pre-LLM with the prompt only;\n * emitting a response-less event creates a\n * duplicate that double-counts the per-event\n * cost baseline downstream. The paired Stop\n * event already includes the prompt from the\n * rollout, so UserPromptSubmit is pure noise.\n * Kept in the supported set so legacy\n * installs (which still register a hook\n * pointing at us) don't error out — we just\n * drop the event on the floor.\n *\n * Other event names (`PreToolUse`, `PostToolUse`, `SessionStart`,\n * `PermissionRequest`) silent-exit at the plugin layer (return null).\n *\n * The handler MUST run synchronously: Codex skips `async = true` hook\n * handlers with a warning, and the per-turn capture window is short.\n */\nimport type { MonitoringPayload } from \"../../plugin.js\";\nimport type { CodexMonitorConfig } from \"./config.js\";\nimport {\n emptyRollout,\n loadRolloutForSession,\n type ExtractedRollout,\n} from \"./transcript.js\";\n\n/**\n * Codex hook event payload — superset of fields seen across Stop /\n * UserPromptSubmit. Loose typing because the schema only stabilized\n * in v0.124.0 and we need to tolerate fields shifting between\n * patches. Per D-003: parse defensively.\n *\n * NOTE: `prompt` is still typed here for completeness even though\n * `UserPromptSubmit` is silent-exited at the handler layer. Tests and\n * legacy callers may still construct payloads with this field.\n */\nexport interface CodexHookEvent {\n hook_event_name?: string;\n session_id?: string;\n cwd?: string;\n model?: string;\n permission_mode?: string;\n transcript_path?: string | null;\n turn_id?: string;\n /** UserPromptSubmit only — currently dropped (see file header). */\n prompt?: string;\n /** Stop only. May be null when the assistant produced no text. */\n last_assistant_message?: string | null;\n /** Stop only. */\n stop_hook_active?: boolean;\n}\n\nexport type DebugLogger = (label: string, data: unknown) => void;\nconst noopDebug: DebugLogger = () => {};\n\n/**\n * Hook events Codex emits that we register handlers for. Compared\n * case-insensitively because Codex uses PascalCase and shell scripts\n * occasionally typo casing.\n */\nconst SUPPORTED_EVENTS = new Set([\"Stop\", \"UserPromptSubmit\"]);\n\nexport function isSupportedCodexEvent(eventName: string): boolean {\n return SUPPORTED_EVENTS.has(eventName);\n}\n\n/**\n * Build a canonical MonitoringPayload from a parsed Codex hook\n * payload + rollout extract + per-tool monitor config. Pure function;\n * no I/O. Returns null for events we don't handle.\n *\n * `UserPromptSubmit` always returns null here: the rollout-based\n * `Stop` capture is the canonical source of a turn's prompt + response,\n * and emitting a pre-LLM event with no response creates a duplicate\n * monitoring record that double-counts the per-event cost baseline.\n */\nexport function buildCodexPayload(\n eventName: string,\n eventData: CodexHookEvent,\n config: CodexMonitorConfig,\n rollout: ExtractedRollout = emptyRollout(),\n): MonitoringPayload | null {\n if (!isSupportedCodexEvent(eventName)) return null;\n // UserPromptSubmit is recognized (legacy installs still register it)\n // but produces no payload — see file header.\n if (eventName === \"UserPromptSubmit\") return null;\n\n const sessionId =\n typeof eventData.session_id === \"string\" && eventData.session_id\n ? eventData.session_id\n : `codex-${Date.now()}`;\n\n const cwd = typeof eventData.cwd === \"string\" ? eventData.cwd : \"\";\n const turnId =\n typeof eventData.turn_id === \"string\" ? eventData.turn_id : \"\";\n const permissionMode =\n typeof eventData.permission_mode === \"string\"\n ? eventData.permission_mode\n : \"\";\n const transcriptPath =\n typeof eventData.transcript_path === \"string\"\n ? eventData.transcript_path\n : \"\";\n\n // Model name preference: hook payload first (always present per\n // schema), then rollout fallback. The hook value is what Codex\n // *intends* to use for this turn; the rollout reflects what was\n // actually configured at session start.\n const modelName =\n (typeof eventData.model === \"string\" && eventData.model.trim()\n ? eventData.model\n : null) ?? rollout.modelName;\n\n const customData: Record<string, unknown> = {\n hookEvent: eventData.hook_event_name ?? eventName,\n sessionId,\n cwd,\n turnId,\n permissionMode,\n transcriptPath,\n inputTokens: rollout.inputTokens,\n outputTokens: rollout.outputTokens,\n cachedInputTokens: rollout.cachedInputTokens,\n reasoningOutputTokens: rollout.reasoningOutputTokens,\n numTurns: rollout.numTurns,\n };\n\n if (rollout.rolloutPath) {\n customData.rolloutPath = rollout.rolloutPath;\n }\n if (typeof eventData.stop_hook_active === \"boolean\") {\n customData.stopHookActive = eventData.stop_hook_active;\n }\n\n // Stop event\n const inlineAssistant =\n typeof eventData.last_assistant_message === \"string\" &&\n eventData.last_assistant_message.trim()\n ? eventData.last_assistant_message\n : \"\";\n const response = inlineAssistant || rollout.response;\n\n return {\n prompt: rollout.prompt,\n response,\n chatId: sessionId,\n source: config.source,\n modelName: modelName ?? undefined,\n tokens: rollout.tokens,\n customData,\n };\n}\n\n/**\n * Effectful handler: parse stdin payload, look up the rollout, and\n * build the canonical payload. Returns null when the event is not one\n * we handle, the payload doesn't carry a session_id, or the rollout\n * lookup yields nothing for a Stop event without an inline assistant\n * message (i.e. nothing to report).\n *\n * `UserPromptSubmit` is silent-exited here regardless of payload: the\n * Stop event captures the full turn (prompt + response + tokens) from\n * the rollout JSONL, and a pre-LLM emit creates a duplicate event\n * downstream that has no response and double-counts the per-event\n * cost baseline.\n */\nexport function handleCodexHook(\n eventName: string,\n payloadJson: unknown,\n config: CodexMonitorConfig,\n options: { debugLog?: DebugLogger; sessionsDir?: string } = {},\n): MonitoringPayload | null {\n const debugLog = options.debugLog ?? noopDebug;\n if (!isSupportedCodexEvent(eventName)) {\n debugLog(\"hook-unknown-event\", eventName);\n return null;\n }\n\n // Silent-exit UserPromptSubmit: rollout-driven Stop is the canonical\n // capture; emitting here would produce a duplicate, response-less\n // event and double-count cost downstream. Legacy installs may still\n // register this hook; we accept the call and drop it on the floor.\n if (eventName === \"UserPromptSubmit\") {\n debugLog(\"user-prompt-submit-dropped\", { eventName });\n return null;\n }\n\n const eventData = (payloadJson ?? {}) as CodexHookEvent;\n debugLog(\"event-parsed\", { eventName, eventData });\n\n const sessionId =\n typeof eventData.session_id === \"string\" ? eventData.session_id : \"\";\n\n let rollout = emptyRollout();\n if (eventName === \"Stop\" && sessionId) {\n rollout = loadRolloutForSession(sessionId, {\n debugLog,\n sessionsDir: options.sessionsDir,\n });\n }\n\n const payload = buildCodexPayload(eventName, eventData, config, rollout);\n if (!payload) return null;\n\n // For Stop: a payload with no prompt AND no response is noise — no\n // reason to send it.\n if (!payload.prompt && !payload.response) {\n debugLog(\"payload-empty\", { eventName, sessionId });\n return null;\n }\n\n debugLog(\"payload-built\", payload);\n return payload;\n}\n","/**\n * Cursor plugin (D-005 source = \"cursor\"). Per D-004, this stage\n * supports per-user install only (`~/.cursor/hooks.json`); system-wide\n * enterprise install is deferred to Stage 4.5.\n *\n * Contract: implements `ToolMonitorPlugin` against the canonical\n * MonitoringPayload shape. The hook adapter pairs `beforeSubmitPrompt`\n * + `afterAgentResponse` across separate CLI invocations via the\n * pairing-state sidecar in `pairing-state.ts`.\n */\nimport * as fs from \"node:fs\";\nimport * as os from \"node:os\";\nimport {\n registerPlugin,\n type HookResult,\n type InstallOpts,\n type InstallResult,\n type StatusReport,\n type ToolMonitorPlugin,\n type UninstallOpts,\n} from \"../../plugin.js\";\nimport { findConfiguredWorkspace } from \"../../paths.js\";\nimport { installCursor, uninstallCursor } from \"./install.js\";\nimport { getCursorStatus } from \"./status.js\";\nimport { loadCursorConfig } from \"./config.js\";\nimport { getCursorUserDir } from \"./paths.js\";\nimport {\n buildOrphanPayload,\n buildPairedPayload,\n collectUnknownFields,\n extractAttachments,\n extractCursorMeta,\n extractCursorTokens,\n extractPromptText,\n extractResponseText,\n normalizeEventName,\n type CursorHookPayload,\n} from \"./hook.js\";\nimport {\n clearPendingPrompt,\n listPendingPrompts,\n stashPendingPrompt,\n takePendingPrompt,\n} from \"./pairing-state.js\";\n\nconst TOOL_ID = \"cursor\" as const;\n\n/**\n * Debug logger. Mirrors the Claude Code plugin: writes only when\n * OLAKAI_MONITOR_DEBUG=1, never throws. Useful for diagnosing beta\n * payload-shape changes without polluting Cursor's UI.\n */\nfunction debugLog(label: string, data: unknown): void {\n if (process.env.OLAKAI_MONITOR_DEBUG !== \"1\") return;\n try {\n const logPath = `/tmp/olakai-monitor-debug-${process.pid}.log`;\n const line = `[${new Date().toISOString()}] cursor:${label}: ${\n typeof data === \"string\" ? data : JSON.stringify(data, null, 2)\n }\\n`;\n fs.appendFileSync(logPath, line, \"utf-8\");\n } catch {\n // ignore\n }\n}\n\n/**\n * Resolve the configured project root for a Cursor hook event. Cursor's\n * payload exposes `workspace_roots` (an array) — we walk ancestors of\n * each candidate looking for an `.olakai/monitor-cursor.json` file.\n * Falls back to `process.cwd()` if the payload omits workspace_roots.\n *\n * Exported for unit tests.\n */\nexport function resolveCursorProjectRoot(\n payload: CursorHookPayload,\n fallbackCwd: string = process.cwd(),\n): string | null {\n const roots = Array.isArray(payload.workspace_roots)\n ? payload.workspace_roots.filter(\n (r): r is string => typeof r === \"string\" && r.trim().length > 0,\n )\n : [];\n const candidates = roots.length > 0 ? roots : [fallbackCwd];\n for (const candidate of candidates) {\n const found = findConfiguredWorkspace(candidate, [TOOL_ID]);\n if (found) return found;\n }\n return null;\n}\n\ninterface HandleHookOpts {\n projectRoot?: string;\n /** Override `~` for tests. */\n homeDir?: string;\n}\n\n/**\n * Plugin's `handleHook` implementation. Public so tests can call it\n * directly with custom homeDir.\n */\nexport async function handleCursorHook(\n eventName: string,\n payloadJson: unknown,\n opts: HandleHookOpts = {},\n): Promise<HookResult | null> {\n const event = normalizeEventName(eventName);\n if (!event) {\n debugLog(\"hook-unknown-event\", eventName);\n return null;\n }\n\n const payload =\n payloadJson && typeof payloadJson === \"object\"\n ? (payloadJson as CursorHookPayload)\n : ({} as CursorHookPayload);\n debugLog(\"event-parsed\", { event, payload });\n\n const meta = extractCursorMeta(payload);\n const homeDir = opts.homeDir ?? os.homedir();\n\n switch (event) {\n case \"beforeSubmitPrompt\": {\n if (!meta.conversationId) {\n debugLog(\"missing-conversation-id\", { event });\n return null;\n }\n stashPendingPrompt(\n {\n prompt: extractPromptText(payload),\n userEmail: meta.userEmail,\n model: meta.model,\n cursorVersion: meta.cursorVersion,\n conversationId: meta.conversationId,\n generationId: meta.generationId,\n workspaceRoots: meta.workspaceRoots,\n transcriptPath: meta.transcriptPath,\n attachments: extractAttachments(payload),\n stashedAt: new Date().toISOString(),\n extra: collectUnknownFields(payload),\n },\n homeDir,\n );\n // Stash-only path emits no event yet — waits for afterAgentResponse.\n return null;\n }\n\n case \"afterAgentResponse\": {\n if (!meta.conversationId) {\n debugLog(\"missing-conversation-id\", { event });\n return null;\n }\n const projectRoot = resolveCursorProjectRoot(\n payload,\n opts.projectRoot ?? process.cwd(),\n );\n if (!projectRoot) {\n debugLog(\"config-not-found\", {\n workspaceRoots: meta.workspaceRoots,\n fallbackCwd: opts.projectRoot ?? process.cwd(),\n });\n // Still consume the stashed prompt so we don't leak files.\n takePendingPrompt(meta.conversationId, meta.generationId, homeDir);\n return null;\n }\n\n const config = loadCursorConfig(projectRoot);\n if (!config) {\n debugLog(\"config-load-failed\", { projectRoot });\n takePendingPrompt(meta.conversationId, meta.generationId, homeDir);\n return null;\n }\n\n const stashed = takePendingPrompt(\n meta.conversationId,\n meta.generationId,\n homeDir,\n );\n\n const responseText = extractResponseText(payload);\n const promptText = stashed?.prompt ?? extractPromptText(payload);\n const userEmail = meta.userEmail ?? stashed?.userEmail;\n const model = meta.model ?? stashed?.model;\n const cursorVersion = meta.cursorVersion ?? stashed?.cursorVersion;\n const workspaceRoots = meta.workspaceRoots ?? stashed?.workspaceRoots;\n const transcriptPath = meta.transcriptPath ?? stashed?.transcriptPath;\n const attachments =\n extractAttachments(payload) ?? stashed?.attachments;\n const tokens = extractCursorTokens(payload);\n const unknownFields = mergeUnknownFields(\n collectUnknownFields(payload),\n stashed?.extra,\n );\n\n const built = buildPairedPayload(\n {\n conversationId: meta.conversationId,\n generationId: meta.generationId ?? stashed?.generationId,\n prompt: promptText,\n response: responseText,\n userEmail,\n model,\n cursorVersion,\n workspaceRoots,\n transcriptPath,\n attachments,\n inputTokens: tokens.inputTokens,\n outputTokens: tokens.outputTokens,\n cacheReadTokens: tokens.cacheReadTokens,\n cacheWriteTokens: tokens.cacheWriteTokens,\n unknownFields,\n },\n config,\n );\n\n // First-class identity: surface user_email at the top level so\n // the backend can populate the event's email field directly.\n // The canonical MonitoringPayload doesn't include `email`, but\n // the existing /api/monitoring/prompt accepts extra top-level\n // keys — set it here as a non-typed extension.\n const finalPayload = userEmail\n ? ({ ...built, email: userEmail } as typeof built & { email: string })\n : built;\n\n debugLog(\"payload-built\", finalPayload);\n\n return {\n payload: finalPayload,\n transport: {\n endpoint: config.monitoringEndpoint,\n apiKey: config.apiKey,\n projectRoot,\n },\n };\n }\n\n case \"sessionEnd\":\n case \"stop\": {\n // Flush any orphan prompts for the ending conversation. We can\n // emit at most one orphan from a single hook invocation (the\n // dispatcher collects one HookResult per call); pick the orphan\n // matching this conversationId if any, otherwise the oldest.\n const orphan = pickOrphanForFlush(meta.conversationId, homeDir);\n if (!orphan) return null;\n\n const projectRoot = resolveCursorProjectRoot(\n // Synthesize a payload-like for resolution — orphan carries\n // the workspace_roots from the stashed beforeSubmitPrompt.\n {\n workspace_roots: orphan.workspaceRoots,\n } as CursorHookPayload,\n opts.projectRoot ?? process.cwd(),\n );\n if (!projectRoot) {\n debugLog(\"orphan-config-not-found\", {\n conversationId: orphan.conversationId,\n });\n clearPendingPrompt(\n orphan.conversationId,\n orphan.generationId,\n homeDir,\n );\n return null;\n }\n\n const config = loadCursorConfig(projectRoot);\n if (!config) {\n debugLog(\"orphan-config-load-failed\", { projectRoot });\n clearPendingPrompt(\n orphan.conversationId,\n orphan.generationId,\n homeDir,\n );\n return null;\n }\n\n // Remove the stash file now that we're committing to flush.\n clearPendingPrompt(\n orphan.conversationId,\n orphan.generationId,\n homeDir,\n );\n\n // Orphan tokens stay at 0: Cursor's `beforeSubmitPrompt` payload\n // (the only source for orphan flushes) does not carry the\n // input_tokens/output_tokens fields — those only appear on\n // `afterAgentResponse`. `buildPairedPayload` will coerce missing\n // token inputs to 0 via `asNumber`.\n const built = buildOrphanPayload(\n {\n conversationId: orphan.conversationId,\n generationId: orphan.generationId,\n prompt: orphan.prompt,\n response: \"\",\n userEmail: orphan.userEmail,\n model: orphan.model,\n cursorVersion: orphan.cursorVersion,\n workspaceRoots: orphan.workspaceRoots,\n transcriptPath: orphan.transcriptPath,\n attachments: orphan.attachments,\n unknownFields: orphan.extra,\n },\n config,\n event === \"sessionEnd\" ? \"session-end\" : \"orphan-prompt\",\n );\n\n const finalPayload = orphan.userEmail\n ? ({ ...built, email: orphan.userEmail } as typeof built & {\n email: string;\n })\n : built;\n\n return {\n payload: finalPayload,\n transport: {\n endpoint: config.monitoringEndpoint,\n apiKey: config.apiKey,\n projectRoot,\n },\n };\n }\n }\n}\n\nfunction mergeUnknownFields(\n primary: Record<string, unknown> | undefined,\n fallback: Record<string, unknown> | undefined,\n): Record<string, unknown> | undefined {\n if (!primary && !fallback) return undefined;\n return { ...(fallback ?? {}), ...(primary ?? {}) };\n}\n\nfunction pickOrphanForFlush(\n conversationId: string | undefined,\n homeDir: string,\n): ReturnType<typeof listPendingPrompts>[number] | null {\n const pending = listPendingPrompts(homeDir);\n if (pending.length === 0) return null;\n\n if (conversationId) {\n const match = pending.find((p) => p.conversationId === conversationId);\n if (match) return match;\n }\n // No conversationId in the sessionEnd payload, or no match — flush\n // the oldest orphan as a best-effort.\n return pending.sort((a, b) =>\n (a.stashedAt || \"\").localeCompare(b.stashedAt || \"\"),\n )[0];\n}\n\nconst cursorPlugin: ToolMonitorPlugin = {\n id: TOOL_ID,\n displayName: \"Cursor\",\n\n install(opts: InstallOpts): Promise<InstallResult> {\n return installCursor(opts);\n },\n\n uninstall(opts: UninstallOpts): Promise<void> {\n return uninstallCursor(opts);\n },\n\n status(opts): Promise<StatusReport> {\n return getCursorStatus(opts);\n },\n\n handleHook(eventName, payloadJson, opts): Promise<HookResult | null> {\n return handleCursorHook(eventName, payloadJson, opts);\n },\n\n async detectInstalled(): Promise<boolean> {\n try {\n // `~/.cursor/` exists for any installed Cursor user (it's where\n // Cursor stores per-user state). `which cursor` is a fallback\n // for portable installs that don't write to ~/.cursor yet.\n if (fs.existsSync(getCursorUserDir())) return true;\n return whichCursorOnPath();\n } catch {\n return false;\n }\n },\n};\n\nfunction whichCursorOnPath(): boolean {\n const pathEnv = process.env.PATH;\n if (!pathEnv) return false;\n const sep = process.platform === \"win32\" ? \";\" : \":\";\n const exts =\n process.platform === \"win32\"\n ? (process.env.PATHEXT ?? \".EXE;.CMD;.BAT\").split(\";\")\n : [\"\"];\n for (const dir of pathEnv.split(sep)) {\n for (const ext of exts) {\n const candidate = `${dir}/cursor${ext.toLowerCase()}`;\n try {\n if (fs.existsSync(candidate)) return true;\n } catch {\n // ignore\n }\n }\n }\n return false;\n}\n\nregisterPlugin(cursorPlugin);\n\nexport default cursorPlugin;\nexport {\n buildPairedPayload,\n buildOrphanPayload,\n extractCursorMeta,\n extractPromptText,\n extractResponseText,\n isCursorEventName,\n normalizeEventName,\n type CursorHookPayload,\n} from \"./hook.js\";\nexport {\n mergeCursorHooks,\n removeOlakaiCursorHooks,\n hasOlakaiCursorHooks,\n type CursorHookEntry,\n type CursorHooksConfig,\n} from \"./hooks-config.js\";\nexport type { CursorMonitorConfig } from \"./config.js\";\nexport {\n stashPendingPrompt,\n takePendingPrompt,\n listPendingPrompts,\n clearPendingPrompt,\n} from \"./pairing-state.js\";\n","/**\n * Cursor install/uninstall flows. Per D-004, this stage installs hooks\n * to the per-user path only (`~/.cursor/hooks.json`); system-wide\n * enterprise install is deferred to Stage 4.5.\n */\nimport * as fs from \"node:fs\";\nimport * as os from \"node:os\";\nimport * as path from \"node:path\";\nimport {\n createAgent,\n getAgent,\n listAgents,\n type Agent,\n} from \"../../../lib/api.js\";\nimport { getValidToken } from \"../../../lib/auth.js\";\nimport { getBaseUrl } from \"../../../lib/config.js\";\nimport { promptUser } from \"../../prompt.js\";\nimport { validatePastedApiKey } from \"../../validate-pasted-key.js\";\nimport type { InstallOpts, InstallResult, UninstallOpts } from \"../../plugin.js\";\nimport { OLAKAI_DIR } from \"../../paths.js\";\nimport {\n getCursorConfigPath,\n writeCursorConfig,\n deleteCursorConfig,\n type CursorMonitorConfig,\n} from \"./config.js\";\nimport {\n CURSOR_DIR_NAME,\n CURSOR_HOOKS_FILE,\n getCursorHooksPath,\n getCursorUserDir,\n} from \"./paths.js\";\nimport {\n mergeCursorHooks,\n removeOlakaiCursorHooks,\n type CursorHooksConfig,\n} from \"./hooks-config.js\";\n\nconst CURSOR_SOURCE = \"cursor\";\nconst CURSOR_AGENT_SOURCE = \"CURSOR\";\nconst CURSOR_AGENT_CATEGORY = \"CODING\";\n\n/**\n * Read `~/.cursor/hooks.json` (or any JSON file) tolerantly. Returns\n * null on missing file, malformed JSON, or read error — install logic\n * treats null as \"start from scratch\" and writes a fresh config.\n */\nfunction readJsonFileTolerant<T>(filePath: string): T | null {\n try {\n if (!fs.existsSync(filePath)) return null;\n const raw = fs.readFileSync(filePath, \"utf-8\");\n return JSON.parse(raw) as T;\n } catch {\n return null;\n }\n}\n\nfunction writeJsonFileWithDir(filePath: string, data: unknown): void {\n const dir = path.dirname(filePath);\n if (!fs.existsSync(dir)) {\n fs.mkdirSync(dir, { recursive: true });\n }\n fs.writeFileSync(filePath, JSON.stringify(data, null, 2) + \"\\n\", \"utf-8\");\n}\n\nexport interface InstallCursorOpts extends InstallOpts {\n /** Override `~` for tests. Production callers leave this undefined. */\n homeDir?: string;\n}\n\nexport async function installCursor(\n opts: InstallCursorOpts,\n): Promise<InstallResult> {\n const projectRoot = opts.projectRoot ?? process.cwd();\n const homeDir = opts.homeDir ?? os.homedir();\n\n const token = getValidToken();\n if (!token) {\n console.error(\"Not logged in. Run 'olakai login' first.\");\n process.exit(1);\n }\n\n console.log(\"Setting up Cursor monitoring for this workspace...\\n\");\n console.log(\n \"Note: Cursor hooks are installed globally per user (~/.cursor/hooks.json).\",\n );\n console.log(\n `Activity from this workspace (${projectRoot}) will be associated with`,\n );\n console.log(\"the agent you select below.\\n\");\n\n const dirName = path.basename(projectRoot);\n const agent = await chooseOrCreateAgent(dirName);\n\n const monitoringEndpoint = `${getBaseUrl()}/api/monitoring/prompt`;\n\n let apiKey = agent.apiKey?.key;\n if (!apiKey) {\n console.log(\n \"\\nThe API key for this agent is not available (it is only shown once at creation).\",\n );\n apiKey = await promptUser(\"Paste the API key for this agent: \");\n if (!apiKey) {\n console.error(\"API key is required for monitoring.\");\n process.exit(1);\n }\n\n // Pasted key — verify it actually belongs to the agent the user\n // picked. This guards against silent misattribution when a key\n // from a different agent is pasted by mistake. The create-new\n // path doesn't reach here (apiKey.key is populated inline by the\n // create response), so no validation is needed there.\n await validatePastedApiKey({\n monitoringEndpoint,\n apiKey,\n expectedAgentId: agent.id,\n expectedAgentName: agent.name,\n expectedApiKeyId: agent.apiKey?.id ?? null,\n });\n }\n\n // Per-user hooks config\n const cursorDir = getCursorUserDir(homeDir);\n if (!fs.existsSync(cursorDir)) {\n fs.mkdirSync(cursorDir, { recursive: true });\n }\n\n const hooksPath = getCursorHooksPath(homeDir);\n const existingHooks = readJsonFileTolerant<CursorHooksConfig>(hooksPath);\n const mergedHooks = mergeCursorHooks(existingHooks);\n writeJsonFileWithDir(hooksPath, mergedHooks);\n\n // Per-project monitor config\n const monitorConfig: CursorMonitorConfig = {\n agentId: agent.id,\n apiKey,\n agentName: agent.name,\n source: CURSOR_SOURCE,\n createdAt: new Date().toISOString(),\n monitoringEndpoint,\n };\n writeCursorConfig(projectRoot, monitorConfig);\n\n const configPath = getCursorConfigPath(projectRoot);\n const configRel = path.relative(projectRoot, configPath);\n const hooksDisplay = `~/${path.join(CURSOR_DIR_NAME, CURSOR_HOOKS_FILE)}`;\n\n console.log(\"\");\n console.log(`✓ Agent \"${agent.name}\" configured (ID: ${agent.id})`);\n if (agent.apiKey?.key) {\n console.log(\"✓ API key generated\");\n }\n console.log(`✓ Cursor hooks installed at ${hooksDisplay}`);\n console.log(`✓ Monitor config saved to ${configRel}`);\n console.log(\"\");\n console.log(\n \"Monitoring is now active. Restart Cursor for the new hooks to take effect.\",\n );\n console.log(`View activity at: ${getBaseUrl()}/dashboard`);\n console.log(\"\");\n console.log(\n `⚠ Ensure ${OLAKAI_DIR}/ is in your .gitignore (it contains your API key)`,\n );\n console.log(\"\");\n console.log(\"To check status: olakai monitor status --tool cursor\");\n console.log(\"To disable: olakai monitor disable --tool cursor\");\n\n return {\n agentId: agent.id,\n agentName: agent.name,\n source: CURSOR_SOURCE,\n monitoringEndpoint,\n };\n}\n\nasync function chooseOrCreateAgent(defaultName: string): Promise<Agent> {\n const choice = await promptUser(\n \"Create a new agent or use an existing one? (new/existing) [new]: \",\n );\n\n if (choice.toLowerCase() === \"existing\" || choice.toLowerCase() === \"e\") {\n const agents = await listAgents();\n if (agents.length === 0) {\n console.log(\"No agents found. Creating a new one instead.\\n\");\n return createNewAgent(defaultName);\n }\n console.log(\"\\nAvailable agents:\");\n for (let i = 0; i < agents.length; i++) {\n console.log(\n ` ${i + 1}. ${agents[i].name} (${agents[i].id.slice(0, 12)}...)`,\n );\n }\n\n const selection = await promptUser(`\\nSelect agent (1-${agents.length}): `);\n const idx = parseInt(selection, 10) - 1;\n if (isNaN(idx) || idx < 0 || idx >= agents.length) {\n console.error(\"Invalid selection.\");\n process.exit(1);\n }\n\n const fetched = await getAgent(agents[idx].id);\n if (!fetched.apiKey?.key && !fetched.apiKey?.isActive) {\n console.log(\n \"\\nThis agent has no active API key. Please create a new agent instead,\",\n );\n console.log(\"or generate an API key via the Olakai dashboard.\\n\");\n const createNew = await promptUser(\"Create a new agent? (y/n) [y]: \");\n if (createNew.toLowerCase() !== \"n\") {\n return createNewAgent(defaultName);\n }\n process.exit(1);\n }\n return fetched;\n }\n\n return createNewAgent(defaultName);\n}\n\nasync function createNewAgent(defaultName: string): Promise<Agent> {\n const nameInput = await promptUser(`Agent name [${defaultName}]: `);\n const agentName = nameInput || defaultName;\n return createAgent({\n name: agentName,\n description: `Cursor local agent for ${agentName}`,\n role: \"WORKER\",\n createApiKey: true,\n category: CURSOR_AGENT_CATEGORY,\n source: CURSOR_AGENT_SOURCE,\n });\n}\n\nexport interface UninstallCursorOpts extends UninstallOpts {\n /** Override `~` for tests. */\n homeDir?: string;\n}\n\nexport async function uninstallCursor(\n opts: UninstallCursorOpts,\n): Promise<void> {\n const projectRoot = opts.projectRoot ?? process.cwd();\n const homeDir = opts.homeDir ?? os.homedir();\n\n const hooksPath = getCursorHooksPath(homeDir);\n const existingHooks = readJsonFileTolerant<CursorHooksConfig>(hooksPath);\n if (existingHooks) {\n const cleaned = removeOlakaiCursorHooks(existingHooks);\n if (\n !cleaned.hooks ||\n Object.keys(cleaned.hooks).length === 0\n ) {\n // No hooks left at all. If the file only contained Olakai entries\n // and nothing else (no version override, no extra keys), remove\n // it entirely so we don't leave a dead `{}` behind.\n const otherKeys = Object.keys(cleaned).filter(\n (k) => k !== \"hooks\" && k !== \"version\",\n );\n const onlyDefaults =\n otherKeys.length === 0 &&\n (cleaned.version === 1 || cleaned.version === undefined);\n if (onlyDefaults) {\n try {\n fs.unlinkSync(hooksPath);\n } catch {\n // best-effort\n }\n } else {\n writeJsonFileWithDir(hooksPath, cleaned);\n }\n } else {\n writeJsonFileWithDir(hooksPath, cleaned);\n }\n console.log(\n `✓ Olakai hooks removed from ~/${path.join(CURSOR_DIR_NAME, CURSOR_HOOKS_FILE)}`,\n );\n } else {\n console.log(\"No Cursor hooks file found.\");\n }\n\n if (!opts.keepConfig) {\n const configPath = getCursorConfigPath(projectRoot);\n const configRel = path.relative(projectRoot, configPath);\n if (deleteCursorConfig(projectRoot)) {\n console.log(`✓ Monitor config removed (${configRel})`);\n }\n } else {\n const configPath = getCursorConfigPath(projectRoot);\n const configRel = path.relative(projectRoot, configPath);\n console.log(`Monitor config retained at ${configRel}`);\n }\n\n console.log(\"\");\n console.log(\n \"Monitoring disabled. Run 'olakai monitor init --tool cursor' to re-enable.\",\n );\n console.log(\"Restart Cursor for the change to take effect.\");\n}\n","/**\n * Per-tool monitor config storage for Cursor. Lives at\n * `.olakai/monitor-cursor.json` in the configured project root.\n *\n * Cursor's hooks config is global per user (`~/.cursor/hooks.json`),\n * but the per-project config (which agent + apiKey to associate with\n * events from this workspace) lives under the project root just like\n * Claude Code's. The hook adapter walks ancestors of `workspace_roots`\n * to find the configured workspace.\n */\nimport * as fs from \"node:fs\";\nimport * as path from \"node:path\";\nimport {\n getMonitorConfigPath as resolveMonitorConfigPath,\n getOlakaiDir,\n} from \"../../paths.js\";\n\nexport interface CursorMonitorConfig {\n agentId: string;\n apiKey: string;\n agentName: string;\n source: string;\n createdAt: string;\n monitoringEndpoint: string;\n}\n\nexport function getCursorConfigPath(projectRoot: string): string {\n return resolveMonitorConfigPath(projectRoot, \"cursor\");\n}\n\nexport function loadCursorConfig(\n projectRoot: string,\n): CursorMonitorConfig | null {\n const filePath = getCursorConfigPath(projectRoot);\n try {\n if (!fs.existsSync(filePath)) return null;\n const raw = fs.readFileSync(filePath, \"utf-8\");\n return JSON.parse(raw) as CursorMonitorConfig;\n } catch {\n return null;\n }\n}\n\nexport function writeCursorConfig(\n projectRoot: string,\n config: CursorMonitorConfig,\n): void {\n const filePath = getCursorConfigPath(projectRoot);\n const dir = path.dirname(filePath);\n if (!fs.existsSync(dir)) {\n fs.mkdirSync(dir, { recursive: true });\n }\n fs.writeFileSync(filePath, JSON.stringify(config, null, 2) + \"\\n\", \"utf-8\");\n try {\n fs.chmodSync(filePath, 0o600);\n } catch {\n // chmod failures are non-fatal — Windows / unusual filesystems\n }\n}\n\nexport function deleteCursorConfig(projectRoot: string): boolean {\n const filePath = getCursorConfigPath(projectRoot);\n if (!fs.existsSync(filePath)) return false;\n try {\n fs.unlinkSync(filePath);\n return true;\n } catch {\n return false;\n }\n}\n\nexport function getOlakaiConfigDir(projectRoot: string): string {\n return getOlakaiDir(projectRoot);\n}\n","/**\n * Cursor-specific path helpers. Cursor hooks are configured globally\n * per user at `~/.cursor/hooks.json` (per D-004; system-wide enterprise\n * install is deferred to Stage 4.5).\n */\nimport * as os from \"node:os\";\nimport * as path from \"node:path\";\n\nexport const CURSOR_DIR_NAME = \".cursor\";\nexport const CURSOR_HOOKS_FILE = \"hooks.json\";\n\n/**\n * Per-user Cursor directory (`~/.cursor`). `homeDir` override exists\n * for tests so we can point at a tmp dir without touching the real\n * user home.\n */\nexport function getCursorUserDir(homeDir: string = os.homedir()): string {\n return path.join(homeDir, CURSOR_DIR_NAME);\n}\n\n/**\n * Per-user Cursor hooks config (`~/.cursor/hooks.json`).\n */\nexport function getCursorHooksPath(homeDir: string = os.homedir()): string {\n return path.join(getCursorUserDir(homeDir), CURSOR_HOOKS_FILE);\n}\n","/**\n * Cursor `~/.cursor/hooks.json` merge helpers.\n *\n * Pure functions (no filesystem access) so they can be unit-tested\n * exhaustively against the merge semantics. The install/uninstall\n * dispatchers in `install.ts`/`uninstall.ts` own the actual file I/O.\n *\n * Cursor's hooks config is JSON, with each event name mapping to an\n * array of hook entries: `{ command: string, timeout?: number }`. The\n * shape mirrors Cursor's published examples at\n * https://cursor.com/docs/hooks (still beta as of v1.7+, expect drift).\n */\n\n/**\n * Substring used to identify Olakai-installed hook commands inside an\n * existing `~/.cursor/hooks.json`. Every Olakai hook command starts\n * with `olakai monitor hook --tool cursor`, so the marker is sufficient\n * for both install-side dedup and uninstall-side filtering.\n */\nexport const OLAKAI_HOOK_MARKER = \"olakai monitor hook --tool cursor\";\n\n/**\n * One hook entry as Cursor expects it. Other vendor-supported fields\n * (e.g. `script`, `cwd`) are tolerated on read but not produced by us;\n * preserved verbatim by the merge logic via the catch-all index signature.\n */\nexport interface CursorHookEntry {\n command: string;\n timeout?: number;\n [extra: string]: unknown;\n}\n\n/**\n * Top-level shape of `~/.cursor/hooks.json`. `version` is recommended\n * by Cursor docs; we set it on first write and preserve whatever value\n * the user already had on subsequent writes.\n */\nexport interface CursorHooksConfig {\n version?: number;\n hooks?: Record<string, CursorHookEntry[]>;\n [extra: string]: unknown;\n}\n\n/**\n * Hook events we register. `beforeSubmitPrompt` and `afterAgentResponse`\n * give us the prompt/response pair; `sessionEnd` and `stop` flush any\n * orphan prompts. Tab hooks and tool-use hooks deferred per the Stage 4\n * design decisions.\n */\nexport const CURSOR_HOOK_DEFINITIONS: Record<string, CursorHookEntry[]> = {\n beforeSubmitPrompt: [\n {\n command: \"olakai monitor hook --tool cursor beforeSubmitPrompt\",\n timeout: 5,\n },\n ],\n afterAgentResponse: [\n {\n command: \"olakai monitor hook --tool cursor afterAgentResponse\",\n timeout: 5,\n },\n ],\n sessionEnd: [\n {\n command: \"olakai monitor hook --tool cursor sessionEnd\",\n timeout: 5,\n },\n ],\n stop: [\n {\n command: \"olakai monitor hook --tool cursor stop\",\n timeout: 5,\n },\n ],\n};\n\n/**\n * Default version field written on first install. Matches the schema\n * version Cursor docs use in their examples.\n */\nexport const CURSOR_HOOKS_VERSION = 1;\n\n/**\n * Merge our hook entries into an existing config. For each event in\n * `definitions`:\n * - If the existing array already contains an Olakai hook (entry\n * whose `command` includes `OLAKAI_HOOK_MARKER`), leave the array\n * untouched.\n * - Otherwise, append our entries to whatever the user had.\n *\n * Other top-level keys and other event arrays are preserved verbatim.\n * Returns a new config object — never mutates the input.\n */\nexport function mergeCursorHooks(\n existing: CursorHooksConfig | null | undefined,\n definitions: Record<string, CursorHookEntry[]> = CURSOR_HOOK_DEFINITIONS,\n): CursorHooksConfig {\n const base: CursorHooksConfig = existing ? { ...existing } : {};\n if (typeof base.version !== \"number\") {\n base.version = CURSOR_HOOKS_VERSION;\n }\n\n const mergedHooks: Record<string, CursorHookEntry[]> = {\n ...(base.hooks ?? {}),\n };\n\n for (const [event, defaultEntries] of Object.entries(definitions)) {\n const existingEntries = mergedHooks[event] ?? [];\n const hasOlakaiEntry = existingEntries.some((e) =>\n typeof e?.command === \"string\" && e.command.includes(OLAKAI_HOOK_MARKER),\n );\n if (hasOlakaiEntry) {\n mergedHooks[event] = existingEntries;\n } else {\n mergedHooks[event] = [...existingEntries, ...defaultEntries];\n }\n }\n\n return {\n ...base,\n hooks: mergedHooks,\n };\n}\n\n/**\n * Inverse of merge — strip Olakai-installed entries from an existing\n * config. Events whose array becomes empty after filtering are removed\n * from `hooks`. If `hooks` itself is empty after filtering, it is\n * removed. Other top-level keys are preserved verbatim.\n */\nexport function removeOlakaiCursorHooks(\n existing: CursorHooksConfig | null | undefined,\n): CursorHooksConfig {\n const base: CursorHooksConfig = existing ? { ...existing } : {};\n const sourceHooks = base.hooks ?? {};\n const cleaned: Record<string, CursorHookEntry[]> = {};\n\n for (const [event, entries] of Object.entries(sourceHooks)) {\n const filtered = entries.filter(\n (e) =>\n typeof e?.command !== \"string\" ||\n !e.command.includes(OLAKAI_HOOK_MARKER),\n );\n if (filtered.length > 0) {\n cleaned[event] = filtered;\n }\n }\n\n if (Object.keys(cleaned).length > 0) {\n base.hooks = cleaned;\n } else {\n delete base.hooks;\n }\n return base;\n}\n\n/**\n * Convenience: does this config currently have any Olakai-installed\n * hook entries? Used by status reporting.\n */\nexport function hasOlakaiCursorHooks(\n config: CursorHooksConfig | null | undefined,\n): boolean {\n if (!config?.hooks) return false;\n return Object.values(config.hooks).some((entries) =>\n entries.some(\n (e) =>\n typeof e?.command === \"string\" && e.command.includes(OLAKAI_HOOK_MARKER),\n ),\n );\n}\n","import * as fs from \"node:fs\";\nimport * as os from \"node:os\";\nimport * as path from \"node:path\";\nimport type { StatusReport } from \"../../plugin.js\";\nimport { CURSOR_DIR_NAME, CURSOR_HOOKS_FILE, getCursorHooksPath } from \"./paths.js\";\nimport {\n hasOlakaiCursorHooks,\n type CursorHooksConfig,\n} from \"./hooks-config.js\";\nimport { getCursorConfigPath, loadCursorConfig } from \"./config.js\";\n\nexport interface CursorStatusOpts {\n projectRoot?: string;\n /** Override `~` for tests. */\n homeDir?: string;\n}\n\nexport async function getCursorStatus(\n opts?: CursorStatusOpts,\n): Promise<StatusReport> {\n const projectRoot = opts?.projectRoot ?? process.cwd();\n const homeDir = opts?.homeDir ?? os.homedir();\n\n const configPath = getCursorConfigPath(projectRoot);\n const config = loadCursorConfig(projectRoot);\n\n let hooksConfigured = false;\n const hooksPath = getCursorHooksPath(homeDir);\n if (fs.existsSync(hooksPath)) {\n try {\n const raw = fs.readFileSync(hooksPath, \"utf-8\");\n const parsed = JSON.parse(raw) as CursorHooksConfig;\n hooksConfigured = hasOlakaiCursorHooks(parsed);\n } catch {\n // Treat unreadable hooks file as not-configured.\n }\n }\n\n if (!config) {\n return {\n toolId: \"cursor\",\n configured: false,\n hooksConfigured,\n configPath,\n notes: hooksConfigured\n ? [\n \"Cursor hooks installed but no monitor config in this workspace — run 'olakai monitor init --tool cursor' to associate it with an agent.\",\n ]\n : [],\n };\n }\n\n return {\n toolId: \"cursor\",\n configured: true,\n hooksConfigured,\n agentId: config.agentId,\n agentName: config.agentName,\n source: config.source,\n apiKeyMasked: config.apiKey.slice(0, 12) + \"...\",\n monitoringEndpoint: config.monitoringEndpoint,\n configuredAt: config.createdAt,\n configPath,\n };\n}\n\nexport async function printCursorStatus(opts?: CursorStatusOpts): Promise<void> {\n const projectRoot = opts?.projectRoot ?? process.cwd();\n const status = await getCursorStatus(opts);\n\n if (!status.configured) {\n console.log(\"Monitoring is not configured for this workspace.\");\n if (status.hooksConfigured) {\n console.log(\n \"(Cursor hooks ARE installed globally — run init to associate this workspace with an agent.)\",\n );\n }\n console.log(\n \"Run 'olakai monitor init --tool cursor' to set up monitoring.\",\n );\n process.exit(1);\n }\n\n const configRel = status.configPath\n ? path.relative(projectRoot, status.configPath)\n : \"(unknown)\";\n const hooksDisplay = `~/${path.join(CURSOR_DIR_NAME, CURSOR_HOOKS_FILE)}`;\n\n console.log(\"Olakai Monitor Status (Cursor)\");\n console.log(\"==============================\");\n console.log(`Agent: ${status.agentName}`);\n console.log(`Agent ID: ${status.agentId}`);\n console.log(`API Key: ${status.apiKeyMasked}`);\n console.log(`Endpoint: ${status.monitoringEndpoint}`);\n console.log(`Source: ${status.source}`);\n console.log(`Configured: ${status.configuredAt}`);\n console.log(`Config file: ${configRel}`);\n console.log(\n `Hooks: ${\n status.hooksConfigured\n ? `Active (${hooksDisplay})`\n : `Missing (re-run 'olakai monitor init --tool cursor')`\n }`,\n );\n}\n","/**\n * Cursor hook adapter. Translates beta Cursor hook payloads into our\n * canonical MonitoringPayload, pairing `beforeSubmitPrompt` and\n * `afterAgentResponse` across separate CLI invocations via the\n * pairing-state sidecar.\n *\n * Defensive parsing: Cursor hooks shipped in v1.7 (Oct 2025) and the\n * schema is still beta. Every field access is guarded; unknown fields\n * are preserved in a debug bag rather than crashing.\n */\nimport type { MonitoringPayload } from \"../../plugin.js\";\nimport type { CursorMonitorConfig } from \"./config.js\";\n\nexport type CursorEventName =\n | \"beforeSubmitPrompt\"\n | \"afterAgentResponse\"\n | \"sessionEnd\"\n | \"stop\";\n\nexport const SUPPORTED_CURSOR_EVENTS = new Set<string>([\n \"beforeSubmitPrompt\",\n \"afterAgentResponse\",\n \"sessionEnd\",\n \"stop\",\n]);\n\n/**\n * Subset of the Cursor hook payload we care about. Documented fields\n * (per https://cursor.com/docs/hooks as of Apr 2026): `conversation_id`,\n * `generation_id`, `model`, `cursor_version`, `workspace_roots`,\n * `user_email`, `transcript_path`. Per-event fields like `prompt`,\n * `response`, `text`, and `attachments` vary across versions:\n * - `prompt` (beforeSubmitPrompt): top-level string, or nested\n * `{ text, attachments }` envelope (older betas).\n * - `response` (afterAgentResponse v1.7): top-level string or\n * `{ text }` envelope.\n * - `text` (afterAgentResponse v3.x): top-level string. Confirmed\n * against a real Cursor v3.2.11 staging payload — replaces the\n * v1.7 `response` field.\n * - `input_tokens` / `output_tokens` / `cache_read_tokens` /\n * `cache_write_tokens` (afterAgentResponse v3.x): per-turn token\n * counts. Not present on beforeSubmitPrompt.\n */\nexport interface CursorHookPayload {\n event?: string;\n conversation_id?: string;\n generation_id?: string;\n model?: string;\n cursor_version?: string;\n workspace_roots?: string[];\n user_email?: string;\n transcript_path?: string;\n prompt?: string | { text?: string; attachments?: unknown[] };\n response?: string | { text?: string };\n /** v3.x top-level response text (replaces `response`). */\n text?: string;\n attachments?: unknown[];\n /** v3.x per-turn token counts (afterAgentResponse only). */\n input_tokens?: number;\n output_tokens?: number;\n cache_read_tokens?: number;\n cache_write_tokens?: number;\n [extra: string]: unknown;\n}\n\nfunction asString(value: unknown): string | undefined {\n return typeof value === \"string\" && value.trim() ? value : undefined;\n}\n\n/**\n * Defensive numeric coercion. Treats `undefined`, `null`, non-numeric\n * types, and `NaN` as 0. Used for the v3.x token fields, which may be\n * missing on older Cursor builds and absent entirely on\n * `beforeSubmitPrompt`.\n */\nexport function asNumber(value: unknown): number {\n if (typeof value !== \"number\") return 0;\n if (!Number.isFinite(value)) return 0;\n return value;\n}\n\n/**\n * Extracted per-turn token breakdown from a Cursor v3.x\n * `afterAgentResponse` payload. Each field defaults to 0 when missing.\n */\nexport interface ExtractedCursorTokens {\n inputTokens: number;\n outputTokens: number;\n cacheReadTokens: number;\n cacheWriteTokens: number;\n}\n\nexport function extractCursorTokens(\n payload: CursorHookPayload,\n): ExtractedCursorTokens {\n return {\n inputTokens: asNumber(payload.input_tokens),\n outputTokens: asNumber(payload.output_tokens),\n cacheReadTokens: asNumber(payload.cache_read_tokens),\n cacheWriteTokens: asNumber(payload.cache_write_tokens),\n };\n}\n\nfunction asStringArray(value: unknown): string[] | undefined {\n if (!Array.isArray(value)) return undefined;\n const out: string[] = [];\n for (const item of value) {\n if (typeof item === \"string\" && item.trim()) out.push(item);\n }\n return out.length > 0 ? out : undefined;\n}\n\n/**\n * Pull the prompt text out of either a top-level string field or a\n * nested envelope. Returns \"\" when neither is present so callers can\n * stash an empty placeholder rather than a malformed entry.\n */\nexport function extractPromptText(payload: CursorHookPayload): string {\n if (typeof payload.prompt === \"string\") return payload.prompt;\n if (\n payload.prompt &&\n typeof payload.prompt === \"object\" &&\n typeof (payload.prompt as { text?: unknown }).text === \"string\"\n ) {\n return (payload.prompt as { text: string }).text;\n }\n return \"\";\n}\n\n/**\n * Pull the response text from one of three known shapes, in order of\n * preference:\n * 1. `payload.response` (string) — older beta builds.\n * 2. `payload.response.text` (object envelope) — older beta builds.\n * 3. `payload.text` (top-level string) — Cursor v3.x format,\n * confirmed against a real v3.2.11 payload. This is the current\n * production shape.\n * Returns \"\" when none match so callers can stash an empty placeholder\n * rather than a malformed entry.\n */\nexport function extractResponseText(payload: CursorHookPayload): string {\n if (typeof payload.response === \"string\") return payload.response;\n if (\n payload.response &&\n typeof payload.response === \"object\" &&\n typeof (payload.response as { text?: unknown }).text === \"string\"\n ) {\n return (payload.response as { text: string }).text;\n }\n if (typeof payload.text === \"string\") return payload.text;\n return \"\";\n}\n\nexport function extractAttachments(\n payload: CursorHookPayload,\n): unknown[] | undefined {\n if (Array.isArray(payload.attachments)) return payload.attachments;\n if (\n payload.prompt &&\n typeof payload.prompt === \"object\" &&\n Array.isArray((payload.prompt as { attachments?: unknown[] }).attachments)\n ) {\n return (payload.prompt as { attachments: unknown[] }).attachments;\n }\n return undefined;\n}\n\n/**\n * Inputs to `buildPairedPayload`. Pulled out as a struct to keep the\n * call-site at the plugin readable.\n */\nexport interface PairedPayloadInputs {\n conversationId: string;\n generationId?: string;\n prompt: string;\n response: string;\n userEmail?: string;\n model?: string;\n cursorVersion?: string;\n workspaceRoots?: string[];\n transcriptPath?: string;\n attachments?: unknown[];\n /**\n * Per-turn token counts from Cursor v3.x `afterAgentResponse`. All\n * default to 0 when absent (e.g. older builds, orphan flushes). The\n * canonical `tokens` field on the MonitoringPayload is computed as\n * `inputTokens + outputTokens` (mirrors the Codex plugin convention\n * — cache_read tokens are typically billed at a different rate so\n * we keep them in customData rather than rolling them into the\n * headline number).\n */\n inputTokens?: number;\n outputTokens?: number;\n cacheReadTokens?: number;\n cacheWriteTokens?: number;\n /** Free-form bag — surfaced into customData for forensic value. */\n unknownFields?: Record<string, unknown>;\n}\n\n/**\n * Build a canonical MonitoringPayload from a paired prompt/response.\n * Pure — exported for unit tests.\n */\nexport function buildPairedPayload(\n inputs: PairedPayloadInputs,\n config: CursorMonitorConfig,\n): MonitoringPayload {\n const customData: Record<string, unknown> = {\n hookEvent: \"afterAgentResponse\",\n conversationId: inputs.conversationId,\n };\n if (inputs.generationId) customData.generationId = inputs.generationId;\n if (inputs.cursorVersion) customData.cursorVersion = inputs.cursorVersion;\n if (inputs.workspaceRoots) customData.workspaceRoots = inputs.workspaceRoots;\n if (inputs.transcriptPath) customData.transcriptPath = inputs.transcriptPath;\n if (inputs.attachments && inputs.attachments.length > 0) {\n customData.attachmentCount = inputs.attachments.length;\n }\n if (inputs.userEmail) customData.userEmail = inputs.userEmail;\n\n // Token breakdown — surface even when zero so downstream consumers\n // see a stable shape and can distinguish \"no tokens reported\" from\n // \"field absent\". The aggregate `tokens` is what drives cost KPIs.\n const inputTokens = asNumber(inputs.inputTokens);\n const outputTokens = asNumber(inputs.outputTokens);\n const cacheReadTokens = asNumber(inputs.cacheReadTokens);\n const cacheWriteTokens = asNumber(inputs.cacheWriteTokens);\n customData.inputTokens = inputTokens;\n customData.outputTokens = outputTokens;\n customData.cacheReadTokens = cacheReadTokens;\n customData.cacheWriteTokens = cacheWriteTokens;\n\n if (\n inputs.unknownFields &&\n Object.keys(inputs.unknownFields).length > 0\n ) {\n customData.unknownPayloadFields = inputs.unknownFields;\n }\n\n return {\n prompt: inputs.prompt,\n response: inputs.response,\n chatId: inputs.conversationId,\n source: config.source,\n modelName: inputs.model,\n tokens: inputTokens + outputTokens,\n customData,\n };\n}\n\n/**\n * Build a partial-orphan MonitoringPayload — emitted by `sessionEnd`\n * or `stop` when we have a stashed prompt that never received a paired\n * response. Response is the empty string (the canonical payload\n * requires a string), and customData carries `partial: true` plus\n * `partialReason: \"orphan-prompt\"` so the backend can flag it.\n */\nexport function buildOrphanPayload(\n inputs: PairedPayloadInputs,\n config: CursorMonitorConfig,\n reason: \"orphan-prompt\" | \"session-end\" = \"orphan-prompt\",\n): MonitoringPayload {\n const base = buildPairedPayload({ ...inputs, response: \"\" }, config);\n return {\n ...base,\n customData: {\n ...base.customData,\n hookEvent: \"sessionEnd\",\n partial: true,\n partialReason: reason,\n },\n };\n}\n\n/**\n * Identify keys present in the payload that aren't part of the\n * documented schema. Used to populate `unknownPayloadFields` so we\n * can spot beta-schema drift in production.\n */\nconst KNOWN_PAYLOAD_KEYS = new Set([\n \"event\",\n \"conversation_id\",\n \"generation_id\",\n \"model\",\n \"cursor_version\",\n \"workspace_roots\",\n \"user_email\",\n \"transcript_path\",\n \"prompt\",\n \"response\",\n \"text\",\n \"attachments\",\n \"input_tokens\",\n \"output_tokens\",\n \"cache_read_tokens\",\n \"cache_write_tokens\",\n]);\n\nexport function collectUnknownFields(\n payload: CursorHookPayload,\n): Record<string, unknown> | undefined {\n const out: Record<string, unknown> = {};\n for (const key of Object.keys(payload)) {\n if (!KNOWN_PAYLOAD_KEYS.has(key)) {\n out[key] = payload[key];\n }\n }\n return Object.keys(out).length > 0 ? out : undefined;\n}\n\n/**\n * Normalize Cursor's documented event names to lowercase comparison.\n * Cursor docs use camelCase (`beforeSubmitPrompt`); we keep that as\n * the canonical string but accept any-case input from callers (the\n * dispatcher passes the literal CLI argument through).\n */\nexport function normalizeEventName(event: string): CursorEventName | null {\n const lower = event.trim();\n if (!lower) return null;\n const exact = lower as CursorEventName;\n if (SUPPORTED_CURSOR_EVENTS.has(exact)) return exact;\n // Accept lowercased variants (\"stop\" vs \"Stop\") — Cursor has been\n // inconsistent across beta builds. Falls back to null on no match.\n for (const known of SUPPORTED_CURSOR_EVENTS) {\n if (known.toLowerCase() === lower.toLowerCase()) return known as CursorEventName;\n }\n return null;\n}\n\nexport function isCursorEventName(value: string): value is CursorEventName {\n return SUPPORTED_CURSOR_EVENTS.has(value);\n}\n\n/**\n * Helpers for consumers to quickly extract the documented fields with\n * defensive guards. Returned as a struct so the plugin can pass it\n * around without re-walking the payload.\n */\nexport interface ExtractedCursorMeta {\n conversationId: string | undefined;\n generationId: string | undefined;\n model: string | undefined;\n cursorVersion: string | undefined;\n workspaceRoots: string[] | undefined;\n userEmail: string | undefined;\n transcriptPath: string | undefined;\n}\n\nexport function extractCursorMeta(\n payload: CursorHookPayload,\n): ExtractedCursorMeta {\n return {\n conversationId: asString(payload.conversation_id),\n generationId: asString(payload.generation_id),\n model: asString(payload.model),\n cursorVersion: asString(payload.cursor_version),\n workspaceRoots: asStringArray(payload.workspace_roots),\n userEmail: asString(payload.user_email),\n transcriptPath: asString(payload.transcript_path),\n };\n}\n","/**\n * Cross-invocation pairing state for Cursor's split prompt/response\n * hooks. `beforeSubmitPrompt` and `afterAgentResponse` fire as separate\n * CLI invocations — to build a single MonitoringPayload we stash the\n * prompt under the conversation+generation key on the first invocation\n * and pair it with the response on the second.\n *\n * State lives at `~/.olakai/cursor-pairings/<conversation>__<generation>.json`\n * (or `.../<conversation>.json` when generation is missing). Files are\n * removed on successful pair or session-end flush. The directory is\n * created on demand and best-effort cleaned up on flush.\n *\n * Mirrors the pattern in `commands/monitor-state.ts` (per-session dedup\n * for Claude Code) — pure w.r.t. process state, all errors swallowed,\n * `homeDir` overridable for tests.\n */\n\nimport * as fs from \"node:fs\";\nimport * as os from \"node:os\";\nimport * as path from \"node:path\";\n\nexport interface PendingCursorPrompt {\n prompt: string;\n userEmail?: string;\n model?: string;\n cursorVersion?: string;\n conversationId: string;\n generationId?: string;\n workspaceRoots?: string[];\n transcriptPath?: string;\n attachments?: unknown[];\n /** ISO timestamp captured at stash time. Powers orphan-flush ordering. */\n stashedAt: string;\n /** Free-form bag for additional payload-shape fields surfaced later. */\n extra?: Record<string, unknown>;\n}\n\nconst STATE_DIR_SEGMENTS = [\".olakai\", \"cursor-pairings\"];\n\nfunction getPairingsDir(homeDir: string): string {\n return path.join(homeDir, ...STATE_DIR_SEGMENTS);\n}\n\n/**\n * Filenames must round-trip safely on macOS/Linux/Windows. Cursor IDs\n * are UUIDs in practice; we still sanitize defensively in case the\n * beta schema ever loosens.\n */\nfunction sanitizeKeyFragment(value: string): string {\n return value.replace(/[^A-Za-z0-9._-]/g, \"_\");\n}\n\nfunction getPairingKey(\n conversationId: string,\n generationId: string | undefined,\n): string {\n const conv = sanitizeKeyFragment(conversationId);\n if (!generationId) return conv;\n return `${conv}__${sanitizeKeyFragment(generationId)}`;\n}\n\nfunction getPairingFile(\n conversationId: string,\n generationId: string | undefined,\n homeDir: string,\n): string {\n return path.join(\n getPairingsDir(homeDir),\n `${getPairingKey(conversationId, generationId)}.json`,\n );\n}\n\n/**\n * Stash a prompt for later pairing. Empty conversationId is a no-op:\n * without a key we can't pair, and emitting an unkeyed orphan would\n * race with concurrent prompts in other windows.\n */\nexport function stashPendingPrompt(\n pending: PendingCursorPrompt,\n homeDir: string = os.homedir(),\n): void {\n if (!pending.conversationId) return;\n const dir = getPairingsDir(homeDir);\n try {\n if (!fs.existsSync(dir)) {\n fs.mkdirSync(dir, { recursive: true });\n }\n const filePath = getPairingFile(\n pending.conversationId,\n pending.generationId,\n homeDir,\n );\n fs.writeFileSync(\n filePath,\n JSON.stringify(pending, null, 2) + \"\\n\",\n \"utf-8\",\n );\n } catch {\n // Pairing-state failures must never break the host tool.\n }\n}\n\n/**\n * Load + delete a stashed prompt for the given conversation/generation\n * pair. Returns null when none is found. The delete is unconditional\n * even if the JSON parses to garbage, to avoid leaving poison files\n * behind that the orphan-flush would later trip over.\n *\n * Generation matching: when the response carries a generationId, we\n * try the (conversation+generation) key first, then fall back to the\n * conversation-only key. This handles the case where an older Cursor\n * version omits generationId on `beforeSubmitPrompt` but includes it\n * on `afterAgentResponse`.\n */\nexport function takePendingPrompt(\n conversationId: string,\n generationId: string | undefined,\n homeDir: string = os.homedir(),\n): PendingCursorPrompt | null {\n if (!conversationId) return null;\n\n const candidates: string[] = [];\n if (generationId) {\n candidates.push(getPairingFile(conversationId, generationId, homeDir));\n }\n candidates.push(getPairingFile(conversationId, undefined, homeDir));\n\n for (const filePath of candidates) {\n let raw: string;\n try {\n if (!fs.existsSync(filePath)) continue;\n raw = fs.readFileSync(filePath, \"utf-8\");\n } catch {\n continue;\n }\n try {\n fs.unlinkSync(filePath);\n } catch {\n // best-effort cleanup\n }\n try {\n const parsed = JSON.parse(raw) as PendingCursorPrompt;\n if (parsed && typeof parsed.conversationId === \"string\") {\n return parsed;\n }\n } catch {\n // poison file — file already deleted above; skip\n }\n }\n return null;\n}\n\n/**\n * List all currently-stashed prompts. Used by `sessionEnd`/`stop` to\n * flush orphans. The caller is responsible for deciding which orphans\n * belong to the ending session (via `conversationId` match) and for\n * removing the stash files via `clearPendingPrompt` after emitting\n * the partial event.\n */\nexport function listPendingPrompts(\n homeDir: string = os.homedir(),\n): PendingCursorPrompt[] {\n const dir = getPairingsDir(homeDir);\n if (!fs.existsSync(dir)) return [];\n\n let files: string[];\n try {\n files = fs.readdirSync(dir);\n } catch {\n return [];\n }\n\n const result: PendingCursorPrompt[] = [];\n for (const name of files) {\n if (!name.endsWith(\".json\")) continue;\n const filePath = path.join(dir, name);\n try {\n const raw = fs.readFileSync(filePath, \"utf-8\");\n const parsed = JSON.parse(raw) as PendingCursorPrompt;\n if (parsed && typeof parsed.conversationId === \"string\") {\n result.push(parsed);\n }\n } catch {\n // skip malformed entries — orphan flush is best-effort\n }\n }\n return result;\n}\n\n/**\n * Delete a single stashed-prompt file. Used after flushing an orphan\n * partial event. Non-existent files are not an error.\n */\nexport function clearPendingPrompt(\n conversationId: string,\n generationId: string | undefined,\n homeDir: string = os.homedir(),\n): void {\n if (!conversationId) return;\n const candidates: string[] = [];\n if (generationId) {\n candidates.push(getPairingFile(conversationId, generationId, homeDir));\n }\n candidates.push(getPairingFile(conversationId, undefined, homeDir));\n for (const filePath of candidates) {\n try {\n if (fs.existsSync(filePath)) {\n fs.unlinkSync(filePath);\n }\n } catch {\n // best-effort\n }\n }\n}\n"],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAEA,SAAS,qBAAqB;AAC9B,SAAS,eAAe;;;ACHxB,OAAO,UAAU;;;ACuKjB,eAAsB,oBAAiD;AACrE,QAAM,WAAW,MAAM,MAAM,GAAG,WAAW,CAAC,yBAAyB;AAAA,IACnE,QAAQ;AAAA,IACR,SAAS;AAAA,MACP,gBAAgB;AAAA,IAClB;AAAA,IACA,MAAM,KAAK,UAAU,EAAE,WAAW,UAAU,CAAC;AAAA,EAC/C,CAAC;AAED,MAAI,CAAC,SAAS,IAAI;AAChB,UAAM,QAAS,MAAM,SAAS,KAAK;AACnC,UAAM,IAAI,MAAM,MAAM,qBAAqB,MAAM,SAAS,+BAA+B;AAAA,EAC3F;AAEA,SAAQ,MAAM,SAAS,KAAK;AAC9B;AAMA,eAAsB,aACpB,YAC+B;AAC/B,QAAM,WAAW,MAAM,MAAM,GAAG,WAAW,CAAC,0BAA0B;AAAA,IACpE,QAAQ;AAAA,IACR,SAAS;AAAA,MACP,gBAAgB;AAAA,IAClB;AAAA,IACA,MAAM,KAAK,UAAU;AAAA,MACnB,YAAY;AAAA,MACZ,aAAa;AAAA,MACb,WAAW;AAAA,IACb,CAAC;AAAA,EACH,CAAC;AAED,QAAM,OAAQ,MAAM,SAAS,KAAK;AAElC,MAAI,CAAC,SAAS,IAAI;AAChB,QAAI,WAAW,QAAQ,KAAK,UAAU,yBAAyB;AAC7D,aAAO;AAAA,IACT;AACA,UAAM,WAAW,uBAAuB,OAAO,KAAK,oBAAqB,WAAW,OAAO,KAAK,QAAQ;AACxG,UAAM,IAAI,MAAM,YAAY,uBAAuB;AAAA,EACrD;AAEA,SAAO;AACT;AAKA,eAAsB,iBAA0C;AAC9D,QAAM,QAAQ,cAAc;AAE5B,MAAI,CAAC,OAAO;AACV,UAAM,IAAI,MAAM,0CAA0C;AAAA,EAC5D;AAEA,QAAM,WAAW,MAAM,MAAM,GAAG,WAAW,CAAC,gBAAgB;AAAA,IAC1D,SAAS;AAAA,MACP,eAAe,UAAU,KAAK;AAAA,IAChC;AAAA,EACF,CAAC;AAED,MAAI,CAAC,SAAS,IAAI;AAChB,QAAI,SAAS,WAAW,KAAK;AAC3B,YAAM,IAAI,MAAM,4DAA4D;AAAA,IAC9E;AACA,UAAM,IAAI,MAAM,yBAAyB;AAAA,EAC3C;AAEA,SAAQ,MAAM,SAAS,KAAK;AAC9B;AASA,eAAsB,WAAW,SAEZ;AACnB,QAAM,QAAQ,cAAc;AAC5B,MAAI,CAAC,OAAO;AACV,UAAM,IAAI,MAAM,0CAA0C;AAAA,EAC5D;AAEA,QAAM,SAAS,IAAI,gBAAgB;AACnC,MAAI,SAAS,aAAa;AACxB,WAAO,IAAI,eAAe,MAAM;AAAA,EAClC;AAEA,QAAM,MAAM,GAAG,WAAW,CAAC,qBAAqB,OAAO,SAAS,IAAI,IAAI,MAAM,KAAK,EAAE;AACrF,QAAM,WAAW,MAAM,MAAM,KAAK;AAAA,IAChC,SAAS;AAAA,MACP,eAAe,UAAU,KAAK;AAAA,IAChC;AAAA,EACF,CAAC;AAED,MAAI,CAAC,SAAS,IAAI;AAChB,QAAI,SAAS,WAAW,KAAK;AAC3B,YAAM,IAAI,MAAM,4DAA4D;AAAA,IAC9E;AACA,UAAM,QAAS,MAAM,SAAS,KAAK;AACnC,UAAM,IAAI,MAAM,MAAM,SAAS,uBAAuB;AAAA,EACxD;AAEA,QAAM,OAAQ,MAAM,SAAS,KAAK;AAClC,SAAO,KAAK;AACd;AAKA,eAAsB,SAAS,IAA4B;AACzD,QAAM,QAAQ,cAAc;AAC5B,MAAI,CAAC,OAAO;AACV,UAAM,IAAI,MAAM,0CAA0C;AAAA,EAC5D;AAEA,QAAM,WAAW,MAAM,MAAM,GAAG,WAAW,CAAC,sBAAsB,EAAE,IAAI;AAAA,IACtE,SAAS;AAAA,MACP,eAAe,UAAU,KAAK;AAAA,IAChC;AAAA,EACF,CAAC;AAED,MAAI,CAAC,SAAS,IAAI;AAChB,QAAI,SAAS,WAAW,KAAK;AAC3B,YAAM,IAAI,MAAM,4DAA4D;AAAA,IAC9E;AACA,QAAI,SAAS,WAAW,KAAK;AAC3B,YAAM,IAAI,MAAM,iBAAiB;AAAA,IACnC;AACA,UAAM,QAAS,MAAM,SAAS,KAAK;AACnC,UAAM,IAAI,MAAM,MAAM,SAAS,qBAAqB;AAAA,EACtD;AAEA,SAAQ,MAAM,SAAS,KAAK;AAC9B;AAKA,eAAsB,YAAY,SAA6C;AAC7E,QAAM,QAAQ,cAAc;AAC5B,MAAI,CAAC,OAAO;AACV,UAAM,IAAI,MAAM,0CAA0C;AAAA,EAC5D;AAEA,QAAM,WAAW,MAAM,MAAM,GAAG,WAAW,CAAC,sBAAsB;AAAA,IAChE,QAAQ;AAAA,IACR,SAAS;AAAA,MACP,eAAe,UAAU,KAAK;AAAA,MAC9B,gBAAgB;AAAA,IAClB;AAAA,IACA,MAAM,KAAK,UAAU,OAAO;AAAA,EAC9B,CAAC;AAED,MAAI,CAAC,SAAS,IAAI;AAChB,QAAI,SAAS,WAAW,KAAK;AAC3B,YAAM,IAAI,MAAM,4DAA4D;AAAA,IAC9E;AACA,QAAI,SAAS,WAAW,KAAK;AAC3B,YAAM,IAAI,MAAM,wCAAwC;AAAA,IAC1D;AACA,UAAM,QAAS,MAAM,SAAS,KAAK;AACnC,UAAM,IAAI,MAAM,MAAM,SAAS,wBAAwB;AAAA,EACzD;AAEA,SAAQ,MAAM,SAAS,KAAK;AAC9B;AAKA,eAAsB,YACpB,IACA,SACgB;AAChB,QAAM,QAAQ,cAAc;AAC5B,MAAI,CAAC,OAAO;AACV,UAAM,IAAI,MAAM,0CAA0C;AAAA,EAC5D;AAEA,QAAM,WAAW,MAAM,MAAM,GAAG,WAAW,CAAC,sBAAsB,EAAE,IAAI;AAAA,IACtE,QAAQ;AAAA,IACR,SAAS;AAAA,MACP,eAAe,UAAU,KAAK;AAAA,MAC9B,gBAAgB;AAAA,IAClB;AAAA,IACA,MAAM,KAAK,UAAU,OAAO;AAAA,EAC9B,CAAC;AAED,MAAI,CAAC,SAAS,IAAI;AAChB,QAAI,SAAS,WAAW,KAAK;AAC3B,YAAM,IAAI,MAAM,4DAA4D;AAAA,IAC9E;AACA,QAAI,SAAS,WAAW,KAAK;AAC3B,YAAM,IAAI,MAAM,iBAAiB;AAAA,IACnC;AACA,QAAI,SAAS,WAAW,KAAK;AAC3B,YAAM,IAAI,MAAM,wCAAwC;AAAA,IAC1D;AACA,UAAM,QAAS,MAAM,SAAS,KAAK;AACnC,UAAM,IAAI,MAAM,MAAM,SAAS,wBAAwB;AAAA,EACzD;AAEA,SAAQ,MAAM,SAAS,KAAK;AAC9B;AAKA,eAAsB,YAAY,IAA2B;AAC3D,QAAM,QAAQ,cAAc;AAC5B,MAAI,CAAC,OAAO;AACV,UAAM,IAAI,MAAM,0CAA0C;AAAA,EAC5D;AAEA,QAAM,WAAW,MAAM,MAAM,GAAG,WAAW,CAAC,sBAAsB,EAAE,IAAI;AAAA,IACtE,QAAQ;AAAA,IACR,SAAS;AAAA,MACP,eAAe,UAAU,KAAK;AAAA,IAChC;AAAA,EACF,CAAC;AAED,MAAI,CAAC,SAAS,IAAI;AAChB,QAAI,SAAS,WAAW,KAAK;AAC3B,YAAM,IAAI,MAAM,4DAA4D;AAAA,IAC9E;AACA,QAAI,SAAS,WAAW,KAAK;AAC3B,YAAM,IAAI,MAAM,iBAAiB;AAAA,IACnC;AACA,UAAM,QAAS,MAAM,SAAS,KAAK;AACnC,UAAM,IAAI,MAAM,MAAM,SAAS,wBAAwB;AAAA,EACzD;AACF;AASA,eAAsB,cAAc,SAGZ;AACtB,QAAM,QAAQ,cAAc;AAC5B,MAAI,CAAC,OAAO;AACV,UAAM,IAAI,MAAM,0CAA0C;AAAA,EAC5D;AAEA,QAAM,SAAS,IAAI,gBAAgB;AACnC,MAAI,SAAS,eAAe;AAC1B,WAAO,IAAI,iBAAiB,MAAM;AAAA,EACpC;AACA,MAAI,SAAS,iBAAiB;AAC5B,WAAO,IAAI,mBAAmB,MAAM;AAAA,EACtC;AAEA,QAAM,MAAM,GAAG,WAAW,CAAC,wBAAwB,OAAO,SAAS,IAAI,IAAI,MAAM,KAAK,EAAE;AACxF,QAAM,WAAW,MAAM,MAAM,KAAK;AAAA,IAChC,SAAS;AAAA,MACP,eAAe,UAAU,KAAK;AAAA,IAChC;AAAA,EACF,CAAC;AAED,MAAI,CAAC,SAAS,IAAI;AAChB,QAAI,SAAS,WAAW,KAAK;AAC3B,YAAM,IAAI,MAAM,4DAA4D;AAAA,IAC9E;AACA,UAAM,QAAS,MAAM,SAAS,KAAK;AACnC,UAAM,IAAI,MAAM,MAAM,SAAS,0BAA0B;AAAA,EAC3D;AAEA,QAAM,OAAQ,MAAM,SAAS,KAAK;AAClC,SAAO,KAAK;AACd;AAKA,eAAsB,YAAY,IAA+B;AAC/D,QAAM,QAAQ,cAAc;AAC5B,MAAI,CAAC,OAAO;AACV,UAAM,IAAI,MAAM,0CAA0C;AAAA,EAC5D;AAEA,QAAM,WAAW,MAAM,MAAM,GAAG,WAAW,CAAC,yBAAyB,EAAE,IAAI;AAAA,IACzE,SAAS;AAAA,MACP,eAAe,UAAU,KAAK;AAAA,IAChC;AAAA,EACF,CAAC;AAED,MAAI,CAAC,SAAS,IAAI;AAChB,QAAI,SAAS,WAAW,KAAK;AAC3B,YAAM,IAAI,MAAM,4DAA4D;AAAA,IAC9E;AACA,QAAI,SAAS,WAAW,KAAK;AAC3B,YAAM,IAAI,MAAM,oBAAoB;AAAA,IACtC;AACA,UAAM,QAAS,MAAM,SAAS,KAAK;AACnC,UAAM,IAAI,MAAM,MAAM,SAAS,wBAAwB;AAAA,EACzD;AAEA,SAAQ,MAAM,SAAS,KAAK;AAC9B;AAKA,eAAsB,eACpB,SACmB;AACnB,QAAM,QAAQ,cAAc;AAC5B,MAAI,CAAC,OAAO;AACV,UAAM,IAAI,MAAM,0CAA0C;AAAA,EAC5D;AAEA,QAAM,WAAW,MAAM,MAAM,GAAG,WAAW,CAAC,yBAAyB;AAAA,IACnE,QAAQ;AAAA,IACR,SAAS;AAAA,MACP,eAAe,UAAU,KAAK;AAAA,MAC9B,gBAAgB;AAAA,IAClB;AAAA,IACA,MAAM,KAAK,UAAU,OAAO;AAAA,EAC9B,CAAC;AAED,MAAI,CAAC,SAAS,IAAI;AAChB,QAAI,SAAS,WAAW,KAAK;AAC3B,YAAM,IAAI,MAAM,4DAA4D;AAAA,IAC9E;AACA,QAAI,SAAS,WAAW,KAAK;AAC3B,YAAM,IAAI,MAAM,0CAA0C;AAAA,IAC5D;AACA,UAAM,QAAS,MAAM,SAAS,KAAK;AACnC,UAAM,IAAI,MAAM,MAAM,SAAS,2BAA2B;AAAA,EAC5D;AAEA,SAAQ,MAAM,SAAS,KAAK;AAC9B;AAKA,eAAsB,eACpB,IACA,SACmB;AACnB,QAAM,QAAQ,cAAc;AAC5B,MAAI,CAAC,OAAO;AACV,UAAM,IAAI,MAAM,0CAA0C;AAAA,EAC5D;AAEA,QAAM,WAAW,MAAM,MAAM,GAAG,WAAW,CAAC,yBAAyB,EAAE,IAAI;AAAA,IACzE,QAAQ;AAAA,IACR,SAAS;AAAA,MACP,eAAe,UAAU,KAAK;AAAA,MAC9B,gBAAgB;AAAA,IAClB;AAAA,IACA,MAAM,KAAK,UAAU,OAAO;AAAA,EAC9B,CAAC;AAED,MAAI,CAAC,SAAS,IAAI;AAChB,QAAI,SAAS,WAAW,KAAK;AAC3B,YAAM,IAAI,MAAM,4DAA4D;AAAA,IAC9E;AACA,QAAI,SAAS,WAAW,KAAK;AAC3B,YAAM,IAAI,MAAM,oBAAoB;AAAA,IACtC;AACA,QAAI,SAAS,WAAW,KAAK;AAC3B,YAAM,IAAI,MAAM,0CAA0C;AAAA,IAC5D;AACA,UAAM,QAAS,MAAM,SAAS,KAAK;AACnC,UAAM,IAAI,MAAM,MAAM,SAAS,2BAA2B;AAAA,EAC5D;AAEA,SAAQ,MAAM,SAAS,KAAK;AAC9B;AAKA,eAAsB,eAAe,IAA2B;AAC9D,QAAM,QAAQ,cAAc;AAC5B,MAAI,CAAC,OAAO;AACV,UAAM,IAAI,MAAM,0CAA0C;AAAA,EAC5D;AAEA,QAAM,WAAW,MAAM,MAAM,GAAG,WAAW,CAAC,yBAAyB,EAAE,IAAI;AAAA,IACzE,QAAQ;AAAA,IACR,SAAS;AAAA,MACP,eAAe,UAAU,KAAK;AAAA,IAChC;AAAA,EACF,CAAC;AAED,MAAI,CAAC,SAAS,IAAI;AAChB,QAAI,SAAS,WAAW,KAAK;AAC3B,YAAM,IAAI,MAAM,4DAA4D;AAAA,IAC9E;AACA,QAAI,SAAS,WAAW,KAAK;AAC3B,YAAM,IAAI,MAAM,oBAAoB;AAAA,IACtC;AACA,UAAM,QAAS,MAAM,SAAS,KAAK;AACnC,UAAM,IAAI,MAAM,MAAM,SAAS,2BAA2B;AAAA,EAC5D;AACF;AASA,eAAsB,SAAS,SAGF;AAC3B,QAAM,QAAQ,cAAc;AAC5B,MAAI,CAAC,OAAO;AACV,UAAM,IAAI,MAAM,0CAA0C;AAAA,EAC5D;AAEA,QAAM,SAAS,IAAI,gBAAgB;AACnC,MAAI,SAAS,SAAS;AACpB,WAAO,IAAI,WAAW,QAAQ,OAAO;AAAA,EACvC;AACA,MAAI,SAAS,iBAAiB;AAC5B,WAAO,IAAI,mBAAmB,MAAM;AAAA,EACtC;AAEA,QAAM,MAAM,GAAG,WAAW,CAAC,mBAAmB,OAAO,SAAS,IAAI,IAAI,MAAM,KAAK,EAAE;AACnF,QAAM,WAAW,MAAM,MAAM,KAAK;AAAA,IAChC,SAAS;AAAA,MACP,eAAe,UAAU,KAAK;AAAA,IAChC;AAAA,EACF,CAAC;AAED,MAAI,CAAC,SAAS,IAAI;AAChB,QAAI,SAAS,WAAW,KAAK;AAC3B,YAAM,IAAI,MAAM,4DAA4D;AAAA,IAC9E;AACA,UAAM,QAAS,MAAM,SAAS,KAAK;AACnC,UAAM,IAAI,MAAM,MAAM,SAAS,qBAAqB;AAAA,EACtD;AAEA,QAAM,OAAQ,MAAM,SAAS,KAAK;AAClC,SAAO,KAAK;AACd;AAKA,eAAsB,OAAO,IAAoC;AAC/D,QAAM,QAAQ,cAAc;AAC5B,MAAI,CAAC,OAAO;AACV,UAAM,IAAI,MAAM,0CAA0C;AAAA,EAC5D;AAEA,QAAM,WAAW,MAAM,MAAM,GAAG,WAAW,CAAC,oBAAoB,EAAE,IAAI;AAAA,IACpE,SAAS;AAAA,MACP,eAAe,UAAU,KAAK;AAAA,IAChC;AAAA,EACF,CAAC;AAED,MAAI,CAAC,SAAS,IAAI;AAChB,QAAI,SAAS,WAAW,KAAK;AAC3B,YAAM,IAAI,MAAM,4DAA4D;AAAA,IAC9E;AACA,QAAI,SAAS,WAAW,KAAK;AAC3B,YAAM,IAAI,MAAM,0BAA0B;AAAA,IAC5C;AACA,UAAM,QAAS,MAAM,SAAS,KAAK;AACnC,UAAM,IAAI,MAAM,MAAM,SAAS,mBAAmB;AAAA,EACpD;AAEA,SAAQ,MAAM,SAAS,KAAK;AAC9B;AAKA,eAAsB,UAAU,SAAmD;AACjF,QAAM,QAAQ,cAAc;AAC5B,MAAI,CAAC,OAAO;AACV,UAAM,IAAI,MAAM,0CAA0C;AAAA,EAC5D;AAEA,QAAM,WAAW,MAAM,MAAM,GAAG,WAAW,CAAC,oBAAoB;AAAA,IAC9D,QAAQ;AAAA,IACR,SAAS;AAAA,MACP,eAAe,UAAU,KAAK;AAAA,MAC9B,gBAAgB;AAAA,IAClB;AAAA,IACA,MAAM,KAAK,UAAU,OAAO;AAAA,EAC9B,CAAC;AAED,MAAI,CAAC,SAAS,IAAI;AAChB,QAAI,SAAS,WAAW,KAAK;AAC3B,YAAM,IAAI,MAAM,4DAA4D;AAAA,IAC9E;AACA,QAAI,SAAS,WAAW,KAAK;AAC3B,YAAM,IAAI,MAAM,gDAAgD;AAAA,IAClE;AACA,UAAM,QAAS,MAAM,SAAS,KAAK;AACnC,UAAM,IAAI,MAAM,MAAM,SAAS,sBAAsB;AAAA,EACvD;AAEA,SAAQ,MAAM,SAAS,KAAK;AAC9B;AAKA,eAAsB,UACpB,IACA,SACwB;AACxB,QAAM,QAAQ,cAAc;AAC5B,MAAI,CAAC,OAAO;AACV,UAAM,IAAI,MAAM,0CAA0C;AAAA,EAC5D;AAEA,QAAM,WAAW,MAAM,MAAM,GAAG,WAAW,CAAC,oBAAoB,EAAE,IAAI;AAAA,IACpE,QAAQ;AAAA,IACR,SAAS;AAAA,MACP,eAAe,UAAU,KAAK;AAAA,MAC9B,gBAAgB;AAAA,IAClB;AAAA,IACA,MAAM,KAAK,UAAU,OAAO;AAAA,EAC9B,CAAC;AAED,MAAI,CAAC,SAAS,IAAI;AAChB,QAAI,SAAS,WAAW,KAAK;AAC3B,YAAM,IAAI,MAAM,4DAA4D;AAAA,IAC9E;AACA,QAAI,SAAS,WAAW,KAAK;AAC3B,YAAM,IAAI,MAAM,0BAA0B;AAAA,IAC5C;AACA,QAAI,SAAS,WAAW,KAAK;AAC3B,YAAM,IAAI,MAAM,gDAAgD;AAAA,IAClE;AACA,UAAM,QAAS,MAAM,SAAS,KAAK;AACnC,UAAM,IAAI,MAAM,MAAM,SAAS,sBAAsB;AAAA,EACvD;AAEA,SAAQ,MAAM,SAAS,KAAK;AAC9B;AAKA,eAAsB,UAAU,IAA2B;AACzD,QAAM,QAAQ,cAAc;AAC5B,MAAI,CAAC,OAAO;AACV,UAAM,IAAI,MAAM,0CAA0C;AAAA,EAC5D;AAEA,QAAM,WAAW,MAAM,MAAM,GAAG,WAAW,CAAC,oBAAoB,EAAE,IAAI;AAAA,IACpE,QAAQ;AAAA,IACR,SAAS;AAAA,MACP,eAAe,UAAU,KAAK;AAAA,IAChC;AAAA,EACF,CAAC;AAED,MAAI,CAAC,SAAS,IAAI;AAChB,QAAI,SAAS,WAAW,KAAK;AAC3B,YAAM,IAAI,MAAM,4DAA4D;AAAA,IAC9E;AACA,QAAI,SAAS,WAAW,KAAK;AAC3B,YAAM,IAAI,MAAM,0BAA0B;AAAA,IAC5C;AACA,UAAM,QAAS,MAAM,SAAS,KAAK;AACnC,UAAM,IAAI,MAAM,MAAM,SAAS,sBAAsB;AAAA,EACvD;AACF;AAKA,eAAsB,uBACpB,SACA,OAC4B;AAC5B,QAAM,QAAQ,cAAc;AAC5B,MAAI,CAAC,OAAO;AACV,UAAM,IAAI,MAAM,0CAA0C;AAAA,EAC5D;AAEA,QAAM,SAAS,IAAI,gBAAgB;AACnC,MAAI,SAAS;AACX,WAAO,IAAI,WAAW,OAAO;AAAA,EAC/B;AACA,MAAI,OAAO;AACT,WAAO,IAAI,SAAS,KAAK;AAAA,EAC3B;AAEA,QAAM,MAAM,GAAG,WAAW,CAAC,qCAAqC,OAAO,SAAS,IAAI,IAAI,MAAM,KAAK,EAAE;AACrG,QAAM,WAAW,MAAM,MAAM,KAAK;AAAA,IAChC,SAAS;AAAA,MACP,eAAe,UAAU,KAAK;AAAA,IAChC;AAAA,EACF,CAAC;AAED,MAAI,CAAC,SAAS,IAAI;AAChB,QAAI,SAAS,WAAW,KAAK;AAC3B,YAAM,IAAI,MAAM,4DAA4D;AAAA,IAC9E;AACA,UAAM,QAAS,MAAM,SAAS,KAAK;AACnC,UAAM,IAAI,MAAM,MAAM,SAAS,iCAAiC;AAAA,EAClE;AAEA,QAAM,OAAQ,MAAM,SAAS,KAAK;AAClC,SAAO,KAAK;AACd;AAKA,eAAsB,mBACpB,SACA,SACA,OACkC;AAClC,QAAM,QAAQ,cAAc;AAC5B,MAAI,CAAC,OAAO;AACV,UAAM,IAAI,MAAM,0CAA0C;AAAA,EAC5D;AAEA,QAAM,OAA2C,EAAE,SAAS,QAAQ;AACpE,MAAI,OAAO;AACT,SAAK,QAAQ;AAAA,EACf;AAEA,QAAM,WAAW,MAAM,MAAM,GAAG,WAAW,CAAC,6BAA6B;AAAA,IACvE,QAAQ;AAAA,IACR,SAAS;AAAA,MACP,eAAe,UAAU,KAAK;AAAA,MAC9B,gBAAgB;AAAA,IAClB;AAAA,IACA,MAAM,KAAK,UAAU,IAAI;AAAA,EAC3B,CAAC;AAED,MAAI,CAAC,SAAS,IAAI;AAChB,QAAI,SAAS,WAAW,KAAK;AAC3B,YAAM,IAAI,MAAM,4DAA4D;AAAA,IAC9E;AACA,UAAM,QAAS,MAAM,SAAS,KAAK;AACnC,UAAM,IAAI,MAAM,MAAM,SAAS,4BAA4B;AAAA,EAC7D;AAEA,SAAQ,MAAM,SAAS,KAAK;AAC9B;AAoBA,eAAsB,yBACpB,oBACA,QACwC;AAGxC,QAAM,qBAAqB,mBAAmB,QAAQ,QAAQ,EAAE;AAChE,QAAM,MAAM,GAAG,kBAAkB;AAEjC,QAAM,aAAa,IAAI,gBAAgB;AACvC,QAAM,UAAU,WAAW,MAAM,WAAW,MAAM,GAAG,GAAI;AAEzD,MAAI;AACF,UAAM,WAAW,MAAM,MAAM,KAAK;AAAA,MAChC,QAAQ;AAAA,MACR,SAAS;AAAA,QACP,aAAa;AAAA,MACf;AAAA,MACA,QAAQ,WAAW;AAAA,IACrB,CAAC;AAED,QAAI,CAAC,SAAS,IAAI;AAChB,aAAO;AAAA,IACT;AAEA,UAAM,OAAQ,MAAM,SAAS,KAAK;AAClC,QACE,OAAO,MAAM,cAAc,YAC3B,OAAO,MAAM,aAAa,UAC1B;AACA,aAAO;AAAA,IACT;AAEA,WAAO,EAAE,WAAW,KAAK,WAAW,UAAU,KAAK,SAAS;AAAA,EAC9D,QAAQ;AAGN,WAAO;AAAA,EACT,UAAE;AACA,iBAAa,OAAO;AAAA,EACtB;AACF;AAqGA,eAAsB,aACpB,UAA+B,CAAC,GACD;AAC/B,QAAM,QAAQ,cAAc;AAC5B,MAAI,CAAC,OAAO;AACV,UAAM,IAAI,MAAM,0CAA0C;AAAA,EAC5D;AAEA,QAAM,SAAS,IAAI,gBAAgB;AACnC,MAAI,QAAQ,QAAS,QAAO,IAAI,WAAW,QAAQ,OAAO;AAC1D,MAAI,QAAQ,WAAY,QAAO,IAAI,cAAc,QAAQ,UAAU;AACnE,MAAI,QAAQ,MAAO,QAAO,IAAI,SAAS,QAAQ,KAAK;AACpD,MAAI,QAAQ,MAAO,QAAO,IAAI,SAAS,QAAQ,KAAK;AACpD,MAAI,QAAQ,UAAU,OAAW,QAAO,IAAI,SAAS,OAAO,QAAQ,KAAK,CAAC;AAC1E,MAAI,QAAQ,WAAW,OAAW,QAAO,IAAI,UAAU,OAAO,QAAQ,MAAM,CAAC;AAC7E,MAAI,QAAQ,eAAgB,QAAO,IAAI,kBAAkB,MAAM;AAC/D,MAAI,QAAQ,iBAAkB,QAAO,IAAI,oBAAoB,MAAM;AAEnE,QAAM,MAAM,GAAG,WAAW,CAAC,wBAAwB,OAAO,SAAS,IAAI,IAAI,MAAM,KAAK,EAAE;AACxF,QAAM,WAAW,MAAM,MAAM,KAAK;AAAA,IAChC,SAAS;AAAA,MACP,eAAe,UAAU,KAAK;AAAA,IAChC;AAAA,EACF,CAAC;AAED,MAAI,CAAC,SAAS,IAAI;AAChB,QAAI,SAAS,WAAW,KAAK;AAC3B,YAAM,IAAI,MAAM,4DAA4D;AAAA,IAC9E;AACA,UAAM,QAAS,MAAM,SAAS,KAAK;AACnC,UAAM,IAAI,MAAM,MAAM,SAAS,yBAAyB;AAAA,EAC1D;AAEA,SAAQ,MAAM,SAAS,KAAK;AAC9B;AAKA,eAAsB,YACpB,IACA,gBACyB;AACzB,QAAM,QAAQ,cAAc;AAC5B,MAAI,CAAC,OAAO;AACV,UAAM,IAAI,MAAM,0CAA0C;AAAA,EAC5D;AAEA,QAAM,SAAS,IAAI,gBAAgB;AACnC,MAAI,eAAgB,QAAO,IAAI,kBAAkB,MAAM;AAEvD,QAAM,MAAM,GAAG,WAAW,CAAC,yBAAyB,EAAE,GAAG,OAAO,SAAS,IAAI,IAAI,MAAM,KAAK,EAAE;AAC9F,QAAM,WAAW,MAAM,MAAM,KAAK;AAAA,IAChC,SAAS;AAAA,MACP,eAAe,UAAU,KAAK;AAAA,IAChC;AAAA,EACF,CAAC;AAED,MAAI,CAAC,SAAS,IAAI;AAChB,QAAI,SAAS,WAAW,KAAK;AAC3B,YAAM,IAAI,MAAM,4DAA4D;AAAA,IAC9E;AACA,QAAI,SAAS,WAAW,KAAK;AAC3B,YAAM,IAAI,MAAM,0BAA0B;AAAA,IAC5C;AACA,UAAM,QAAS,MAAM,SAAS,KAAK;AACnC,UAAM,IAAI,MAAM,MAAM,SAAS,wBAAwB;AAAA,EACzD;AAEA,SAAQ,MAAM,SAAS,KAAK;AAC9B;AAKA,eAAsB,gBACpB,SAC+B;AAC/B,QAAM,QAAQ,cAAc;AAC5B,MAAI,CAAC,OAAO;AACV,UAAM,IAAI,MAAM,0CAA0C;AAAA,EAC5D;AAEA,MAAI,CAAC,QAAQ,WAAW,CAAC,QAAQ,YAAY;AAC3C,UAAM,IAAI,MAAM,0CAA0C;AAAA,EAC5D;AAEA,QAAM,SAAS,IAAI,gBAAgB;AACnC,MAAI,QAAQ,QAAS,QAAO,IAAI,WAAW,QAAQ,OAAO;AAC1D,MAAI,QAAQ,WAAY,QAAO,IAAI,cAAc,QAAQ,UAAU;AACnE,MAAI,QAAQ,MAAO,QAAO,IAAI,SAAS,QAAQ,KAAK;AACpD,MAAI,QAAQ,MAAO,QAAO,IAAI,SAAS,QAAQ,KAAK;AACpD,MAAI,QAAQ,OAAQ,QAAO,IAAI,UAAU,QAAQ,MAAM;AACvD,MAAI,QAAQ,aAAc,QAAO,IAAI,gBAAgB,MAAM;AAE3D,QAAM,MAAM,GAAG,WAAW,CAAC,qBAAqB,OAAO,SAAS,IAAI,IAAI,MAAM,KAAK,EAAE;AACrF,QAAM,WAAW,MAAM,MAAM,KAAK;AAAA,IAChC,SAAS;AAAA,MACP,eAAe,UAAU,KAAK;AAAA,IAChC;AAAA,EACF,CAAC;AAED,MAAI,CAAC,SAAS,IAAI;AAChB,QAAI,SAAS,WAAW,KAAK;AAC3B,YAAM,IAAI,MAAM,4DAA4D;AAAA,IAC9E;AACA,UAAM,QAAS,MAAM,SAAS,KAAK;AACnC,UAAM,IAAI,MAAM,MAAM,SAAS,6BAA6B;AAAA,EAC9D;AAEA,SAAQ,MAAM,SAAS,KAAK;AAC9B;AA0CA,eAAsB,aACpB,SAC+B;AAC/B,QAAM,QAAQ,cAAc;AAC5B,MAAI,CAAC,OAAO;AACV,UAAM,IAAI,MAAM,0CAA0C;AAAA,EAC5D;AAEA,QAAM,SAAS,IAAI,gBAAgB;AACnC,SAAO,IAAI,WAAW,QAAQ,OAAO;AACrC,MAAI,QAAQ,MAAO,QAAO,IAAI,SAAS,QAAQ,KAAK;AACpD,MAAI,QAAQ,MAAO,QAAO,IAAI,SAAS,QAAQ,KAAK;AACpD,MAAI,QAAQ,UAAU,OAAW,QAAO,IAAI,SAAS,OAAO,QAAQ,KAAK,CAAC;AAC1E,MAAI,QAAQ,WAAW,OAAW,QAAO,IAAI,UAAU,OAAO,QAAQ,MAAM,CAAC;AAE7E,QAAM,MAAM,GAAG,WAAW,CAAC,0BAA0B,MAAM;AAC3D,QAAM,WAAW,MAAM,MAAM,KAAK;AAAA,IAChC,SAAS;AAAA,MACP,eAAe,UAAU,KAAK;AAAA,IAChC;AAAA,EACF,CAAC;AAED,MAAI,CAAC,SAAS,IAAI;AAChB,QAAI,SAAS,WAAW,KAAK;AAC3B,YAAM,IAAI,MAAM,4DAA4D;AAAA,IAC9E;AACA,UAAM,QAAS,MAAM,SAAS,KAAK;AACnC,UAAM,IAAI,MAAM,MAAM,SAAS,yBAAyB;AAAA,EAC1D;AAEA,SAAQ,MAAM,SAAS,KAAK;AAC9B;AAmCA,eAAsB,sBAAsB,SAA+C;AACzF,QAAM,QAAQ,cAAc;AAC5B,MAAI,CAAC,OAAO;AACV,UAAM,IAAI,MAAM,0CAA0C;AAAA,EAC5D;AAEA,QAAM,SAAS,IAAI,gBAAgB;AACnC,MAAI,SAAS;AACX,WAAO,IAAI,WAAW,OAAO;AAAA,EAC/B;AAEA,QAAM,MAAM,GAAG,WAAW,CAAC,0BAA0B,OAAO,SAAS,IAAI,IAAI,MAAM,KAAK,EAAE;AAC1F,QAAM,WAAW,MAAM,MAAM,KAAK;AAAA,IAChC,SAAS;AAAA,MACP,eAAe,UAAU,KAAK;AAAA,IAChC;AAAA,EACF,CAAC;AAED,MAAI,CAAC,SAAS,IAAI;AAChB,QAAI,SAAS,WAAW,KAAK;AAC3B,YAAM,IAAI,MAAM,4DAA4D;AAAA,IAC9E;AACA,UAAM,QAAS,MAAM,SAAS,KAAK;AACnC,UAAM,IAAI,MAAM,MAAM,SAAS,2CAA2C;AAAA,EAC5E;AAEA,QAAM,OAAQ,MAAM,SAAS,KAAK;AAClC,SAAO,KAAK;AACd;AAKA,eAAsB,oBAAoB,IAAuC;AAC/E,QAAM,QAAQ,cAAc;AAC5B,MAAI,CAAC,OAAO;AACV,UAAM,IAAI,MAAM,0CAA0C;AAAA,EAC5D;AAEA,QAAM,MAAM,GAAG,WAAW,CAAC,2BAA2B,mBAAmB,EAAE,CAAC;AAC5E,QAAM,WAAW,MAAM,MAAM,KAAK;AAAA,IAChC,SAAS;AAAA,MACP,eAAe,UAAU,KAAK;AAAA,IAChC;AAAA,EACF,CAAC;AAED,MAAI,CAAC,SAAS,IAAI;AAChB,QAAI,SAAS,WAAW,KAAK;AAC3B,YAAM,IAAI,MAAM,4DAA4D;AAAA,IAC9E;AACA,QAAI,SAAS,WAAW,KAAK;AAC3B,YAAM,IAAI,MAAM,qCAAqC;AAAA,IACvD;AACA,UAAM,QAAS,MAAM,SAAS,KAAK;AACnC,UAAM,IAAI,MAAM,MAAM,SAAS,yCAAyC;AAAA,EAC1E;AAEA,SAAQ,MAAM,SAAS,KAAK;AAC9B;AAKA,eAAsB,uBACpB,SAC2B;AAC3B,QAAM,QAAQ,cAAc;AAC5B,MAAI,CAAC,OAAO;AACV,UAAM,IAAI,MAAM,0CAA0C;AAAA,EAC5D;AAEA,QAAM,MAAM,GAAG,WAAW,CAAC;AAC3B,QAAM,WAAW,MAAM,MAAM,KAAK;AAAA,IAChC,QAAQ;AAAA,IACR,SAAS;AAAA,MACP,eAAe,UAAU,KAAK;AAAA,MAC9B,gBAAgB;AAAA,IAClB;AAAA,IACA,MAAM,KAAK,UAAU,OAAO;AAAA,EAC9B,CAAC;AAED,MAAI,CAAC,SAAS,IAAI;AAChB,QAAI,SAAS,WAAW,KAAK;AAC3B,YAAM,IAAI,MAAM,4DAA4D;AAAA,IAC9E;AACA,QAAI,SAAS,WAAW,KAAK;AAC3B,YAAM,IAAI,MAAM,2DAA2D;AAAA,IAC7E;AACA,UAAM,QAAS,MAAM,SAAS,KAAK;AACnC,UAAM,IAAI,MAAM,MAAM,SAAS,4CAA4C;AAAA,EAC7E;AAEA,SAAQ,MAAM,SAAS,KAAK;AAC9B;AAKA,eAAsB,uBACpB,IACA,SAC2B;AAC3B,QAAM,QAAQ,cAAc;AAC5B,MAAI,CAAC,OAAO;AACV,UAAM,IAAI,MAAM,0CAA0C;AAAA,EAC5D;AAEA,QAAM,MAAM,GAAG,WAAW,CAAC,2BAA2B,mBAAmB,EAAE,CAAC;AAC5E,QAAM,WAAW,MAAM,MAAM,KAAK;AAAA,IAChC,QAAQ;AAAA,IACR,SAAS;AAAA,MACP,eAAe,UAAU,KAAK;AAAA,MAC9B,gBAAgB;AAAA,IAClB;AAAA,IACA,MAAM,KAAK,UAAU,OAAO;AAAA,EAC9B,CAAC;AAED,MAAI,CAAC,SAAS,IAAI;AAChB,QAAI,SAAS,WAAW,KAAK;AAC3B,YAAM,IAAI,MAAM,4DAA4D;AAAA,IAC9E;AACA,QAAI,SAAS,WAAW,KAAK;AAC3B,YAAM,IAAI,MAAM,qCAAqC;AAAA,IACvD;AACA,QAAI,SAAS,WAAW,KAAK;AAC3B,YAAM,IAAI,MAAM,2DAA2D;AAAA,IAC7E;AACA,UAAM,QAAS,MAAM,SAAS,KAAK;AACnC,UAAM,IAAI,MAAM,MAAM,SAAS,4CAA4C;AAAA,EAC7E;AAEA,SAAQ,MAAM,SAAS,KAAK;AAC9B;AAKA,eAAsB,uBAAuB,IAA2B;AACtE,QAAM,QAAQ,cAAc;AAC5B,MAAI,CAAC,OAAO;AACV,UAAM,IAAI,MAAM,0CAA0C;AAAA,EAC5D;AAEA,QAAM,MAAM,GAAG,WAAW,CAAC,2BAA2B,mBAAmB,EAAE,CAAC;AAC5E,QAAM,WAAW,MAAM,MAAM,KAAK;AAAA,IAChC,QAAQ;AAAA,IACR,SAAS;AAAA,MACP,eAAe,UAAU,KAAK;AAAA,IAChC;AAAA,EACF,CAAC;AAED,MAAI,CAAC,SAAS,IAAI;AAChB,QAAI,SAAS,WAAW,KAAK;AAC3B,YAAM,IAAI,MAAM,4DAA4D;AAAA,IAC9E;AACA,QAAI,SAAS,WAAW,KAAK;AAC3B,YAAM,IAAI,MAAM,qCAAqC;AAAA,IACvD;AACA,UAAM,QAAS,MAAM,SAAS,KAAK;AACnC,UAAM,IAAI,MAAM,MAAM,SAAS,4CAA4C;AAAA,EAC7E;AACF;;;ADl1CA,IAAM,mBAAmB;AAKzB,eAAsB,eAA8B;AAElD,MAAI,aAAa,GAAG;AAClB,QAAI;AACF,YAAM,OAAO,MAAM,eAAe;AAClC,cAAQ,IAAI,wBAAwB,KAAK,KAAK,EAAE;AAChD,cAAQ,IAAI,uCAAuC;AACnD;AAAA,IACF,QAAQ;AAAA,IAER;AAAA,EACF;AAEA,UAAQ,IAAI,yBAAyB,eAAe,CAAC;AAAA,CAAQ;AAE7D,MAAI;AAEF,UAAM,aAAa,MAAM,kBAAkB;AAG3C,YAAQ,IAAI,2BAA2B;AACvC,YAAQ,IAAI;AAAA,IAAO,WAAW,yBAAyB;AAAA,CAAI;AAC3D,YAAQ,IAAI,YAAY,WAAW,gBAAgB,kBAAkB;AACrE,YAAQ,IAAI;AAAA,IAAO,WAAW,SAAS;AAAA,CAAI;AAG3C,YAAQ,IAAI,oBAAoB;AAChC,QAAI;AACF,YAAM,KAAK,WAAW,yBAAyB;AAAA,IACjD,QAAQ;AACN,cAAQ,IAAI,wCAAwC;AAAA,IACtD;AAEA,YAAQ,IAAI,gCAAgC;AAG5C,UAAM,YAAY,KAAK,IAAI,IAAI,WAAW,aAAa;AAEvD,WAAO,KAAK,IAAI,IAAI,WAAW;AAC7B,YAAM,MAAM,gBAAgB;AAE5B,UAAI;AACF,cAAM,gBAAgB,MAAM,aAAa,WAAW,WAAW;AAE/D,YAAI,eAAe;AAEjB,oBAAU,cAAc,cAAc,cAAc,UAAU;AAG9D,gBAAM,OAAO,MAAM,eAAe;AAElC,kBAAQ,IAAI;AAAA,eAAkB,KAAK,KAAK,EAAE;AAC1C,kBAAQ,IAAI,YAAY,KAAK,SAAS,EAAE;AACxC,kBAAQ,IAAI,SAAS,KAAK,IAAI,EAAE;AAChC;AAAA,QACF;AAGA,gBAAQ,OAAO,MAAM,GAAG;AAAA,MAC1B,SAAS,OAAO;AACd,YAAI,iBAAiB,OAAO;AAC1B,kBAAQ,MAAM;AAAA,gBAAmB,MAAM,OAAO,EAAE;AAAA,QAClD,OAAO;AACL,kBAAQ,MAAM,+BAA+B;AAAA,QAC/C;AACA,gBAAQ,KAAK,CAAC;AAAA,MAChB;AAAA,IACF;AAEA,YAAQ,MAAM,sCAAsC;AACpD,YAAQ,KAAK,CAAC;AAAA,EAChB,SAAS,OAAO;AACd,QAAI,iBAAiB,OAAO;AAC1B,cAAQ,MAAM,iBAAiB,MAAM,OAAO,EAAE;AAAA,IAChD,OAAO;AACL,cAAQ,MAAM,6BAA6B;AAAA,IAC7C;AACA,YAAQ,KAAK,CAAC;AAAA,EAChB;AACF;AAEA,SAAS,MAAM,IAA2B;AACxC,SAAO,IAAI,QAAQ,CAAC,YAAY,WAAW,SAAS,EAAE,CAAC;AACzD;;;AExFO,SAAS,gBAAsB;AACpC,MAAI,CAAC,aAAa,GAAG;AACnB,YAAQ,IAAI,0BAA0B;AACtC;AAAA,EACF;AAEA,aAAW;AACX,UAAQ,IAAI,0BAA0B;AACxC;;;ACNA,eAAsB,gBAA+B;AACnD,MAAI,CAAC,aAAa,GAAG;AACnB,YAAQ,IAAI,oDAAoD;AAChE,YAAQ,KAAK,CAAC;AAAA,EAChB;AAEA,MAAI;AACF,UAAM,OAAO,MAAM,eAAe;AAElC,YAAQ,IAAI,eAAe,KAAK,KAAK,EAAE;AACvC,YAAQ,IAAI,eAAe,KAAK,SAAS,IAAI,KAAK,QAAQ,EAAE;AAC5D,YAAQ,IAAI,eAAe,KAAK,IAAI,EAAE;AACtC,YAAQ,IAAI,eAAe,KAAK,SAAS,EAAE;AAC3C,YAAQ,IAAI,gBAAgB,eAAe,CAAC,EAAE;AAAA,EAChD,SAAS,OAAO;AACd,QAAI,iBAAiB,OAAO;AAC1B,cAAQ,MAAM,UAAU,MAAM,OAAO,EAAE;AAAA,IACzC,OAAO;AACL,cAAQ,MAAM,yBAAyB;AAAA,IACzC;AACA,YAAQ,KAAK,CAAC;AAAA,EAChB;AACF;;;ACnBA,SAAS,iBAAiB,QAAuB;AAC/C,MAAI,OAAO,WAAW,GAAG;AACvB,YAAQ,IAAI,kBAAkB;AAC9B;AAAA,EACF;AAGA,QAAM,UAAU,CAAC,MAAM,QAAQ,QAAQ,YAAY,SAAS;AAC5D,QAAM,OAAO,OAAO,IAAI,CAAC,UAAU;AAAA,IACjC,MAAM,GAAG,MAAM,GAAG,EAAE,IAAI;AAAA,IACxB,MAAM,KAAK,MAAM,GAAG,EAAE;AAAA,IACtB,MAAM;AAAA,IACN,MAAM,aAAa,MAAM,WAAW,MAAM,GAAG,EAAE,IAAI,QAAQ;AAAA,IAC3D,MAAM,SAAU,MAAM,OAAO,WAAW,WAAW,aAAc;AAAA,EACnE,CAAC;AAED,QAAM,SAAS,QAAQ;AAAA,IAAI,CAAC,GAAG,MAC7B,KAAK,IAAI,EAAE,QAAQ,GAAG,KAAK,IAAI,CAAC,MAAM,EAAE,CAAC,EAAE,MAAM,CAAC;AAAA,EACpD;AAGA,UAAQ,IAAI,QAAQ,IAAI,CAAC,GAAG,MAAM,EAAE,OAAO,OAAO,CAAC,CAAC,CAAC,EAAE,KAAK,IAAI,CAAC;AACjE,UAAQ,IAAI,OAAO,IAAI,CAAC,MAAM,IAAI,OAAO,CAAC,CAAC,EAAE,KAAK,IAAI,CAAC;AAGvD,aAAW,OAAO,MAAM;AACtB,YAAQ,IAAI,IAAI,IAAI,CAAC,MAAM,MAAM,KAAK,OAAO,OAAO,CAAC,CAAC,CAAC,EAAE,KAAK,IAAI,CAAC;AAAA,EACrE;AACF;AAEA,SAAS,kBAAkB,OAAoB;AAC7C,UAAQ,IAAI,gBAAgB,MAAM,EAAE,EAAE;AACtC,UAAQ,IAAI,gBAAgB,MAAM,IAAI,EAAE;AACxC,UAAQ,IAAI,gBAAgB,MAAM,eAAe,GAAG,EAAE;AACtD,UAAQ,IAAI,gBAAgB,MAAM,IAAI,EAAE;AACxC,UAAQ,IAAI,gBAAgB,MAAM,MAAM,EAAE;AAC1C,UAAQ,IAAI,gBAAgB,MAAM,YAAY,GAAG,EAAE;AACnD,UAAQ,IAAI,gBAAgB,MAAM,cAAc,GAAG,EAAE;AAErD,MAAI,MAAM,UAAU;AAClB,YAAQ,IAAI,gBAAgB,MAAM,SAAS,IAAI,EAAE;AAAA,EACnD;AAEA,UAAQ,IAAI,EAAE;AACd,UAAQ,IAAI,UAAU;AACtB,MAAI,MAAM,QAAQ;AAChB,YAAQ,IAAI,gBAAgB,MAAM,OAAO,EAAE,EAAE;AAC7C,QAAI,MAAM,OAAO,KAAK;AACpB,cAAQ,IAAI,gBAAgB,MAAM,OAAO,GAAG,EAAE;AAAA,IAChD,OAAO;AACL,cAAQ,IAAI,gBAAgB,MAAM,OAAO,SAAS,EAAE;AAAA,IACtD;AACA,YAAQ,IAAI,gBAAgB,MAAM,OAAO,WAAW,WAAW,UAAU,EAAE;AAAA,EAC7E,OAAO;AACL,YAAQ,IAAI,QAAQ;AAAA,EACtB;AAEA,MAAI,MAAM,kBAAkB,MAAM,eAAe,SAAS,GAAG;AAC3D,YAAQ,IAAI,EAAE;AACd,YAAQ,IAAI,kBAAkB;AAC9B,eAAW,OAAO,MAAM,gBAAgB;AACtC,cAAQ,IAAI,OAAO,IAAI,IAAI,KAAK,IAAI,IAAI,GAAG;AAAA,IAC7C;AAAA,EACF;AACF;AAEA,eAAe,YAAY,SAGT;AAChB,MAAI;AACF,UAAM,SAAS,MAAM,WAAW,EAAE,aAAa,QAAQ,YAAY,CAAC;AAEpE,QAAI,QAAQ,MAAM;AAChB,cAAQ,IAAI,KAAK,UAAU,QAAQ,MAAM,CAAC,CAAC;AAAA,IAC7C,OAAO;AACL,uBAAiB,MAAM;AAAA,IACzB;AAAA,EACF,SAAS,OAAO;AACd,YAAQ;AAAA,MACN,UAAU,iBAAiB,QAAQ,MAAM,UAAU,eAAe;AAAA,IACpE;AACA,YAAQ,KAAK,CAAC;AAAA,EAChB;AACF;AAEA,eAAe,WAAW,IAAY,SAA4C;AAChF,MAAI;AACF,UAAM,QAAQ,MAAM,SAAS,EAAE;AAE/B,QAAI,QAAQ,MAAM;AAChB,cAAQ,IAAI,KAAK,UAAU,OAAO,MAAM,CAAC,CAAC;AAAA,IAC5C,OAAO;AACL,wBAAkB,KAAK;AAAA,IACzB;AAAA,EACF,SAAS,OAAO;AACd,YAAQ;AAAA,MACN,UAAU,iBAAiB,QAAQ,MAAM,UAAU,eAAe;AAAA,IACpE;AACA,YAAQ,KAAK,CAAC;AAAA,EAChB;AACF;AAEA,eAAe,cAAc,SAQX;AAChB,MAAI;AACF,QAAI,CAAC,QAAQ,MAAM;AACjB,cAAQ,MAAM,2BAA2B;AACzC,cAAQ,KAAK,CAAC;AAAA,IAChB;AAEA,UAAM,QAAQ,MAAM,YAAY;AAAA,MAC9B,MAAM,QAAQ;AAAA,MACd,aAAa,QAAQ,eAAe;AAAA,MACpC,MAAO,QAAQ,QAAqC;AAAA,MACpD,YAAY,QAAQ;AAAA,MACpB,cAAc,QAAQ,cAAc;AAAA,MACpC,UAAU,QAAQ;AAAA,IACpB,CAAC;AAED,QAAI,QAAQ,MAAM;AAChB,cAAQ,IAAI,KAAK,UAAU,OAAO,MAAM,CAAC,CAAC;AAAA,IAC5C,OAAO;AACL,cAAQ,IAAI,6BAA6B;AACzC,cAAQ,IAAI,EAAE;AACd,wBAAkB,KAAK;AAEvB,UAAI,MAAM,QAAQ,KAAK;AACrB,gBAAQ,IAAI,EAAE;AACd,gBAAQ;AAAA,UACN;AAAA,QACF;AAAA,MACF;AAAA,IACF;AAAA,EACF,SAAS,OAAO;AACd,YAAQ;AAAA,MACN,UAAU,iBAAiB,QAAQ,MAAM,UAAU,eAAe;AAAA,IACpE;AACA,YAAQ,KAAK,CAAC;AAAA,EAChB;AACF;AAEA,eAAe,cACb,IACA,SAQe;AACf,MAAI;AACF,UAAM,UAMF,CAAC;AAEL,QAAI,QAAQ,SAAS,OAAW,SAAQ,OAAO,QAAQ;AACvD,QAAI,QAAQ,gBAAgB;AAC1B,cAAQ,cAAc,QAAQ;AAChC,QAAI,QAAQ,SAAS;AACnB,cAAQ,OAAO,QAAQ;AACzB,QAAI,QAAQ,aAAa,OAAW,SAAQ,aAAa,QAAQ;AACjE,QAAI,QAAQ,aAAa,OAAW,SAAQ,WAAW,QAAQ;AAE/D,QAAI,OAAO,KAAK,OAAO,EAAE,WAAW,GAAG;AACrC,cAAQ,MAAM,iDAAiD;AAC/D,cAAQ,KAAK,CAAC;AAAA,IAChB;AAEA,UAAM,QAAQ,MAAM,YAAY,IAAI,OAAO;AAE3C,QAAI,QAAQ,MAAM;AAChB,cAAQ,IAAI,KAAK,UAAU,OAAO,MAAM,CAAC,CAAC;AAAA,IAC5C,OAAO;AACL,cAAQ,IAAI,6BAA6B;AACzC,cAAQ,IAAI,EAAE;AACd,wBAAkB,KAAK;AAAA,IACzB;AAAA,EACF,SAAS,OAAO;AACd,YAAQ;AAAA,MACN,UAAU,iBAAiB,QAAQ,MAAM,UAAU,eAAe;AAAA,IACpE;AACA,YAAQ,KAAK,CAAC;AAAA,EAChB;AACF;AAEA,eAAe,cACb,IACA,SACe;AACf,MAAI;AACF,QAAI,CAAC,QAAQ,OAAO;AAGlB,cAAQ,IAAI,6CAA6C;AACzD,cAAQ,IAAI,kCAAkC;AAC9C,cAAQ,KAAK,CAAC;AAAA,IAChB;AAEA,UAAM,YAAY,EAAE;AACpB,YAAQ,IAAI,6BAA6B;AAAA,EAC3C,SAAS,OAAO;AACd,YAAQ;AAAA,MACN,UAAU,iBAAiB,QAAQ,MAAM,UAAU,eAAe;AAAA,IACpE;AACA,YAAQ,KAAK,CAAC;AAAA,EAChB;AACF;AAEO,SAAS,sBAAsBA,UAAwB;AAC5D,QAAM,SAASA,SACZ,QAAQ,QAAQ,EAChB,YAAY,eAAe;AAE9B,SACG,QAAQ,MAAM,EACd,YAAY,iBAAiB,EAC7B,OAAO,UAAU,gBAAgB,EACjC,OAAO,kBAAkB,yBAAyB,EAClD,OAAO,WAAW;AAErB,SACG,QAAQ,UAAU,EAClB,YAAY,mBAAmB,EAC/B,OAAO,UAAU,gBAAgB,EACjC,OAAO,UAAU;AAEpB,SACG,QAAQ,QAAQ,EAChB,YAAY,oBAAoB,EAChC,eAAe,iBAAiB,YAAY,EAC5C,OAAO,+BAA+B,mBAAmB,EACzD,OAAO,iBAAiB,sCAAsC,QAAQ,EACtE,OAAO,mBAAmB,uBAAuB,EACjD,OAAO,kBAAkB,kCAAkC,EAC3D,OAAO,yBAAyB,gBAAgB,EAChD,OAAO,UAAU,gBAAgB,EACjC,OAAO,aAAa;AAEvB,SACG,QAAQ,aAAa,EACrB,YAAY,iBAAiB,EAC7B,OAAO,iBAAiB,YAAY,EACpC,OAAO,+BAA+B,mBAAmB,EACzD,OAAO,iBAAiB,oCAAoC,EAC5D,OAAO,mBAAmB,uBAAuB,EACjD,OAAO,yBAAyB,gBAAgB,EAChD,OAAO,UAAU,gBAAgB,EACjC,OAAO,aAAa;AAEvB,SACG,QAAQ,aAAa,EACrB,YAAY,iBAAiB,EAC7B,OAAO,WAAW,mBAAmB,EACrC,OAAO,aAAa;AACzB;;;AC5QA,SAAS,oBAAoB,WAA6B;AACxD,MAAI,UAAU,WAAW,GAAG;AAC1B,YAAQ,IAAI,qBAAqB;AACjC;AAAA,EACF;AAGA,QAAM,UAAU,CAAC,MAAM,QAAQ,UAAU,QAAQ;AACjD,QAAM,OAAO,UAAU,IAAI,CAAC,OAAO;AAAA,IACjC,GAAG,GAAG,MAAM,GAAG,EAAE,IAAI;AAAA,IACrB,GAAG,KAAK,MAAM,GAAG,EAAE;AAAA,IACnB,GAAG,WAAW,SAAS;AAAA,IACvB,GAAG,WAAW,WAAW;AAAA,EAC3B,CAAC;AAED,QAAM,SAAS,QAAQ;AAAA,IAAI,CAAC,GAAG,MAC7B,KAAK,IAAI,EAAE,QAAQ,GAAG,KAAK,IAAI,CAAC,MAAM,EAAE,CAAC,EAAE,MAAM,CAAC;AAAA,EACpD;AAGA,UAAQ,IAAI,QAAQ,IAAI,CAAC,GAAG,MAAM,EAAE,OAAO,OAAO,CAAC,CAAC,CAAC,EAAE,KAAK,IAAI,CAAC;AACjE,UAAQ,IAAI,OAAO,IAAI,CAAC,MAAM,IAAI,OAAO,CAAC,CAAC,EAAE,KAAK,IAAI,CAAC;AAGvD,aAAW,OAAO,MAAM;AACtB,YAAQ,IAAI,IAAI,IAAI,CAAC,MAAM,MAAM,KAAK,OAAO,OAAO,CAAC,CAAC,CAAC,EAAE,KAAK,IAAI,CAAC;AAAA,EACrE;AACF;AAEA,SAAS,qBAAqB,UAA0B;AACtD,UAAQ,IAAI,gBAAgB,SAAS,EAAE,EAAE;AACzC,UAAQ,IAAI,gBAAgB,SAAS,IAAI,EAAE;AAC3C,UAAQ,IAAI,gBAAgB,SAAS,eAAe,GAAG,EAAE;AACzD,UAAQ,IAAI,gBAAgB,SAAS,WAAW,WAAW,UAAU,EAAE;AACvE,UAAQ,IAAI,gBAAgB,SAAS,UAAU,EAAE;AACjD,MAAI,SAAS,WAAW;AACtB,YAAQ,IAAI,gBAAgB,IAAI,KAAK,SAAS,SAAS,EAAE,YAAY,CAAC,EAAE;AAAA,EAC1E;AACA,MAAI,SAAS,WAAW;AACtB,YAAQ,IAAI,gBAAgB,IAAI,KAAK,SAAS,SAAS,EAAE,YAAY,CAAC,EAAE;AAAA,EAC1E;AAEA,MAAI,SAAS,UAAU,SAAS,OAAO,SAAS,GAAG;AACjD,YAAQ,IAAI,EAAE;AACd,YAAQ,IAAI,SAAS;AACrB,eAAW,SAAS,SAAS,QAAQ;AACnC,YAAM,eAAe,MAAM,SACvB,MAAM,OAAO,WACX,oBACA,sBACF;AACJ,cAAQ,IAAI,OAAO,MAAM,IAAI,KAAK,MAAM,IAAI,OAAO,YAAY,EAAE;AAAA,IACnE;AAAA,EACF;AACF;AAEA,eAAeC,aAAY,SAIT;AAChB,MAAI;AACF,UAAM,YAAY,MAAM,cAAc;AAAA,MACpC,eAAe,QAAQ;AAAA,MACvB,iBAAiB,QAAQ;AAAA,IAC3B,CAAC;AAED,QAAI,QAAQ,MAAM;AAChB,cAAQ,IAAI,KAAK,UAAU,WAAW,MAAM,CAAC,CAAC;AAAA,IAChD,OAAO;AACL,0BAAoB,SAAS;AAAA,IAC/B;AAAA,EACF,SAAS,OAAO;AACd,YAAQ;AAAA,MACN,UAAU,iBAAiB,QAAQ,MAAM,UAAU,eAAe;AAAA,IACpE;AACA,YAAQ,KAAK,CAAC;AAAA,EAChB;AACF;AAEA,eAAeC,YAAW,IAAY,SAA4C;AAChF,MAAI;AACF,UAAM,WAAW,MAAM,YAAY,EAAE;AAErC,QAAI,QAAQ,MAAM;AAChB,cAAQ,IAAI,KAAK,UAAU,UAAU,MAAM,CAAC,CAAC;AAAA,IAC/C,OAAO;AACL,2BAAqB,QAAQ;AAAA,IAC/B;AAAA,EACF,SAAS,OAAO;AACd,YAAQ;AAAA,MACN,UAAU,iBAAiB,QAAQ,MAAM,UAAU,eAAe;AAAA,IACpE;AACA,YAAQ,KAAK,CAAC;AAAA,EAChB;AACF;AAEA,eAAeC,eAAc,SAIX;AAChB,MAAI;AACF,QAAI,CAAC,QAAQ,MAAM;AACjB,cAAQ,MAAM,2BAA2B;AACzC,cAAQ,KAAK,CAAC;AAAA,IAChB;AAEA,UAAM,WAAW,MAAM,eAAe;AAAA,MACpC,MAAM,QAAQ;AAAA,MACd,aAAa,QAAQ;AAAA,IACvB,CAAC;AAED,QAAI,QAAQ,MAAM;AAChB,cAAQ,IAAI,KAAK,UAAU,UAAU,MAAM,CAAC,CAAC;AAAA,IAC/C,OAAO;AACL,cAAQ,IAAI,gCAAgC;AAC5C,cAAQ,IAAI,EAAE;AACd,2BAAqB,QAAQ;AAAA,IAC/B;AAAA,EACF,SAAS,OAAO;AACd,YAAQ;AAAA,MACN,UAAU,iBAAiB,QAAQ,MAAM,UAAU,eAAe;AAAA,IACpE;AACA,YAAQ,KAAK,CAAC;AAAA,EAChB;AACF;AAEA,eAAeC,eACb,IACA,SAOe;AACf,MAAI;AACF,UAAM,UAIF,CAAC;AAEL,QAAI,QAAQ,SAAS,OAAW,SAAQ,OAAO,QAAQ;AACvD,QAAI,QAAQ,gBAAgB;AAC1B,cAAQ,cAAc,QAAQ;AAChC,QAAI,QAAQ,OAAQ,SAAQ,WAAW;AACvC,QAAI,QAAQ,SAAU,SAAQ,WAAW;AAEzC,QAAI,OAAO,KAAK,OAAO,EAAE,WAAW,GAAG;AACrC,cAAQ,MAAM,iDAAiD;AAC/D,cAAQ,KAAK,CAAC;AAAA,IAChB;AAEA,UAAM,WAAW,MAAM,eAAe,IAAI,OAAO;AAEjD,QAAI,QAAQ,MAAM;AAChB,cAAQ,IAAI,KAAK,UAAU,UAAU,MAAM,CAAC,CAAC;AAAA,IAC/C,OAAO;AACL,cAAQ,IAAI,gCAAgC;AAC5C,cAAQ,IAAI,EAAE;AACd,2BAAqB,QAAQ;AAAA,IAC/B;AAAA,EACF,SAAS,OAAO;AACd,YAAQ;AAAA,MACN,UAAU,iBAAiB,QAAQ,MAAM,UAAU,eAAe;AAAA,IACpE;AACA,YAAQ,KAAK,CAAC;AAAA,EAChB;AACF;AAEA,eAAeC,eACb,IACA,SACe;AACf,MAAI;AACF,QAAI,CAAC,QAAQ,OAAO;AAGlB,cAAQ,IAAI,gDAAgD;AAC5D,cAAQ,IAAI,kCAAkC;AAC9C,cAAQ,KAAK,CAAC;AAAA,IAChB;AAEA,UAAM,eAAe,EAAE;AACvB,YAAQ,IAAI,gCAAgC;AAAA,EAC9C,SAAS,OAAO;AACd,YAAQ;AAAA,MACN,UAAU,iBAAiB,QAAQ,MAAM,UAAU,eAAe;AAAA,IACpE;AACA,YAAQ,KAAK,CAAC;AAAA,EAChB;AACF;AAEO,SAAS,yBAAyBC,UAAwB;AAC/D,QAAM,YAAYA,SACf,QAAQ,WAAW,EACnB,YAAY,kBAAkB;AAEjC,YACG,QAAQ,MAAM,EACd,YAAY,oBAAoB,EAChC,OAAO,UAAU,gBAAgB,EACjC,OAAO,oBAAoB,uBAAuB,EAClD,OAAO,sBAAsB,4BAA4B,EACzD,OAAOL,YAAW;AAErB,YACG,QAAQ,UAAU,EAClB,YAAY,sBAAsB,EAClC,OAAO,UAAU,gBAAgB,EACjC,OAAOC,WAAU;AAEpB,YACG,QAAQ,QAAQ,EAChB,YAAY,uBAAuB,EACnC,eAAe,iBAAiB,eAAe,EAC/C,OAAO,+BAA+B,sBAAsB,EAC5D,OAAO,UAAU,gBAAgB,EACjC,OAAOC,cAAa;AAEvB,YACG,QAAQ,aAAa,EACrB,YAAY,mBAAmB,EAC/B,OAAO,iBAAiB,eAAe,EACvC,OAAO,+BAA+B,sBAAsB,EAC5D,OAAO,YAAY,wBAAwB,EAC3C,OAAO,cAAc,0BAA0B,EAC/C,OAAO,UAAU,gBAAgB,EACjC,OAAOC,cAAa;AAEvB,YACG,QAAQ,aAAa,EACrB,YAAY,mBAAmB,EAC/B,OAAO,WAAW,mBAAmB,EACrC,OAAOC,cAAa;AACzB;;;ACxOA,IAAM,sBAAkD;AAAA,EACtD;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AACF;AAEA,IAAM,iBAAiB,CAAC,WAAW,cAAc,UAAU;AAE3D,IAAM,aAAyB,CAAC,kBAAkB,QAAQ,UAAU;AAepE,IAAM,uBAA6C;AAAA,EACjD;AAAA,IACE,IAAI;AAAA,IACJ,MAAM;AAAA,IACN,aACE;AAAA,IACF,aAAa;AAAA,IACb,gBAAgB;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,IAShB,sBAAsB;AAAA,MACpB,EAAE,OAAO,iBAAiB,OAAO,EAAE;AAAA,MACnC,EAAE,OAAO,YAAY,OAAO,EAAE;AAAA,MAC9B,EAAE,OAAO,WAAW,OAAO,EAAE;AAAA,MAC7B,EAAE,OAAO,YAAY,OAAO,EAAE;AAAA,MAC9B,EAAE,OAAO,iBAAiB,OAAO,EAAE;AAAA,IACrC;AAAA,EACF;AAAA,EACA;AAAA,IACE,IAAI;AAAA,IACJ,MAAM;AAAA,IACN,aACE;AAAA,IACF,aAAa;AAAA,IACb,gBAAgB;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,IAShB,sBAAsB;AAAA,MACpB,EAAE,OAAO,iBAAiB,OAAO,EAAE;AAAA,MACnC,EAAE,OAAO,iBAAiB,OAAO,EAAE;AAAA,MACnC,EAAE,OAAO,iBAAiB,OAAO,GAAG;AAAA,MACpC,EAAE,OAAO,oBAAoB,OAAO,GAAG;AAAA,MACvC,EAAE,OAAO,sBAAsB,OAAO,GAAG;AAAA,IAC3C;AAAA,EACF;AACF;AAEA,SAAS,+BAA+B,SAAsC;AAC5E,SAAO,QAAQ,IAAI,CAAC,MAAM,GAAG,EAAE,KAAK,MAAM,EAAE,KAAK,EAAE,EAAE,KAAK,IAAI;AAChE;AAEA,SAAS,sBACP,UACA,SACQ;AACR,SAAO,SAAS,eAAe;AAAA,IAC7B;AAAA,IACA,+BAA+B,OAAO;AAAA,EACxC;AACF;AAEA,SAAS,eAAe,MAA6B;AACnD,MAAI,KAAK,WAAW,GAAG;AACrB,YAAQ,IAAI,2BAA2B;AACvC;AAAA,EACF;AAGA,QAAM,UAAU,CAAC,MAAM,QAAQ,SAAS,cAAc,eAAe,QAAQ;AAC7E,QAAM,OAAO,KAAK,IAAI,CAAC,QAAQ;AAAA,IAC7B,IAAI,GAAG,MAAM,GAAG,EAAE,IAAI;AAAA,IACtB,IAAI,KAAK,MAAM,GAAG,EAAE;AAAA,IACpB,IAAI,SAAS;AAAA,IACb,IAAI;AAAA,IACJ,IAAI;AAAA,IACJ,IAAI,WAAW,WAAW;AAAA,EAC5B,CAAC;AAED,QAAM,SAAS,QAAQ;AAAA,IAAI,CAAC,GAAG,MAC7B,KAAK,IAAI,EAAE,QAAQ,GAAG,KAAK,IAAI,CAAC,MAAM,EAAE,CAAC,EAAE,MAAM,CAAC;AAAA,EACpD;AAGA,UAAQ,IAAI,QAAQ,IAAI,CAAC,GAAG,MAAM,EAAE,OAAO,OAAO,CAAC,CAAC,CAAC,EAAE,KAAK,IAAI,CAAC;AACjE,UAAQ,IAAI,OAAO,IAAI,CAAC,MAAM,IAAI,OAAO,CAAC,CAAC,EAAE,KAAK,IAAI,CAAC;AAGvD,aAAW,OAAO,MAAM;AACtB,YAAQ,IAAI,IAAI,IAAI,CAAC,MAAM,MAAM,KAAK,OAAO,OAAO,CAAC,CAAC,CAAC,EAAE,KAAK,IAAI,CAAC;AAAA,EACrE;AACF;AAEA,SAAS,gBAAgB,KAA0B;AACjD,UAAQ,IAAI,iBAAiB,IAAI,EAAE,EAAE;AACrC,UAAQ,IAAI,iBAAiB,IAAI,IAAI,EAAE;AACvC,UAAQ,IAAI,iBAAiB,IAAI,eAAe,GAAG,EAAE;AACrD,UAAQ,IAAI,iBAAiB,IAAI,IAAI,EAAE;AACvC,UAAQ,IAAI,iBAAiB,IAAI,YAAY,GAAG,EAAE;AAClD,UAAQ,IAAI,iBAAiB,IAAI,WAAW,GAAG,EAAE;AACjD,UAAQ,IAAI,iBAAiB,IAAI,SAAS,gBAAgB,EAAE;AAC5D,UAAQ,IAAI,iBAAiB,IAAI,YAAY,EAAE;AAC/C,UAAQ,IAAI,iBAAiB,IAAI,wBAAwB,EAAE;AAC3D,UAAQ,IAAI,iBAAiB,IAAI,QAAQ,GAAG,EAAE;AAC9C,UAAQ,IAAI,iBAAiB,IAAI,WAAW,WAAW,UAAU,EAAE;AAEnE,MAAI,IAAI,kBAAkB;AACxB,YAAQ,IAAI,EAAE;AACd,YAAQ,IAAI,wBAAwB;AACpC,YAAQ,IAAI,KAAK,UAAU,IAAI,kBAAkB,MAAM,CAAC,CAAC;AAAA,EAC3D;AAEA,MAAI,IAAI,WAAW;AACjB,YAAQ,IAAI,EAAE;AACd,YAAQ,IAAI,iBAAiB,IAAI,KAAK,IAAI,SAAS,EAAE,YAAY,CAAC,EAAE;AAAA,EACtE;AACA,MAAI,IAAI,WAAW;AACjB,YAAQ,IAAI,iBAAiB,IAAI,KAAK,IAAI,SAAS,EAAE,YAAY,CAAC,EAAE;AAAA,EACtE;AACF;AAEA,SAAS,4BAA4B,WAAoC;AACvE,MAAI,UAAU,WAAW,GAAG;AAC1B,YAAQ,IAAI,6BAA6B;AACzC;AAAA,EACF;AAGA,QAAM,UAAU,CAAC,QAAQ,QAAQ,UAAU,aAAa;AACxD,QAAM,OAAO,UAAU,IAAI,CAAC,MAAM;AAAA,IAChC,EAAE;AAAA,IACF,EAAE;AAAA,IACF,EAAE;AAAA,IACF,EAAE,YAAY,MAAM,GAAG,EAAE;AAAA,EAC3B,CAAC;AAED,QAAM,SAAS,QAAQ;AAAA,IAAI,CAAC,GAAG,MAC7B,KAAK,IAAI,EAAE,QAAQ,GAAG,KAAK,IAAI,CAAC,MAAM,EAAE,CAAC,EAAE,MAAM,CAAC;AAAA,EACpD;AAGA,UAAQ,IAAI,QAAQ,IAAI,CAAC,GAAG,MAAM,EAAE,OAAO,OAAO,CAAC,CAAC,CAAC,EAAE,KAAK,IAAI,CAAC;AACjE,UAAQ,IAAI,OAAO,IAAI,CAAC,MAAM,IAAI,OAAO,CAAC,CAAC,EAAE,KAAK,IAAI,CAAC;AAGvD,aAAW,OAAO,MAAM;AACtB,YAAQ,IAAI,IAAI,IAAI,CAAC,MAAM,MAAM,KAAK,OAAO,OAAO,CAAC,CAAC,CAAC,EAAE,KAAK,IAAI,CAAC;AAAA,EACrE;AACF;AAEA,eAAeE,aAAY,SAIT;AAChB,MAAI;AACF,UAAM,OAAO,MAAM,SAAS;AAAA,MAC1B,SAAS,QAAQ;AAAA,MACjB,iBAAiB,QAAQ;AAAA,IAC3B,CAAC;AAED,QAAI,QAAQ,MAAM;AAChB,cAAQ,IAAI,KAAK,UAAU,MAAM,MAAM,CAAC,CAAC;AAAA,IAC3C,OAAO;AACL,qBAAe,IAAI;AAAA,IACrB;AAAA,EACF,SAAS,OAAO;AACd,YAAQ;AAAA,MACN,UAAU,iBAAiB,QAAQ,MAAM,UAAU,eAAe;AAAA,IACpE;AACA,YAAQ,KAAK,CAAC;AAAA,EAChB;AACF;AAEA,eAAeC,YACb,IACA,SACe;AACf,MAAI;AACF,UAAM,MAAM,MAAM,OAAO,EAAE;AAE3B,QAAI,QAAQ,MAAM;AAChB,cAAQ,IAAI,KAAK,UAAU,KAAK,MAAM,CAAC,CAAC;AAAA,IAC1C,OAAO;AACL,sBAAgB,GAAG;AAAA,IACrB;AAAA,EACF,SAAS,OAAO;AACd,YAAQ;AAAA,MACN,UAAU,iBAAiB,QAAQ,MAAM,UAAU,eAAe;AAAA,IACpE;AACA,YAAQ,KAAK,CAAC;AAAA,EAChB;AACF;AAEA,eAAeC,eAAc,SAgBX;AAChB,MAAI;AACF,QAAI,CAAC,QAAQ,MAAM;AACjB,cAAQ,MAAM,2BAA2B;AACzC,cAAQ,KAAK,CAAC;AAAA,IAChB;AAEA,QAAI,CAAC,QAAQ,cAAc;AACzB,cAAQ,MAAM,oCAAoC;AAClD,cAAQ,MAAM,iBAAiB,eAAe,KAAK,IAAI,CAAC,EAAE;AAC1D,cAAQ,KAAK,CAAC;AAAA,IAChB;AAEA,QAAI,CAAC,eAAe,SAAS,QAAQ,YAAY,GAAG;AAClD,cAAQ,MAAM,iCAAiC,QAAQ,YAAY,GAAG;AACtE,cAAQ,MAAM,iBAAiB,eAAe,KAAK,IAAI,CAAC,EAAE;AAC1D,cAAQ,KAAK,CAAC;AAAA,IAChB;AAGA,UAAM,aAAa,QAAQ,MAAM,YAAY;AAC7C,QAAI,CAAC,WAAW,SAAS,UAAU,GAAG;AACpC,cAAQ,MAAM,yBAAyB,QAAQ,KAAK,GAAG;AACvD,cAAQ,MAAM,iBAAiB,WAAW,KAAK,IAAI,CAAC,EAAE;AACtD,cAAQ,KAAK,CAAC;AAAA,IAChB;AAGA,QAAI;AACJ,QAAI,eAAe,QAAQ;AAE3B,QAAI,QAAQ,iBAAiB,WAAW;AACtC,UAAI,CAAC,QAAQ,SAAS;AACpB,gBAAQ;AAAA,UACN;AAAA,QACF;AACA,gBAAQ,KAAK,CAAC;AAAA,MAChB;AAEA,YAAM,aAAa,MAAM,mBAAmB,QAAQ,SAAS,QAAQ,SAAS,UAAU;AACxF,UAAI,CAAC,WAAW,OAAO;AACrB,gBAAQ,MAAM,2BAA2B,WAAW,KAAK,EAAE;AAC3D,gBAAQ,KAAK,CAAC;AAAA,MAChB;AAEA,yBAAmB,EAAE,SAAS,WAAW,cAAc;AAAA,IACzD,WAAW,QAAQ,iBAAiB,cAAc;AAChD,UAAI,CAAC,QAAQ,YAAY;AACvB,gBAAQ;AAAA,UACN;AAAA,QACF;AACA,gBAAQ,KAAK,CAAC;AAAA,MAChB;AAEA,YAAM,cAAc,qBAAqB,IAAI,CAAC,MAAM,EAAE,EAAE;AACxD,YAAM,WAAW,qBAAqB;AAAA,QACpC,CAAC,MAAM,EAAE,OAAO,QAAQ;AAAA,MAC1B;AACA,UAAI,CAAC,UAAU;AACb,gBAAQ;AAAA,UACN,4BAA4B,QAAQ,UAAU,uBAAuB,YAAY,KAAK,IAAI,CAAC;AAAA,QAC7F;AACA,gBAAQ,KAAK,CAAC;AAAA,MAChB;AAGA,UAAI,gBAAgB,SAAS;AAC7B,UAAI,QAAQ,iBAAiB,QAAQ,cAAc;AACjD,cAAM,YAAY,QAAQ,gBACtB,QAAQ,cAAc,MAAM,GAAG,EAAE,IAAI,CAAC,MAAM,EAAE,KAAK,CAAC,IACpD,SAAS,qBAAqB,IAAI,CAAC,MAAM,OAAO,EAAE,KAAK,CAAC;AAC5D,cAAM,YAAY,QAAQ,eACtB,QAAQ,aAAa,MAAM,GAAG,EAAE,IAAI,CAAC,MAAM,EAAE,KAAK,CAAC,IACnD,SAAS,qBAAqB,IAAI,CAAC,MAAM,EAAE,KAAK;AAEpD,YAAI,UAAU,WAAW,UAAU,QAAQ;AACzC,kBAAQ;AAAA,YACN,4BAA4B,UAAU,MAAM,iCAAiC,UAAU,MAAM;AAAA,UAC/F;AACA,kBAAQ,KAAK,CAAC;AAAA,QAChB;AAEA,wBAAgB,UAAU,IAAI,CAAC,GAAG,OAAO;AAAA,UACvC,OAAO,UAAU,CAAC;AAAA,UAClB,OAAO,OAAO,CAAC;AAAA,QACjB,EAAE;AAAA,MACJ;AAGA,YAAM,iBAAiB,sBAAsB,UAAU,aAAa;AAEpE,yBAAmB;AAAA,QACjB;AAAA,QACA,eAAe,cAAc,IAAI,CAAC,MAAM,EAAE,KAAK;AAAA,QAC/C,mBAAmB,cAAc,IAAI,CAAC,MAAM,EAAE,KAAK;AAAA,QACnD,sBAAsB,SAAS;AAAA,MACjC;AAGA,UAAI,QAAQ,mBAAmB,QAAW;AACxC,cAAM,SAAS,OAAO,QAAQ,cAAc;AAC5C,YAAI,MAAM,MAAM,KAAK,SAAS,KAAK,SAAS,GAAG;AAC7C,kBAAQ,MAAM,4DAA4D;AAC1E,kBAAQ,KAAK,CAAC;AAAA,QAChB;AACA,yBAAiB,iBAAiB;AAAA,MACpC;AAGA,UAAI,CAAC,cAAc;AACjB,uBAAe,SAAS;AAAA,MAC1B;AAAA,IACF;AAGA,QAAI;AACJ,QAAI,QAAQ,aAAa;AACvB,YAAM,mBACJ,QAAQ,YAAY,YAAY;AAClC,UAAI,CAAC,oBAAoB,SAAS,gBAAgB,GAAG;AACnD,gBAAQ,MAAM,sCAAsC,QAAQ,WAAW,GAAG;AAC1E,gBAAQ,MAAM,iBAAiB,oBAAoB,KAAK,IAAI,CAAC,EAAE;AAC/D,gBAAQ,KAAK,CAAC;AAAA,MAChB;AACA,oBAAc;AAAA,IAChB;AAEA,UAAM,UAA4B;AAAA,MAChC,MAAM,QAAQ;AAAA,MACd,cAAc,QAAQ;AAAA,MACtB,OAAO;AAAA,MACP,aAAa,QAAQ;AAAA,MACrB,MACE,QAAQ,SAAS,eAAe,eAAe;AAAA,MACjD,UAAU,QAAQ;AAAA,MAClB,SAAS,QAAQ;AAAA,MACjB;AAAA,MACA,MAAM;AAAA,MACN,0BAA0B;AAAA,IAC5B;AAEA,UAAM,MAAM,MAAM,UAAU,OAAO;AAEnC,QAAI,QAAQ,MAAM;AAChB,cAAQ,IAAI,KAAK,UAAU,KAAK,MAAM,CAAC,CAAC;AAAA,IAC1C,OAAO;AACL,cAAQ,IAAI,sCAAsC;AAClD,cAAQ,IAAI,EAAE;AACd,sBAAgB,GAAG;AAAA,IACrB;AAAA,EACF,SAAS,OAAO;AACd,YAAQ;AAAA,MACN,UAAU,iBAAiB,QAAQ,MAAM,UAAU,eAAe;AAAA,IACpE;AACA,YAAQ,KAAK,CAAC;AAAA,EAChB;AACF;AAEA,eAAeC,eACb,IACA,SAce;AACf,MAAI;AACF,UAAM,UAAmC,CAAC;AAE1C,QAAI,QAAQ,SAAS,OAAW,SAAQ,OAAO,QAAQ;AACvD,QAAI,QAAQ,gBAAgB;AAC1B,cAAQ,cAAc,QAAQ;AAChC,QAAI,QAAQ,aAAa,OAAW,SAAQ,WAAW,QAAQ;AAC/D,QAAI,QAAQ,YAAY,OAAW,SAAQ,UAAU,QAAQ;AAC7D,QAAI,QAAQ,iBAAiB;AAC3B,cAAQ,eAAe,QAAQ;AACjC,QAAI,QAAQ,SAAS,OAAW,SAAQ,OAAO,QAAQ;AACvD,QAAI,QAAQ,OAAQ,SAAQ,WAAW;AACvC,QAAI,QAAQ,SAAU,SAAQ,WAAW;AAGzC,QAAI;AACJ,QAAI,QAAQ,UAAU,QAAW;AAC/B,YAAM,aAAa,QAAQ,MAAM,YAAY;AAC7C,UAAI,CAAC,WAAW,SAAS,UAAU,GAAG;AACpC,gBAAQ,MAAM,yBAAyB,QAAQ,KAAK,GAAG;AACvD,gBAAQ,MAAM,iBAAiB,WAAW,KAAK,IAAI,CAAC,EAAE;AACtD,gBAAQ,KAAK,CAAC;AAAA,MAChB;AACA,cAAQ,QAAQ;AAChB,uBAAiB;AAAA,IACnB;AAGA,QAAI,QAAQ,YAAY,QAAW;AACjC,YAAM,aAAa,MAAM,mBAAmB,QAAQ,SAAS,QAAQ,SAAS,cAAc;AAC5F,UAAI,CAAC,WAAW,OAAO;AACrB,gBAAQ,MAAM,2BAA2B,WAAW,KAAK,EAAE;AAC3D,gBAAQ,KAAK,CAAC;AAAA,MAChB;AAEA,cAAQ,mBAAmB,EAAE,SAAS,WAAW,cAAc;AAAA,IACjE;AAGA,QAAI,QAAQ,aAAa;AACvB,YAAM,mBACJ,QAAQ,YAAY,YAAY;AAClC,UAAI,CAAC,oBAAoB,SAAS,gBAAgB,GAAG;AACnD,gBAAQ,MAAM,sCAAsC,QAAQ,WAAW,GAAG;AAC1E,gBAAQ,MAAM,iBAAiB,oBAAoB,KAAK,IAAI,CAAC,EAAE;AAC/D,gBAAQ,KAAK,CAAC;AAAA,MAChB;AACA,cAAQ,2BAA2B;AAAA,IACrC;AAEA,QAAI,OAAO,KAAK,OAAO,EAAE,WAAW,GAAG;AACrC,cAAQ,MAAM,iDAAiD;AAC/D,cAAQ,KAAK,CAAC;AAAA,IAChB;AAEA,UAAM,MAAM,MAAM,UAAU,IAAI,OAAO;AAEvC,QAAI,QAAQ,MAAM;AAChB,cAAQ,IAAI,KAAK,UAAU,KAAK,MAAM,CAAC,CAAC;AAAA,IAC1C,OAAO;AACL,cAAQ,IAAI,sCAAsC;AAClD,cAAQ,IAAI,EAAE;AACd,sBAAgB,GAAG;AAAA,IACrB;AAAA,EACF,SAAS,OAAO;AACd,YAAQ;AAAA,MACN,UAAU,iBAAiB,QAAQ,MAAM,UAAU,eAAe;AAAA,IACpE;AACA,YAAQ,KAAK,CAAC;AAAA,EAChB;AACF;AAEA,eAAeC,eACb,IACA,SACe;AACf,MAAI;AACF,QAAI,CAAC,QAAQ,OAAO;AAClB,cAAQ,IAAI,sDAAsD;AAClE,cAAQ,IAAI,kCAAkC;AAC9C,cAAQ,KAAK,CAAC;AAAA,IAChB;AAEA,UAAM,UAAU,EAAE;AAClB,YAAQ,IAAI,sCAAsC;AAAA,EACpD,SAAS,OAAO;AACd,YAAQ;AAAA,MACN,UAAU,iBAAiB,QAAQ,MAAM,UAAU,eAAe;AAAA,IACpE;AACA,YAAQ,KAAK,CAAC;AAAA,EAChB;AACF;AAEA,eAAe,wBAAwB,SAIrB;AAChB,MAAI;AAEF,QAAI;AACJ,QAAI,QAAQ,OAAO;AACjB,YAAM,aAAa,QAAQ,MAAM,YAAY;AAC7C,UAAI,CAAC,WAAW,SAAS,UAAU,GAAG;AACpC,gBAAQ,MAAM,yBAAyB,QAAQ,KAAK,GAAG;AACvD,gBAAQ,MAAM,iBAAiB,WAAW,KAAK,IAAI,CAAC,EAAE;AACtD,gBAAQ,KAAK,CAAC;AAAA,MAChB;AACA,uBAAiB;AAAA,IACnB;AAEA,UAAM,YAAY,MAAM,uBAAuB,QAAQ,SAAS,cAAc;AAE9E,QAAI,QAAQ,MAAM;AAChB,cAAQ,IAAI,KAAK,UAAU,WAAW,MAAM,CAAC,CAAC;AAAA,IAChD,OAAO;AACL,cAAQ,IAAI,+CAA+C;AAC3D,cAAQ,IAAI,EAAE;AACd,kCAA4B,SAAS;AACrC,cAAQ,IAAI,EAAE;AACd,cAAQ;AAAA,QACN;AAAA,MACF;AACA,cAAQ,IAAI,0BAA0B;AACtC,cAAQ,IAAI,wBAAwB;AACpC,cAAQ,IAAI,gEAAgE;AAAA,IAC9E;AAAA,EACF,SAAS,OAAO;AACd,YAAQ;AAAA,MACN,UAAU,iBAAiB,QAAQ,MAAM,UAAU,eAAe;AAAA,IACpE;AACA,YAAQ,KAAK,CAAC;AAAA,EAChB;AACF;AAEA,eAAe,gBAAgB,SAKb;AAChB,MAAI;AACF,QAAI,CAAC,QAAQ,SAAS;AACpB,cAAQ,MAAM,8BAA8B;AAC5C,cAAQ,KAAK,CAAC;AAAA,IAChB;AAGA,QAAI;AACJ,QAAI,QAAQ,OAAO;AACjB,YAAM,aAAa,QAAQ,MAAM,YAAY;AAC7C,UAAI,CAAC,WAAW,SAAS,UAAU,GAAG;AACpC,gBAAQ,MAAM,yBAAyB,QAAQ,KAAK,GAAG;AACvD,gBAAQ,MAAM,iBAAiB,WAAW,KAAK,IAAI,CAAC,EAAE;AACtD,gBAAQ,KAAK,CAAC;AAAA,MAChB;AACA,uBAAiB;AAAA,IACnB;AAEA,UAAM,SAAS,MAAM,mBAAmB,QAAQ,SAAS,QAAQ,SAAS,cAAc;AAExF,QAAI,QAAQ,MAAM;AAChB,cAAQ,IAAI,KAAK,UAAU,QAAQ,MAAM,CAAC,CAAC;AAAA,IAC7C,OAAO;AACL,UAAI,OAAO,OAAO;AAChB,gBAAQ,IAAI,mBAAmB;AAC/B,gBAAQ,IAAI,gBAAgB,OAAO,QAAQ,SAAS,EAAE;AAAA,MACxD,OAAO;AACL,gBAAQ,MAAM,qBAAqB;AACnC,gBAAQ,MAAM,KAAK,OAAO,KAAK,EAAE;AACjC,YAAI,OAAO,cAAc,QAAW;AAClC,kBAAQ,MAAM,yBAAyB,OAAO,SAAS,EAAE;AAAA,QAC3D;AACA,gBAAQ,KAAK,CAAC;AAAA,MAChB;AAAA,IACF;AAAA,EACF,SAAS,OAAO;AACd,YAAQ;AAAA,MACN,UAAU,iBAAiB,QAAQ,MAAM,UAAU,eAAe;AAAA,IACpE;AACA,YAAQ,KAAK,CAAC;AAAA,EAChB;AACF;AAEA,SAAS,iBAAiB,SAAmC;AAC3D,MAAI,QAAQ,MAAM;AAChB,YAAQ;AAAA,MACN,KAAK;AAAA,QACH,qBAAqB,IAAI,CAAC,OAAO;AAAA,UAC/B,IAAI,EAAE;AAAA,UACN,MAAM,EAAE;AAAA,UACR,aAAa,EAAE;AAAA,UACf,aAAa,EAAE;AAAA,UACf,eAAe,EAAE;AAAA,QACnB,EAAE;AAAA,QACF;AAAA,QACA;AAAA,MACF;AAAA,IACF;AAAA,EACF,OAAO;AACL,YAAQ,IAAI,iCAAiC;AAC7C,YAAQ,IAAI,EAAE;AACd,eAAW,KAAK,sBAAsB;AACpC,cAAQ,IAAI,KAAK,EAAE,GAAG,OAAO,EAAE,CAAC,IAAI,EAAE,WAAW,EAAE;AACnD,YAAM,aAAa,EAAE;AACrB,cAAQ;AAAA,QACN,GAAG,GAAG,OAAO,EAAE,CAAC,YAAY,WAAW,IAAI,CAAC,MAAM,GAAG,EAAE,KAAK,KAAK,EAAE,KAAK,GAAG,EAAE,KAAK,IAAI,CAAC;AAAA,MACzF;AACA,cAAQ;AAAA,QACN,GAAG,GAAG,OAAO,EAAE,CAAC,iBAAiB,EAAE,WAAW;AAAA,MAChD;AACA,cAAQ,IAAI,EAAE;AAAA,IAChB;AACA,YAAQ,IAAI,QAAQ;AACpB,YAAQ;AAAA,MACN;AAAA,IACF;AAAA,EACF;AACF;AAEO,SAAS,oBAAoBC,UAAwB;AAC1D,QAAM,OAAOA,SACV,QAAQ,MAAM,EACd,YAAY,wBAAwB;AAEvC,OACG,QAAQ,MAAM,EACd,YAAY,0BAA0B,EACtC,OAAO,UAAU,gBAAgB,EACjC,OAAO,mBAAmB,oBAAoB,EAC9C,OAAO,sBAAsB,kCAAkC,EAC/D,OAAOL,YAAW;AAErB,OACG,QAAQ,UAAU,EAClB,YAAY,4BAA4B,EACxC,OAAO,UAAU,gBAAgB,EACjC,OAAOC,WAAU;AAEpB,OACG,QAAQ,QAAQ,EAChB,YAAY,6BAA6B,EACzC,eAAe,iBAAiB,UAAU,EAC1C;AAAA,IACC;AAAA,IACA;AAAA,EACF,EACC;AAAA,IACC;AAAA,IACA;AAAA,EACF,EACC,OAAO,+BAA+B,iBAAiB,EACvD,OAAO,iBAAiB,gDAAgD,EACxE,OAAO,yBAAyB,2BAA2B,EAC3D,OAAO,mBAAmB,qCAAqC,EAC/D,OAAO,uBAAuB,sDAAsD,EACpF,OAAO,sBAAsB,6DAA6D,EAC1F,OAAO,6BAA6B,wDAAwD,EAC5F,OAAO,4BAA4B,gDAAgD,EACnF,OAAO,8BAA8B,oDAAoD,EACzF,OAAO,iBAAiB,yCAAyC,EACjE;AAAA,IACC;AAAA,IACA;AAAA,EACF,EACC,OAAO,UAAU,gBAAgB,EACjC,OAAOC,cAAa;AAEvB,OACG,QAAQ,WAAW,EACnB,YAAY,qCAAqC,EACjD,OAAO,UAAU,gBAAgB,EACjC,OAAO,gBAAgB;AAE1B,OACG,QAAQ,aAAa,EACrB,YAAY,yBAAyB,EACrC,OAAO,iBAAiB,UAAU,EAClC,OAAO,+BAA+B,iBAAiB,EACvD,OAAO,yBAAyB,cAAc,EAC9C,OAAO,mBAAmB,sBAAsB,EAChD,OAAO,mBAAmB,8CAA8C,EACxE,OAAO,wBAAwB,iBAAiB,EAChD,OAAO,uBAAuB,oBAAoB,EAClD,OAAO,iBAAiB,cAAc,EACtC,OAAO,0BAA0B,4BAA4B,EAC7D,OAAO,YAAY,mBAAmB,EACtC,OAAO,cAAc,qBAAqB,EAC1C,OAAO,UAAU,gBAAgB,EACjC,OAAOC,cAAa;AAEvB,OACG,QAAQ,aAAa,EACrB,YAAY,yBAAyB,EACrC,OAAO,WAAW,mBAAmB,EACrC,OAAOC,cAAa;AAEvB,OACG,QAAQ,mBAAmB,EAC3B,YAAY,+CAA+C,EAC3D,OAAO,UAAU,gBAAgB,EACjC,OAAO,mBAAmB,kCAAkC,EAC5D,OAAO,mBAAmB,8DAA8D,EACxF,OAAO,uBAAuB;AAEjC,OACG,QAAQ,UAAU,EAClB,YAAY,mCAAmC,EAC/C,eAAe,uBAAuB,gCAAgC,EACtE,OAAO,mBAAmB,gCAAgC,EAC1D,OAAO,mBAAmB,2DAA2D,EACrF,OAAO,UAAU,gBAAgB,EACjC,OAAO,eAAe;AAC3B;;;AC1tBA,IAAM,aAA+B,CAAC,UAAU,UAAU,SAAS;AAEnE,SAAS,YAAY,SAAmC;AACtD,MAAI,QAAQ,WAAW,GAAG;AACxB,YAAQ,IAAI,sCAAsC;AAClD;AAAA,EACF;AAGA,QAAM,UAAU,CAAC,MAAM,QAAQ,QAAQ,YAAY,aAAa;AAChE,QAAM,OAAO,QAAQ,IAAI,CAAC,WAAW;AAAA,IACnC,OAAO,GAAG,MAAM,GAAG,EAAE,IAAI;AAAA,IACzB,OAAO,KAAK,MAAM,GAAG,EAAE;AAAA,IACvB,OAAO;AAAA,IACP,OAAO,UAAU,OAAO,QAAQ,MAAM,GAAG,EAAE,IAAI,QAAQ;AAAA,KACtD,OAAO,eAAe,KAAK,MAAM,GAAG,EAAE;AAAA,EACzC,CAAC;AAED,QAAM,SAAS,QAAQ;AAAA,IAAI,CAAC,GAAG,MAC7B,KAAK,IAAI,EAAE,QAAQ,GAAG,KAAK,IAAI,CAAC,MAAM,EAAE,CAAC,EAAE,MAAM,CAAC;AAAA,EACpD;AAGA,UAAQ,IAAI,QAAQ,IAAI,CAAC,GAAG,MAAM,EAAE,OAAO,OAAO,CAAC,CAAC,CAAC,EAAE,KAAK,IAAI,CAAC;AACjE,UAAQ,IAAI,OAAO,IAAI,CAAC,MAAM,IAAI,OAAO,CAAC,CAAC,EAAE,KAAK,IAAI,CAAC;AAGvD,aAAW,OAAO,MAAM;AACtB,YAAQ,IAAI,IAAI,IAAI,CAAC,MAAM,MAAM,KAAK,OAAO,OAAO,CAAC,CAAC,CAAC,EAAE,KAAK,IAAI,CAAC;AAAA,EACrE;AACF;AAEA,SAAS,aAAa,QAAgC;AACpD,UAAQ,IAAI,gBAAgB,OAAO,EAAE,EAAE;AACvC,UAAQ,IAAI,gBAAgB,OAAO,IAAI,EAAE;AACzC,UAAQ,IAAI,gBAAgB,OAAO,IAAI,EAAE;AACzC,UAAQ,IAAI,gBAAgB,OAAO,WAAW,0BAA0B,EAAE;AAC1E,UAAQ,IAAI,gBAAgB,OAAO,eAAe,GAAG,EAAE;AACvD,MAAI,OAAO,WAAW;AACpB,YAAQ,IAAI,gBAAgB,IAAI,KAAK,OAAO,SAAS,EAAE,YAAY,CAAC,EAAE;AAAA,EACxE;AACA,MAAI,OAAO,WAAW;AACpB,YAAQ,IAAI,gBAAgB,IAAI,KAAK,OAAO,SAAS,EAAE,YAAY,CAAC,EAAE;AAAA,EACxE;AACF;AAEA,eAAeE,aAAY,SAA8D;AACvF,MAAI;AACF,UAAM,UAAU,MAAM,sBAAsB,QAAQ,OAAO;AAE3D,QAAI,QAAQ,MAAM;AAChB,cAAQ,IAAI,KAAK,UAAU,SAAS,MAAM,CAAC,CAAC;AAAA,IAC9C,OAAO;AACL,kBAAY,OAAO;AAAA,IACrB;AAAA,EACF,SAAS,OAAO;AACd,YAAQ;AAAA,MACN,UAAU,iBAAiB,QAAQ,MAAM,UAAU,eAAe;AAAA,IACpE;AACA,YAAQ,KAAK,CAAC;AAAA,EAChB;AACF;AAEA,eAAeC,YACb,IACA,SACe;AACf,MAAI;AACF,UAAM,SAAS,MAAM,oBAAoB,EAAE;AAE3C,QAAI,QAAQ,MAAM;AAChB,cAAQ,IAAI,KAAK,UAAU,QAAQ,MAAM,CAAC,CAAC;AAAA,IAC7C,OAAO;AACL,mBAAa,MAAM;AAAA,IACrB;AAAA,EACF,SAAS,OAAO;AACd,YAAQ;AAAA,MACN,UAAU,iBAAiB,QAAQ,MAAM,UAAU,eAAe;AAAA,IACpE;AACA,YAAQ,KAAK,CAAC;AAAA,EAChB;AACF;AAEA,eAAeC,eAAc,SAMX;AAChB,MAAI;AACF,QAAI,CAAC,QAAQ,SAAS;AACpB,cAAQ,MAAM,+BAA+B;AAC7C,cAAQ,MAAM,8DAA8D;AAC5E,cAAQ,KAAK,CAAC;AAAA,IAChB;AAEA,QAAI,CAAC,QAAQ,MAAM;AACjB,cAAQ,MAAM,2BAA2B;AACzC,cAAQ,KAAK,CAAC;AAAA,IAChB;AAEA,QAAI,CAAC,QAAQ,MAAM;AACjB,cAAQ,MAAM,2BAA2B;AACzC,cAAQ,MAAM,iBAAiB,WAAW,KAAK,IAAI,CAAC,EAAE;AACtD,cAAQ,KAAK,CAAC;AAAA,IAChB;AAEA,UAAM,YAAY,QAAQ,KAAK,YAAY;AAC3C,QAAI,CAAC,WAAW,SAAS,SAAS,GAAG;AACnC,cAAQ,MAAM,wBAAwB,QAAQ,IAAI,GAAG;AACrD,cAAQ,MAAM,iBAAiB,WAAW,KAAK,IAAI,CAAC,EAAE;AACtD,cAAQ,KAAK,CAAC;AAAA,IAChB;AAEA,UAAM,SAAS,MAAM,uBAAuB;AAAA,MAC1C,SAAS,QAAQ;AAAA,MACjB,MAAM,QAAQ;AAAA,MACd,MAAM;AAAA,MACN,aAAa,QAAQ,eAAe;AAAA,IACtC,CAAC;AAED,QAAI,QAAQ,MAAM;AAChB,cAAQ,IAAI,KAAK,UAAU,QAAQ,MAAM,CAAC,CAAC;AAAA,IAC7C,OAAO;AACL,cAAQ,IAAI,iDAAiD;AAC7D,cAAQ,IAAI,EAAE;AACd,mBAAa,MAAM;AAAA,IACrB;AAAA,EACF,SAAS,OAAO;AACd,YAAQ;AAAA,MACN,UAAU,iBAAiB,QAAQ,MAAM,UAAU,eAAe;AAAA,IACpE;AACA,YAAQ,KAAK,CAAC;AAAA,EAChB;AACF;AAEA,eAAeC,eACb,IACA,SAMe;AACf,MAAI;AACF,UAAM,UAIF,CAAC;AAEL,QAAI,QAAQ,SAAS,OAAW,SAAQ,OAAO,QAAQ;AACvD,QAAI,QAAQ,gBAAgB;AAC1B,cAAQ,cAAc,QAAQ,eAAe;AAE/C,QAAI,QAAQ,SAAS,QAAW;AAC9B,YAAM,YAAY,QAAQ,KAAK,YAAY;AAC3C,UAAI,CAAC,WAAW,SAAS,SAAS,GAAG;AACnC,gBAAQ,MAAM,wBAAwB,QAAQ,IAAI,GAAG;AACrD,gBAAQ,MAAM,iBAAiB,WAAW,KAAK,IAAI,CAAC,EAAE;AACtD,gBAAQ,KAAK,CAAC;AAAA,MAChB;AACA,cAAQ,OAAO;AAAA,IACjB;AAEA,QAAI,OAAO,KAAK,OAAO,EAAE,WAAW,GAAG;AACrC,cAAQ,MAAM,iDAAiD;AAC/D,cAAQ,KAAK,CAAC;AAAA,IAChB;AAEA,UAAM,SAAS,MAAM,uBAAuB,IAAI,OAAO;AAEvD,QAAI,QAAQ,MAAM;AAChB,cAAQ,IAAI,KAAK,UAAU,QAAQ,MAAM,CAAC,CAAC;AAAA,IAC7C,OAAO;AACL,cAAQ,IAAI,iDAAiD;AAC7D,cAAQ,IAAI,EAAE;AACd,mBAAa,MAAM;AAAA,IACrB;AAAA,EACF,SAAS,OAAO;AACd,YAAQ;AAAA,MACN,UAAU,iBAAiB,QAAQ,MAAM,UAAU,eAAe;AAAA,IACpE;AACA,YAAQ,KAAK,CAAC;AAAA,EAChB;AACF;AAEA,eAAeC,eACb,IACA,SACe;AACf,MAAI;AACF,QAAI,CAAC,QAAQ,OAAO;AAClB,cAAQ;AAAA,QACN;AAAA,MACF;AACA,cAAQ,IAAI,kCAAkC;AAC9C,cAAQ,KAAK,CAAC;AAAA,IAChB;AAEA,UAAM,uBAAuB,EAAE;AAC/B,YAAQ,IAAI,iDAAiD;AAAA,EAC/D,SAAS,OAAO;AACd,YAAQ;AAAA,MACN,UAAU,iBAAiB,QAAQ,MAAM,UAAU,eAAe;AAAA,IACpE;AACA,YAAQ,KAAK,CAAC;AAAA,EAChB;AACF;AAEO,SAAS,0BAA0BC,UAAwB;AAChE,QAAM,aAAaA,SAChB,QAAQ,aAAa,EACrB,YAAY,oDAAoD;AAEnE,aACG,QAAQ,MAAM,EACd,YAAY,iCAAiC,EAC7C,OAAO,wBAAwB,uDAAuD,EACtF,OAAO,UAAU,gBAAgB,EACjC,OAAOL,YAAW;AAErB,aACG,QAAQ,UAAU,EAClB,YAAY,uCAAuC,EACnD,OAAO,UAAU,gBAAgB,EACjC,OAAOC,WAAU;AAEpB,aACG,QAAQ,QAAQ,EAChB,YAAY,qDAAqD,EACjE,eAAe,wBAAwB,qBAAqB,EAC5D,eAAe,iBAAiB,2CAA2C,EAC3E;AAAA,IACC;AAAA,IACA;AAAA,EACF,EACC,OAAO,+BAA+B,2BAA2B,EACjE,OAAO,UAAU,gBAAgB,EACjC,OAAOC,cAAa;AAEvB,aACG,QAAQ,aAAa,EACrB,YAAY,oCAAoC,EAChD,OAAO,iBAAiB,oBAAoB,EAC5C,OAAO,iBAAiB,uCAAuC,EAC/D,OAAO,+BAA+B,2BAA2B,EACjE,OAAO,UAAU,gBAAgB,EACjC,OAAOC,cAAa;AAEvB,aACG,QAAQ,aAAa,EACrB,YAAY,oCAAoC,EAChD,OAAO,WAAW,mBAAmB,EACrC,OAAOC,cAAa;AACzB;;;AC/PA,SAAS,oBAAoB,MAAkC;AAC7D,MAAI,KAAK,QAAQ,WAAW,GAAG;AAC7B,YAAQ,IAAI,oBAAoB;AAChC;AAAA,EACF;AAGA,QAAM,UAAU,CAAC,MAAM,SAAS,OAAO,SAAS,UAAU,YAAY,QAAQ,QAAQ;AACtF,QAAM,OAAO,KAAK,QAAQ,IAAI,CAAC,WAAW;AAAA,IACxC,OAAO,GAAG,MAAM,GAAG,EAAE,IAAI;AAAA,IACzB,OAAO,cAAc,OAAO,UAAU,OAAO,QAAQ,MAAM,GAAG,EAAE,IAAI,QAAQ;AAAA,IAC5E,OAAO,IAAI,MAAM,GAAG,EAAE;AAAA,IACtB,OAAO,SAAS,MAAM,GAAG,EAAE,KAAK;AAAA,IAChC,OAAO,OAAO,MAAM;AAAA,IACpB,OAAO,OAAO,WAAW;AAAA,IACzB,OAAO,aAAa,QAAQ;AAAA,IAC5B,OAAO,iBAAiB,MAAM,GAAG,EAAE;AAAA,EACrC,CAAC;AAED,QAAM,SAAS,QAAQ;AAAA,IAAI,CAAC,GAAG,MAC7B,KAAK,IAAI,EAAE,QAAQ,GAAG,KAAK,IAAI,CAAC,MAAM,EAAE,CAAC,EAAE,MAAM,CAAC;AAAA,EACpD;AAGA,UAAQ,IAAI,QAAQ,IAAI,CAAC,GAAG,MAAM,EAAE,OAAO,OAAO,CAAC,CAAC,CAAC,EAAE,KAAK,IAAI,CAAC;AACjE,UAAQ,IAAI,OAAO,IAAI,CAAC,MAAM,IAAI,OAAO,CAAC,CAAC,EAAE,KAAK,IAAI,CAAC;AAGvD,aAAW,OAAO,MAAM;AACtB,YAAQ,IAAI,IAAI,IAAI,CAAC,MAAM,MAAM,KAAK,OAAO,OAAO,CAAC,CAAC,CAAC,EAAE,KAAK,IAAI,CAAC;AAAA,EACrE;AAGA,UAAQ,IAAI,EAAE;AACd,UAAQ,IAAI,WAAW,KAAK,QAAQ,MAAM,OAAO,KAAK,KAAK,qBAAqB,KAAK,MAAM,GAAG;AAC9F,MAAI,KAAK,SAAS;AAChB,YAAQ,IAAI,gBAAgB,KAAK,SAAS,KAAK,KAAK,sBAAsB;AAAA,EAC5E;AACF;AAEA,SAAS,qBAAqB,QAA8B;AAC1D,UAAQ,IAAI,iBAAiB,OAAO,EAAE,EAAE;AACxC,UAAQ,IAAI,iBAAiB,OAAO,SAAS,EAAE;AAC/C,UAAQ,IAAI,iBAAiB,OAAO,aAAa,GAAG,KAAK,OAAO,WAAW,GAAG,GAAG;AACjF,UAAQ,IAAI,iBAAiB,OAAO,gBAAgB,GAAG,KAAK,OAAO,cAAc,GAAG,GAAG;AACvF,MAAI,OAAO,iBAAiB;AAC1B,YAAQ,IAAI,iBAAiB,OAAO,eAAe,EAAE;AAAA,EACvD;AACA,UAAQ,IAAI,iBAAiB,OAAO,GAAG,EAAE;AACzC,UAAQ,IAAI,iBAAiB,OAAO,WAAW,GAAG,KAAK,OAAO,aAAa,GAAG,GAAG;AACjF,UAAQ,IAAI,iBAAiB,OAAO,MAAM,EAAE;AAC5C,UAAQ,IAAI,iBAAiB,OAAO,WAAW,IAAI;AACnD,UAAQ,IAAI,iBAAiB,OAAO,aAAa,QAAQ,IAAI,EAAE;AAC/D,UAAQ,IAAI,iBAAiB,OAAO,UAAU,QAAQ,IAAI,EAAE;AAC5D,UAAQ,IAAI,iBAAiB,OAAO,gBAAgB,EAAE;AAEtD,MAAI,OAAO,eAAe,OAAO,YAAY,SAAS,GAAG;AACvD,YAAQ,IAAI,iBAAiB,OAAO,YAAY,KAAK,IAAI,CAAC,EAAE;AAAA,EAC9D;AAEA,MAAI,OAAO,WAAW;AACpB,YAAQ,IAAI,EAAE;AACd,YAAQ,IAAI,YAAY;AACxB,YAAQ,IAAI,iBAAiB,OAAO,UAAU,QAAQ,GAAG,EAAE;AAC3D,YAAQ,IAAI,iBAAiB,OAAO,UAAU,WAAW,GAAG,EAAE;AAC9D,YAAQ,IAAI,iBAAiB,OAAO,UAAU,qBAAqB,GAAG,UAAU;AAChF,YAAQ,IAAI,iBAAiB,OAAO,UAAU,+BAA+B,GAAG,EAAE;AAAA,EACpF;AAEA,MAAI,OAAO,WAAW,OAAO,KAAK,OAAO,OAAO,EAAE,SAAS,GAAG;AAC5D,YAAQ,IAAI,EAAE;AACd,YAAQ,IAAI,OAAO;AACnB,eAAW,CAAC,KAAK,KAAK,KAAK,OAAO,QAAQ,OAAO,OAAO,GAAG;AACzD,cAAQ,IAAI,KAAK,GAAG,KAAK,KAAK,EAAE;AAAA,IAClC;AAAA,EACF;AAEA,MAAI,OAAO,WAAW,QAAW;AAC/B,YAAQ,IAAI,EAAE;AACd,YAAQ,IAAI,SAAS;AACrB,YAAQ,IAAI,KAAK;AACjB,YAAQ,IAAI,OAAO,OAAO,MAAM,GAAG,GAAI,KAAK,OAAO,OAAO,SAAS,MAAO,QAAQ,GAAG;AACrF,YAAQ,IAAI,KAAK;AAAA,EACnB;AAEA,MAAI,OAAO,aAAa,QAAW;AACjC,YAAQ,IAAI,EAAE;AACd,YAAQ,IAAI,WAAW;AACvB,YAAQ,IAAI,KAAK;AACjB,YAAQ,IAAI,OAAO,SAAS,MAAM,GAAG,GAAI,KAAK,OAAO,SAAS,SAAS,MAAO,QAAQ,GAAG;AACzF,YAAQ,IAAI,KAAK;AAAA,EACnB;AACF;AAEA,SAAS,cAAc,KAA2B;AAChD,QAAM,SAAS,IAAI,cAAc;AACjC,QAAM,SAAS,IAAI,cAAc;AACjC,SAAO,GAAG,MAAM,GAAG,IAAI,KAAK,GAAG,MAAM;AACvC;AAEA,SAAS,mBAAmB,MAAkC;AAE5D,UAAQ,IAAI,YAAY;AACxB,aAAW,OAAO,KAAK,UAAU;AAC/B,YAAQ,IAAI,KAAK,IAAI,KAAK,OAAO,EAAE,CAAC,IAAI,cAAc,GAAG,CAAC,EAAE;AAAA,EAC9D;AAGA,MAAI,KAAK,KAAK,SAAS,GAAG;AACxB,YAAQ,IAAI,EAAE;AACd,YAAQ,IAAI,cAAc;AAC1B,UAAM,UAAU,CAAC,QAAQ,SAAS,QAAQ,eAAe,aAAa;AACtE,UAAM,OAAO,KAAK,KAAK,IAAI,CAAC,QAAQ;AAAA,MAClC,IAAI,KAAK,MAAM,GAAG,EAAE;AAAA,MACpB,IAAI,UAAU,OAAO,OAAO,IAAI,KAAK,IAAI;AAAA,MACzC,IAAI,QAAQ;AAAA,MACZ,IAAI;AAAA,MACJ,OAAO,IAAI,cAAc;AAAA,IAC3B,CAAC;AAED,UAAM,SAAS,QAAQ;AAAA,MAAI,CAAC,GAAG,MAC7B,KAAK,IAAI,EAAE,QAAQ,GAAG,KAAK,IAAI,CAAC,MAAM,EAAE,CAAC,EAAE,MAAM,CAAC;AAAA,IACpD;AAEA,YAAQ,IAAI,OAAO,QAAQ,IAAI,CAAC,GAAG,MAAM,EAAE,OAAO,OAAO,CAAC,CAAC,CAAC,EAAE,KAAK,IAAI,CAAC;AACxE,YAAQ,IAAI,OAAO,OAAO,IAAI,CAAC,MAAM,IAAI,OAAO,CAAC,CAAC,EAAE,KAAK,IAAI,CAAC;AAE9D,eAAW,OAAO,MAAM;AACtB,cAAQ,IAAI,OAAO,IAAI,IAAI,CAAC,MAAM,MAAM,KAAK,OAAO,OAAO,CAAC,CAAC,CAAC,EAAE,KAAK,IAAI,CAAC;AAAA,IAC5E;AAAA,EACF;AAGA,MAAI,KAAK,cAAc,KAAK,WAAW,SAAS,GAAG;AACjD,YAAQ,IAAI,EAAE;AACd,YAAQ,IAAI,mBAAmB;AAC/B,eAAW,UAAU,KAAK,YAAY;AACpC,cAAQ,IAAI,KAAK,OAAO,WAAW,MAAM,OAAO,SAAS,EAAE;AAC3D,iBAAW,OAAO,OAAO,UAAU;AACjC,gBAAQ,IAAI,OAAO,IAAI,IAAI,KAAK,cAAc,GAAG,CAAC,EAAE;AAAA,MACtD;AAAA,IACF;AAAA,EACF;AAGA,MAAI,KAAK,SAAS,KAAK,MAAM,SAAS,GAAG;AACvC,YAAQ,IAAI,EAAE;AACd,YAAQ,IAAI,yBAAyB,KAAK,MAAM,MAAM,UAAU;AAChE,YAAQ,IAAI,mCAAmC;AAAA,EACjD;AACF;AAEA,eAAeE,aAAY,SAUT;AAChB,MAAI;AACF,UAAM,OAAO,MAAM,aAAa;AAAA,MAC9B,SAAS,QAAQ;AAAA,MACjB,YAAY,QAAQ;AAAA,MACpB,OAAO,QAAQ;AAAA,MACf,OAAO,QAAQ;AAAA,MACf,OAAO,QAAQ,QAAQ,SAAS,QAAQ,OAAO,EAAE,IAAI;AAAA,MACrD,QAAQ,QAAQ,SAAS,SAAS,QAAQ,QAAQ,EAAE,IAAI;AAAA,MACxD,gBAAgB,QAAQ;AAAA,MACxB,kBAAkB,QAAQ;AAAA,IAC5B,CAAC;AAED,QAAI,QAAQ,MAAM;AAChB,cAAQ,IAAI,KAAK,UAAU,MAAM,MAAM,CAAC,CAAC;AAAA,IAC3C,OAAO;AACL,0BAAoB,IAAI;AAAA,IAC1B;AAAA,EACF,SAAS,OAAO;AACd,YAAQ;AAAA,MACN,UAAU,iBAAiB,QAAQ,MAAM,UAAU,eAAe;AAAA,IACpE;AACA,YAAQ,KAAK,CAAC;AAAA,EAChB;AACF;AAEA,eAAeC,YACb,IACA,SACe;AACf,MAAI;AACF,UAAM,SAAS,MAAM,YAAY,IAAI,QAAQ,cAAc;AAE3D,QAAI,QAAQ,MAAM;AAChB,cAAQ,IAAI,KAAK,UAAU,QAAQ,MAAM,CAAC,CAAC;AAAA,IAC7C,OAAO;AACL,2BAAqB,MAAM;AAAA,IAC7B;AAAA,EACF,SAAS,OAAO;AACd,YAAQ;AAAA,MACN,UAAU,iBAAiB,QAAQ,MAAM,UAAU,eAAe;AAAA,IACpE;AACA,YAAQ,KAAK,CAAC;AAAA,EAChB;AACF;AAEA,eAAe,YAAY,SAQT;AAChB,MAAI;AACF,QAAI,CAAC,QAAQ,WAAW,CAAC,QAAQ,YAAY;AAC3C,cAAQ,MAAM,uDAAuD;AACrE,cAAQ,KAAK,CAAC;AAAA,IAChB;AAEA,UAAM,OAAO,MAAM,gBAAgB;AAAA,MACjC,SAAS,QAAQ;AAAA,MACjB,YAAY,QAAQ;AAAA,MACpB,OAAO,QAAQ;AAAA,MACf,OAAO,QAAQ;AAAA,MACf,QAAQ,QAAQ;AAAA,MAChB,cAAc,QAAQ;AAAA,IACxB,CAAC;AAED,QAAI,QAAQ,MAAM;AAChB,cAAQ,IAAI,KAAK,UAAU,MAAM,MAAM,CAAC,CAAC;AAAA,IAC3C,OAAO;AACL,yBAAmB,IAAI;AAAA,IACzB;AAAA,EACF,SAAS,OAAO;AACd,YAAQ;AAAA,MACN,UAAU,iBAAiB,QAAQ,MAAM,UAAU,eAAe;AAAA,IACpE;AACA,YAAQ,KAAK,CAAC;AAAA,EAChB;AACF;AAEA,SAAS,oBAAoB,MAAkC;AAE7D,UAAQ,IAAI,2BAA2B;AACvC,UAAQ,IAAI,EAAE;AACd,UAAQ,IAAI,UAAU;AACtB,UAAQ,IAAI,sBAAsB,KAAK,QAAQ,YAAY,EAAE;AAE7D,QAAM,WAAW,CAAC,aAAa,OAAO,qBAAqB,uBAAuB,SAAS;AAC3F,aAAW,UAAU,UAAU;AAC7B,UAAM,QAAQ,KAAK,QAAQ,SAAS,MAAM,KAAK;AAC/C,UAAM,MAAM,KAAK,QAAQ,eAAe,KAAM,QAAQ,KAAK,QAAQ,eAAgB,KAAK,QAAQ,CAAC,IAAI;AACrG,UAAM,QAAQ,OAAO,OAAO,CAAC,IAAI,OAAO,MAAM,CAAC,EAAE,YAAY,EAAE,QAAQ,MAAM,GAAG;AAChF,YAAQ,IAAI,KAAK,MAAM,OAAO,EAAE,CAAC,IAAI,OAAO,KAAK,EAAE,SAAS,CAAC,CAAC,KAAK,GAAG,IAAI;AAAA,EAC5E;AAEA,MAAI,KAAK,SAAS,WAAW,GAAG;AAC9B,YAAQ,IAAI,EAAE;AACd,YAAQ,IAAI,oBAAoB;AAChC;AAAA,EACF;AAEA,UAAQ,IAAI,EAAE;AAGd,QAAM,UAAU,CAAC,MAAM,UAAU,QAAQ,aAAa,UAAU,YAAY,SAAS;AACrF,QAAM,OAAO,KAAK,SAAS,IAAI,CAAC,MAAM;AAAA,IACpC,EAAE,GAAG,MAAM,GAAG,EAAE,IAAI;AAAA,IACpB,EAAE;AAAA,IACF,EAAE,kBAAkB;AAAA,IACpB,EAAE,sBAAsB,QAAQ;AAAA,IAChC,OAAO,EAAE,qBAAqB;AAAA,IAC9B,EAAE,aAAa,QAAQ;AAAA,IACvB,EAAE,oBAAoB;AAAA,EACxB,CAAC;AAED,QAAM,SAAS,QAAQ;AAAA,IAAI,CAAC,GAAG,MAC7B,KAAK,IAAI,EAAE,QAAQ,GAAG,KAAK,IAAI,CAAC,MAAM,EAAE,CAAC,EAAE,MAAM,CAAC;AAAA,EACpD;AAEA,UAAQ,IAAI,QAAQ,IAAI,CAAC,GAAG,MAAM,EAAE,OAAO,OAAO,CAAC,CAAC,CAAC,EAAE,KAAK,IAAI,CAAC;AACjE,UAAQ,IAAI,OAAO,IAAI,CAAC,MAAM,IAAI,OAAO,CAAC,CAAC,EAAE,KAAK,IAAI,CAAC;AAEvD,aAAW,OAAO,MAAM;AACtB,YAAQ,IAAI,IAAI,IAAI,CAAC,MAAM,MAAM,KAAK,OAAO,OAAO,CAAC,CAAC,CAAC,EAAE,KAAK,IAAI,CAAC;AAAA,EACrE;AAEA,UAAQ,IAAI,EAAE;AACd,UAAQ,IAAI,WAAW,KAAK,SAAS,MAAM,OAAO,KAAK,KAAK,qBAAqB,KAAK,MAAM,GAAG;AAC/F,MAAI,KAAK,SAAS;AAChB,YAAQ,IAAI,gBAAgB,KAAK,SAAS,KAAK,KAAK,sBAAsB;AAAA,EAC5E;AACF;AAEA,eAAe,gBAAgB,SAOb;AAChB,MAAI;AACF,UAAM,OAAO,MAAM,aAAa;AAAA,MAC9B,SAAS,QAAQ;AAAA,MACjB,OAAO,QAAQ;AAAA,MACf,OAAO,QAAQ;AAAA,MACf,OAAO,QAAQ,QAAQ,SAAS,QAAQ,OAAO,EAAE,IAAI;AAAA,MACrD,QAAQ,QAAQ,SAAS,SAAS,QAAQ,QAAQ,EAAE,IAAI;AAAA,IAC1D,CAAC;AAED,QAAI,QAAQ,MAAM;AAChB,cAAQ,IAAI,KAAK,UAAU,MAAM,MAAM,CAAC,CAAC;AAAA,IAC3C,OAAO;AACL,0BAAoB,IAAI;AAAA,IAC1B;AAAA,EACF,SAAS,OAAO;AACd,YAAQ;AAAA,MACN,UAAU,iBAAiB,QAAQ,MAAM,UAAU,eAAe;AAAA,IACpE;AACA,YAAQ,KAAK,CAAC;AAAA,EAChB;AACF;AAEO,SAAS,wBAAwBC,UAAwB;AAC9D,QAAM,WAAWA,SACd,QAAQ,UAAU,EAClB,YAAY,iCAAiC;AAEhD,WACG,QAAQ,MAAM,EACd,YAAY,mCAAmC,EAC/C,OAAO,mBAAmB,oBAAoB,EAC9C,OAAO,sBAAsB,uBAAuB,EACpD,OAAO,kBAAkB,yBAAyB,EAClD,OAAO,kBAAkB,uBAAuB,EAChD,OAAO,eAAe,oBAAoB,IAAI,EAC9C,OAAO,gBAAgB,wBAAwB,GAAG,EAClD,OAAO,qBAAqB,iCAAiC,EAC7D,OAAO,uBAAuB,4BAA4B,EAC1D,OAAO,UAAU,gBAAgB,EACjC,OAAOF,YAAW;AAErB,WACG,QAAQ,UAAU,EAClB,YAAY,4BAA4B,EACxC,OAAO,qBAAqB,iCAAiC,EAC7D,OAAO,UAAU,gBAAgB,EACjC,OAAOC,WAAU;AAEpB,WACG,QAAQ,MAAM,EACd,YAAY,2BAA2B,EACvC,OAAO,mBAAmB,UAAU,EACpC,OAAO,sBAAsB,aAAa,EAC1C,OAAO,kBAAkB,2BAA2B,EACpD,OAAO,kBAAkB,yBAAyB,EAClD,OAAO,mBAAmB,4CAA4C,EACtE,OAAO,mBAAmB,6BAA6B,EACvD,OAAO,UAAU,gBAAgB,EACjC,OAAO,WAAW;AAErB,WACG,QAAQ,UAAU,EAClB,YAAY,4DAA4D,EACxE,eAAe,mBAAmB,qBAAqB,EACvD,OAAO,kBAAkB,yBAAyB,EAClD,OAAO,kBAAkB,uBAAuB,EAChD,OAAO,eAAe,oBAAoB,IAAI,EAC9C,OAAO,gBAAgB,wBAAwB,GAAG,EAClD,OAAO,UAAU,gBAAgB,EACjC,OAAO,eAAe;AAC3B;;;ACrYA,YAAYE,UAAQ;;;ACApB,YAAYC,SAAQ;;;ACiBb,IAAM,WAA8B;AAAA,EACzC;AAAA,EACA;AAAA,EACA;AACF;AAwIA,IAAM,WAAW,oBAAI,IAA+B;AAE7C,SAAS,eAAe,QAAiC;AAC9D,WAAS,IAAI,OAAO,IAAI,MAAM;AAChC;AAEO,SAAS,UAAU,IAA+B;AACvD,MAAI,CAAC,SAAS,EAAE,GAAG;AACjB,UAAM,IAAI;AAAA,MACR,kBAAkB,EAAE,uBAAuB,SAAS,KAAK,IAAI,CAAC;AAAA,IAChE;AAAA,EACF;AACA,QAAM,SAAS,SAAS,IAAI,EAAE;AAC9B,MAAI,CAAC,QAAQ;AACX,UAAM,IAAI;AAAA,MACR,SAAS,EAAE;AAAA,IACb;AAAA,EACF;AACA,SAAO;AACT;AAOO,SAAS,cAAmC;AACjD,SAAO,MAAM,KAAK,SAAS,OAAO,CAAC;AACrC;AAEO,SAAS,SAAS,OAAgC;AACvD,SAAQ,SAA+B,SAAS,KAAK;AACvD;;;ACzKA,YAAY,QAAQ;AACpB,YAAY,QAAQ;AACpB,YAAY,UAAU;AAYtB,IAAM,qBAAqB,CAAC,WAAW,eAAe;AAOtD,SAAS,YAAY,SAAyB;AAC5C,SAAY,UAAK,SAAS,GAAG,kBAAkB;AACjD;AAEA,SAAS,aAAa,WAAmB,SAAyB;AAChE,SAAY,UAAK,YAAY,OAAO,GAAG,GAAG,SAAS,OAAO;AAC5D;AAQA,IAAI,cAAkC;AAE/B,SAAS,eAAe,QAAkC;AAC/D,gBAAc;AAChB;AAEA,SAAS,IAAI,OAAe,MAAqB;AAC/C,MAAI,aAAa;AACf,QAAI;AACF,kBAAY,OAAO,IAAI;AAAA,IACzB,QAAQ;AAAA,IAER;AAAA,EACF;AACF;AAMO,SAAS,iBACd,WACA,UAAqB,WAAQ,GACD;AAC5B,MAAI,CAAC,UAAW,QAAO;AACvB,QAAM,WAAW,aAAa,WAAW,OAAO;AAChD,MAAI;AACF,QAAI,CAAI,cAAW,QAAQ,EAAG,QAAO;AACrC,UAAM,MAAS,gBAAa,UAAU,OAAO;AAC7C,UAAM,SAAS,KAAK,MAAM,GAAG;AAC7B,QACE,OAAO,QAAQ,sBAAsB,YACrC,OAAO,QAAQ,mBAAmB,YAClC,OAAO,QAAQ,yBAAyB,UACxC;AAGA,aAAO;AAAA,IACT;AACA,WAAO;AAAA,MACL,mBAAmB,OAAO;AAAA,MAC1B,gBAAgB,OAAO;AAAA,MACvB,sBAAsB,OAAO;AAAA,IAC/B;AAAA,EACF,SAAS,KAAK;AACZ,QAAI,qBAAqB;AAAA,MACvB;AAAA,MACA,OAAQ,IAAc;AAAA,IACxB,CAAC;AACD,WAAO;AAAA,EACT;AACF;AAMO,SAAS,iBACd,WACA,OACA,UAAqB,WAAQ,GACvB;AACN,MAAI,CAAC,UAAW;AAChB,QAAM,MAAM,YAAY,OAAO;AAC/B,QAAM,WAAW,aAAa,WAAW,OAAO;AAChD,MAAI;AACF,QAAI,CAAI,cAAW,GAAG,GAAG;AACvB,MAAG,aAAU,KAAK,EAAE,WAAW,KAAK,CAAC;AAAA,IACvC;AACA,IAAG,iBAAc,UAAU,KAAK,UAAU,OAAO,MAAM,CAAC,IAAI,MAAM,OAAO;AAAA,EAC3E,SAAS,KAAK;AACZ,QAAI,qBAAqB;AAAA,MACvB;AAAA,MACA,OAAQ,IAAc;AAAA,IACxB,CAAC;AAAA,EACH;AACF;AAYO,SAAS,iBACd,UACA,sBACS;AACT,MAAI,CAAC,qBAAsB,QAAO;AAClC,MAAI,CAAC,SAAU,QAAO;AACtB,SAAO,SAAS,sBAAsB;AACxC;;;ACtJA,YAAYC,SAAQ;;;ACIpB,YAAY,cAAc;AAEnB,SAAS,WAAW,UAAmC;AAC5D,QAAM,KAAc,yBAAgB;AAAA,IAClC,OAAO,QAAQ;AAAA,IACf,QAAQ,QAAQ;AAAA,EAClB,CAAC;AACD,SAAO,IAAI,QAAQ,CAAC,YAAY;AAC9B,OAAG,SAAS,UAAU,CAAC,WAAW;AAChC,SAAG,MAAM;AACT,cAAQ,OAAO,KAAK,CAAC;AAAA,IACvB,CAAC;AAAA,EACH,CAAC;AACH;AAOO,SAAS,gBAAyB;AACvC,SAAO,QAAQ,QAAQ,MAAM,SAAS,QAAQ,OAAO,KAAK;AAC5D;;;ACMA,eAAsB,qBACpB,MACe;AACf,QAAM,aAAa,MAAM;AAAA,IACvB,KAAK;AAAA,IACL,KAAK;AAAA,EACP;AAEA,MAAI,eAAe,MAAM;AAIvB,YAAQ;AAAA,MACN;AAAA,IACF;AACA;AAAA,EACF;AAEA,MAAI,KAAK,qBAAqB,MAAM;AAIlC;AAAA,EACF;AAEA,MAAI,WAAW,aAAa,KAAK,kBAAkB;AAEjD;AAAA,EACF;AAKA,UAAQ,IAAI,EAAE;AACd,UAAQ;AAAA,IACN,iDAA4C,KAAK,iBAAiB,MAAM,KAAK,eAAe;AAAA,EAC9F;AACA,UAAQ;AAAA,IACN;AAAA,EACF;AACA,UAAQ;AAAA,IACN,gDAA2C,KAAK,iBAAiB;AAAA,EACnE;AACA,UAAQ,IAAI,EAAE;AAEd,QAAM,UAAU,MAAM,WAAW,wCAAwC;AACzE,MAAI,QAAQ,KAAK,EAAE,YAAY,MAAM,KAAK;AACxC,YAAQ,IAAI,2DAA2D;AACvE,YAAQ,KAAK,CAAC;AAAA,EAChB;AACF;;;AFxDA,OAAOC,WAAU;AAEjB,IAAM,qBAAqB;AAC3B,IAAM,2BAA2B;AACjC,IAAM,6BAA6B;AAEnC,eAAsB,kBACpB,MACwB;AACxB,QAAM,cAAc,KAAK,eAAe,QAAQ,IAAI;AAEpD,QAAM,QAAQ,cAAc;AAC5B,MAAI,CAAC,OAAO;AACV,YAAQ,MAAM,0CAA0C;AACxD,YAAQ,KAAK,CAAC;AAAA,EAChB;AAEA,UAAQ,IAAI,2DAA2D;AAEvE,QAAM,UAAUA,MAAK,SAAS,WAAW;AAEzC,MAAI;AACJ,QAAM,SAAS,MAAM;AAAA,IACnB;AAAA,EACF;AAEA,MAAI,OAAO,YAAY,MAAM,cAAc,OAAO,YAAY,MAAM,KAAK;AACvE,UAAM,SAAS,MAAM,WAAW;AAChC,QAAI,OAAO,WAAW,GAAG;AACvB,cAAQ,IAAI,gDAAgD;AAC5D,cAAQ,MAAM,eAAe,OAAO;AAAA,IACtC,OAAO;AACL,cAAQ,IAAI,qBAAqB;AACjC,eAAS,IAAI,GAAG,IAAI,OAAO,QAAQ,KAAK;AACtC,gBAAQ;AAAA,UACN,KAAK,IAAI,CAAC,KAAK,OAAO,CAAC,EAAE,IAAI,KAAK,OAAO,CAAC,EAAE,GAAG,MAAM,GAAG,EAAE,CAAC;AAAA,QAC7D;AAAA,MACF;AAEA,YAAM,YAAY,MAAM,WAAW;AAAA,kBAAqB,OAAO,MAAM,KAAK;AAC1E,YAAM,MAAM,SAAS,WAAW,EAAE,IAAI;AAEtC,UAAI,MAAM,GAAG,KAAK,MAAM,KAAK,OAAO,OAAO,QAAQ;AACjD,gBAAQ,MAAM,oBAAoB;AAClC,gBAAQ,KAAK,CAAC;AAAA,MAChB;AAEA,cAAQ,MAAM,SAAS,OAAO,GAAG,EAAE,EAAE;AAErC,UAAI,CAAC,MAAM,QAAQ,OAAO,CAAC,MAAM,QAAQ,UAAU;AACjD,gBAAQ;AAAA,UACN;AAAA,QACF;AACA,gBAAQ,IAAI,oDAAoD;AAChE,cAAM,YAAY,MAAM,WAAW,iCAAiC;AACpE,YAAI,UAAU,YAAY,MAAM,KAAK;AACnC,kBAAQ,MAAM,eAAe,OAAO;AAAA,QACtC,OAAO;AACL,kBAAQ,KAAK,CAAC;AAAA,QAChB;AAAA,MACF;AAAA,IACF;AAAA,EACF,OAAO;AACL,YAAQ,MAAM,eAAe,OAAO;AAAA,EACtC;AAEA,QAAM,qBAAqB,GAAG,WAAW,CAAC;AAE1C,MAAI,SAAS,MAAM,QAAQ;AAC3B,MAAI,CAAC,QAAQ;AACX,YAAQ;AAAA,MACN;AAAA,IACF;AACA,aAAS,MAAM,WAAW,oCAAoC;AAC9D,QAAI,CAAC,QAAQ;AACX,cAAQ,MAAM,qCAAqC;AACnD,cAAQ,KAAK,CAAC;AAAA,IAChB;AAOA,UAAM,qBAAqB;AAAA,MACzB;AAAA,MACA;AAAA,MACA,iBAAiB,MAAM;AAAA,MACvB,mBAAmB,MAAM;AAAA,MACzB,kBAAkB,MAAM,QAAQ,MAAM;AAAA,IACxC,CAAC;AAAA,EACH;AAEA,QAAM,YAAY,aAAa,WAAW;AAC1C,MAAI,CAAI,eAAW,SAAS,GAAG;AAC7B,IAAG,cAAU,WAAW,EAAE,WAAW,KAAK,CAAC;AAAA,EAC7C;AAEA,QAAM,eAAe,gBAAgB,WAAW;AAChD,QAAM,mBAAmB,aAA6B,YAAY,KAAK,CAAC;AACxE,QAAM,cAAc,mBAAmB,iBAAiB,KAAK;AAC7D,QAAM,kBAAkC;AAAA,IACtC,GAAG;AAAA,IACH,OAAO;AAAA,EACT;AACA,gBAAc,cAAc,eAAe;AAE3C,QAAM,gBAA+B;AAAA,IACnC,SAAS,MAAM;AAAA,IACf;AAAA,IACA,WAAW,MAAM;AAAA,IACjB,QAAQ;AAAA,IACR,YAAW,oBAAI,KAAK,GAAE,YAAY;AAAA,IAClC;AAAA,EACF;AACA,wBAAsB,aAAa,aAAa;AAEhD,QAAM,aAAa,wBAAwB,WAAW;AACtD,QAAM,YAAYA,MAAK,SAAS,aAAa,UAAU;AAEvD,UAAQ,IAAI,EAAE;AACd,UAAQ,IAAI,iBAAY,MAAM,IAAI,qBAAqB,MAAM,EAAE,GAAG;AAClE,MAAI,MAAM,QAAQ,KAAK;AACrB,YAAQ,IAAI,0BAAqB;AAAA,EACnC;AACA,UAAQ;AAAA,IACN,0CAAqC,UAAU,IAAI,aAAa;AAAA,EAClE;AACA,UAAQ,IAAI,kCAA6B,SAAS,EAAE;AACpD,UAAQ,IAAI,EAAE;AACd,UAAQ;AAAA,IACN;AAAA,EACF;AACA,UAAQ,IAAI,mCAAmC,WAAW,CAAC,YAAY;AACvE,UAAQ,IAAI,EAAE;AACd,UAAQ;AAAA,IACN,iBAAY,UAAU;AAAA,EACxB;AACA,UAAQ,IAAI,EAAE;AACd,UAAQ,IAAI,4DAA4D;AACxE,UAAQ,IAAI,6DAA6D;AAEzE,SAAO;AAAA,IACL,SAAS,MAAM;AAAA,IACf,WAAW,MAAM;AAAA,IACjB,QAAQ;AAAA,IACR;AAAA,EACF;AACF;AAEA,eAAe,eAAe,aAAqC;AACjE,QAAM,YAAY,MAAM,WAAW,eAAe,WAAW,KAAK;AAClE,QAAM,YAAY,aAAa;AAC/B,SAAO,YAAY;AAAA,IACjB,MAAM;AAAA,IACN,aAAa,+BAA+B,SAAS;AAAA,IACrD,MAAM;AAAA,IACN,cAAc;AAAA,IACd,UAAU;AAAA,IACV,QAAQ;AAAA,EACV,CAAC;AACH;AAEA,eAAsB,oBAAoB,MAAoC;AAC5E,QAAM,cAAc,KAAK,eAAe,QAAQ,IAAI;AAEpD,QAAM,eAAe,gBAAgB,WAAW;AAChD,QAAM,WAAW,aAA6B,YAAY;AAE1D,MAAI,UAAU,OAAO;AACnB,UAAM,eAAmD,CAAC;AAC1D,eAAW,CAAC,OAAO,OAAO,KAAK,OAAO,QAAQ,SAAS,KAAK,GAAG;AAC7D,YAAM,WAAW,QAAQ;AAAA,QACvB,CAAC,MAAM,CAAC,EAAE,MAAM,KAAK,CAAC,MAAM,EAAE,QAAQ,SAAS,kBAAkB,CAAC;AAAA,MACpE;AACA,UAAI,SAAS,SAAS,GAAG;AACvB,qBAAa,KAAK,IAAI;AAAA,MACxB;AAAA,IACF;AACA,QAAI,OAAO,KAAK,YAAY,EAAE,SAAS,GAAG;AACxC,eAAS,QAAQ;AAAA,IACnB,OAAO;AACL,aAAO,SAAS;AAAA,IAClB;AACA,kBAAc,cAAc,QAAQ;AACpC,YAAQ;AAAA,MACN,oCAA+B,UAAU,IAAI,aAAa;AAAA,IAC5D;AAAA,EACF,OAAO;AACL,YAAQ,IAAI,kCAAkC;AAAA,EAChD;AAEA,MAAI,CAAC,KAAK,YAAY;AACpB,UAAM,aAAa,wBAAwB,WAAW;AACtD,UAAM,YAAYA,MAAK,SAAS,aAAa,UAAU;AACvD,QAAI,uBAAuB,WAAW,GAAG;AACvC,cAAQ,IAAI,kCAA6B,SAAS,GAAG;AAAA,IACvD;AAAA,EACF,OAAO;AACL,UAAM,aAAa,wBAAwB,WAAW;AACtD,UAAM,YAAYA,MAAK,SAAS,aAAa,UAAU;AACvD,YAAQ,IAAI,8BAA8B,SAAS,EAAE;AAAA,EACvD;AAEA,UAAQ,IAAI,EAAE;AACd,UAAQ;AAAA,IACN;AAAA,EACF;AACF;;;AGvNA,YAAYC,SAAQ;;;AC0FpB,IAAM,0BAA0B,oBAAI,IAAY;AAAA,EAC9C;AAAA,EACA;AAAA,EACA;AACF,CAAC;AAMD,IAAM,iBAAiB;AAgBvB,IAAM,cAAc;AAEb,SAAS,YAAY,aAAqD;AAC/E,MAAI,OAAO,gBAAgB,SAAU,QAAO;AAC5C,QAAM,UAAU,YAAY,UAAU;AACtC,MAAI,CAAC,QAAS,QAAO;AACrB,QAAM,QAAQ,YAAY,KAAK,OAAO;AACtC,MAAI,CAAC,MAAO,QAAO;AACnB,SAAO,MAAM,CAAC;AAChB;AAQO,SAAS,mBACd,SACQ;AACR,MAAI,OAAO,YAAY,SAAU,QAAO;AACxC,MAAI,CAAC,MAAM,QAAQ,OAAO,EAAG,QAAO;AACpC,QAAM,QAAkB,CAAC;AACzB,aAAW,SAAS,SAAS;AAC3B,QAAI,OAAO,SAAS,UAAU,OAAO,MAAM,SAAS,UAAU;AAC5D,YAAM,KAAK,MAAM,IAAI;AAAA,IACvB;AAAA,EACF;AACA,SAAO,MAAM,KAAK,IAAI,EAAE,KAAK;AAC/B;AAUO,SAAS,kBAAkB,MAAsB,MAAuB;AAC7E,MAAI,KAAK,WAAW,KAAM,QAAO;AACjC,MAAI,CAAC,KAAM,QAAO;AAClB,SACE,KAAK,SAAS,gBAAgB,KAC9B,KAAK,SAAS,wBAAwB,KACtC,KAAK,SAAS,mBAAmB;AAErC;AAMA,SAAS,eAAe,IAAgC;AACtD,MAAI,OAAO,OAAO,YAAY,CAAC,GAAI,QAAO;AAC1C,SAAO,KAAK,MAAM,EAAE;AACtB;AAQA,SAAS,kBAAkB,MAA+B;AACxD,MAAI,KAAK,SAAS,SAAU,QAAO;AACnC,QAAM,UAAU,KAAK,WAAW;AAChC,SACE,YAAY,sBACZ,YAAY,iBACZ,YAAY,kBACZ,WAAW,KAAK,OAAO;AAE3B;AAYO,SAAS,gBAAgB,KAAsC;AACpE,QAAM,QAAiC;AAAA,IACrC,QAAQ;AAAA,IACR,UAAU;AAAA,IACV,QAAQ;AAAA,IACR,aAAa;AAAA,IACb,cAAc;AAAA,IACd,WAAW;AAAA,IACX,UAAU;AAAA,IACV,eAAe;AAAA,IACf,kBAAkB;AAAA,IAClB,kBAAkB;AAAA,EACpB;AAEA,MAAI,CAAC,IAAK,QAAO;AAEjB,QAAM,QAAQ,IAAI,MAAM,IAAI;AAC5B,MAAI,eAAe;AACnB,MAAI,oBAA4B;AAMhC,MAAI;AACJ,MAAI,oBAAoB;AACxB,MAAI,yBAAiC;AACrC,MAAI,qBAAoC;AACxC,MAAI,2BAA2B;AAC/B,MAAI,4BAA4B;AAChC,MAAI,WAAW;AAKf,MAAI,2BAAmC;AAOvC,MAAI,gBAAgB;AACpB,MAAI,mBAAmB;AACvB,MAAI,kBAAkB,oBAAI,IAAY;AAEtC,aAAW,WAAW,OAAO;AAC3B,QAAI,CAAC,QAAS;AACd,QAAI;AACJ,QAAI;AACF,eAAS,KAAK,MAAM,OAAO;AAAA,IAC7B,QAAQ;AACN;AAAA,IACF;AAIA,QAAI,kBAAkB,MAAM,EAAG;AAK/B,QAAI,OAAO,gBAAgB,KAAM;AAEjC,QAAI,OAAO,SAAS,UAAU,OAAO,SAAS;AAC5C,YAAM,OAAO,mBAAmB,OAAO,QAAQ,OAAO;AACtD,UAAI,kBAAkB,QAAQ,IAAI,EAAG;AACrC,qBAAe;AACf,0BAAoB,eAAe,OAAO,SAAS;AACnD,iCAA2B;AAK3B,sBAAgB;AAChB,yBAAmB;AACnB,wBAAkB,oBAAI,IAAY;AAIlC,6BACE,OAAO,OAAO,cAAc,YAAY,OAAO,YAC3C,OAAO,YACP;AAAA,IACR,WAAW,OAAO,SAAS,eAAe,OAAO,SAAS;AACxD,YAAM,OAAO,mBAAmB,OAAO,QAAQ,OAAO;AAGtD,kBAAY;AACZ,UAAI,KAAM,qBAAoB;AAC9B,UAAI,OAAO,OAAO,QAAQ,UAAU,UAAU;AAC5C,6BAAqB,OAAO,QAAQ;AAAA,MACtC;AAOA,YAAM,UAAU,OAAO,QAAQ;AAC/B,UAAI,MAAM,QAAQ,OAAO,GAAG;AAC1B,mBAAW,SAAS,SAAS;AAC3B,cAAI;AACF,gBAAI,CAAC,SAAS,MAAM,SAAS,WAAY;AACzC,6BAAiB;AACjB,kBAAM,OAAO,OAAO,MAAM,SAAS,WAAW,MAAM,OAAO;AAC3D,gBAAI,SAAS,gBAAgB;AAC3B,kCAAoB;AACpB;AAAA,YACF;AACA,gBAAI,wBAAwB,IAAI,IAAI,GAAG;AACrC,oBAAM,QAAQ,MAAM;AACpB,kBACE,UAAU,QACV,OAAO,UAAU,YACjB,eAAe,OACf;AACA,sBAAM,WAAY,MAAkC;AACpD,oBAAI,OAAO,aAAa,YAAY,UAAU;AAC5C,kCAAgB,IAAI,QAAQ;AAAA,gBAC9B;AAAA,cACF;AAAA,YACF;AAAA,UACF,QAAQ;AAAA,UAGR;AAAA,QACF;AAAA,MACF;AACA,YAAM,QAAQ,OAAO,QAAQ;AAC7B,UAAI,OAAO;AAIT,cAAM,SACH,MAAM,gBAAgB,MACtB,MAAM,+BAA+B,MACrC,MAAM,2BAA2B;AACpC,cAAM,SAAS,MAAM,iBAAiB;AACtC,mCAA2B;AAC3B,oCAA4B;AAAA,MAC9B;AACA,YAAM,KAAK,eAAe,OAAO,SAAS;AAC1C,UAAI,CAAC,OAAO,MAAM,EAAE,GAAG;AACrB,iCAAyB;AAAA,MAC3B;AAAA,IACF;AAAA,EACF;AAEA,QAAM,SAAkC;AAAA,IACtC,QAAQ;AAAA,IACR,UAAU;AAAA,IACV,QAAQ,2BAA2B;AAAA,IACnC,aAAa;AAAA,IACb,cAAc;AAAA,IACd,WAAW;AAAA,IACX;AAAA,IACA;AAAA,IACA,kBAAkB,gBAAgB;AAAA,IAClC;AAAA,EACF;AAEA,MACE,CAAC,OAAO,MAAM,wBAAwB,KACtC,CAAC,OAAO,MAAM,sBAAsB,KACpC,0BAA0B,0BAC1B;AACA,WAAO,YAAY,KAAK;AAAA,MACtB,yBAAyB;AAAA,IAC3B;AAAA,EACF;AAEA,QAAM,QAAQ,YAAY,YAAY;AACtC,MAAI,OAAO;AACT,WAAO,QAAQ;AAAA,EACjB;AAEA,MAAI,sBAAsB;AACxB,WAAO,oBAAoB;AAAA,EAC7B;AAEA,SAAO;AACT;;;ADnVA,IAAM,YAAyB,MAAM;AAAC;AAQ/B,SAAS,sBACd,gBACAC,YAAwB,WACC;AACzB,QAAM,QAAiC;AAAA,IACrC,QAAQ;AAAA,IACR,UAAU;AAAA,IACV,QAAQ;AAAA,IACR,aAAa;AAAA,IACb,cAAc;AAAA,IACd,WAAW;AAAA,IACX,UAAU;AAAA,IACV,eAAe;AAAA,IACf,kBAAkB;AAAA,IAClB,kBAAkB;AAAA,EACpB;AAEA,MAAI,CAAC,eAAgB,QAAO;AAE5B,MAAI;AACJ,MAAI;AACF,UAAS,iBAAa,gBAAgB,OAAO;AAAA,EAC/C,SAAS,KAAK;AACZ,IAAAA,UAAS,0BAA0B;AAAA,MACjC;AAAA,MACA,OAAQ,IAAc;AAAA,IACxB,CAAC;AACD,WAAO;AAAA,EACT;AAEA,SAAO,gBAAgB,GAAG;AAC5B;AAEA,SAAS,oBAAoB,OAA4C;AACvE,QAAM,aAAa;AAAA,IACjB,MAAM;AAAA,IACN,MAAM;AAAA,IACN,MAAM;AAAA,IACN,MAAM,YAAY;AAAA,EACpB;AACA,aAAW,SAAS,YAAY;AAC9B,QAAI,OAAO,UAAU,YAAY,MAAM,KAAK,GAAG;AAC7C,aAAO,MAAM,KAAK;AAAA,IACpB;AAAA,EACF;AACA,SAAO;AACT;AAUO,SAAS,uBACd,OACA,WACA,QAC0B;AAC1B,QAAM,YAAY,UAAU,cAAc,eAAe,KAAK,IAAI,CAAC;AAEnE,UAAQ,OAAO;AAAA,IACb,KAAK;AAAA,IACL,KAAK,iBAAiB;AACpB,YAAM,YAAY,sBAAsB,UAAU,eAAe;AACjE,YAAM,aAAa,UAAU;AAE7B,YAAM,aAAsC;AAAA,QAC1C,WACE,UAAU,oBACT,aAAa,iBAAiB;AAAA,QACjC;AAAA,QACA,gBAAgB,UAAU,mBAAmB;AAAA,QAC7C,KAAK,UAAU,OAAO;AAAA,QACtB,gBAAgB,UAAU,oBAAoB;AAAA,QAC9C,aAAa,UAAU;AAAA,QACvB,cAAc,UAAU;AAAA,QACxB,UAAU,UAAU;AAAA;AAAA;AAAA;AAAA,QAIpB,eAAe,UAAU;AAAA,QACzB,kBAAkB,UAAU;AAAA,QAC5B,kBAAkB,UAAU;AAAA,MAC9B;AAEA,UAAI,OAAO,UAAU,cAAc,UAAU;AAC3C,mBAAW,YAAY,UAAU;AAAA,MACnC;AAEA,UAAI,YAAY;AACd,cAAM,WAAW,oBAAoB,SAAS;AAC9C,YAAI,UAAU;AACZ,qBAAW,WAAW;AAAA,QACxB;AAAA,MACF,WAAW,UAAU,OAAO;AAE1B,mBAAW,QAAQ,UAAU;AAAA,MAC/B;AAMA,YAAM,mBAAmB,UAAU;AACnC,YAAM,WACJ,OAAO,qBAAqB,YAAY,iBAAiB,KAAK,IAC1D,mBACA,UAAU;AAEhB,aAAO;AAAA,QACL,QAAQ,UAAU;AAAA,QAClB;AAAA,QACA,QAAQ;AAAA,QACR,QAAQ,OAAO;AAAA,QACf,WAAW,UAAU,aAAa;AAAA,QAClC,QAAQ,UAAU;AAAA,QAClB;AAAA,MACF;AAAA,IACF;AAAA,IAEA;AACE,aAAO;AAAA,EACX;AACF;;;ANvKA,IAAM,UAAU;AAChB,IAAM,wBAAwB,oBAAI,IAAI,CAAC,QAAQ,eAAe,CAAC;AAM/D,SAAS,SAAS,OAAe,MAAqB;AACpD,MAAI,QAAQ,IAAI,yBAAyB,IAAK;AAC9C,MAAI;AACF,UAAM,UAAU,6BAA6B,QAAQ,GAAG;AACxD,UAAM,OAAO,KAAI,oBAAI,KAAK,GAAE,YAAY,CAAC,KAAK,KAAK,KACjD,OAAO,SAAS,WAAW,OAAO,KAAK,UAAU,MAAM,MAAM,CAAC,CAChE;AAAA;AACA,IAAG,mBAAe,SAAS,MAAM,OAAO;AAAA,EAC1C,QAAQ;AAAA,EAER;AACF;AAcO,SAAS,8BACd,WACA,aACe;AACf,QAAM,aACJ,OAAO,UAAU,QAAQ,YAAY,UAAU,IAAI,KAAK,IACpD,UAAU,MACV;AACN,SAAO,wBAAwB,YAAY,CAAC,OAAO,CAAC;AACtD;AAEA,IAAM,mBAAsC;AAAA,EAC1C,IAAI;AAAA,EACJ,aAAa;AAAA,EAEb,QAAQ,MAA2C;AACjD,WAAO,kBAAkB,IAAI;AAAA,EAC/B;AAAA,EAEA,UAAU,MAAoC;AAC5C,WAAO,oBAAoB,IAAI;AAAA,EACjC;AAAA,EAEA,OAAO,MAA6B;AAClC,WAAO,oBAAoB,IAAI;AAAA,EACjC;AAAA,EAEA,MAAM,WACJ,WACA,aAC4B;AAC5B,mBAAe,QAAQ;AAEvB,UAAM,QAAQ,UAAU,KAAK;AAC7B,QAAI,CAAC,sBAAsB,IAAI,KAAK,GAAG;AACrC,eAAS,sBAAsB,KAAK;AACpC,aAAO;AAAA,IACT;AAEA,UAAM,YAAa,eAAe,CAAC;AACnC,aAAS,gBAAgB,EAAE,OAAO,UAAU,CAAC;AAE7C,UAAM,cAAc;AAAA,MAClB;AAAA,MACA,QAAQ,IAAI;AAAA,IACd;AACA,QAAI,CAAC,aAAa;AAChB,eAAS,oBAAoB;AAAA,QAC3B,UACE,OAAO,UAAU,QAAQ,YAAY,UAAU,IAAI,KAAK,IACpD,UAAU,MACV,QAAQ,IAAI;AAAA,MACpB,CAAC;AACD,aAAO;AAAA,IACT;AAEA,UAAM,SAAS,qBAAqB,aAAa,MAAM;AAAA,IAGvD,CAAC;AACD,QAAI,CAAC,QAAQ;AACX,eAAS,sBAAsB,EAAE,YAAY,CAAC;AAC9C,aAAO;AAAA,IACT;AAEA,UAAM,UAAU,uBAAuB,OAAO,WAAW,MAAM;AAC/D,QAAI,CAAC,QAAS,QAAO;AAErB,aAAS,iBAAiB,OAAO;AAMjC,UAAM,YACH,OAAO,UAAU,eAAe,YAAY,UAAU,cACvD;AACF,UAAM,YAAY;AAAA,MAChB,UAAU;AAAA,MACV;AAAA,IACF;AACA,UAAM,oBAAoB,UAAU;AAgBpC,QACE,UAAU,OAAO,KAAK,MAAM,MAC5B,UAAU,SAAS,KAAK,MAAM,MAC9B,UAAU,aAAa,GACvB;AACA,eAAS,oBAAoB;AAAA,QAC3B;AAAA,QACA;AAAA,QACA,gBAAgB,UAAU;AAAA,MAC5B,CAAC;AACD,aAAO;AAAA,IACT;AAEA,QAAI,WAAW;AACb,YAAM,gBAAgB,iBAAiB,SAAS;AAChD,UAAI,CAAC,iBAAiB,eAAe,iBAAiB,GAAG;AACvD,iBAAS,mBAAmB,EAAE,WAAW,kBAAkB,CAAC;AAC5D,eAAO;AAAA,MACT;AAAA,IACF;AAMA,QAAI,aAAa,mBAAmB;AAClC,uBAAiB,WAAW;AAAA,QAC1B,mBAAmB;AAAA,QACnB,iBAAgB,oBAAI,KAAK,GAAE,YAAY;AAAA,QACvC,sBAAsB,UAAU;AAAA,MAClC,CAAC;AACD,eAAS,eAAe;AAAA,QACtB;AAAA,QACA;AAAA,QACA,UAAU,UAAU;AAAA,MACtB,CAAC;AAAA,IACH;AAEA,WAAO;AAAA,MACL;AAAA,MACA,WAAW;AAAA,QACT,UAAU,OAAO;AAAA,QACjB,QAAQ,OAAO;AAAA,QACf;AAAA,MACF;AAAA,IACF;AAAA,EACF;AAAA,EAEA,MAAM,gBAAgB,MAAwB;AAC5C,UAAM,cAAc,MAAM,eAAe,QAAQ,IAAI;AACrD,QAAI;AACF,UAAO,eAAW,qBAAqB,aAAa,OAAO,CAAC,GAAG;AAC7D,eAAO;AAAA,MACT;AACA,UAAO,eAAW,iCAAiC,WAAW,CAAC,GAAG;AAChE,eAAO;AAAA,MACT;AACA,aAAO;AAAA,IACT,QAAQ;AACN,aAAO;AAAA,IACT;AAAA,EACF;AACF;AAEA,eAAe,gBAAgB;;;AQzM/B,YAAYC,SAAQ;AACpB,SAAS,iBAAiB;;;ACP1B,YAAYC,SAAQ;AACpB,YAAYC,WAAU;AACtB,YAAY,UAAU;;;ACPtB,YAAYC,SAAQ;AACpB,YAAYC,WAAU;AAEf,IAAM,qBAAqB;AAC3B,IAAM,wBAAwB;AAC9B,IAAM,yBAAyB;AAE/B,SAAS,kBAA0B;AACxC,SAAY,WAAQ,YAAQ,GAAG,kBAAkB;AACnD;AAEO,SAAS,qBAA6B;AAC3C,SAAY,WAAK,gBAAgB,GAAG,qBAAqB;AAC3D;AAEO,SAAS,sBAA8B;AAC5C,SAAY,WAAK,gBAAgB,GAAG,sBAAsB;AAC5D;;;ACAO,IAAMC,sBAAqB;AAE3B,IAAM,6BAA6B;AAUnC,IAAM,6BAA6B,CAAC,MAAM;AAuC1C,SAAS,qBACd,OACmB;AACnB,SAAO;AAAA,IACL,OAAO;AAAA,MACL;AAAA,QACE,MAAM;AAAA,QACN,SAAS,oCAAoC,KAAK;AAAA,QAClD,SAAS;AAAA,MACX;AAAA,IACF;AAAA,EACF;AACF;AAEA,SAAS,gBAAgB,SAAoC;AAC3D,SACE,OAAO,QAAQ,YAAY,YAC3B,QAAQ,QAAQ,SAASA,mBAAkB;AAE/C;AAEA,SAAS,2BAA2B,OAAmC;AACrE,MAAI,CAAC,MAAM,QAAQ,MAAM,KAAK,EAAG,QAAO;AACxC,SAAO,MAAM,MAAM,KAAK,eAAe;AACzC;AAYO,SAAS,gBACd,UACA,SAA4C,4BAC3B;AACjB,QAAM,SAA0B,EAAE,GAAI,YAAY,CAAC,EAAG;AAEtD,aAAW,SAAS,QAAQ;AAC1B,UAAM,iBAAiB,OAAO,KAAK,KAAK,CAAC;AACzC,UAAM,gBAAgB,eAAe,KAAK,0BAA0B;AACpE,QAAI,eAAe;AACjB,aAAO,KAAK,IAAI;AAAA,IAClB,OAAO;AACL,aAAO,KAAK,IAAI,CAAC,GAAG,gBAAgB,qBAAqB,KAAK,CAAC;AAAA,IACjE;AAAA,EACF;AAEA,SAAO;AACT;AAWO,SAAS,iBACd,UAC6B;AAC7B,MAAI,CAAC,SAAU,QAAO;AACtB,QAAM,UAA2B,CAAC;AAClC,aAAW,CAAC,OAAO,MAAM,KAAK,OAAO,QAAQ,QAAQ,GAAG;AACtD,QAAI,CAAC,MAAM,QAAQ,MAAM,EAAG;AAC5B,UAAM,iBAAsC,CAAC;AAC7C,eAAW,SAAS,QAAQ;AAC1B,YAAM,WAAW,MAAM,QAAQ,MAAM,KAAK,IAAI,MAAM,QAAQ,CAAC;AAC7D,YAAM,YAAY,SAAS,OAAO,CAAC,MAAM,CAAC,gBAAgB,CAAC,CAAC;AAC5D,UAAI,UAAU,WAAW,KAAK,SAAS,SAAS,GAAG;AAEjD;AAAA,MACF;AACA,UAAI,UAAU,WAAW,SAAS,QAAQ;AAExC,uBAAe,KAAK,KAAK;AAAA,MAC3B,OAAO;AACL,uBAAe,KAAK,EAAE,GAAG,OAAO,OAAO,UAAU,CAAC;AAAA,MACpD;AAAA,IACF;AACA,QAAI,eAAe,SAAS,GAAG;AAC7B,cAAQ,KAAK,IAAI;AAAA,IACnB;AAAA,EACF;AACA,SAAO,OAAO,KAAK,OAAO,EAAE,SAAS,IAAI,UAAU;AACrD;AAMO,SAAS,wBAAwB,QAAkC;AACxE,QAAM,QAAQ,OAAO;AACrB,MAAI,CAAC,MAAO,QAAO;AACnB,aAAW,UAAU,OAAO,OAAO,KAAK,GAAG;AACzC,QAAI,CAAC,MAAM,QAAQ,MAAM,EAAG;AAC5B,eAAW,SAAS,QAAQ;AAC1B,UAAI,2BAA2B,KAAK,EAAG,QAAO;AAAA,IAChD;AAAA,EACF;AACA,SAAO;AACT;;;ACnLA,YAAYC,SAAQ;AACpB,YAAYC,WAAU;AAef,SAASC,oBAAmB,aAA6B;AAC9D,SAAO,qBAAyB,aAAa,OAAO;AACtD;AAEO,SAAS,gBACd,aAC2B;AAC3B,QAAM,WAAWA,oBAAmB,WAAW;AAC/C,MAAI;AACF,QAAI,CAAI,eAAW,QAAQ,EAAG,QAAO;AACrC,UAAM,MAAS,iBAAa,UAAU,OAAO;AAC7C,WAAO,KAAK,MAAM,GAAG;AAAA,EACvB,QAAQ;AACN,WAAO;AAAA,EACT;AACF;AAEO,SAAS,iBACd,aACA,QACM;AACN,QAAM,WAAWA,oBAAmB,WAAW;AAC/C,QAAM,MAAW,cAAQ,QAAQ;AACjC,MAAI,CAAI,eAAW,GAAG,GAAG;AACvB,IAAG,cAAU,KAAK,EAAE,WAAW,KAAK,CAAC;AAAA,EACvC;AACA,EAAG,kBAAc,UAAU,KAAK,UAAU,QAAQ,MAAM,CAAC,IAAI,MAAM,OAAO;AAC1E,MAAI;AACF,IAAG,cAAU,UAAU,GAAK;AAAA,EAC9B,QAAQ;AAAA,EAER;AACF;AAEO,SAAS,kBAAkB,aAA8B;AAC9D,QAAM,WAAWA,oBAAmB,WAAW;AAC/C,MAAI,CAAI,eAAW,QAAQ,EAAG,QAAO;AACrC,MAAI;AACF,IAAG,eAAW,QAAQ;AACtB,WAAO;AAAA,EACT,QAAQ;AACN,WAAO;AAAA,EACT;AACF;;;AHnBO,IAAM,eAAe;AACrB,IAAM,qBAAqB;AAC3B,IAAM,uBAAuB;AAEpC,eAAsB,aAAa,MAA2C;AAC5E,QAAM,cAAc,KAAK,eAAe,QAAQ,IAAI;AAEpD,QAAM,QAAQ,cAAc;AAC5B,MAAI,CAAC,OAAO;AACV,YAAQ,MAAM,0CAA0C;AACxD,YAAQ,KAAK,CAAC;AAAA,EAChB;AAEA,UAAQ,IAAI,yDAAyD;AAErE,QAAM,UAAe,eAAS,WAAW;AAEzC,MAAI;AACJ,QAAM,SAAS,MAAM;AAAA,IACnB;AAAA,EACF;AAEA,MAAI,OAAO,YAAY,MAAM,cAAc,OAAO,YAAY,MAAM,KAAK;AACvE,UAAM,SAAS,MAAM,WAAW;AAChC,QAAI,OAAO,WAAW,GAAG;AACvB,cAAQ,IAAI,gDAAgD;AAC5D,cAAQ,MAAMC,gBAAe,OAAO;AAAA,IACtC,OAAO;AACL,cAAQ,IAAI,qBAAqB;AACjC,eAAS,IAAI,GAAG,IAAI,OAAO,QAAQ,KAAK;AACtC,gBAAQ;AAAA,UACN,KAAK,IAAI,CAAC,KAAK,OAAO,CAAC,EAAE,IAAI,KAAK,OAAO,CAAC,EAAE,GAAG,MAAM,GAAG,EAAE,CAAC;AAAA,QAC7D;AAAA,MACF;AAEA,YAAM,YAAY,MAAM,WAAW;AAAA,kBAAqB,OAAO,MAAM,KAAK;AAC1E,YAAM,MAAM,SAAS,WAAW,EAAE,IAAI;AAEtC,UAAI,MAAM,GAAG,KAAK,MAAM,KAAK,OAAO,OAAO,QAAQ;AACjD,gBAAQ,MAAM,oBAAoB;AAClC,gBAAQ,KAAK,CAAC;AAAA,MAChB;AAEA,cAAQ,MAAM,SAAS,OAAO,GAAG,EAAE,EAAE;AASrC,UAAI,CAAC,MAAM,QAAQ,OAAO,CAAC,MAAM,QAAQ,UAAU;AACjD,gBAAQ;AAAA,UACN;AAAA,QACF;AACA,gBAAQ,IAAI,oDAAoD;AAChE,cAAM,YAAY,MAAM,WAAW,iCAAiC;AACpE,YAAI,UAAU,YAAY,MAAM,KAAK;AACnC,kBAAQ,MAAMA,gBAAe,OAAO;AAAA,QACtC,OAAO;AACL,kBAAQ,KAAK,CAAC;AAAA,QAChB;AAAA,MACF;AAAA,IACF;AAAA,EACF,OAAO;AACL,YAAQ,MAAMA,gBAAe,OAAO;AAAA,EACtC;AAEA,QAAM,qBAAqB,GAAG,WAAW,CAAC;AAE1C,MAAI,SAAS,MAAM,QAAQ;AAC3B,MAAI,CAAC,QAAQ;AACX,YAAQ;AAAA,MACN;AAAA,IACF;AACA,aAAS,MAAM,WAAW,oCAAoC;AAC9D,QAAI,CAAC,QAAQ;AACX,cAAQ,MAAM,qCAAqC;AACnD,cAAQ,KAAK,CAAC;AAAA,IAChB;AAOA,UAAM,qBAAqB;AAAA,MACzB;AAAA,MACA;AAAA,MACA,iBAAiB,MAAM;AAAA,MACvB,mBAAmB,MAAM;AAAA,MACzB,kBAAkB,MAAM,QAAQ,MAAM;AAAA,IACxC,CAAC;AAAA,EACH;AAGA,QAAM,EAAE,eAAe,mBAAmB,IAAI,wBAAwB;AAGtE,QAAM,gBAAoC;AAAA,IACxC,SAAS,MAAM;AAAA,IACf;AAAA,IACA,WAAW,MAAM;AAAA,IACjB,QAAQ;AAAA,IACR,YAAW,oBAAI,KAAK,GAAE,YAAY;AAAA,IAClC;AAAA,EACF;AACA,mBAAiB,aAAa,aAAa;AAE3C,QAAM,aAAaC,oBAA0B,WAAW;AACxD,QAAM,YAAiB,eAAS,aAAa,UAAU;AAEvD,UAAQ,IAAI,EAAE;AACd,UAAQ,IAAI,iBAAY,MAAM,IAAI,qBAAqB,MAAM,EAAE,GAAG;AAClE,MAAI,MAAM,QAAQ,KAAK;AACrB,YAAQ,IAAI,0BAAqB;AAAA,EACnC;AACA,UAAQ;AAAA,IACN,sCAAiC,kBAAkB,IAAI,qBAAqB;AAAA,EAC9E;AACA,UAAQ,IAAI,kCAA6B,SAAS,EAAE;AACpD,UAAQ,IAAI,EAAE;AACd,UAAQ;AAAA,IACN;AAAA,EACF;AACA,UAAQ,IAAI,mCAAmC,WAAW,CAAC,YAAY;AACvE,UAAQ,IAAI,EAAE;AACd,UAAQ;AAAA,IACN,iBAAY,UAAU;AAAA,EACxB;AACA,UAAQ;AAAA,IACN;AAAA,EACF;AACA,MAAI,oBAAoB;AAEtB,YAAQ;AAAA,MACN,iCAA4B,kBAAkB,IAAI,qBAAqB;AAAA,IACzE;AAAA,EACF;AACA,UAAQ,IAAI,EAAE;AACd,UAAQ,IAAI,sDAAsD;AAClE,UAAQ,IAAI,uDAAuD;AAEnE,SAAO;AAAA,IACL,SAAS,MAAM;AAAA,IACf,WAAW,MAAM;AAAA,IACjB,QAAQ;AAAA,IACR;AAAA,EACF;AACF;AAEA,eAAeD,gBAAe,aAAqC;AACjE,QAAM,YAAY,MAAM,WAAW,eAAe,WAAW,KAAK;AAClE,QAAM,YAAY,aAAa;AAC/B,SAAO,YAAY;AAAA,IACjB,MAAM;AAAA,IACN,aAAa,6BAA6B,SAAS;AAAA,IACnD,MAAM;AAAA,IACN,cAAc;AAAA,IACd,UAAU;AAAA,IACV,QAAQ;AAAA,EACV,CAAC;AACH;AA4BO,SAAS,0BAAoD;AAClE,QAAM,UAAU,gBAAgB;AAChC,QAAM,aAAa,mBAAuB;AAE1C,MAAI,CAAI,eAAW,OAAO,GAAG;AAC3B,IAAG,cAAU,SAAS,EAAE,WAAW,KAAK,CAAC;AAAA,EAC3C;AAEA,QAAM,gBAAmB,eAAW,UAAU;AAE9C,QAAM,SAAS,oBAAoB,UAAU;AAC7C,QAAM,SAA0B;AAAA,IAC9B,GAAG;AAAA,IACH,OAAO,gBAAgB,OAAO,OAAO,0BAA0B;AAAA,EACjE;AAEA,uBAAqB,YAAY,MAAM;AACvC,SAAO,EAAE,cAAc;AACzB;AAEA,eAAsB,eAAe,MAAoC;AACvE,QAAM,cAAc,KAAK,eAAe,QAAQ,IAAI;AAEpD,QAAM,eAAe,sBAAsB;AAC3C,MAAI,cAAc;AAChB,YAAQ;AAAA,MACN,sCAAiC,kBAAkB,IAAI,qBAAqB;AAAA,IAC9E;AAAA,EACF,OAAO;AACL,YAAQ,IAAI,wCAAwC;AAAA,EACtD;AAEA,MAAI,CAAC,KAAK,YAAY;AACpB,UAAM,aAAaC,oBAA0B,WAAW;AACxD,UAAM,YAAiB,eAAS,aAAa,UAAU;AACvD,QAAI,kBAAkB,WAAW,GAAG;AAClC,cAAQ,IAAI,kCAA6B,SAAS,GAAG;AAAA,IACvD;AAAA,EACF,OAAO;AACL,UAAM,aAAaA,oBAA0B,WAAW;AACxD,UAAM,YAAiB,eAAS,aAAa,UAAU;AACvD,YAAQ,IAAI,8BAA8B,SAAS,EAAE;AAAA,EACvD;AAEA,UAAQ,IAAI,EAAE;AACd,UAAQ;AAAA,IACN;AAAA,EACF;AACF;AAeO,SAAS,yBACd,QACiB;AACjB,QAAM,UAAU,iBAAiB,OAAO,KAAK;AAC7C,QAAM,OAAwB,EAAE,GAAG,OAAO;AAC1C,MAAI,YAAY,QAAW;AACzB,WAAO,KAAK;AAAA,EACd,OAAO;AACL,SAAK,QAAQ;AAAA,EACf;AACA,SAAO;AACT;AAOO,SAAS,wBAAiC;AAC/C,QAAM,aAAa,mBAAuB;AAC1C,MAAI,CAAI,eAAW,UAAU,EAAG,QAAO;AACvC,QAAM,SAAS,oBAAoB,UAAU;AAC7C,MAAI,CAAC,wBAAwB,MAAM,EAAG,QAAO;AAE7C,QAAM,OAAO,yBAAyB,MAAM;AAC5C,uBAAqB,YAAY,IAAI;AACrC,SAAO;AACT;AAOO,SAAS,oBAAoB,YAAqC;AACvE,MAAI;AACF,QAAI,CAAI,eAAW,UAAU,EAAG,QAAO,CAAC;AACxC,UAAM,MAAS,iBAAa,YAAY,OAAO;AAC/C,QAAI,CAAC,IAAI,KAAK,EAAG,QAAO,CAAC;AACzB,WAAY,WAAM,GAAG;AAAA,EACvB,QAAQ;AACN,WAAO,CAAC;AAAA,EACV;AACF;AAEO,SAAS,qBACd,YACA,MACM;AACN,QAAM,MAAW,cAAQ,UAAU;AACnC,MAAI,CAAI,eAAW,GAAG,GAAG;AACvB,IAAG,cAAU,KAAK,EAAE,WAAW,KAAK,CAAC;AAAA,EACvC;AAKA,QAAM,aAAkB,eAAU,IAAoB;AACtD,EAAG,kBAAc,YAAY,YAAY,OAAO;AAClD;;;AIlWA,OAAOC,WAAU;AACjB,YAAYC,SAAQ;AAgBpB,eAAsB,eAAe,MAEX;AACxB,QAAM,cAAc,MAAM,eAAe,QAAQ,IAAI;AACrD,QAAM,aAAaC,oBAA0B,WAAW;AACxD,QAAM,SAAS,gBAAgB,WAAW;AAE1C,QAAM,kBAAkB,sBAAsB;AAE9C,MAAI,CAAC,QAAQ;AACX,WAAO;AAAA,MACL,QAAQ;AAAA,MACR,YAAY;AAAA,MACZ;AAAA,MACA;AAAA,MACA,OAAO,kBACH;AAAA,QACE,4BAA4B,kBAAkB,IAAI,qBAAqB;AAAA,MACzE,IACA,CAAC;AAAA,IACP;AAAA,EACF;AAEA,SAAO;AAAA,IACL,QAAQ;AAAA,IACR,YAAY;AAAA,IACZ;AAAA,IACA,SAAS,OAAO;AAAA,IAChB,WAAW,OAAO;AAAA,IAClB,QAAQ,OAAO;AAAA,IACf,cAAc,OAAO,OAAO,MAAM,GAAG,EAAE,IAAI;AAAA,IAC3C,oBAAoB,OAAO;AAAA,IAC3B,cAAc,OAAO;AAAA,IACrB;AAAA,EACF;AACF;AAEA,SAAS,wBAAiC;AACxC,QAAM,aAAa,mBAAuB;AAC1C,MAAI,CAAI,eAAW,UAAU,EAAG,QAAO;AACvC,QAAM,SAAS,oBAAoB,UAAU;AAC7C,SAAO,wBAAwB,MAAM;AACvC;;;ACxCA,YAAYC,SAAQ;AACpB,YAAYC,WAAU;AAwBf,SAAS,eAAiC;AAC/C,SAAO;AAAA,IACL,QAAQ;AAAA,IACR,UAAU;AAAA,IACV,WAAW;AAAA,IACX,aAAa;AAAA,IACb,cAAc;AAAA,IACd,mBAAmB;AAAA,IACnB,uBAAuB;AAAA,IACvB,QAAQ;AAAA,IACR,UAAU;AAAA,EACZ;AACF;AAGA,IAAMC,aAAyB,MAAM;AAAC;AAStC,IAAM,iBAA8C;AAAA,EAClD,SAAS;AAAA,EACT,UAAU;AACZ;AASO,SAAS,0BACd,WACA,cAAsB,oBAAoB,GAC1C,SAA4B,CAAC,GACd;AACf,QAAM,SAAS,EAAE,GAAG,gBAAgB,GAAG,OAAO;AAC9C,MAAI,CAAC,UAAW,QAAO;AACvB,MAAI,CAAI,eAAW,WAAW,EAAG,QAAO;AAExC,QAAM,SAAS,IAAI,SAAS;AAC5B,QAAM,UAA+C,CAAC;AACtD,MAAI,cAAc;AAClB,MAAI,eAAe;AAEnB,QAAM,QAAkB,CAAC,WAAW;AACpC,SAAO,MAAM,SAAS,GAAG;AACvB,UAAM,MAAM,MAAM,MAAM;AACxB,QAAI,gBAAgB,OAAO,QAAS;AAEpC,QAAI;AACJ,QAAI;AACF,gBAAa,gBAAY,KAAK,EAAE,eAAe,KAAK,CAAC;AAAA,IACvD,QAAQ;AACN;AAAA,IACF;AAEA,eAAW,SAAS,SAAS;AAC3B,UAAI,iBAAiB,OAAO,SAAU;AACtC,YAAM,OAAY,WAAK,KAAK,MAAM,IAAI;AACtC,UAAI,MAAM,YAAY,GAAG;AACvB,cAAM,KAAK,IAAI;AACf;AAAA,MACF;AACA,UAAI,CAAC,MAAM,OAAO,EAAG;AACrB,UAAI,CAAC,MAAM,KAAK,SAAS,MAAM,EAAG;AAClC,UAAI,CAAC,MAAM,KAAK,WAAW,UAAU,EAAG;AACxC,UAAI;AACF,cAAM,OAAU,aAAS,IAAI;AAC7B,gBAAQ,KAAK,EAAE,MAAM,MAAM,SAAS,KAAK,QAAQ,CAAC;AAAA,MACpD,QAAQ;AAAA,MAER;AAAA,IACF;AAAA,EACF;AAEA,MAAI,QAAQ,WAAW,EAAG,QAAO;AAGjC,UAAQ,KAAK,CAAC,GAAG,MAAM,EAAE,UAAU,EAAE,OAAO;AAC5C,SAAO,QAAQ,CAAC,EAAE;AACpB;AA8CO,SAAS,oBACd,KACAC,YAAwBD,YACN;AAClB,QAAM,SAAS,aAAa;AAC5B,MAAI,CAAC,IAAK,QAAO;AAEjB,QAAM,QAAQ,IAAI,MAAM,IAAI;AAC5B,MAAI,kBAAkB;AACtB,MAAI,uBAAuB;AAC3B,MAAI,iBAAoC;AACxC,MAAI,kBAAqC;AACzC,MAAI,YAA2B;AAC/B,MAAI,gBAAgB;AAEpB,aAAW,QAAQ,OAAO;AACxB,UAAM,UAAU,KAAK,KAAK;AAC1B,QAAI,CAAC,QAAS;AACd,QAAI;AACJ,QAAI;AACF,eAAS,KAAK,MAAM,OAAO;AAAA,IAC7B,SAAS,KAAK;AACZ,MAAAC,UAAS,6BAA6B;AAAA,QACpC,MAAM,QAAQ,MAAM,GAAG,GAAG;AAAA,QAC1B,OAAQ,IAAc;AAAA,MACxB,CAAC;AACD;AAAA,IACF;AAEA,UAAM,OAAO,OAAO;AACpB,UAAM,UAAU,OAAO;AAKvB,QAAI,CAAC,QAAQ,CAAC,QAAS;AAEvB,QAAI,SAAS,gBAAgB;AAG3B;AAAA,IACF;AAEA,QAAI,SAAS,aAAa;AACxB,YAAM,KAAK;AACX,YAAM,SAAS,GAAG;AAClB,UAAI,WAAW,kBAAkB,OAAO,GAAG,YAAY,UAAU;AAC/D,0BAAkB,GAAG;AACrB,yBAAiB;AAAA,MACnB,WAAW,WAAW,mBAAmB,OAAO,GAAG,YAAY,UAAU;AACvE,+BAAuB,GAAG;AAAA,MAC5B,WAAW,WAAW,iBAAiB,GAAG,MAAM;AAC9C,YAAI,GAAG,KAAK,kBAAkB;AAC5B,2BAAiB,GAAG,KAAK;AAAA,QAC3B;AACA,YAAI,GAAG,KAAK,mBAAmB;AAC7B,4BAAkB,GAAG,KAAK;AAAA,QAC5B;AAAA,MACF,WACE,WAAW,wBACX,OAAO,GAAG,UAAU,YACpB,GAAG,OACH;AACA,oBAAY,GAAG;AAAA,MACjB;AACA;AAAA,IACF;AAEA,QAAI,SAAS,iBAAiB;AAC5B,YAAM,KAAK;AACX,UAAI,GAAG,SAAS,aAAa,MAAM,QAAQ,GAAG,OAAO,GAAG;AACtD,cAAM,OAAO,uBAAuB,GAAG,OAAO;AAC9C,YAAI,CAAC,KAAM;AACX,YAAI,GAAG,SAAS,QAAQ;AACtB,4BAAkB;AAClB,2BAAiB;AAAA,QACnB,WAAW,GAAG,SAAS,aAAa;AAClC,iCAAuB;AAAA,QACzB;AAAA,MACF;AACA;AAAA,IACF;AAAA,EAGF;AAEA,SAAO,SAAS;AAChB,SAAO,WAAW;AAClB,SAAO,YAAY;AACnB,SAAO,WAAW;AAKlB,QAAM,cAAc,kBAAkB;AACtC,MAAI,aAAa;AACf,WAAO,cAAc,aAAa,YAAY,YAAY;AAC1D,WAAO,eAAe,aAAa,YAAY,aAAa;AAC5D,WAAO,oBAAoB,aAAa,YAAY,mBAAmB;AACvE,WAAO,wBAAwB;AAAA,MAC7B,YAAY;AAAA,IACd;AACA,WAAO,SACL,aAAa,YAAY,YAAY,KACrC,OAAO,cAAc,OAAO;AAAA,EAChC;AAEA,SAAO;AACT;AAEA,SAAS,uBACP,SACQ;AACR,QAAM,QAAkB,CAAC;AACzB,aAAW,SAAS,SAAS;AAC3B,QAAI,OAAO,MAAM,SAAS,SAAU;AACpC,QACE,MAAM,SAAS,iBACf,MAAM,SAAS,gBACf,MAAM,SAAS,QACf;AACA,YAAM,KAAK,MAAM,IAAI;AAAA,IACvB;AAAA,EACF;AACA,SAAO,MAAM,KAAK,IAAI,EAAE,KAAK;AAC/B;AAEA,SAAS,aAAa,OAAwB;AAC5C,SAAO,OAAO,UAAU,YAAY,OAAO,SAAS,KAAK,IAAI,QAAQ;AACvE;AAQO,SAAS,sBACd,WACA,UAA4D,CAAC,GAC3C;AAClB,QAAMA,YAAW,QAAQ,YAAYD;AACrC,QAAM,cAAc,QAAQ,eAAe,oBAAoB;AAC/D,QAAM,SAAS,aAAa;AAE5B,QAAM,cAAc,0BAA0B,WAAW,WAAW;AACpE,MAAI,CAAC,aAAa;AAChB,IAAAC,UAAS,qBAAqB;AAAA,MAC5B;AAAA,MACA;AAAA,IACF,CAAC;AACD,WAAO;AAAA,EACT;AAEA,MAAI;AACJ,MAAI;AACF,UAAS,iBAAa,aAAa,OAAO;AAAA,EAC5C,SAAS,KAAK;AACZ,IAAAA,UAAS,uBAAuB;AAAA,MAC9B;AAAA,MACA,OAAQ,IAAc;AAAA,IACxB,CAAC;AACD,WAAO;AAAA,EACT;AAEA,QAAM,SAAS,oBAAoB,KAAKA,SAAQ;AAChD,SAAO,cAAc;AACrB,SAAO;AACT;;;AC3RA,IAAMC,aAAyB,MAAM;AAAC;AAOtC,IAAM,mBAAmB,oBAAI,IAAI,CAAC,QAAQ,kBAAkB,CAAC;AAEtD,SAAS,sBAAsB,WAA4B;AAChE,SAAO,iBAAiB,IAAI,SAAS;AACvC;AAYO,SAAS,kBACd,WACA,WACA,QACA,UAA4B,aAAa,GACf;AAC1B,MAAI,CAAC,sBAAsB,SAAS,EAAG,QAAO;AAG9C,MAAI,cAAc,mBAAoB,QAAO;AAE7C,QAAM,YACJ,OAAO,UAAU,eAAe,YAAY,UAAU,aAClD,UAAU,aACV,SAAS,KAAK,IAAI,CAAC;AAEzB,QAAM,MAAM,OAAO,UAAU,QAAQ,WAAW,UAAU,MAAM;AAChE,QAAM,SACJ,OAAO,UAAU,YAAY,WAAW,UAAU,UAAU;AAC9D,QAAM,iBACJ,OAAO,UAAU,oBAAoB,WACjC,UAAU,kBACV;AACN,QAAM,iBACJ,OAAO,UAAU,oBAAoB,WACjC,UAAU,kBACV;AAMN,QAAM,aACH,OAAO,UAAU,UAAU,YAAY,UAAU,MAAM,KAAK,IACzD,UAAU,QACV,SAAS,QAAQ;AAEvB,QAAM,aAAsC;AAAA,IAC1C,WAAW,UAAU,mBAAmB;AAAA,IACxC;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA,aAAa,QAAQ;AAAA,IACrB,cAAc,QAAQ;AAAA,IACtB,mBAAmB,QAAQ;AAAA,IAC3B,uBAAuB,QAAQ;AAAA,IAC/B,UAAU,QAAQ;AAAA,EACpB;AAEA,MAAI,QAAQ,aAAa;AACvB,eAAW,cAAc,QAAQ;AAAA,EACnC;AACA,MAAI,OAAO,UAAU,qBAAqB,WAAW;AACnD,eAAW,iBAAiB,UAAU;AAAA,EACxC;AAGA,QAAM,kBACJ,OAAO,UAAU,2BAA2B,YAC5C,UAAU,uBAAuB,KAAK,IAClC,UAAU,yBACV;AACN,QAAM,WAAW,mBAAmB,QAAQ;AAE5C,SAAO;AAAA,IACL,QAAQ,QAAQ;AAAA,IAChB;AAAA,IACA,QAAQ;AAAA,IACR,QAAQ,OAAO;AAAA,IACf,WAAW,aAAa;AAAA,IACxB,QAAQ,QAAQ;AAAA,IAChB;AAAA,EACF;AACF;AAeO,SAAS,gBACd,WACA,aACA,QACA,UAA4D,CAAC,GACnC;AAC1B,QAAMC,YAAW,QAAQ,YAAYD;AACrC,MAAI,CAAC,sBAAsB,SAAS,GAAG;AACrC,IAAAC,UAAS,sBAAsB,SAAS;AACxC,WAAO;AAAA,EACT;AAMA,MAAI,cAAc,oBAAoB;AACpC,IAAAA,UAAS,8BAA8B,EAAE,UAAU,CAAC;AACpD,WAAO;AAAA,EACT;AAEA,QAAM,YAAa,eAAe,CAAC;AACnC,EAAAA,UAAS,gBAAgB,EAAE,WAAW,UAAU,CAAC;AAEjD,QAAM,YACJ,OAAO,UAAU,eAAe,WAAW,UAAU,aAAa;AAEpE,MAAI,UAAU,aAAa;AAC3B,MAAI,cAAc,UAAU,WAAW;AACrC,cAAU,sBAAsB,WAAW;AAAA,MACzC,UAAAA;AAAA,MACA,aAAa,QAAQ;AAAA,IACvB,CAAC;AAAA,EACH;AAEA,QAAM,UAAU,kBAAkB,WAAW,WAAW,QAAQ,OAAO;AACvE,MAAI,CAAC,QAAS,QAAO;AAIrB,MAAI,CAAC,QAAQ,UAAU,CAAC,QAAQ,UAAU;AACxC,IAAAA,UAAS,iBAAiB,EAAE,WAAW,UAAU,CAAC;AAClD,WAAO;AAAA,EACT;AAEA,EAAAA,UAAS,iBAAiB,OAAO;AACjC,SAAO;AACT;;;APvLA,IAAMC,WAAU;AAOhB,SAASC,UAAS,OAAe,MAAqB;AACpD,MAAI,QAAQ,IAAI,yBAAyB,IAAK;AAC9C,MAAI;AACF,UAAM,UAAU,6BAA6B,QAAQ,GAAG;AACxD,UAAM,OAAO,KAAI,oBAAI,KAAK,GAAE,YAAY,CAAC,WAAW,KAAK,KACvD,OAAO,SAAS,WAAW,OAAO,KAAK,UAAU,MAAM,MAAM,CAAC,CAChE;AAAA;AACA,IAAG,mBAAe,SAAS,MAAM,OAAO;AAAA,EAC1C,QAAQ;AAAA,EAER;AACF;AAWO,SAAS,wBACd,WACA,aACe;AACf,QAAM,aACJ,OAAO,UAAU,QAAQ,YAAY,UAAU,IAAI,KAAK,IACpD,UAAU,MACV;AACN,SAAO,wBAAwB,YAAY,CAACD,QAAO,CAAC;AACtD;AAEA,IAAM,cAAiC;AAAA,EACrC,IAAIA;AAAA,EACJ,aAAa;AAAA,EAEb,QAAQ,MAA2C;AACjD,WAAO,aAAa,IAAI;AAAA,EAC1B;AAAA,EAEA,UAAU,MAAoC;AAC5C,WAAO,eAAe,IAAI;AAAA,EAC5B;AAAA,EAEA,OAAO,MAA6B;AAClC,WAAO,eAAe,IAAI;AAAA,EAC5B;AAAA,EAEA,MAAM,WACJ,WACA,aAC4B;AAC5B,UAAM,YAAa,eAAe,CAAC;AACnC,IAAAC,UAAS,cAAc,EAAE,WAAW,YAAY,eAAe,KAAK,CAAC;AAErE,UAAM,cAAc,wBAAwB,WAAW,QAAQ,IAAI,CAAC;AACpE,QAAI,CAAC,aAAa;AAChB,MAAAA,UAAS,oBAAoB;AAAA,QAC3B,UACE,OAAO,UAAU,QAAQ,YAAY,UAAU,IAAI,KAAK,IACpD,UAAU,MACV,QAAQ,IAAI;AAAA,MACpB,CAAC;AACD,aAAO;AAAA,IACT;AAEA,UAAM,SAAS,gBAAgB,WAAW;AAC1C,QAAI,CAAC,QAAQ;AACX,MAAAA,UAAS,0BAA0B,EAAE,YAAY,CAAC;AAClD,aAAO;AAAA,IACT;AAEA,UAAM,UAAU,gBAAgB,WAAW,WAAW,QAAQ;AAAA,MAC5D,UAAAA;AAAA,IACF,CAAC;AACD,QAAI,CAAC,QAAS,QAAO;AAErB,WAAO;AAAA,MACL;AAAA,MACA,WAAW;AAAA,QACT,UAAU,OAAO;AAAA,QACjB,QAAQ,OAAO;AAAA,QACf;AAAA,MACF;AAAA,IACF;AAAA,EACF;AAAA,EAEA,MAAM,gBAAgB,MAAwB;AAW5C,UAAM,cAAc,MAAM,eAAe,QAAQ,IAAI;AACrD,QAAI;AACF,UAAO,eAAWC,oBAA0B,WAAW,CAAC,GAAG;AACzD,eAAO;AAAA,MACT;AAAA,IACF,QAAQ;AAAA,IAER;AACA,QAAI;AACF,UAAO,eAAW,mBAAuB,CAAC,GAAG;AAC3C,eAAO;AAAA,MACT;AACA,UAAO,eAAW,gBAAgB,CAAC,GAAG;AAEpC,eAAO;AAAA,MACT;AAAA,IACF,QAAQ;AAAA,IAER;AACA,WAAO,wBAAwB;AAAA,EACjC;AACF;AAEA,SAAS,0BAAmC;AAC1C,MAAI;AACF,UAAM,QAAQ;AAAA,MACZ,QAAQ,aAAa,UAAU,UAAU;AAAA,MACzC,CAAC,OAAO;AAAA,MACR;AAAA,QACE,OAAO,CAAC,UAAU,QAAQ,QAAQ;AAAA,QAClC,SAAS;AAAA,MACX;AAAA,IACF;AACA,QAAI,MAAM,WAAW,KAAK,MAAM,UAAU,MAAM,OAAO,SAAS,EAAE,KAAK,GAAG;AACxE,aAAO;AAAA,IACT;AAAA,EACF,QAAQ;AAAA,EAER;AACA,SAAO;AACT;AAEA,eAAe,WAAW;;;AQtL1B,YAAYC,UAAQ;AACpB,YAAYC,SAAQ;;;ACNpB,YAAYC,UAAQ;AACpB,YAAYC,SAAQ;AACpB,YAAYC,YAAU;;;ACGtB,YAAYC,UAAQ;AACpB,YAAYC,WAAU;AAef,SAAS,oBAAoB,aAA6B;AAC/D,SAAO,qBAAyB,aAAa,QAAQ;AACvD;AAEO,SAAS,iBACd,aAC4B;AAC5B,QAAM,WAAW,oBAAoB,WAAW;AAChD,MAAI;AACF,QAAI,CAAI,gBAAW,QAAQ,EAAG,QAAO;AACrC,UAAM,MAAS,kBAAa,UAAU,OAAO;AAC7C,WAAO,KAAK,MAAM,GAAG;AAAA,EACvB,QAAQ;AACN,WAAO;AAAA,EACT;AACF;AAEO,SAAS,kBACd,aACA,QACM;AACN,QAAM,WAAW,oBAAoB,WAAW;AAChD,QAAM,MAAW,cAAQ,QAAQ;AACjC,MAAI,CAAI,gBAAW,GAAG,GAAG;AACvB,IAAG,eAAU,KAAK,EAAE,WAAW,KAAK,CAAC;AAAA,EACvC;AACA,EAAG,mBAAc,UAAU,KAAK,UAAU,QAAQ,MAAM,CAAC,IAAI,MAAM,OAAO;AAC1E,MAAI;AACF,IAAG,eAAU,UAAU,GAAK;AAAA,EAC9B,QAAQ;AAAA,EAER;AACF;AAEO,SAAS,mBAAmB,aAA8B;AAC/D,QAAM,WAAW,oBAAoB,WAAW;AAChD,MAAI,CAAI,gBAAW,QAAQ,EAAG,QAAO;AACrC,MAAI;AACF,IAAG,gBAAW,QAAQ;AACtB,WAAO;AAAA,EACT,QAAQ;AACN,WAAO;AAAA,EACT;AACF;;;AChEA,YAAYC,SAAQ;AACpB,YAAYC,WAAU;AAEf,IAAM,kBAAkB;AACxB,IAAM,oBAAoB;AAO1B,SAAS,iBAAiB,UAAqB,YAAQ,GAAW;AACvE,SAAY,WAAK,SAAS,eAAe;AAC3C;AAKO,SAAS,mBAAmB,UAAqB,YAAQ,GAAW;AACzE,SAAY,WAAK,iBAAiB,OAAO,GAAG,iBAAiB;AAC/D;;;ACNO,IAAMC,sBAAqB;AA8B3B,IAAM,0BAA6D;AAAA,EACxE,oBAAoB;AAAA,IAClB;AAAA,MACE,SAAS;AAAA,MACT,SAAS;AAAA,IACX;AAAA,EACF;AAAA,EACA,oBAAoB;AAAA,IAClB;AAAA,MACE,SAAS;AAAA,MACT,SAAS;AAAA,IACX;AAAA,EACF;AAAA,EACA,YAAY;AAAA,IACV;AAAA,MACE,SAAS;AAAA,MACT,SAAS;AAAA,IACX;AAAA,EACF;AAAA,EACA,MAAM;AAAA,IACJ;AAAA,MACE,SAAS;AAAA,MACT,SAAS;AAAA,IACX;AAAA,EACF;AACF;AAMO,IAAM,uBAAuB;AAa7B,SAAS,iBACd,UACA,cAAiD,yBAC9B;AACnB,QAAM,OAA0B,WAAW,EAAE,GAAG,SAAS,IAAI,CAAC;AAC9D,MAAI,OAAO,KAAK,YAAY,UAAU;AACpC,SAAK,UAAU;AAAA,EACjB;AAEA,QAAM,cAAiD;AAAA,IACrD,GAAI,KAAK,SAAS,CAAC;AAAA,EACrB;AAEA,aAAW,CAAC,OAAO,cAAc,KAAK,OAAO,QAAQ,WAAW,GAAG;AACjE,UAAM,kBAAkB,YAAY,KAAK,KAAK,CAAC;AAC/C,UAAM,iBAAiB,gBAAgB;AAAA,MAAK,CAAC,MAC3C,OAAO,GAAG,YAAY,YAAY,EAAE,QAAQ,SAASA,mBAAkB;AAAA,IACzE;AACA,QAAI,gBAAgB;AAClB,kBAAY,KAAK,IAAI;AAAA,IACvB,OAAO;AACL,kBAAY,KAAK,IAAI,CAAC,GAAG,iBAAiB,GAAG,cAAc;AAAA,IAC7D;AAAA,EACF;AAEA,SAAO;AAAA,IACL,GAAG;AAAA,IACH,OAAO;AAAA,EACT;AACF;AAQO,SAAS,wBACd,UACmB;AACnB,QAAM,OAA0B,WAAW,EAAE,GAAG,SAAS,IAAI,CAAC;AAC9D,QAAM,cAAc,KAAK,SAAS,CAAC;AACnC,QAAM,UAA6C,CAAC;AAEpD,aAAW,CAAC,OAAO,OAAO,KAAK,OAAO,QAAQ,WAAW,GAAG;AAC1D,UAAM,WAAW,QAAQ;AAAA,MACvB,CAAC,MACC,OAAO,GAAG,YAAY,YACtB,CAAC,EAAE,QAAQ,SAASA,mBAAkB;AAAA,IAC1C;AACA,QAAI,SAAS,SAAS,GAAG;AACvB,cAAQ,KAAK,IAAI;AAAA,IACnB;AAAA,EACF;AAEA,MAAI,OAAO,KAAK,OAAO,EAAE,SAAS,GAAG;AACnC,SAAK,QAAQ;AAAA,EACf,OAAO;AACL,WAAO,KAAK;AAAA,EACd;AACA,SAAO;AACT;AAMO,SAAS,qBACd,QACS;AACT,MAAI,CAAC,QAAQ,MAAO,QAAO;AAC3B,SAAO,OAAO,OAAO,OAAO,KAAK,EAAE;AAAA,IAAK,CAAC,YACvC,QAAQ;AAAA,MACN,CAAC,MACC,OAAO,GAAG,YAAY,YAAY,EAAE,QAAQ,SAASA,mBAAkB;AAAA,IAC3E;AAAA,EACF;AACF;;;AHpIA,IAAM,gBAAgB;AACtB,IAAM,sBAAsB;AAC5B,IAAM,wBAAwB;AAO9B,SAAS,qBAAwB,UAA4B;AAC3D,MAAI;AACF,QAAI,CAAI,gBAAW,QAAQ,EAAG,QAAO;AACrC,UAAM,MAAS,kBAAa,UAAU,OAAO;AAC7C,WAAO,KAAK,MAAM,GAAG;AAAA,EACvB,QAAQ;AACN,WAAO;AAAA,EACT;AACF;AAEA,SAAS,qBAAqB,UAAkB,MAAqB;AACnE,QAAM,MAAW,eAAQ,QAAQ;AACjC,MAAI,CAAI,gBAAW,GAAG,GAAG;AACvB,IAAG,eAAU,KAAK,EAAE,WAAW,KAAK,CAAC;AAAA,EACvC;AACA,EAAG,mBAAc,UAAU,KAAK,UAAU,MAAM,MAAM,CAAC,IAAI,MAAM,OAAO;AAC1E;AAOA,eAAsB,cACpB,MACwB;AACxB,QAAM,cAAc,KAAK,eAAe,QAAQ,IAAI;AACpD,QAAM,UAAU,KAAK,WAAc,YAAQ;AAE3C,QAAM,QAAQ,cAAc;AAC5B,MAAI,CAAC,OAAO;AACV,YAAQ,MAAM,0CAA0C;AACxD,YAAQ,KAAK,CAAC;AAAA,EAChB;AAEA,UAAQ,IAAI,sDAAsD;AAClE,UAAQ;AAAA,IACN;AAAA,EACF;AACA,UAAQ;AAAA,IACN,iCAAiC,WAAW;AAAA,EAC9C;AACA,UAAQ,IAAI,+BAA+B;AAE3C,QAAM,UAAe,gBAAS,WAAW;AACzC,QAAM,QAAQ,MAAM,oBAAoB,OAAO;AAE/C,QAAM,qBAAqB,GAAG,WAAW,CAAC;AAE1C,MAAI,SAAS,MAAM,QAAQ;AAC3B,MAAI,CAAC,QAAQ;AACX,YAAQ;AAAA,MACN;AAAA,IACF;AACA,aAAS,MAAM,WAAW,oCAAoC;AAC9D,QAAI,CAAC,QAAQ;AACX,cAAQ,MAAM,qCAAqC;AACnD,cAAQ,KAAK,CAAC;AAAA,IAChB;AAOA,UAAM,qBAAqB;AAAA,MACzB;AAAA,MACA;AAAA,MACA,iBAAiB,MAAM;AAAA,MACvB,mBAAmB,MAAM;AAAA,MACzB,kBAAkB,MAAM,QAAQ,MAAM;AAAA,IACxC,CAAC;AAAA,EACH;AAGA,QAAM,YAAY,iBAAiB,OAAO;AAC1C,MAAI,CAAI,gBAAW,SAAS,GAAG;AAC7B,IAAG,eAAU,WAAW,EAAE,WAAW,KAAK,CAAC;AAAA,EAC7C;AAEA,QAAM,YAAY,mBAAmB,OAAO;AAC5C,QAAM,gBAAgB,qBAAwC,SAAS;AACvE,QAAM,cAAc,iBAAiB,aAAa;AAClD,uBAAqB,WAAW,WAAW;AAG3C,QAAM,gBAAqC;AAAA,IACzC,SAAS,MAAM;AAAA,IACf;AAAA,IACA,WAAW,MAAM;AAAA,IACjB,QAAQ;AAAA,IACR,YAAW,oBAAI,KAAK,GAAE,YAAY;AAAA,IAClC;AAAA,EACF;AACA,oBAAkB,aAAa,aAAa;AAE5C,QAAM,aAAa,oBAAoB,WAAW;AAClD,QAAM,YAAiB,gBAAS,aAAa,UAAU;AACvD,QAAM,eAAe,KAAU,YAAK,iBAAiB,iBAAiB,CAAC;AAEvE,UAAQ,IAAI,EAAE;AACd,UAAQ,IAAI,iBAAY,MAAM,IAAI,qBAAqB,MAAM,EAAE,GAAG;AAClE,MAAI,MAAM,QAAQ,KAAK;AACrB,YAAQ,IAAI,0BAAqB;AAAA,EACnC;AACA,UAAQ,IAAI,oCAA+B,YAAY,EAAE;AACzD,UAAQ,IAAI,kCAA6B,SAAS,EAAE;AACpD,UAAQ,IAAI,EAAE;AACd,UAAQ;AAAA,IACN;AAAA,EACF;AACA,UAAQ,IAAI,qBAAqB,WAAW,CAAC,YAAY;AACzD,UAAQ,IAAI,EAAE;AACd,UAAQ;AAAA,IACN,iBAAY,UAAU;AAAA,EACxB;AACA,UAAQ,IAAI,EAAE;AACd,UAAQ,IAAI,uDAAuD;AACnE,UAAQ,IAAI,wDAAwD;AAEpE,SAAO;AAAA,IACL,SAAS,MAAM;AAAA,IACf,WAAW,MAAM;AAAA,IACjB,QAAQ;AAAA,IACR;AAAA,EACF;AACF;AAEA,eAAe,oBAAoB,aAAqC;AACtE,QAAM,SAAS,MAAM;AAAA,IACnB;AAAA,EACF;AAEA,MAAI,OAAO,YAAY,MAAM,cAAc,OAAO,YAAY,MAAM,KAAK;AACvE,UAAM,SAAS,MAAM,WAAW;AAChC,QAAI,OAAO,WAAW,GAAG;AACvB,cAAQ,IAAI,gDAAgD;AAC5D,aAAOC,gBAAe,WAAW;AAAA,IACnC;AACA,YAAQ,IAAI,qBAAqB;AACjC,aAAS,IAAI,GAAG,IAAI,OAAO,QAAQ,KAAK;AACtC,cAAQ;AAAA,QACN,KAAK,IAAI,CAAC,KAAK,OAAO,CAAC,EAAE,IAAI,KAAK,OAAO,CAAC,EAAE,GAAG,MAAM,GAAG,EAAE,CAAC;AAAA,MAC7D;AAAA,IACF;AAEA,UAAM,YAAY,MAAM,WAAW;AAAA,kBAAqB,OAAO,MAAM,KAAK;AAC1E,UAAM,MAAM,SAAS,WAAW,EAAE,IAAI;AACtC,QAAI,MAAM,GAAG,KAAK,MAAM,KAAK,OAAO,OAAO,QAAQ;AACjD,cAAQ,MAAM,oBAAoB;AAClC,cAAQ,KAAK,CAAC;AAAA,IAChB;AAEA,UAAM,UAAU,MAAM,SAAS,OAAO,GAAG,EAAE,EAAE;AAC7C,QAAI,CAAC,QAAQ,QAAQ,OAAO,CAAC,QAAQ,QAAQ,UAAU;AACrD,cAAQ;AAAA,QACN;AAAA,MACF;AACA,cAAQ,IAAI,oDAAoD;AAChE,YAAM,YAAY,MAAM,WAAW,iCAAiC;AACpE,UAAI,UAAU,YAAY,MAAM,KAAK;AACnC,eAAOA,gBAAe,WAAW;AAAA,MACnC;AACA,cAAQ,KAAK,CAAC;AAAA,IAChB;AACA,WAAO;AAAA,EACT;AAEA,SAAOA,gBAAe,WAAW;AACnC;AAEA,eAAeA,gBAAe,aAAqC;AACjE,QAAM,YAAY,MAAM,WAAW,eAAe,WAAW,KAAK;AAClE,QAAM,YAAY,aAAa;AAC/B,SAAO,YAAY;AAAA,IACjB,MAAM;AAAA,IACN,aAAa,0BAA0B,SAAS;AAAA,IAChD,MAAM;AAAA,IACN,cAAc;AAAA,IACd,UAAU;AAAA,IACV,QAAQ;AAAA,EACV,CAAC;AACH;AAOA,eAAsB,gBACpB,MACe;AACf,QAAM,cAAc,KAAK,eAAe,QAAQ,IAAI;AACpD,QAAM,UAAU,KAAK,WAAc,YAAQ;AAE3C,QAAM,YAAY,mBAAmB,OAAO;AAC5C,QAAM,gBAAgB,qBAAwC,SAAS;AACvE,MAAI,eAAe;AACjB,UAAM,UAAU,wBAAwB,aAAa;AACrD,QACE,CAAC,QAAQ,SACT,OAAO,KAAK,QAAQ,KAAK,EAAE,WAAW,GACtC;AAIA,YAAM,YAAY,OAAO,KAAK,OAAO,EAAE;AAAA,QACrC,CAAC,MAAM,MAAM,WAAW,MAAM;AAAA,MAChC;AACA,YAAM,eACJ,UAAU,WAAW,MACpB,QAAQ,YAAY,KAAK,QAAQ,YAAY;AAChD,UAAI,cAAc;AAChB,YAAI;AACF,UAAG,gBAAW,SAAS;AAAA,QACzB,QAAQ;AAAA,QAER;AAAA,MACF,OAAO;AACL,6BAAqB,WAAW,OAAO;AAAA,MACzC;AAAA,IACF,OAAO;AACL,2BAAqB,WAAW,OAAO;AAAA,IACzC;AACA,YAAQ;AAAA,MACN,sCAAsC,YAAK,iBAAiB,iBAAiB,CAAC;AAAA,IAChF;AAAA,EACF,OAAO;AACL,YAAQ,IAAI,6BAA6B;AAAA,EAC3C;AAEA,MAAI,CAAC,KAAK,YAAY;AACpB,UAAM,aAAa,oBAAoB,WAAW;AAClD,UAAM,YAAiB,gBAAS,aAAa,UAAU;AACvD,QAAI,mBAAmB,WAAW,GAAG;AACnC,cAAQ,IAAI,kCAA6B,SAAS,GAAG;AAAA,IACvD;AAAA,EACF,OAAO;AACL,UAAM,aAAa,oBAAoB,WAAW;AAClD,UAAM,YAAiB,gBAAS,aAAa,UAAU;AACvD,YAAQ,IAAI,8BAA8B,SAAS,EAAE;AAAA,EACvD;AAEA,UAAQ,IAAI,EAAE;AACd,UAAQ;AAAA,IACN;AAAA,EACF;AACA,UAAQ,IAAI,+CAA+C;AAC7D;;;AIvSA,YAAYC,UAAQ;AACpB,YAAYC,SAAQ;AACpB,YAAYC,YAAU;AAetB,eAAsB,gBACpB,MACuB;AACvB,QAAM,cAAc,MAAM,eAAe,QAAQ,IAAI;AACrD,QAAM,UAAU,MAAM,WAAc,YAAQ;AAE5C,QAAM,aAAa,oBAAoB,WAAW;AAClD,QAAM,SAAS,iBAAiB,WAAW;AAE3C,MAAI,kBAAkB;AACtB,QAAM,YAAY,mBAAmB,OAAO;AAC5C,MAAO,gBAAW,SAAS,GAAG;AAC5B,QAAI;AACF,YAAM,MAAS,kBAAa,WAAW,OAAO;AAC9C,YAAM,SAAS,KAAK,MAAM,GAAG;AAC7B,wBAAkB,qBAAqB,MAAM;AAAA,IAC/C,QAAQ;AAAA,IAER;AAAA,EACF;AAEA,MAAI,CAAC,QAAQ;AACX,WAAO;AAAA,MACL,QAAQ;AAAA,MACR,YAAY;AAAA,MACZ;AAAA,MACA;AAAA,MACA,OAAO,kBACH;AAAA,QACE;AAAA,MACF,IACA,CAAC;AAAA,IACP;AAAA,EACF;AAEA,SAAO;AAAA,IACL,QAAQ;AAAA,IACR,YAAY;AAAA,IACZ;AAAA,IACA,SAAS,OAAO;AAAA,IAChB,WAAW,OAAO;AAAA,IAClB,QAAQ,OAAO;AAAA,IACf,cAAc,OAAO,OAAO,MAAM,GAAG,EAAE,IAAI;AAAA,IAC3C,oBAAoB,OAAO;AAAA,IAC3B,cAAc,OAAO;AAAA,IACrB;AAAA,EACF;AACF;;;AC7CO,IAAM,0BAA0B,oBAAI,IAAY;AAAA,EACrD;AAAA,EACA;AAAA,EACA;AAAA,EACA;AACF,CAAC;AAyCD,SAAS,SAAS,OAAoC;AACpD,SAAO,OAAO,UAAU,YAAY,MAAM,KAAK,IAAI,QAAQ;AAC7D;AAQO,SAAS,SAAS,OAAwB;AAC/C,MAAI,OAAO,UAAU,SAAU,QAAO;AACtC,MAAI,CAAC,OAAO,SAAS,KAAK,EAAG,QAAO;AACpC,SAAO;AACT;AAaO,SAAS,oBACd,SACuB;AACvB,SAAO;AAAA,IACL,aAAa,SAAS,QAAQ,YAAY;AAAA,IAC1C,cAAc,SAAS,QAAQ,aAAa;AAAA,IAC5C,iBAAiB,SAAS,QAAQ,iBAAiB;AAAA,IACnD,kBAAkB,SAAS,QAAQ,kBAAkB;AAAA,EACvD;AACF;AAEA,SAAS,cAAc,OAAsC;AAC3D,MAAI,CAAC,MAAM,QAAQ,KAAK,EAAG,QAAO;AAClC,QAAM,MAAgB,CAAC;AACvB,aAAW,QAAQ,OAAO;AACxB,QAAI,OAAO,SAAS,YAAY,KAAK,KAAK,EAAG,KAAI,KAAK,IAAI;AAAA,EAC5D;AACA,SAAO,IAAI,SAAS,IAAI,MAAM;AAChC;AAOO,SAAS,kBAAkB,SAAoC;AACpE,MAAI,OAAO,QAAQ,WAAW,SAAU,QAAO,QAAQ;AACvD,MACE,QAAQ,UACR,OAAO,QAAQ,WAAW,YAC1B,OAAQ,QAAQ,OAA8B,SAAS,UACvD;AACA,WAAQ,QAAQ,OAA4B;AAAA,EAC9C;AACA,SAAO;AACT;AAaO,SAAS,oBAAoB,SAAoC;AACtE,MAAI,OAAO,QAAQ,aAAa,SAAU,QAAO,QAAQ;AACzD,MACE,QAAQ,YACR,OAAO,QAAQ,aAAa,YAC5B,OAAQ,QAAQ,SAAgC,SAAS,UACzD;AACA,WAAQ,QAAQ,SAA8B;AAAA,EAChD;AACA,MAAI,OAAO,QAAQ,SAAS,SAAU,QAAO,QAAQ;AACrD,SAAO;AACT;AAEO,SAAS,mBACd,SACuB;AACvB,MAAI,MAAM,QAAQ,QAAQ,WAAW,EAAG,QAAO,QAAQ;AACvD,MACE,QAAQ,UACR,OAAO,QAAQ,WAAW,YAC1B,MAAM,QAAS,QAAQ,OAAuC,WAAW,GACzE;AACA,WAAQ,QAAQ,OAAsC;AAAA,EACxD;AACA,SAAO;AACT;AAsCO,SAAS,mBACd,QACA,QACmB;AACnB,QAAM,aAAsC;AAAA,IAC1C,WAAW;AAAA,IACX,gBAAgB,OAAO;AAAA,EACzB;AACA,MAAI,OAAO,aAAc,YAAW,eAAe,OAAO;AAC1D,MAAI,OAAO,cAAe,YAAW,gBAAgB,OAAO;AAC5D,MAAI,OAAO,eAAgB,YAAW,iBAAiB,OAAO;AAC9D,MAAI,OAAO,eAAgB,YAAW,iBAAiB,OAAO;AAC9D,MAAI,OAAO,eAAe,OAAO,YAAY,SAAS,GAAG;AACvD,eAAW,kBAAkB,OAAO,YAAY;AAAA,EAClD;AACA,MAAI,OAAO,UAAW,YAAW,YAAY,OAAO;AAKpD,QAAM,cAAc,SAAS,OAAO,WAAW;AAC/C,QAAM,eAAe,SAAS,OAAO,YAAY;AACjD,QAAM,kBAAkB,SAAS,OAAO,eAAe;AACvD,QAAM,mBAAmB,SAAS,OAAO,gBAAgB;AACzD,aAAW,cAAc;AACzB,aAAW,eAAe;AAC1B,aAAW,kBAAkB;AAC7B,aAAW,mBAAmB;AAE9B,MACE,OAAO,iBACP,OAAO,KAAK,OAAO,aAAa,EAAE,SAAS,GAC3C;AACA,eAAW,uBAAuB,OAAO;AAAA,EAC3C;AAEA,SAAO;AAAA,IACL,QAAQ,OAAO;AAAA,IACf,UAAU,OAAO;AAAA,IACjB,QAAQ,OAAO;AAAA,IACf,QAAQ,OAAO;AAAA,IACf,WAAW,OAAO;AAAA,IAClB,QAAQ,cAAc;AAAA,IACtB;AAAA,EACF;AACF;AASO,SAAS,mBACd,QACA,QACA,SAA0C,iBACvB;AACnB,QAAM,OAAO,mBAAmB,EAAE,GAAG,QAAQ,UAAU,GAAG,GAAG,MAAM;AACnE,SAAO;AAAA,IACL,GAAG;AAAA,IACH,YAAY;AAAA,MACV,GAAG,KAAK;AAAA,MACR,WAAW;AAAA,MACX,SAAS;AAAA,MACT,eAAe;AAAA,IACjB;AAAA,EACF;AACF;AAOA,IAAM,qBAAqB,oBAAI,IAAI;AAAA,EACjC;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AACF,CAAC;AAEM,SAAS,qBACd,SACqC;AACrC,QAAM,MAA+B,CAAC;AACtC,aAAW,OAAO,OAAO,KAAK,OAAO,GAAG;AACtC,QAAI,CAAC,mBAAmB,IAAI,GAAG,GAAG;AAChC,UAAI,GAAG,IAAI,QAAQ,GAAG;AAAA,IACxB;AAAA,EACF;AACA,SAAO,OAAO,KAAK,GAAG,EAAE,SAAS,IAAI,MAAM;AAC7C;AAQO,SAAS,mBAAmB,OAAuC;AACxE,QAAM,QAAQ,MAAM,KAAK;AACzB,MAAI,CAAC,MAAO,QAAO;AACnB,QAAM,QAAQ;AACd,MAAI,wBAAwB,IAAI,KAAK,EAAG,QAAO;AAG/C,aAAW,SAAS,yBAAyB;AAC3C,QAAI,MAAM,YAAY,MAAM,MAAM,YAAY,EAAG,QAAO;AAAA,EAC1D;AACA,SAAO;AACT;AAqBO,SAAS,kBACd,SACqB;AACrB,SAAO;AAAA,IACL,gBAAgB,SAAS,QAAQ,eAAe;AAAA,IAChD,cAAc,SAAS,QAAQ,aAAa;AAAA,IAC5C,OAAO,SAAS,QAAQ,KAAK;AAAA,IAC7B,eAAe,SAAS,QAAQ,cAAc;AAAA,IAC9C,gBAAgB,cAAc,QAAQ,eAAe;AAAA,IACrD,WAAW,SAAS,QAAQ,UAAU;AAAA,IACtC,gBAAgB,SAAS,QAAQ,eAAe;AAAA,EAClD;AACF;;;ACvVA,YAAYC,UAAQ;AACpB,YAAYC,SAAQ;AACpB,YAAYC,YAAU;AAkBtB,IAAMC,sBAAqB,CAAC,WAAW,iBAAiB;AAExD,SAAS,eAAe,SAAyB;AAC/C,SAAY,YAAK,SAAS,GAAGA,mBAAkB;AACjD;AAOA,SAAS,oBAAoB,OAAuB;AAClD,SAAO,MAAM,QAAQ,oBAAoB,GAAG;AAC9C;AAEA,SAAS,cACP,gBACA,cACQ;AACR,QAAM,OAAO,oBAAoB,cAAc;AAC/C,MAAI,CAAC,aAAc,QAAO;AAC1B,SAAO,GAAG,IAAI,KAAK,oBAAoB,YAAY,CAAC;AACtD;AAEA,SAAS,eACP,gBACA,cACA,SACQ;AACR,SAAY;AAAA,IACV,eAAe,OAAO;AAAA,IACtB,GAAG,cAAc,gBAAgB,YAAY,CAAC;AAAA,EAChD;AACF;AAOO,SAAS,mBACd,SACA,UAAqB,YAAQ,GACvB;AACN,MAAI,CAAC,QAAQ,eAAgB;AAC7B,QAAM,MAAM,eAAe,OAAO;AAClC,MAAI;AACF,QAAI,CAAI,gBAAW,GAAG,GAAG;AACvB,MAAG,eAAU,KAAK,EAAE,WAAW,KAAK,CAAC;AAAA,IACvC;AACA,UAAM,WAAW;AAAA,MACf,QAAQ;AAAA,MACR,QAAQ;AAAA,MACR;AAAA,IACF;AACA,IAAG;AAAA,MACD;AAAA,MACA,KAAK,UAAU,SAAS,MAAM,CAAC,IAAI;AAAA,MACnC;AAAA,IACF;AAAA,EACF,QAAQ;AAAA,EAER;AACF;AAcO,SAAS,kBACd,gBACA,cACA,UAAqB,YAAQ,GACD;AAC5B,MAAI,CAAC,eAAgB,QAAO;AAE5B,QAAM,aAAuB,CAAC;AAC9B,MAAI,cAAc;AAChB,eAAW,KAAK,eAAe,gBAAgB,cAAc,OAAO,CAAC;AAAA,EACvE;AACA,aAAW,KAAK,eAAe,gBAAgB,QAAW,OAAO,CAAC;AAElE,aAAW,YAAY,YAAY;AACjC,QAAI;AACJ,QAAI;AACF,UAAI,CAAI,gBAAW,QAAQ,EAAG;AAC9B,YAAS,kBAAa,UAAU,OAAO;AAAA,IACzC,QAAQ;AACN;AAAA,IACF;AACA,QAAI;AACF,MAAG,gBAAW,QAAQ;AAAA,IACxB,QAAQ;AAAA,IAER;AACA,QAAI;AACF,YAAM,SAAS,KAAK,MAAM,GAAG;AAC7B,UAAI,UAAU,OAAO,OAAO,mBAAmB,UAAU;AACvD,eAAO;AAAA,MACT;AAAA,IACF,QAAQ;AAAA,IAER;AAAA,EACF;AACA,SAAO;AACT;AASO,SAAS,mBACd,UAAqB,YAAQ,GACN;AACvB,QAAM,MAAM,eAAe,OAAO;AAClC,MAAI,CAAI,gBAAW,GAAG,EAAG,QAAO,CAAC;AAEjC,MAAI;AACJ,MAAI;AACF,YAAW,iBAAY,GAAG;AAAA,EAC5B,QAAQ;AACN,WAAO,CAAC;AAAA,EACV;AAEA,QAAM,SAAgC,CAAC;AACvC,aAAW,QAAQ,OAAO;AACxB,QAAI,CAAC,KAAK,SAAS,OAAO,EAAG;AAC7B,UAAM,WAAgB,YAAK,KAAK,IAAI;AACpC,QAAI;AACF,YAAM,MAAS,kBAAa,UAAU,OAAO;AAC7C,YAAM,SAAS,KAAK,MAAM,GAAG;AAC7B,UAAI,UAAU,OAAO,OAAO,mBAAmB,UAAU;AACvD,eAAO,KAAK,MAAM;AAAA,MACpB;AAAA,IACF,QAAQ;AAAA,IAER;AAAA,EACF;AACA,SAAO;AACT;AAMO,SAAS,mBACd,gBACA,cACA,UAAqB,YAAQ,GACvB;AACN,MAAI,CAAC,eAAgB;AACrB,QAAM,aAAuB,CAAC;AAC9B,MAAI,cAAc;AAChB,eAAW,KAAK,eAAe,gBAAgB,cAAc,OAAO,CAAC;AAAA,EACvE;AACA,aAAW,KAAK,eAAe,gBAAgB,QAAW,OAAO,CAAC;AAClE,aAAW,YAAY,YAAY;AACjC,QAAI;AACF,UAAO,gBAAW,QAAQ,GAAG;AAC3B,QAAG,gBAAW,QAAQ;AAAA,MACxB;AAAA,IACF,QAAQ;AAAA,IAER;AAAA,EACF;AACF;;;APxKA,IAAMC,WAAU;AAOhB,SAASC,UAAS,OAAe,MAAqB;AACpD,MAAI,QAAQ,IAAI,yBAAyB,IAAK;AAC9C,MAAI;AACF,UAAM,UAAU,6BAA6B,QAAQ,GAAG;AACxD,UAAM,OAAO,KAAI,oBAAI,KAAK,GAAE,YAAY,CAAC,YAAY,KAAK,KACxD,OAAO,SAAS,WAAW,OAAO,KAAK,UAAU,MAAM,MAAM,CAAC,CAChE;AAAA;AACA,IAAG,oBAAe,SAAS,MAAM,OAAO;AAAA,EAC1C,QAAQ;AAAA,EAER;AACF;AAUO,SAAS,yBACd,SACA,cAAsB,QAAQ,IAAI,GACnB;AACf,QAAM,QAAQ,MAAM,QAAQ,QAAQ,eAAe,IAC/C,QAAQ,gBAAgB;AAAA,IACtB,CAAC,MAAmB,OAAO,MAAM,YAAY,EAAE,KAAK,EAAE,SAAS;AAAA,EACjE,IACA,CAAC;AACL,QAAM,aAAa,MAAM,SAAS,IAAI,QAAQ,CAAC,WAAW;AAC1D,aAAW,aAAa,YAAY;AAClC,UAAM,QAAQ,wBAAwB,WAAW,CAACD,QAAO,CAAC;AAC1D,QAAI,MAAO,QAAO;AAAA,EACpB;AACA,SAAO;AACT;AAYA,eAAsB,iBACpB,WACA,aACA,OAAuB,CAAC,GACI;AAC5B,QAAM,QAAQ,mBAAmB,SAAS;AAC1C,MAAI,CAAC,OAAO;AACV,IAAAC,UAAS,sBAAsB,SAAS;AACxC,WAAO;AAAA,EACT;AAEA,QAAM,UACJ,eAAe,OAAO,gBAAgB,WACjC,cACA,CAAC;AACR,EAAAA,UAAS,gBAAgB,EAAE,OAAO,QAAQ,CAAC;AAE3C,QAAM,OAAO,kBAAkB,OAAO;AACtC,QAAM,UAAU,KAAK,WAAc,YAAQ;AAE3C,UAAQ,OAAO;AAAA,IACb,KAAK,sBAAsB;AACzB,UAAI,CAAC,KAAK,gBAAgB;AACxB,QAAAA,UAAS,2BAA2B,EAAE,MAAM,CAAC;AAC7C,eAAO;AAAA,MACT;AACA;AAAA,QACE;AAAA,UACE,QAAQ,kBAAkB,OAAO;AAAA,UACjC,WAAW,KAAK;AAAA,UAChB,OAAO,KAAK;AAAA,UACZ,eAAe,KAAK;AAAA,UACpB,gBAAgB,KAAK;AAAA,UACrB,cAAc,KAAK;AAAA,UACnB,gBAAgB,KAAK;AAAA,UACrB,gBAAgB,KAAK;AAAA,UACrB,aAAa,mBAAmB,OAAO;AAAA,UACvC,YAAW,oBAAI,KAAK,GAAE,YAAY;AAAA,UAClC,OAAO,qBAAqB,OAAO;AAAA,QACrC;AAAA,QACA;AAAA,MACF;AAEA,aAAO;AAAA,IACT;AAAA,IAEA,KAAK,sBAAsB;AACzB,UAAI,CAAC,KAAK,gBAAgB;AACxB,QAAAA,UAAS,2BAA2B,EAAE,MAAM,CAAC;AAC7C,eAAO;AAAA,MACT;AACA,YAAM,cAAc;AAAA,QAClB;AAAA,QACA,KAAK,eAAe,QAAQ,IAAI;AAAA,MAClC;AACA,UAAI,CAAC,aAAa;AAChB,QAAAA,UAAS,oBAAoB;AAAA,UAC3B,gBAAgB,KAAK;AAAA,UACrB,aAAa,KAAK,eAAe,QAAQ,IAAI;AAAA,QAC/C,CAAC;AAED,0BAAkB,KAAK,gBAAgB,KAAK,cAAc,OAAO;AACjE,eAAO;AAAA,MACT;AAEA,YAAM,SAAS,iBAAiB,WAAW;AAC3C,UAAI,CAAC,QAAQ;AACX,QAAAA,UAAS,sBAAsB,EAAE,YAAY,CAAC;AAC9C,0BAAkB,KAAK,gBAAgB,KAAK,cAAc,OAAO;AACjE,eAAO;AAAA,MACT;AAEA,YAAM,UAAU;AAAA,QACd,KAAK;AAAA,QACL,KAAK;AAAA,QACL;AAAA,MACF;AAEA,YAAM,eAAe,oBAAoB,OAAO;AAChD,YAAM,aAAa,SAAS,UAAU,kBAAkB,OAAO;AAC/D,YAAM,YAAY,KAAK,aAAa,SAAS;AAC7C,YAAM,QAAQ,KAAK,SAAS,SAAS;AACrC,YAAM,gBAAgB,KAAK,iBAAiB,SAAS;AACrD,YAAM,iBAAiB,KAAK,kBAAkB,SAAS;AACvD,YAAM,iBAAiB,KAAK,kBAAkB,SAAS;AACvD,YAAM,cACJ,mBAAmB,OAAO,KAAK,SAAS;AAC1C,YAAM,SAAS,oBAAoB,OAAO;AAC1C,YAAM,gBAAgB;AAAA,QACpB,qBAAqB,OAAO;AAAA,QAC5B,SAAS;AAAA,MACX;AAEA,YAAM,QAAQ;AAAA,QACZ;AAAA,UACE,gBAAgB,KAAK;AAAA,UACrB,cAAc,KAAK,gBAAgB,SAAS;AAAA,UAC5C,QAAQ;AAAA,UACR,UAAU;AAAA,UACV;AAAA,UACA;AAAA,UACA;AAAA,UACA;AAAA,UACA;AAAA,UACA;AAAA,UACA,aAAa,OAAO;AAAA,UACpB,cAAc,OAAO;AAAA,UACrB,iBAAiB,OAAO;AAAA,UACxB,kBAAkB,OAAO;AAAA,UACzB;AAAA,QACF;AAAA,QACA;AAAA,MACF;AAOA,YAAM,eAAe,YAChB,EAAE,GAAG,OAAO,OAAO,UAAU,IAC9B;AAEJ,MAAAA,UAAS,iBAAiB,YAAY;AAEtC,aAAO;AAAA,QACL,SAAS;AAAA,QACT,WAAW;AAAA,UACT,UAAU,OAAO;AAAA,UACjB,QAAQ,OAAO;AAAA,UACf;AAAA,QACF;AAAA,MACF;AAAA,IACF;AAAA,IAEA,KAAK;AAAA,IACL,KAAK,QAAQ;AAKX,YAAM,SAAS,mBAAmB,KAAK,gBAAgB,OAAO;AAC9D,UAAI,CAAC,OAAQ,QAAO;AAEpB,YAAM,cAAc;AAAA;AAAA;AAAA,QAGlB;AAAA,UACE,iBAAiB,OAAO;AAAA,QAC1B;AAAA,QACA,KAAK,eAAe,QAAQ,IAAI;AAAA,MAClC;AACA,UAAI,CAAC,aAAa;AAChB,QAAAA,UAAS,2BAA2B;AAAA,UAClC,gBAAgB,OAAO;AAAA,QACzB,CAAC;AACD;AAAA,UACE,OAAO;AAAA,UACP,OAAO;AAAA,UACP;AAAA,QACF;AACA,eAAO;AAAA,MACT;AAEA,YAAM,SAAS,iBAAiB,WAAW;AAC3C,UAAI,CAAC,QAAQ;AACX,QAAAA,UAAS,6BAA6B,EAAE,YAAY,CAAC;AACrD;AAAA,UACE,OAAO;AAAA,UACP,OAAO;AAAA,UACP;AAAA,QACF;AACA,eAAO;AAAA,MACT;AAGA;AAAA,QACE,OAAO;AAAA,QACP,OAAO;AAAA,QACP;AAAA,MACF;AAOA,YAAM,QAAQ;AAAA,QACZ;AAAA,UACE,gBAAgB,OAAO;AAAA,UACvB,cAAc,OAAO;AAAA,UACrB,QAAQ,OAAO;AAAA,UACf,UAAU;AAAA,UACV,WAAW,OAAO;AAAA,UAClB,OAAO,OAAO;AAAA,UACd,eAAe,OAAO;AAAA,UACtB,gBAAgB,OAAO;AAAA,UACvB,gBAAgB,OAAO;AAAA,UACvB,aAAa,OAAO;AAAA,UACpB,eAAe,OAAO;AAAA,QACxB;AAAA,QACA;AAAA,QACA,UAAU,eAAe,gBAAgB;AAAA,MAC3C;AAEA,YAAM,eAAe,OAAO,YACvB,EAAE,GAAG,OAAO,OAAO,OAAO,UAAU,IAGrC;AAEJ,aAAO;AAAA,QACL,SAAS;AAAA,QACT,WAAW;AAAA,UACT,UAAU,OAAO;AAAA,UACjB,QAAQ,OAAO;AAAA,UACf;AAAA,QACF;AAAA,MACF;AAAA,IACF;AAAA,EACF;AACF;AAEA,SAAS,mBACP,SACA,UACqC;AACrC,MAAI,CAAC,WAAW,CAAC,SAAU,QAAO;AAClC,SAAO,EAAE,GAAI,YAAY,CAAC,GAAI,GAAI,WAAW,CAAC,EAAG;AACnD;AAEA,SAAS,mBACP,gBACA,SACsD;AACtD,QAAM,UAAU,mBAAmB,OAAO;AAC1C,MAAI,QAAQ,WAAW,EAAG,QAAO;AAEjC,MAAI,gBAAgB;AAClB,UAAM,QAAQ,QAAQ,KAAK,CAAC,MAAM,EAAE,mBAAmB,cAAc;AACrE,QAAI,MAAO,QAAO;AAAA,EACpB;AAGA,SAAO,QAAQ;AAAA,IAAK,CAAC,GAAG,OACrB,EAAE,aAAa,IAAI,cAAc,EAAE,aAAa,EAAE;AAAA,EACrD,EAAE,CAAC;AACL;AAEA,IAAM,eAAkC;AAAA,EACtC,IAAID;AAAA,EACJ,aAAa;AAAA,EAEb,QAAQ,MAA2C;AACjD,WAAO,cAAc,IAAI;AAAA,EAC3B;AAAA,EAEA,UAAU,MAAoC;AAC5C,WAAO,gBAAgB,IAAI;AAAA,EAC7B;AAAA,EAEA,OAAO,MAA6B;AAClC,WAAO,gBAAgB,IAAI;AAAA,EAC7B;AAAA,EAEA,WAAW,WAAW,aAAa,MAAkC;AACnE,WAAO,iBAAiB,WAAW,aAAa,IAAI;AAAA,EACtD;AAAA,EAEA,MAAM,kBAAoC;AACxC,QAAI;AAIF,UAAO,gBAAW,iBAAiB,CAAC,EAAG,QAAO;AAC9C,aAAO,kBAAkB;AAAA,IAC3B,QAAQ;AACN,aAAO;AAAA,IACT;AAAA,EACF;AACF;AAEA,SAAS,oBAA6B;AACpC,QAAM,UAAU,QAAQ,IAAI;AAC5B,MAAI,CAAC,QAAS,QAAO;AACrB,QAAM,MAAM,QAAQ,aAAa,UAAU,MAAM;AACjD,QAAM,OACJ,QAAQ,aAAa,WAChB,QAAQ,IAAI,WAAW,kBAAkB,MAAM,GAAG,IACnD,CAAC,EAAE;AACT,aAAW,OAAO,QAAQ,MAAM,GAAG,GAAG;AACpC,eAAW,OAAO,MAAM;AACtB,YAAM,YAAY,GAAG,GAAG,UAAU,IAAI,YAAY,CAAC;AACnD,UAAI;AACF,YAAO,gBAAW,SAAS,EAAG,QAAO;AAAA,MACvC,QAAQ;AAAA,MAER;AAAA,IACF;AAAA,EACF;AACA,SAAO;AACT;AAEA,eAAe,YAAY;;;AjBtX3B,SAAS,UAAU,YAAoB,KAAuB;AAC5D,SAAO,IAAI,QAAQ,CAAC,YAAY;AAC9B,QAAI,QAAQ,MAAM,OAAO;AACvB,cAAQ,EAAE;AACV;AAAA,IACF;AAEA,QAAI,OAAO;AACX,UAAM,QAAQ,WAAW,MAAM;AAC7B,cAAQ,MAAM,mBAAmB;AACjC,cAAQ,MAAM,QAAQ;AACtB,cAAQ,IAAI;AAAA,IACd,GAAG,SAAS;AAEZ,YAAQ,MAAM,YAAY,OAAO;AACjC,YAAQ,MAAM,GAAG,QAAQ,CAAC,UAAkB;AAC1C,cAAQ;AAAA,IACV,CAAC;AACD,YAAQ,MAAM,GAAG,OAAO,MAAM;AAC5B,mBAAa,KAAK;AAClB,cAAQ,IAAI;AAAA,IACd,CAAC;AACD,YAAQ,MAAM,GAAG,SAAS,MAAM;AAC9B,mBAAa,KAAK;AAClB,cAAQ,IAAI;AAAA,IACd,CAAC;AAAA,EACH,CAAC;AACH;AAOA,IAAM,+BAAuC;AAE7C,eAAe,uBACb,MACA,SACiB;AACjB,MAAI,OAAO,SAAS,YAAY,KAAK,SAAS,GAAG;AAC/C,QAAI,CAAC,SAAS,IAAI,GAAG;AACnB,cAAQ;AAAA,QACN,mBAAmB,IAAI,iBAAiB,SAAS,KAAK,IAAI,CAAC;AAAA,MAC7D;AACA,cAAQ,KAAK,CAAC;AAAA,IAChB;AACA,WAAO;AAAA,EACT;AAEA,MAAI,CAAC,cAAc,GAAG;AACpB,YAAQ;AAAA,MACN,gDAAgD,4BAA4B;AAAA,IAC9E;AACA,WAAO;AAAA,EACT;AAEA,SAAO,cAAc,OAAO;AAC9B;AAEA,eAAe,cACb,SACiB;AACjB,QAAM,UAAU,YAAY;AAC5B,QAAM,WAAqB,CAAC;AAC5B,aAAW,KAAK,SAAS;AACvB,QAAI;AACF,UAAI,MAAM,EAAE,gBAAgB,EAAG,UAAS,KAAK,EAAE,EAAE;AAAA,IACnD,QAAQ;AAAA,IAER;AAAA,EACF;AAEA,UAAQ,IAAI,2CAA2C;AACvD,WAAS,IAAI,GAAG,IAAI,QAAQ,QAAQ,KAAK;AACvC,UAAM,IAAI,QAAQ,CAAC;AACnB,UAAM,OAAO,SAAS,SAAS,EAAE,EAAE,IAAI,gBAAgB;AACvD,YAAQ,IAAI,KAAK,IAAI,CAAC,KAAK,EAAE,WAAW,KAAK,EAAE,EAAE,IAAI,IAAI,EAAE;AAAA,EAC7D;AAEA,QAAM,aAAa,QAAQ,UAAU,CAAC,MAAM,SAAS,SAAS,EAAE,EAAE,CAAC;AACnE,QAAM,eAAe,cAAc,IAAI,GAAG,aAAa,CAAC,KAAK;AAC7D,QAAM,SAAS,MAAM;AAAA,IACnB,oBAAoB,OAAO,OAAO,QAAQ,MAAM,MAAM,YAAY;AAAA,EACpE;AAEA,QAAM,SAAS,OAAO,KAAK,MAAM,KAAK,eAAe,OAAO,KAAK;AACjE,QAAM,MAAM,SAAS,QAAQ,EAAE,IAAI;AACnC,MAAI,MAAM,GAAG,KAAK,MAAM,KAAK,OAAO,QAAQ,QAAQ;AAClD,YAAQ,MAAM,oBAAoB;AAClC,YAAQ,KAAK,CAAC;AAAA,EAChB;AACA,SAAO,QAAQ,GAAG,EAAE;AACtB;AAMA,eAAe,YAAY,SAAkC;AAC3D,QAAM,SAAS,MAAM,uBAAuB,QAAQ,MAAM,MAAM;AAChE,QAAM,SAAS,UAAU,MAAM;AAC/B,QAAM;AAAA,IAAgB;AAAA,IAAQ,MAC5B,OAAO,QAAQ,EAAE,aAAa,QAAQ,IAAI,GAAG,aAAa,KAAK,CAAC;AAAA,EAClE;AACF;AAEA,eAAe,cACb,SACe;AACf,QAAM,SAAS,MAAM,uBAAuB,QAAQ,MAAM,QAAQ;AAClE,QAAM,SAAS,UAAU,MAAM;AAE/B,MAAI,QAAQ,MAAM;AAChB,UAAME,UAAS,MAAM,OAAO,OAAO,EAAE,aAAa,QAAQ,IAAI,EAAE,CAAC;AACjE,YAAQ,IAAI,KAAK,UAAUA,SAAQ,MAAM,CAAC,CAAC;AAC3C;AAAA,EACF;AAQA,MAAI,OAAO,OAAO,eAAe;AAC/B,UAAM,EAAE,sBAAsB,IAAI,MAAM,OACtC,sBACF;AACA,UAAM,sBAAsB,EAAE,aAAa,QAAQ,IAAI,EAAE,CAAC;AAC1D;AAAA,EACF;AAEA,QAAM,SAAS,MAAM,OAAO,OAAO,EAAE,aAAa,QAAQ,IAAI,EAAE,CAAC;AACjE,MAAI,OAAO,SAAS,OAAO,MAAM,SAAS,GAAG;AAC3C,eAAW,QAAQ,OAAO,OAAO;AAC/B,cAAQ,IAAI,IAAI;AAAA,IAClB;AACA;AAAA,EACF;AAGA,UAAQ,IAAI,KAAK,UAAU,QAAQ,MAAM,CAAC,CAAC;AAC7C;AAEA,eAAe,eACb,SACe;AACf,QAAM,SAAS,MAAM,uBAAuB,QAAQ,MAAM,SAAS;AACnE,QAAM,SAAS,UAAU,MAAM;AAC/B,QAAM;AAAA,IAAgB;AAAA,IAAQ,MAC5B,OAAO,UAAU;AAAA,MACf,aAAa,QAAQ,IAAI;AAAA,MACzB,YAAY,QAAQ;AAAA,IACtB,CAAC;AAAA,EACH;AACF;AAEA,eAAe,gBACb,QACA,IACmB;AACnB,MAAI;AACF,WAAO,MAAM,GAAG;AAAA,EAClB,SAAS,KAAK;AACZ,UAAM,IAAI;AACV,QAAI,EAAE,SAAS,uBAAuB;AACpC,cAAQ,MAAM,GAAG,OAAO,WAAW,KAAK,EAAE,OAAO,EAAE;AACnD,cAAQ,KAAK,CAAC;AAAA,IAChB;AACA,UAAM;AAAA,EACR;AACF;AAYA,eAAe,YACb,OACA,SACA,SACe;AACf,MAAI;AAIF,UAAM,cACJ,QAAQ,qBAAqB,MAAM,MAAM;AAE3C,QAAI;AACJ,QAAI,aAAa;AACf,UAAI,CAAC,QAAQ,QAAQ,CAAC,SAAS,QAAQ,IAAI,GAAG;AAG5C,6BAAqB,QAAQ,MAAM,KAAK;AACxC;AAAA,MACF;AACA,eAAS,QAAQ;AAAA,IACnB,OAAO;AACL,eAAS;AAAA,IACX;AACA,UAAM,SAAS,UAAU,MAAM;AAE/B,UAAM,YAAY,MAAM,UAAU,GAAI;AACtC,QAAI,cAAuB,CAAC;AAC5B,QAAI,WAAW;AACb,UAAI;AACF,sBAAc,KAAK,MAAM,SAAS;AAAA,MACpC,QAAQ;AAAA,MAGR;AAAA,IACF;AAEA,UAAM,SAAS,MAAM,OAAO,WAAW,OAAO,WAAW;AACzD,QAAI,CAAC,OAAQ;AAMb,UAAM,sBAAsB,MAAM;AAAA,EACpC,QAAQ;AAAA,EAGR;AACF;AAEA,SAAS,qBACP,OACA,OACM;AACN,MAAI,QAAQ,IAAI,yBAAyB,IAAK;AAC9C,MAAI;AAGF,UAAM,UAAU,6BAA6B,QAAQ,GAAG;AACxD,UAAM,OAAO,KAAI,oBAAI,KAAK,GAAE,YAAY,CAAC,6BAA6B,KAAK;AAAA,MACzE,EAAE,OAAO,MAAM,SAAS,KAAK;AAAA,IAC/B,CAAC;AAAA;AACD,IAAG,oBAAe,SAAS,MAAM,OAAO;AAAA,EAC1C,QAAQ;AAAA,EAER;AACF;AAEA,eAAe,sBAAsB,QAAmC;AACtE,QAAM,aAAa,IAAI,gBAAgB;AACvC,QAAM,YAAY,WAAW,MAAM,WAAW,MAAM,GAAG,GAAI;AAC3D,QAAM,QAAQ,QAAQ,IAAI,yBAAyB;AACnD,QAAM,UAAU,6BAA6B,QAAQ,GAAG;AACxD,QAAMC,OAAM,CAAC,OAAe,SAAkB;AAC5C,QAAI,CAAC,MAAO;AACZ,QAAI;AACF,MAAG;AAAA,QACD;AAAA,QACA,KAAI,oBAAI,KAAK,GAAE,YAAY,CAAC,gBAAgB,KAAK,KAAK,KAAK,UAAU,IAAI,CAAC;AAAA;AAAA,QAC1E;AAAA,MACF;AAAA,IACF,QAAQ;AAAA,IAER;AAAA,EACF;AACA,MAAI;AACF,IAAAA,KAAI,WAAW;AAAA,MACb,UAAU,OAAO,UAAU;AAAA,MAC3B,eAAe,QAAQ,OAAO,UAAU,MAAM;AAAA,MAC9C,cAAc,OAAO,UAAU,SAC3B,OAAO,UAAU,OAAO,MAAM,GAAG,CAAC,IAAI,QACtC;AAAA,MACJ,WAAW,KAAK,UAAU,CAAC,OAAO,OAAO,CAAC,EAAE;AAAA,IAC9C,CAAC;AACD,UAAM,WAAW,MAAM,MAAM,OAAO,UAAU,UAAU;AAAA,MACtD,QAAQ;AAAA,MACR,SAAS;AAAA,QACP,aAAa,OAAO,UAAU;AAAA,QAC9B,gBAAgB;AAAA,MAClB;AAAA,MACA,MAAM,KAAK,UAAU,CAAC,OAAO,OAAO,CAAC;AAAA,MACrC,QAAQ,WAAW;AAAA,IACrB,CAAC;AACD,QAAI,cAA6B;AACjC,QAAI;AACF,qBAAe,MAAM,SAAS,KAAK,GAAG,MAAM,GAAG,GAAG;AAAA,IACpD,QAAQ;AAAA,IAER;AACA,IAAAA,KAAI,UAAU,EAAE,QAAQ,SAAS,QAAQ,YAAY,CAAC;AAAA,EACxD,SAAS,KAAK;AACZ,IAAAA,KAAI,cAAc;AAAA,MAChB,MAAM,eAAe,QAAQ,IAAI,OAAO;AAAA,MACxC,SAAS,eAAe,QAAQ,IAAI,UAAU,OAAO,GAAG;AAAA,IAC1D,CAAC;AACD,UAAM;AAAA,EACR,UAAE;AACA,iBAAa,SAAS;AAAA,EACxB;AACF;AAEO,SAAS,uBAAuBC,UAAwB;AAC7D,QAAM,UAAUA,SACb,QAAQ,SAAS,EACjB;AAAA,IACC;AAAA,EACF;AAEF,UACG,QAAQ,MAAM,EACd,YAAY,6CAA6C,EACzD;AAAA,IACC;AAAA,IACA,sBAAsB,SAAS,KAAK,GAAG,CAAC;AAAA,EAC1C,EACC,OAAO,WAAW;AAErB,UACG,QAAQ,cAAc,EACtB,YAAY,2DAA2D,EACvE;AAAA,IACC;AAAA,IACA;AAAA,EACF,EACC,OAAO,WAAW;AAErB,UACG,QAAQ,QAAQ,EAChB,YAAY,2CAA2C,EACvD;AAAA,IACC;AAAA,IACA,oBAAoB,SAAS,KAAK,GAAG,CAAC;AAAA,EACxC,EACC,OAAO,UAAU,gBAAgB,EACjC,OAAO,aAAa;AAEvB,UACG,QAAQ,SAAS,EACjB,YAAY,8CAA8C,EAC1D;AAAA,IACC;AAAA,IACA,oBAAoB,SAAS,KAAK,GAAG,CAAC;AAAA,EACxC,EACC;AAAA,IACC;AAAA,IACA;AAAA,EACF,EACC,OAAO,cAAc;AAKxB,aAAW,UAAU,YAAY,GAAG;AAClC,WAAO,mBAAmB,OAAO;AAAA,EACnC;AACF;;;AVjXA,IAAMC,WAAU,cAAc,YAAY,GAAG;AAC7C,IAAM,cAAcA,SAAQ,iBAAiB;AAE7C,IAAM,UAAU,IAAI,QAAQ;AAE5B,QACG,KAAK,QAAQ,EACb,YAAY,iBAAiB,EAC7B,QAAQ,YAAY,OAAO,EAC3B;AAAA,EACC;AAAA,EACA,uBAAuB,qBAAqB,EAAE,KAAK,IAAI,CAAC;AAAA,EACxD;AACF,EACC,KAAK,aAAa,CAAC,gBAAgB;AAClC,QAAM,UAAU,YAAY,KAAK;AACjC,MAAI,QAAQ,KAAK;AACf,QAAI,CAAC,mBAAmB,QAAQ,GAAG,GAAG;AACpC,cAAQ;AAAA,QACN,wBAAwB,QAAQ,GAAG,oBAAoB,qBAAqB,EAAE,KAAK,IAAI,CAAC;AAAA,MAC1F;AACA,cAAQ,KAAK,CAAC;AAAA,IAChB;AACA,mBAAe,QAAQ,GAAkB;AAAA,EAC3C;AACF,CAAC;AAEH,QACG,QAAQ,OAAO,EACf,YAAY,+CAA+C,EAC3D,OAAO,YAAY;AAEtB,QACG,QAAQ,QAAQ,EAChB,YAAY,qBAAqB,EACjC,OAAO,aAAa;AAEvB,QACG,QAAQ,QAAQ,EAChB,YAAY,6BAA6B,EACzC,OAAO,aAAa;AAGvB,sBAAsB,OAAO;AAC7B,yBAAyB,OAAO;AAChC,oBAAoB,OAAO;AAC3B,0BAA0B,OAAO;AAGjC,wBAAwB,OAAO;AAG/B,uBAAuB,OAAO;AAE9B,QAAQ,MAAM;","names":["program","listCommand","getCommand","createCommand","updateCommand","deleteCommand","program","listCommand","getCommand","createCommand","updateCommand","deleteCommand","program","listCommand","getCommand","createCommand","updateCommand","deleteCommand","program","listCommand","getCommand","program","fs","fs","fs","path","fs","debugLog","fs","fs","path","os","path","OLAKAI_HOOK_MARKER","fs","path","getCodexConfigPath","createNewAgent","getCodexConfigPath","path","fs","getCodexConfigPath","fs","path","noopDebug","debugLog","noopDebug","debugLog","TOOL_ID","debugLog","getCodexConfigPath","fs","os","fs","os","path","fs","path","os","path","OLAKAI_HOOK_MARKER","createNewAgent","fs","os","path","fs","os","path","STATE_DIR_SEGMENTS","TOOL_ID","debugLog","report","log","program","require"]}