olakai-cli 0.6.3 → 0.6.5
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/api-63UDJX5M.js +70 -0
- package/dist/chunk-2Q7JYGCK.js +316 -0
- package/dist/chunk-2Q7JYGCK.js.map +1 -0
- package/dist/{chunk-OHPX4STO.js → chunk-AVB4N2UN.js} +2 -310
- package/dist/chunk-AVB4N2UN.js.map +1 -0
- package/dist/chunk-GU4HEL24.js +876 -0
- package/dist/chunk-GU4HEL24.js.map +1 -0
- package/dist/index.js +246 -1033
- package/dist/index.js.map +1 -1
- package/dist/{status-CAHO5FHI.js → status-USHUUHK6.js} +3 -2
- package/dist/status-USHUUHK6.js.map +1 -0
- package/package.json +1 -1
- package/dist/chunk-OHPX4STO.js.map +0 -1
- /package/dist/{status-CAHO5FHI.js.map → api-63UDJX5M.js.map} +0 -0
package/dist/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
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/init.ts","../src/lib/handshake.ts","../src/monitor/prompt.ts","../src/monitor/detect-all.ts","../src/monitor/plugins/codex/paths.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/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/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","../src/monitor/install.ts","../src/lib/branding.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/profiles.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 { initCommand, type InitCommandOptions } from \"./commands/init.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 { registerProfilesCommand } from \"./commands/profiles.js\";\nimport {\n setEnvironment,\n setHostOverride,\n isValidEnvironment,\n getValidEnvironments,\n type Environment,\n} from \"./lib/config.js\";\nimport { setProfileOverride } from \"./lib/profiles.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 .option(\n \"--host <host>\",\n \"On-prem Olakai host (e.g. olakai.acme.com). Overrides --env and OLAKAI_HOST.\",\n )\n .option(\n \"--profile <name>\",\n \"Olakai profile to use (overrides OLAKAI_PROFILE, workspace config, and registry default).\",\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 if (typeof options.host === \"string\" && options.host.length > 0) {\n setHostOverride(options.host);\n }\n if (typeof options.profile === \"string\" && options.profile.length > 0) {\n setProfileOverride(options.profile);\n }\n });\n\nprogram\n .command(\"init\")\n .description(\n \"Interactive self-onboarding wizard: pick host, verify email, get a CLI token.\",\n )\n .option(\"--email <email>\", \"Pre-fill the email (skips the email prompt)\")\n .option(\n \"--non-interactive\",\n \"Fail fast on any missing required input (no prompts).\",\n )\n .option(\n \"--skip-monitor\",\n \"Skip the optional 'olakai monitor init' handoff at the end.\",\n )\n .action((options: InitCommandOptions) => initCommand(options));\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\n// Register subcommands for AWS-style profile management\nregisterProfilesCommand(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 { getBaseUrl, getEnvironment } from \"../lib/config.js\";\nimport { patchProfile, resolveProfileName } from \"../lib/profiles.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 const resolved = resolveProfileName();\n const profileName = resolved?.name ?? \"default\";\n console.log(\n `Logging in to Olakai (profile: ${profileName}, host: ${getBaseUrl()}, env: ${getEnvironment()})...\\n`,\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 (lands in the active profile, or \"default\" if\n // no profile was explicitly selected).\n saveToken(tokenResponse.access_token, tokenResponse.expires_in);\n\n // Get user info and cache identifiers on the profile so\n // offline `whoami` still has something to show.\n const user = await getCurrentUser();\n try {\n patchProfile(profileName, {\n email: user.email,\n userId: user.id,\n accountId: user.accountId,\n });\n } catch {\n // best-effort\n }\n\n console.log(`\\nLogged in as ${user.email}`);\n console.log(`Profile: ${profileName}`);\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, loadToken } from \"../lib/auth.js\";\nimport { getBaseUrl, getEnvironment } from \"../lib/config.js\";\nimport { patchProfile, resolveActiveProfile } from \"../lib/profiles.js\";\n\nfunction formatExpiry(expiresAt: number | undefined): string {\n if (typeof expiresAt !== \"number\") return \"no token\";\n const now = Math.floor(Date.now() / 1000);\n if (expiresAt <= now) return \"expired\";\n const seconds = expiresAt - now;\n const days = Math.floor(seconds / 86400);\n const hours = Math.floor((seconds % 86400) / 3600);\n if (days > 0) return `${days}d ${hours}h`;\n const minutes = Math.floor((seconds % 3600) / 60);\n if (hours > 0) return `${hours}h ${minutes}m`;\n return `${minutes}m`;\n}\n\n/**\n * Whoami command handler.\n *\n * Prints the active profile, host, user identity (email + name +\n * account), and token expiry. Falls back gracefully when individual\n * fields aren't available (e.g. unauthenticated, or the backend is\n * unreachable but a profile is configured locally).\n */\nexport async function whoamiCommand(): Promise<void> {\n let active;\n try {\n active = resolveActiveProfile();\n } catch (err) {\n console.error(err instanceof Error ? err.message : String(err));\n process.exit(1);\n }\n\n // Always print the resolved local view first — works even when\n // unauthenticated.\n if (active) {\n const effectiveHost = getBaseUrl();\n console.log(`Profile: ${active.name} (from ${active.source})`);\n if (effectiveHost !== active.host) {\n console.log(`Host: ${effectiveHost} (overrides profile host)`);\n console.log(`Profile host: ${active.host}`);\n } else if (active.hostFromWorkspaceConfig) {\n console.log(`Host: ${active.host} (from workspace config)`);\n } else {\n console.log(`Host: ${active.host}`);\n }\n } else {\n // \"Not logged in\" is an error state — write to stderr so scripts\n // that pipe `whoami` to grep / jq don't catch this in their stdout.\n console.error(`Profile: (none)`);\n console.error(`Host: ${getBaseUrl()}`);\n console.error(`Environment: ${getEnvironment()}`);\n console.error(\"Not logged in. Run 'olakai login' to authenticate.\");\n process.exit(1);\n }\n\n if (!isTokenValid()) {\n const creds = loadToken();\n console.log(`Token: ${creds ? \"expired\" : \"missing\"}`);\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 // Backfill cached identifiers so subsequent `profiles list` /\n // `whoami` (and future offline commands) can display them without\n // a network round-trip. Best-effort: any failure is swallowed.\n try {\n patchProfile(active.name, {\n email: user.email,\n userId: user.id,\n accountId: user.accountId,\n });\n } catch {\n // ignore\n }\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(\n `Token: valid (expires in ${formatExpiry(active.profile.expiresAt)})`,\n );\n } catch (error) {\n // Fall back to cached identifiers when the backend is unreachable\n // but we still have a valid local token.\n if (active.profile.email) {\n console.log(`Email: ${active.profile.email} (cached)`);\n }\n if (active.profile.accountId) {\n console.log(`Account ID: ${active.profile.accountId} (cached)`);\n }\n console.log(\n `Token: valid (expires in ${formatExpiry(active.profile.expiresAt)})`,\n );\n if (error instanceof Error) {\n console.error(`Warning: could not contact Olakai backend: ${error.message}`);\n } else {\n console.error(\"Warning: could not contact Olakai backend\");\n }\n }\n}\n","/**\n * `olakai init` — the self-onboarding wizard (OLA-212).\n *\n * Flow at a glance:\n *\n * 1. Resolve the target profile name. If it already holds a valid\n * token, offer an early exit (\"already authenticated\").\n * 2. Pick a host: `--host`/env > existing profile host > interactive\n * menu (production / staging / on-prem custom).\n * 3. Collect the user's email.\n * 4. POST /api/cli/handshake. Branch on the response:\n * - device-flow → hand off to the existing `loginCommand`\n * (same device-flow used by `olakai login`; we DO NOT\n * duplicate that flow here).\n * - OTP → enter the OTP loop (verify → exchange).\n * - signup → open browser + ask user to re-run.\n * - blocked → fail with a clear admin-action message.\n * 5. On OTP success: exchange the consent token for the 30-day\n * bearer, persist it to the active profile via `saveToken`.\n * 6. Offer monitor setup. Actually chaining into `olakai monitor`\n * is owned by S5 (OLA-214); for now we just print the one-liner.\n *\n * Non-interactive mode (`--non-interactive`) fails fast on any prompt\n * the user could have answered via flag/env. That makes the wizard\n * safe to call from automation (e.g. CI bootstrapping a profile from\n * a service account email).\n */\n\nimport open from \"open\";\nimport {\n postHandshake,\n postHandshakeExchange,\n postHandshakeVerify,\n} from \"../lib/handshake.js\";\nimport { loginCommand } from \"./login.js\";\nimport { saveToken, isTokenValid } from \"../lib/auth.js\";\nimport { getBaseUrl, setHostOverride } from \"../lib/config.js\";\nimport {\n HOSTS,\n patchProfile,\n readProfilesFile,\n resolveProfileName,\n} from \"../lib/profiles.js\";\nimport { promptUser, isInteractive } from \"../monitor/prompt.js\";\nimport { detectInstalledTools } from \"../monitor/detect-all.js\";\nimport { runMonitorInstall } from \"../monitor/install.js\";\nimport {\n formatExistingUserBrowserGreeting,\n printLogoHeader,\n} from \"../lib/branding.js\";\n\nexport interface InitCommandOptions {\n email?: string;\n host?: string;\n /** Identical to the global `--profile` flag; commander passes it through. */\n profile?: string;\n nonInteractive?: boolean;\n skipMonitor?: boolean;\n}\n\n/**\n * The most permissive RFC-5322-ish email check the CLI is comfortable\n * shipping. Backend does the real validation; this is just enough to\n * stop obviously-broken input from costing the user a network round\n * trip.\n */\nconst EMAIL_REGEX = /^[^\\s@]+@[^\\s@]+\\.[^\\s@]+$/;\nconst OTP_REGEX = /^\\d{6}$/;\nconst PRESET_HOSTS: ReadonlyArray<{ label: string; url: string }> = [\n { label: \"production (app.olakai.ai)\", url: HOSTS.production },\n { label: \"staging (staging.app.olakai.ai)\", url: HOSTS.staging },\n];\n\nexport async function initCommand(options: InitCommandOptions): Promise<void> {\n const interactive = !options.nonInteractive && isInteractive();\n\n // Logo + tagline at the very top of the interactive flow. Suppressed\n // by `printLogoHeader` itself when stdout isn't a TTY so CI runs and\n // piped output stay clean.\n if (interactive) {\n printLogoHeader();\n }\n\n try {\n // 1. Resolve the profile we'll be writing to. `resolveProfileName`\n // is the lenient resolver — it never throws, and may return null\n // if no registry exists yet (fresh install).\n const resolved = resolveProfileName();\n const profileName = resolved?.name ?? \"default\";\n\n // 2. Resolve the host. CLI flag (already handled by the global\n // preAction hook) wins via getBaseUrl(). Otherwise prefer the\n // profile's stored host. Otherwise interactive pick.\n const host = await resolveHost(profileName, options, interactive);\n // Apply the host so all subsequent `getBaseUrl()` calls (incl. the\n // handshake client) point at the right backend.\n setHostOverride(host);\n\n // 3. Early-exit if the active profile already has a valid token.\n if (isTokenValid()) {\n const file = readProfilesFile();\n const existing = file.profiles[profileName];\n const who = existing?.email ?? \"unknown\";\n if (options.nonInteractive) {\n // Non-interactive: idempotent no-op. Don't surprise scripts.\n console.log(\n `Already authenticated as ${who} on ${host} (profile: ${profileName}).`,\n );\n return;\n }\n const answer = await promptUser(\n `Already authenticated as ${who} on ${host} (profile: ${profileName}). Re-authenticate? [y/N]: `,\n );\n if (answer.trim().toLowerCase() !== \"y\") {\n console.log(\"Keeping existing credentials. Run 'olakai logout' to sign out.\");\n return;\n }\n }\n\n // 4. Email.\n const email = await resolveEmail(options, interactive);\n\n console.log(`\\nContacting ${host} for ${email}...`);\n\n // 5. Handshake. One retry on transient network failures (per\n // spec) — only `network_error`, never 4xx/5xx, which carry\n // semantic meaning the wizard must surface unchanged.\n let handshake = await postHandshake({ email, host });\n if (handshake.kind === \"error\" && handshake.code === \"network_error\") {\n console.log(\"(Network error contacting Olakai — retrying once...)\");\n handshake = await postHandshake({ email, host });\n }\n if (handshake.kind === \"error\") {\n handleHandshakeError(handshake);\n return;\n }\n\n const response = handshake.data;\n\n switch (response.status) {\n case \"user_exists\":\n if (\"deviceFlowOk\" in response && response.deviceFlowOk === true) {\n // Existing non-EMPLOYEE user → existing device-flow login.\n // Reuse `loginCommand` verbatim so there's exactly one\n // device-flow code path in the CLI.\n //\n // Pre-browser greeting (OLA-226): the prior one-liner read as\n // unexplained friction to admins evaluating Olakai (Xavier\n // session, 2026-05-14). Surface that we identified the user,\n // explain the role-tier reason for the browser step, and\n // make the contrast with the Employee-role OTP path explicit\n // so admins don't generalize the friction to their team.\n console.log(\"\");\n console.log(formatExistingUserBrowserGreeting(email));\n if (interactive) {\n // Press-Enter gate. The user has read the message; opening\n // the browser without acknowledgement felt abrupt during\n // Xavier's evaluation. Ctrl-C still bails as expected.\n await promptUser(\n \"\\n > Press Enter to open your browser, or Ctrl-C to cancel: \",\n );\n }\n console.log(\"\");\n await loginCommand();\n await offerMonitorSetup(options, interactive);\n return;\n }\n // EMPLOYEE refresh path: OTP. Narrow via the OTP-branch shape.\n if (\"otpSent\" in response && response.otpSent === true) {\n await runOtpFlow(email, profileName, {\n emailObfuscated: response.emailObfuscated,\n expiresIn: response.expiresIn,\n });\n await offerMonitorSetup(options, interactive);\n return;\n }\n // Defensive fallback — the backend returned `user_exists`\n // without the expected discriminator. Surface clearly instead\n // of silently hanging.\n console.error(\n \"Unexpected handshake response: 'user_exists' without device-flow or OTP signal.\",\n );\n process.exit(1);\n return;\n\n case \"domain_claimed\":\n await runOtpFlow(email, profileName, {\n emailObfuscated: response.emailObfuscated,\n expiresIn: response.expiresIn,\n });\n await offerMonitorSetup(options, interactive);\n return;\n\n case \"saas_can_self_signup\": {\n console.log(\n \"\\nWe don't have you yet. Opening your browser to create an account...\",\n );\n // BLOCKING from pre-PR review: validate the URL scheme before\n // handing it to the platform opener. A compromised or\n // misconfigured backend could otherwise return `file://`,\n // `javascript:`, `vscode://`, `ssh://`, etc. — anything the\n // OS opener accepts. Defense-in-depth: only http/https.\n if (isSafeOpenUrl(response.signupUrl)) {\n try {\n await open(response.signupUrl);\n } catch {\n console.log(\n `(Could not open browser automatically. Visit ${response.signupUrl})`,\n );\n }\n } else {\n console.log(\n `(Server returned an unexpected signup URL scheme. Visit ${response.signupUrl} manually in your browser.)`,\n );\n }\n console.log(\n \"When done, re-run 'olakai init' to finish authenticating this CLI.\",\n );\n return;\n }\n\n case \"blocked\": {\n const domain = email.split(\"@\")[1] ?? email;\n console.error(\n `\\nYour domain \"${domain}\" isn't connected to an Olakai workspace.`,\n );\n if (response.message) {\n console.error(response.message);\n }\n console.error(\"Ask your admin to claim it, then re-run 'olakai init'.\");\n process.exit(1);\n }\n }\n } catch (err) {\n if (err instanceof InitAbortedError) {\n if (err.message) console.error(err.message);\n process.exit(err.exitCode);\n }\n console.error(err instanceof Error ? err.message : String(err));\n process.exit(1);\n }\n}\n\n/**\n * Allow only `http:` / `https:` schemes for any URL we hand to the\n * platform opener (`open`). The OS opener accepts `file:`, `mailto:`,\n * `vscode://`, `ssh://`, custom URL handlers, etc. — none of which a\n * trustworthy handshake response should ever return. Falling through to\n * a manual copy/paste message is the safe degradation.\n */\nfunction isSafeOpenUrl(raw: string): boolean {\n try {\n const url = new URL(raw);\n return url.protocol === \"http:\" || url.protocol === \"https:\";\n } catch {\n return false;\n }\n}\n\n// ---- host selection --------------------------------------------------------\n\nasync function resolveHost(\n profileName: string,\n options: InitCommandOptions,\n interactive: boolean,\n): Promise<string> {\n // `getBaseUrl()` already applies `--host`/OLAKAI_HOST overrides set\n // by the global preAction hook. If either is in effect, that's the\n // host we use. If neither is in effect, the lenient resolver in\n // `getBaseUrl()` may still return the profile's stored host — that's\n // also fine.\n //\n // Precedence per CLAUDE.md: `--host` flag wins over `OLAKAI_HOST`\n // env (the flag is the more explicit signal). Practically a no-op\n // today because `preAction` already pushed both into `getBaseUrl()`,\n // but checking the flag first keeps this in lockstep with the\n // documented resolution order so a future refactor can't drift.\n const fromFlag = options.host?.trim() || process.env.OLAKAI_HOST?.trim();\n if (fromFlag) {\n return getBaseUrl();\n }\n\n // If the profile already has a host, prefer it — but offer an\n // override path for interactive users with no valid token (OLA-229).\n //\n // The stored host survives `olakai logout` (which only clears\n // `token` + `expiresAt`, see `profiles.ts`), so a user who logged\n // out specifically to switch workspaces would otherwise be quietly\n // routed back to the same one. Silent prefer is right for:\n // - non-interactive runs (CI / scripts)\n // - re-runs with a still-valid token (the user opted into\n // re-auth via the early-exit prompt; they're keeping the\n // current workspace)\n // Re-prompt is right when interactive AND there's no valid token —\n // the user is actively re-authenticating from a logged-out state\n // and might be switching contexts.\n const file = readProfilesFile();\n const existing = file.profiles[profileName];\n if (existing?.host) {\n if (!interactive || isTokenValid()) {\n return existing.host;\n }\n const keep = await promptUser(\n `\\nConnect to ${existing.host}? [Y/n] (or pick a different workspace): `,\n );\n if (keep.trim().toLowerCase() !== \"n\") {\n return existing.host;\n }\n // Fall through to the picker below.\n console.log(\"\");\n }\n\n if (!interactive) {\n throw new InitAbortedError(\n \"No host configured. Pass --host or set OLAKAI_HOST in non-interactive mode.\",\n );\n }\n\n // Interactive picker.\n console.log(\"\\nWhich Olakai workspace are you connecting to?\");\n for (let i = 0; i < PRESET_HOSTS.length; i += 1) {\n const entry = PRESET_HOSTS[i]!;\n console.log(` ${i + 1}) ${entry.label}`);\n }\n console.log(` ${PRESET_HOSTS.length + 1}) Custom (on-prem)`);\n\n const choice = await promptUser(`Choose [1-${PRESET_HOSTS.length + 1}]: `);\n const idx = Number.parseInt(choice.trim(), 10);\n if (idx >= 1 && idx <= PRESET_HOSTS.length) {\n return PRESET_HOSTS[idx - 1]!.url;\n }\n if (idx === PRESET_HOSTS.length + 1) {\n return promptForCustomHost();\n }\n console.error(\"Invalid choice. Re-run 'olakai init' and pick a valid option.\");\n throw new InitAbortedError(\"\", 1);\n}\n\nasync function promptForCustomHost(): Promise<string> {\n for (let attempt = 0; attempt < 3; attempt += 1) {\n const raw = await promptUser(\"On-prem URL or hostname (e.g. olakai.acme.com): \");\n const normalized = normalizeHost(raw.trim());\n if (normalized) {\n return normalized;\n }\n console.log(\"That doesn't look like a valid host. Try again.\");\n }\n throw new InitAbortedError(\"Too many invalid host entries.\", 1);\n}\n\nfunction normalizeHost(value: string): string | null {\n if (!value) return null;\n // Allow bare hostnames; require at least one dot OR `localhost`.\n // Anything else is almost certainly a typo.\n const withScheme = /^https?:\\/\\//i.test(value) ? value : `https://${value}`;\n let url: URL;\n try {\n url = new URL(withScheme);\n } catch {\n return null;\n }\n if (!url.hostname) return null;\n if (!url.hostname.includes(\".\") && url.hostname !== \"localhost\") {\n return null;\n }\n return `${url.protocol}//${url.host}`.replace(/\\/+$/, \"\");\n}\n\n// ---- email collection ------------------------------------------------------\n\nasync function resolveEmail(\n options: InitCommandOptions,\n interactive: boolean,\n): Promise<string> {\n if (options.email) {\n const trimmed = options.email.trim();\n if (!EMAIL_REGEX.test(trimmed)) {\n throw new InitAbortedError(\n `Invalid email: \"${options.email}\". Re-run with a well-formed --email.`,\n );\n }\n return trimmed;\n }\n if (!interactive) {\n throw new InitAbortedError(\n \"Missing --email in non-interactive mode. Pass --email <you@company.com>.\",\n );\n }\n for (let attempt = 0; attempt < 3; attempt += 1) {\n const raw = await promptUser(\"Work email: \");\n const trimmed = raw.trim();\n if (EMAIL_REGEX.test(trimmed)) {\n return trimmed;\n }\n console.log(\"That doesn't look like a valid email. Try again.\");\n }\n throw new InitAbortedError(\"Too many invalid email entries.\", 1);\n}\n\n// ---- OTP loop --------------------------------------------------------------\n\ninterface OtpContext {\n emailObfuscated: string;\n expiresIn: number;\n}\n\nasync function runOtpFlow(\n email: string,\n profileName: string,\n ctx: OtpContext,\n): Promise<void> {\n const expiryMin = Math.max(1, Math.round(ctx.expiresIn / 60));\n console.log(\n `\\nWe sent a 6-digit code to ${ctx.emailObfuscated} (expires in ${expiryMin} min).`,\n );\n\n // The OTP loop terminates on:\n // - verify success → break and exchange\n // - locked / no_code → exit 1\n // - expired → restart handshake (caller's responsibility — we\n // surface a clear message and exit 1, instructing the user to\n // re-run init; that's strictly simpler than re-driving the\n // handshake mid-loop, and matches the wording in the spec)\n for (;;) {\n const code = await promptUser(\"Enter the 6-digit code: \");\n const trimmed = code.trim();\n if (!OTP_REGEX.test(trimmed)) {\n console.log(\"Codes are 6 digits. Try again.\");\n continue;\n }\n // One-shot retry on transient network failure. Same shape as the\n // existing handshake retry — `verify` is idempotent on the wire\n // (no state change unless the request reaches the server and\n // decodes), so retrying a connection-level failure is safe. The\n // rare race where the server consumed an OTP attempt but the\n // response was lost trades one attempt-counter slot for not\n // aborting the whole flow on a TLS hiccup — favorable trade given\n // the 5-attempt lockout budget.\n let result = await postHandshakeVerify({ email, code: trimmed });\n if (result.kind === \"error\" && result.code === \"network_error\") {\n console.log(\"(Network error verifying code — retrying once...)\");\n result = await postHandshakeVerify({ email, code: trimmed });\n }\n if (result.kind === \"ok\") {\n const consentToken = result.data.consentToken;\n await runExchange(consentToken, profileName, email);\n return;\n }\n\n switch (result.code) {\n case \"invalid_code\": {\n const remaining = result.detail?.attemptsRemaining;\n const tail =\n typeof remaining === \"number\"\n ? ` ${remaining} attempt${remaining === 1 ? \"\" : \"s\"} remaining.`\n : \"\";\n console.log(`Wrong code.${tail}`);\n continue;\n }\n case \"locked\":\n console.error(\n \"Too many attempts. Request a fresh code by re-running 'olakai init'.\",\n );\n throw new InitAbortedError(\"\", 1);\n case \"expired\":\n console.error(\n \"Code expired. Re-run 'olakai init' to request a new one.\",\n );\n throw new InitAbortedError(\"\", 1);\n case \"no_code\":\n console.error(\n \"No live code for this email. Run 'olakai init' again to request one.\",\n );\n throw new InitAbortedError(\"\", 1);\n case \"rate_limited\": {\n const wait = result.retryAfter\n ? ` Retry in ${result.retryAfter}s.`\n : \"\";\n console.error(`Rate limit hit while verifying.${wait}`);\n throw new InitAbortedError(\"\", 1);\n }\n case \"service_unavailable\":\n console.error(\n \"Olakai is temporarily unavailable. Try again in a minute.\",\n );\n throw new InitAbortedError(\"\", 1);\n case \"network_error\":\n console.error(\n `Network error${result.causeCode ? ` (${result.causeCode})` : \"\"}: ${result.message}`,\n );\n throw new InitAbortedError(\"\", 1);\n default:\n console.error(\n `Verification failed (${result.code}): ${result.message}`,\n );\n throw new InitAbortedError(\"\", 1);\n }\n }\n}\n\nasync function runExchange(\n consentToken: string,\n profileName: string,\n email: string,\n): Promise<void> {\n // One-shot retry on transient network failure. The undici socket\n // drops we saw in production (Xavier session, 2026-05-14) were one\n // failure followed by an immediate success on the same call. Without\n // this retry, that flake aborts the wizard after the user has\n // already typed the OTP.\n //\n // Edge case: if the server actually processed the exchange and the\n // response socket died, the consent JWT is already burned and the\n // retry returns `invalid_consent`. User sees the standard\n // \"Consent token was rejected. Re-run 'olakai init' to start over.\"\n // — same outcome as today's no-retry path on that rare race, so\n // strictly net-positive on every other transient failure mode.\n let result = await postHandshakeExchange({ consentToken });\n if (result.kind === \"error\" && result.code === \"network_error\") {\n console.log(\"(Network error exchanging consent — retrying once...)\");\n result = await postHandshakeExchange({ consentToken });\n }\n if (result.kind === \"error\") {\n switch (result.code) {\n case \"invalid_consent\":\n console.error(\n \"Consent token was rejected. Re-run 'olakai init' to start over.\",\n );\n break;\n case \"user_unavailable\":\n console.error(\n \"Your user record is unavailable on the backend. Contact your admin.\",\n );\n break;\n case \"rate_limited\": {\n const wait = result.retryAfter\n ? ` Retry in ${result.retryAfter}s.`\n : \"\";\n console.error(`Rate limit hit while exchanging consent.${wait}`);\n break;\n }\n case \"service_unavailable\":\n console.error(\n \"Olakai is temporarily unavailable. Try again in a minute.\",\n );\n break;\n case \"network_error\":\n console.error(\n `Network error exchanging consent${result.causeCode ? ` (${result.causeCode})` : \"\"}: ${result.message}`,\n );\n break;\n default:\n console.error(`Exchange failed (${result.code}): ${result.message}`);\n }\n throw new InitAbortedError(\"\", 1);\n }\n\n // Persist into the active profile. `saveToken` writes to the\n // resolved profile (creating it if needed) and respects the active\n // host via `getBaseUrl()`.\n saveToken(result.data.access_token, result.data.expires_in);\n // Cache the email on the profile so subsequent `whoami` calls don't\n // need to round-trip when offline. We don't have user/account IDs\n // until the user hits an authenticated endpoint, but the email\n // alone is enough for friendly re-auth prompts.\n try {\n patchProfile(profileName, { email });\n } catch {\n // Best-effort — failure here doesn't invalidate the login.\n }\n\n console.log(`\\nLogged in as ${email} on ${getBaseUrl()}.`);\n console.log(`Profile: ${profileName}`);\n}\n\n// ---- handshake-level error surfacing --------------------------------------\n\nfunction handleHandshakeError(\n err: Extract<Awaited<ReturnType<typeof postHandshake>>, { kind: \"error\" }>,\n): never {\n switch (err.code) {\n case \"validation_error\":\n console.error(`That email didn't pass validation: ${err.message}`);\n break;\n case \"blocked\":\n console.error(err.message);\n console.error(\n \"Ask your admin to claim your domain, then re-run 'olakai init'.\",\n );\n break;\n case \"rate_limited\": {\n const wait = err.retryAfter ? ` Retry in ${err.retryAfter}s.` : \"\";\n console.error(`Too many attempts.${wait}`);\n break;\n }\n case \"service_unavailable\":\n console.error(\"Olakai is temporarily unavailable. Try again in a minute.\");\n break;\n case \"network_error\":\n console.error(\n `Network error contacting Olakai${err.causeCode ? ` (${err.causeCode})` : \"\"}: ${err.message}`,\n );\n break;\n default:\n console.error(`Handshake failed (${err.code}): ${err.message}`);\n }\n process.exit(1);\n}\n\n// ---- monitor handoff (OLA-214) --------------------------------------------\n\n/**\n * Auto-detect installed local coding agents, prompt per-tool, and chain\n * into the existing `monitor init` plugin install for each tool the\n * user opts into.\n *\n * Design notes:\n *\n * - `--skip-monitor` short-circuits before detection runs. We treat it\n * as an explicit \"don't touch hooks here\", not \"I'll do it later\"\n * — so no docs-pointer line either. The wizard already said\n * everything it needed to say at that point.\n *\n * - Non-interactive mode auto-accepts each detected tool. Rationale:\n * if you went out of your way to run `olakai init --non-interactive`\n * you've opted into the chained setup; failing fast here would\n * defeat the CI use case. Inside each `runMonitorInstall` the\n * plugin still gates on required inputs and fast-fails on missing\n * ones (e.g. unable to mint an API key without a prompt) rather\n * than hanging.\n *\n * - Per-tool failures are isolated. A flake on the agents-API for one\n * tool must not strand the user without monitoring on the others.\n * We catch, surface a retry hint, and continue.\n *\n * - The plugin's own `install()` already handles the \"config already\n * exists in this workspace, replace? [y/N]\" prompt — we don't\n * re-implement it here.\n */\nasync function offerMonitorSetup(\n options: InitCommandOptions,\n interactive: boolean,\n): Promise<void> {\n if (options.skipMonitor) return;\n\n const detected = await detectInstalledTools(process.cwd());\n if (detected.length === 0) {\n console.log(\n \"\\nNo coding agents detected in this workspace.\",\n );\n console.log(\n \"Install Claude Code, Codex, or Cursor and run 'olakai monitor init' to start tracking.\",\n );\n return;\n }\n\n console.log(\n `\\nDetected ${detected.length} coding agent${detected.length === 1 ? \"\" : \"s\"} in this workspace.`,\n );\n\n for (const { tool, reason } of detected) {\n let proceed = true;\n if (interactive) {\n const answer = await promptUser(\n `\\nSet up monitoring for ${tool}? (${reason}) [Y/n]: `,\n );\n const normalized = answer.trim().toLowerCase();\n // Default-yes: empty / 'y' / 'yes' all proceed. Anything else\n // counts as a decline (matches the convention used by the\n // re-auth prompt earlier in the wizard).\n proceed =\n normalized === \"\" || normalized === \"y\" || normalized === \"yes\";\n }\n\n if (!proceed) {\n console.log(\n `Skipped ${tool}. Run 'olakai monitor init --tool ${tool}' later if you change your mind.`,\n );\n continue;\n }\n\n try {\n await runMonitorInstall(tool, { interactive });\n console.log(`${tool} monitoring configured.`);\n } catch (err) {\n // Isolate the failure — don't poison the remaining tools or\n // abort the wizard with a non-zero exit. Re-running just the\n // failed tool is a single command, so we surface it.\n const message = err instanceof Error ? err.message : String(err);\n console.error(`${tool} setup failed: ${message}`);\n console.error(\n `Run 'olakai monitor init --tool ${tool}' to retry.`,\n );\n }\n }\n}\n\n// ---- exit signaling --------------------------------------------------------\n\n/**\n * Internal marker for \"we've already printed a clear user-facing\n * message; just exit with the given code\". Lets nested helpers bail\n * out without each one calling `process.exit()` directly (which would\n * be untestable).\n */\nclass InitAbortedError extends Error {\n exitCode: number;\n constructor(message: string, exitCode = 1) {\n super(message);\n this.name = \"InitAbortedError\";\n this.exitCode = exitCode;\n }\n}\n","/**\n * Typed client for the CLI handshake API (OLA-210).\n *\n * Three unauthenticated endpoints back the `olakai init` wizard:\n *\n * POST /api/cli/handshake → branch the wizard (device-flow,\n * OTP, signup, or blocked)\n * POST /api/cli/handshake/verify → exchange a 6-digit OTP for a\n * short-lived consent token\n * POST /api/cli/handshake/exchange → exchange the consent token for\n * the long-lived CLI bearer\n *\n * The HTTP layer is intentionally thin: no retries, no progress\n * reporting. The wizard owns retry/UX decisions because the right\n * behavior depends heavily on the user-facing branch (e.g. `expired`\n * vs `invalid_code` need very different prompts).\n *\n * Every function returns a discriminated-union result keyed by `kind`:\n *\n * `kind === \"ok\"` — happy path, payload in `data`\n * `kind === \"error\"` — typed failure with backend `code`\n *\n * Backend error contract (mirrors S1 spec):\n *\n * 400 validation_error\n * 400 invalid_code (verify, with `attemptsRemaining`)\n * 401 invalid_consent / user_unavailable (exchange)\n * 403 blocked (handshake)\n * 404 no_code (verify)\n * 410 expired (verify)\n * 429 locked (verify, lockout) / rate_limited\n * 503 service_unavailable\n *\n * Rate-limit responses surface `Retry-After` (seconds) so the wizard\n * can print an informed wait message.\n */\n\nimport { getBaseUrl } from \"./config.js\";\n\n/** Discriminated success/error envelope used by every handshake call. */\nexport type HandshakeResult<TOk, TError = HandshakeErrorCode> =\n | { kind: \"ok\"; data: TOk }\n | {\n kind: \"error\";\n code: TError;\n message: string;\n status: number;\n retryAfter?: number;\n /**\n * For `network_error`s: the underlying undici / Node error code\n * (e.g. `UND_ERR_CONNECT`, `ECONNRESET`). `Error.cause` carries\n * this on `fetch()` failures; we surface it here so the UI can\n * print something more actionable than the bare `\"fetch failed\"`\n * string. Unset for non-network errors and for network errors\n * with no exposed cause code.\n */\n causeCode?: string;\n };\n\nexport type HandshakeErrorCode =\n | \"validation_error\"\n | \"invalid_code\"\n | \"invalid_consent\"\n | \"user_unavailable\"\n | \"blocked\"\n | \"no_code\"\n | \"expired\"\n | \"locked\"\n | \"rate_limited\"\n | \"service_unavailable\"\n | \"network_error\"\n | \"unknown_error\";\n\n// ---- POST /api/cli/handshake -----------------------------------------------\n\n/**\n * The branch the backend tells us to follow. Each variant is a tagged\n * object so callers can `switch (resp.data.status)`.\n */\nexport type HandshakeResponse =\n | { status: \"user_exists\"; deviceFlowOk: true }\n | {\n status: \"user_exists\";\n otpSent: true;\n emailObfuscated: string;\n codeExpiresAt: string;\n expiresIn: number;\n }\n | {\n status: \"domain_claimed\";\n accountId: string;\n userId: string;\n matchType: \"exact\" | \"suffix\";\n emailObfuscated: string;\n codeExpiresAt: string;\n expiresIn: number;\n }\n | { status: \"saas_can_self_signup\"; signupUrl: string }\n | { status: \"blocked\"; message: string };\n\nexport interface HandshakeRequest {\n email: string;\n /** Optional explicit host hint (the backend may key per-host policy off this). */\n host?: string;\n}\n\n/**\n * POST /api/cli/handshake. Returns one of the five branches above, or a\n * typed error envelope. Network/parse failures map to `network_error`.\n */\nexport async function postHandshake(\n body: HandshakeRequest,\n): Promise<HandshakeResult<HandshakeResponse, HandshakeErrorCode>> {\n return postHandshakeJson<HandshakeResponse>(\n `${getBaseUrl()}/api/cli/handshake`,\n body,\n );\n}\n\n// ---- POST /api/cli/handshake/verify ---------------------------------------\n\nexport interface VerifyRequest {\n email: string;\n code: string;\n}\n\nexport interface VerifySuccess {\n consentToken: string;\n expiresIn: number;\n}\n\n/**\n * Extra context for the `invalid_code` branch. Backend includes\n * `attemptsRemaining` so we can print \"N attempts remaining\" before\n * the next prompt.\n */\nexport interface VerifyErrorDetail {\n attemptsRemaining?: number;\n}\n\nexport type VerifyResult = HandshakeResult<VerifySuccess, HandshakeErrorCode> & {\n detail?: VerifyErrorDetail;\n};\n\nexport async function postHandshakeVerify(\n body: VerifyRequest,\n): Promise<VerifyResult> {\n const url = `${getBaseUrl()}/api/cli/handshake/verify`;\n const result = await postHandshakeJson<VerifySuccess>(url, body, {\n captureDetail: true,\n });\n return result as VerifyResult;\n}\n\n// ---- POST /api/cli/handshake/exchange -------------------------------------\n\nexport interface ExchangeRequest {\n consentToken: string;\n}\n\n/** Same shape as device-flow's `/api/auth/device/token` response. */\nexport interface ExchangeSuccess {\n access_token: string;\n token_type: \"Bearer\";\n expires_in: number;\n}\n\nexport async function postHandshakeExchange(\n body: ExchangeRequest,\n): Promise<HandshakeResult<ExchangeSuccess, HandshakeErrorCode>> {\n return postHandshakeJson<ExchangeSuccess>(\n `${getBaseUrl()}/api/cli/handshake/exchange`,\n body,\n );\n}\n\n// ---- shared transport ------------------------------------------------------\n\ninterface PostOptions {\n /**\n * When true, attempts to surface response-body fields (esp.\n * `attemptsRemaining` on `invalid_code`) on the returned envelope's\n * `detail` field. Other endpoints don't need it.\n */\n captureDetail?: boolean;\n}\n\ninterface ErrorBody {\n error?: string;\n code?: string;\n message?: string;\n attemptsRemaining?: number;\n}\n\n/**\n * Shared transport for the three handshake endpoints. Centralized so\n * Retry-After parsing, JSON-error decoding, and the network-error\n * fallback live in one place.\n */\nasync function postHandshakeJson<TOk>(\n url: string,\n body: unknown,\n options: PostOptions = {},\n): Promise<HandshakeResult<TOk, HandshakeErrorCode> & { detail?: VerifyErrorDetail }> {\n let response: Response;\n try {\n response = await fetch(url, {\n method: \"POST\",\n headers: { \"Content-Type\": \"application/json\" },\n body: JSON.stringify(body),\n });\n } catch (err) {\n return buildNetworkError(err);\n }\n\n if (response.ok) {\n let data: TOk;\n try {\n data = (await response.json()) as TOk;\n } catch (err) {\n return {\n kind: \"error\",\n code: \"unknown_error\",\n message: err instanceof Error ? err.message : \"Failed to parse response\",\n status: response.status,\n };\n }\n return { kind: \"ok\", data };\n }\n\n // Best-effort error body decode — backend may return a JSON envelope\n // or (rarely) a plain string. Anything unparseable degrades to a\n // generic unknown_error with the HTTP status preserved.\n let errBody: ErrorBody = {};\n try {\n errBody = (await response.json()) as ErrorBody;\n } catch {\n // ignore\n }\n\n const code = mapErrorCode(response.status, errBody);\n // Fallback message includes the request pathname so an unannotated\n // 5xx tells the user *what* failed, not just the status code.\n // Hostname is intentionally omitted — it varies by environment and\n // contributes nothing to the user's understanding of the error.\n let fallbackPath = \"\";\n try {\n fallbackPath = new URL(url).pathname;\n } catch {\n // Malformed URL — use the raw url string as a last resort.\n fallbackPath = url;\n }\n const message =\n errBody.message ||\n errBody.error ||\n `Request to ${fallbackPath} failed with status ${response.status}`;\n const retryAfter = parseRetryAfter(response.headers.get(\"retry-after\"));\n\n const envelope: HandshakeResult<TOk, HandshakeErrorCode> & {\n detail?: VerifyErrorDetail;\n } = {\n kind: \"error\",\n code,\n message,\n status: response.status,\n ...(retryAfter !== undefined ? { retryAfter } : {}),\n };\n\n if (options.captureDetail && typeof errBody.attemptsRemaining === \"number\") {\n envelope.detail = { attemptsRemaining: errBody.attemptsRemaining };\n }\n\n return envelope;\n}\n\n/**\n * Map an HTTP status + parsed error body to a canonical\n * `HandshakeErrorCode`. The backend's `code` field wins when present;\n * otherwise we fall back to the status code semantics from the S1\n * spec.\n */\nfunction mapErrorCode(status: number, body: ErrorBody): HandshakeErrorCode {\n const known: HandshakeErrorCode[] = [\n \"validation_error\",\n \"invalid_code\",\n \"invalid_consent\",\n \"user_unavailable\",\n \"blocked\",\n \"no_code\",\n \"expired\",\n \"locked\",\n \"rate_limited\",\n \"service_unavailable\",\n ];\n // Defensive: only trust the backend's `code` / `error` fields when\n // they're actually strings. A malformed server returning numeric or\n // object payloads must not slip past the `includes()` guard.\n if (typeof body.code === \"string\" && (known as string[]).includes(body.code)) {\n return body.code as HandshakeErrorCode;\n }\n if (typeof body.error === \"string\" && (known as string[]).includes(body.error)) {\n return body.error as HandshakeErrorCode;\n }\n switch (status) {\n case 400:\n return \"validation_error\";\n case 401:\n return \"invalid_consent\";\n case 403:\n return \"blocked\";\n case 404:\n return \"no_code\";\n case 410:\n return \"expired\";\n case 429:\n return \"rate_limited\";\n case 503:\n return \"service_unavailable\";\n default:\n return \"unknown_error\";\n }\n}\n\n/**\n * Build a `network_error` envelope from a `fetch()` rejection, surfacing\n * the undici `err.cause.code` (e.g. `UND_ERR_CONNECT`, `ECONNRESET`)\n * when present. The bare `err.message` from undici is the unhelpful\n * `\"fetch failed\"`; the cause carries the actionable signal. We pull\n * `cause.code` onto the envelope's `causeCode` and append `cause.message`\n * onto the human message so both the structured field and the rendered\n * string carry the diagnostic.\n *\n * `Error.cause` is `unknown` per TS lib types; we treat it defensively\n * as a possibly-object value with optional string `code` / `message`.\n */\nfunction buildNetworkError(\n err: unknown,\n): { kind: \"error\"; code: \"network_error\"; message: string; status: 0; causeCode?: string } {\n const base =\n err instanceof Error ? err.message : \"Network request failed\";\n let causeCode: string | undefined;\n let causeMessage: string | undefined;\n if (err instanceof Error && err.cause && typeof err.cause === \"object\") {\n const c = err.cause as { code?: unknown; message?: unknown };\n if (typeof c.code === \"string\" && c.code.length > 0) {\n causeCode = c.code;\n }\n if (typeof c.message === \"string\" && c.message.length > 0) {\n causeMessage = c.message;\n }\n }\n // Compose the message: keep \"fetch failed\" prefix (some downstream\n // tooling matches against it), append cause-message when different.\n const message =\n causeMessage && causeMessage !== base ? `${base}: ${causeMessage}` : base;\n return {\n kind: \"error\",\n code: \"network_error\",\n message,\n status: 0,\n ...(causeCode ? { causeCode } : {}),\n };\n}\n\nfunction parseRetryAfter(header: string | null): number | undefined {\n if (!header) return undefined;\n const asNumber = Number(header);\n if (Number.isFinite(asNumber) && asNumber > 0) {\n return Math.floor(asNumber);\n }\n // Retry-After can also be an HTTP date — convert to seconds-from-now.\n const asDate = Date.parse(header);\n if (Number.isFinite(asDate)) {\n const seconds = Math.floor((asDate - Date.now()) / 1000);\n return seconds > 0 ? seconds : undefined;\n }\n return undefined;\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 * Multi-tool detection for chained `olakai init` → `olakai monitor init`\n * (OLA-214).\n *\n * Walks the registered monitor plugins (see `plugins/index.ts`) and\n * reports which of them appear installed in the current workspace.\n * Each entry carries a short human-readable `reason` we surface in the\n * per-tool consent prompt — the wizard's UX promise was\n *\n * \"Detected Claude Code in this workspace. Set up monitoring? [Y/n]\"\n *\n * The reason string is what makes that line specific (e.g.\n * \"found `.claude/settings.json`\") rather than a generic \"detected\".\n *\n * Implementation note: we don't reimplement each plugin's `detectInstalled`\n * here — that would diverge over time. Instead we call the plugin's\n * boolean probe and then, when it returns true, do a cheap follow-up\n * stat on a small set of well-known signal paths to pick the most\n * informative reason. If none match, we fall back to a generic phrase\n * so the prompt is always at least readable.\n */\nimport * as fs from \"node:fs\";\nimport * as path from \"node:path\";\nimport {\n getLegacyClaudeMonitorConfigPath,\n getMonitorConfigPath,\n} from \"./paths.js\";\nimport {\n getCodexConfigPath as getCodexHomeConfigPath,\n getCodexHomeDir,\n} from \"./plugins/codex/paths.js\";\n// Side-effect import: ensures plugins are registered when the init\n// wizard pulls this module in without going through monitor.ts.\nimport \"./plugins/index.js\";\nimport {\n listPlugins,\n type ToolId,\n type ToolMonitorPlugin,\n} from \"./plugin.js\";\n\nexport interface DetectedTool {\n tool: ToolId;\n /**\n * Short human-readable phrase identifying what signal triggered the\n * match. Designed to be inlined into a prompt: e.g.\n * `\"detected (found .claude/settings.json)\"`.\n */\n reason: string;\n}\n\n/**\n * Returns the detected tools, in the order plugins were registered. We\n * preserve order so the consent prompts are deterministic across runs\n * (and across `process.cwd()` shifts in tests).\n */\nexport async function detectInstalledTools(\n projectRoot: string = process.cwd(),\n): Promise<DetectedTool[]> {\n const detected: DetectedTool[] = [];\n for (const plugin of listPlugins()) {\n let installed = false;\n try {\n installed = await plugin.detectInstalled({ projectRoot });\n } catch {\n // detectInstalled is best-effort. A throwing probe should never\n // poison the wizard — treat it as \"not detected\".\n installed = false;\n }\n if (!installed) continue;\n detected.push({\n tool: plugin.id,\n reason: describeDetection(plugin, projectRoot),\n });\n }\n return detected;\n}\n\nfunction describeDetection(\n plugin: ToolMonitorPlugin,\n projectRoot: string,\n): string {\n // Prefer the most specific signal: an existing workspace-local\n // monitor config means the user already ran `olakai monitor init`\n // for this tool in this workspace at some point. Mention that so\n // they understand a re-run will trigger the plugin's own\n // \"replace?\" prompt rather than a fresh install.\n try {\n if (fs.existsSync(getMonitorConfigPath(projectRoot, plugin.id))) {\n return `existing config at .olakai/monitor-${plugin.id}.json`;\n }\n } catch {\n // fall through\n }\n\n switch (plugin.id) {\n case \"claude-code\": {\n try {\n if (fs.existsSync(getLegacyClaudeMonitorConfigPath(projectRoot))) {\n return \"legacy config at .claude/olakai-monitor.json\";\n }\n } catch {\n // fall through\n }\n try {\n const settings = path.join(projectRoot, \".claude\", \"settings.json\");\n if (fs.existsSync(settings)) {\n return \"found .claude/settings.json\";\n }\n } catch {\n // fall through\n }\n return \"Claude Code detected\";\n }\n case \"codex\": {\n try {\n if (fs.existsSync(getCodexHomeConfigPath())) {\n return \"found ~/.codex/config.toml\";\n }\n if (fs.existsSync(getCodexHomeDir())) {\n return \"found ~/.codex/\";\n }\n } catch {\n // fall through\n }\n return \"Codex CLI on PATH\";\n }\n case \"cursor\": {\n return \"Cursor installed for this user\";\n }\n default: {\n // Compile-time exhaustiveness check: when a 4th tool gets added\n // to `ToolId` (see CLAUDE.md \"Adding a New Local Coding Agent\n // Tool\" guide), this assertion fires at type-check time so the\n // missing case is impossible to miss. Until then, we keep a\n // graceful runtime fallback so a future tool doesn't ship with\n // `Set up monitoring for newtool? (undefined)` in the prompt.\n const _exhaustive: never = plugin.id;\n void _exhaustive;\n return `${plugin.displayName} detected`;\n }\n }\n}\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","import * 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 {\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 // Two independent signals — either is enough to surface\n // \"claude-code\" in the interactive `init` selector:\n // 1. The user already ran `olakai monitor init --tool claude-code`\n // here (workspace-local monitor config exists, new or legacy\n // path), OR\n // 2. The Claude Code CLI itself is installed on this host\n // (`claude` binary on PATH).\n //\n // We deliberately do NOT check for `~/.claude/` directory presence:\n // that directory is shared with Claude Desktop, so it would\n // false-positive for users who run the desktop app but never the\n // CLI. The `claude` binary on PATH is the precise signal for the\n // Claude Code CLI.\n //\n // Matches the structure of `codex.detectInstalled` so the three\n // plugins behave consistently for first-run users (Xavier session,\n // 2026-05-14 — first-run users were seeing \"No coding agents\n // detected\" even when Claude Code was installed because this\n // function only checked for an Olakai marker file).\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 } catch {\n // Fall through to the binary probe.\n }\n return detectClaudeBinaryOnPath();\n },\n};\n\n/**\n * Synchronous `which claude` / `where claude` probe. Cheap (<10ms in\n * practice) and any failure is treated as \"not installed\". Modeled on\n * `detectCodexBinaryOnPath` in `../codex/index.ts`.\n */\nfunction detectClaudeBinaryOnPath(): boolean {\n try {\n const probe = spawnSync(\n process.platform === \"win32\" ? \"where\" : \"which\",\n [\"claude\"],\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(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 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 * 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","/**\n * Programmatic entry point for \"run `olakai monitor init --tool X` for\n * me, but from inside another command\" (OLA-214 — chained `olakai init`\n * → `olakai monitor init`).\n *\n * `monitor.ts` already wires the user-facing Commander surface; this\n * module exposes the same install path so `init.ts` can drive it\n * without going through argv parsing. We deliberately do NOT re-export\n * `monitor init`'s `--tool` resolution / prompt — the wizard caller has\n * already decided which tool to install (via auto-detection +\n * per-tool consent), so we skip straight to `plugin.install(...)`.\n *\n * Errors from `plugin.install` bubble up so the caller (the wizard)\n * can decide whether to abort the whole chain or just skip this tool\n * and continue with the next one. The wizard chooses the latter — one\n * tool's API failure shouldn't strand the user without monitoring on\n * the other detected tools.\n */\nimport \"./plugins/index.js\";\nimport {\n getPlugin,\n type InstallResult,\n type ToolId,\n} from \"./plugin.js\";\n\nexport interface RunMonitorInstallOpts {\n /** Defaults to `process.cwd()`. Threaded through to the plugin. */\n projectRoot?: string;\n /**\n * `true` when the wizard knows the terminal is interactive AND the\n * user did not pass `--non-interactive`. Plugins decide what this\n * means — most still prompt for required inputs even when\n * `interactive` is false, because they have no other way to obtain\n * (e.g.) a pasted API key. That's fine: non-interactive callers must\n * supply the inputs the plugins need ahead of time, and a missing\n * input becomes a fast-fail rather than a hang.\n */\n interactive?: boolean;\n}\n\nexport async function runMonitorInstall(\n toolId: ToolId,\n opts: RunMonitorInstallOpts = {},\n): Promise<InstallResult> {\n const plugin = getPlugin(toolId);\n return plugin.install({\n projectRoot: opts.projectRoot ?? process.cwd(),\n interactive: opts.interactive ?? true,\n });\n}\n","/**\n * Terminal branding for the `olakai init` wizard (OLA-226).\n *\n * `olakai init` is the first thing an admin evaluating Olakai sees from\n * the CLI — Xavier's product-feedback session flagged the current\n * messaging as too curt for that role. This module owns the visual\n * shell (logo header, colors) and the role-aware copy for the admin /\n * analyst handoff to the browser device-flow.\n *\n * Color strategy: raw ANSI escapes, no new dependency. Cyan-tinted\n * `◉` mark matches the Olakai logo's teal/cyan palette. We respect\n * `NO_COLOR` (https://no-color.org/) and only emit color sequences\n * when stdout is a TTY — pipelines and CI logs stay clean.\n */\n\nconst RESET = \"\\x1b[0m\";\nconst CYAN = \"\\x1b[36m\";\nconst DIM = \"\\x1b[2m\";\n\nfunction colorize(text: string, color: string): string {\n if (process.env.NO_COLOR) return text;\n if (!process.stdout.isTTY) return text;\n return `${color}${text}${RESET}`;\n}\n\n/**\n * Prints the wizard's logo header. Call once at the very top of the\n * interactive `olakai init` flow — it sets the visual tone for the\n * entire session.\n *\n * Skipped automatically when stdout is not a TTY (CI, piped output)\n * so logs / `--non-interactive` runs stay machine-parseable.\n */\nexport function printLogoHeader(): void {\n if (!process.stdout.isTTY) return;\n const mark = colorize(\"◉\", CYAN);\n const tagline = colorize(\"Enterprise AI observability\", DIM);\n console.log(\"\");\n console.log(` ${mark} olakai`);\n console.log(` ${tagline}`);\n console.log(` ──────────────────────────────`);\n console.log(\"\");\n}\n\n/**\n * Multi-line greeting shown to existing-account users (ADMIN /\n * ANALYST / USER) on the `user_exists + deviceFlowOk` branch BEFORE\n * the browser opens for device-flow auth.\n *\n * Two goals:\n * 1. Acknowledge that we identified the user by name/email — Xavier\n * flagged the current \"Welcome back! Opening browser...\" as\n * feeling impersonal for someone evaluating the product.\n * 2. Explain WHY the browser step applies here AND clarify it does\n * NOT apply to Employee-role developers (who get the OTP flow).\n * The distinction is the heart of the feedback: admins shouldn't\n * conclude \"this is friction for my whole team\" from their own\n * elevated-privileges flow.\n *\n * Personalization is email-only by design. The handshake `user_exists\n * + deviceFlowOk` response is deliberately bounded to a tiny\n * email-enumeration oracle (status + boolean) — adding name/role/\n * accountName here would enlarge the oracle on an unauthenticated\n * endpoint. The richer per-user display (name, role, account) comes\n * AFTER browser auth, where `loginCommand` already prints them.\n */\nexport function formatExistingUserBrowserGreeting(email: string): string {\n return [\n ` ✓ Found your Olakai account — ${email}`,\n ``,\n ` Since you have login access to an Olakai workspace, we'll route`,\n ` you through your account's standard sign-in. Admin and analyst`,\n ` users authenticate the CLI through the browser, matching how`,\n ` they sign in to the web app.`,\n ``,\n ` Employee-role developers skip this step and self-onboard with`,\n ` a one-time email code — no browser, no SSO prompt.`,\n ].join(\"\\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\";\nimport { runMonitorInstall } from \"../monitor/install.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 // Delegate to `runMonitorInstall` so this command and the chained\n // `olakai init` path go through exactly one install code path. Any\n // future cross-cutting addition (telemetry, validation, logging)\n // only needs to touch `src/monitor/install.ts`.\n await runPluginAction(plugin, () => runMonitorInstall(toolId, { interactive: true }));\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","/**\n * `olakai profiles ...` — AWS-style profile management.\n *\n * Subcommands:\n * - list Print all profiles, mark the active one\n * - use Set the registry default\n * - remove Delete a profile (refuses to remove the active default)\n * - current Show the resolved active profile\n */\n\nimport { Command } from \"commander\";\nimport { getBaseUrl } from \"../lib/config.js\";\nimport {\n readProfilesFile,\n removeProfile,\n resolveActiveProfile,\n resolveProfileName,\n setDefaultProfile,\n} from \"../lib/profiles.js\";\n\nfunction formatExpiry(expiresAt: number | undefined): string {\n if (typeof expiresAt !== \"number\") return \"no token\";\n const now = Math.floor(Date.now() / 1000);\n if (expiresAt <= now) return \"expired\";\n const seconds = expiresAt - now;\n const days = Math.floor(seconds / 86400);\n const hours = Math.floor((seconds % 86400) / 3600);\n if (days > 0) return `${days}d ${hours}h`;\n const minutes = Math.floor((seconds % 3600) / 60);\n if (hours > 0) return `${hours}h ${minutes}m`;\n return `${minutes}m`;\n}\n\nfunction maskToken(token: string | undefined): string {\n if (!token) return \"—\";\n if (token.length <= 8) return \"***\";\n return `${token.slice(0, 4)}…${token.slice(-4)}`;\n}\n\nfunction listAction(options: { json?: boolean }): void {\n const file = readProfilesFile();\n let resolved: { name: string } | null = null;\n try {\n resolved = resolveProfileName();\n } catch {\n resolved = null;\n }\n const activeName = resolved?.name ?? file.default;\n\n if (options.json) {\n console.log(\n JSON.stringify(\n {\n default: file.default ?? null,\n active: activeName ?? null,\n profiles: Object.entries(file.profiles).map(([name, p]) => ({\n name,\n host: p.host,\n isDefault: file.default === name,\n isActive: activeName === name,\n email: p.email ?? null,\n accountId: p.accountId ?? null,\n expiresIn: p.expiresAt\n ? Math.max(0, p.expiresAt - Math.floor(Date.now() / 1000))\n : null,\n hasToken: Boolean(p.token),\n })),\n },\n null,\n 2,\n ),\n );\n return;\n }\n\n const names = Object.keys(file.profiles);\n if (names.length === 0) {\n console.log(\"No profiles configured. Run 'olakai login' to create one.\");\n return;\n }\n\n for (const name of names) {\n const p = file.profiles[name];\n if (!p) continue;\n const markers: string[] = [];\n if (file.default === name) markers.push(\"default\");\n if (activeName === name) markers.push(\"active\");\n const label = markers.length > 0 ? ` (${markers.join(\", \")})` : \"\";\n const expiry = formatExpiry(p.expiresAt);\n const email = p.email ? ` — ${p.email}` : \"\";\n console.log(`* ${name}${label}`);\n console.log(` host: ${p.host}`);\n console.log(` token: ${maskToken(p.token)} (${expiry})${email}`);\n }\n}\n\nfunction useAction(name: string): void {\n try {\n setDefaultProfile(name);\n console.log(`Default profile is now: ${name}`);\n } catch (err) {\n console.error(err instanceof Error ? err.message : String(err));\n process.exit(1);\n }\n}\n\nfunction removeAction(name: string): void {\n try {\n removeProfile(name);\n console.log(`Removed profile: ${name}`);\n } catch (err) {\n console.error(err instanceof Error ? err.message : String(err));\n process.exit(1);\n }\n}\n\nfunction currentAction(options: { json?: boolean }): void {\n let active;\n try {\n active = resolveActiveProfile();\n } catch (err) {\n console.error(err instanceof Error ? err.message : String(err));\n process.exit(1);\n }\n if (!active) {\n if (options.json) {\n console.log(JSON.stringify({ active: null }, null, 2));\n } else {\n console.log(\"No profile configured. Run 'olakai login' to create one.\");\n }\n return;\n }\n\n // The \"effective\" host is what `getBaseUrl()` actually returns\n // (factoring in --host / OLAKAI_HOST overrides). The profile's\n // stored host is shown separately so the user can see when an\n // override is in effect.\n const effectiveHost = getBaseUrl();\n const overridden = effectiveHost !== active.host;\n\n if (options.json) {\n console.log(\n JSON.stringify(\n {\n name: active.name,\n host: effectiveHost,\n profileHost: active.host,\n source: active.source,\n hostFromWorkspaceConfig: active.hostFromWorkspaceConfig,\n hostOverridden: overridden,\n email: active.profile.email ?? null,\n accountId: active.profile.accountId ?? null,\n hasToken: Boolean(active.profile.token),\n expiresAt: active.profile.expiresAt ?? null,\n expiresIn: active.profile.expiresAt\n ? Math.max(\n 0,\n active.profile.expiresAt - Math.floor(Date.now() / 1000),\n )\n : null,\n },\n null,\n 2,\n ),\n );\n return;\n }\n\n console.log(`Profile: ${active.name} (from ${active.source})`);\n if (overridden) {\n console.log(`Host: ${effectiveHost} (overrides profile host)`);\n console.log(`Profile host: ${active.host}`);\n } else if (active.hostFromWorkspaceConfig) {\n console.log(`Host: ${active.host} (from workspace config)`);\n } else {\n console.log(`Host: ${active.host}`);\n }\n if (active.profile.email) {\n console.log(`Email: ${active.profile.email}`);\n }\n if (active.profile.accountId) {\n console.log(`Account ID: ${active.profile.accountId}`);\n }\n console.log(`Token: ${maskToken(active.profile.token)}`);\n console.log(`Expires in: ${formatExpiry(active.profile.expiresAt)}`);\n}\n\nexport function registerProfilesCommand(program: Command): void {\n const profiles = program\n .command(\"profiles\")\n .description(\"Manage Olakai authentication profiles (AWS-style)\");\n\n profiles\n .command(\"list\")\n .description(\"List all configured profiles\")\n .option(\"--json\", \"Output as JSON\")\n .action((options: { json?: boolean }) => {\n listAction(options);\n });\n\n profiles\n .command(\"use <name>\")\n .description(\"Set <name> as the default profile\")\n .action((name: string) => {\n useAction(name);\n });\n\n profiles\n .command(\"remove <name>\")\n .description(\"Remove a profile (refuses to remove the active default)\")\n .action((name: string) => {\n removeAction(name);\n });\n\n profiles\n .command(\"current\")\n .description(\"Print the active profile (resolved from flag/env/workspace/default)\")\n .option(\"--json\", \"Output as JSON\")\n .action((options: { json?: boolean }) => {\n currentAction(options);\n });\n}\n"],"mappings":"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","names":["open","asNumber","fs","path","fs","os","path","fs","path","fs","debugLog","fs","spawnSync","fs","path","OLAKAI_HOOK_MARKER","fs","path","getCodexConfigPath","createNewAgent","getCodexConfigPath","path","fs","getCodexConfigPath","fs","path","noopDebug","debugLog","noopDebug","debugLog","TOOL_ID","debugLog","getCodexConfigPath","spawnSync","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","open","program","listCommand","getCommand","createCommand","updateCommand","deleteCommand","program","listCommand","getCommand","createCommand","updateCommand","deleteCommand","program","listCommand","getCommand","createCommand","updateCommand","deleteCommand","program","listCommand","getCommand","program","fs","initCommand","report","log","program","formatExpiry","program","require"]}
|
|
1
|
+
{"version":3,"sources":["../src/index.ts","../src/commands/login.ts","../src/commands/logout.ts","../src/commands/whoami.ts","../src/commands/init.ts","../src/lib/handshake.ts","../src/monitor/prompt.ts","../src/monitor/detect-all.ts","../src/monitor/plugins/codex/paths.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/self-monitor-provision.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/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","../src/monitor/install.ts","../src/lib/branding.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/profiles.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 { initCommand, type InitCommandOptions } from \"./commands/init.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 { registerProfilesCommand } from \"./commands/profiles.js\";\nimport {\n setEnvironment,\n setHostOverride,\n isValidEnvironment,\n getValidEnvironments,\n type Environment,\n} from \"./lib/config.js\";\nimport { setProfileOverride } from \"./lib/profiles.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 .option(\n \"--host <host>\",\n \"On-prem Olakai host (e.g. olakai.acme.com). Overrides --env and OLAKAI_HOST.\",\n )\n .option(\n \"--profile <name>\",\n \"Olakai profile to use (overrides OLAKAI_PROFILE, workspace config, and registry default).\",\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 if (typeof options.host === \"string\" && options.host.length > 0) {\n setHostOverride(options.host);\n }\n if (typeof options.profile === \"string\" && options.profile.length > 0) {\n setProfileOverride(options.profile);\n }\n });\n\nprogram\n .command(\"init\")\n .description(\n \"Interactive self-onboarding wizard: pick host, verify email, get a CLI token.\",\n )\n .option(\"--email <email>\", \"Pre-fill the email (skips the email prompt)\")\n .option(\n \"--non-interactive\",\n \"Fail fast on any missing required input (no prompts).\",\n )\n .option(\n \"--skip-monitor\",\n \"Skip the optional 'olakai monitor init' handoff at the end.\",\n )\n .action((options: InitCommandOptions) => initCommand(options));\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\n// Register subcommands for AWS-style profile management\nregisterProfilesCommand(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 { getBaseUrl, getEnvironment } from \"../lib/config.js\";\nimport { patchProfile, resolveProfileName } from \"../lib/profiles.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 const resolved = resolveProfileName();\n const profileName = resolved?.name ?? \"default\";\n console.log(\n `Logging in to Olakai (profile: ${profileName}, host: ${getBaseUrl()}, env: ${getEnvironment()})...\\n`,\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 (lands in the active profile, or \"default\" if\n // no profile was explicitly selected).\n saveToken(tokenResponse.access_token, tokenResponse.expires_in);\n\n // Get user info and cache identifiers on the profile so\n // offline `whoami` still has something to show.\n const user = await getCurrentUser();\n try {\n patchProfile(profileName, {\n email: user.email,\n userId: user.id,\n accountId: user.accountId,\n });\n } catch {\n // best-effort\n }\n\n console.log(`\\nLogged in as ${user.email}`);\n console.log(`Profile: ${profileName}`);\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 { 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, loadToken } from \"../lib/auth.js\";\nimport { getBaseUrl, getEnvironment } from \"../lib/config.js\";\nimport { patchProfile, resolveActiveProfile } from \"../lib/profiles.js\";\n\nfunction formatExpiry(expiresAt: number | undefined): string {\n if (typeof expiresAt !== \"number\") return \"no token\";\n const now = Math.floor(Date.now() / 1000);\n if (expiresAt <= now) return \"expired\";\n const seconds = expiresAt - now;\n const days = Math.floor(seconds / 86400);\n const hours = Math.floor((seconds % 86400) / 3600);\n if (days > 0) return `${days}d ${hours}h`;\n const minutes = Math.floor((seconds % 3600) / 60);\n if (hours > 0) return `${hours}h ${minutes}m`;\n return `${minutes}m`;\n}\n\n/**\n * Whoami command handler.\n *\n * Prints the active profile, host, user identity (email + name +\n * account), and token expiry. Falls back gracefully when individual\n * fields aren't available (e.g. unauthenticated, or the backend is\n * unreachable but a profile is configured locally).\n */\nexport async function whoamiCommand(): Promise<void> {\n let active;\n try {\n active = resolveActiveProfile();\n } catch (err) {\n console.error(err instanceof Error ? err.message : String(err));\n process.exit(1);\n }\n\n // Always print the resolved local view first — works even when\n // unauthenticated.\n if (active) {\n const effectiveHost = getBaseUrl();\n console.log(`Profile: ${active.name} (from ${active.source})`);\n if (effectiveHost !== active.host) {\n console.log(`Host: ${effectiveHost} (overrides profile host)`);\n console.log(`Profile host: ${active.host}`);\n } else if (active.hostFromWorkspaceConfig) {\n console.log(`Host: ${active.host} (from workspace config)`);\n } else {\n console.log(`Host: ${active.host}`);\n }\n } else {\n // \"Not logged in\" is an error state — write to stderr so scripts\n // that pipe `whoami` to grep / jq don't catch this in their stdout.\n console.error(`Profile: (none)`);\n console.error(`Host: ${getBaseUrl()}`);\n console.error(`Environment: ${getEnvironment()}`);\n console.error(\"Not logged in. Run 'olakai login' to authenticate.\");\n process.exit(1);\n }\n\n if (!isTokenValid()) {\n const creds = loadToken();\n console.log(`Token: ${creds ? \"expired\" : \"missing\"}`);\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 // Backfill cached identifiers so subsequent `profiles list` /\n // `whoami` (and future offline commands) can display them without\n // a network round-trip. Best-effort: any failure is swallowed.\n try {\n patchProfile(active.name, {\n email: user.email,\n userId: user.id,\n accountId: user.accountId,\n });\n } catch {\n // ignore\n }\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(\n `Token: valid (expires in ${formatExpiry(active.profile.expiresAt)})`,\n );\n } catch (error) {\n // Fall back to cached identifiers when the backend is unreachable\n // but we still have a valid local token.\n if (active.profile.email) {\n console.log(`Email: ${active.profile.email} (cached)`);\n }\n if (active.profile.accountId) {\n console.log(`Account ID: ${active.profile.accountId} (cached)`);\n }\n console.log(\n `Token: valid (expires in ${formatExpiry(active.profile.expiresAt)})`,\n );\n if (error instanceof Error) {\n console.error(`Warning: could not contact Olakai backend: ${error.message}`);\n } else {\n console.error(\"Warning: could not contact Olakai backend\");\n }\n }\n}\n","/**\n * `olakai init` — the self-onboarding wizard (OLA-212).\n *\n * Flow at a glance:\n *\n * 1. Resolve the target profile name. If it already holds a valid\n * token, offer an early exit (\"already authenticated\").\n * 2. Pick a host: `--host`/env > existing profile host > interactive\n * menu (production / staging / on-prem custom).\n * 3. Collect the user's email.\n * 4. POST /api/cli/handshake. Branch on the response:\n * - device-flow → hand off to the existing `loginCommand`\n * (same device-flow used by `olakai login`; we DO NOT\n * duplicate that flow here).\n * - OTP → enter the OTP loop (verify → exchange).\n * - signup → open browser + ask user to re-run.\n * - blocked → fail with a clear admin-action message.\n * 5. On OTP success: exchange the consent token for the 30-day\n * bearer, persist it to the active profile via `saveToken`.\n * 6. Offer monitor setup. Actually chaining into `olakai monitor`\n * is owned by S5 (OLA-214); for now we just print the one-liner.\n *\n * Non-interactive mode (`--non-interactive`) fails fast on any prompt\n * the user could have answered via flag/env. That makes the wizard\n * safe to call from automation (e.g. CI bootstrapping a profile from\n * a service account email).\n */\n\nimport open from \"open\";\nimport {\n postHandshake,\n postHandshakeExchange,\n postHandshakeVerify,\n} from \"../lib/handshake.js\";\nimport { loginCommand } from \"./login.js\";\nimport { saveToken, isTokenValid } from \"../lib/auth.js\";\nimport { getBaseUrl, setHostOverride } from \"../lib/config.js\";\nimport {\n HOSTS,\n patchProfile,\n readProfilesFile,\n resolveProfileName,\n} from \"../lib/profiles.js\";\nimport { promptUser, isInteractive } from \"../monitor/prompt.js\";\nimport { detectInstalledTools } from \"../monitor/detect-all.js\";\nimport { runMonitorInstall } from \"../monitor/install.js\";\nimport {\n formatExistingUserBrowserGreeting,\n printLogoHeader,\n} from \"../lib/branding.js\";\n\nexport interface InitCommandOptions {\n email?: string;\n host?: string;\n /** Identical to the global `--profile` flag; commander passes it through. */\n profile?: string;\n nonInteractive?: boolean;\n skipMonitor?: boolean;\n}\n\n/**\n * The most permissive RFC-5322-ish email check the CLI is comfortable\n * shipping. Backend does the real validation; this is just enough to\n * stop obviously-broken input from costing the user a network round\n * trip.\n */\nconst EMAIL_REGEX = /^[^\\s@]+@[^\\s@]+\\.[^\\s@]+$/;\nconst OTP_REGEX = /^\\d{6}$/;\nconst PRESET_HOSTS: ReadonlyArray<{ label: string; url: string }> = [\n { label: \"production (app.olakai.ai)\", url: HOSTS.production },\n { label: \"staging (staging.app.olakai.ai)\", url: HOSTS.staging },\n];\n\nexport async function initCommand(options: InitCommandOptions): Promise<void> {\n const interactive = !options.nonInteractive && isInteractive();\n\n // Logo + tagline at the very top of the interactive flow. Suppressed\n // by `printLogoHeader` itself when stdout isn't a TTY so CI runs and\n // piped output stay clean.\n if (interactive) {\n printLogoHeader();\n }\n\n try {\n // 1. Resolve the profile we'll be writing to. `resolveProfileName`\n // is the lenient resolver — it never throws, and may return null\n // if no registry exists yet (fresh install).\n const resolved = resolveProfileName();\n const profileName = resolved?.name ?? \"default\";\n\n // 2. Early-exit / re-auth check FIRST (before host resolution).\n //\n // We must run this before `resolveHost` so the user's choice\n // (\"Re-authenticate? [y/N]\") can influence host resolution. The\n // previous order resolved the host first, which silently locked in\n // the stored host whenever the token was still valid — leaving no\n // path to switch workspaces (e.g. staging → production) without\n // first running `olakai logout`.\n //\n // The prompt references the *stored* host (the workspace the\n // current token authenticates against), not a freshly-picked one.\n let optedReAuth = false;\n if (isTokenValid()) {\n const file = readProfilesFile();\n const existing = file.profiles[profileName];\n const who = existing?.email ?? \"unknown\";\n const where = existing?.host ?? \"(unknown host)\";\n if (options.nonInteractive) {\n // Non-interactive: idempotent no-op. Don't surprise scripts.\n console.log(\n `Already authenticated as ${who} on ${where} (profile: ${profileName}).`,\n );\n return;\n }\n const answer = await promptUser(\n `Already authenticated as ${who} on ${where} (profile: ${profileName}). Re-authenticate? [y/N]: `,\n );\n if (answer.trim().toLowerCase() !== \"y\") {\n console.log(\"Keeping existing credentials. Run 'olakai logout' to sign out.\");\n return;\n }\n optedReAuth = true;\n }\n\n // 3. Resolve the host. CLI flag (already handled by the global\n // preAction hook) wins via getBaseUrl(). Otherwise prefer the\n // profile's stored host — but offer a switch prompt when the\n // user is actively re-authenticating (post-logout OR via the\n // \"Re-authenticate? [y]\" path above).\n const host = await resolveHost(\n profileName,\n options,\n interactive,\n optedReAuth,\n );\n // Apply the host so all subsequent `getBaseUrl()` calls (incl. the\n // handshake client) point at the right backend.\n setHostOverride(host);\n\n // 4. Email.\n const email = await resolveEmail(options, interactive);\n\n console.log(`\\nContacting ${host} for ${email}...`);\n\n // 5. Handshake. One retry on transient network failures (per\n // spec) — only `network_error`, never 4xx/5xx, which carry\n // semantic meaning the wizard must surface unchanged.\n let handshake = await postHandshake({ email, host });\n if (handshake.kind === \"error\" && handshake.code === \"network_error\") {\n console.log(\"(Network error contacting Olakai — retrying once...)\");\n handshake = await postHandshake({ email, host });\n }\n if (handshake.kind === \"error\") {\n handleHandshakeError(handshake);\n return;\n }\n\n const response = handshake.data;\n\n switch (response.status) {\n case \"user_exists\":\n if (\"deviceFlowOk\" in response && response.deviceFlowOk === true) {\n // Existing non-EMPLOYEE user → existing device-flow login.\n // Reuse `loginCommand` verbatim so there's exactly one\n // device-flow code path in the CLI.\n //\n // Pre-browser greeting (OLA-226): the prior one-liner read as\n // unexplained friction to admins evaluating Olakai (Xavier\n // session, 2026-05-14). Surface that we identified the user,\n // explain the role-tier reason for the browser step, and\n // make the contrast with the Employee-role OTP path explicit\n // so admins don't generalize the friction to their team.\n console.log(\"\");\n console.log(formatExistingUserBrowserGreeting(email));\n if (interactive) {\n // Press-Enter gate. The user has read the message; opening\n // the browser without acknowledgement felt abrupt during\n // Xavier's evaluation. Ctrl-C still bails as expected.\n await promptUser(\n \"\\n > Press Enter to open your browser, or Ctrl-C to cancel: \",\n );\n }\n console.log(\"\");\n await loginCommand();\n await offerMonitorSetup(options, interactive);\n return;\n }\n // EMPLOYEE refresh path: OTP. Narrow via the OTP-branch shape.\n if (\"otpSent\" in response && response.otpSent === true) {\n await runOtpFlow(email, profileName, {\n emailObfuscated: response.emailObfuscated,\n expiresIn: response.expiresIn,\n });\n await offerMonitorSetup(options, interactive);\n return;\n }\n // Defensive fallback — the backend returned `user_exists`\n // without the expected discriminator. Surface clearly instead\n // of silently hanging.\n console.error(\n \"Unexpected handshake response: 'user_exists' without device-flow or OTP signal.\",\n );\n process.exit(1);\n return;\n\n case \"domain_claimed\":\n await runOtpFlow(email, profileName, {\n emailObfuscated: response.emailObfuscated,\n expiresIn: response.expiresIn,\n });\n await offerMonitorSetup(options, interactive);\n return;\n\n case \"saas_can_self_signup\": {\n console.log(\n \"\\nWe don't have you yet. Opening your browser to create an account...\",\n );\n // BLOCKING from pre-PR review: validate the URL scheme before\n // handing it to the platform opener. A compromised or\n // misconfigured backend could otherwise return `file://`,\n // `javascript:`, `vscode://`, `ssh://`, etc. — anything the\n // OS opener accepts. Defense-in-depth: only http/https.\n if (isSafeOpenUrl(response.signupUrl)) {\n try {\n await open(response.signupUrl);\n } catch {\n console.log(\n `(Could not open browser automatically. Visit ${response.signupUrl})`,\n );\n }\n } else {\n console.log(\n `(Server returned an unexpected signup URL scheme. Visit ${response.signupUrl} manually in your browser.)`,\n );\n }\n console.log(\n \"When done, re-run 'olakai init' to finish authenticating this CLI.\",\n );\n return;\n }\n\n case \"blocked\": {\n const domain = email.split(\"@\")[1] ?? email;\n console.error(\n `\\nYour domain \"${domain}\" isn't connected to an Olakai workspace.`,\n );\n if (response.message) {\n console.error(response.message);\n }\n console.error(\"Ask your admin to claim it, then re-run 'olakai init'.\");\n process.exit(1);\n }\n }\n } catch (err) {\n if (err instanceof InitAbortedError) {\n if (err.message) console.error(err.message);\n process.exit(err.exitCode);\n }\n console.error(err instanceof Error ? err.message : String(err));\n process.exit(1);\n }\n}\n\n/**\n * Allow only `http:` / `https:` schemes for any URL we hand to the\n * platform opener (`open`). The OS opener accepts `file:`, `mailto:`,\n * `vscode://`, `ssh://`, custom URL handlers, etc. — none of which a\n * trustworthy handshake response should ever return. Falling through to\n * a manual copy/paste message is the safe degradation.\n */\nfunction isSafeOpenUrl(raw: string): boolean {\n try {\n const url = new URL(raw);\n return url.protocol === \"http:\" || url.protocol === \"https:\";\n } catch {\n return false;\n }\n}\n\n// ---- host selection --------------------------------------------------------\n\nasync function resolveHost(\n profileName: string,\n options: InitCommandOptions,\n interactive: boolean,\n forceHostPrompt = false,\n): Promise<string> {\n // `getBaseUrl()` already applies `--host`/OLAKAI_HOST overrides set\n // by the global preAction hook. If either is in effect, that's the\n // host we use. If neither is in effect, the lenient resolver in\n // `getBaseUrl()` may still return the profile's stored host — that's\n // also fine.\n //\n // Precedence per CLAUDE.md: `--host` flag wins over `OLAKAI_HOST`\n // env (the flag is the more explicit signal). Practically a no-op\n // today because `preAction` already pushed both into `getBaseUrl()`,\n // but checking the flag first keeps this in lockstep with the\n // documented resolution order so a future refactor can't drift.\n const fromFlag = options.host?.trim() || process.env.OLAKAI_HOST?.trim();\n if (fromFlag) {\n return getBaseUrl();\n }\n\n // If the profile already has a host, prefer it — but offer an\n // override path for interactive users with no valid token (OLA-229).\n //\n // The stored host survives `olakai logout` (which only clears\n // `token` + `expiresAt`, see `profiles.ts`), so a user who logged\n // out specifically to switch workspaces would otherwise be quietly\n // routed back to the same one. Silent prefer is right for:\n // - non-interactive runs (CI / scripts)\n // - re-runs with a still-valid token (the user opted into\n // re-auth via the early-exit prompt; they're keeping the\n // current workspace)\n // Re-prompt is right when interactive AND there's no valid token —\n // the user is actively re-authenticating from a logged-out state\n // and might be switching contexts.\n const file = readProfilesFile();\n const existing = file.profiles[profileName];\n if (existing?.host) {\n // Offer a workspace-switch prompt when either:\n // - the user is post-logout (no valid token; OLA-229), OR\n // - the user explicitly opted to re-authenticate via the\n // valid-token early-exit prompt in `initCommand`\n // (`forceHostPrompt`).\n // Otherwise the stored host is silently reused (idempotent\n // re-runs, non-interactive scripts).\n const shouldOfferSwitch =\n interactive && (forceHostPrompt || !isTokenValid());\n if (!shouldOfferSwitch) {\n return existing.host;\n }\n const keep = await promptUser(\n `\\nConnect to ${existing.host}? [Y/n] (or pick a different workspace): `,\n );\n if (keep.trim().toLowerCase() !== \"n\") {\n return existing.host;\n }\n // Fall through to the picker below.\n console.log(\"\");\n }\n\n if (!interactive) {\n throw new InitAbortedError(\n \"No host configured. Pass --host or set OLAKAI_HOST in non-interactive mode.\",\n );\n }\n\n // Interactive picker.\n console.log(\"\\nWhich Olakai workspace are you connecting to?\");\n for (let i = 0; i < PRESET_HOSTS.length; i += 1) {\n const entry = PRESET_HOSTS[i]!;\n console.log(` ${i + 1}) ${entry.label}`);\n }\n console.log(` ${PRESET_HOSTS.length + 1}) Custom (on-prem)`);\n\n const choice = await promptUser(`Choose [1-${PRESET_HOSTS.length + 1}]: `);\n const idx = Number.parseInt(choice.trim(), 10);\n if (idx >= 1 && idx <= PRESET_HOSTS.length) {\n return PRESET_HOSTS[idx - 1]!.url;\n }\n if (idx === PRESET_HOSTS.length + 1) {\n return promptForCustomHost();\n }\n console.error(\"Invalid choice. Re-run 'olakai init' and pick a valid option.\");\n throw new InitAbortedError(\"\", 1);\n}\n\nasync function promptForCustomHost(): Promise<string> {\n for (let attempt = 0; attempt < 3; attempt += 1) {\n const raw = await promptUser(\"On-prem URL or hostname (e.g. olakai.acme.com): \");\n const normalized = normalizeHost(raw.trim());\n if (normalized) {\n return normalized;\n }\n console.log(\"That doesn't look like a valid host. Try again.\");\n }\n throw new InitAbortedError(\"Too many invalid host entries.\", 1);\n}\n\nfunction normalizeHost(value: string): string | null {\n if (!value) return null;\n // Allow bare hostnames; require at least one dot OR `localhost`.\n // Anything else is almost certainly a typo.\n const withScheme = /^https?:\\/\\//i.test(value) ? value : `https://${value}`;\n let url: URL;\n try {\n url = new URL(withScheme);\n } catch {\n return null;\n }\n if (!url.hostname) return null;\n if (!url.hostname.includes(\".\") && url.hostname !== \"localhost\") {\n return null;\n }\n return `${url.protocol}//${url.host}`.replace(/\\/+$/, \"\");\n}\n\n// ---- email collection ------------------------------------------------------\n\nasync function resolveEmail(\n options: InitCommandOptions,\n interactive: boolean,\n): Promise<string> {\n if (options.email) {\n const trimmed = options.email.trim();\n if (!EMAIL_REGEX.test(trimmed)) {\n throw new InitAbortedError(\n `Invalid email: \"${options.email}\". Re-run with a well-formed --email.`,\n );\n }\n return trimmed;\n }\n if (!interactive) {\n throw new InitAbortedError(\n \"Missing --email in non-interactive mode. Pass --email <you@company.com>.\",\n );\n }\n for (let attempt = 0; attempt < 3; attempt += 1) {\n const raw = await promptUser(\"Work email: \");\n const trimmed = raw.trim();\n if (EMAIL_REGEX.test(trimmed)) {\n return trimmed;\n }\n console.log(\"That doesn't look like a valid email. Try again.\");\n }\n throw new InitAbortedError(\"Too many invalid email entries.\", 1);\n}\n\n// ---- OTP loop --------------------------------------------------------------\n\ninterface OtpContext {\n emailObfuscated: string;\n expiresIn: number;\n}\n\nasync function runOtpFlow(\n email: string,\n profileName: string,\n ctx: OtpContext,\n): Promise<void> {\n const expiryMin = Math.max(1, Math.round(ctx.expiresIn / 60));\n console.log(\n `\\nWe sent a 6-digit code to ${ctx.emailObfuscated} (expires in ${expiryMin} min).`,\n );\n\n // The OTP loop terminates on:\n // - verify success → break and exchange\n // - locked / no_code → exit 1\n // - expired → restart handshake (caller's responsibility — we\n // surface a clear message and exit 1, instructing the user to\n // re-run init; that's strictly simpler than re-driving the\n // handshake mid-loop, and matches the wording in the spec)\n for (;;) {\n const code = await promptUser(\"Enter the 6-digit code: \");\n const trimmed = code.trim();\n if (!OTP_REGEX.test(trimmed)) {\n console.log(\"Codes are 6 digits. Try again.\");\n continue;\n }\n // One-shot retry on transient network failure. Same shape as the\n // existing handshake retry — `verify` is idempotent on the wire\n // (no state change unless the request reaches the server and\n // decodes), so retrying a connection-level failure is safe. The\n // rare race where the server consumed an OTP attempt but the\n // response was lost trades one attempt-counter slot for not\n // aborting the whole flow on a TLS hiccup — favorable trade given\n // the 5-attempt lockout budget.\n let result = await postHandshakeVerify({ email, code: trimmed });\n if (result.kind === \"error\" && result.code === \"network_error\") {\n console.log(\"(Network error verifying code — retrying once...)\");\n result = await postHandshakeVerify({ email, code: trimmed });\n }\n if (result.kind === \"ok\") {\n const consentToken = result.data.consentToken;\n await runExchange(consentToken, profileName, email);\n return;\n }\n\n switch (result.code) {\n case \"invalid_code\": {\n const remaining = result.detail?.attemptsRemaining;\n const tail =\n typeof remaining === \"number\"\n ? ` ${remaining} attempt${remaining === 1 ? \"\" : \"s\"} remaining.`\n : \"\";\n console.log(`Wrong code.${tail}`);\n continue;\n }\n case \"locked\":\n console.error(\n \"Too many attempts. Request a fresh code by re-running 'olakai init'.\",\n );\n throw new InitAbortedError(\"\", 1);\n case \"expired\":\n console.error(\n \"Code expired. Re-run 'olakai init' to request a new one.\",\n );\n throw new InitAbortedError(\"\", 1);\n case \"no_code\":\n console.error(\n \"No live code for this email. Run 'olakai init' again to request one.\",\n );\n throw new InitAbortedError(\"\", 1);\n case \"rate_limited\": {\n const wait = result.retryAfter\n ? ` Retry in ${result.retryAfter}s.`\n : \"\";\n console.error(`Rate limit hit while verifying.${wait}`);\n throw new InitAbortedError(\"\", 1);\n }\n case \"service_unavailable\":\n console.error(\n \"Olakai is temporarily unavailable. Try again in a minute.\",\n );\n throw new InitAbortedError(\"\", 1);\n case \"network_error\":\n console.error(\n `Network error${result.causeCode ? ` (${result.causeCode})` : \"\"}: ${result.message}`,\n );\n throw new InitAbortedError(\"\", 1);\n default:\n console.error(\n `Verification failed (${result.code}): ${result.message}`,\n );\n throw new InitAbortedError(\"\", 1);\n }\n }\n}\n\nasync function runExchange(\n consentToken: string,\n profileName: string,\n email: string,\n): Promise<void> {\n // One-shot retry on transient network failure. The undici socket\n // drops we saw in production (Xavier session, 2026-05-14) were one\n // failure followed by an immediate success on the same call. Without\n // this retry, that flake aborts the wizard after the user has\n // already typed the OTP.\n //\n // Edge case: if the server actually processed the exchange and the\n // response socket died, the consent JWT is already burned and the\n // retry returns `invalid_consent`. User sees the standard\n // \"Consent token was rejected. Re-run 'olakai init' to start over.\"\n // — same outcome as today's no-retry path on that rare race, so\n // strictly net-positive on every other transient failure mode.\n let result = await postHandshakeExchange({ consentToken });\n if (result.kind === \"error\" && result.code === \"network_error\") {\n console.log(\"(Network error exchanging consent — retrying once...)\");\n result = await postHandshakeExchange({ consentToken });\n }\n if (result.kind === \"error\") {\n switch (result.code) {\n case \"invalid_consent\":\n console.error(\n \"Consent token was rejected. Re-run 'olakai init' to start over.\",\n );\n break;\n case \"user_unavailable\":\n console.error(\n \"Your user record is unavailable on the backend. Contact your admin.\",\n );\n break;\n case \"rate_limited\": {\n const wait = result.retryAfter\n ? ` Retry in ${result.retryAfter}s.`\n : \"\";\n console.error(`Rate limit hit while exchanging consent.${wait}`);\n break;\n }\n case \"service_unavailable\":\n console.error(\n \"Olakai is temporarily unavailable. Try again in a minute.\",\n );\n break;\n case \"network_error\":\n console.error(\n `Network error exchanging consent${result.causeCode ? ` (${result.causeCode})` : \"\"}: ${result.message}`,\n );\n break;\n default:\n console.error(`Exchange failed (${result.code}): ${result.message}`);\n }\n throw new InitAbortedError(\"\", 1);\n }\n\n // Persist into the active profile. `saveToken` writes to the\n // resolved profile (creating it if needed) and respects the active\n // host via `getBaseUrl()`.\n saveToken(result.data.access_token, result.data.expires_in);\n // Cache the email on the profile so subsequent `whoami` calls don't\n // need to round-trip when offline. We don't have user/account IDs\n // until the user hits an authenticated endpoint, but the email\n // alone is enough for friendly re-auth prompts.\n try {\n patchProfile(profileName, { email });\n } catch {\n // Best-effort — failure here doesn't invalidate the login.\n }\n\n console.log(`\\nLogged in as ${email} on ${getBaseUrl()}.`);\n console.log(`Profile: ${profileName}`);\n}\n\n// ---- handshake-level error surfacing --------------------------------------\n\nfunction handleHandshakeError(\n err: Extract<Awaited<ReturnType<typeof postHandshake>>, { kind: \"error\" }>,\n): never {\n switch (err.code) {\n case \"validation_error\":\n console.error(`That email didn't pass validation: ${err.message}`);\n break;\n case \"blocked\":\n console.error(err.message);\n console.error(\n \"Ask your admin to claim your domain, then re-run 'olakai init'.\",\n );\n break;\n case \"rate_limited\": {\n const wait = err.retryAfter ? ` Retry in ${err.retryAfter}s.` : \"\";\n console.error(`Too many attempts.${wait}`);\n break;\n }\n case \"service_unavailable\":\n console.error(\"Olakai is temporarily unavailable. Try again in a minute.\");\n break;\n case \"network_error\":\n console.error(\n `Network error contacting Olakai${err.causeCode ? ` (${err.causeCode})` : \"\"}: ${err.message}`,\n );\n break;\n default:\n console.error(`Handshake failed (${err.code}): ${err.message}`);\n }\n process.exit(1);\n}\n\n// ---- monitor handoff (OLA-214) --------------------------------------------\n\n/**\n * Auto-detect installed local coding agents, prompt per-tool, and chain\n * into the existing `monitor init` plugin install for each tool the\n * user opts into.\n *\n * Design notes:\n *\n * - `--skip-monitor` short-circuits before detection runs. We treat it\n * as an explicit \"don't touch hooks here\", not \"I'll do it later\"\n * — so no docs-pointer line either. The wizard already said\n * everything it needed to say at that point.\n *\n * - Non-interactive mode auto-accepts each detected tool. Rationale:\n * if you went out of your way to run `olakai init --non-interactive`\n * you've opted into the chained setup; failing fast here would\n * defeat the CI use case. Inside each `runMonitorInstall` the\n * plugin still gates on required inputs and fast-fails on missing\n * ones (e.g. unable to mint an API key without a prompt) rather\n * than hanging.\n *\n * - Per-tool failures are isolated. A flake on the agents-API for one\n * tool must not strand the user without monitoring on the others.\n * We catch, surface a retry hint, and continue.\n *\n * - The plugin's own `install()` already handles the \"config already\n * exists in this workspace, replace? [y/N]\" prompt — we don't\n * re-implement it here.\n */\nasync function offerMonitorSetup(\n options: InitCommandOptions,\n interactive: boolean,\n): Promise<void> {\n if (options.skipMonitor) return;\n\n const detected = await detectInstalledTools(process.cwd());\n if (detected.length === 0) {\n console.log(\n \"\\nNo coding agents detected in this workspace.\",\n );\n console.log(\n \"Install Claude Code, Codex, or Cursor and run 'olakai monitor init' to start tracking.\",\n );\n return;\n }\n\n console.log(\n `\\nDetected ${detected.length} coding agent${detected.length === 1 ? \"\" : \"s\"} in this workspace.`,\n );\n\n for (const { tool, reason } of detected) {\n let proceed = true;\n if (interactive) {\n const answer = await promptUser(\n `\\nSet up monitoring for ${tool}? (${reason}) [Y/n]: `,\n );\n const normalized = answer.trim().toLowerCase();\n // Default-yes: empty / 'y' / 'yes' all proceed. Anything else\n // counts as a decline (matches the convention used by the\n // re-auth prompt earlier in the wizard).\n proceed =\n normalized === \"\" || normalized === \"y\" || normalized === \"yes\";\n }\n\n if (!proceed) {\n console.log(\n `Skipped ${tool}. Run 'olakai monitor init --tool ${tool}' later if you change your mind.`,\n );\n continue;\n }\n\n try {\n await runMonitorInstall(tool, { interactive });\n console.log(`${tool} monitoring configured.`);\n } catch (err) {\n // Isolate the failure — don't poison the remaining tools or\n // abort the wizard with a non-zero exit. Re-running just the\n // failed tool is a single command, so we surface it.\n const message = err instanceof Error ? err.message : String(err);\n console.error(`${tool} setup failed: ${message}`);\n console.error(\n `Run 'olakai monitor init --tool ${tool}' to retry.`,\n );\n }\n }\n}\n\n// ---- exit signaling --------------------------------------------------------\n\n/**\n * Internal marker for \"we've already printed a clear user-facing\n * message; just exit with the given code\". Lets nested helpers bail\n * out without each one calling `process.exit()` directly (which would\n * be untestable).\n */\nclass InitAbortedError extends Error {\n exitCode: number;\n constructor(message: string, exitCode = 1) {\n super(message);\n this.name = \"InitAbortedError\";\n this.exitCode = exitCode;\n }\n}\n","/**\n * Typed client for the CLI handshake API (OLA-210).\n *\n * Three unauthenticated endpoints back the `olakai init` wizard:\n *\n * POST /api/cli/handshake → branch the wizard (device-flow,\n * OTP, signup, or blocked)\n * POST /api/cli/handshake/verify → exchange a 6-digit OTP for a\n * short-lived consent token\n * POST /api/cli/handshake/exchange → exchange the consent token for\n * the long-lived CLI bearer\n *\n * The HTTP layer is intentionally thin: no retries, no progress\n * reporting. The wizard owns retry/UX decisions because the right\n * behavior depends heavily on the user-facing branch (e.g. `expired`\n * vs `invalid_code` need very different prompts).\n *\n * Every function returns a discriminated-union result keyed by `kind`:\n *\n * `kind === \"ok\"` — happy path, payload in `data`\n * `kind === \"error\"` — typed failure with backend `code`\n *\n * Backend error contract (mirrors S1 spec):\n *\n * 400 validation_error\n * 400 invalid_code (verify, with `attemptsRemaining`)\n * 401 invalid_consent / user_unavailable (exchange)\n * 403 blocked (handshake)\n * 404 no_code (verify)\n * 410 expired (verify)\n * 429 locked (verify, lockout) / rate_limited\n * 503 service_unavailable\n *\n * Rate-limit responses surface `Retry-After` (seconds) so the wizard\n * can print an informed wait message.\n */\n\nimport { getBaseUrl } from \"./config.js\";\n\n/** Discriminated success/error envelope used by every handshake call. */\nexport type HandshakeResult<TOk, TError = HandshakeErrorCode> =\n | { kind: \"ok\"; data: TOk }\n | {\n kind: \"error\";\n code: TError;\n message: string;\n status: number;\n retryAfter?: number;\n /**\n * For `network_error`s: the underlying undici / Node error code\n * (e.g. `UND_ERR_CONNECT`, `ECONNRESET`). `Error.cause` carries\n * this on `fetch()` failures; we surface it here so the UI can\n * print something more actionable than the bare `\"fetch failed\"`\n * string. Unset for non-network errors and for network errors\n * with no exposed cause code.\n */\n causeCode?: string;\n };\n\nexport type HandshakeErrorCode =\n | \"validation_error\"\n | \"invalid_code\"\n | \"invalid_consent\"\n | \"user_unavailable\"\n | \"blocked\"\n | \"no_code\"\n | \"expired\"\n | \"locked\"\n | \"rate_limited\"\n | \"service_unavailable\"\n | \"network_error\"\n | \"unknown_error\";\n\n// ---- POST /api/cli/handshake -----------------------------------------------\n\n/**\n * The branch the backend tells us to follow. Each variant is a tagged\n * object so callers can `switch (resp.data.status)`.\n */\nexport type HandshakeResponse =\n | { status: \"user_exists\"; deviceFlowOk: true }\n | {\n status: \"user_exists\";\n otpSent: true;\n emailObfuscated: string;\n codeExpiresAt: string;\n expiresIn: number;\n }\n | {\n status: \"domain_claimed\";\n accountId: string;\n userId: string;\n matchType: \"exact\" | \"suffix\";\n emailObfuscated: string;\n codeExpiresAt: string;\n expiresIn: number;\n }\n | { status: \"saas_can_self_signup\"; signupUrl: string }\n | { status: \"blocked\"; message: string };\n\nexport interface HandshakeRequest {\n email: string;\n /** Optional explicit host hint (the backend may key per-host policy off this). */\n host?: string;\n}\n\n/**\n * POST /api/cli/handshake. Returns one of the five branches above, or a\n * typed error envelope. Network/parse failures map to `network_error`.\n */\nexport async function postHandshake(\n body: HandshakeRequest,\n): Promise<HandshakeResult<HandshakeResponse, HandshakeErrorCode>> {\n return postHandshakeJson<HandshakeResponse>(\n `${getBaseUrl()}/api/cli/handshake`,\n body,\n );\n}\n\n// ---- POST /api/cli/handshake/verify ---------------------------------------\n\nexport interface VerifyRequest {\n email: string;\n code: string;\n}\n\nexport interface VerifySuccess {\n consentToken: string;\n expiresIn: number;\n}\n\n/**\n * Extra context for the `invalid_code` branch. Backend includes\n * `attemptsRemaining` so we can print \"N attempts remaining\" before\n * the next prompt.\n */\nexport interface VerifyErrorDetail {\n attemptsRemaining?: number;\n}\n\nexport type VerifyResult = HandshakeResult<VerifySuccess, HandshakeErrorCode> & {\n detail?: VerifyErrorDetail;\n};\n\nexport async function postHandshakeVerify(\n body: VerifyRequest,\n): Promise<VerifyResult> {\n const url = `${getBaseUrl()}/api/cli/handshake/verify`;\n const result = await postHandshakeJson<VerifySuccess>(url, body, {\n captureDetail: true,\n });\n return result as VerifyResult;\n}\n\n// ---- POST /api/cli/handshake/exchange -------------------------------------\n\nexport interface ExchangeRequest {\n consentToken: string;\n}\n\n/** Same shape as device-flow's `/api/auth/device/token` response. */\nexport interface ExchangeSuccess {\n access_token: string;\n token_type: \"Bearer\";\n expires_in: number;\n}\n\nexport async function postHandshakeExchange(\n body: ExchangeRequest,\n): Promise<HandshakeResult<ExchangeSuccess, HandshakeErrorCode>> {\n return postHandshakeJson<ExchangeSuccess>(\n `${getBaseUrl()}/api/cli/handshake/exchange`,\n body,\n );\n}\n\n// ---- shared transport ------------------------------------------------------\n\ninterface PostOptions {\n /**\n * When true, attempts to surface response-body fields (esp.\n * `attemptsRemaining` on `invalid_code`) on the returned envelope's\n * `detail` field. Other endpoints don't need it.\n */\n captureDetail?: boolean;\n}\n\ninterface ErrorBody {\n error?: string;\n code?: string;\n message?: string;\n attemptsRemaining?: number;\n}\n\n/**\n * Shared transport for the three handshake endpoints. Centralized so\n * Retry-After parsing, JSON-error decoding, and the network-error\n * fallback live in one place.\n */\nasync function postHandshakeJson<TOk>(\n url: string,\n body: unknown,\n options: PostOptions = {},\n): Promise<HandshakeResult<TOk, HandshakeErrorCode> & { detail?: VerifyErrorDetail }> {\n let response: Response;\n try {\n response = await fetch(url, {\n method: \"POST\",\n headers: { \"Content-Type\": \"application/json\" },\n body: JSON.stringify(body),\n });\n } catch (err) {\n return buildNetworkError(err);\n }\n\n if (response.ok) {\n let data: TOk;\n try {\n data = (await response.json()) as TOk;\n } catch (err) {\n return {\n kind: \"error\",\n code: \"unknown_error\",\n message: err instanceof Error ? err.message : \"Failed to parse response\",\n status: response.status,\n };\n }\n return { kind: \"ok\", data };\n }\n\n // Best-effort error body decode — backend may return a JSON envelope\n // or (rarely) a plain string. Anything unparseable degrades to a\n // generic unknown_error with the HTTP status preserved.\n let errBody: ErrorBody = {};\n try {\n errBody = (await response.json()) as ErrorBody;\n } catch {\n // ignore\n }\n\n const code = mapErrorCode(response.status, errBody);\n // Fallback message includes the request pathname so an unannotated\n // 5xx tells the user *what* failed, not just the status code.\n // Hostname is intentionally omitted — it varies by environment and\n // contributes nothing to the user's understanding of the error.\n let fallbackPath = \"\";\n try {\n fallbackPath = new URL(url).pathname;\n } catch {\n // Malformed URL — use the raw url string as a last resort.\n fallbackPath = url;\n }\n const message =\n errBody.message ||\n errBody.error ||\n `Request to ${fallbackPath} failed with status ${response.status}`;\n const retryAfter = parseRetryAfter(response.headers.get(\"retry-after\"));\n\n const envelope: HandshakeResult<TOk, HandshakeErrorCode> & {\n detail?: VerifyErrorDetail;\n } = {\n kind: \"error\",\n code,\n message,\n status: response.status,\n ...(retryAfter !== undefined ? { retryAfter } : {}),\n };\n\n if (options.captureDetail && typeof errBody.attemptsRemaining === \"number\") {\n envelope.detail = { attemptsRemaining: errBody.attemptsRemaining };\n }\n\n return envelope;\n}\n\n/**\n * Map an HTTP status + parsed error body to a canonical\n * `HandshakeErrorCode`. The backend's `code` field wins when present;\n * otherwise we fall back to the status code semantics from the S1\n * spec.\n */\nfunction mapErrorCode(status: number, body: ErrorBody): HandshakeErrorCode {\n const known: HandshakeErrorCode[] = [\n \"validation_error\",\n \"invalid_code\",\n \"invalid_consent\",\n \"user_unavailable\",\n \"blocked\",\n \"no_code\",\n \"expired\",\n \"locked\",\n \"rate_limited\",\n \"service_unavailable\",\n ];\n // Defensive: only trust the backend's `code` / `error` fields when\n // they're actually strings. A malformed server returning numeric or\n // object payloads must not slip past the `includes()` guard.\n if (typeof body.code === \"string\" && (known as string[]).includes(body.code)) {\n return body.code as HandshakeErrorCode;\n }\n if (typeof body.error === \"string\" && (known as string[]).includes(body.error)) {\n return body.error as HandshakeErrorCode;\n }\n switch (status) {\n case 400:\n return \"validation_error\";\n case 401:\n return \"invalid_consent\";\n case 403:\n return \"blocked\";\n case 404:\n return \"no_code\";\n case 410:\n return \"expired\";\n case 429:\n return \"rate_limited\";\n case 503:\n return \"service_unavailable\";\n default:\n return \"unknown_error\";\n }\n}\n\n/**\n * Build a `network_error` envelope from a `fetch()` rejection, surfacing\n * the undici `err.cause.code` (e.g. `UND_ERR_CONNECT`, `ECONNRESET`)\n * when present. The bare `err.message` from undici is the unhelpful\n * `\"fetch failed\"`; the cause carries the actionable signal. We pull\n * `cause.code` onto the envelope's `causeCode` and append `cause.message`\n * onto the human message so both the structured field and the rendered\n * string carry the diagnostic.\n *\n * `Error.cause` is `unknown` per TS lib types; we treat it defensively\n * as a possibly-object value with optional string `code` / `message`.\n */\nfunction buildNetworkError(\n err: unknown,\n): { kind: \"error\"; code: \"network_error\"; message: string; status: 0; causeCode?: string } {\n const base =\n err instanceof Error ? err.message : \"Network request failed\";\n let causeCode: string | undefined;\n let causeMessage: string | undefined;\n if (err instanceof Error && err.cause && typeof err.cause === \"object\") {\n const c = err.cause as { code?: unknown; message?: unknown };\n if (typeof c.code === \"string\" && c.code.length > 0) {\n causeCode = c.code;\n }\n if (typeof c.message === \"string\" && c.message.length > 0) {\n causeMessage = c.message;\n }\n }\n // Compose the message: keep \"fetch failed\" prefix (some downstream\n // tooling matches against it), append cause-message when different.\n const message =\n causeMessage && causeMessage !== base ? `${base}: ${causeMessage}` : base;\n return {\n kind: \"error\",\n code: \"network_error\",\n message,\n status: 0,\n ...(causeCode ? { causeCode } : {}),\n };\n}\n\nfunction parseRetryAfter(header: string | null): number | undefined {\n if (!header) return undefined;\n const asNumber = Number(header);\n if (Number.isFinite(asNumber) && asNumber > 0) {\n return Math.floor(asNumber);\n }\n // Retry-After can also be an HTTP date — convert to seconds-from-now.\n const asDate = Date.parse(header);\n if (Number.isFinite(asDate)) {\n const seconds = Math.floor((asDate - Date.now()) / 1000);\n return seconds > 0 ? seconds : undefined;\n }\n return undefined;\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 * Multi-tool detection for chained `olakai init` → `olakai monitor init`\n * (OLA-214).\n *\n * Walks the registered monitor plugins (see `plugins/index.ts`) and\n * reports which of them appear installed in the current workspace.\n * Each entry carries a short human-readable `reason` we surface in the\n * per-tool consent prompt — the wizard's UX promise was\n *\n * \"Detected Claude Code in this workspace. Set up monitoring? [Y/n]\"\n *\n * The reason string is what makes that line specific (e.g.\n * \"found `.claude/settings.json`\") rather than a generic \"detected\".\n *\n * Implementation note: we don't reimplement each plugin's `detectInstalled`\n * here — that would diverge over time. Instead we call the plugin's\n * boolean probe and then, when it returns true, do a cheap follow-up\n * stat on a small set of well-known signal paths to pick the most\n * informative reason. If none match, we fall back to a generic phrase\n * so the prompt is always at least readable.\n */\nimport * as fs from \"node:fs\";\nimport * as path from \"node:path\";\nimport {\n getLegacyClaudeMonitorConfigPath,\n getMonitorConfigPath,\n} from \"./paths.js\";\nimport {\n getCodexConfigPath as getCodexHomeConfigPath,\n getCodexHomeDir,\n} from \"./plugins/codex/paths.js\";\n// Side-effect import: ensures plugins are registered when the init\n// wizard pulls this module in without going through monitor.ts.\nimport \"./plugins/index.js\";\nimport {\n listPlugins,\n type ToolId,\n type ToolMonitorPlugin,\n} from \"./plugin.js\";\n\nexport interface DetectedTool {\n tool: ToolId;\n /**\n * Short human-readable phrase identifying what signal triggered the\n * match. Designed to be inlined into a prompt: e.g.\n * `\"detected (found .claude/settings.json)\"`.\n */\n reason: string;\n}\n\n/**\n * Returns the detected tools, in the order plugins were registered. We\n * preserve order so the consent prompts are deterministic across runs\n * (and across `process.cwd()` shifts in tests).\n */\nexport async function detectInstalledTools(\n projectRoot: string = process.cwd(),\n): Promise<DetectedTool[]> {\n const detected: DetectedTool[] = [];\n for (const plugin of listPlugins()) {\n let installed = false;\n try {\n installed = await plugin.detectInstalled({ projectRoot });\n } catch {\n // detectInstalled is best-effort. A throwing probe should never\n // poison the wizard — treat it as \"not detected\".\n installed = false;\n }\n if (!installed) continue;\n detected.push({\n tool: plugin.id,\n reason: describeDetection(plugin, projectRoot),\n });\n }\n return detected;\n}\n\nfunction describeDetection(\n plugin: ToolMonitorPlugin,\n projectRoot: string,\n): string {\n // Prefer the most specific signal: an existing workspace-local\n // monitor config means the user already ran `olakai monitor init`\n // for this tool in this workspace at some point. Mention that so\n // they understand a re-run will trigger the plugin's own\n // \"replace?\" prompt rather than a fresh install.\n try {\n if (fs.existsSync(getMonitorConfigPath(projectRoot, plugin.id))) {\n return `existing config at .olakai/monitor-${plugin.id}.json`;\n }\n } catch {\n // fall through\n }\n\n switch (plugin.id) {\n case \"claude-code\": {\n try {\n if (fs.existsSync(getLegacyClaudeMonitorConfigPath(projectRoot))) {\n return \"legacy config at .claude/olakai-monitor.json\";\n }\n } catch {\n // fall through\n }\n try {\n const settings = path.join(projectRoot, \".claude\", \"settings.json\");\n if (fs.existsSync(settings)) {\n return \"found .claude/settings.json\";\n }\n } catch {\n // fall through\n }\n return \"Claude Code detected\";\n }\n case \"codex\": {\n try {\n if (fs.existsSync(getCodexHomeConfigPath())) {\n return \"found ~/.codex/config.toml\";\n }\n if (fs.existsSync(getCodexHomeDir())) {\n return \"found ~/.codex/\";\n }\n } catch {\n // fall through\n }\n return \"Codex CLI on PATH\";\n }\n case \"cursor\": {\n return \"Cursor installed for this user\";\n }\n default: {\n // Compile-time exhaustiveness check: when a 4th tool gets added\n // to `ToolId` (see CLAUDE.md \"Adding a New Local Coding Agent\n // Tool\" guide), this assertion fires at type-check time so the\n // missing case is impossible to miss. Until then, we keep a\n // graceful runtime fallback so a future tool doesn't ship with\n // `Set up monitoring for newtool? (undefined)` in the prompt.\n const _exhaustive: never = plugin.id;\n void _exhaustive;\n return `${plugin.displayName} detected`;\n }\n }\n}\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","import * 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 {\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 // Two independent signals — either is enough to surface\n // \"claude-code\" in the interactive `init` selector:\n // 1. The user already ran `olakai monitor init --tool claude-code`\n // here (workspace-local monitor config exists, new or legacy\n // path), OR\n // 2. The Claude Code CLI itself is installed on this host\n // (`claude` binary on PATH).\n //\n // We deliberately do NOT check for `~/.claude/` directory presence:\n // that directory is shared with Claude Desktop, so it would\n // false-positive for users who run the desktop app but never the\n // CLI. The `claude` binary on PATH is the precise signal for the\n // Claude Code CLI.\n //\n // Matches the structure of `codex.detectInstalled` so the three\n // plugins behave consistently for first-run users (Xavier session,\n // 2026-05-14 — first-run users were seeing \"No coding agents\n // detected\" even when Claude Code was installed because this\n // function only checked for an Olakai marker file).\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 } catch {\n // Fall through to the binary probe.\n }\n return detectClaudeBinaryOnPath();\n },\n};\n\n/**\n * Synchronous `which claude` / `where claude` probe. Cheap (<10ms in\n * practice) and any failure is treated as \"not installed\". Modeled on\n * `detectCodexBinaryOnPath` in `../codex/index.ts`.\n */\nfunction detectClaudeBinaryOnPath(): boolean {\n try {\n const probe = spawnSync(\n process.platform === \"win32\" ? \"where\" : \"which\",\n [\"claude\"],\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(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 { type Agent } from \"../../../lib/api.js\";\nimport { getValidToken } from \"../../../lib/auth.js\";\nimport { getBaseUrl } from \"../../../lib/config.js\";\nimport type { InstallOpts, InstallResult, UninstallOpts } from \"../../plugin.js\";\nimport { provisionSelfMonitorAgent } from \"../../self-monitor-provision.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 // Provision (or reuse) the self-monitor agent for this user +\n // workspace. The helper handles:\n // - default name = `<workspace>-<email-localpart>` (multi-user\n // shared-monorepo collision-safe)\n // - cross-workspace reuse via /agents/mine + regenerate-api-key\n // - 409 name-collision retry with a user-provided alternative\n // - 403 / role-aware error messages bubble up from createAgent\n const agent: Agent = await provisionSelfMonitorAgent({\n projectRoot,\n source: CLAUDE_CODE_AGENT_SOURCE,\n displayName: \"Claude Code\",\n category: CLAUDE_CODE_AGENT_CATEGORY,\n });\n\n const monitoringEndpoint = `${getBaseUrl()}/api/monitoring/prompt`;\n\n const apiKey = agent.apiKey?.key;\n if (!apiKey) {\n // Should not happen: both the create and the regenerate paths\n // return the plaintext key in the response. Surface as a clear\n // error rather than silently writing a bad config.\n console.error(\n \"Internal error: agent provisioned but no API key returned. Please re-run 'olakai monitor init'.\",\n );\n process.exit(1);\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\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 self-monitor agent provisioning for the coding-agent\n * plugins (claude-code, codex, cursor).\n *\n * Replaces the old \"Create new / use existing?\" two-branch prompt with\n * a deterministic flow:\n *\n * 1. Fetch the caller's identity from `/api/user/me`.\n * 2. Compose a default agent name that scopes to the workspace AND\n * the caller's email local-part (`<workspace>-<localpart>`). This\n * avoids the shared-monorepo collision where two devs on the same\n * `~/team-repo` would both default to `team-repo` and the second\n * to run would 409 on the existing-unique constraint.\n * 3. Try `GET /api/config/agents/mine?source=X&name=Y` to detect an\n * agent the user has already provisioned (cross-workspace\n * recovery, or same workspace after a local config wipe).\n * 4. If found, prompt the user to rotate the API key — they'll get\n * a fresh plaintext key for the local config, and any other\n * workspace using the old key starts 401-ing until it re-inits.\n * 5. If not found, accept a user-overridable name and create the\n * agent. Backend enforces the strict whitelist + per-user rate\n * limit + tier ceiling.\n *\n * The \"use an existing one (pick from list)\" branch is gone — the\n * backend doesn't let non-ADMIN users list arbitrary account agents\n * anyway, and self-monitor agents are intrinsically owned per-user.\n */\n\nimport path from \"node:path\";\nimport {\n createAgent,\n getCurrentUser,\n listMyAgents,\n regenerateAgentApiKey,\n type Agent,\n} from \"../lib/api.js\";\nimport { promptUser } from \"./prompt.js\";\n\nexport interface ProvisionOptions {\n projectRoot: string;\n /** Backend AgentSource enum value. */\n source: \"CLAUDE_CODE\" | \"CODEX\" | \"CURSOR\";\n /** Human-readable name for prompts and descriptions (\"Claude Code\"). */\n displayName: string;\n /** Category sent on create (\"CODING\" for all current coding agents). */\n category: string;\n}\n\nexport async function provisionSelfMonitorAgent(\n opts: ProvisionOptions,\n): Promise<Agent> {\n // One API call for the whole flow — used for both the default name\n // template and (in future) any role-aware messaging.\n const me = await getCurrentUser();\n const localPart = (me.email.split(\"@\")[0] ?? \"user\")\n .toLowerCase()\n .replace(/[^a-z0-9]+/g, \"-\")\n .replace(/^-+|-+$/g, \"\");\n const workspaceName = path.basename(opts.projectRoot).toLowerCase();\n const defaultName = `${workspaceName}-${localPart}`;\n\n // Check for an existing self-monitor agent owned by this user.\n // Filtering by name on the server side keeps the round-trip cheap\n // even for users with many agents.\n let existing: Awaited<ReturnType<typeof listMyAgents>> = [];\n try {\n existing = await listMyAgents({\n source: opts.source,\n name: defaultName,\n });\n } catch (err) {\n // Old backend (pre-self-monitor) — falls through to the create\n // path, which surfaces the appropriate 403 message via\n // `createAgent`'s role-aware error mapping.\n const message = err instanceof Error ? err.message : String(err);\n if (!message.includes(\"Failed to list your agents\")) {\n // Re-throw unexpected errors; only the \"backend doesn't know\n // this endpoint yet\" case should fall through silently.\n }\n }\n\n if (existing.length > 0) {\n const found = existing[0];\n console.log(\n `\\nFound your existing ${opts.displayName} agent \"${found.name}\".`,\n );\n console.log(\n \"Re-using it requires rotating its API key. Any other workspace currently using this agent will start failing on the next monitor request until it re-runs 'olakai monitor init'.\",\n );\n const ack = await promptUser(\"Rotate the API key and reuse? [y/N]: \");\n if (ack.trim().toLowerCase() !== \"y\") {\n console.error(\n \"Cancelled. To use this workspace without affecting the other workspace, run 'olakai monitor init' again and pick a different agent name when prompted.\",\n );\n process.exit(1);\n }\n const rotated = await regenerateAgentApiKey(found.id);\n return {\n id: found.id,\n name: found.name,\n description: found.description,\n role: found.role,\n // `source` on the listMyAgents response is the AgentSource enum\n // string; the Agent type narrows it more loosely. Cast through\n // the shared union.\n source: found.source as Agent[\"source\"],\n apiKey: {\n id: rotated.id,\n key: rotated.key,\n keyMasked: rotated.keyMasked,\n isActive: rotated.isActive,\n },\n workflowId: null,\n category: opts.category,\n };\n }\n\n // No existing self-monitor agent — create one. The user can override\n // the default name (e.g. on a 409 name-collision retry with a\n // pre-existing admin-created agent of the same name).\n const nameInput = await promptUser(`Agent name [${defaultName}]: `);\n const agentName = nameInput.trim() || defaultName;\n\n try {\n return await createAgent({\n name: agentName,\n description: `${opts.displayName} local agent for ${agentName}`,\n role: \"WORKER\",\n createApiKey: true,\n category: opts.category,\n source: opts.source,\n });\n } catch (err) {\n // On name collision, give the user one retry chance with a new\n // name instead of forcing them through `monitor uninstall` +\n // re-run.\n const message = err instanceof Error ? err.message : String(err);\n if (\n message.toLowerCase().includes(\"already exists\") ||\n message.toLowerCase().includes(\"conflict\")\n ) {\n console.log(\n `\\nAn agent named \"${agentName}\" already exists on this account (created by someone else or an admin).`,\n );\n const retry = await promptUser(\"Try a different name: \");\n if (!retry.trim()) {\n console.error(\"No name provided. Aborting.\");\n process.exit(1);\n }\n return createAgent({\n name: retry.trim(),\n description: `${opts.displayName} local agent for ${retry.trim()}`,\n role: \"WORKER\",\n createApiKey: true,\n category: opts.category,\n source: opts.source,\n });\n }\n throw err;\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 { type Agent } from \"../../../lib/api.js\";\nimport { getValidToken } from \"../../../lib/auth.js\";\nimport { getBaseUrl } from \"../../../lib/config.js\";\nimport { OLAKAI_DIR } from \"../../paths.js\";\nimport type { InstallOpts, InstallResult, UninstallOpts } from \"../../plugin.js\";\nimport { provisionSelfMonitorAgent } from \"../../self-monitor-provision.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 // Provision (or reuse) the self-monitor agent — same shared helper\n // as claude-code/cursor. See `self-monitor-provision.ts` for the\n // multi-workspace / multi-user collision handling.\n const agent: Agent = await provisionSelfMonitorAgent({\n projectRoot,\n source: CODEX_AGENT_SOURCE,\n displayName: \"Codex CLI\",\n category: CODEX_AGENT_CATEGORY,\n });\n\n const monitoringEndpoint = `${getBaseUrl()}/api/monitoring/prompt`;\n\n const apiKey = agent.apiKey?.key;\n if (!apiKey) {\n console.error(\n \"Internal error: agent provisioned but no API key returned. Please re-run 'olakai monitor init'.\",\n );\n process.exit(1);\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\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 * 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 { type Agent } from \"../../../lib/api.js\";\nimport { getValidToken } from \"../../../lib/auth.js\";\nimport { getBaseUrl } from \"../../../lib/config.js\";\nimport type { InstallOpts, InstallResult, UninstallOpts } from \"../../plugin.js\";\nimport { OLAKAI_DIR } from \"../../paths.js\";\nimport { provisionSelfMonitorAgent } from \"../../self-monitor-provision.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 // Provision (or reuse) the self-monitor agent — same shared helper\n // as claude-code/codex.\n const agent: Agent = await provisionSelfMonitorAgent({\n projectRoot,\n source: CURSOR_AGENT_SOURCE,\n displayName: \"Cursor\",\n category: CURSOR_AGENT_CATEGORY,\n });\n\n const monitoringEndpoint = `${getBaseUrl()}/api/monitoring/prompt`;\n\n const apiKey = agent.apiKey?.key;\n if (!apiKey) {\n console.error(\n \"Internal error: agent provisioned but no API key returned. Please re-run 'olakai monitor init'.\",\n );\n process.exit(1);\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\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","/**\n * Programmatic entry point for \"run `olakai monitor init --tool X` for\n * me, but from inside another command\" (OLA-214 — chained `olakai init`\n * → `olakai monitor init`).\n *\n * `monitor.ts` already wires the user-facing Commander surface; this\n * module exposes the same install path so `init.ts` can drive it\n * without going through argv parsing. We deliberately do NOT re-export\n * `monitor init`'s `--tool` resolution / prompt — the wizard caller has\n * already decided which tool to install (via auto-detection +\n * per-tool consent), so we skip straight to `plugin.install(...)`.\n *\n * Errors from `plugin.install` bubble up so the caller (the wizard)\n * can decide whether to abort the whole chain or just skip this tool\n * and continue with the next one. The wizard chooses the latter — one\n * tool's API failure shouldn't strand the user without monitoring on\n * the other detected tools.\n */\nimport \"./plugins/index.js\";\nimport {\n getPlugin,\n type InstallResult,\n type ToolId,\n} from \"./plugin.js\";\n\nexport interface RunMonitorInstallOpts {\n /** Defaults to `process.cwd()`. Threaded through to the plugin. */\n projectRoot?: string;\n /**\n * `true` when the wizard knows the terminal is interactive AND the\n * user did not pass `--non-interactive`. Plugins decide what this\n * means — most still prompt for required inputs even when\n * `interactive` is false, because they have no other way to obtain\n * (e.g.) a pasted API key. That's fine: non-interactive callers must\n * supply the inputs the plugins need ahead of time, and a missing\n * input becomes a fast-fail rather than a hang.\n */\n interactive?: boolean;\n}\n\nexport async function runMonitorInstall(\n toolId: ToolId,\n opts: RunMonitorInstallOpts = {},\n): Promise<InstallResult> {\n const plugin = getPlugin(toolId);\n return plugin.install({\n projectRoot: opts.projectRoot ?? process.cwd(),\n interactive: opts.interactive ?? true,\n });\n}\n","/**\n * Terminal branding for the `olakai init` wizard (OLA-226).\n *\n * `olakai init` is the first thing an admin evaluating Olakai sees from\n * the CLI — Xavier's product-feedback session flagged the current\n * messaging as too curt for that role. This module owns the visual\n * shell (logo header, colors) and the role-aware copy for the admin /\n * analyst handoff to the browser device-flow.\n *\n * Color strategy: raw ANSI escapes, no new dependency. Cyan-tinted\n * `◉` mark matches the Olakai logo's teal/cyan palette. We respect\n * `NO_COLOR` (https://no-color.org/) and only emit color sequences\n * when stdout is a TTY — pipelines and CI logs stay clean.\n */\n\nconst RESET = \"\\x1b[0m\";\nconst CYAN = \"\\x1b[36m\";\nconst DIM = \"\\x1b[2m\";\n\nfunction colorize(text: string, color: string): string {\n if (process.env.NO_COLOR) return text;\n if (!process.stdout.isTTY) return text;\n return `${color}${text}${RESET}`;\n}\n\n/**\n * Prints the wizard's logo header. Call once at the very top of the\n * interactive `olakai init` flow — it sets the visual tone for the\n * entire session.\n *\n * Skipped automatically when stdout is not a TTY (CI, piped output)\n * so logs / `--non-interactive` runs stay machine-parseable.\n */\nexport function printLogoHeader(): void {\n if (!process.stdout.isTTY) return;\n const mark = colorize(\"◉\", CYAN);\n const tagline = colorize(\"Enterprise AI observability\", DIM);\n console.log(\"\");\n console.log(` ${mark} olakai`);\n console.log(` ${tagline}`);\n console.log(` ──────────────────────────────`);\n console.log(\"\");\n}\n\n/**\n * Multi-line greeting shown to existing-account users (ADMIN /\n * ANALYST / USER) on the `user_exists + deviceFlowOk` branch BEFORE\n * the browser opens for device-flow auth.\n *\n * Two goals:\n * 1. Acknowledge that we identified the user by name/email — Xavier\n * flagged the current \"Welcome back! Opening browser...\" as\n * feeling impersonal for someone evaluating the product.\n * 2. Explain WHY the browser step applies here AND clarify it does\n * NOT apply to Employee-role developers (who get the OTP flow).\n * The distinction is the heart of the feedback: admins shouldn't\n * conclude \"this is friction for my whole team\" from their own\n * elevated-privileges flow.\n *\n * Personalization is email-only by design. The handshake `user_exists\n * + deviceFlowOk` response is deliberately bounded to a tiny\n * email-enumeration oracle (status + boolean) — adding name/role/\n * accountName here would enlarge the oracle on an unauthenticated\n * endpoint. The richer per-user display (name, role, account) comes\n * AFTER browser auth, where `loginCommand` already prints them.\n */\nexport function formatExistingUserBrowserGreeting(email: string): string {\n return [\n ` ✓ Found your Olakai account — ${email}`,\n ``,\n ` Since you have login access to an Olakai workspace, we'll route`,\n ` you through your account's standard sign-in. Admin and analyst`,\n ` users authenticate the CLI through the browser, matching how`,\n ` they sign in to the web app.`,\n ``,\n ` Employee-role developers skip this step and self-onboard with`,\n ` a one-time email code — no browser, no SSO prompt.`,\n ].join(\"\\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\";\nimport { runMonitorInstall } from \"../monitor/install.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 // Delegate to `runMonitorInstall` so this command and the chained\n // `olakai init` path go through exactly one install code path. Any\n // future cross-cutting addition (telemetry, validation, logging)\n // only needs to touch `src/monitor/install.ts`.\n await runPluginAction(plugin, () => runMonitorInstall(toolId, { interactive: true }));\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; deleteAgent?: boolean },\n): Promise<void> {\n const toolId = await resolveToolFromOptions(options.tool, \"disable\");\n const plugin = getPlugin(toolId);\n\n // Capture the agent id BEFORE uninstall when the user asks to delete\n // the remote agent — uninstall removes the local monitor config, so\n // status() afterwards would have nothing to report. Errors here are\n // non-fatal: if status fails we still proceed with the local\n // uninstall and skip the remote delete.\n let agentIdToDelete: string | undefined;\n if (options.deleteAgent) {\n try {\n const report = await plugin.status({ projectRoot: process.cwd() });\n if (report.configured && report.agentId) {\n agentIdToDelete = report.agentId;\n } else {\n console.log(\n \"No monitor config found in this workspace — nothing to delete remotely.\",\n );\n }\n } catch (err) {\n const msg = err instanceof Error ? err.message : String(err);\n console.warn(\n `Couldn't read local monitor config to identify the agent (${msg}). Proceeding with local-only uninstall.`,\n );\n }\n }\n\n await runPluginAction(plugin, () =>\n plugin.uninstall({\n projectRoot: process.cwd(),\n keepConfig: options.keepConfig,\n }),\n );\n\n if (agentIdToDelete) {\n const { deleteAgent } = await import(\"../lib/api.js\");\n try {\n await deleteAgent(agentIdToDelete);\n console.log(`✓ Remote agent ${agentIdToDelete} deleted.`);\n } catch (err) {\n const msg = err instanceof Error ? err.message : String(err);\n console.error(\n `Local uninstall succeeded, but remote agent delete failed: ${msg}`,\n );\n console.error(\n `You can retry by visiting the Olakai dashboard, or rerun 'olakai monitor disable --tool ${toolId} --delete-agent' (the local config is gone, so the agent id won't be re-discovered — use the dashboard).`,\n );\n process.exit(1);\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 .option(\n \"--delete-agent\",\n \"Also delete the remote agent on the Olakai backend. Useful when retiring a workspace permanently. Self-monitor owner or ADMIN only.\",\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","/**\n * `olakai profiles ...` — AWS-style profile management.\n *\n * Subcommands:\n * - list Print all profiles, mark the active one\n * - use Set the registry default\n * - remove Delete a profile (refuses to remove the active default)\n * - current Show the resolved active profile\n */\n\nimport { Command } from \"commander\";\nimport { getBaseUrl } from \"../lib/config.js\";\nimport {\n readProfilesFile,\n removeProfile,\n resolveActiveProfile,\n resolveProfileName,\n setDefaultProfile,\n} from \"../lib/profiles.js\";\n\nfunction formatExpiry(expiresAt: number | undefined): string {\n if (typeof expiresAt !== \"number\") return \"no token\";\n const now = Math.floor(Date.now() / 1000);\n if (expiresAt <= now) return \"expired\";\n const seconds = expiresAt - now;\n const days = Math.floor(seconds / 86400);\n const hours = Math.floor((seconds % 86400) / 3600);\n if (days > 0) return `${days}d ${hours}h`;\n const minutes = Math.floor((seconds % 3600) / 60);\n if (hours > 0) return `${hours}h ${minutes}m`;\n return `${minutes}m`;\n}\n\nfunction maskToken(token: string | undefined): string {\n if (!token) return \"—\";\n if (token.length <= 8) return \"***\";\n return `${token.slice(0, 4)}…${token.slice(-4)}`;\n}\n\nfunction listAction(options: { json?: boolean }): void {\n const file = readProfilesFile();\n let resolved: { name: string } | null = null;\n try {\n resolved = resolveProfileName();\n } catch {\n resolved = null;\n }\n const activeName = resolved?.name ?? file.default;\n\n if (options.json) {\n console.log(\n JSON.stringify(\n {\n default: file.default ?? null,\n active: activeName ?? null,\n profiles: Object.entries(file.profiles).map(([name, p]) => ({\n name,\n host: p.host,\n isDefault: file.default === name,\n isActive: activeName === name,\n email: p.email ?? null,\n accountId: p.accountId ?? null,\n expiresIn: p.expiresAt\n ? Math.max(0, p.expiresAt - Math.floor(Date.now() / 1000))\n : null,\n hasToken: Boolean(p.token),\n })),\n },\n null,\n 2,\n ),\n );\n return;\n }\n\n const names = Object.keys(file.profiles);\n if (names.length === 0) {\n console.log(\"No profiles configured. Run 'olakai login' to create one.\");\n return;\n }\n\n for (const name of names) {\n const p = file.profiles[name];\n if (!p) continue;\n const markers: string[] = [];\n if (file.default === name) markers.push(\"default\");\n if (activeName === name) markers.push(\"active\");\n const label = markers.length > 0 ? ` (${markers.join(\", \")})` : \"\";\n const expiry = formatExpiry(p.expiresAt);\n const email = p.email ? ` — ${p.email}` : \"\";\n console.log(`* ${name}${label}`);\n console.log(` host: ${p.host}`);\n console.log(` token: ${maskToken(p.token)} (${expiry})${email}`);\n }\n}\n\nfunction useAction(name: string): void {\n try {\n setDefaultProfile(name);\n console.log(`Default profile is now: ${name}`);\n } catch (err) {\n console.error(err instanceof Error ? err.message : String(err));\n process.exit(1);\n }\n}\n\nfunction removeAction(name: string): void {\n try {\n removeProfile(name);\n console.log(`Removed profile: ${name}`);\n } catch (err) {\n console.error(err instanceof Error ? err.message : String(err));\n process.exit(1);\n }\n}\n\nfunction currentAction(options: { json?: boolean }): void {\n let active;\n try {\n active = resolveActiveProfile();\n } catch (err) {\n console.error(err instanceof Error ? err.message : String(err));\n process.exit(1);\n }\n if (!active) {\n if (options.json) {\n console.log(JSON.stringify({ active: null }, null, 2));\n } else {\n console.log(\"No profile configured. Run 'olakai login' to create one.\");\n }\n return;\n }\n\n // The \"effective\" host is what `getBaseUrl()` actually returns\n // (factoring in --host / OLAKAI_HOST overrides). The profile's\n // stored host is shown separately so the user can see when an\n // override is in effect.\n const effectiveHost = getBaseUrl();\n const overridden = effectiveHost !== active.host;\n\n if (options.json) {\n console.log(\n JSON.stringify(\n {\n name: active.name,\n host: effectiveHost,\n profileHost: active.host,\n source: active.source,\n hostFromWorkspaceConfig: active.hostFromWorkspaceConfig,\n hostOverridden: overridden,\n email: active.profile.email ?? null,\n accountId: active.profile.accountId ?? null,\n hasToken: Boolean(active.profile.token),\n expiresAt: active.profile.expiresAt ?? null,\n expiresIn: active.profile.expiresAt\n ? Math.max(\n 0,\n active.profile.expiresAt - Math.floor(Date.now() / 1000),\n )\n : null,\n },\n null,\n 2,\n ),\n );\n return;\n }\n\n console.log(`Profile: ${active.name} (from ${active.source})`);\n if (overridden) {\n console.log(`Host: ${effectiveHost} (overrides profile host)`);\n console.log(`Profile host: ${active.host}`);\n } else if (active.hostFromWorkspaceConfig) {\n console.log(`Host: ${active.host} (from workspace config)`);\n } else {\n console.log(`Host: ${active.host}`);\n }\n if (active.profile.email) {\n console.log(`Email: ${active.profile.email}`);\n }\n if (active.profile.accountId) {\n console.log(`Account ID: ${active.profile.accountId}`);\n }\n console.log(`Token: ${maskToken(active.profile.token)}`);\n console.log(`Expires in: ${formatExpiry(active.profile.expiresAt)}`);\n}\n\nexport function registerProfilesCommand(program: Command): void {\n const profiles = program\n .command(\"profiles\")\n .description(\"Manage Olakai authentication profiles (AWS-style)\");\n\n profiles\n .command(\"list\")\n .description(\"List all configured profiles\")\n .option(\"--json\", \"Output as JSON\")\n .action((options: { json?: boolean }) => {\n listAction(options);\n });\n\n profiles\n .command(\"use <name>\")\n .description(\"Set <name> as the default profile\")\n .action((name: string) => {\n useAction(name);\n });\n\n profiles\n .command(\"remove <name>\")\n .description(\"Remove a profile (refuses to remove the active default)\")\n .action((name: string) => {\n removeAction(name);\n });\n\n profiles\n .command(\"current\")\n .description(\"Print the active profile (resolved from flag/env/workspace/default)\")\n .option(\"--json\", \"Output as JSON\")\n .action((options: { json?: boolean }) => {\n currentAction(options);\n });\n}\n"],"mappings":"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","names":["open","asNumber","fs","path","fs","os","path","fs","path","path","path","fs","debugLog","fs","spawnSync","fs","path","OLAKAI_HOOK_MARKER","fs","path","getCodexConfigPath","getCodexConfigPath","path","fs","getCodexConfigPath","fs","path","noopDebug","debugLog","noopDebug","debugLog","TOOL_ID","debugLog","getCodexConfigPath","spawnSync","fs","os","fs","os","path","fs","path","os","path","OLAKAI_HOOK_MARKER","fs","os","path","fs","os","path","STATE_DIR_SEGMENTS","TOOL_ID","debugLog","open","program","listCommand","getCommand","createCommand","updateCommand","deleteCommand","program","listCommand","getCommand","createCommand","updateCommand","deleteCommand","program","listCommand","getCommand","createCommand","updateCommand","deleteCommand","program","listCommand","getCommand","program","fs","initCommand","report","deleteAgent","log","program","formatExpiry","program","require"]}
|