@evident-ai/cli 0.2.1-dev.6dcb71e → 0.2.1-dev.880fb8c
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/index.js +28 -14
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -1863,9 +1863,20 @@ Port ${state.port} is already in use.`));
|
|
|
1863
1863
|
state.opencodeVersion = health.version ?? null;
|
|
1864
1864
|
}
|
|
1865
1865
|
} else {
|
|
1866
|
-
|
|
1867
|
-
|
|
1866
|
+
log(state, `OpenCode is not running on port ${state.port}. Starting it automatically...`);
|
|
1867
|
+
state.opencodeProcess = await startOpenCode(state.port);
|
|
1868
|
+
const health = await waitForOpenCodeHealth(state.port, 3e4);
|
|
1869
|
+
if (!health.healthy) {
|
|
1870
|
+
throw new Error(
|
|
1871
|
+
`OpenCode failed to start on port ${state.port}. Install with: npm install -g opencode-ai`
|
|
1872
|
+
);
|
|
1873
|
+
}
|
|
1874
|
+
log(
|
|
1875
|
+
state,
|
|
1876
|
+
`OpenCode started on port ${state.port}${health.version ? ` (v${health.version})` : ""}`
|
|
1868
1877
|
);
|
|
1878
|
+
state.opencodeConnected = true;
|
|
1879
|
+
state.opencodeVersion = health.version ?? null;
|
|
1869
1880
|
}
|
|
1870
1881
|
}
|
|
1871
1882
|
var AUTH_EXPIRED_EXIT_CODE = 77;
|
|
@@ -1911,7 +1922,7 @@ function isNetworkError(error2) {
|
|
|
1911
1922
|
return false;
|
|
1912
1923
|
}
|
|
1913
1924
|
async function processQueue(state, authHeader, triggerReconnect) {
|
|
1914
|
-
let
|
|
1925
|
+
let idlePolls = 0;
|
|
1915
1926
|
let currentAuthHeader = authHeader;
|
|
1916
1927
|
while (state.running) {
|
|
1917
1928
|
if (state.reconnecting && state.reconnectPromise) {
|
|
@@ -1930,7 +1941,7 @@ async function processQueue(state, authHeader, triggerReconnect) {
|
|
|
1930
1941
|
);
|
|
1931
1942
|
state.consecutiveFetchFailures = 0;
|
|
1932
1943
|
if (conversations.length > 0) {
|
|
1933
|
-
|
|
1944
|
+
idlePolls = 0;
|
|
1934
1945
|
for (const conv of conversations) {
|
|
1935
1946
|
if (!state.running) break;
|
|
1936
1947
|
if (!state.lockedConversations.has(conv.id)) {
|
|
@@ -2097,25 +2108,28 @@ async function processQueue(state, authHeader, triggerReconnect) {
|
|
|
2097
2108
|
}
|
|
2098
2109
|
} else {
|
|
2099
2110
|
if (state.idleTimeout !== null) {
|
|
2100
|
-
|
|
2101
|
-
|
|
2111
|
+
idlePolls++;
|
|
2112
|
+
if (idlePolls === 1) {
|
|
2102
2113
|
logActivity(state, {
|
|
2103
2114
|
type: "info",
|
|
2104
2115
|
message: `Queue empty, waiting (timeout: ${state.idleTimeout}s)...`
|
|
2105
2116
|
});
|
|
2106
2117
|
if (state.interactive) displayStatus(state);
|
|
2107
2118
|
}
|
|
2108
|
-
if (Date.now() - idleStart > state.idleTimeout * 1e3) {
|
|
2109
|
-
logActivity(state, {
|
|
2110
|
-
type: "info",
|
|
2111
|
-
message: "Idle timeout reached"
|
|
2112
|
-
});
|
|
2113
|
-
if (state.interactive) displayStatus(state);
|
|
2114
|
-
break;
|
|
2115
|
-
}
|
|
2116
2119
|
}
|
|
2117
2120
|
}
|
|
2118
2121
|
await new Promise((resolve) => setTimeout(resolve, MESSAGE_POLL_INTERVAL_MS));
|
|
2122
|
+
if (state.idleTimeout !== null && idlePolls >= 2) {
|
|
2123
|
+
const idleMs = idlePolls * MESSAGE_POLL_INTERVAL_MS;
|
|
2124
|
+
if (idleMs > state.idleTimeout * 1e3) {
|
|
2125
|
+
logActivity(state, {
|
|
2126
|
+
type: "info",
|
|
2127
|
+
message: "Idle timeout reached"
|
|
2128
|
+
});
|
|
2129
|
+
if (state.interactive) displayStatus(state);
|
|
2130
|
+
break;
|
|
2131
|
+
}
|
|
2132
|
+
}
|
|
2119
2133
|
} catch (error2) {
|
|
2120
2134
|
if (error2 instanceof AuthenticationError) {
|
|
2121
2135
|
const result = await handleAuthError(state, error2);
|
package/dist/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/index.ts","../src/commands/login.ts","../src/lib/config.ts","../src/lib/api.ts","../src/lib/keychain.ts","../src/utils/ui.ts","../src/commands/logout.ts","../src/commands/whoami.ts","../src/commands/run.ts","../../../packages/types/src/telemetry/index.ts","../../../packages/types/src/tunnel/index.ts","../src/lib/telemetry.ts","../src/lib/auth.ts","../src/lib/opencode/health.ts","../src/lib/opencode/process.ts","../src/lib/opencode/install.ts","../src/lib/opencode/session.ts","../src/lib/tunnel/connection.ts","../src/lib/tunnel/forwarding.ts","../src/lib/tunnel/events.ts"],"sourcesContent":["/**\n * Evident CLI\n *\n * Run OpenCode locally and connect it to the Evident platform.\n */\n\nimport { Command } from 'commander';\nimport { login } from './commands/login.js';\nimport { logout } from './commands/logout.js';\nimport { whoami } from './commands/whoami.js';\nimport { run } from './commands/run.js';\nimport { setEnvironment, type Environment } from './lib/config.js';\n\nconst program = new Command();\n\nprogram\n .name('evident')\n .description('Run OpenCode locally and connect it to Evident')\n .version('0.1.0')\n .option('-e, --env <environment>', 'Environment to use (local, dev, production)', 'production')\n .hook('preAction', (thisCommand) => {\n const env = thisCommand.opts().env as Environment;\n if (env) {\n setEnvironment(env);\n }\n });\n\n// Login command\nprogram\n .command('login')\n .description('Authenticate with Evident')\n .option('--token', 'Use token-based authentication (for CI/CD)')\n .option('--no-browser', 'Do not open the browser automatically')\n .action(login);\n\n// Logout command\nprogram.command('logout').description('Remove stored credentials').action(logout);\n\n// Whoami command\nprogram.command('whoami').description('Show the currently logged in user').action(whoami);\n\n// Run command (unified - connects to Evident and processes messages)\nprogram\n .command('run')\n .description('Connect to Evident and process messages')\n .requiredOption('-a, --agent <id>', 'Agent ID to connect to')\n .option('-p, --port <port>', 'OpenCode port (default: 4096)', '4096')\n .option('-v, --verbose', 'Show detailed request/response information')\n .option('-c, --conversation <id>', 'Process only this specific conversation')\n .option('--idle-timeout <seconds>', 'Exit after N seconds idle')\n .option('--json', 'Output in JSON format')\n .action(\n (options: {\n agent: string;\n port: string;\n verbose?: boolean;\n conversation?: string;\n idleTimeout?: string;\n json?: boolean;\n }) => {\n run({\n agent: options.agent,\n port: parseInt(options.port, 10),\n verbose: options.verbose,\n conversation: options.conversation,\n idleTimeout: options.idleTimeout ? parseInt(options.idleTimeout, 10) : undefined,\n json: options.json,\n });\n },\n );\n\n// Parse arguments\nprogram.parse();\n","/**\n * Login Command\n *\n * Authenticates the user using OAuth Device Flow.\n * See ADR-0018 for details.\n */\n\nimport open from 'open';\nimport ora from 'ora';\nimport chalk from 'chalk';\nimport { api } from '../lib/api.js';\nimport { storeToken } from '../lib/keychain.js';\nimport { printSuccess, printError, blank, waitForEnter, sleep } from '../utils/ui.js';\n\ninterface DeviceAuthResponse {\n device_code: string;\n user_code: string;\n verification_uri: string;\n expires_in: number;\n interval: number;\n}\n\ninterface TokenPollResponse {\n status: 'pending' | 'complete' | 'expired';\n access_token?: string;\n expires_at?: string;\n user?: {\n id: string;\n email: string;\n };\n}\n\ninterface LoginOptions {\n token?: boolean;\n noBrowser?: boolean;\n}\n\n/**\n * Start device flow authentication\n */\nasync function deviceFlowLogin(options: LoginOptions): Promise<void> {\n // Step 1: Request device code\n let deviceAuth: DeviceAuthResponse;\n try {\n deviceAuth = await api.post<DeviceAuthResponse>('/auth/device');\n } catch (error) {\n const message = error instanceof Error ? error.message : 'Unknown error';\n printError(`Failed to start authentication: ${message}`);\n process.exit(1);\n }\n\n const { device_code, user_code, verification_uri, interval } = deviceAuth;\n\n // Step 2: Display instructions\n blank();\n console.log(chalk.bold('To authenticate, visit:'));\n console.log();\n console.log(` ${chalk.cyan(verification_uri)}`);\n console.log();\n console.log(chalk.bold('And enter this code:'));\n console.log();\n console.log(` ${chalk.yellow.bold(user_code)}`);\n blank();\n\n // Step 3: Open browser (unless --no-browser)\n if (!options.noBrowser) {\n await waitForEnter('Press Enter to open the browser...');\n try {\n await open(verification_uri);\n } catch {\n console.log(chalk.dim('Could not open browser. Please visit the URL manually.'));\n }\n }\n\n // Step 4: Poll for completion\n const spinner = ora('Waiting for authentication...').start();\n\n const pollIntervalMs = (interval || 5) * 1000;\n const maxAttempts = 60; // 5 minutes max at 5s intervals\n let attempts = 0;\n\n while (attempts < maxAttempts) {\n await sleep(pollIntervalMs);\n attempts++;\n\n try {\n const result = await api.post<TokenPollResponse>('/auth/device/token', {\n device_code,\n });\n\n if (result.status === 'complete' && result.access_token && result.user) {\n // Success! Store the token\n await storeToken({\n token: result.access_token,\n user: result.user,\n expiresAt: result.expires_at,\n });\n\n spinner.stop();\n blank();\n printSuccess(`Logged in as ${chalk.bold(result.user.email)}`);\n return;\n }\n\n if (result.status === 'expired') {\n spinner.stop();\n blank();\n printError('Authentication expired. Please try again.');\n process.exit(1);\n }\n\n // Still pending, continue polling\n } catch (error) {\n // Network error, continue polling\n const message = error instanceof Error ? error.message : 'Unknown error';\n spinner.text = `Waiting for authentication... (${message})`;\n }\n }\n\n spinner.stop();\n blank();\n printError('Authentication timed out. Please try again.');\n process.exit(1);\n}\n\n/**\n * Token-based login (for CI/CD)\n */\nasync function tokenLogin(): Promise<void> {\n console.log('Token login mode.');\n console.log('Visit your Evident dashboard to generate a CLI token.');\n blank();\n\n // Read token from stdin\n process.stdout.write('Paste token: ');\n\n const token = await new Promise<string>((resolve) => {\n let data = '';\n process.stdin.setEncoding('utf8');\n process.stdin.on('data', (chunk) => {\n data += chunk;\n });\n process.stdin.on('end', () => {\n resolve(data.trim());\n });\n // For TTY, read a single line\n if (process.stdin.isTTY) {\n process.stdin.once('data', (chunk) => {\n process.stdin.pause();\n resolve(chunk.toString().trim());\n });\n process.stdin.resume();\n }\n });\n\n if (!token) {\n printError('No token provided.');\n process.exit(1);\n }\n\n // Validate the token\n const spinner = ora('Validating token...').start();\n\n try {\n interface ValidateResponse {\n user: { id: string; email: string };\n expires_at?: string;\n }\n\n const result = await api.post<ValidateResponse>('/auth/token/validate', { token });\n\n await storeToken({\n token,\n user: result.user,\n expiresAt: result.expires_at,\n });\n\n spinner.stop();\n printSuccess(`Logged in as ${chalk.bold(result.user.email)}`);\n } catch (error) {\n spinner.stop();\n const message = error instanceof Error ? error.message : 'Invalid token';\n printError(`Authentication failed: ${message}`);\n process.exit(1);\n }\n}\n\n/**\n * Login command handler\n */\nexport async function login(options: LoginOptions): Promise<void> {\n if (options.token) {\n await tokenLogin();\n } else {\n await deviceFlowLogin(options);\n }\n}\n","/**\n * CLI Configuration\n *\n * Manages configuration values and file-based credential storage.\n * Supports multiple environments: local, dev, production\n */\n\nimport Conf from 'conf';\nimport { homedir } from 'node:os';\nimport { join } from 'node:path';\n\n// Supported environments\nexport type Environment = 'local' | 'dev' | 'production';\n\n// Configuration schema\ninterface ConfigSchema {\n apiUrl: string;\n tunnelUrl: string;\n}\n\n// Credentials schema (stored separately with stricter permissions)\ninterface CredentialsSchema {\n token?: string;\n user?: {\n id: string;\n email: string;\n };\n expiresAt?: string;\n}\n\n// Environment presets\n// Domain format: {service}.{env}.evident.run (with aliases for production)\n// API URLs include /v1 prefix as all endpoints are versioned\nconst environmentPresets: Record<Environment, ConfigSchema> = {\n local: {\n apiUrl: 'http://localhost:3001/v1',\n tunnelUrl: 'ws://localhost:8787',\n },\n dev: {\n apiUrl: 'https://api.dev.evident.run/v1',\n tunnelUrl: 'wss://tunnel.dev.evident.run',\n },\n production: {\n // Production URLs also have aliases: api.evident.run, tunnel.evident.run\n apiUrl: 'https://api.production.evident.run/v1',\n tunnelUrl: 'wss://tunnel.production.evident.run',\n },\n};\n\n// Default to production\nconst defaults: ConfigSchema = environmentPresets.production;\n\n// Current environment (can be set via --env flag or EVIDENT_ENV)\nlet currentEnvironment: Environment = 'production';\n\n/**\n * Set the current environment\n */\nexport function setEnvironment(env: Environment): void {\n currentEnvironment = env;\n}\n\n/**\n * Get the current environment\n */\nexport function getEnvironment(): Environment {\n // Environment variable takes precedence\n const envVar = process.env.EVIDENT_ENV as Environment | undefined;\n if (envVar && environmentPresets[envVar]) {\n return envVar;\n }\n return currentEnvironment;\n}\n\n/**\n * Get configuration for current environment\n */\nfunction getEnvConfig(): ConfigSchema {\n return environmentPresets[getEnvironment()];\n}\n\n// Environment overrides (env vars take highest precedence)\nfunction getApiUrl(): string {\n return process.env.EVIDENT_API_URL ?? getEnvConfig().apiUrl;\n}\n\nfunction getTunnelUrl(): string {\n return process.env.EVIDENT_TUNNEL_URL ?? getEnvConfig().tunnelUrl;\n}\n\n// Configuration store\nconst config = new Conf<ConfigSchema>({\n projectName: 'evident',\n projectSuffix: '',\n defaults,\n});\n\n// Credentials store (separate file with restricted access)\nconst credentials = new Conf<CredentialsSchema>({\n projectName: 'evident',\n projectSuffix: '',\n configName: 'credentials',\n defaults: {},\n});\n\n/**\n * Get the configuration directory path\n */\nexport function getConfigDir(): string {\n // XDG_CONFIG_HOME on Linux, ~/.config on others\n const xdgConfig = process.env.XDG_CONFIG_HOME;\n if (xdgConfig) {\n return join(xdgConfig, 'evident');\n }\n return join(homedir(), '.config', 'evident');\n}\n\n/**\n * Get the API URL\n */\nexport function getApiUrlConfig(): string {\n return getApiUrl();\n}\n\n/**\n * Get the tunnel WebSocket URL\n */\nexport function getTunnelUrlConfig(): string {\n return getTunnelUrl();\n}\n\n/**\n * Get stored credentials\n */\nexport function getCredentials(): CredentialsSchema {\n return {\n token: credentials.get('token'),\n user: credentials.get('user'),\n expiresAt: credentials.get('expiresAt'),\n };\n}\n\n/**\n * Store credentials\n */\nexport function setCredentials(creds: CredentialsSchema): void {\n if (creds.token) credentials.set('token', creds.token);\n if (creds.user) credentials.set('user', creds.user);\n if (creds.expiresAt) credentials.set('expiresAt', creds.expiresAt);\n}\n\n/**\n * Clear stored credentials\n */\nexport function clearCredentials(): void {\n credentials.clear();\n}\n\n/**\n * Check if we have valid credentials\n */\nexport function hasValidCredentials(): boolean {\n const creds = getCredentials();\n\n if (!creds.token) {\n return false;\n }\n\n if (creds.expiresAt) {\n const expiresAt = new Date(creds.expiresAt);\n if (expiresAt < new Date()) {\n return false;\n }\n }\n\n return true;\n}\n\n/**\n * Get the CLI command name based on how it was invoked.\n * Returns 'evident' for normal usage, or the actual invocation for dev/npx usage.\n */\nexport function getCliName(): string {\n // Check if running via npx - multiple detection methods\n // 1. npm_execpath contains npx\n // 2. npm_command is 'exec' (npx sets this)\n // 3. Running from a global npx cache directory\n const argv1 = process.argv[1] || '';\n const isNpx =\n process.env.npm_execpath?.includes('npx') ||\n process.env.npm_command === 'exec' ||\n argv1.includes('_npx') ||\n argv1.includes('.npm/_cacache');\n\n if (isNpx) {\n return 'npx @evident-ai/cli@latest';\n }\n\n // Check if running via tsx (development)\n if (argv1.includes('tsx') || argv1.includes('ts-node')) {\n return 'pnpm --filter @evident-ai/cli dev:run';\n }\n\n // Default to 'evident' for normal installed CLI\n return 'evident';\n}\n\nexport { config, credentials };\n","/**\n * API Client\n *\n * Handles HTTP requests to the Evident backend API.\n */\n\nimport { getApiUrlConfig, getCredentials } from './config.js';\n\ninterface ApiRequestOptions {\n method?: 'GET' | 'POST' | 'PUT' | 'DELETE' | 'PATCH';\n body?: unknown;\n headers?: Record<string, string>;\n authenticated?: boolean;\n}\n\ninterface ApiError {\n message: string;\n statusCode: number;\n error?: string;\n}\n\nexport class ApiClient {\n private baseUrl: string;\n\n constructor(baseUrl?: string) {\n this.baseUrl = baseUrl ?? getApiUrlConfig();\n }\n\n /**\n * Make an API request\n */\n async request<T>(path: string, options: ApiRequestOptions = {}): Promise<T> {\n const { method = 'GET', body, headers = {}, authenticated = false } = options;\n\n const url = `${this.baseUrl}${path}`;\n\n const requestHeaders: Record<string, string> = {\n 'Content-Type': 'application/json',\n ...headers,\n };\n\n // Add authentication header if requested\n if (authenticated) {\n const creds = getCredentials();\n if (!creds.token) {\n throw new Error('Not authenticated. Run the `login` command first.');\n }\n requestHeaders['Authorization'] = `Bearer ${creds.token}`;\n }\n\n const response = await fetch(url, {\n method,\n headers: requestHeaders,\n body: body ? JSON.stringify(body) : undefined,\n });\n\n // Handle errors\n if (!response.ok) {\n let errorData: ApiError;\n try {\n errorData = (await response.json()) as ApiError;\n } catch {\n errorData = {\n message: response.statusText,\n statusCode: response.status,\n };\n }\n\n const error = new Error(errorData.message) as Error & { statusCode: number };\n error.statusCode = response.status;\n throw error;\n }\n\n // Handle empty responses\n const contentType = response.headers.get('Content-Type');\n if (!contentType?.includes('application/json')) {\n return {} as T;\n }\n\n return response.json() as Promise<T>;\n }\n\n /**\n * GET request\n */\n async get<T>(path: string, options: Omit<ApiRequestOptions, 'method' | 'body'> = {}): Promise<T> {\n return this.request<T>(path, { ...options, method: 'GET' });\n }\n\n /**\n * POST request\n */\n async post<T>(\n path: string,\n body?: unknown,\n options: Omit<ApiRequestOptions, 'method'> = {},\n ): Promise<T> {\n return this.request<T>(path, { ...options, method: 'POST', body });\n }\n\n /**\n * PUT request\n */\n async put<T>(\n path: string,\n body?: unknown,\n options: Omit<ApiRequestOptions, 'method'> = {},\n ): Promise<T> {\n return this.request<T>(path, { ...options, method: 'PUT', body });\n }\n\n /**\n * DELETE request\n */\n async delete<T>(\n path: string,\n options: Omit<ApiRequestOptions, 'method' | 'body'> = {},\n ): Promise<T> {\n return this.request<T>(path, { ...options, method: 'DELETE' });\n }\n}\n\n// Lazy API client instance - created on first use after env is set\nlet _api: ApiClient | null = null;\nexport const api = {\n get<T>(path: string, options?: Parameters<ApiClient['get']>[1]) {\n if (!_api) _api = new ApiClient();\n return _api.get<T>(path, options);\n },\n post<T>(path: string, body?: unknown, options?: Parameters<ApiClient['post']>[2]) {\n if (!_api) _api = new ApiClient();\n return _api.post<T>(path, body, options);\n },\n put<T>(path: string, body?: unknown, options?: Parameters<ApiClient['put']>[2]) {\n if (!_api) _api = new ApiClient();\n return _api.put<T>(path, body, options);\n },\n delete<T>(path: string, options?: Parameters<ApiClient['delete']>[1]) {\n if (!_api) _api = new ApiClient();\n return _api.delete<T>(path, options);\n },\n};\n","/**\n * Keychain Storage\n *\n * Provides secure credential storage using the system keychain.\n * Falls back to file-based storage if keychain is unavailable.\n */\n\nimport { getCredentials, setCredentials, clearCredentials } from './config.js';\n\nconst SERVICE_NAME = 'evident-cli';\nconst ACCOUNT_NAME = 'default';\n\n// Dynamic import for keytar (optional dependency)\nasync function getKeytar(): Promise<typeof import('keytar') | null> {\n try {\n const keytar = await import('keytar');\n // Verify keytar is actually functional (has the expected methods)\n if (typeof keytar.setPassword !== 'function') {\n return null;\n }\n return keytar;\n } catch {\n // keytar not available (e.g., missing native dependencies)\n return null;\n }\n}\n\nexport interface StoredCredentials {\n token: string;\n user: {\n id: string;\n email: string;\n };\n expiresAt?: string;\n}\n\n/**\n * Store credentials in the system keychain\n */\nexport async function storeToken(credentials: StoredCredentials): Promise<void> {\n const keytar = await getKeytar();\n\n if (keytar) {\n // Store in system keychain\n await keytar.setPassword(SERVICE_NAME, ACCOUNT_NAME, JSON.stringify(credentials));\n } else {\n // Fallback to file-based storage\n setCredentials({\n token: credentials.token,\n user: credentials.user,\n expiresAt: credentials.expiresAt,\n });\n }\n}\n\n/**\n * Retrieve credentials from the system keychain\n */\nexport async function getToken(): Promise<StoredCredentials | null> {\n const keytar = await getKeytar();\n\n if (keytar) {\n // Try system keychain first\n const stored = await keytar.getPassword(SERVICE_NAME, ACCOUNT_NAME);\n if (stored) {\n try {\n return JSON.parse(stored) as StoredCredentials;\n } catch {\n // Invalid JSON, clear it\n await keytar.deletePassword(SERVICE_NAME, ACCOUNT_NAME);\n return null;\n }\n }\n }\n\n // Fallback to file-based storage\n const creds = getCredentials();\n if (creds.token && creds.user) {\n return {\n token: creds.token,\n user: creds.user,\n expiresAt: creds.expiresAt,\n };\n }\n\n return null;\n}\n\n/**\n * Delete credentials from the system keychain\n */\nexport async function deleteToken(): Promise<void> {\n const keytar = await getKeytar();\n\n if (keytar) {\n await keytar.deletePassword(SERVICE_NAME, ACCOUNT_NAME);\n }\n\n // Always clear file-based storage too\n clearCredentials();\n}\n\n/**\n * Check if credentials are valid (not expired)\n */\nexport async function hasValidToken(): Promise<boolean> {\n const credentials = await getToken();\n\n if (!credentials) {\n return false;\n }\n\n if (credentials.expiresAt) {\n const expiresAt = new Date(credentials.expiresAt);\n if (expiresAt < new Date()) {\n return false;\n }\n }\n\n return true;\n}\n","/**\n * CLI UI Utilities\n *\n * Common formatting and display functions.\n */\n\nimport chalk from 'chalk';\n\n/**\n * Format success message\n */\nexport function success(message: string): string {\n return `${chalk.green('✓')} ${message}`;\n}\n\n/**\n * Format error message\n */\nexport function error(message: string): string {\n return `${chalk.red('✗')} ${message}`;\n}\n\n/**\n * Format warning message\n */\nexport function warning(message: string): string {\n return `${chalk.yellow('!')} ${message}`;\n}\n\n/**\n * Format info message\n */\nexport function info(message: string): string {\n return `${chalk.blue('i')} ${message}`;\n}\n\n/**\n * Print success message\n */\nexport function printSuccess(message: string): void {\n console.log(success(message));\n}\n\n/**\n * Print error message\n */\nexport function printError(message: string): void {\n console.error(error(message));\n}\n\n/**\n * Print warning message\n */\nexport function printWarning(message: string): void {\n console.log(warning(message));\n}\n\n/**\n * Print info message\n */\nexport function printInfo(message: string): void {\n console.log(info(message));\n}\n\n/**\n * Format a key-value pair for display\n */\nexport function keyValue(key: string, value: string): string {\n return `${chalk.dim(key + ':')} ${value}`;\n}\n\n/**\n * Print a blank line\n */\nexport function blank(): void {\n console.log();\n}\n\n/**\n * Wait for user to press Enter\n */\nexport function waitForEnter(prompt = 'Press Enter to continue...'): Promise<void> {\n return new Promise((resolve) => {\n process.stdout.write(chalk.dim(prompt));\n\n const handler = (): void => {\n process.stdin.removeListener('data', handler);\n process.stdin.setRawMode?.(false);\n process.stdin.pause();\n console.log();\n resolve();\n };\n\n if (process.stdin.isTTY) {\n process.stdin.setRawMode?.(true);\n }\n process.stdin.resume();\n process.stdin.once('data', handler);\n });\n}\n\n/**\n * Sleep for a given number of milliseconds\n */\nexport function sleep(ms: number): Promise<void> {\n return new Promise((resolve) => setTimeout(resolve, ms));\n}\n","/**\n * Logout Command\n *\n * Removes stored credentials.\n */\n\nimport { deleteToken, getToken } from '../lib/keychain.js';\nimport { printSuccess, printWarning } from '../utils/ui.js';\n\n/**\n * Logout command handler\n */\nexport async function logout(): Promise<void> {\n const credentials = await getToken();\n\n if (!credentials) {\n printWarning('You are not logged in.');\n return;\n }\n\n await deleteToken();\n printSuccess('Logged out successfully.');\n}\n","/**\n * Whoami Command\n *\n * Displays the currently logged in user.\n */\n\nimport chalk from 'chalk';\nimport { getToken } from '../lib/keychain.js';\nimport { printError, keyValue, blank } from '../utils/ui.js';\n\n/**\n * Whoami command handler\n */\nexport async function whoami(): Promise<void> {\n const credentials = await getToken();\n\n if (!credentials) {\n printError('Not logged in. Run the `login` command to authenticate.');\n process.exit(1);\n }\n\n blank();\n console.log(keyValue('User', chalk.bold(credentials.user.email)));\n console.log(keyValue('User ID', credentials.user.id));\n\n if (credentials.expiresAt) {\n const expiresAt = new Date(credentials.expiresAt);\n const now = new Date();\n\n if (expiresAt < now) {\n console.log(keyValue('Status', chalk.red('Token expired')));\n } else {\n const daysRemaining = Math.ceil(\n (expiresAt.getTime() - now.getTime()) / (1000 * 60 * 60 * 24),\n );\n console.log(keyValue('Expires', `${daysRemaining} days`));\n }\n }\n\n blank();\n}\n","/**\n * Run Command\n *\n * Unified command that connects to Evident and processes messages.\n *\n * Usage:\n * evident run --agent <id> # Interactive mode\n * evident run --agent <id> --conversation <id> # Process single conversation\n * evident run --agent <id> --idle-timeout 30 # Exit after 30s idle\n *\n * Features:\n * - Connects tunnel to Evident\n * - Processes pending messages from queue\n * - Forwards incoming requests to local OpenCode\n * - Rich interactive UI when running interactively\n * - JSON output mode for CI/CD\n */\n\nimport { ChildProcess } from 'child_process';\nimport chalk from 'chalk';\nimport ora from 'ora';\nimport { select } from '@inquirer/prompts';\nimport { getApiUrlConfig, getCliName } from '../lib/config.js';\nimport { printError, blank } from '../utils/ui.js';\nimport {\n telemetry,\n EventTypes,\n shutdownTelemetry,\n emitAgentConnected,\n emitAgentDisconnected,\n emitAgentMessageProcessing,\n emitAgentMessageDone,\n emitAgentMessageFailed,\n} from '../lib/telemetry.js';\nimport {\n getAuthCredentials,\n getAuthHeader,\n isInteractive,\n getToken,\n type AuthCredentials,\n} from '../lib/auth.js';\nimport {\n checkOpenCodeHealth,\n waitForOpenCodeHealth,\n startOpenCode,\n stopOpenCode,\n findHealthyOpenCodeInstances,\n isPortInUse,\n findAvailablePort,\n isOpenCodeInstalled,\n promptOpenCodeInstall,\n createOpenCodeSession,\n sendMessageToOpenCode,\n type OpenCodeQuestion,\n type OpenCodePermission,\n} from '../lib/opencode/index.js';\nimport { connectTunnel, getReconnectDelay, type TunnelConnection } from '../lib/tunnel/index.js';\nimport { login } from './login.js';\n\n// ============================================================================\n// Types\n// ============================================================================\n\nexport interface RunOptions {\n agent?: string;\n port?: number;\n verbose?: boolean;\n conversation?: string;\n idleTimeout?: number;\n json?: boolean;\n}\n\ninterface ActivityLogEntry {\n timestamp: Date;\n type: 'request' | 'response' | 'error' | 'info';\n method?: string;\n path?: string;\n status?: number;\n durationMs?: number;\n error?: string;\n message?: string;\n requestId?: string;\n}\n\ninterface RunState {\n agentId: string;\n agentName: string | null;\n port: number;\n verbose: boolean;\n conversationFilter: string | null;\n idleTimeout: number | null;\n json: boolean;\n interactive: boolean;\n\n // Connection state\n connected: boolean;\n opencodeConnected: boolean;\n opencodeVersion: string | null;\n reconnectAttempt: number;\n\n // Process management\n opencodeProcess: ChildProcess | null;\n tunnelConnection: TunnelConnection | null;\n running: boolean;\n\n // Activity tracking\n activityLog: ActivityLogEntry[];\n displayInitialized: boolean;\n lastActivity: Date;\n pendingRequests: Map<string, { startTime: number; method: string; path: string }>;\n\n // Queue processing\n sessions: Map<string, string>; // conversationId -> sessionId\n messageCount: number;\n\n // Lock management\n lockCorrelationId: string;\n lockedConversations: Set<string>;\n lockHeartbeatTimer: ReturnType<typeof setInterval> | null;\n\n // Reconnection management\n consecutiveFetchFailures: number;\n reconnecting: boolean;\n reconnectPromise: Promise<void> | null;\n\n // Authentication (mutable — updated on re-auth)\n authHeader: string;\n}\n\n// ============================================================================\n// Constants\n// ============================================================================\n\nconst MAX_ACTIVITY_LOG_ENTRIES = 10;\nconst MESSAGE_POLL_INTERVAL_MS = 2000;\nconst MAX_CONSECUTIVE_FETCH_FAILURES = 3;\nconst LOCK_HEARTBEAT_INTERVAL_MS = 5 * 60 * 1000; // 5 minutes\n\n// ============================================================================\n// API Calls\n// ============================================================================\n\ninterface AgentInfo {\n id: string;\n name: string;\n sandbox_type: 'local' | 'github_actions';\n status: string;\n}\n\ninterface PendingConversation {\n id: string;\n agent_id: string;\n opencode_session_id: string | null;\n pending_message_count: number;\n oldest_pending_at: string;\n}\n\ninterface QueuedMessage {\n id: string;\n thread_id: string;\n content: string;\n status: string;\n created_at: string;\n opencode_agent: string | null;\n opencode_model: string | null;\n}\n\n/**\n * Resolve the agent ID from an agent key via the /v1/me endpoint.\n * Only works when authenticated with EVIDENT_AGENT_KEY (agent_key auth type).\n */\nasync function resolveAgentIdFromKey(\n authHeader: string,\n): Promise<{ agent_id?: string; error?: string }> {\n const apiUrl = getApiUrlConfig();\n try {\n const response = await fetch(`${apiUrl}/me`, {\n headers: { Authorization: authHeader },\n });\n\n if (!response.ok) {\n return { error: `Failed to resolve agent from key: HTTP ${response.status}` };\n }\n\n const data = (await response.json()) as { auth_type: string; agent_id?: string };\n if (data.auth_type === 'agent_key' && data.agent_id) {\n return { agent_id: data.agent_id };\n }\n\n return {\n error:\n 'Cannot resolve agent ID: auth type is not agent_key. Please provide --agent explicitly.',\n };\n } catch (error) {\n const message = error instanceof Error ? error.message : 'Unknown error';\n return { error: `Failed to resolve agent from key: ${message}` };\n }\n}\n\n/**\n * Validate agent exists and get its info\n */\nasync function getAgentInfo(\n agentId: string,\n authHeader: string,\n): Promise<{ valid: boolean; agent?: AgentInfo; error?: string; authFailed?: boolean }> {\n const apiUrl = getApiUrlConfig();\n\n try {\n const response = await fetch(`${apiUrl}/agents/${agentId}`, {\n headers: { Authorization: authHeader },\n });\n\n if (response.status === 404) {\n return { valid: false, error: 'Agent not found' };\n }\n\n if (response.status === 401) {\n return { valid: false, error: 'Authentication failed', authFailed: true };\n }\n\n if (!response.ok) {\n return { valid: false, error: `API error: ${response.status}` };\n }\n\n const agent = (await response.json()) as AgentInfo;\n\n if (agent.sandbox_type !== 'local' && agent.sandbox_type !== 'github_actions') {\n return {\n valid: false,\n error: `Agent is type '${agent.sandbox_type}', must be 'local' or 'github_actions' for CLI connection`,\n };\n }\n\n return { valid: true, agent };\n } catch (error) {\n const message = error instanceof Error ? error.message : 'Unknown error';\n return { valid: false, error: `Failed to validate agent: ${message}` };\n }\n}\n\n/**\n * Custom error class for authentication failures\n * This allows queue processing to detect auth issues and handle them appropriately\n */\nclass AuthenticationError extends Error {\n constructor(message: string) {\n super(message);\n this.name = 'AuthenticationError';\n }\n}\n\n/**\n * Check if a response indicates an authentication failure\n */\nfunction checkAuthResponse(response: Response, context: string): void {\n if (response.status === 401 || response.status === 403) {\n throw new AuthenticationError(\n `Authentication failed during ${context}: HTTP ${response.status}. Your session may have expired.`,\n );\n }\n}\n\n/**\n * Get conversations with pending messages\n */\nasync function getPendingConversations(\n agentId: string,\n authHeader: string,\n conversationFilter?: string,\n): Promise<PendingConversation[]> {\n const apiUrl = getApiUrlConfig();\n const response = await fetch(`${apiUrl}/agents/${agentId}/conversations/pending`, {\n headers: { Authorization: authHeader },\n });\n\n checkAuthResponse(response, 'fetching pending conversations');\n\n if (!response.ok) {\n throw new Error(`Failed to get pending conversations: HTTP ${response.status}`);\n }\n\n const data = (await response.json()) as { conversations: PendingConversation[] };\n let conversations = data.conversations;\n\n // Filter by conversation ID if specified\n if (conversationFilter) {\n conversations = conversations.filter((c) => c.id === conversationFilter);\n }\n\n return conversations;\n}\n\n/**\n * Get pending messages for a conversation\n */\nasync function getPendingMessages(\n agentId: string,\n conversationId: string,\n authHeader: string,\n): Promise<QueuedMessage[]> {\n const apiUrl = getApiUrlConfig();\n const response = await fetch(\n `${apiUrl}/agents/${agentId}/threads/${conversationId}/messages?status=pending`,\n { headers: { Authorization: authHeader } },\n );\n\n checkAuthResponse(response, 'fetching pending messages');\n\n if (!response.ok) {\n throw new Error(`Failed to get messages: HTTP ${response.status}`);\n }\n\n return response.json() as Promise<QueuedMessage[]>;\n}\n\n/**\n * Mark a message as processing\n */\nasync function markMessageProcessing(\n agentId: string,\n conversationId: string,\n messageId: string,\n authHeader: string,\n): Promise<boolean> {\n const apiUrl = getApiUrlConfig();\n const response = await fetch(\n `${apiUrl}/agents/${agentId}/threads/${conversationId}/messages/${messageId}`,\n {\n method: 'PATCH',\n headers: { Authorization: authHeader, 'Content-Type': 'application/json' },\n body: JSON.stringify({ status: 'processing' }),\n },\n );\n\n checkAuthResponse(response, 'marking message as processing');\n\n return response.ok;\n}\n\n/**\n * Report a pending question or permission to the API so it can be surfaced\n * to the user via their connected channel (e.g. Slack).\n */\nasync function reportInteractiveEvent(\n agentId: string,\n conversationId: string,\n type: 'question' | 'permission',\n data: OpenCodeQuestion | OpenCodePermission,\n authHeader: string,\n): Promise<void> {\n const apiUrl = getApiUrlConfig();\n const response = await fetch(\n `${apiUrl}/agents/${agentId}/threads/${conversationId}/interactive-event`,\n {\n method: 'POST',\n headers: { Authorization: authHeader, 'Content-Type': 'application/json' },\n body: JSON.stringify({ type, data }),\n },\n );\n\n checkAuthResponse(response, 'reporting interactive event');\n\n if (!response.ok) {\n throw new Error(`Failed to report interactive event: HTTP ${response.status}`);\n }\n}\n\n/**\n * Mark a message as done\n */\nasync function markMessageDone(\n agentId: string,\n conversationId: string,\n messageId: string,\n authHeader: string,\n sessionId?: string,\n): Promise<void> {\n const apiUrl = getApiUrlConfig();\n const body: Record<string, unknown> = { status: 'done' };\n if (sessionId) {\n body.opencode_session_id = sessionId;\n }\n const response = await fetch(\n `${apiUrl}/agents/${agentId}/threads/${conversationId}/messages/${messageId}`,\n {\n method: 'PATCH',\n headers: { Authorization: authHeader, 'Content-Type': 'application/json' },\n body: JSON.stringify(body),\n },\n );\n\n checkAuthResponse(response, 'marking message as done');\n}\n\n/**\n * Mark a message as failed\n */\nasync function markMessageFailed(\n agentId: string,\n conversationId: string,\n messageId: string,\n authHeader: string,\n): Promise<void> {\n const apiUrl = getApiUrlConfig();\n const response = await fetch(\n `${apiUrl}/agents/${agentId}/threads/${conversationId}/messages/${messageId}`,\n {\n method: 'PATCH',\n headers: { Authorization: authHeader, 'Content-Type': 'application/json' },\n body: JSON.stringify({ status: 'failed' }),\n },\n );\n\n checkAuthResponse(response, 'marking message as failed');\n}\n\n/**\n * Acquire a lock on a conversation\n */\nasync function acquireConversationLock(\n agentId: string,\n conversationId: string,\n correlationId: string,\n authHeader: string,\n): Promise<{ acquired: boolean; error?: string }> {\n const apiUrl = getApiUrlConfig();\n try {\n const response = await fetch(`${apiUrl}/agents/${agentId}/threads/${conversationId}/lock`, {\n method: 'POST',\n headers: { Authorization: authHeader, 'Content-Type': 'application/json' },\n body: JSON.stringify({ correlation_id: correlationId }),\n });\n\n checkAuthResponse(response, 'acquiring conversation lock');\n\n if (response.status === 409) {\n return { acquired: false, error: 'Conversation already locked by another runner' };\n }\n\n if (!response.ok) {\n return { acquired: false, error: `Failed to acquire lock: HTTP ${response.status}` };\n }\n\n return { acquired: true };\n } catch (error) {\n if (error instanceof AuthenticationError) throw error;\n return { acquired: false, error: String(error) };\n }\n}\n\n/**\n * Extend a lock on a conversation (heartbeat)\n */\nasync function extendConversationLock(\n agentId: string,\n conversationId: string,\n correlationId: string,\n authHeader: string,\n): Promise<boolean> {\n const apiUrl = getApiUrlConfig();\n try {\n const response = await fetch(\n `${apiUrl}/agents/${agentId}/threads/${conversationId}/lock/extend`,\n {\n method: 'POST',\n headers: { Authorization: authHeader, 'Content-Type': 'application/json' },\n body: JSON.stringify({ correlation_id: correlationId }),\n },\n );\n return response.ok;\n } catch {\n return false;\n }\n}\n\n/**\n * Release a lock on a conversation\n */\nasync function releaseConversationLock(\n agentId: string,\n conversationId: string,\n correlationId: string,\n authHeader: string,\n): Promise<void> {\n const apiUrl = getApiUrlConfig();\n try {\n await fetch(\n `${apiUrl}/agents/${agentId}/threads/${conversationId}/lock?correlation_id=${encodeURIComponent(correlationId)}`,\n {\n method: 'DELETE',\n headers: { Authorization: authHeader },\n },\n );\n } catch {\n // Best effort — don't fail on lock release errors\n }\n}\n\n/**\n * Update conversation with OpenCode session ID\n */\nasync function updateConversationSession(\n agentId: string,\n conversationId: string,\n sessionId: string,\n authHeader: string,\n): Promise<void> {\n const apiUrl = getApiUrlConfig();\n const response = await fetch(`${apiUrl}/agents/${agentId}/threads/${conversationId}`, {\n method: 'PATCH',\n headers: { Authorization: authHeader, 'Content-Type': 'application/json' },\n body: JSON.stringify({ opencode_session_id: sessionId }),\n });\n\n checkAuthResponse(response, 'updating conversation session');\n if (!response.ok) {\n const text = await response.text().catch(() => '');\n throw new Error(\n `Failed to update conversation session: HTTP ${response.status}${text ? `: ${text}` : ''}`,\n );\n }\n}\n\n/**\n * Update conversation title from OpenCode session\n */\nasync function updateConversationTitle(\n agentId: string,\n conversationId: string,\n title: string,\n authHeader: string,\n): Promise<void> {\n const apiUrl = getApiUrlConfig();\n const response = await fetch(`${apiUrl}/agents/${agentId}/threads/${conversationId}`, {\n method: 'PATCH',\n headers: { Authorization: authHeader, 'Content-Type': 'application/json' },\n body: JSON.stringify({ title }),\n });\n\n checkAuthResponse(response, 'updating conversation title');\n}\n\n// ============================================================================\n// Logging\n// ============================================================================\n\nfunction log(state: RunState, message: string, isError = false): void {\n if (state.json) {\n console.log(\n JSON.stringify({\n timestamp: new Date().toISOString(),\n level: isError ? 'error' : 'info',\n message,\n }),\n );\n } else if (!state.interactive) {\n // Non-interactive, non-JSON: simple output\n const prefix = isError ? chalk.red('✗') : chalk.green('•');\n console.log(`${prefix} ${message}`);\n }\n // In interactive mode, we use the activity log instead\n}\n\nfunction logActivity(state: RunState, entry: Omit<ActivityLogEntry, 'timestamp'>): void {\n const fullEntry: ActivityLogEntry = {\n ...entry,\n timestamp: new Date(),\n };\n\n state.activityLog.push(fullEntry);\n\n if (state.activityLog.length > MAX_ACTIVITY_LOG_ENTRIES) {\n state.activityLog.shift();\n }\n\n state.lastActivity = fullEntry.timestamp;\n\n // In non-interactive mode, also log to console immediately\n if (!state.interactive) {\n if (entry.type === 'error') {\n log(state, entry.error ?? 'Unknown error', true);\n } else if (entry.type === 'info' && entry.message) {\n log(state, entry.message);\n }\n }\n}\n\n// ============================================================================\n// Display (Interactive Mode)\n// ============================================================================\n\nconst ANSI = {\n moveUp: (n: number) => `\\x1b[${n}A`,\n};\n\nconst STATUS_DISPLAY_HEIGHT = 22;\n\nfunction colorizeStatus(status: number): string {\n if (status >= 200 && status < 300) {\n return chalk.green(status.toString());\n } else if (status >= 300 && status < 400) {\n return chalk.yellow(status.toString());\n } else if (status >= 400 && status < 500) {\n return chalk.red(status.toString());\n } else if (status >= 500) {\n return chalk.bgRed.white(` ${status} `);\n }\n return status.toString();\n}\n\nfunction formatActivityEntry(entry: ActivityLogEntry): string {\n const time = entry.timestamp.toLocaleTimeString('en-US', {\n hour12: false,\n hour: '2-digit',\n minute: '2-digit',\n second: '2-digit',\n });\n\n switch (entry.type) {\n case 'request': {\n const duration = entry.durationMs ? ` (${entry.durationMs}ms)` : '';\n const status = entry.status ? ` -> ${colorizeStatus(entry.status)}` : ' ...';\n return ` ${chalk.dim(`[${time}]`)} ${chalk.cyan('<-')} ${entry.method} ${entry.path}${status}${duration}`;\n }\n\n case 'response': {\n const duration = entry.durationMs ? ` (${entry.durationMs}ms)` : '';\n return ` ${chalk.dim(`[${time}]`)} ${chalk.green('->')} ${entry.method} ${entry.path} ${colorizeStatus(entry.status!)}${duration}`;\n }\n\n case 'error': {\n const errorMsg = entry.error || 'Unknown error';\n const path = entry.path ? ` ${entry.method} ${entry.path}` : '';\n return ` ${chalk.dim(`[${time}]`)} ${chalk.red('x')}${path} - ${chalk.red(errorMsg)}`;\n }\n\n case 'info': {\n return ` ${chalk.dim(`[${time}]`)} ${chalk.blue('*')} ${entry.message}`;\n }\n\n default:\n return ` ${chalk.dim(`[${time}]`)} ${entry.message || 'Unknown'}`;\n }\n}\n\nfunction displayStatus(state: RunState): void {\n if (!state.interactive) return;\n\n const lines: string[] = [];\n\n // Header\n lines.push(chalk.bold('Evident'));\n lines.push(chalk.dim('-'.repeat(60)));\n lines.push('');\n\n // Agent info\n if (state.agentName) {\n lines.push(` Agent: ${state.agentName}`);\n }\n lines.push(` ID: ${state.agentId}`);\n if (state.conversationFilter) {\n lines.push(` Filter: conversation ${state.conversationFilter.slice(0, 8)}...`);\n }\n lines.push('');\n\n // Status indicators\n if (state.connected) {\n lines.push(` ${chalk.green('*')} Tunnel: ${chalk.green('Connected to Evident')}`);\n } else {\n if (state.reconnectAttempt > 0) {\n lines.push(\n ` ${chalk.yellow('o')} Tunnel: ${chalk.yellow(`Reconnecting... (attempt ${state.reconnectAttempt})`)}`,\n );\n } else {\n lines.push(` ${chalk.yellow('o')} Tunnel: ${chalk.yellow('Connecting...')}`);\n }\n }\n\n if (state.opencodeConnected) {\n const version = state.opencodeVersion ? `, v${state.opencodeVersion}` : '';\n lines.push(\n ` ${chalk.green('*')} OpenCode: ${chalk.green(`Running on port ${state.port}${version}`)}`,\n );\n } else {\n lines.push(` ${chalk.red('o')} OpenCode: ${chalk.red(`Not connected (port ${state.port})`)}`);\n }\n\n lines.push('');\n\n // Messages processed\n if (state.messageCount > 0) {\n lines.push(` Messages: ${state.messageCount} processed`);\n lines.push('');\n }\n\n // Activity log\n if (state.activityLog.length > 0) {\n lines.push(chalk.bold(' Activity:'));\n for (const entry of state.activityLog) {\n lines.push(formatActivityEntry(entry));\n }\n } else {\n lines.push(chalk.dim(' No activity yet. Waiting for requests...'));\n }\n\n lines.push('');\n lines.push(chalk.dim('-'.repeat(60)));\n\n if (state.verbose) {\n lines.push(chalk.dim(' Verbose mode: ON'));\n }\n\n lines.push('');\n lines.push(\n chalk.dim(` Tip: Run \\`opencode attach http://localhost:${state.port}\\` to see live activity`),\n );\n lines.push(chalk.dim(' Press Ctrl+C to disconnect'));\n\n while (lines.length < STATUS_DISPLAY_HEIGHT) {\n lines.push('');\n }\n\n if (!state.displayInitialized) {\n console.log('');\n console.log(chalk.dim('='.repeat(60)));\n console.log('');\n for (const line of lines) {\n console.log(line);\n }\n state.displayInitialized = true;\n } else {\n process.stdout.write(ANSI.moveUp(STATUS_DISPLAY_HEIGHT + 3));\n console.log(chalk.dim('='.repeat(60)));\n console.log('');\n for (const line of lines) {\n process.stdout.write('\\x1b[2K');\n console.log(line);\n }\n }\n}\n\n// ============================================================================\n// Authentication Helpers\n// ============================================================================\n\nasync function promptForLogin(\n promptMessage: string,\n successMessage: string,\n): Promise<AuthCredentials> {\n const action = await select({\n message: promptMessage,\n choices: [\n {\n name: 'Yes, log me in',\n value: 'login',\n description: 'Opens a browser to authenticate with Evident',\n },\n {\n name: 'No, exit',\n value: 'exit',\n description: 'Exit without logging in',\n },\n ],\n });\n\n if (action === 'exit') {\n console.log(chalk.dim(`\\nYou can log in later by running: ${getCliName()} login`));\n process.exit(0);\n }\n\n await login({ noBrowser: false });\n\n const credentials = await getToken();\n if (!credentials) {\n printError('Login failed. Please try again.');\n process.exit(1);\n }\n\n blank();\n console.log(chalk.green(successMessage));\n blank();\n\n return { token: credentials.token, authType: 'bearer', user: credentials.user };\n}\n\n// ============================================================================\n// OpenCode Setup\n// ============================================================================\n\nasync function ensureOpenCodeRunning(state: RunState): Promise<void> {\n const healthCheck = await checkOpenCodeHealth(state.port);\n\n if (healthCheck.healthy) {\n state.opencodeConnected = true;\n state.opencodeVersion = healthCheck.version ?? null;\n return;\n }\n\n // Check if running on different port\n const runningInstances = await findHealthyOpenCodeInstances();\n\n if (runningInstances.length > 0) {\n if (!state.interactive) {\n throw new Error(\n `OpenCode not found on port ${state.port}, but running on port ${runningInstances[0].port}. ` +\n `Use --port ${runningInstances[0].port}`,\n );\n }\n\n blank();\n console.log(chalk.yellow('Found OpenCode running on different port(s):'));\n for (const instance of runningInstances) {\n const ver = instance.version ? ` (v${instance.version})` : '';\n const cwd = instance.cwd ? ` in ${instance.cwd}` : '';\n console.log(chalk.dim(` * Port ${instance.port}${ver}${cwd}`));\n }\n blank();\n\n if (runningInstances.length === 1) {\n console.log(chalk.yellow('Tip: Run with the correct port:'));\n console.log(\n chalk.dim(\n ` ${getCliName()} run --agent ${state.agentId} --port ${runningInstances[0].port}`,\n ),\n );\n }\n blank();\n throw new Error(`OpenCode not running on port ${state.port}`);\n }\n\n // OpenCode not running anywhere\n if (!isOpenCodeInstalled()) {\n if (!state.interactive) {\n throw new Error('OpenCode is not installed. Install it with: npm install -g opencode-ai');\n }\n\n const result = await promptOpenCodeInstall(true);\n if (result === 'exit') {\n process.exit(0);\n }\n\n if (result === 'installed' || isOpenCodeInstalled()) {\n // Try to start it\n } else {\n throw new Error('OpenCode is not installed');\n }\n }\n\n // Offer to start OpenCode\n if (state.interactive) {\n // Check if port is in use\n let actualPort = state.port;\n if (isPortInUse(state.port)) {\n console.log(chalk.yellow(`\\nPort ${state.port} is already in use.`));\n const alternativePort = findAvailablePort(state.port + 1);\n if (alternativePort) {\n const useAlternative = await select({\n message: `Use port ${alternativePort} instead?`,\n choices: [\n { name: `Yes, use port ${alternativePort}`, value: 'yes' },\n { name: 'No, I will free the port manually', value: 'no' },\n ],\n });\n if (useAlternative === 'yes') {\n actualPort = alternativePort;\n state.port = actualPort;\n } else {\n throw new Error(`Port ${state.port} is in use`);\n }\n }\n }\n\n const action = await select({\n message: 'OpenCode is not running. What would you like to do?',\n choices: [\n {\n name: 'Start OpenCode for me',\n value: 'start',\n description: `Run 'opencode serve --port ${actualPort}'`,\n },\n {\n name: 'Show me the command',\n value: 'manual',\n description: 'Display the command to run manually',\n },\n {\n name: 'Continue without OpenCode',\n value: 'continue',\n description: 'Requests will fail until OpenCode starts',\n },\n ],\n });\n\n if (action === 'manual') {\n blank();\n console.log(chalk.bold('Run this command in another terminal:'));\n blank();\n console.log(` ${chalk.cyan(`opencode serve --port ${actualPort}`)}`);\n blank();\n throw new Error('Please start OpenCode manually');\n }\n\n if (action === 'start') {\n const spinner = ora('Starting OpenCode...').start();\n state.opencodeProcess = await startOpenCode(actualPort);\n const health = await waitForOpenCodeHealth(actualPort, 30000);\n\n if (!health.healthy) {\n spinner.fail('Failed to start OpenCode');\n throw new Error('OpenCode failed to start');\n }\n\n spinner.succeed(\n `OpenCode running on port ${actualPort}${health.version ? ` (v${health.version})` : ''}`,\n );\n state.opencodeConnected = true;\n state.opencodeVersion = health.version ?? null;\n }\n } else {\n // Non-interactive: fail\n throw new Error(\n `OpenCode is not running on port ${state.port}. Start it with: opencode serve --port ${state.port}`,\n );\n }\n}\n\n// ============================================================================\n// Queue Processing\n// ============================================================================\n\n/** Exit code for authentication expiration in non-interactive mode */\nconst AUTH_EXPIRED_EXIT_CODE = 77;\n\n/**\n * Result of handling an authentication error\n */\ninterface AuthErrorResult {\n /** Whether authentication was successfully refreshed */\n success: boolean;\n /** New auth header if re-authenticated */\n newAuthHeader?: string;\n}\n\n/**\n * Handle authentication errors during queue processing.\n * In interactive mode, prompts for re-authentication.\n * In non-interactive mode, exits with a specific exit code.\n */\nasync function handleAuthError(\n state: RunState,\n error: AuthenticationError,\n): Promise<AuthErrorResult> {\n logActivity(state, {\n type: 'error',\n error: error.message,\n });\n if (state.interactive) displayStatus(state);\n\n if (!state.interactive) {\n // Non-interactive mode: log clear message and exit\n blank();\n console.log(chalk.red('Authentication expired'));\n console.log(chalk.dim('Your authentication token is no longer valid.'));\n blank();\n console.log(chalk.dim('To fix this:'));\n console.log(chalk.dim(` 1. Run '${getCliName()} login' to re-authenticate`));\n console.log(chalk.dim(' 2. Restart this command'));\n blank();\n await cleanup(state);\n await shutdownTelemetry();\n process.exit(AUTH_EXPIRED_EXIT_CODE);\n // Return to prevent fallthrough when process.exit is mocked in tests\n return { success: false };\n }\n\n // Interactive mode: prompt for re-authentication\n blank();\n console.log(chalk.yellow('Your authentication has expired.'));\n blank();\n\n try {\n const credentials = await promptForLogin(\n 'Would you like to log in again?',\n 'Re-authenticated successfully! Resuming...',\n );\n\n const newAuthHeader = getAuthHeader(credentials);\n return { success: true, newAuthHeader };\n } catch {\n // User declined to re-authenticate or login failed\n return { success: false };\n }\n}\n\n/**\n * Check if an error is a network/fetch failure that might be recoverable\n * through reconnection (as opposed to a logic error)\n */\nfunction isNetworkError(error: unknown): boolean {\n if (error instanceof Error) {\n const message = error.message.toLowerCase();\n return (\n message.includes('fetch failed') ||\n message.includes('network') ||\n message.includes('econnrefused') ||\n message.includes('econnreset') ||\n message.includes('etimedout') ||\n message.includes('socket hang up')\n );\n }\n return false;\n}\n\nasync function processQueue(\n state: RunState,\n authHeader: string,\n triggerReconnect: () => Promise<void>,\n): Promise<void> {\n let idleStart: number | null = null;\n let currentAuthHeader = authHeader;\n\n while (state.running) {\n // Wait for any ongoing reconnection to complete\n if (state.reconnecting && state.reconnectPromise) {\n logActivity(state, {\n type: 'info',\n message: 'Waiting for tunnel reconnection...',\n });\n if (state.interactive) displayStatus(state);\n await state.reconnectPromise;\n }\n\n try {\n const conversations = await getPendingConversations(\n state.agentId,\n currentAuthHeader,\n state.conversationFilter ?? undefined,\n );\n\n // Reset consecutive failures on success\n state.consecutiveFetchFailures = 0;\n\n if (conversations.length > 0) {\n idleStart = null;\n\n for (const conv of conversations) {\n if (!state.running) break;\n\n // Acquire lock on the conversation before processing\n if (!state.lockedConversations.has(conv.id)) {\n const lockResult = await acquireConversationLock(\n state.agentId,\n conv.id,\n state.lockCorrelationId,\n currentAuthHeader,\n );\n if (!lockResult.acquired) {\n logActivity(state, {\n type: 'info',\n message: `Conversation ${conv.id.slice(0, 8)} locked by another runner — skipping`,\n });\n if (state.interactive) displayStatus(state);\n continue;\n }\n state.lockedConversations.add(conv.id);\n logActivity(state, {\n type: 'info',\n message: `Lock acquired on conversation ${conv.id.slice(0, 8)}`,\n });\n }\n\n logActivity(state, {\n type: 'info',\n message: `Processing conversation ${conv.id.slice(0, 8)}... (${conv.pending_message_count} pending)`,\n });\n if (state.interactive) displayStatus(state);\n\n // Get or create session\n let sessionId = state.sessions.get(conv.id);\n if (!sessionId) {\n if (conv.opencode_session_id) {\n sessionId = conv.opencode_session_id;\n } else {\n sessionId = await createOpenCodeSession(state.port);\n await updateConversationSession(state.agentId, conv.id, sessionId, currentAuthHeader);\n logActivity(state, {\n type: 'info',\n message: `Created session ${sessionId.slice(0, 8)}`,\n });\n }\n state.sessions.set(conv.id, sessionId);\n }\n\n // Process messages\n const messages = await getPendingMessages(state.agentId, conv.id, currentAuthHeader);\n\n for (const message of messages) {\n if (!state.running) break;\n\n logActivity(state, {\n type: 'info',\n message: `Processing message ${message.id.slice(0, 8)}...`,\n });\n if (state.interactive) displayStatus(state);\n\n const claimed = await markMessageProcessing(\n state.agentId,\n conv.id,\n message.id,\n currentAuthHeader,\n );\n if (!claimed) {\n logActivity(state, {\n type: 'info',\n message: `Message ${message.id.slice(0, 8)} already claimed`,\n });\n continue;\n }\n\n // Report to API for activity log (only after claim succeeds)\n emitAgentMessageProcessing(state.agentId, {\n message_id: message.id,\n conversation_id: conv.id,\n });\n\n try {\n const result = await sendMessageToOpenCode(\n state.port,\n sessionId,\n message.content,\n {\n agent: message.opencode_agent ?? undefined,\n model: message.opencode_model ?? undefined,\n },\n {\n onQuestion: async (question) => {\n try {\n await reportInteractiveEvent(\n state.agentId,\n conv.id,\n 'question',\n question,\n currentAuthHeader,\n );\n logActivity(state, {\n type: 'info',\n message: `Question surfaced to user (id: ${question.id.slice(0, 8)})`,\n });\n } catch (err) {\n logActivity(state, {\n type: 'error',\n error: `Failed to surface question: ${err}`,\n });\n }\n },\n onPermission: async (permission) => {\n try {\n await reportInteractiveEvent(\n state.agentId,\n conv.id,\n 'permission',\n permission,\n currentAuthHeader,\n );\n logActivity(state, {\n type: 'info',\n message: `Permission request surfaced to user (id: ${permission.id.slice(0, 8)})`,\n });\n } catch (err) {\n logActivity(state, {\n type: 'error',\n error: `Failed to surface permission: ${err}`,\n });\n }\n },\n },\n );\n\n // Sync OpenCode's session title to the conversation (best-effort)\n if (result.title) {\n try {\n await updateConversationTitle(\n state.agentId,\n conv.id,\n result.title,\n currentAuthHeader,\n );\n } catch {\n // Non-fatal: title sync failure should not fail the message\n }\n }\n await markMessageDone(\n state.agentId,\n conv.id,\n message.id,\n currentAuthHeader,\n sessionId,\n );\n state.messageCount++;\n logActivity(state, {\n type: 'info',\n message: `Message ${message.id.slice(0, 8)} processed`,\n });\n // Report to API for activity log\n emitAgentMessageDone(state.agentId, {\n message_id: message.id,\n conversation_id: conv.id,\n });\n } catch (error) {\n // Re-throw auth errors to be handled at the outer level\n if (error instanceof AuthenticationError) {\n throw error;\n }\n await markMessageFailed(state.agentId, conv.id, message.id, currentAuthHeader);\n logActivity(state, {\n type: 'error',\n error: `Message ${message.id.slice(0, 8)} failed: ${error}`,\n });\n // Report to API for activity log\n emitAgentMessageFailed(state.agentId, {\n message_id: message.id,\n conversation_id: conv.id,\n error: String(error),\n });\n }\n\n if (state.interactive) displayStatus(state);\n }\n }\n } else {\n // No pending messages\n if (state.idleTimeout !== null) {\n if (idleStart === null) {\n idleStart = Date.now();\n logActivity(state, {\n type: 'info',\n message: `Queue empty, waiting (timeout: ${state.idleTimeout}s)...`,\n });\n if (state.interactive) displayStatus(state);\n }\n\n if (Date.now() - idleStart > state.idleTimeout * 1000) {\n logActivity(state, {\n type: 'info',\n message: 'Idle timeout reached',\n });\n if (state.interactive) displayStatus(state);\n break;\n }\n }\n }\n\n await new Promise((resolve) => setTimeout(resolve, MESSAGE_POLL_INTERVAL_MS));\n } catch (error) {\n // Handle authentication errors specially\n if (error instanceof AuthenticationError) {\n const result = await handleAuthError(state, error);\n if (result.success && result.newAuthHeader) {\n currentAuthHeader = result.newAuthHeader;\n state.authHeader = result.newAuthHeader;\n logActivity(state, {\n type: 'info',\n message: 'Continuing with new credentials...',\n });\n if (state.interactive) displayStatus(state);\n continue; // Retry immediately with new credentials\n } else {\n // User declined re-auth, stop processing\n state.running = false;\n break;\n }\n }\n\n const errorMessage = error instanceof Error ? error.message : String(error);\n logActivity(state, {\n type: 'error',\n error: `Queue processing error: ${errorMessage}`,\n });\n if (state.interactive) displayStatus(state);\n\n // Track consecutive fetch failures to detect connection issues\n if (isNetworkError(error)) {\n state.consecutiveFetchFailures++;\n\n if (state.consecutiveFetchFailures >= MAX_CONSECUTIVE_FETCH_FAILURES) {\n logActivity(state, {\n type: 'info',\n message: `Detected ${state.consecutiveFetchFailures} consecutive fetch failures, triggering reconnection...`,\n });\n if (state.interactive) displayStatus(state);\n\n // Trigger reconnection\n await triggerReconnect();\n state.consecutiveFetchFailures = 0;\n }\n }\n\n await new Promise((resolve) => setTimeout(resolve, MESSAGE_POLL_INTERVAL_MS));\n }\n }\n}\n\n// ============================================================================\n// Cleanup\n// ============================================================================\n\nasync function cleanup(state: RunState, authHeader?: string): Promise<void> {\n state.running = false;\n\n // Stop lock heartbeat\n if (state.lockHeartbeatTimer) {\n clearInterval(state.lockHeartbeatTimer);\n state.lockHeartbeatTimer = null;\n }\n\n // Release all locks\n if (authHeader && state.lockedConversations.size > 0) {\n for (const convId of state.lockedConversations) {\n await releaseConversationLock(state.agentId, convId, state.lockCorrelationId, authHeader);\n }\n if (state.interactive) {\n logActivity(state, {\n type: 'info',\n message: `Released ${state.lockedConversations.size} lock(s)`,\n });\n displayStatus(state);\n } else {\n log(state, `Released ${state.lockedConversations.size} lock(s)`);\n }\n state.lockedConversations.clear();\n }\n\n if (state.tunnelConnection) {\n state.tunnelConnection.close();\n state.tunnelConnection = null;\n }\n\n if (state.opencodeProcess) {\n stopOpenCode(state.opencodeProcess);\n if (state.interactive) {\n logActivity(state, { type: 'info', message: 'Stopped OpenCode process' });\n displayStatus(state);\n } else {\n log(state, 'Stopped OpenCode process');\n }\n state.opencodeProcess = null;\n }\n}\n\n// ============================================================================\n// Main Command Handler\n// ============================================================================\n\nexport async function run(options: RunOptions): Promise<void> {\n const interactive = isInteractive(options.json);\n\n // Initialize state\n const state: RunState = {\n agentId: options.agent || '',\n agentName: null,\n port: options.port ?? 4096,\n verbose: options.verbose ?? false,\n conversationFilter: options.conversation ?? null,\n idleTimeout: options.idleTimeout ?? null,\n json: options.json ?? false,\n interactive,\n\n connected: false,\n opencodeConnected: false,\n opencodeVersion: null,\n reconnectAttempt: 0,\n\n opencodeProcess: null,\n tunnelConnection: null,\n running: true,\n\n activityLog: [],\n displayInitialized: false,\n lastActivity: new Date(),\n pendingRequests: new Map(),\n\n sessions: new Map(),\n messageCount: 0,\n\n lockCorrelationId: `cli-${Date.now()}-${Math.random().toString(36).slice(2, 8)}`,\n lockedConversations: new Set(),\n lockHeartbeatTimer: null,\n\n consecutiveFetchFailures: 0,\n reconnecting: false,\n reconnectPromise: null,\n\n authHeader: '',\n };\n\n if (state.idleTimeout === null && (process.env.GITHUB_ACTIONS || process.env.CI)) {\n log(\n state,\n 'Warning: No --idle-timeout set in CI environment. The runner will poll indefinitely until the job times out. Consider adding --idle-timeout 30 to avoid wasting runner minutes.',\n false,\n );\n }\n\n // Set up cleanup handlers\n const handleSignal = async () => {\n if (state.interactive) {\n logActivity(state, { type: 'info', message: 'Shutting down...' });\n displayStatus(state);\n } else {\n log(state, 'Shutting down...');\n }\n await cleanup(state, state.authHeader);\n await shutdownTelemetry();\n process.exit(0);\n };\n\n process.on('SIGINT', handleSignal);\n process.on('SIGTERM', handleSignal);\n\n try {\n // Step 1: Authenticate\n let credentials = await getAuthCredentials();\n\n if (!credentials) {\n if (!interactive) {\n printError('Authentication required');\n blank();\n console.log(chalk.dim('Set EVIDENT_AGENT_KEY environment variable for CI'));\n console.log(chalk.dim('Or run `evident login` for interactive authentication'));\n blank();\n process.exit(1);\n }\n\n blank();\n console.log(chalk.yellow('You are not logged in to Evident.'));\n blank();\n\n credentials = await promptForLogin(\n 'Would you like to log in now?',\n 'Login successful! Continuing...',\n );\n }\n\n state.authHeader = getAuthHeader(credentials);\n\n // Resolve agent ID from key if not provided explicitly\n if (!state.agentId) {\n if (credentials.authType === 'agent_key') {\n const resolved = await resolveAgentIdFromKey(state.authHeader);\n if (resolved.agent_id) {\n state.agentId = resolved.agent_id;\n log(state, `Resolved agent ID from key: ${state.agentId}`);\n } else {\n printError(resolved.error || 'Failed to resolve agent ID from key');\n process.exit(1);\n }\n } else {\n printError('--agent is required when not using EVIDENT_AGENT_KEY');\n blank();\n console.log(chalk.dim('Either provide --agent <id> or set EVIDENT_AGENT_KEY'));\n blank();\n process.exit(1);\n }\n }\n\n telemetry.info(\n EventTypes.CLI_COMMAND,\n 'Starting run command',\n {\n command: 'run',\n agentId: state.agentId,\n port: state.port,\n conversationFilter: state.conversationFilter,\n interactive,\n },\n state.agentId,\n );\n\n // Step 2: Validate agent\n if (interactive && !state.json) {\n blank();\n console.log(chalk.bold('Evident Run'));\n console.log(chalk.dim('-'.repeat(40)));\n }\n\n const spinner = interactive && !state.json ? ora('Validating agent...').start() : null;\n let validation = await getAgentInfo(state.agentId, state.authHeader);\n\n if (!validation.valid && validation.authFailed && interactive) {\n spinner?.fail('Authentication failed');\n blank();\n console.log(chalk.yellow('Your authentication token is invalid or expired.'));\n blank();\n\n credentials = await promptForLogin(\n 'Would you like to log in again?',\n 'Login successful! Retrying...',\n );\n\n state.authHeader = getAuthHeader(credentials);\n spinner?.start('Validating agent...');\n validation = await getAgentInfo(state.agentId, state.authHeader);\n }\n\n if (!validation.valid) {\n spinner?.fail(`Agent validation failed: ${validation.error}`);\n throw new Error(validation.error);\n }\n\n spinner?.succeed(`Agent: ${validation.agent!.name || state.agentId}`);\n state.agentName = validation.agent!.name;\n\n // Step 3: Ensure OpenCode is running\n const ocSpinner = interactive && !state.json ? ora('Checking OpenCode...').start() : null;\n\n try {\n await ensureOpenCodeRunning(state);\n const version = state.opencodeVersion ? ` (v${state.opencodeVersion})` : '';\n ocSpinner?.succeed(`OpenCode running on port ${state.port}${version}`);\n } catch (error) {\n ocSpinner?.fail((error as Error).message);\n throw error;\n }\n\n // Step 4: Connect tunnel\n const tunnelSpinner = interactive && !state.json ? ora('Connecting tunnel...').start() : null;\n\n /**\n * Connect to the tunnel with retry logic.\n * Can be called for initial connection or for reconnection after disconnect.\n * @param isReconnect - Whether this is a reconnection attempt (vs initial connection)\n */\n const connectWithRetry = async (isReconnect = false): Promise<void> => {\n // Prevent multiple simultaneous reconnection attempts\n if (isReconnect && state.reconnecting) {\n return;\n }\n\n state.reconnecting = true;\n\n // Close existing connection if any\n if (state.tunnelConnection) {\n try {\n state.tunnelConnection.close();\n } catch {\n // Ignore close errors\n }\n state.tunnelConnection = null;\n }\n\n while (state.running) {\n try {\n state.tunnelConnection = await connectTunnel({\n agentId: state.agentId,\n authHeader: state.authHeader,\n port: state.port,\n onConnected: (agentId) => {\n state.connected = true;\n state.reconnectAttempt = 0;\n state.reconnecting = false;\n state.consecutiveFetchFailures = 0;\n // Update state with server-resolved agent ID for consistency\n state.agentId = agentId;\n logActivity(state, {\n type: 'info',\n message: isReconnect\n ? `Tunnel reconnected (agent: ${agentId})`\n : `Tunnel connected (agent: ${agentId})`,\n });\n // Report to API for activity log\n emitAgentConnected(state.agentId, { port: state.port });\n if (state.interactive) displayStatus(state);\n },\n onDisconnected: (code, reason) => {\n state.connected = false;\n logActivity(state, {\n type: 'info',\n message: `Tunnel disconnected (code: ${code}, reason: ${reason})`,\n });\n // Report to API for activity log\n emitAgentDisconnected(state.agentId, { code, reason });\n if (state.interactive) displayStatus(state);\n\n // Auto-reconnect on unexpected disconnection (not manual shutdown)\n // Code 1000 = normal closure, 1001 = going away (expected)\n // Other codes indicate unexpected disconnection\n // Also skip if reconnection is already in progress (e.g., from fetch failures)\n if (state.running && code !== 1000 && !state.reconnecting) {\n logActivity(state, {\n type: 'info',\n message: 'Attempting automatic reconnection...',\n });\n if (state.interactive) displayStatus(state);\n\n // Trigger reconnection asynchronously\n state.reconnectPromise = connectWithRetry(true).catch((err) => {\n logActivity(state, {\n type: 'error',\n error: `Reconnection failed: ${err.message}`,\n });\n if (state.interactive) displayStatus(state);\n });\n }\n },\n onError: (error) => {\n logActivity(state, { type: 'error', error });\n if (state.interactive) displayStatus(state);\n },\n onRequest: (method, path, requestId) => {\n state.pendingRequests.set(requestId, {\n startTime: Date.now(),\n method,\n path,\n });\n logActivity(state, { type: 'request', method, path, requestId });\n if (state.interactive) displayStatus(state);\n },\n onResponse: (status, durationMs, requestId) => {\n const pending = state.pendingRequests.get(requestId);\n state.pendingRequests.delete(requestId);\n state.opencodeConnected = true;\n\n const lastEntry = state.activityLog[state.activityLog.length - 1];\n if (lastEntry && lastEntry.requestId === requestId) {\n lastEntry.type = 'response';\n lastEntry.status = status;\n lastEntry.durationMs = durationMs;\n } else if (pending) {\n logActivity(state, {\n type: 'response',\n method: pending.method,\n path: pending.path,\n status,\n durationMs,\n requestId,\n });\n }\n if (state.interactive) displayStatus(state);\n },\n onInfo: (message) => {\n logActivity(state, { type: 'info', message });\n if (state.interactive) displayStatus(state);\n },\n });\n\n if (!isReconnect) {\n tunnelSpinner?.succeed('Tunnel connected');\n }\n return;\n } catch (error) {\n state.reconnectAttempt++;\n const delay = getReconnectDelay(state.reconnectAttempt);\n\n if ((error as Error).message === 'Unauthorized') {\n state.reconnecting = false;\n if (!isReconnect) {\n tunnelSpinner?.fail('Unauthorized');\n }\n throw error;\n }\n\n logActivity(state, {\n type: 'error',\n error: `Connection failed, retrying in ${Math.round(delay / 1000)}s...`,\n });\n if (state.interactive) displayStatus(state);\n\n await new Promise((resolve) => setTimeout(resolve, delay));\n }\n }\n\n state.reconnecting = false;\n };\n\n /**\n * Trigger reconnection from queue processing when fetch failures are detected.\n * Handles errors gracefully to avoid crashing processQueue.\n */\n const triggerReconnect = async (): Promise<void> => {\n if (!state.reconnecting) {\n state.reconnectPromise = connectWithRetry(true).catch((err) => {\n logActivity(state, {\n type: 'error',\n error: `Reconnection failed: ${err.message}`,\n });\n if (state.interactive) displayStatus(state);\n });\n }\n if (state.reconnectPromise) {\n await state.reconnectPromise;\n }\n };\n\n await connectWithRetry(false);\n\n // Step 5: Start lock heartbeat (extends locks every 5 minutes)\n state.lockHeartbeatTimer = setInterval(async () => {\n for (const convId of state.lockedConversations) {\n const extended = await extendConversationLock(\n state.agentId,\n convId,\n state.lockCorrelationId,\n state.authHeader,\n );\n if (!extended) {\n logActivity(state, {\n type: 'error',\n error: `Failed to extend lock on conversation ${convId.slice(0, 8)}`,\n });\n state.lockedConversations.delete(convId);\n }\n }\n }, LOCK_HEARTBEAT_INTERVAL_MS);\n\n // Step 6: Process queue and handle requests\n if (interactive && !state.json) {\n displayStatus(state);\n } else {\n log(state, 'Processing queue...');\n }\n\n await processQueue(state, state.authHeader, triggerReconnect);\n\n // Done\n await cleanup(state, state.authHeader);\n\n if (state.json) {\n console.log(\n JSON.stringify({\n status: 'success',\n messages_processed: state.messageCount,\n }),\n );\n } else if (!interactive) {\n log(state, `Completed. Processed ${state.messageCount} message(s).`);\n }\n\n await shutdownTelemetry();\n process.exit(0);\n } catch (error) {\n await cleanup(state, state.authHeader);\n\n const message = error instanceof Error ? error.message : String(error);\n\n if (state.json) {\n console.log(JSON.stringify({ status: 'error', error: message }));\n } else {\n printError(message);\n }\n\n telemetry.error(EventTypes.CLI_ERROR, `Run command failed: ${message}`, {\n command: 'run',\n agentId: options.agent,\n });\n await shutdownTelemetry();\n process.exit(1);\n }\n}\n","/**\n * Telemetry API types - shared between CLI and API\n *\n * These types define the contract for the telemetry endpoint.\n * Both CLI and API should use these types to ensure type safety.\n */\n\nimport { EventSeverity } from '../events/index.js';\n\n/** Client types that can send telemetry */\nexport type TelemetryClientType = 'cli' | 'sdk' | 'web';\n\n// ============================================================================\n// Event type constants\n// ============================================================================\n\nexport const TelemetryEventTypes = {\n // Agent activity events (shown in web UI activity log)\n AGENT_CONNECTED: 'agent.connected',\n AGENT_DISCONNECTED: 'agent.disconnected',\n AGENT_MESSAGE_PROCESSING: 'agent.message_processing',\n AGENT_MESSAGE_DONE: 'agent.message_done',\n AGENT_MESSAGE_FAILED: 'agent.message_failed',\n} as const;\n\nexport type TelemetryEventType = (typeof TelemetryEventTypes)[keyof typeof TelemetryEventTypes];\n\n// ============================================================================\n// Specific event types with typed metadata\n// ============================================================================\n\n/** Agent connected to Evident */\nexport interface AgentConnectedEvent {\n event_type: typeof TelemetryEventTypes.AGENT_CONNECTED;\n severity?: EventSeverity;\n message?: string;\n metadata: { port: number };\n agent_id: string;\n timestamp?: string;\n}\n\n/** Agent disconnected from Evident */\nexport interface AgentDisconnectedEvent {\n event_type: typeof TelemetryEventTypes.AGENT_DISCONNECTED;\n severity?: EventSeverity;\n message?: string;\n metadata: { code: number; reason: string };\n agent_id: string;\n timestamp?: string;\n}\n\n/** Agent started processing a message */\nexport interface AgentMessageProcessingEvent {\n event_type: typeof TelemetryEventTypes.AGENT_MESSAGE_PROCESSING;\n severity?: EventSeverity;\n message?: string;\n metadata: { message_id: string; conversation_id: string };\n agent_id: string;\n timestamp?: string;\n}\n\n/** Agent finished processing a message successfully */\nexport interface AgentMessageDoneEvent {\n event_type: typeof TelemetryEventTypes.AGENT_MESSAGE_DONE;\n severity?: EventSeverity;\n message?: string;\n metadata: { message_id: string; conversation_id: string };\n agent_id: string;\n timestamp?: string;\n}\n\n/** Agent failed to process a message */\nexport interface AgentMessageFailedEvent {\n event_type: typeof TelemetryEventTypes.AGENT_MESSAGE_FAILED;\n severity?: EventSeverity;\n message?: string;\n metadata: { message_id: string; conversation_id: string; reason?: string; error?: string };\n agent_id: string;\n timestamp?: string;\n}\n\n/** Union of all specific telemetry events */\nexport type TelemetryEvent =\n | AgentConnectedEvent\n | AgentDisconnectedEvent\n | AgentMessageProcessingEvent\n | AgentMessageDoneEvent\n | AgentMessageFailedEvent;\n\n// ============================================================================\n// Generic event type (for API validation - accepts any event)\n// ============================================================================\n\n/**\n * Generic telemetry event request (used by API for validation).\n * Clients should use specific event types above for type safety.\n */\nexport interface TelemetryEventRequest {\n event_type: string;\n severity?: EventSeverity;\n message?: string;\n metadata?: Record<string, unknown>;\n agent_id?: string;\n timestamp?: string;\n}\n\n// ============================================================================\n// Request/Response types\n// ============================================================================\n\n/**\n * Batch request to submit multiple telemetry events\n */\nexport interface SubmitTelemetryEventsRequest {\n events: TelemetryEventRequest[];\n client_type: TelemetryClientType;\n client_version?: string;\n}\n\n/**\n * Response from submitting telemetry events\n */\nexport interface SubmitTelemetryEventsResponse {\n received: number;\n}\n","/**\n * Tunnel types - shared between API, Tunnel Relay (Cloudflare Worker), and CLI\n *\n * These types define the protocol for the WebSocket tunnel that connects\n * local OpenCode instances to the Evident platform.\n */\n\n// ============================================================================\n// API <-> Relay communication\n// ============================================================================\n\n/**\n * Token validation response from API to Relay\n * Sent when CLI connects and Relay validates the token with the API\n */\nexport interface TunnelTokenValidationResponse {\n agent_id: string;\n user_id: string;\n}\n\n/**\n * Token validation request from Relay to API\n */\nexport interface TunnelTokenValidationRequest {\n token: string;\n agent_id: string;\n auth_type: 'bearer' | 'sandbox_key';\n}\n\n/**\n * Status update from Relay to API\n * Sent when CLI connects or disconnects\n */\nexport interface TunnelStatusUpdate {\n agent_id: string;\n status: 'connected' | 'disconnected';\n close_code?: number;\n close_reason?: string;\n}\n\n/**\n * Internal request from API to forward to tunnel\n */\nexport interface TunnelForwardRequest {\n request_id: string;\n method: string;\n path: string;\n headers?: Record<string, string>;\n body?: unknown;\n timeout_ms?: number;\n}\n\n// ============================================================================\n// Relay <-> CLI communication (WebSocket messages)\n// ============================================================================\n\n/**\n * Message types from Relay to CLI\n */\nexport type RelayToCLIMessage =\n | { type: 'connected'; agent_id: string }\n | { type: 'error'; code: string; message: string }\n | { type: 'ping' }\n | { type: 'request'; id: string; payload: TunnelRequestPayload }\n | { type: 'subscribe_events'; id: string }\n | { type: 'unsubscribe_events'; id: string };\n\n/**\n * HTTP request payload forwarded to CLI\n */\nexport interface TunnelRequestPayload {\n method: string;\n path: string;\n headers?: Record<string, string>;\n body?: unknown;\n}\n\n/**\n * Message types from CLI to Relay\n */\nexport type CLIToRelayMessage =\n | { type: 'pong' }\n | { type: 'response'; id: string; payload: TunnelResponsePayload }\n | {\n type: 'response_start';\n id: string;\n total_chunks: number;\n total_size: number;\n payload: Omit<TunnelResponsePayload, 'body'>;\n }\n | { type: 'response_chunk'; id: string; chunk_index: number; data: string }\n | { type: 'response_end'; id: string }\n | { type: 'status'; status: 'ready' | 'busy' }\n | { type: 'event'; id: string; event: unknown }\n | { type: 'event_error'; id: string; error: string }\n | { type: 'event_end'; id: string };\n\n/**\n * Response payload from CLI\n */\nexport interface TunnelResponsePayload {\n status: number;\n headers?: Record<string, string>;\n body?: unknown;\n}\n\n// ============================================================================\n// Internal Relay state\n// ============================================================================\n\n/**\n * Tunnel connection metadata stored in the Durable Object\n */\nexport interface TunnelMetadata {\n agent_id: string;\n user_id: string;\n connected_at: string;\n last_activity: string;\n}\n\n// Note: TunnelStatus is defined in agents/index.ts as 'connected' | 'disconnected' | null\n// We re-use that type for tunnel operations\n\n// ============================================================================\n// Protocol constants\n// ============================================================================\n\n/** Responses larger than this are chunked (512KB) */\nexport const TUNNEL_CHUNK_THRESHOLD = 512 * 1024;\n\n/** Size of each chunk - fits under 1MB with base64 encoding (768KB) */\nexport const TUNNEL_CHUNK_SIZE = 768 * 1024;\n\n/** Maximum total response size (50MB) */\nexport const TUNNEL_MAX_RESPONSE_SIZE = 50 * 1024 * 1024;\n\n/** Timeout for receiving all chunks (30s) */\nexport const TUNNEL_CHUNK_TIMEOUT_MS = 30 * 1000;\n","/**\n * CLI Telemetry Client\n *\n * Captures and reports events to the Evident API for debugging and observability.\n * Events are batched and sent periodically to minimize network overhead.\n */\n\nimport {\n TelemetryEventRequest,\n SubmitTelemetryEventsRequest,\n TelemetryEventTypes,\n TelemetryEvent,\n AgentConnectedEvent,\n AgentDisconnectedEvent,\n AgentMessageProcessingEvent,\n AgentMessageDoneEvent,\n AgentMessageFailedEvent,\n EventSeverity,\n} from '@evident/types';\nimport { getApiUrlConfig } from './config.js';\nimport { getToken } from './keychain.js';\n\n// Get version from package.json at build time\nconst CLI_VERSION = process.env.npm_package_version || 'unknown';\n\n// Re-export for convenience\nexport type { EventSeverity } from '@evident/types';\n// Re-export event types from shared package\nexport { TelemetryEventTypes } from '@evident/types';\n\n// Event buffer for batching\nlet eventBuffer: TelemetryEventRequest[] = [];\nlet flushTimeout: NodeJS.Timeout | null = null;\nlet isShuttingDown = false;\n\n// Configuration\nconst FLUSH_INTERVAL_MS = 5000; // Flush every 5 seconds\nconst MAX_BUFFER_SIZE = 50; // Flush when buffer reaches this size\nconst FLUSH_TIMEOUT_MS = 3000; // Timeout for flush requests\n\n/**\n * Log a telemetry event\n * Events are buffered and sent in batches\n */\nexport function logEvent(\n eventType: string,\n options: {\n severity?: EventSeverity;\n message?: string;\n metadata?: Record<string, unknown>;\n agentId?: string;\n } = {},\n): void {\n const event: TelemetryEventRequest = {\n event_type: eventType,\n severity: options.severity || 'info',\n message: options.message,\n metadata: options.metadata,\n agent_id: options.agentId,\n timestamp: new Date().toISOString(),\n };\n\n eventBuffer.push(event);\n\n // Flush immediately for errors or if buffer is full\n if (options.severity === 'error' || eventBuffer.length >= MAX_BUFFER_SIZE) {\n void flushEvents();\n } else if (!flushTimeout && !isShuttingDown) {\n // Schedule a flush\n flushTimeout = setTimeout(() => {\n flushTimeout = null;\n void flushEvents();\n }, FLUSH_INTERVAL_MS);\n }\n}\n\n/**\n * Convenience methods for different severity levels\n */\nexport const telemetry = {\n debug: (\n eventType: string,\n message?: string,\n metadata?: Record<string, unknown>,\n agentId?: string,\n ) => logEvent(eventType, { severity: 'debug', message, metadata, agentId }),\n\n info: (\n eventType: string,\n message?: string,\n metadata?: Record<string, unknown>,\n agentId?: string,\n ) => logEvent(eventType, { severity: 'info', message, metadata, agentId }),\n\n warn: (\n eventType: string,\n message?: string,\n metadata?: Record<string, unknown>,\n agentId?: string,\n ) => logEvent(eventType, { severity: 'warning', message, metadata, agentId }),\n\n error: (\n eventType: string,\n message?: string,\n metadata?: Record<string, unknown>,\n agentId?: string,\n ) => logEvent(eventType, { severity: 'error', message, metadata, agentId }),\n};\n\n/**\n * Flush buffered events to the API\n */\nexport async function flushEvents(): Promise<void> {\n if (eventBuffer.length === 0) return;\n\n // Take current buffer and reset\n const events = eventBuffer;\n eventBuffer = [];\n\n // Clear any pending flush timeout\n if (flushTimeout) {\n clearTimeout(flushTimeout);\n flushTimeout = null;\n }\n\n try {\n const credentials = await getToken();\n if (!credentials) {\n // Not logged in, can't send telemetry\n return;\n }\n\n const apiUrl = getApiUrlConfig();\n const controller = new AbortController();\n const timeout = setTimeout(() => controller.abort(), FLUSH_TIMEOUT_MS);\n\n try {\n // Type-check the request against the shared contract\n const request: SubmitTelemetryEventsRequest = {\n events,\n client_type: 'cli',\n client_version: CLI_VERSION,\n };\n\n const response = await fetch(`${apiUrl}/telemetry/events`, {\n method: 'POST',\n headers: {\n 'Content-Type': 'application/json',\n Authorization: `Bearer ${credentials.token}`,\n },\n body: JSON.stringify(request),\n signal: controller.signal,\n });\n\n if (!response.ok) {\n // Log failure but don't throw - telemetry shouldn't break the CLI\n console.error(`Telemetry flush failed: ${response.status}`);\n }\n } finally {\n clearTimeout(timeout);\n }\n } catch (error) {\n // Silently ignore telemetry errors - don't disrupt the user\n if (process.env.DEBUG) {\n console.error('Telemetry error:', error);\n }\n }\n}\n\n/**\n * Shutdown telemetry - flush remaining events\n * Call this before the process exits\n */\nexport async function shutdownTelemetry(): Promise<void> {\n isShuttingDown = true;\n\n if (flushTimeout) {\n clearTimeout(flushTimeout);\n flushTimeout = null;\n }\n\n await flushEvents();\n}\n\n// ============================================================================\n// Type-safe event emitters for agent activity events\n// These ensure the correct metadata is provided for each event type\n// ============================================================================\n\nfunction emitEvent(event: TelemetryEvent): void {\n logEvent(event.event_type, {\n severity: event.severity,\n message: event.message,\n metadata: event.metadata,\n agentId: event.agent_id,\n });\n}\n\n/** Emit agent connected event */\nexport function emitAgentConnected(\n agentId: string,\n metadata: AgentConnectedEvent['metadata'],\n): void {\n emitEvent({\n event_type: TelemetryEventTypes.AGENT_CONNECTED,\n severity: 'info',\n message: 'Agent CLI connected',\n metadata,\n agent_id: agentId,\n } satisfies AgentConnectedEvent);\n}\n\n/** Emit agent disconnected event */\nexport function emitAgentDisconnected(\n agentId: string,\n metadata: AgentDisconnectedEvent['metadata'],\n): void {\n emitEvent({\n event_type: TelemetryEventTypes.AGENT_DISCONNECTED,\n severity: 'info',\n message: `Agent CLI disconnected (code: ${metadata.code})`,\n metadata,\n agent_id: agentId,\n } satisfies AgentDisconnectedEvent);\n}\n\n/** Emit agent message processing event */\nexport function emitAgentMessageProcessing(\n agentId: string,\n metadata: AgentMessageProcessingEvent['metadata'],\n): void {\n emitEvent({\n event_type: TelemetryEventTypes.AGENT_MESSAGE_PROCESSING,\n severity: 'info',\n message: `Processing message ${metadata.message_id.slice(0, 8)}...`,\n metadata,\n agent_id: agentId,\n } satisfies AgentMessageProcessingEvent);\n}\n\n/** Emit agent message done event */\nexport function emitAgentMessageDone(\n agentId: string,\n metadata: AgentMessageDoneEvent['metadata'],\n): void {\n emitEvent({\n event_type: TelemetryEventTypes.AGENT_MESSAGE_DONE,\n severity: 'info',\n message: `Message ${metadata.message_id.slice(0, 8)} processed`,\n metadata,\n agent_id: agentId,\n } satisfies AgentMessageDoneEvent);\n}\n\n/** Emit agent message failed event */\nexport function emitAgentMessageFailed(\n agentId: string,\n metadata: AgentMessageFailedEvent['metadata'],\n): void {\n emitEvent({\n event_type: TelemetryEventTypes.AGENT_MESSAGE_FAILED,\n severity: 'error',\n message: metadata.error\n ? `Message ${metadata.message_id.slice(0, 8)} failed: ${metadata.error}`\n : `Message ${metadata.message_id.slice(0, 8)} ${metadata.reason || 'failed'}`,\n metadata,\n agent_id: agentId,\n } satisfies AgentMessageFailedEvent);\n}\n\n// ============================================================================\n// Legacy event types (for non-activity events like CLI lifecycle, auth, etc.)\n// ============================================================================\n\nexport const EventTypes = {\n // Tunnel lifecycle\n TUNNEL_STARTING: 'tunnel.starting',\n TUNNEL_CONNECTED: 'tunnel.connected',\n TUNNEL_DISCONNECTED: 'tunnel.disconnected',\n TUNNEL_RECONNECTING: 'tunnel.reconnecting',\n TUNNEL_ERROR: 'tunnel.error',\n\n // OpenCode communication\n OPENCODE_HEALTH_CHECK: 'opencode.health_check',\n OPENCODE_HEALTH_OK: 'opencode.health_ok',\n OPENCODE_HEALTH_FAILED: 'opencode.health_failed',\n OPENCODE_REQUEST_RECEIVED: 'opencode.request_received',\n OPENCODE_REQUEST_FORWARDED: 'opencode.request_forwarded',\n OPENCODE_RESPONSE_SENT: 'opencode.response_sent',\n OPENCODE_UNREACHABLE: 'opencode.unreachable',\n OPENCODE_ERROR: 'opencode.error',\n\n // Authentication\n AUTH_LOGIN_STARTED: 'auth.login_started',\n AUTH_LOGIN_SUCCESS: 'auth.login_success',\n AUTH_LOGIN_FAILED: 'auth.login_failed',\n AUTH_LOGOUT: 'auth.logout',\n\n // CLI lifecycle\n CLI_STARTED: 'cli.started',\n CLI_COMMAND: 'cli.command',\n CLI_ERROR: 'cli.error',\n} as const;\n","/**\n * Unified Authentication\n *\n * Provides authentication that works for both interactive (keychain) and CI (env vars) modes.\n *\n * Priority:\n * 1. EVIDENT_AGENT_KEY - API key for CI environments\n * 2. EVIDENT_TOKEN - User token (alternative to key)\n * 3. Keychain - Stored credentials from `evident login`\n */\n\nimport { getToken, StoredCredentials } from './keychain.js';\n\nexport type AuthType = 'agent_key' | 'bearer';\n\nexport interface AuthCredentials {\n token: string;\n authType: AuthType;\n /** User info (only available for keychain auth) */\n user?: {\n id: string;\n email: string;\n };\n}\n\n/**\n * Get the authentication credentials.\n *\n * Priority:\n * 1. EVIDENT_AGENT_KEY env var (CI mode)\n * 2. EVIDENT_TOKEN env var (CI mode)\n * 3. Keychain credentials (interactive mode)\n *\n * @returns Credentials if available, null otherwise\n */\nexport async function getAuthCredentials(): Promise<AuthCredentials | null> {\n // Check for agent key (CI environment)\n const agentKey = process.env.EVIDENT_AGENT_KEY;\n if (agentKey) {\n return { token: agentKey, authType: 'agent_key' };\n }\n\n // Check for user token (env var)\n const userToken = process.env.EVIDENT_TOKEN;\n if (userToken) {\n return { token: userToken, authType: 'bearer' };\n }\n\n // Fall back to keychain credentials\n const keychainCreds = await getToken();\n if (keychainCreds) {\n return {\n token: keychainCreds.token,\n authType: 'bearer',\n user: keychainCreds.user,\n };\n }\n\n // No credentials available\n return null;\n}\n\n/**\n * Get the Authorization header value for the given credentials\n */\nexport function getAuthHeader(credentials: AuthCredentials): string {\n if (credentials.authType === 'agent_key') {\n return `SandboxKey ${credentials.token}`;\n }\n return `Bearer ${credentials.token}`;\n}\n\n/**\n * Check if we're running in an interactive environment.\n *\n * Non-interactive if:\n * - CI environment variable is set\n * - GITHUB_ACTIONS environment variable is set\n * - stdin is not a TTY\n *\n * @param jsonOutput - If true, force non-interactive mode\n */\nexport function isInteractive(jsonOutput?: boolean): boolean {\n if (jsonOutput) return false;\n if (process.env.CI) return false;\n if (process.env.GITHUB_ACTIONS) return false;\n if (!process.stdin.isTTY) return false;\n return true;\n}\n\n// Re-export keychain functions for convenience\nexport { getToken, storeToken, deleteToken, hasValidToken } from './keychain.js';\nexport type { StoredCredentials };\n","/**\n * OpenCode Health Checking\n *\n * Functions for checking OpenCode health status and waiting for it to become healthy.\n */\n\nexport interface HealthCheckResult {\n healthy: boolean;\n version?: string;\n error?: string;\n}\n\n/**\n * Check if a port has a valid OpenCode instance by calling /global/health\n */\nexport async function checkOpenCodeHealth(port: number): Promise<HealthCheckResult> {\n try {\n const response = await fetch(`http://localhost:${port}/global/health`, {\n signal: AbortSignal.timeout(2000), // 2 second timeout\n });\n if (!response.ok) {\n return { healthy: false, error: `HTTP ${response.status}` };\n }\n const data = (await response.json().catch(() => ({}))) as { version?: string };\n return { healthy: true, version: data.version };\n } catch (error) {\n const message = error instanceof Error ? error.message : 'Unknown error';\n return { healthy: false, error: message };\n }\n}\n\n/**\n * Wait for OpenCode to be healthy\n */\nexport async function waitForOpenCodeHealth(\n port: number,\n timeoutMs: number = 30000,\n): Promise<HealthCheckResult> {\n const startTime = Date.now();\n\n while (Date.now() - startTime < timeoutMs) {\n const health = await checkOpenCodeHealth(port);\n if (health.healthy) {\n return health;\n }\n await new Promise((resolve) => setTimeout(resolve, 1000));\n }\n\n return { healthy: false, error: 'Timeout waiting for OpenCode to be healthy' };\n}\n","/**\n * OpenCode Process Management\n *\n * Functions for starting, stopping, and finding OpenCode processes.\n */\n\nimport { execSync, spawn, ChildProcess } from 'child_process';\nimport { checkOpenCodeHealth } from './health.js';\n\n// Common ports that OpenCode might run on\nconst OPENCODE_PORT_RANGE = [4096, 4097, 4098, 4099, 4100];\n\nexport interface OpenCodeInstance {\n pid: number;\n port: number;\n cwd?: string;\n version?: string;\n}\n\n/**\n * Get the working directory of a process\n */\nfunction getProcessCwd(pid: number): string | undefined {\n const platform = process.platform;\n\n try {\n if (platform === 'darwin') {\n // macOS: use lsof to get cwd\n const output = execSync(`lsof -a -p ${pid} -d cwd -Fn 2>/dev/null`, {\n encoding: 'utf-8',\n stdio: ['pipe', 'pipe', 'pipe'],\n }).trim();\n // Output format: \"p<pid>\\nn<path>\"\n const lines = output.split('\\n');\n for (const line of lines) {\n if (line.startsWith('n') && !line.startsWith('n ')) {\n return line.slice(1); // Remove 'n' prefix\n }\n }\n } else if (platform === 'linux') {\n // Linux: read /proc/<pid>/cwd symlink\n const output = execSync(`readlink /proc/${pid}/cwd 2>/dev/null`, {\n encoding: 'utf-8',\n stdio: ['pipe', 'pipe', 'pipe'],\n }).trim();\n if (output) return output;\n }\n } catch {\n // Failed to get cwd, return undefined\n }\n\n return undefined;\n}\n\n/**\n * Check if a port is in use by any process\n */\nexport function isPortInUse(port: number): boolean {\n const platform = process.platform;\n\n try {\n if (platform === 'darwin' || platform === 'linux') {\n execSync(`lsof -i :${port} -sTCP:LISTEN 2>/dev/null`, {\n encoding: 'utf-8',\n stdio: ['pipe', 'pipe', 'pipe'],\n });\n return true; // Command succeeded, port is in use\n }\n } catch {\n // lsof failed or returned empty, port is free\n }\n\n return false;\n}\n\n/**\n * Find the next available port starting from the given port\n */\nexport function findAvailablePort(startPort: number, maxAttempts: number = 10): number | null {\n for (let i = 0; i < maxAttempts; i++) {\n const port = startPort + i;\n if (!isPortInUse(port)) {\n return port;\n }\n }\n return null;\n}\n\n/**\n * Find running OpenCode processes by scanning the process list\n * Uses pgrep for more reliable process matching\n * Returns array of instances with their PIDs and ports\n */\nexport function findOpenCodeProcesses(): OpenCodeInstance[] {\n const instances: OpenCodeInstance[] = [];\n\n try {\n const platform = process.platform;\n\n if (platform === 'darwin' || platform === 'linux') {\n // Method 1: Use pgrep for more reliable process matching\n let pids: number[] = [];\n\n try {\n // pgrep -f matches against full command line\n const pgrepOutput = execSync('pgrep -f \"opencode serve|opencode-serve\"', {\n encoding: 'utf-8',\n stdio: ['pipe', 'pipe', 'pipe'],\n }).trim();\n\n if (pgrepOutput) {\n pids = pgrepOutput\n .split('\\n')\n .map((p) => parseInt(p.trim(), 10))\n .filter((p) => !isNaN(p));\n }\n } catch {\n // pgrep found nothing or failed, try ps fallback\n try {\n const psOutput = execSync('ps aux | grep -E \"opencode (serve|--port)\" | grep -v grep', {\n encoding: 'utf-8',\n stdio: ['pipe', 'pipe', 'pipe'],\n }).trim();\n\n if (psOutput) {\n for (const line of psOutput.split('\\n')) {\n const parts = line.trim().split(/\\s+/);\n if (parts.length >= 2) {\n const pid = parseInt(parts[1], 10);\n if (!isNaN(pid)) pids.push(pid);\n }\n }\n }\n } catch {\n // ps also failed, pids stays empty\n }\n }\n\n // For each PID, find what port it's listening on and get cwd\n for (const pid of pids) {\n try {\n const lsofOutput = execSync(`lsof -Pan -p ${pid} -i TCP -sTCP:LISTEN 2>/dev/null`, {\n encoding: 'utf-8',\n stdio: ['pipe', 'pipe', 'pipe'],\n }).trim();\n\n for (const line of lsofOutput.split('\\n')) {\n // Parse port from lsof output (e.g., \"node 12345 user 23u IPv4 0x1234 0t0 TCP *:4096 (LISTEN)\")\n const portMatch = line.match(/:(\\d+)\\s+\\(LISTEN\\)/);\n if (portMatch) {\n const port = parseInt(portMatch[1], 10);\n if (!isNaN(port) && !instances.some((i) => i.port === port)) {\n const cwd = getProcessCwd(pid);\n instances.push({ pid, port, cwd });\n }\n }\n }\n } catch {\n // lsof failed for this PID, skip it\n }\n }\n }\n } catch {\n // Process detection failed, return empty array\n }\n\n return instances;\n}\n\n/**\n * Scan common OpenCode ports and check for healthy instances\n * This is a fallback when process-based detection fails\n */\nexport async function scanPortsForOpenCode(): Promise<OpenCodeInstance[]> {\n const instances: OpenCodeInstance[] = [];\n\n // Check each port in parallel for speed\n const checks = OPENCODE_PORT_RANGE.map(async (port) => {\n const health = await checkOpenCodeHealth(port);\n if (health.healthy) {\n // Try to find the PID for this port\n let pid = 0;\n try {\n const lsofOutput = execSync(`lsof -ti :${port} -sTCP:LISTEN 2>/dev/null`, {\n encoding: 'utf-8',\n stdio: ['pipe', 'pipe', 'pipe'],\n }).trim();\n if (lsofOutput) {\n pid = parseInt(lsofOutput.split('\\n')[0], 10) || 0;\n }\n } catch {\n // Couldn't get PID, that's ok\n }\n\n const cwd = pid ? getProcessCwd(pid) : undefined;\n return { pid, port, cwd, version: health.version };\n }\n return null;\n });\n\n const results = await Promise.all(checks);\n for (const result of results) {\n if (result) {\n instances.push(result);\n }\n }\n\n return instances;\n}\n\n/**\n * Find all running OpenCode instances that are healthy\n * Uses process detection first, falls back to port scanning\n */\nexport async function findHealthyOpenCodeInstances(): Promise<OpenCodeInstance[]> {\n // First try process-based detection\n const processes = findOpenCodeProcesses();\n const healthy: OpenCodeInstance[] = [];\n\n for (const proc of processes) {\n const health = await checkOpenCodeHealth(proc.port);\n if (health.healthy) {\n healthy.push({ ...proc, version: health.version });\n }\n }\n\n // If process detection found nothing, fall back to port scanning\n if (healthy.length === 0) {\n const scanned = await scanPortsForOpenCode();\n return scanned;\n }\n\n return healthy;\n}\n\n/**\n * Start OpenCode as a child process\n */\nexport async function startOpenCode(port: number): Promise<ChildProcess> {\n // Try to find opencode command\n let command = 'opencode';\n let args = ['serve', '--port', port.toString()];\n\n try {\n execSync('which opencode', { stdio: 'ignore' });\n } catch {\n // opencode not in PATH, try npx\n command = 'npx';\n args = ['opencode', 'serve', '--port', port.toString()];\n }\n\n const child = spawn(command, args, {\n detached: true,\n stdio: 'ignore',\n cwd: process.cwd(),\n });\n\n return child;\n}\n\n/**\n * Stop OpenCode process\n * Handles both POSIX (process groups with negative PID) and Windows (direct kill)\n */\nexport function stopOpenCode(opencodeProcess: ChildProcess | null): void {\n if (!opencodeProcess || !opencodeProcess.pid) {\n return;\n }\n\n try {\n if (process.platform === 'win32') {\n // Windows: kill the process directly (no process groups)\n opencodeProcess.kill('SIGTERM');\n } else {\n // POSIX: kill the process group (negative PID) since we spawned with detached: true\n process.kill(-opencodeProcess.pid, 'SIGTERM');\n }\n } catch {\n // Process may have already exited, ignore errors\n }\n}\n","/**\n * OpenCode Installation Detection and Prompts\n *\n * Functions for checking if OpenCode is installed and prompting for installation.\n */\n\nimport { execSync } from 'child_process';\nimport chalk from 'chalk';\nimport { select } from '@inquirer/prompts';\nimport { blank } from '../../utils/ui.js';\n\n// OpenCode installation URL\nconst OPENCODE_INSTALL_URL = 'https://opencode.ai';\n\n/**\n * Check if OpenCode is installed on the system.\n * Returns true if the `opencode` command is available in PATH.\n */\nexport function isOpenCodeInstalled(): boolean {\n try {\n const platform = process.platform;\n if (platform === 'win32') {\n execSync('where opencode', { stdio: 'ignore' });\n } else {\n execSync('which opencode', { stdio: 'ignore' });\n }\n return true;\n } catch {\n return false;\n }\n}\n\nexport type InstallPromptResult = 'installed' | 'continue' | 'exit';\n\n/**\n * Display OpenCode installation instructions and offer to install.\n * Returns 'installed' if user installed it, 'continue' to proceed anyway, or 'exit' to stop.\n *\n * @param interactive - If false, outputs JSON error and returns 'exit'\n */\nexport async function promptOpenCodeInstall(interactive: boolean): Promise<InstallPromptResult> {\n if (!interactive) {\n // In non-interactive mode, just output a JSON message and exit\n console.log(\n JSON.stringify({\n status: 'error',\n error: 'OpenCode is not installed',\n install_url: OPENCODE_INSTALL_URL,\n install_commands: {\n npm: 'npm install -g opencode-ai',\n curl: 'curl -fsSL https://opencode.ai/install.sh | sh',\n },\n }),\n );\n return 'exit';\n }\n\n blank();\n console.log(chalk.yellow('OpenCode is not installed on your system.'));\n blank();\n console.log(chalk.dim('OpenCode is an AI coding agent that runs locally on your machine.'));\n console.log(chalk.dim(`Learn more at: ${chalk.cyan(OPENCODE_INSTALL_URL)}`));\n blank();\n\n const action = await select({\n message: 'How would you like to proceed?',\n choices: [\n {\n name: 'Show installation instructions',\n value: 'instructions',\n description: 'Display commands to install OpenCode',\n },\n {\n name: 'Continue without OpenCode',\n value: 'continue',\n description: 'Connect anyway (requests will fail until OpenCode is installed)',\n },\n {\n name: 'Exit',\n value: 'exit',\n description: 'Exit and install OpenCode manually',\n },\n ],\n });\n\n if (action === 'instructions') {\n blank();\n console.log(chalk.bold('Install OpenCode using one of these methods:'));\n blank();\n console.log(chalk.dim(' # Option 1: Install via npm (recommended)'));\n console.log(` ${chalk.cyan('npm install -g opencode-ai')}`);\n blank();\n console.log(chalk.dim(' # Option 2: Install via curl'));\n console.log(` ${chalk.cyan('curl -fsSL https://opencode.ai/install.sh | sh')}`);\n blank();\n console.log(chalk.dim(`For more options, visit: ${chalk.cyan(OPENCODE_INSTALL_URL)}`));\n blank();\n\n const afterInstall = await select({\n message: 'After installing, what would you like to do?',\n choices: [\n {\n name: 'I installed it - continue',\n value: 'continue',\n description: 'Proceed with the run command',\n },\n {\n name: 'Exit',\n value: 'exit',\n description: 'Exit now and run the command again later',\n },\n ],\n });\n\n if (afterInstall === 'continue') {\n // Verify installation\n if (isOpenCodeInstalled()) {\n console.log(chalk.green('\\n✓ OpenCode detected!'));\n return 'installed';\n } else {\n console.log(chalk.yellow('\\nOpenCode still not detected in PATH.'));\n console.log(chalk.dim('You may need to restart your terminal or add it to your PATH.'));\n\n const proceed = await select({\n message: 'Continue anyway?',\n choices: [\n { name: 'Yes, continue', value: 'continue' },\n { name: 'No, exit', value: 'exit' },\n ],\n });\n return proceed === 'continue' ? 'continue' : 'exit';\n }\n }\n return 'exit';\n }\n\n return action as 'continue' | 'exit';\n}\n","/**\n * OpenCode Session Management\n *\n * Functions for creating and managing OpenCode sessions.\n */\n\n/**\n * Create a new OpenCode session\n */\nexport async function createOpenCodeSession(port: number): Promise<string> {\n const response = await fetch(`http://localhost:${port}/session`, {\n method: 'POST',\n headers: { 'Content-Type': 'application/json' },\n body: JSON.stringify({}),\n });\n\n if (!response.ok) {\n throw new Error(`Failed to create session: HTTP ${response.status}`);\n }\n\n const data = (await response.json()) as { id: string };\n return data.id;\n}\n\n/**\n * Optional OpenCode routing options for sendMessageToOpenCode\n */\nexport interface MessageOptions {\n /** OpenCode agent name (e.g. \"build\", \"plan\") */\n agent?: string;\n /** Model in provider/model format (e.g. \"anthropic/claude-opus-4-6\") */\n model?: string;\n}\n\nexport interface SendMessageResult {\n title?: string;\n}\n\n// Minimal types matching the OpenCode API shapes (avoiding API imports in CLI)\n\nexport interface OpenCodeQuestionOption {\n label: string;\n description: string;\n}\n\nexport interface OpenCodeQuestionInfo {\n question: string;\n header: string;\n options: OpenCodeQuestionOption[];\n}\n\nexport interface OpenCodeQuestion {\n id: string;\n sessionID: string;\n questions: OpenCodeQuestionInfo[];\n tool?: { messageID: string; callID: string };\n}\n\nexport interface OpenCodePermission {\n id: string;\n type: string;\n pattern?: string | string[];\n sessionID: string;\n messageID: string;\n callID?: string;\n title: string;\n metadata: Record<string, unknown>;\n time: { created: number };\n}\n\n/**\n * Hooks called while the message is being processed.\n * Each question/permission is reported at most once (tracked by ID).\n */\nexport interface SessionInteractiveHooks {\n onQuestion?: (question: OpenCodeQuestion) => Promise<void>;\n onPermission?: (permission: OpenCodePermission) => Promise<void>;\n}\n\n/**\n * Send a message to an OpenCode session and wait for it to complete.\n *\n * OpenCode uses a blocking HTTP endpoint: POST /session/:id/message holds the\n * connection open until processing completes (including any wait for the user\n * to answer an interactive question). While waiting, we poll for pending\n * questions and permissions every second so they can be surfaced without\n * blocking the main request.\n *\n * Throws on HTTP errors or when maxWaitMs is exceeded.\n */\nexport async function sendMessageToOpenCode(\n port: number,\n sessionId: string,\n content: string,\n options?: MessageOptions,\n hooks?: SessionInteractiveHooks,\n maxWaitMs: number = 10 * 60 * 1000,\n): Promise<SendMessageResult> {\n const body: Record<string, unknown> = {\n parts: [{ type: 'text', text: content }],\n };\n\n if (options?.agent) {\n body.agent = options.agent;\n }\n\n if (options?.model) {\n const slashIndex = options.model.indexOf('/');\n if (slashIndex !== -1) {\n body.model = {\n providerID: options.model.substring(0, slashIndex),\n modelID: options.model.substring(slashIndex + 1),\n };\n }\n }\n\n let pollDone = false;\n const reportedQuestions = new Set<string>();\n const reportedPermissions = new Set<string>();\n\n // Polls for interactive events while the message request is in-flight.\n const pollInteractive = async () => {\n while (!pollDone) {\n await new Promise<void>((resolve) => setTimeout(resolve, 1000));\n if (pollDone) break;\n\n if (hooks?.onQuestion) {\n try {\n const res = await fetch(`http://localhost:${port}/question`);\n if (res.ok) {\n const questions = (await res.json()) as OpenCodeQuestion[];\n for (const q of questions) {\n if (q.sessionID === sessionId && !reportedQuestions.has(q.id)) {\n reportedQuestions.add(q.id);\n await hooks.onQuestion(q);\n }\n }\n }\n } catch {\n // Non-fatal: interactive detection is best-effort\n }\n }\n\n if (hooks?.onPermission) {\n try {\n const res = await fetch(`http://localhost:${port}/permission`);\n if (res.ok) {\n const permissions = (await res.json()) as OpenCodePermission[];\n for (const p of permissions) {\n if (p.sessionID === sessionId && !reportedPermissions.has(p.id)) {\n reportedPermissions.add(p.id);\n await hooks.onPermission(p);\n }\n }\n }\n } catch {\n // Non-fatal: interactive detection is best-effort\n }\n }\n }\n };\n\n // Awaits the message endpoint; sets pollDone when done so the poll loop exits.\n const sendMessage = async (): Promise<SendMessageResult> => {\n const controller = new AbortController();\n const timer = setTimeout(() => controller.abort(), maxWaitMs);\n try {\n const res = await fetch(`http://localhost:${port}/session/${sessionId}/message`, {\n method: 'POST',\n headers: { 'Content-Type': 'application/json' },\n body: JSON.stringify(body),\n signal: controller.signal,\n });\n if (!res.ok) {\n const text = await res.text().catch(() => '');\n throw new Error(`OpenCode message failed: HTTP ${res.status}${text ? `: ${text}` : ''}`);\n }\n // Fetch the updated session title after successful completion\n const sessionRes = await fetch(`http://localhost:${port}/session/${sessionId}`).catch(\n () => null,\n );\n const session = sessionRes?.ok ? ((await sessionRes.json()) as { title?: string }) : null;\n return { title: session?.title };\n } catch (err) {\n if (err instanceof Error && err.name === 'AbortError') {\n throw new Error('Message processing timed out');\n }\n throw err;\n } finally {\n clearTimeout(timer);\n pollDone = true;\n }\n };\n\n const [result] = await Promise.all([sendMessage(), pollInteractive()]);\n return result;\n}\n","/**\n * Tunnel WebSocket Connection\n *\n * Functions for establishing and managing WebSocket tunnel connections.\n */\n\nimport WebSocket from 'ws';\nimport { getTunnelUrlConfig } from '../config.js';\nimport type { RelayToCLIMessage } from '@evident/types';\nimport { forwardToOpenCode, sendResponse } from './forwarding.js';\nimport { subscribeToOpenCodeEvents } from './events.js';\n\n// Re-export the message type\nexport type RelayMessage = RelayToCLIMessage;\n\n// Reconnection constants\nconst MAX_RECONNECT_DELAY = 30000; // 30 seconds\nconst BASE_RECONNECT_DELAY = 500; // 0.5 seconds\n\nexport interface TunnelConnectionOptions {\n agentId: string;\n authHeader: string;\n port: number;\n onConnected?: (agentId: string) => void;\n onDisconnected?: (code: number, reason: string) => void;\n onError?: (error: string) => void;\n onRequest?: (method: string, path: string, requestId: string) => void;\n onResponse?: (status: number, durationMs: number, requestId: string) => void;\n onInfo?: (message: string) => void;\n}\n\nexport interface TunnelConnection {\n ws: WebSocket;\n close: () => void;\n // Active event subscriptions: subscription_id -> AbortController\n activeEventSubscriptions: Map<string, AbortController>;\n}\n\n/**\n * Calculate reconnect delay with exponential backoff and jitter\n */\nexport function getReconnectDelay(attempt: number): number {\n const exponentialDelay = BASE_RECONNECT_DELAY * Math.pow(2, attempt);\n const jitter = Math.random() * 1000;\n return Math.min(exponentialDelay + jitter, MAX_RECONNECT_DELAY);\n}\n\n/**\n * Connect to the tunnel relay\n *\n * @returns A promise that resolves with the WebSocket connection when connected,\n * or rejects on connection failure\n */\nexport function connectTunnel(options: TunnelConnectionOptions): Promise<TunnelConnection> {\n const {\n agentId,\n authHeader,\n port,\n onConnected,\n onDisconnected,\n onError,\n onRequest,\n onResponse,\n onInfo,\n } = options;\n\n const tunnelUrl = getTunnelUrlConfig();\n const url = `${tunnelUrl}/tunnel/${agentId}/connect`;\n const activeEventSubscriptions = new Map<string, AbortController>();\n\n return new Promise((resolve, reject) => {\n const ws = new WebSocket(url, {\n headers: {\n Authorization: authHeader,\n },\n });\n\n const connectionTimeout = setTimeout(() => {\n ws.close();\n reject(new Error('Connection timeout'));\n }, 30000);\n\n ws.on('open', () => {\n onInfo?.('WebSocket connection established');\n });\n\n ws.on('message', async (data: WebSocket.RawData) => {\n try {\n const message: RelayMessage = JSON.parse(data.toString());\n\n switch (message.type) {\n case 'connected': {\n clearTimeout(connectionTimeout);\n const connectedAgentId = message.agent_id ?? agentId;\n onConnected?.(connectedAgentId);\n resolve({\n ws,\n close: () => ws.close(1000, 'CLI shutdown'),\n activeEventSubscriptions,\n });\n break;\n }\n\n case 'error':\n clearTimeout(connectionTimeout);\n onError?.(message.message || 'Unknown tunnel error');\n if (message.code === 'unauthorized') {\n ws.close();\n reject(new Error('Unauthorized'));\n }\n break;\n\n case 'ping':\n ws.send(JSON.stringify({ type: 'pong' }));\n break;\n\n case 'request':\n if (message.id && message.payload) {\n const startTime = Date.now();\n onRequest?.(message.payload.method, message.payload.path, message.id);\n\n const response = await forwardToOpenCode(port, message.payload);\n const durationMs = Date.now() - startTime;\n\n onResponse?.(response.status, durationMs, message.id);\n\n // Use sendResponse which handles chunking for large responses\n sendResponse(ws, message.id, response);\n }\n break;\n\n case 'subscribe_events':\n if (message.id) {\n const abortController = new AbortController();\n activeEventSubscriptions.set(message.id, abortController);\n onInfo?.(`Starting event subscription ${message.id.slice(0, 8)}`);\n\n subscribeToOpenCodeEvents(port, message.id, ws, abortController)\n .catch((error) => {\n if (!abortController.signal.aborted) {\n onError?.(`Event subscription failed: ${error.message}`);\n }\n })\n .finally(() => {\n activeEventSubscriptions.delete(message.id!);\n });\n }\n break;\n\n case 'unsubscribe_events':\n if (message.id) {\n const controller = activeEventSubscriptions.get(message.id);\n if (controller) {\n controller.abort();\n activeEventSubscriptions.delete(message.id);\n }\n }\n break;\n }\n } catch (error) {\n const errorMessage = error instanceof Error ? error.message : 'Unknown error';\n onError?.(`Failed to handle message: ${errorMessage}`);\n }\n });\n\n ws.on('error', (error: Error) => {\n clearTimeout(connectionTimeout);\n onError?.(`Connection error: ${error.message}`);\n reject(error);\n });\n\n ws.on('close', (code: number, reason: Buffer) => {\n const reasonStr = reason.toString() || 'No reason provided';\n onDisconnected?.(code, reasonStr);\n\n // Cancel all active event subscriptions\n for (const [, controller] of activeEventSubscriptions) {\n controller.abort();\n }\n activeEventSubscriptions.clear();\n });\n });\n}\n","/**\n * Tunnel Request Forwarding\n *\n * Functions for forwarding requests to OpenCode and handling responses.\n */\n\nimport WebSocket from 'ws';\n\n// Chunked response protocol constants (must match tunnel-relay)\nconst CHUNK_THRESHOLD = 512 * 1024; // 512KB - responses larger than this are chunked\nconst CHUNK_SIZE = 768 * 1024; // 768KB - size of each chunk\n\nexport interface ForwardRequest {\n method: string;\n path: string;\n headers?: Record<string, string>;\n body?: unknown;\n}\n\nexport interface ForwardResponse {\n status: number;\n headers?: Record<string, string>;\n body?: unknown;\n}\n\n/**\n * Forward request to local OpenCode instance\n */\nexport async function forwardToOpenCode(\n port: number,\n request: ForwardRequest,\n): Promise<ForwardResponse> {\n const url = `http://localhost:${port}${request.path}`;\n\n try {\n const response = await fetch(url, {\n method: request.method,\n headers: {\n 'Content-Type': 'application/json',\n ...request.headers,\n },\n body: request.body ? JSON.stringify(request.body) : undefined,\n });\n\n let body: unknown;\n const contentType = response.headers.get('Content-Type');\n const text = await response.text();\n\n // Handle empty responses (e.g., 204 No Content)\n if (!text || text.length === 0) {\n body = null;\n } else if (contentType?.includes('application/json')) {\n try {\n body = JSON.parse(text);\n } catch {\n // If JSON parsing fails, return as text\n body = text;\n }\n } else {\n body = text;\n }\n\n return {\n status: response.status,\n body,\n };\n } catch (error) {\n const message = error instanceof Error ? error.message : 'Unknown error';\n return {\n status: 502,\n body: { error: 'Failed to connect to OpenCode', message },\n };\n }\n}\n\n/**\n * Send a response back to the relay.\n * Automatically uses chunked protocol for large responses (>= 512KB body).\n */\nexport function sendResponse(ws: WebSocket, requestId: string, response: ForwardResponse): void {\n const bodyStr = JSON.stringify(response.body ?? null);\n const bodyBytes = Buffer.from(bodyStr, 'utf-8');\n\n if (bodyBytes.length < CHUNK_THRESHOLD) {\n // Small response: send as single message (common case)\n ws.send(\n JSON.stringify({\n type: 'response',\n id: requestId,\n payload: response,\n }),\n );\n return;\n }\n\n // Large response: use chunked protocol\n sendResponseAsChunks(ws, requestId, response, bodyBytes);\n}\n\n/**\n * Send a large response as multiple chunks.\n * Only called when response body exceeds CHUNK_THRESHOLD.\n */\nfunction sendResponseAsChunks(\n ws: WebSocket,\n requestId: string,\n response: { status: number; headers?: Record<string, string> },\n bodyBytes: Buffer,\n): void {\n const chunks = splitIntoChunks(bodyBytes, CHUNK_SIZE);\n\n // Send start message with metadata\n ws.send(\n JSON.stringify({\n type: 'response_start',\n id: requestId,\n total_chunks: chunks.length,\n total_size: bodyBytes.length,\n payload: {\n status: response.status,\n headers: response.headers,\n },\n }),\n );\n\n // Send each chunk\n for (let i = 0; i < chunks.length; i++) {\n ws.send(\n JSON.stringify({\n type: 'response_chunk',\n id: requestId,\n chunk_index: i,\n data: chunks[i].toString('base64'),\n }),\n );\n }\n\n // Send end message\n ws.send(\n JSON.stringify({\n type: 'response_end',\n id: requestId,\n }),\n );\n}\n\n/**\n * Split a buffer into chunks of the specified size\n */\nfunction splitIntoChunks(data: Buffer, chunkSize: number): Buffer[] {\n const chunks: Buffer[] = [];\n for (let i = 0; i < data.length; i += chunkSize) {\n chunks.push(data.subarray(i, i + chunkSize));\n }\n return chunks;\n}\n","/**\n * Tunnel SSE Event Subscription\n *\n * Functions for subscribing to OpenCode events and forwarding them through the WebSocket.\n */\n\nimport WebSocket from 'ws';\n\n/**\n * Subscribe to OpenCode events and forward them through the WebSocket\n *\n * @param port - OpenCode port\n * @param subscriptionId - Unique ID for this subscription\n * @param ws - WebSocket connection to relay\n * @param abortController - Controller to cancel the subscription\n */\nexport async function subscribeToOpenCodeEvents(\n port: number,\n subscriptionId: string,\n ws: WebSocket,\n abortController: AbortController,\n): Promise<void> {\n const url = `http://localhost:${port}/event`;\n\n try {\n const response = await fetch(url, {\n headers: { Accept: 'text/event-stream' },\n signal: abortController.signal,\n });\n\n if (!response.ok) {\n throw new Error(`Failed to connect to OpenCode events: ${response.status}`);\n }\n\n if (!response.body) {\n throw new Error('No response body');\n }\n\n const reader = response.body.getReader();\n const decoder = new TextDecoder();\n let buffer = '';\n\n // eslint-disable-next-line no-constant-condition\n while (true) {\n const { done, value } = await reader.read();\n\n if (done) {\n // Stream ended\n ws.send(JSON.stringify({ type: 'event_end', id: subscriptionId }));\n break;\n }\n\n buffer += decoder.decode(value, { stream: true });\n const lines = buffer.split('\\n');\n buffer = lines.pop() || '';\n\n for (const line of lines) {\n if (line.startsWith('data: ')) {\n try {\n const event = JSON.parse(line.slice(6));\n // Forward event to relay\n ws.send(JSON.stringify({ type: 'event', id: subscriptionId, event }));\n } catch {\n // Ignore parse errors for individual events\n }\n }\n }\n }\n } catch (error) {\n if (abortController.signal.aborted) {\n // Subscription was cancelled, this is expected\n return;\n }\n\n const message = error instanceof Error ? error.message : 'Unknown error';\n // Send error to relay\n ws.send(JSON.stringify({ type: 'event_error', id: subscriptionId, error: message }));\n throw error;\n }\n}\n"],"mappings":"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","names":["chalk","error","credentials","error","chalk","credentials","chalk","credentials","chalk","chalk","ora","select","credentials","error","credentials","error","execSync","chalk","execSync","chalk","error","error","error","error","chalk","select","credentials","ora"]}
|
|
1
|
+
{"version":3,"sources":["../src/index.ts","../src/commands/login.ts","../src/lib/config.ts","../src/lib/api.ts","../src/lib/keychain.ts","../src/utils/ui.ts","../src/commands/logout.ts","../src/commands/whoami.ts","../src/commands/run.ts","../../../packages/types/src/telemetry/index.ts","../../../packages/types/src/tunnel/index.ts","../src/lib/telemetry.ts","../src/lib/auth.ts","../src/lib/opencode/health.ts","../src/lib/opencode/process.ts","../src/lib/opencode/install.ts","../src/lib/opencode/session.ts","../src/lib/tunnel/connection.ts","../src/lib/tunnel/forwarding.ts","../src/lib/tunnel/events.ts"],"sourcesContent":["/**\n * Evident CLI\n *\n * Run OpenCode locally and connect it to the Evident platform.\n */\n\nimport { Command } from 'commander';\nimport { login } from './commands/login.js';\nimport { logout } from './commands/logout.js';\nimport { whoami } from './commands/whoami.js';\nimport { run } from './commands/run.js';\nimport { setEnvironment, type Environment } from './lib/config.js';\n\nconst program = new Command();\n\nprogram\n .name('evident')\n .description('Run OpenCode locally and connect it to Evident')\n .version('0.1.0')\n .option('-e, --env <environment>', 'Environment to use (local, dev, production)', 'production')\n .hook('preAction', (thisCommand) => {\n const env = thisCommand.opts().env as Environment;\n if (env) {\n setEnvironment(env);\n }\n });\n\n// Login command\nprogram\n .command('login')\n .description('Authenticate with Evident')\n .option('--token', 'Use token-based authentication (for CI/CD)')\n .option('--no-browser', 'Do not open the browser automatically')\n .action(login);\n\n// Logout command\nprogram.command('logout').description('Remove stored credentials').action(logout);\n\n// Whoami command\nprogram.command('whoami').description('Show the currently logged in user').action(whoami);\n\n// Run command (unified - connects to Evident and processes messages)\nprogram\n .command('run')\n .description('Connect to Evident and process messages')\n .requiredOption('-a, --agent <id>', 'Agent ID to connect to')\n .option('-p, --port <port>', 'OpenCode port (default: 4096)', '4096')\n .option('-v, --verbose', 'Show detailed request/response information')\n .option('-c, --conversation <id>', 'Process only this specific conversation')\n .option('--idle-timeout <seconds>', 'Exit after N seconds idle')\n .option('--json', 'Output in JSON format')\n .action(\n (options: {\n agent: string;\n port: string;\n verbose?: boolean;\n conversation?: string;\n idleTimeout?: string;\n json?: boolean;\n }) => {\n run({\n agent: options.agent,\n port: parseInt(options.port, 10),\n verbose: options.verbose,\n conversation: options.conversation,\n idleTimeout: options.idleTimeout ? parseInt(options.idleTimeout, 10) : undefined,\n json: options.json,\n });\n },\n );\n\n// Parse arguments\nprogram.parse();\n","/**\n * Login Command\n *\n * Authenticates the user using OAuth Device Flow.\n * See ADR-0018 for details.\n */\n\nimport open from 'open';\nimport ora from 'ora';\nimport chalk from 'chalk';\nimport { api } from '../lib/api.js';\nimport { storeToken } from '../lib/keychain.js';\nimport { printSuccess, printError, blank, waitForEnter, sleep } from '../utils/ui.js';\n\ninterface DeviceAuthResponse {\n device_code: string;\n user_code: string;\n verification_uri: string;\n expires_in: number;\n interval: number;\n}\n\ninterface TokenPollResponse {\n status: 'pending' | 'complete' | 'expired';\n access_token?: string;\n expires_at?: string;\n user?: {\n id: string;\n email: string;\n };\n}\n\ninterface LoginOptions {\n token?: boolean;\n noBrowser?: boolean;\n}\n\n/**\n * Start device flow authentication\n */\nasync function deviceFlowLogin(options: LoginOptions): Promise<void> {\n // Step 1: Request device code\n let deviceAuth: DeviceAuthResponse;\n try {\n deviceAuth = await api.post<DeviceAuthResponse>('/auth/device');\n } catch (error) {\n const message = error instanceof Error ? error.message : 'Unknown error';\n printError(`Failed to start authentication: ${message}`);\n process.exit(1);\n }\n\n const { device_code, user_code, verification_uri, interval } = deviceAuth;\n\n // Step 2: Display instructions\n blank();\n console.log(chalk.bold('To authenticate, visit:'));\n console.log();\n console.log(` ${chalk.cyan(verification_uri)}`);\n console.log();\n console.log(chalk.bold('And enter this code:'));\n console.log();\n console.log(` ${chalk.yellow.bold(user_code)}`);\n blank();\n\n // Step 3: Open browser (unless --no-browser)\n if (!options.noBrowser) {\n await waitForEnter('Press Enter to open the browser...');\n try {\n await open(verification_uri);\n } catch {\n console.log(chalk.dim('Could not open browser. Please visit the URL manually.'));\n }\n }\n\n // Step 4: Poll for completion\n const spinner = ora('Waiting for authentication...').start();\n\n const pollIntervalMs = (interval || 5) * 1000;\n const maxAttempts = 60; // 5 minutes max at 5s intervals\n let attempts = 0;\n\n while (attempts < maxAttempts) {\n await sleep(pollIntervalMs);\n attempts++;\n\n try {\n const result = await api.post<TokenPollResponse>('/auth/device/token', {\n device_code,\n });\n\n if (result.status === 'complete' && result.access_token && result.user) {\n // Success! Store the token\n await storeToken({\n token: result.access_token,\n user: result.user,\n expiresAt: result.expires_at,\n });\n\n spinner.stop();\n blank();\n printSuccess(`Logged in as ${chalk.bold(result.user.email)}`);\n return;\n }\n\n if (result.status === 'expired') {\n spinner.stop();\n blank();\n printError('Authentication expired. Please try again.');\n process.exit(1);\n }\n\n // Still pending, continue polling\n } catch (error) {\n // Network error, continue polling\n const message = error instanceof Error ? error.message : 'Unknown error';\n spinner.text = `Waiting for authentication... (${message})`;\n }\n }\n\n spinner.stop();\n blank();\n printError('Authentication timed out. Please try again.');\n process.exit(1);\n}\n\n/**\n * Token-based login (for CI/CD)\n */\nasync function tokenLogin(): Promise<void> {\n console.log('Token login mode.');\n console.log('Visit your Evident dashboard to generate a CLI token.');\n blank();\n\n // Read token from stdin\n process.stdout.write('Paste token: ');\n\n const token = await new Promise<string>((resolve) => {\n let data = '';\n process.stdin.setEncoding('utf8');\n process.stdin.on('data', (chunk) => {\n data += chunk;\n });\n process.stdin.on('end', () => {\n resolve(data.trim());\n });\n // For TTY, read a single line\n if (process.stdin.isTTY) {\n process.stdin.once('data', (chunk) => {\n process.stdin.pause();\n resolve(chunk.toString().trim());\n });\n process.stdin.resume();\n }\n });\n\n if (!token) {\n printError('No token provided.');\n process.exit(1);\n }\n\n // Validate the token\n const spinner = ora('Validating token...').start();\n\n try {\n interface ValidateResponse {\n user: { id: string; email: string };\n expires_at?: string;\n }\n\n const result = await api.post<ValidateResponse>('/auth/token/validate', { token });\n\n await storeToken({\n token,\n user: result.user,\n expiresAt: result.expires_at,\n });\n\n spinner.stop();\n printSuccess(`Logged in as ${chalk.bold(result.user.email)}`);\n } catch (error) {\n spinner.stop();\n const message = error instanceof Error ? error.message : 'Invalid token';\n printError(`Authentication failed: ${message}`);\n process.exit(1);\n }\n}\n\n/**\n * Login command handler\n */\nexport async function login(options: LoginOptions): Promise<void> {\n if (options.token) {\n await tokenLogin();\n } else {\n await deviceFlowLogin(options);\n }\n}\n","/**\n * CLI Configuration\n *\n * Manages configuration values and file-based credential storage.\n * Supports multiple environments: local, dev, production\n */\n\nimport Conf from 'conf';\nimport { homedir } from 'node:os';\nimport { join } from 'node:path';\n\n// Supported environments\nexport type Environment = 'local' | 'dev' | 'production';\n\n// Configuration schema\ninterface ConfigSchema {\n apiUrl: string;\n tunnelUrl: string;\n}\n\n// Credentials schema (stored separately with stricter permissions)\ninterface CredentialsSchema {\n token?: string;\n user?: {\n id: string;\n email: string;\n };\n expiresAt?: string;\n}\n\n// Environment presets\n// Domain format: {service}.{env}.evident.run (with aliases for production)\n// API URLs include /v1 prefix as all endpoints are versioned\nconst environmentPresets: Record<Environment, ConfigSchema> = {\n local: {\n apiUrl: 'http://localhost:3001/v1',\n tunnelUrl: 'ws://localhost:8787',\n },\n dev: {\n apiUrl: 'https://api.dev.evident.run/v1',\n tunnelUrl: 'wss://tunnel.dev.evident.run',\n },\n production: {\n // Production URLs also have aliases: api.evident.run, tunnel.evident.run\n apiUrl: 'https://api.production.evident.run/v1',\n tunnelUrl: 'wss://tunnel.production.evident.run',\n },\n};\n\n// Default to production\nconst defaults: ConfigSchema = environmentPresets.production;\n\n// Current environment (can be set via --env flag or EVIDENT_ENV)\nlet currentEnvironment: Environment = 'production';\n\n/**\n * Set the current environment\n */\nexport function setEnvironment(env: Environment): void {\n currentEnvironment = env;\n}\n\n/**\n * Get the current environment\n */\nexport function getEnvironment(): Environment {\n // Environment variable takes precedence\n const envVar = process.env.EVIDENT_ENV as Environment | undefined;\n if (envVar && environmentPresets[envVar]) {\n return envVar;\n }\n return currentEnvironment;\n}\n\n/**\n * Get configuration for current environment\n */\nfunction getEnvConfig(): ConfigSchema {\n return environmentPresets[getEnvironment()];\n}\n\n// Environment overrides (env vars take highest precedence)\nfunction getApiUrl(): string {\n return process.env.EVIDENT_API_URL ?? getEnvConfig().apiUrl;\n}\n\nfunction getTunnelUrl(): string {\n return process.env.EVIDENT_TUNNEL_URL ?? getEnvConfig().tunnelUrl;\n}\n\n// Configuration store\nconst config = new Conf<ConfigSchema>({\n projectName: 'evident',\n projectSuffix: '',\n defaults,\n});\n\n// Credentials store (separate file with restricted access)\nconst credentials = new Conf<CredentialsSchema>({\n projectName: 'evident',\n projectSuffix: '',\n configName: 'credentials',\n defaults: {},\n});\n\n/**\n * Get the configuration directory path\n */\nexport function getConfigDir(): string {\n // XDG_CONFIG_HOME on Linux, ~/.config on others\n const xdgConfig = process.env.XDG_CONFIG_HOME;\n if (xdgConfig) {\n return join(xdgConfig, 'evident');\n }\n return join(homedir(), '.config', 'evident');\n}\n\n/**\n * Get the API URL\n */\nexport function getApiUrlConfig(): string {\n return getApiUrl();\n}\n\n/**\n * Get the tunnel WebSocket URL\n */\nexport function getTunnelUrlConfig(): string {\n return getTunnelUrl();\n}\n\n/**\n * Get stored credentials\n */\nexport function getCredentials(): CredentialsSchema {\n return {\n token: credentials.get('token'),\n user: credentials.get('user'),\n expiresAt: credentials.get('expiresAt'),\n };\n}\n\n/**\n * Store credentials\n */\nexport function setCredentials(creds: CredentialsSchema): void {\n if (creds.token) credentials.set('token', creds.token);\n if (creds.user) credentials.set('user', creds.user);\n if (creds.expiresAt) credentials.set('expiresAt', creds.expiresAt);\n}\n\n/**\n * Clear stored credentials\n */\nexport function clearCredentials(): void {\n credentials.clear();\n}\n\n/**\n * Check if we have valid credentials\n */\nexport function hasValidCredentials(): boolean {\n const creds = getCredentials();\n\n if (!creds.token) {\n return false;\n }\n\n if (creds.expiresAt) {\n const expiresAt = new Date(creds.expiresAt);\n if (expiresAt < new Date()) {\n return false;\n }\n }\n\n return true;\n}\n\n/**\n * Get the CLI command name based on how it was invoked.\n * Returns 'evident' for normal usage, or the actual invocation for dev/npx usage.\n */\nexport function getCliName(): string {\n // Check if running via npx - multiple detection methods\n // 1. npm_execpath contains npx\n // 2. npm_command is 'exec' (npx sets this)\n // 3. Running from a global npx cache directory\n const argv1 = process.argv[1] || '';\n const isNpx =\n process.env.npm_execpath?.includes('npx') ||\n process.env.npm_command === 'exec' ||\n argv1.includes('_npx') ||\n argv1.includes('.npm/_cacache');\n\n if (isNpx) {\n return 'npx @evident-ai/cli@latest';\n }\n\n // Check if running via tsx (development)\n if (argv1.includes('tsx') || argv1.includes('ts-node')) {\n return 'pnpm --filter @evident-ai/cli dev:run';\n }\n\n // Default to 'evident' for normal installed CLI\n return 'evident';\n}\n\nexport { config, credentials };\n","/**\n * API Client\n *\n * Handles HTTP requests to the Evident backend API.\n */\n\nimport { getApiUrlConfig, getCredentials } from './config.js';\n\ninterface ApiRequestOptions {\n method?: 'GET' | 'POST' | 'PUT' | 'DELETE' | 'PATCH';\n body?: unknown;\n headers?: Record<string, string>;\n authenticated?: boolean;\n}\n\ninterface ApiError {\n message: string;\n statusCode: number;\n error?: string;\n}\n\nexport class ApiClient {\n private baseUrl: string;\n\n constructor(baseUrl?: string) {\n this.baseUrl = baseUrl ?? getApiUrlConfig();\n }\n\n /**\n * Make an API request\n */\n async request<T>(path: string, options: ApiRequestOptions = {}): Promise<T> {\n const { method = 'GET', body, headers = {}, authenticated = false } = options;\n\n const url = `${this.baseUrl}${path}`;\n\n const requestHeaders: Record<string, string> = {\n 'Content-Type': 'application/json',\n ...headers,\n };\n\n // Add authentication header if requested\n if (authenticated) {\n const creds = getCredentials();\n if (!creds.token) {\n throw new Error('Not authenticated. Run the `login` command first.');\n }\n requestHeaders['Authorization'] = `Bearer ${creds.token}`;\n }\n\n const response = await fetch(url, {\n method,\n headers: requestHeaders,\n body: body ? JSON.stringify(body) : undefined,\n });\n\n // Handle errors\n if (!response.ok) {\n let errorData: ApiError;\n try {\n errorData = (await response.json()) as ApiError;\n } catch {\n errorData = {\n message: response.statusText,\n statusCode: response.status,\n };\n }\n\n const error = new Error(errorData.message) as Error & { statusCode: number };\n error.statusCode = response.status;\n throw error;\n }\n\n // Handle empty responses\n const contentType = response.headers.get('Content-Type');\n if (!contentType?.includes('application/json')) {\n return {} as T;\n }\n\n return response.json() as Promise<T>;\n }\n\n /**\n * GET request\n */\n async get<T>(path: string, options: Omit<ApiRequestOptions, 'method' | 'body'> = {}): Promise<T> {\n return this.request<T>(path, { ...options, method: 'GET' });\n }\n\n /**\n * POST request\n */\n async post<T>(\n path: string,\n body?: unknown,\n options: Omit<ApiRequestOptions, 'method'> = {},\n ): Promise<T> {\n return this.request<T>(path, { ...options, method: 'POST', body });\n }\n\n /**\n * PUT request\n */\n async put<T>(\n path: string,\n body?: unknown,\n options: Omit<ApiRequestOptions, 'method'> = {},\n ): Promise<T> {\n return this.request<T>(path, { ...options, method: 'PUT', body });\n }\n\n /**\n * DELETE request\n */\n async delete<T>(\n path: string,\n options: Omit<ApiRequestOptions, 'method' | 'body'> = {},\n ): Promise<T> {\n return this.request<T>(path, { ...options, method: 'DELETE' });\n }\n}\n\n// Lazy API client instance - created on first use after env is set\nlet _api: ApiClient | null = null;\nexport const api = {\n get<T>(path: string, options?: Parameters<ApiClient['get']>[1]) {\n if (!_api) _api = new ApiClient();\n return _api.get<T>(path, options);\n },\n post<T>(path: string, body?: unknown, options?: Parameters<ApiClient['post']>[2]) {\n if (!_api) _api = new ApiClient();\n return _api.post<T>(path, body, options);\n },\n put<T>(path: string, body?: unknown, options?: Parameters<ApiClient['put']>[2]) {\n if (!_api) _api = new ApiClient();\n return _api.put<T>(path, body, options);\n },\n delete<T>(path: string, options?: Parameters<ApiClient['delete']>[1]) {\n if (!_api) _api = new ApiClient();\n return _api.delete<T>(path, options);\n },\n};\n","/**\n * Keychain Storage\n *\n * Provides secure credential storage using the system keychain.\n * Falls back to file-based storage if keychain is unavailable.\n */\n\nimport { getCredentials, setCredentials, clearCredentials } from './config.js';\n\nconst SERVICE_NAME = 'evident-cli';\nconst ACCOUNT_NAME = 'default';\n\n// Dynamic import for keytar (optional dependency)\nasync function getKeytar(): Promise<typeof import('keytar') | null> {\n try {\n const keytar = await import('keytar');\n // Verify keytar is actually functional (has the expected methods)\n if (typeof keytar.setPassword !== 'function') {\n return null;\n }\n return keytar;\n } catch {\n // keytar not available (e.g., missing native dependencies)\n return null;\n }\n}\n\nexport interface StoredCredentials {\n token: string;\n user: {\n id: string;\n email: string;\n };\n expiresAt?: string;\n}\n\n/**\n * Store credentials in the system keychain\n */\nexport async function storeToken(credentials: StoredCredentials): Promise<void> {\n const keytar = await getKeytar();\n\n if (keytar) {\n // Store in system keychain\n await keytar.setPassword(SERVICE_NAME, ACCOUNT_NAME, JSON.stringify(credentials));\n } else {\n // Fallback to file-based storage\n setCredentials({\n token: credentials.token,\n user: credentials.user,\n expiresAt: credentials.expiresAt,\n });\n }\n}\n\n/**\n * Retrieve credentials from the system keychain\n */\nexport async function getToken(): Promise<StoredCredentials | null> {\n const keytar = await getKeytar();\n\n if (keytar) {\n // Try system keychain first\n const stored = await keytar.getPassword(SERVICE_NAME, ACCOUNT_NAME);\n if (stored) {\n try {\n return JSON.parse(stored) as StoredCredentials;\n } catch {\n // Invalid JSON, clear it\n await keytar.deletePassword(SERVICE_NAME, ACCOUNT_NAME);\n return null;\n }\n }\n }\n\n // Fallback to file-based storage\n const creds = getCredentials();\n if (creds.token && creds.user) {\n return {\n token: creds.token,\n user: creds.user,\n expiresAt: creds.expiresAt,\n };\n }\n\n return null;\n}\n\n/**\n * Delete credentials from the system keychain\n */\nexport async function deleteToken(): Promise<void> {\n const keytar = await getKeytar();\n\n if (keytar) {\n await keytar.deletePassword(SERVICE_NAME, ACCOUNT_NAME);\n }\n\n // Always clear file-based storage too\n clearCredentials();\n}\n\n/**\n * Check if credentials are valid (not expired)\n */\nexport async function hasValidToken(): Promise<boolean> {\n const credentials = await getToken();\n\n if (!credentials) {\n return false;\n }\n\n if (credentials.expiresAt) {\n const expiresAt = new Date(credentials.expiresAt);\n if (expiresAt < new Date()) {\n return false;\n }\n }\n\n return true;\n}\n","/**\n * CLI UI Utilities\n *\n * Common formatting and display functions.\n */\n\nimport chalk from 'chalk';\n\n/**\n * Format success message\n */\nexport function success(message: string): string {\n return `${chalk.green('✓')} ${message}`;\n}\n\n/**\n * Format error message\n */\nexport function error(message: string): string {\n return `${chalk.red('✗')} ${message}`;\n}\n\n/**\n * Format warning message\n */\nexport function warning(message: string): string {\n return `${chalk.yellow('!')} ${message}`;\n}\n\n/**\n * Format info message\n */\nexport function info(message: string): string {\n return `${chalk.blue('i')} ${message}`;\n}\n\n/**\n * Print success message\n */\nexport function printSuccess(message: string): void {\n console.log(success(message));\n}\n\n/**\n * Print error message\n */\nexport function printError(message: string): void {\n console.error(error(message));\n}\n\n/**\n * Print warning message\n */\nexport function printWarning(message: string): void {\n console.log(warning(message));\n}\n\n/**\n * Print info message\n */\nexport function printInfo(message: string): void {\n console.log(info(message));\n}\n\n/**\n * Format a key-value pair for display\n */\nexport function keyValue(key: string, value: string): string {\n return `${chalk.dim(key + ':')} ${value}`;\n}\n\n/**\n * Print a blank line\n */\nexport function blank(): void {\n console.log();\n}\n\n/**\n * Wait for user to press Enter\n */\nexport function waitForEnter(prompt = 'Press Enter to continue...'): Promise<void> {\n return new Promise((resolve) => {\n process.stdout.write(chalk.dim(prompt));\n\n const handler = (): void => {\n process.stdin.removeListener('data', handler);\n process.stdin.setRawMode?.(false);\n process.stdin.pause();\n console.log();\n resolve();\n };\n\n if (process.stdin.isTTY) {\n process.stdin.setRawMode?.(true);\n }\n process.stdin.resume();\n process.stdin.once('data', handler);\n });\n}\n\n/**\n * Sleep for a given number of milliseconds\n */\nexport function sleep(ms: number): Promise<void> {\n return new Promise((resolve) => setTimeout(resolve, ms));\n}\n","/**\n * Logout Command\n *\n * Removes stored credentials.\n */\n\nimport { deleteToken, getToken } from '../lib/keychain.js';\nimport { printSuccess, printWarning } from '../utils/ui.js';\n\n/**\n * Logout command handler\n */\nexport async function logout(): Promise<void> {\n const credentials = await getToken();\n\n if (!credentials) {\n printWarning('You are not logged in.');\n return;\n }\n\n await deleteToken();\n printSuccess('Logged out successfully.');\n}\n","/**\n * Whoami Command\n *\n * Displays the currently logged in user.\n */\n\nimport chalk from 'chalk';\nimport { getToken } from '../lib/keychain.js';\nimport { printError, keyValue, blank } from '../utils/ui.js';\n\n/**\n * Whoami command handler\n */\nexport async function whoami(): Promise<void> {\n const credentials = await getToken();\n\n if (!credentials) {\n printError('Not logged in. Run the `login` command to authenticate.');\n process.exit(1);\n }\n\n blank();\n console.log(keyValue('User', chalk.bold(credentials.user.email)));\n console.log(keyValue('User ID', credentials.user.id));\n\n if (credentials.expiresAt) {\n const expiresAt = new Date(credentials.expiresAt);\n const now = new Date();\n\n if (expiresAt < now) {\n console.log(keyValue('Status', chalk.red('Token expired')));\n } else {\n const daysRemaining = Math.ceil(\n (expiresAt.getTime() - now.getTime()) / (1000 * 60 * 60 * 24),\n );\n console.log(keyValue('Expires', `${daysRemaining} days`));\n }\n }\n\n blank();\n}\n","/**\n * Run Command\n *\n * Unified command that connects to Evident and processes messages.\n *\n * Usage:\n * evident run --agent <id> # Interactive mode\n * evident run --agent <id> --conversation <id> # Process single conversation\n * evident run --agent <id> --idle-timeout 30 # Exit after 30s idle\n *\n * Features:\n * - Connects tunnel to Evident\n * - Processes pending messages from queue\n * - Forwards incoming requests to local OpenCode\n * - Rich interactive UI when running interactively\n * - JSON output mode for CI/CD\n */\n\nimport { ChildProcess } from 'child_process';\nimport chalk from 'chalk';\nimport ora from 'ora';\nimport { select } from '@inquirer/prompts';\nimport { getApiUrlConfig, getCliName } from '../lib/config.js';\nimport { printError, blank } from '../utils/ui.js';\nimport {\n telemetry,\n EventTypes,\n shutdownTelemetry,\n emitAgentConnected,\n emitAgentDisconnected,\n emitAgentMessageProcessing,\n emitAgentMessageDone,\n emitAgentMessageFailed,\n} from '../lib/telemetry.js';\nimport {\n getAuthCredentials,\n getAuthHeader,\n isInteractive,\n getToken,\n type AuthCredentials,\n} from '../lib/auth.js';\nimport {\n checkOpenCodeHealth,\n waitForOpenCodeHealth,\n startOpenCode,\n stopOpenCode,\n findHealthyOpenCodeInstances,\n isPortInUse,\n findAvailablePort,\n isOpenCodeInstalled,\n promptOpenCodeInstall,\n createOpenCodeSession,\n sendMessageToOpenCode,\n type OpenCodeQuestion,\n type OpenCodePermission,\n} from '../lib/opencode/index.js';\nimport { connectTunnel, getReconnectDelay, type TunnelConnection } from '../lib/tunnel/index.js';\nimport { login } from './login.js';\n\n// ============================================================================\n// Types\n// ============================================================================\n\nexport interface RunOptions {\n agent?: string;\n port?: number;\n verbose?: boolean;\n conversation?: string;\n idleTimeout?: number;\n json?: boolean;\n}\n\ninterface ActivityLogEntry {\n timestamp: Date;\n type: 'request' | 'response' | 'error' | 'info';\n method?: string;\n path?: string;\n status?: number;\n durationMs?: number;\n error?: string;\n message?: string;\n requestId?: string;\n}\n\ninterface RunState {\n agentId: string;\n agentName: string | null;\n port: number;\n verbose: boolean;\n conversationFilter: string | null;\n idleTimeout: number | null;\n json: boolean;\n interactive: boolean;\n\n // Connection state\n connected: boolean;\n opencodeConnected: boolean;\n opencodeVersion: string | null;\n reconnectAttempt: number;\n\n // Process management\n opencodeProcess: ChildProcess | null;\n tunnelConnection: TunnelConnection | null;\n running: boolean;\n\n // Activity tracking\n activityLog: ActivityLogEntry[];\n displayInitialized: boolean;\n lastActivity: Date;\n pendingRequests: Map<string, { startTime: number; method: string; path: string }>;\n\n // Queue processing\n sessions: Map<string, string>; // conversationId -> sessionId\n messageCount: number;\n\n // Lock management\n lockCorrelationId: string;\n lockedConversations: Set<string>;\n lockHeartbeatTimer: ReturnType<typeof setInterval> | null;\n\n // Reconnection management\n consecutiveFetchFailures: number;\n reconnecting: boolean;\n reconnectPromise: Promise<void> | null;\n\n // Authentication (mutable — updated on re-auth)\n authHeader: string;\n}\n\n// ============================================================================\n// Constants\n// ============================================================================\n\nconst MAX_ACTIVITY_LOG_ENTRIES = 10;\nconst MESSAGE_POLL_INTERVAL_MS = 2000;\nconst MAX_CONSECUTIVE_FETCH_FAILURES = 3;\nconst LOCK_HEARTBEAT_INTERVAL_MS = 5 * 60 * 1000; // 5 minutes\n\n// ============================================================================\n// API Calls\n// ============================================================================\n\ninterface AgentInfo {\n id: string;\n name: string;\n sandbox_type: 'local' | 'github_actions';\n status: string;\n}\n\ninterface PendingConversation {\n id: string;\n agent_id: string;\n opencode_session_id: string | null;\n pending_message_count: number;\n oldest_pending_at: string;\n}\n\ninterface QueuedMessage {\n id: string;\n thread_id: string;\n content: string;\n status: string;\n created_at: string;\n opencode_agent: string | null;\n opencode_model: string | null;\n}\n\n/**\n * Resolve the agent ID from an agent key via the /v1/me endpoint.\n * Only works when authenticated with EVIDENT_AGENT_KEY (agent_key auth type).\n */\nasync function resolveAgentIdFromKey(\n authHeader: string,\n): Promise<{ agent_id?: string; error?: string }> {\n const apiUrl = getApiUrlConfig();\n try {\n const response = await fetch(`${apiUrl}/me`, {\n headers: { Authorization: authHeader },\n });\n\n if (!response.ok) {\n return { error: `Failed to resolve agent from key: HTTP ${response.status}` };\n }\n\n const data = (await response.json()) as { auth_type: string; agent_id?: string };\n if (data.auth_type === 'agent_key' && data.agent_id) {\n return { agent_id: data.agent_id };\n }\n\n return {\n error:\n 'Cannot resolve agent ID: auth type is not agent_key. Please provide --agent explicitly.',\n };\n } catch (error) {\n const message = error instanceof Error ? error.message : 'Unknown error';\n return { error: `Failed to resolve agent from key: ${message}` };\n }\n}\n\n/**\n * Validate agent exists and get its info\n */\nasync function getAgentInfo(\n agentId: string,\n authHeader: string,\n): Promise<{ valid: boolean; agent?: AgentInfo; error?: string; authFailed?: boolean }> {\n const apiUrl = getApiUrlConfig();\n\n try {\n const response = await fetch(`${apiUrl}/agents/${agentId}`, {\n headers: { Authorization: authHeader },\n });\n\n if (response.status === 404) {\n return { valid: false, error: 'Agent not found' };\n }\n\n if (response.status === 401) {\n return { valid: false, error: 'Authentication failed', authFailed: true };\n }\n\n if (!response.ok) {\n return { valid: false, error: `API error: ${response.status}` };\n }\n\n const agent = (await response.json()) as AgentInfo;\n\n if (agent.sandbox_type !== 'local' && agent.sandbox_type !== 'github_actions') {\n return {\n valid: false,\n error: `Agent is type '${agent.sandbox_type}', must be 'local' or 'github_actions' for CLI connection`,\n };\n }\n\n return { valid: true, agent };\n } catch (error) {\n const message = error instanceof Error ? error.message : 'Unknown error';\n return { valid: false, error: `Failed to validate agent: ${message}` };\n }\n}\n\n/**\n * Custom error class for authentication failures\n * This allows queue processing to detect auth issues and handle them appropriately\n */\nclass AuthenticationError extends Error {\n constructor(message: string) {\n super(message);\n this.name = 'AuthenticationError';\n }\n}\n\n/**\n * Check if a response indicates an authentication failure\n */\nfunction checkAuthResponse(response: Response, context: string): void {\n if (response.status === 401 || response.status === 403) {\n throw new AuthenticationError(\n `Authentication failed during ${context}: HTTP ${response.status}. Your session may have expired.`,\n );\n }\n}\n\n/**\n * Get conversations with pending messages\n */\nasync function getPendingConversations(\n agentId: string,\n authHeader: string,\n conversationFilter?: string,\n): Promise<PendingConversation[]> {\n const apiUrl = getApiUrlConfig();\n const response = await fetch(`${apiUrl}/agents/${agentId}/conversations/pending`, {\n headers: { Authorization: authHeader },\n });\n\n checkAuthResponse(response, 'fetching pending conversations');\n\n if (!response.ok) {\n throw new Error(`Failed to get pending conversations: HTTP ${response.status}`);\n }\n\n const data = (await response.json()) as { conversations: PendingConversation[] };\n let conversations = data.conversations;\n\n // Filter by conversation ID if specified\n if (conversationFilter) {\n conversations = conversations.filter((c) => c.id === conversationFilter);\n }\n\n return conversations;\n}\n\n/**\n * Get pending messages for a conversation\n */\nasync function getPendingMessages(\n agentId: string,\n conversationId: string,\n authHeader: string,\n): Promise<QueuedMessage[]> {\n const apiUrl = getApiUrlConfig();\n const response = await fetch(\n `${apiUrl}/agents/${agentId}/threads/${conversationId}/messages?status=pending`,\n { headers: { Authorization: authHeader } },\n );\n\n checkAuthResponse(response, 'fetching pending messages');\n\n if (!response.ok) {\n throw new Error(`Failed to get messages: HTTP ${response.status}`);\n }\n\n return response.json() as Promise<QueuedMessage[]>;\n}\n\n/**\n * Mark a message as processing\n */\nasync function markMessageProcessing(\n agentId: string,\n conversationId: string,\n messageId: string,\n authHeader: string,\n): Promise<boolean> {\n const apiUrl = getApiUrlConfig();\n const response = await fetch(\n `${apiUrl}/agents/${agentId}/threads/${conversationId}/messages/${messageId}`,\n {\n method: 'PATCH',\n headers: { Authorization: authHeader, 'Content-Type': 'application/json' },\n body: JSON.stringify({ status: 'processing' }),\n },\n );\n\n checkAuthResponse(response, 'marking message as processing');\n\n return response.ok;\n}\n\n/**\n * Report a pending question or permission to the API so it can be surfaced\n * to the user via their connected channel (e.g. Slack).\n */\nasync function reportInteractiveEvent(\n agentId: string,\n conversationId: string,\n type: 'question' | 'permission',\n data: OpenCodeQuestion | OpenCodePermission,\n authHeader: string,\n): Promise<void> {\n const apiUrl = getApiUrlConfig();\n const response = await fetch(\n `${apiUrl}/agents/${agentId}/threads/${conversationId}/interactive-event`,\n {\n method: 'POST',\n headers: { Authorization: authHeader, 'Content-Type': 'application/json' },\n body: JSON.stringify({ type, data }),\n },\n );\n\n checkAuthResponse(response, 'reporting interactive event');\n\n if (!response.ok) {\n throw new Error(`Failed to report interactive event: HTTP ${response.status}`);\n }\n}\n\n/**\n * Mark a message as done\n */\nasync function markMessageDone(\n agentId: string,\n conversationId: string,\n messageId: string,\n authHeader: string,\n sessionId?: string,\n): Promise<void> {\n const apiUrl = getApiUrlConfig();\n const body: Record<string, unknown> = { status: 'done' };\n if (sessionId) {\n body.opencode_session_id = sessionId;\n }\n const response = await fetch(\n `${apiUrl}/agents/${agentId}/threads/${conversationId}/messages/${messageId}`,\n {\n method: 'PATCH',\n headers: { Authorization: authHeader, 'Content-Type': 'application/json' },\n body: JSON.stringify(body),\n },\n );\n\n checkAuthResponse(response, 'marking message as done');\n}\n\n/**\n * Mark a message as failed\n */\nasync function markMessageFailed(\n agentId: string,\n conversationId: string,\n messageId: string,\n authHeader: string,\n): Promise<void> {\n const apiUrl = getApiUrlConfig();\n const response = await fetch(\n `${apiUrl}/agents/${agentId}/threads/${conversationId}/messages/${messageId}`,\n {\n method: 'PATCH',\n headers: { Authorization: authHeader, 'Content-Type': 'application/json' },\n body: JSON.stringify({ status: 'failed' }),\n },\n );\n\n checkAuthResponse(response, 'marking message as failed');\n}\n\n/**\n * Acquire a lock on a conversation\n */\nasync function acquireConversationLock(\n agentId: string,\n conversationId: string,\n correlationId: string,\n authHeader: string,\n): Promise<{ acquired: boolean; error?: string }> {\n const apiUrl = getApiUrlConfig();\n try {\n const response = await fetch(`${apiUrl}/agents/${agentId}/threads/${conversationId}/lock`, {\n method: 'POST',\n headers: { Authorization: authHeader, 'Content-Type': 'application/json' },\n body: JSON.stringify({ correlation_id: correlationId }),\n });\n\n checkAuthResponse(response, 'acquiring conversation lock');\n\n if (response.status === 409) {\n return { acquired: false, error: 'Conversation already locked by another runner' };\n }\n\n if (!response.ok) {\n return { acquired: false, error: `Failed to acquire lock: HTTP ${response.status}` };\n }\n\n return { acquired: true };\n } catch (error) {\n if (error instanceof AuthenticationError) throw error;\n return { acquired: false, error: String(error) };\n }\n}\n\n/**\n * Extend a lock on a conversation (heartbeat)\n */\nasync function extendConversationLock(\n agentId: string,\n conversationId: string,\n correlationId: string,\n authHeader: string,\n): Promise<boolean> {\n const apiUrl = getApiUrlConfig();\n try {\n const response = await fetch(\n `${apiUrl}/agents/${agentId}/threads/${conversationId}/lock/extend`,\n {\n method: 'POST',\n headers: { Authorization: authHeader, 'Content-Type': 'application/json' },\n body: JSON.stringify({ correlation_id: correlationId }),\n },\n );\n return response.ok;\n } catch {\n return false;\n }\n}\n\n/**\n * Release a lock on a conversation\n */\nasync function releaseConversationLock(\n agentId: string,\n conversationId: string,\n correlationId: string,\n authHeader: string,\n): Promise<void> {\n const apiUrl = getApiUrlConfig();\n try {\n await fetch(\n `${apiUrl}/agents/${agentId}/threads/${conversationId}/lock?correlation_id=${encodeURIComponent(correlationId)}`,\n {\n method: 'DELETE',\n headers: { Authorization: authHeader },\n },\n );\n } catch {\n // Best effort — don't fail on lock release errors\n }\n}\n\n/**\n * Update conversation with OpenCode session ID\n */\nasync function updateConversationSession(\n agentId: string,\n conversationId: string,\n sessionId: string,\n authHeader: string,\n): Promise<void> {\n const apiUrl = getApiUrlConfig();\n const response = await fetch(`${apiUrl}/agents/${agentId}/threads/${conversationId}`, {\n method: 'PATCH',\n headers: { Authorization: authHeader, 'Content-Type': 'application/json' },\n body: JSON.stringify({ opencode_session_id: sessionId }),\n });\n\n checkAuthResponse(response, 'updating conversation session');\n if (!response.ok) {\n const text = await response.text().catch(() => '');\n throw new Error(\n `Failed to update conversation session: HTTP ${response.status}${text ? `: ${text}` : ''}`,\n );\n }\n}\n\n/**\n * Update conversation title from OpenCode session\n */\nasync function updateConversationTitle(\n agentId: string,\n conversationId: string,\n title: string,\n authHeader: string,\n): Promise<void> {\n const apiUrl = getApiUrlConfig();\n const response = await fetch(`${apiUrl}/agents/${agentId}/threads/${conversationId}`, {\n method: 'PATCH',\n headers: { Authorization: authHeader, 'Content-Type': 'application/json' },\n body: JSON.stringify({ title }),\n });\n\n checkAuthResponse(response, 'updating conversation title');\n}\n\n// ============================================================================\n// Logging\n// ============================================================================\n\nfunction log(state: RunState, message: string, isError = false): void {\n if (state.json) {\n console.log(\n JSON.stringify({\n timestamp: new Date().toISOString(),\n level: isError ? 'error' : 'info',\n message,\n }),\n );\n } else if (!state.interactive) {\n // Non-interactive, non-JSON: simple output\n const prefix = isError ? chalk.red('✗') : chalk.green('•');\n console.log(`${prefix} ${message}`);\n }\n // In interactive mode, we use the activity log instead\n}\n\nfunction logActivity(state: RunState, entry: Omit<ActivityLogEntry, 'timestamp'>): void {\n const fullEntry: ActivityLogEntry = {\n ...entry,\n timestamp: new Date(),\n };\n\n state.activityLog.push(fullEntry);\n\n if (state.activityLog.length > MAX_ACTIVITY_LOG_ENTRIES) {\n state.activityLog.shift();\n }\n\n state.lastActivity = fullEntry.timestamp;\n\n // In non-interactive mode, also log to console immediately\n if (!state.interactive) {\n if (entry.type === 'error') {\n log(state, entry.error ?? 'Unknown error', true);\n } else if (entry.type === 'info' && entry.message) {\n log(state, entry.message);\n }\n }\n}\n\n// ============================================================================\n// Display (Interactive Mode)\n// ============================================================================\n\nconst ANSI = {\n moveUp: (n: number) => `\\x1b[${n}A`,\n};\n\nconst STATUS_DISPLAY_HEIGHT = 22;\n\nfunction colorizeStatus(status: number): string {\n if (status >= 200 && status < 300) {\n return chalk.green(status.toString());\n } else if (status >= 300 && status < 400) {\n return chalk.yellow(status.toString());\n } else if (status >= 400 && status < 500) {\n return chalk.red(status.toString());\n } else if (status >= 500) {\n return chalk.bgRed.white(` ${status} `);\n }\n return status.toString();\n}\n\nfunction formatActivityEntry(entry: ActivityLogEntry): string {\n const time = entry.timestamp.toLocaleTimeString('en-US', {\n hour12: false,\n hour: '2-digit',\n minute: '2-digit',\n second: '2-digit',\n });\n\n switch (entry.type) {\n case 'request': {\n const duration = entry.durationMs ? ` (${entry.durationMs}ms)` : '';\n const status = entry.status ? ` -> ${colorizeStatus(entry.status)}` : ' ...';\n return ` ${chalk.dim(`[${time}]`)} ${chalk.cyan('<-')} ${entry.method} ${entry.path}${status}${duration}`;\n }\n\n case 'response': {\n const duration = entry.durationMs ? ` (${entry.durationMs}ms)` : '';\n return ` ${chalk.dim(`[${time}]`)} ${chalk.green('->')} ${entry.method} ${entry.path} ${colorizeStatus(entry.status!)}${duration}`;\n }\n\n case 'error': {\n const errorMsg = entry.error || 'Unknown error';\n const path = entry.path ? ` ${entry.method} ${entry.path}` : '';\n return ` ${chalk.dim(`[${time}]`)} ${chalk.red('x')}${path} - ${chalk.red(errorMsg)}`;\n }\n\n case 'info': {\n return ` ${chalk.dim(`[${time}]`)} ${chalk.blue('*')} ${entry.message}`;\n }\n\n default:\n return ` ${chalk.dim(`[${time}]`)} ${entry.message || 'Unknown'}`;\n }\n}\n\nfunction displayStatus(state: RunState): void {\n if (!state.interactive) return;\n\n const lines: string[] = [];\n\n // Header\n lines.push(chalk.bold('Evident'));\n lines.push(chalk.dim('-'.repeat(60)));\n lines.push('');\n\n // Agent info\n if (state.agentName) {\n lines.push(` Agent: ${state.agentName}`);\n }\n lines.push(` ID: ${state.agentId}`);\n if (state.conversationFilter) {\n lines.push(` Filter: conversation ${state.conversationFilter.slice(0, 8)}...`);\n }\n lines.push('');\n\n // Status indicators\n if (state.connected) {\n lines.push(` ${chalk.green('*')} Tunnel: ${chalk.green('Connected to Evident')}`);\n } else {\n if (state.reconnectAttempt > 0) {\n lines.push(\n ` ${chalk.yellow('o')} Tunnel: ${chalk.yellow(`Reconnecting... (attempt ${state.reconnectAttempt})`)}`,\n );\n } else {\n lines.push(` ${chalk.yellow('o')} Tunnel: ${chalk.yellow('Connecting...')}`);\n }\n }\n\n if (state.opencodeConnected) {\n const version = state.opencodeVersion ? `, v${state.opencodeVersion}` : '';\n lines.push(\n ` ${chalk.green('*')} OpenCode: ${chalk.green(`Running on port ${state.port}${version}`)}`,\n );\n } else {\n lines.push(` ${chalk.red('o')} OpenCode: ${chalk.red(`Not connected (port ${state.port})`)}`);\n }\n\n lines.push('');\n\n // Messages processed\n if (state.messageCount > 0) {\n lines.push(` Messages: ${state.messageCount} processed`);\n lines.push('');\n }\n\n // Activity log\n if (state.activityLog.length > 0) {\n lines.push(chalk.bold(' Activity:'));\n for (const entry of state.activityLog) {\n lines.push(formatActivityEntry(entry));\n }\n } else {\n lines.push(chalk.dim(' No activity yet. Waiting for requests...'));\n }\n\n lines.push('');\n lines.push(chalk.dim('-'.repeat(60)));\n\n if (state.verbose) {\n lines.push(chalk.dim(' Verbose mode: ON'));\n }\n\n lines.push('');\n lines.push(\n chalk.dim(` Tip: Run \\`opencode attach http://localhost:${state.port}\\` to see live activity`),\n );\n lines.push(chalk.dim(' Press Ctrl+C to disconnect'));\n\n while (lines.length < STATUS_DISPLAY_HEIGHT) {\n lines.push('');\n }\n\n if (!state.displayInitialized) {\n console.log('');\n console.log(chalk.dim('='.repeat(60)));\n console.log('');\n for (const line of lines) {\n console.log(line);\n }\n state.displayInitialized = true;\n } else {\n process.stdout.write(ANSI.moveUp(STATUS_DISPLAY_HEIGHT + 3));\n console.log(chalk.dim('='.repeat(60)));\n console.log('');\n for (const line of lines) {\n process.stdout.write('\\x1b[2K');\n console.log(line);\n }\n }\n}\n\n// ============================================================================\n// Authentication Helpers\n// ============================================================================\n\nasync function promptForLogin(\n promptMessage: string,\n successMessage: string,\n): Promise<AuthCredentials> {\n const action = await select({\n message: promptMessage,\n choices: [\n {\n name: 'Yes, log me in',\n value: 'login',\n description: 'Opens a browser to authenticate with Evident',\n },\n {\n name: 'No, exit',\n value: 'exit',\n description: 'Exit without logging in',\n },\n ],\n });\n\n if (action === 'exit') {\n console.log(chalk.dim(`\\nYou can log in later by running: ${getCliName()} login`));\n process.exit(0);\n }\n\n await login({ noBrowser: false });\n\n const credentials = await getToken();\n if (!credentials) {\n printError('Login failed. Please try again.');\n process.exit(1);\n }\n\n blank();\n console.log(chalk.green(successMessage));\n blank();\n\n return { token: credentials.token, authType: 'bearer', user: credentials.user };\n}\n\n// ============================================================================\n// OpenCode Setup\n// ============================================================================\n\nasync function ensureOpenCodeRunning(state: RunState): Promise<void> {\n const healthCheck = await checkOpenCodeHealth(state.port);\n\n if (healthCheck.healthy) {\n state.opencodeConnected = true;\n state.opencodeVersion = healthCheck.version ?? null;\n return;\n }\n\n // Check if running on different port\n const runningInstances = await findHealthyOpenCodeInstances();\n\n if (runningInstances.length > 0) {\n if (!state.interactive) {\n throw new Error(\n `OpenCode not found on port ${state.port}, but running on port ${runningInstances[0].port}. ` +\n `Use --port ${runningInstances[0].port}`,\n );\n }\n\n blank();\n console.log(chalk.yellow('Found OpenCode running on different port(s):'));\n for (const instance of runningInstances) {\n const ver = instance.version ? ` (v${instance.version})` : '';\n const cwd = instance.cwd ? ` in ${instance.cwd}` : '';\n console.log(chalk.dim(` * Port ${instance.port}${ver}${cwd}`));\n }\n blank();\n\n if (runningInstances.length === 1) {\n console.log(chalk.yellow('Tip: Run with the correct port:'));\n console.log(\n chalk.dim(\n ` ${getCliName()} run --agent ${state.agentId} --port ${runningInstances[0].port}`,\n ),\n );\n }\n blank();\n throw new Error(`OpenCode not running on port ${state.port}`);\n }\n\n // OpenCode not running anywhere\n if (!isOpenCodeInstalled()) {\n if (!state.interactive) {\n throw new Error('OpenCode is not installed. Install it with: npm install -g opencode-ai');\n }\n\n const result = await promptOpenCodeInstall(true);\n if (result === 'exit') {\n process.exit(0);\n }\n\n if (result === 'installed' || isOpenCodeInstalled()) {\n // Try to start it\n } else {\n throw new Error('OpenCode is not installed');\n }\n }\n\n // Offer to start OpenCode\n if (state.interactive) {\n // Check if port is in use\n let actualPort = state.port;\n if (isPortInUse(state.port)) {\n console.log(chalk.yellow(`\\nPort ${state.port} is already in use.`));\n const alternativePort = findAvailablePort(state.port + 1);\n if (alternativePort) {\n const useAlternative = await select({\n message: `Use port ${alternativePort} instead?`,\n choices: [\n { name: `Yes, use port ${alternativePort}`, value: 'yes' },\n { name: 'No, I will free the port manually', value: 'no' },\n ],\n });\n if (useAlternative === 'yes') {\n actualPort = alternativePort;\n state.port = actualPort;\n } else {\n throw new Error(`Port ${state.port} is in use`);\n }\n }\n }\n\n const action = await select({\n message: 'OpenCode is not running. What would you like to do?',\n choices: [\n {\n name: 'Start OpenCode for me',\n value: 'start',\n description: `Run 'opencode serve --port ${actualPort}'`,\n },\n {\n name: 'Show me the command',\n value: 'manual',\n description: 'Display the command to run manually',\n },\n {\n name: 'Continue without OpenCode',\n value: 'continue',\n description: 'Requests will fail until OpenCode starts',\n },\n ],\n });\n\n if (action === 'manual') {\n blank();\n console.log(chalk.bold('Run this command in another terminal:'));\n blank();\n console.log(` ${chalk.cyan(`opencode serve --port ${actualPort}`)}`);\n blank();\n throw new Error('Please start OpenCode manually');\n }\n\n if (action === 'start') {\n const spinner = ora('Starting OpenCode...').start();\n state.opencodeProcess = await startOpenCode(actualPort);\n const health = await waitForOpenCodeHealth(actualPort, 30000);\n\n if (!health.healthy) {\n spinner.fail('Failed to start OpenCode');\n throw new Error('OpenCode failed to start');\n }\n\n spinner.succeed(\n `OpenCode running on port ${actualPort}${health.version ? ` (v${health.version})` : ''}`,\n );\n state.opencodeConnected = true;\n state.opencodeVersion = health.version ?? null;\n }\n } else {\n // Non-interactive (CI): auto-start OpenCode rather than failing.\n // GitHub Actions runners have opencode-ai installed but don't pre-start it,\n // so the CLI must start it on their behalf.\n log(state, `OpenCode is not running on port ${state.port}. Starting it automatically...`);\n state.opencodeProcess = await startOpenCode(state.port);\n const health = await waitForOpenCodeHealth(state.port, 30000);\n\n if (!health.healthy) {\n throw new Error(\n `OpenCode failed to start on port ${state.port}. Install with: npm install -g opencode-ai`,\n );\n }\n\n log(\n state,\n `OpenCode started on port ${state.port}${health.version ? ` (v${health.version})` : ''}`,\n );\n state.opencodeConnected = true;\n state.opencodeVersion = health.version ?? null;\n }\n}\n\n// ============================================================================\n// Queue Processing\n// ============================================================================\n\n/** Exit code for authentication expiration in non-interactive mode */\nconst AUTH_EXPIRED_EXIT_CODE = 77;\n\n/**\n * Result of handling an authentication error\n */\ninterface AuthErrorResult {\n /** Whether authentication was successfully refreshed */\n success: boolean;\n /** New auth header if re-authenticated */\n newAuthHeader?: string;\n}\n\n/**\n * Handle authentication errors during queue processing.\n * In interactive mode, prompts for re-authentication.\n * In non-interactive mode, exits with a specific exit code.\n */\nasync function handleAuthError(\n state: RunState,\n error: AuthenticationError,\n): Promise<AuthErrorResult> {\n logActivity(state, {\n type: 'error',\n error: error.message,\n });\n if (state.interactive) displayStatus(state);\n\n if (!state.interactive) {\n // Non-interactive mode: log clear message and exit\n blank();\n console.log(chalk.red('Authentication expired'));\n console.log(chalk.dim('Your authentication token is no longer valid.'));\n blank();\n console.log(chalk.dim('To fix this:'));\n console.log(chalk.dim(` 1. Run '${getCliName()} login' to re-authenticate`));\n console.log(chalk.dim(' 2. Restart this command'));\n blank();\n await cleanup(state);\n await shutdownTelemetry();\n process.exit(AUTH_EXPIRED_EXIT_CODE);\n // Return to prevent fallthrough when process.exit is mocked in tests\n return { success: false };\n }\n\n // Interactive mode: prompt for re-authentication\n blank();\n console.log(chalk.yellow('Your authentication has expired.'));\n blank();\n\n try {\n const credentials = await promptForLogin(\n 'Would you like to log in again?',\n 'Re-authenticated successfully! Resuming...',\n );\n\n const newAuthHeader = getAuthHeader(credentials);\n return { success: true, newAuthHeader };\n } catch {\n // User declined to re-authenticate or login failed\n return { success: false };\n }\n}\n\n/**\n * Check if an error is a network/fetch failure that might be recoverable\n * through reconnection (as opposed to a logic error)\n */\nfunction isNetworkError(error: unknown): boolean {\n if (error instanceof Error) {\n const message = error.message.toLowerCase();\n return (\n message.includes('fetch failed') ||\n message.includes('network') ||\n message.includes('econnrefused') ||\n message.includes('econnreset') ||\n message.includes('etimedout') ||\n message.includes('socket hang up')\n );\n }\n return false;\n}\n\nasync function processQueue(\n state: RunState,\n authHeader: string,\n triggerReconnect: () => Promise<void>,\n): Promise<void> {\n // Number of consecutive poll cycles where the queue was empty.\n // Used to implement idle timeout without relying on wall-clock timing jitter.\n let idlePolls = 0;\n let currentAuthHeader = authHeader;\n\n while (state.running) {\n // Wait for any ongoing reconnection to complete\n if (state.reconnecting && state.reconnectPromise) {\n logActivity(state, {\n type: 'info',\n message: 'Waiting for tunnel reconnection...',\n });\n if (state.interactive) displayStatus(state);\n await state.reconnectPromise;\n }\n\n try {\n const conversations = await getPendingConversations(\n state.agentId,\n currentAuthHeader,\n state.conversationFilter ?? undefined,\n );\n\n // Reset consecutive failures on success\n state.consecutiveFetchFailures = 0;\n\n if (conversations.length > 0) {\n idlePolls = 0;\n\n for (const conv of conversations) {\n if (!state.running) break;\n\n // Acquire lock on the conversation before processing\n if (!state.lockedConversations.has(conv.id)) {\n const lockResult = await acquireConversationLock(\n state.agentId,\n conv.id,\n state.lockCorrelationId,\n currentAuthHeader,\n );\n if (!lockResult.acquired) {\n logActivity(state, {\n type: 'info',\n message: `Conversation ${conv.id.slice(0, 8)} locked by another runner — skipping`,\n });\n if (state.interactive) displayStatus(state);\n continue;\n }\n state.lockedConversations.add(conv.id);\n logActivity(state, {\n type: 'info',\n message: `Lock acquired on conversation ${conv.id.slice(0, 8)}`,\n });\n }\n\n logActivity(state, {\n type: 'info',\n message: `Processing conversation ${conv.id.slice(0, 8)}... (${conv.pending_message_count} pending)`,\n });\n if (state.interactive) displayStatus(state);\n\n // Get or create session\n let sessionId = state.sessions.get(conv.id);\n if (!sessionId) {\n if (conv.opencode_session_id) {\n sessionId = conv.opencode_session_id;\n } else {\n sessionId = await createOpenCodeSession(state.port);\n await updateConversationSession(state.agentId, conv.id, sessionId, currentAuthHeader);\n logActivity(state, {\n type: 'info',\n message: `Created session ${sessionId.slice(0, 8)}`,\n });\n }\n state.sessions.set(conv.id, sessionId);\n }\n\n // Process messages\n const messages = await getPendingMessages(state.agentId, conv.id, currentAuthHeader);\n\n for (const message of messages) {\n if (!state.running) break;\n\n logActivity(state, {\n type: 'info',\n message: `Processing message ${message.id.slice(0, 8)}...`,\n });\n if (state.interactive) displayStatus(state);\n\n const claimed = await markMessageProcessing(\n state.agentId,\n conv.id,\n message.id,\n currentAuthHeader,\n );\n if (!claimed) {\n logActivity(state, {\n type: 'info',\n message: `Message ${message.id.slice(0, 8)} already claimed`,\n });\n continue;\n }\n\n // Report to API for activity log (only after claim succeeds)\n emitAgentMessageProcessing(state.agentId, {\n message_id: message.id,\n conversation_id: conv.id,\n });\n\n try {\n const result = await sendMessageToOpenCode(\n state.port,\n sessionId,\n message.content,\n {\n agent: message.opencode_agent ?? undefined,\n model: message.opencode_model ?? undefined,\n },\n {\n onQuestion: async (question) => {\n try {\n await reportInteractiveEvent(\n state.agentId,\n conv.id,\n 'question',\n question,\n currentAuthHeader,\n );\n logActivity(state, {\n type: 'info',\n message: `Question surfaced to user (id: ${question.id.slice(0, 8)})`,\n });\n } catch (err) {\n logActivity(state, {\n type: 'error',\n error: `Failed to surface question: ${err}`,\n });\n }\n },\n onPermission: async (permission) => {\n try {\n await reportInteractiveEvent(\n state.agentId,\n conv.id,\n 'permission',\n permission,\n currentAuthHeader,\n );\n logActivity(state, {\n type: 'info',\n message: `Permission request surfaced to user (id: ${permission.id.slice(0, 8)})`,\n });\n } catch (err) {\n logActivity(state, {\n type: 'error',\n error: `Failed to surface permission: ${err}`,\n });\n }\n },\n },\n );\n\n // Sync OpenCode's session title to the conversation (best-effort)\n if (result.title) {\n try {\n await updateConversationTitle(\n state.agentId,\n conv.id,\n result.title,\n currentAuthHeader,\n );\n } catch {\n // Non-fatal: title sync failure should not fail the message\n }\n }\n await markMessageDone(\n state.agentId,\n conv.id,\n message.id,\n currentAuthHeader,\n sessionId,\n );\n state.messageCount++;\n logActivity(state, {\n type: 'info',\n message: `Message ${message.id.slice(0, 8)} processed`,\n });\n // Report to API for activity log\n emitAgentMessageDone(state.agentId, {\n message_id: message.id,\n conversation_id: conv.id,\n });\n } catch (error) {\n // Re-throw auth errors to be handled at the outer level\n if (error instanceof AuthenticationError) {\n throw error;\n }\n await markMessageFailed(state.agentId, conv.id, message.id, currentAuthHeader);\n logActivity(state, {\n type: 'error',\n error: `Message ${message.id.slice(0, 8)} failed: ${error}`,\n });\n // Report to API for activity log\n emitAgentMessageFailed(state.agentId, {\n message_id: message.id,\n conversation_id: conv.id,\n error: String(error),\n });\n }\n\n if (state.interactive) displayStatus(state);\n }\n }\n } else {\n // No pending messages — count idle poll cycles\n if (state.idleTimeout !== null) {\n idlePolls++;\n if (idlePolls === 1) {\n logActivity(state, {\n type: 'info',\n message: `Queue empty, waiting (timeout: ${state.idleTimeout}s)...`,\n });\n if (state.interactive) displayStatus(state);\n }\n }\n }\n\n // Sleep between polls. The idle check runs after the sleep so that a message\n // arriving just before the timeout gets at least one more poll cycle.\n await new Promise((resolve) => setTimeout(resolve, MESSAGE_POLL_INTERVAL_MS));\n\n // Check idle timeout after sleeping. Each idle poll represents MESSAGE_POLL_INTERVAL_MS\n // of idle time. We require at least 2 idle polls before firing — this guarantees\n // at least one additional poll runs after the queue first goes empty, giving messages\n // arriving just before the deadline a chance to be picked up.\n if (state.idleTimeout !== null && idlePolls >= 2) {\n const idleMs = idlePolls * MESSAGE_POLL_INTERVAL_MS;\n if (idleMs > state.idleTimeout * 1000) {\n logActivity(state, {\n type: 'info',\n message: 'Idle timeout reached',\n });\n if (state.interactive) displayStatus(state);\n break;\n }\n }\n } catch (error) {\n // Handle authentication errors specially\n if (error instanceof AuthenticationError) {\n const result = await handleAuthError(state, error);\n if (result.success && result.newAuthHeader) {\n currentAuthHeader = result.newAuthHeader;\n state.authHeader = result.newAuthHeader;\n logActivity(state, {\n type: 'info',\n message: 'Continuing with new credentials...',\n });\n if (state.interactive) displayStatus(state);\n continue; // Retry immediately with new credentials\n } else {\n // User declined re-auth, stop processing\n state.running = false;\n break;\n }\n }\n\n const errorMessage = error instanceof Error ? error.message : String(error);\n logActivity(state, {\n type: 'error',\n error: `Queue processing error: ${errorMessage}`,\n });\n if (state.interactive) displayStatus(state);\n\n // Track consecutive fetch failures to detect connection issues\n if (isNetworkError(error)) {\n state.consecutiveFetchFailures++;\n\n if (state.consecutiveFetchFailures >= MAX_CONSECUTIVE_FETCH_FAILURES) {\n logActivity(state, {\n type: 'info',\n message: `Detected ${state.consecutiveFetchFailures} consecutive fetch failures, triggering reconnection...`,\n });\n if (state.interactive) displayStatus(state);\n\n // Trigger reconnection\n await triggerReconnect();\n state.consecutiveFetchFailures = 0;\n }\n }\n\n await new Promise((resolve) => setTimeout(resolve, MESSAGE_POLL_INTERVAL_MS));\n }\n }\n}\n\n// ============================================================================\n// Cleanup\n// ============================================================================\n\nasync function cleanup(state: RunState, authHeader?: string): Promise<void> {\n state.running = false;\n\n // Stop lock heartbeat\n if (state.lockHeartbeatTimer) {\n clearInterval(state.lockHeartbeatTimer);\n state.lockHeartbeatTimer = null;\n }\n\n // Release all locks\n if (authHeader && state.lockedConversations.size > 0) {\n for (const convId of state.lockedConversations) {\n await releaseConversationLock(state.agentId, convId, state.lockCorrelationId, authHeader);\n }\n if (state.interactive) {\n logActivity(state, {\n type: 'info',\n message: `Released ${state.lockedConversations.size} lock(s)`,\n });\n displayStatus(state);\n } else {\n log(state, `Released ${state.lockedConversations.size} lock(s)`);\n }\n state.lockedConversations.clear();\n }\n\n if (state.tunnelConnection) {\n state.tunnelConnection.close();\n state.tunnelConnection = null;\n }\n\n if (state.opencodeProcess) {\n stopOpenCode(state.opencodeProcess);\n if (state.interactive) {\n logActivity(state, { type: 'info', message: 'Stopped OpenCode process' });\n displayStatus(state);\n } else {\n log(state, 'Stopped OpenCode process');\n }\n state.opencodeProcess = null;\n }\n}\n\n// ============================================================================\n// Main Command Handler\n// ============================================================================\n\nexport async function run(options: RunOptions): Promise<void> {\n const interactive = isInteractive(options.json);\n\n // Initialize state\n const state: RunState = {\n agentId: options.agent || '',\n agentName: null,\n port: options.port ?? 4096,\n verbose: options.verbose ?? false,\n conversationFilter: options.conversation ?? null,\n idleTimeout: options.idleTimeout ?? null,\n json: options.json ?? false,\n interactive,\n\n connected: false,\n opencodeConnected: false,\n opencodeVersion: null,\n reconnectAttempt: 0,\n\n opencodeProcess: null,\n tunnelConnection: null,\n running: true,\n\n activityLog: [],\n displayInitialized: false,\n lastActivity: new Date(),\n pendingRequests: new Map(),\n\n sessions: new Map(),\n messageCount: 0,\n\n lockCorrelationId: `cli-${Date.now()}-${Math.random().toString(36).slice(2, 8)}`,\n lockedConversations: new Set(),\n lockHeartbeatTimer: null,\n\n consecutiveFetchFailures: 0,\n reconnecting: false,\n reconnectPromise: null,\n\n authHeader: '',\n };\n\n if (state.idleTimeout === null && (process.env.GITHUB_ACTIONS || process.env.CI)) {\n log(\n state,\n 'Warning: No --idle-timeout set in CI environment. The runner will poll indefinitely until the job times out. Consider adding --idle-timeout 30 to avoid wasting runner minutes.',\n false,\n );\n }\n\n // Set up cleanup handlers\n const handleSignal = async () => {\n if (state.interactive) {\n logActivity(state, { type: 'info', message: 'Shutting down...' });\n displayStatus(state);\n } else {\n log(state, 'Shutting down...');\n }\n await cleanup(state, state.authHeader);\n await shutdownTelemetry();\n process.exit(0);\n };\n\n process.on('SIGINT', handleSignal);\n process.on('SIGTERM', handleSignal);\n\n try {\n // Step 1: Authenticate\n let credentials = await getAuthCredentials();\n\n if (!credentials) {\n if (!interactive) {\n printError('Authentication required');\n blank();\n console.log(chalk.dim('Set EVIDENT_AGENT_KEY environment variable for CI'));\n console.log(chalk.dim('Or run `evident login` for interactive authentication'));\n blank();\n process.exit(1);\n }\n\n blank();\n console.log(chalk.yellow('You are not logged in to Evident.'));\n blank();\n\n credentials = await promptForLogin(\n 'Would you like to log in now?',\n 'Login successful! Continuing...',\n );\n }\n\n state.authHeader = getAuthHeader(credentials);\n\n // Resolve agent ID from key if not provided explicitly\n if (!state.agentId) {\n if (credentials.authType === 'agent_key') {\n const resolved = await resolveAgentIdFromKey(state.authHeader);\n if (resolved.agent_id) {\n state.agentId = resolved.agent_id;\n log(state, `Resolved agent ID from key: ${state.agentId}`);\n } else {\n printError(resolved.error || 'Failed to resolve agent ID from key');\n process.exit(1);\n }\n } else {\n printError('--agent is required when not using EVIDENT_AGENT_KEY');\n blank();\n console.log(chalk.dim('Either provide --agent <id> or set EVIDENT_AGENT_KEY'));\n blank();\n process.exit(1);\n }\n }\n\n telemetry.info(\n EventTypes.CLI_COMMAND,\n 'Starting run command',\n {\n command: 'run',\n agentId: state.agentId,\n port: state.port,\n conversationFilter: state.conversationFilter,\n interactive,\n },\n state.agentId,\n );\n\n // Step 2: Validate agent\n if (interactive && !state.json) {\n blank();\n console.log(chalk.bold('Evident Run'));\n console.log(chalk.dim('-'.repeat(40)));\n }\n\n const spinner = interactive && !state.json ? ora('Validating agent...').start() : null;\n let validation = await getAgentInfo(state.agentId, state.authHeader);\n\n if (!validation.valid && validation.authFailed && interactive) {\n spinner?.fail('Authentication failed');\n blank();\n console.log(chalk.yellow('Your authentication token is invalid or expired.'));\n blank();\n\n credentials = await promptForLogin(\n 'Would you like to log in again?',\n 'Login successful! Retrying...',\n );\n\n state.authHeader = getAuthHeader(credentials);\n spinner?.start('Validating agent...');\n validation = await getAgentInfo(state.agentId, state.authHeader);\n }\n\n if (!validation.valid) {\n spinner?.fail(`Agent validation failed: ${validation.error}`);\n throw new Error(validation.error);\n }\n\n spinner?.succeed(`Agent: ${validation.agent!.name || state.agentId}`);\n state.agentName = validation.agent!.name;\n\n // Step 3: Ensure OpenCode is running\n const ocSpinner = interactive && !state.json ? ora('Checking OpenCode...').start() : null;\n\n try {\n await ensureOpenCodeRunning(state);\n const version = state.opencodeVersion ? ` (v${state.opencodeVersion})` : '';\n ocSpinner?.succeed(`OpenCode running on port ${state.port}${version}`);\n } catch (error) {\n ocSpinner?.fail((error as Error).message);\n throw error;\n }\n\n // Step 4: Connect tunnel\n const tunnelSpinner = interactive && !state.json ? ora('Connecting tunnel...').start() : null;\n\n /**\n * Connect to the tunnel with retry logic.\n * Can be called for initial connection or for reconnection after disconnect.\n * @param isReconnect - Whether this is a reconnection attempt (vs initial connection)\n */\n const connectWithRetry = async (isReconnect = false): Promise<void> => {\n // Prevent multiple simultaneous reconnection attempts\n if (isReconnect && state.reconnecting) {\n return;\n }\n\n state.reconnecting = true;\n\n // Close existing connection if any\n if (state.tunnelConnection) {\n try {\n state.tunnelConnection.close();\n } catch {\n // Ignore close errors\n }\n state.tunnelConnection = null;\n }\n\n while (state.running) {\n try {\n state.tunnelConnection = await connectTunnel({\n agentId: state.agentId,\n authHeader: state.authHeader,\n port: state.port,\n onConnected: (agentId) => {\n state.connected = true;\n state.reconnectAttempt = 0;\n state.reconnecting = false;\n state.consecutiveFetchFailures = 0;\n // Update state with server-resolved agent ID for consistency\n state.agentId = agentId;\n logActivity(state, {\n type: 'info',\n message: isReconnect\n ? `Tunnel reconnected (agent: ${agentId})`\n : `Tunnel connected (agent: ${agentId})`,\n });\n // Report to API for activity log\n emitAgentConnected(state.agentId, { port: state.port });\n if (state.interactive) displayStatus(state);\n },\n onDisconnected: (code, reason) => {\n state.connected = false;\n logActivity(state, {\n type: 'info',\n message: `Tunnel disconnected (code: ${code}, reason: ${reason})`,\n });\n // Report to API for activity log\n emitAgentDisconnected(state.agentId, { code, reason });\n if (state.interactive) displayStatus(state);\n\n // Auto-reconnect on unexpected disconnection (not manual shutdown)\n // Code 1000 = normal closure, 1001 = going away (expected)\n // Other codes indicate unexpected disconnection\n // Also skip if reconnection is already in progress (e.g., from fetch failures)\n if (state.running && code !== 1000 && !state.reconnecting) {\n logActivity(state, {\n type: 'info',\n message: 'Attempting automatic reconnection...',\n });\n if (state.interactive) displayStatus(state);\n\n // Trigger reconnection asynchronously\n state.reconnectPromise = connectWithRetry(true).catch((err) => {\n logActivity(state, {\n type: 'error',\n error: `Reconnection failed: ${err.message}`,\n });\n if (state.interactive) displayStatus(state);\n });\n }\n },\n onError: (error) => {\n logActivity(state, { type: 'error', error });\n if (state.interactive) displayStatus(state);\n },\n onRequest: (method, path, requestId) => {\n state.pendingRequests.set(requestId, {\n startTime: Date.now(),\n method,\n path,\n });\n logActivity(state, { type: 'request', method, path, requestId });\n if (state.interactive) displayStatus(state);\n },\n onResponse: (status, durationMs, requestId) => {\n const pending = state.pendingRequests.get(requestId);\n state.pendingRequests.delete(requestId);\n state.opencodeConnected = true;\n\n const lastEntry = state.activityLog[state.activityLog.length - 1];\n if (lastEntry && lastEntry.requestId === requestId) {\n lastEntry.type = 'response';\n lastEntry.status = status;\n lastEntry.durationMs = durationMs;\n } else if (pending) {\n logActivity(state, {\n type: 'response',\n method: pending.method,\n path: pending.path,\n status,\n durationMs,\n requestId,\n });\n }\n if (state.interactive) displayStatus(state);\n },\n onInfo: (message) => {\n logActivity(state, { type: 'info', message });\n if (state.interactive) displayStatus(state);\n },\n });\n\n if (!isReconnect) {\n tunnelSpinner?.succeed('Tunnel connected');\n }\n return;\n } catch (error) {\n state.reconnectAttempt++;\n const delay = getReconnectDelay(state.reconnectAttempt);\n\n if ((error as Error).message === 'Unauthorized') {\n state.reconnecting = false;\n if (!isReconnect) {\n tunnelSpinner?.fail('Unauthorized');\n }\n throw error;\n }\n\n logActivity(state, {\n type: 'error',\n error: `Connection failed, retrying in ${Math.round(delay / 1000)}s...`,\n });\n if (state.interactive) displayStatus(state);\n\n await new Promise((resolve) => setTimeout(resolve, delay));\n }\n }\n\n state.reconnecting = false;\n };\n\n /**\n * Trigger reconnection from queue processing when fetch failures are detected.\n * Handles errors gracefully to avoid crashing processQueue.\n */\n const triggerReconnect = async (): Promise<void> => {\n if (!state.reconnecting) {\n state.reconnectPromise = connectWithRetry(true).catch((err) => {\n logActivity(state, {\n type: 'error',\n error: `Reconnection failed: ${err.message}`,\n });\n if (state.interactive) displayStatus(state);\n });\n }\n if (state.reconnectPromise) {\n await state.reconnectPromise;\n }\n };\n\n await connectWithRetry(false);\n\n // Step 5: Start lock heartbeat (extends locks every 5 minutes)\n state.lockHeartbeatTimer = setInterval(async () => {\n for (const convId of state.lockedConversations) {\n const extended = await extendConversationLock(\n state.agentId,\n convId,\n state.lockCorrelationId,\n state.authHeader,\n );\n if (!extended) {\n logActivity(state, {\n type: 'error',\n error: `Failed to extend lock on conversation ${convId.slice(0, 8)}`,\n });\n state.lockedConversations.delete(convId);\n }\n }\n }, LOCK_HEARTBEAT_INTERVAL_MS);\n\n // Step 6: Process queue and handle requests\n if (interactive && !state.json) {\n displayStatus(state);\n } else {\n log(state, 'Processing queue...');\n }\n\n await processQueue(state, state.authHeader, triggerReconnect);\n\n // Done\n await cleanup(state, state.authHeader);\n\n if (state.json) {\n console.log(\n JSON.stringify({\n status: 'success',\n messages_processed: state.messageCount,\n }),\n );\n } else if (!interactive) {\n log(state, `Completed. Processed ${state.messageCount} message(s).`);\n }\n\n await shutdownTelemetry();\n process.exit(0);\n } catch (error) {\n await cleanup(state, state.authHeader);\n\n const message = error instanceof Error ? error.message : String(error);\n\n if (state.json) {\n console.log(JSON.stringify({ status: 'error', error: message }));\n } else {\n printError(message);\n }\n\n telemetry.error(EventTypes.CLI_ERROR, `Run command failed: ${message}`, {\n command: 'run',\n agentId: options.agent,\n });\n await shutdownTelemetry();\n process.exit(1);\n }\n}\n","/**\n * Telemetry API types - shared between CLI and API\n *\n * These types define the contract for the telemetry endpoint.\n * Both CLI and API should use these types to ensure type safety.\n */\n\nimport { EventSeverity } from '../events/index.js';\n\n/** Client types that can send telemetry */\nexport type TelemetryClientType = 'cli' | 'sdk' | 'web';\n\n// ============================================================================\n// Event type constants\n// ============================================================================\n\nexport const TelemetryEventTypes = {\n // Agent activity events (shown in web UI activity log)\n AGENT_CONNECTED: 'agent.connected',\n AGENT_DISCONNECTED: 'agent.disconnected',\n AGENT_MESSAGE_PROCESSING: 'agent.message_processing',\n AGENT_MESSAGE_DONE: 'agent.message_done',\n AGENT_MESSAGE_FAILED: 'agent.message_failed',\n} as const;\n\nexport type TelemetryEventType = (typeof TelemetryEventTypes)[keyof typeof TelemetryEventTypes];\n\n// ============================================================================\n// Specific event types with typed metadata\n// ============================================================================\n\n/** Agent connected to Evident */\nexport interface AgentConnectedEvent {\n event_type: typeof TelemetryEventTypes.AGENT_CONNECTED;\n severity?: EventSeverity;\n message?: string;\n metadata: { port: number };\n agent_id: string;\n timestamp?: string;\n}\n\n/** Agent disconnected from Evident */\nexport interface AgentDisconnectedEvent {\n event_type: typeof TelemetryEventTypes.AGENT_DISCONNECTED;\n severity?: EventSeverity;\n message?: string;\n metadata: { code: number; reason: string };\n agent_id: string;\n timestamp?: string;\n}\n\n/** Agent started processing a message */\nexport interface AgentMessageProcessingEvent {\n event_type: typeof TelemetryEventTypes.AGENT_MESSAGE_PROCESSING;\n severity?: EventSeverity;\n message?: string;\n metadata: { message_id: string; conversation_id: string };\n agent_id: string;\n timestamp?: string;\n}\n\n/** Agent finished processing a message successfully */\nexport interface AgentMessageDoneEvent {\n event_type: typeof TelemetryEventTypes.AGENT_MESSAGE_DONE;\n severity?: EventSeverity;\n message?: string;\n metadata: { message_id: string; conversation_id: string };\n agent_id: string;\n timestamp?: string;\n}\n\n/** Agent failed to process a message */\nexport interface AgentMessageFailedEvent {\n event_type: typeof TelemetryEventTypes.AGENT_MESSAGE_FAILED;\n severity?: EventSeverity;\n message?: string;\n metadata: { message_id: string; conversation_id: string; reason?: string; error?: string };\n agent_id: string;\n timestamp?: string;\n}\n\n/** Union of all specific telemetry events */\nexport type TelemetryEvent =\n | AgentConnectedEvent\n | AgentDisconnectedEvent\n | AgentMessageProcessingEvent\n | AgentMessageDoneEvent\n | AgentMessageFailedEvent;\n\n// ============================================================================\n// Generic event type (for API validation - accepts any event)\n// ============================================================================\n\n/**\n * Generic telemetry event request (used by API for validation).\n * Clients should use specific event types above for type safety.\n */\nexport interface TelemetryEventRequest {\n event_type: string;\n severity?: EventSeverity;\n message?: string;\n metadata?: Record<string, unknown>;\n agent_id?: string;\n timestamp?: string;\n}\n\n// ============================================================================\n// Request/Response types\n// ============================================================================\n\n/**\n * Batch request to submit multiple telemetry events\n */\nexport interface SubmitTelemetryEventsRequest {\n events: TelemetryEventRequest[];\n client_type: TelemetryClientType;\n client_version?: string;\n}\n\n/**\n * Response from submitting telemetry events\n */\nexport interface SubmitTelemetryEventsResponse {\n received: number;\n}\n","/**\n * Tunnel types - shared between API, Tunnel Relay (Cloudflare Worker), and CLI\n *\n * These types define the protocol for the WebSocket tunnel that connects\n * local OpenCode instances to the Evident platform.\n */\n\n// ============================================================================\n// API <-> Relay communication\n// ============================================================================\n\n/**\n * Token validation response from API to Relay\n * Sent when CLI connects and Relay validates the token with the API\n */\nexport interface TunnelTokenValidationResponse {\n agent_id: string;\n user_id: string;\n}\n\n/**\n * Token validation request from Relay to API\n */\nexport interface TunnelTokenValidationRequest {\n token: string;\n agent_id: string;\n auth_type: 'bearer' | 'sandbox_key';\n}\n\n/**\n * Status update from Relay to API\n * Sent when CLI connects or disconnects\n */\nexport interface TunnelStatusUpdate {\n agent_id: string;\n status: 'connected' | 'disconnected';\n close_code?: number;\n close_reason?: string;\n}\n\n/**\n * Internal request from API to forward to tunnel\n */\nexport interface TunnelForwardRequest {\n request_id: string;\n method: string;\n path: string;\n headers?: Record<string, string>;\n body?: unknown;\n timeout_ms?: number;\n}\n\n// ============================================================================\n// Relay <-> CLI communication (WebSocket messages)\n// ============================================================================\n\n/**\n * Message types from Relay to CLI\n */\nexport type RelayToCLIMessage =\n | { type: 'connected'; agent_id: string }\n | { type: 'error'; code: string; message: string }\n | { type: 'ping' }\n | { type: 'request'; id: string; payload: TunnelRequestPayload }\n | { type: 'subscribe_events'; id: string }\n | { type: 'unsubscribe_events'; id: string };\n\n/**\n * HTTP request payload forwarded to CLI\n */\nexport interface TunnelRequestPayload {\n method: string;\n path: string;\n headers?: Record<string, string>;\n body?: unknown;\n}\n\n/**\n * Message types from CLI to Relay\n */\nexport type CLIToRelayMessage =\n | { type: 'pong' }\n | { type: 'response'; id: string; payload: TunnelResponsePayload }\n | {\n type: 'response_start';\n id: string;\n total_chunks: number;\n total_size: number;\n payload: Omit<TunnelResponsePayload, 'body'>;\n }\n | { type: 'response_chunk'; id: string; chunk_index: number; data: string }\n | { type: 'response_end'; id: string }\n | { type: 'status'; status: 'ready' | 'busy' }\n | { type: 'event'; id: string; event: unknown }\n | { type: 'event_error'; id: string; error: string }\n | { type: 'event_end'; id: string };\n\n/**\n * Response payload from CLI\n */\nexport interface TunnelResponsePayload {\n status: number;\n headers?: Record<string, string>;\n body?: unknown;\n}\n\n// ============================================================================\n// Internal Relay state\n// ============================================================================\n\n/**\n * Tunnel connection metadata stored in the Durable Object\n */\nexport interface TunnelMetadata {\n agent_id: string;\n user_id: string;\n connected_at: string;\n last_activity: string;\n}\n\n// Note: TunnelStatus is defined in agents/index.ts as 'connected' | 'disconnected' | null\n// We re-use that type for tunnel operations\n\n// ============================================================================\n// Protocol constants\n// ============================================================================\n\n/** Responses larger than this are chunked (512KB) */\nexport const TUNNEL_CHUNK_THRESHOLD = 512 * 1024;\n\n/** Size of each chunk - fits under 1MB with base64 encoding (768KB) */\nexport const TUNNEL_CHUNK_SIZE = 768 * 1024;\n\n/** Maximum total response size (50MB) */\nexport const TUNNEL_MAX_RESPONSE_SIZE = 50 * 1024 * 1024;\n\n/** Timeout for receiving all chunks (30s) */\nexport const TUNNEL_CHUNK_TIMEOUT_MS = 30 * 1000;\n","/**\n * CLI Telemetry Client\n *\n * Captures and reports events to the Evident API for debugging and observability.\n * Events are batched and sent periodically to minimize network overhead.\n */\n\nimport {\n TelemetryEventRequest,\n SubmitTelemetryEventsRequest,\n TelemetryEventTypes,\n TelemetryEvent,\n AgentConnectedEvent,\n AgentDisconnectedEvent,\n AgentMessageProcessingEvent,\n AgentMessageDoneEvent,\n AgentMessageFailedEvent,\n EventSeverity,\n} from '@evident/types';\nimport { getApiUrlConfig } from './config.js';\nimport { getToken } from './keychain.js';\n\n// Get version from package.json at build time\nconst CLI_VERSION = process.env.npm_package_version || 'unknown';\n\n// Re-export for convenience\nexport type { EventSeverity } from '@evident/types';\n// Re-export event types from shared package\nexport { TelemetryEventTypes } from '@evident/types';\n\n// Event buffer for batching\nlet eventBuffer: TelemetryEventRequest[] = [];\nlet flushTimeout: NodeJS.Timeout | null = null;\nlet isShuttingDown = false;\n\n// Configuration\nconst FLUSH_INTERVAL_MS = 5000; // Flush every 5 seconds\nconst MAX_BUFFER_SIZE = 50; // Flush when buffer reaches this size\nconst FLUSH_TIMEOUT_MS = 3000; // Timeout for flush requests\n\n/**\n * Log a telemetry event\n * Events are buffered and sent in batches\n */\nexport function logEvent(\n eventType: string,\n options: {\n severity?: EventSeverity;\n message?: string;\n metadata?: Record<string, unknown>;\n agentId?: string;\n } = {},\n): void {\n const event: TelemetryEventRequest = {\n event_type: eventType,\n severity: options.severity || 'info',\n message: options.message,\n metadata: options.metadata,\n agent_id: options.agentId,\n timestamp: new Date().toISOString(),\n };\n\n eventBuffer.push(event);\n\n // Flush immediately for errors or if buffer is full\n if (options.severity === 'error' || eventBuffer.length >= MAX_BUFFER_SIZE) {\n void flushEvents();\n } else if (!flushTimeout && !isShuttingDown) {\n // Schedule a flush\n flushTimeout = setTimeout(() => {\n flushTimeout = null;\n void flushEvents();\n }, FLUSH_INTERVAL_MS);\n }\n}\n\n/**\n * Convenience methods for different severity levels\n */\nexport const telemetry = {\n debug: (\n eventType: string,\n message?: string,\n metadata?: Record<string, unknown>,\n agentId?: string,\n ) => logEvent(eventType, { severity: 'debug', message, metadata, agentId }),\n\n info: (\n eventType: string,\n message?: string,\n metadata?: Record<string, unknown>,\n agentId?: string,\n ) => logEvent(eventType, { severity: 'info', message, metadata, agentId }),\n\n warn: (\n eventType: string,\n message?: string,\n metadata?: Record<string, unknown>,\n agentId?: string,\n ) => logEvent(eventType, { severity: 'warning', message, metadata, agentId }),\n\n error: (\n eventType: string,\n message?: string,\n metadata?: Record<string, unknown>,\n agentId?: string,\n ) => logEvent(eventType, { severity: 'error', message, metadata, agentId }),\n};\n\n/**\n * Flush buffered events to the API\n */\nexport async function flushEvents(): Promise<void> {\n if (eventBuffer.length === 0) return;\n\n // Take current buffer and reset\n const events = eventBuffer;\n eventBuffer = [];\n\n // Clear any pending flush timeout\n if (flushTimeout) {\n clearTimeout(flushTimeout);\n flushTimeout = null;\n }\n\n try {\n const credentials = await getToken();\n if (!credentials) {\n // Not logged in, can't send telemetry\n return;\n }\n\n const apiUrl = getApiUrlConfig();\n const controller = new AbortController();\n const timeout = setTimeout(() => controller.abort(), FLUSH_TIMEOUT_MS);\n\n try {\n // Type-check the request against the shared contract\n const request: SubmitTelemetryEventsRequest = {\n events,\n client_type: 'cli',\n client_version: CLI_VERSION,\n };\n\n const response = await fetch(`${apiUrl}/telemetry/events`, {\n method: 'POST',\n headers: {\n 'Content-Type': 'application/json',\n Authorization: `Bearer ${credentials.token}`,\n },\n body: JSON.stringify(request),\n signal: controller.signal,\n });\n\n if (!response.ok) {\n // Log failure but don't throw - telemetry shouldn't break the CLI\n console.error(`Telemetry flush failed: ${response.status}`);\n }\n } finally {\n clearTimeout(timeout);\n }\n } catch (error) {\n // Silently ignore telemetry errors - don't disrupt the user\n if (process.env.DEBUG) {\n console.error('Telemetry error:', error);\n }\n }\n}\n\n/**\n * Shutdown telemetry - flush remaining events\n * Call this before the process exits\n */\nexport async function shutdownTelemetry(): Promise<void> {\n isShuttingDown = true;\n\n if (flushTimeout) {\n clearTimeout(flushTimeout);\n flushTimeout = null;\n }\n\n await flushEvents();\n}\n\n// ============================================================================\n// Type-safe event emitters for agent activity events\n// These ensure the correct metadata is provided for each event type\n// ============================================================================\n\nfunction emitEvent(event: TelemetryEvent): void {\n logEvent(event.event_type, {\n severity: event.severity,\n message: event.message,\n metadata: event.metadata,\n agentId: event.agent_id,\n });\n}\n\n/** Emit agent connected event */\nexport function emitAgentConnected(\n agentId: string,\n metadata: AgentConnectedEvent['metadata'],\n): void {\n emitEvent({\n event_type: TelemetryEventTypes.AGENT_CONNECTED,\n severity: 'info',\n message: 'Agent CLI connected',\n metadata,\n agent_id: agentId,\n } satisfies AgentConnectedEvent);\n}\n\n/** Emit agent disconnected event */\nexport function emitAgentDisconnected(\n agentId: string,\n metadata: AgentDisconnectedEvent['metadata'],\n): void {\n emitEvent({\n event_type: TelemetryEventTypes.AGENT_DISCONNECTED,\n severity: 'info',\n message: `Agent CLI disconnected (code: ${metadata.code})`,\n metadata,\n agent_id: agentId,\n } satisfies AgentDisconnectedEvent);\n}\n\n/** Emit agent message processing event */\nexport function emitAgentMessageProcessing(\n agentId: string,\n metadata: AgentMessageProcessingEvent['metadata'],\n): void {\n emitEvent({\n event_type: TelemetryEventTypes.AGENT_MESSAGE_PROCESSING,\n severity: 'info',\n message: `Processing message ${metadata.message_id.slice(0, 8)}...`,\n metadata,\n agent_id: agentId,\n } satisfies AgentMessageProcessingEvent);\n}\n\n/** Emit agent message done event */\nexport function emitAgentMessageDone(\n agentId: string,\n metadata: AgentMessageDoneEvent['metadata'],\n): void {\n emitEvent({\n event_type: TelemetryEventTypes.AGENT_MESSAGE_DONE,\n severity: 'info',\n message: `Message ${metadata.message_id.slice(0, 8)} processed`,\n metadata,\n agent_id: agentId,\n } satisfies AgentMessageDoneEvent);\n}\n\n/** Emit agent message failed event */\nexport function emitAgentMessageFailed(\n agentId: string,\n metadata: AgentMessageFailedEvent['metadata'],\n): void {\n emitEvent({\n event_type: TelemetryEventTypes.AGENT_MESSAGE_FAILED,\n severity: 'error',\n message: metadata.error\n ? `Message ${metadata.message_id.slice(0, 8)} failed: ${metadata.error}`\n : `Message ${metadata.message_id.slice(0, 8)} ${metadata.reason || 'failed'}`,\n metadata,\n agent_id: agentId,\n } satisfies AgentMessageFailedEvent);\n}\n\n// ============================================================================\n// Legacy event types (for non-activity events like CLI lifecycle, auth, etc.)\n// ============================================================================\n\nexport const EventTypes = {\n // Tunnel lifecycle\n TUNNEL_STARTING: 'tunnel.starting',\n TUNNEL_CONNECTED: 'tunnel.connected',\n TUNNEL_DISCONNECTED: 'tunnel.disconnected',\n TUNNEL_RECONNECTING: 'tunnel.reconnecting',\n TUNNEL_ERROR: 'tunnel.error',\n\n // OpenCode communication\n OPENCODE_HEALTH_CHECK: 'opencode.health_check',\n OPENCODE_HEALTH_OK: 'opencode.health_ok',\n OPENCODE_HEALTH_FAILED: 'opencode.health_failed',\n OPENCODE_REQUEST_RECEIVED: 'opencode.request_received',\n OPENCODE_REQUEST_FORWARDED: 'opencode.request_forwarded',\n OPENCODE_RESPONSE_SENT: 'opencode.response_sent',\n OPENCODE_UNREACHABLE: 'opencode.unreachable',\n OPENCODE_ERROR: 'opencode.error',\n\n // Authentication\n AUTH_LOGIN_STARTED: 'auth.login_started',\n AUTH_LOGIN_SUCCESS: 'auth.login_success',\n AUTH_LOGIN_FAILED: 'auth.login_failed',\n AUTH_LOGOUT: 'auth.logout',\n\n // CLI lifecycle\n CLI_STARTED: 'cli.started',\n CLI_COMMAND: 'cli.command',\n CLI_ERROR: 'cli.error',\n} as const;\n","/**\n * Unified Authentication\n *\n * Provides authentication that works for both interactive (keychain) and CI (env vars) modes.\n *\n * Priority:\n * 1. EVIDENT_AGENT_KEY - API key for CI environments\n * 2. EVIDENT_TOKEN - User token (alternative to key)\n * 3. Keychain - Stored credentials from `evident login`\n */\n\nimport { getToken, StoredCredentials } from './keychain.js';\n\nexport type AuthType = 'agent_key' | 'bearer';\n\nexport interface AuthCredentials {\n token: string;\n authType: AuthType;\n /** User info (only available for keychain auth) */\n user?: {\n id: string;\n email: string;\n };\n}\n\n/**\n * Get the authentication credentials.\n *\n * Priority:\n * 1. EVIDENT_AGENT_KEY env var (CI mode)\n * 2. EVIDENT_TOKEN env var (CI mode)\n * 3. Keychain credentials (interactive mode)\n *\n * @returns Credentials if available, null otherwise\n */\nexport async function getAuthCredentials(): Promise<AuthCredentials | null> {\n // Check for agent key (CI environment)\n const agentKey = process.env.EVIDENT_AGENT_KEY;\n if (agentKey) {\n return { token: agentKey, authType: 'agent_key' };\n }\n\n // Check for user token (env var)\n const userToken = process.env.EVIDENT_TOKEN;\n if (userToken) {\n return { token: userToken, authType: 'bearer' };\n }\n\n // Fall back to keychain credentials\n const keychainCreds = await getToken();\n if (keychainCreds) {\n return {\n token: keychainCreds.token,\n authType: 'bearer',\n user: keychainCreds.user,\n };\n }\n\n // No credentials available\n return null;\n}\n\n/**\n * Get the Authorization header value for the given credentials\n */\nexport function getAuthHeader(credentials: AuthCredentials): string {\n if (credentials.authType === 'agent_key') {\n return `SandboxKey ${credentials.token}`;\n }\n return `Bearer ${credentials.token}`;\n}\n\n/**\n * Check if we're running in an interactive environment.\n *\n * Non-interactive if:\n * - CI environment variable is set\n * - GITHUB_ACTIONS environment variable is set\n * - stdin is not a TTY\n *\n * @param jsonOutput - If true, force non-interactive mode\n */\nexport function isInteractive(jsonOutput?: boolean): boolean {\n if (jsonOutput) return false;\n if (process.env.CI) return false;\n if (process.env.GITHUB_ACTIONS) return false;\n if (!process.stdin.isTTY) return false;\n return true;\n}\n\n// Re-export keychain functions for convenience\nexport { getToken, storeToken, deleteToken, hasValidToken } from './keychain.js';\nexport type { StoredCredentials };\n","/**\n * OpenCode Health Checking\n *\n * Functions for checking OpenCode health status and waiting for it to become healthy.\n */\n\nexport interface HealthCheckResult {\n healthy: boolean;\n version?: string;\n error?: string;\n}\n\n/**\n * Check if a port has a valid OpenCode instance by calling /global/health\n */\nexport async function checkOpenCodeHealth(port: number): Promise<HealthCheckResult> {\n try {\n const response = await fetch(`http://localhost:${port}/global/health`, {\n signal: AbortSignal.timeout(2000), // 2 second timeout\n });\n if (!response.ok) {\n return { healthy: false, error: `HTTP ${response.status}` };\n }\n const data = (await response.json().catch(() => ({}))) as { version?: string };\n return { healthy: true, version: data.version };\n } catch (error) {\n const message = error instanceof Error ? error.message : 'Unknown error';\n return { healthy: false, error: message };\n }\n}\n\n/**\n * Wait for OpenCode to be healthy\n */\nexport async function waitForOpenCodeHealth(\n port: number,\n timeoutMs: number = 30000,\n): Promise<HealthCheckResult> {\n const startTime = Date.now();\n\n while (Date.now() - startTime < timeoutMs) {\n const health = await checkOpenCodeHealth(port);\n if (health.healthy) {\n return health;\n }\n await new Promise((resolve) => setTimeout(resolve, 1000));\n }\n\n return { healthy: false, error: 'Timeout waiting for OpenCode to be healthy' };\n}\n","/**\n * OpenCode Process Management\n *\n * Functions for starting, stopping, and finding OpenCode processes.\n */\n\nimport { execSync, spawn, ChildProcess } from 'child_process';\nimport { checkOpenCodeHealth } from './health.js';\n\n// Common ports that OpenCode might run on\nconst OPENCODE_PORT_RANGE = [4096, 4097, 4098, 4099, 4100];\n\nexport interface OpenCodeInstance {\n pid: number;\n port: number;\n cwd?: string;\n version?: string;\n}\n\n/**\n * Get the working directory of a process\n */\nfunction getProcessCwd(pid: number): string | undefined {\n const platform = process.platform;\n\n try {\n if (platform === 'darwin') {\n // macOS: use lsof to get cwd\n const output = execSync(`lsof -a -p ${pid} -d cwd -Fn 2>/dev/null`, {\n encoding: 'utf-8',\n stdio: ['pipe', 'pipe', 'pipe'],\n }).trim();\n // Output format: \"p<pid>\\nn<path>\"\n const lines = output.split('\\n');\n for (const line of lines) {\n if (line.startsWith('n') && !line.startsWith('n ')) {\n return line.slice(1); // Remove 'n' prefix\n }\n }\n } else if (platform === 'linux') {\n // Linux: read /proc/<pid>/cwd symlink\n const output = execSync(`readlink /proc/${pid}/cwd 2>/dev/null`, {\n encoding: 'utf-8',\n stdio: ['pipe', 'pipe', 'pipe'],\n }).trim();\n if (output) return output;\n }\n } catch {\n // Failed to get cwd, return undefined\n }\n\n return undefined;\n}\n\n/**\n * Check if a port is in use by any process\n */\nexport function isPortInUse(port: number): boolean {\n const platform = process.platform;\n\n try {\n if (platform === 'darwin' || platform === 'linux') {\n execSync(`lsof -i :${port} -sTCP:LISTEN 2>/dev/null`, {\n encoding: 'utf-8',\n stdio: ['pipe', 'pipe', 'pipe'],\n });\n return true; // Command succeeded, port is in use\n }\n } catch {\n // lsof failed or returned empty, port is free\n }\n\n return false;\n}\n\n/**\n * Find the next available port starting from the given port\n */\nexport function findAvailablePort(startPort: number, maxAttempts: number = 10): number | null {\n for (let i = 0; i < maxAttempts; i++) {\n const port = startPort + i;\n if (!isPortInUse(port)) {\n return port;\n }\n }\n return null;\n}\n\n/**\n * Find running OpenCode processes by scanning the process list\n * Uses pgrep for more reliable process matching\n * Returns array of instances with their PIDs and ports\n */\nexport function findOpenCodeProcesses(): OpenCodeInstance[] {\n const instances: OpenCodeInstance[] = [];\n\n try {\n const platform = process.platform;\n\n if (platform === 'darwin' || platform === 'linux') {\n // Method 1: Use pgrep for more reliable process matching\n let pids: number[] = [];\n\n try {\n // pgrep -f matches against full command line\n const pgrepOutput = execSync('pgrep -f \"opencode serve|opencode-serve\"', {\n encoding: 'utf-8',\n stdio: ['pipe', 'pipe', 'pipe'],\n }).trim();\n\n if (pgrepOutput) {\n pids = pgrepOutput\n .split('\\n')\n .map((p) => parseInt(p.trim(), 10))\n .filter((p) => !isNaN(p));\n }\n } catch {\n // pgrep found nothing or failed, try ps fallback\n try {\n const psOutput = execSync('ps aux | grep -E \"opencode (serve|--port)\" | grep -v grep', {\n encoding: 'utf-8',\n stdio: ['pipe', 'pipe', 'pipe'],\n }).trim();\n\n if (psOutput) {\n for (const line of psOutput.split('\\n')) {\n const parts = line.trim().split(/\\s+/);\n if (parts.length >= 2) {\n const pid = parseInt(parts[1], 10);\n if (!isNaN(pid)) pids.push(pid);\n }\n }\n }\n } catch {\n // ps also failed, pids stays empty\n }\n }\n\n // For each PID, find what port it's listening on and get cwd\n for (const pid of pids) {\n try {\n const lsofOutput = execSync(`lsof -Pan -p ${pid} -i TCP -sTCP:LISTEN 2>/dev/null`, {\n encoding: 'utf-8',\n stdio: ['pipe', 'pipe', 'pipe'],\n }).trim();\n\n for (const line of lsofOutput.split('\\n')) {\n // Parse port from lsof output (e.g., \"node 12345 user 23u IPv4 0x1234 0t0 TCP *:4096 (LISTEN)\")\n const portMatch = line.match(/:(\\d+)\\s+\\(LISTEN\\)/);\n if (portMatch) {\n const port = parseInt(portMatch[1], 10);\n if (!isNaN(port) && !instances.some((i) => i.port === port)) {\n const cwd = getProcessCwd(pid);\n instances.push({ pid, port, cwd });\n }\n }\n }\n } catch {\n // lsof failed for this PID, skip it\n }\n }\n }\n } catch {\n // Process detection failed, return empty array\n }\n\n return instances;\n}\n\n/**\n * Scan common OpenCode ports and check for healthy instances\n * This is a fallback when process-based detection fails\n */\nexport async function scanPortsForOpenCode(): Promise<OpenCodeInstance[]> {\n const instances: OpenCodeInstance[] = [];\n\n // Check each port in parallel for speed\n const checks = OPENCODE_PORT_RANGE.map(async (port) => {\n const health = await checkOpenCodeHealth(port);\n if (health.healthy) {\n // Try to find the PID for this port\n let pid = 0;\n try {\n const lsofOutput = execSync(`lsof -ti :${port} -sTCP:LISTEN 2>/dev/null`, {\n encoding: 'utf-8',\n stdio: ['pipe', 'pipe', 'pipe'],\n }).trim();\n if (lsofOutput) {\n pid = parseInt(lsofOutput.split('\\n')[0], 10) || 0;\n }\n } catch {\n // Couldn't get PID, that's ok\n }\n\n const cwd = pid ? getProcessCwd(pid) : undefined;\n return { pid, port, cwd, version: health.version };\n }\n return null;\n });\n\n const results = await Promise.all(checks);\n for (const result of results) {\n if (result) {\n instances.push(result);\n }\n }\n\n return instances;\n}\n\n/**\n * Find all running OpenCode instances that are healthy\n * Uses process detection first, falls back to port scanning\n */\nexport async function findHealthyOpenCodeInstances(): Promise<OpenCodeInstance[]> {\n // First try process-based detection\n const processes = findOpenCodeProcesses();\n const healthy: OpenCodeInstance[] = [];\n\n for (const proc of processes) {\n const health = await checkOpenCodeHealth(proc.port);\n if (health.healthy) {\n healthy.push({ ...proc, version: health.version });\n }\n }\n\n // If process detection found nothing, fall back to port scanning\n if (healthy.length === 0) {\n const scanned = await scanPortsForOpenCode();\n return scanned;\n }\n\n return healthy;\n}\n\n/**\n * Start OpenCode as a child process\n */\nexport async function startOpenCode(port: number): Promise<ChildProcess> {\n // Try to find opencode command\n let command = 'opencode';\n let args = ['serve', '--port', port.toString()];\n\n try {\n execSync('which opencode', { stdio: 'ignore' });\n } catch {\n // opencode not in PATH, try npx\n command = 'npx';\n args = ['opencode', 'serve', '--port', port.toString()];\n }\n\n const child = spawn(command, args, {\n detached: true,\n stdio: 'ignore',\n cwd: process.cwd(),\n });\n\n return child;\n}\n\n/**\n * Stop OpenCode process\n * Handles both POSIX (process groups with negative PID) and Windows (direct kill)\n */\nexport function stopOpenCode(opencodeProcess: ChildProcess | null): void {\n if (!opencodeProcess || !opencodeProcess.pid) {\n return;\n }\n\n try {\n if (process.platform === 'win32') {\n // Windows: kill the process directly (no process groups)\n opencodeProcess.kill('SIGTERM');\n } else {\n // POSIX: kill the process group (negative PID) since we spawned with detached: true\n process.kill(-opencodeProcess.pid, 'SIGTERM');\n }\n } catch {\n // Process may have already exited, ignore errors\n }\n}\n","/**\n * OpenCode Installation Detection and Prompts\n *\n * Functions for checking if OpenCode is installed and prompting for installation.\n */\n\nimport { execSync } from 'child_process';\nimport chalk from 'chalk';\nimport { select } from '@inquirer/prompts';\nimport { blank } from '../../utils/ui.js';\n\n// OpenCode installation URL\nconst OPENCODE_INSTALL_URL = 'https://opencode.ai';\n\n/**\n * Check if OpenCode is installed on the system.\n * Returns true if the `opencode` command is available in PATH.\n */\nexport function isOpenCodeInstalled(): boolean {\n try {\n const platform = process.platform;\n if (platform === 'win32') {\n execSync('where opencode', { stdio: 'ignore' });\n } else {\n execSync('which opencode', { stdio: 'ignore' });\n }\n return true;\n } catch {\n return false;\n }\n}\n\nexport type InstallPromptResult = 'installed' | 'continue' | 'exit';\n\n/**\n * Display OpenCode installation instructions and offer to install.\n * Returns 'installed' if user installed it, 'continue' to proceed anyway, or 'exit' to stop.\n *\n * @param interactive - If false, outputs JSON error and returns 'exit'\n */\nexport async function promptOpenCodeInstall(interactive: boolean): Promise<InstallPromptResult> {\n if (!interactive) {\n // In non-interactive mode, just output a JSON message and exit\n console.log(\n JSON.stringify({\n status: 'error',\n error: 'OpenCode is not installed',\n install_url: OPENCODE_INSTALL_URL,\n install_commands: {\n npm: 'npm install -g opencode-ai',\n curl: 'curl -fsSL https://opencode.ai/install.sh | sh',\n },\n }),\n );\n return 'exit';\n }\n\n blank();\n console.log(chalk.yellow('OpenCode is not installed on your system.'));\n blank();\n console.log(chalk.dim('OpenCode is an AI coding agent that runs locally on your machine.'));\n console.log(chalk.dim(`Learn more at: ${chalk.cyan(OPENCODE_INSTALL_URL)}`));\n blank();\n\n const action = await select({\n message: 'How would you like to proceed?',\n choices: [\n {\n name: 'Show installation instructions',\n value: 'instructions',\n description: 'Display commands to install OpenCode',\n },\n {\n name: 'Continue without OpenCode',\n value: 'continue',\n description: 'Connect anyway (requests will fail until OpenCode is installed)',\n },\n {\n name: 'Exit',\n value: 'exit',\n description: 'Exit and install OpenCode manually',\n },\n ],\n });\n\n if (action === 'instructions') {\n blank();\n console.log(chalk.bold('Install OpenCode using one of these methods:'));\n blank();\n console.log(chalk.dim(' # Option 1: Install via npm (recommended)'));\n console.log(` ${chalk.cyan('npm install -g opencode-ai')}`);\n blank();\n console.log(chalk.dim(' # Option 2: Install via curl'));\n console.log(` ${chalk.cyan('curl -fsSL https://opencode.ai/install.sh | sh')}`);\n blank();\n console.log(chalk.dim(`For more options, visit: ${chalk.cyan(OPENCODE_INSTALL_URL)}`));\n blank();\n\n const afterInstall = await select({\n message: 'After installing, what would you like to do?',\n choices: [\n {\n name: 'I installed it - continue',\n value: 'continue',\n description: 'Proceed with the run command',\n },\n {\n name: 'Exit',\n value: 'exit',\n description: 'Exit now and run the command again later',\n },\n ],\n });\n\n if (afterInstall === 'continue') {\n // Verify installation\n if (isOpenCodeInstalled()) {\n console.log(chalk.green('\\n✓ OpenCode detected!'));\n return 'installed';\n } else {\n console.log(chalk.yellow('\\nOpenCode still not detected in PATH.'));\n console.log(chalk.dim('You may need to restart your terminal or add it to your PATH.'));\n\n const proceed = await select({\n message: 'Continue anyway?',\n choices: [\n { name: 'Yes, continue', value: 'continue' },\n { name: 'No, exit', value: 'exit' },\n ],\n });\n return proceed === 'continue' ? 'continue' : 'exit';\n }\n }\n return 'exit';\n }\n\n return action as 'continue' | 'exit';\n}\n","/**\n * OpenCode Session Management\n *\n * Functions for creating and managing OpenCode sessions.\n */\n\n/**\n * Create a new OpenCode session\n */\nexport async function createOpenCodeSession(port: number): Promise<string> {\n const response = await fetch(`http://localhost:${port}/session`, {\n method: 'POST',\n headers: { 'Content-Type': 'application/json' },\n body: JSON.stringify({}),\n });\n\n if (!response.ok) {\n throw new Error(`Failed to create session: HTTP ${response.status}`);\n }\n\n const data = (await response.json()) as { id: string };\n return data.id;\n}\n\n/**\n * Optional OpenCode routing options for sendMessageToOpenCode\n */\nexport interface MessageOptions {\n /** OpenCode agent name (e.g. \"build\", \"plan\") */\n agent?: string;\n /** Model in provider/model format (e.g. \"anthropic/claude-opus-4-6\") */\n model?: string;\n}\n\nexport interface SendMessageResult {\n title?: string;\n}\n\n// Minimal types matching the OpenCode API shapes (avoiding API imports in CLI)\n\nexport interface OpenCodeQuestionOption {\n label: string;\n description: string;\n}\n\nexport interface OpenCodeQuestionInfo {\n question: string;\n header: string;\n options: OpenCodeQuestionOption[];\n}\n\nexport interface OpenCodeQuestion {\n id: string;\n sessionID: string;\n questions: OpenCodeQuestionInfo[];\n tool?: { messageID: string; callID: string };\n}\n\nexport interface OpenCodePermission {\n id: string;\n type: string;\n pattern?: string | string[];\n sessionID: string;\n messageID: string;\n callID?: string;\n title: string;\n metadata: Record<string, unknown>;\n time: { created: number };\n}\n\n/**\n * Hooks called while the message is being processed.\n * Each question/permission is reported at most once (tracked by ID).\n */\nexport interface SessionInteractiveHooks {\n onQuestion?: (question: OpenCodeQuestion) => Promise<void>;\n onPermission?: (permission: OpenCodePermission) => Promise<void>;\n}\n\n/**\n * Send a message to an OpenCode session and wait for it to complete.\n *\n * OpenCode uses a blocking HTTP endpoint: POST /session/:id/message holds the\n * connection open until processing completes (including any wait for the user\n * to answer an interactive question). While waiting, we poll for pending\n * questions and permissions every second so they can be surfaced without\n * blocking the main request.\n *\n * Throws on HTTP errors or when maxWaitMs is exceeded.\n */\nexport async function sendMessageToOpenCode(\n port: number,\n sessionId: string,\n content: string,\n options?: MessageOptions,\n hooks?: SessionInteractiveHooks,\n maxWaitMs: number = 10 * 60 * 1000,\n): Promise<SendMessageResult> {\n const body: Record<string, unknown> = {\n parts: [{ type: 'text', text: content }],\n };\n\n if (options?.agent) {\n body.agent = options.agent;\n }\n\n if (options?.model) {\n const slashIndex = options.model.indexOf('/');\n if (slashIndex !== -1) {\n body.model = {\n providerID: options.model.substring(0, slashIndex),\n modelID: options.model.substring(slashIndex + 1),\n };\n }\n }\n\n let pollDone = false;\n const reportedQuestions = new Set<string>();\n const reportedPermissions = new Set<string>();\n\n // Polls for interactive events while the message request is in-flight.\n const pollInteractive = async () => {\n while (!pollDone) {\n await new Promise<void>((resolve) => setTimeout(resolve, 1000));\n if (pollDone) break;\n\n if (hooks?.onQuestion) {\n try {\n const res = await fetch(`http://localhost:${port}/question`);\n if (res.ok) {\n const questions = (await res.json()) as OpenCodeQuestion[];\n for (const q of questions) {\n if (q.sessionID === sessionId && !reportedQuestions.has(q.id)) {\n reportedQuestions.add(q.id);\n await hooks.onQuestion(q);\n }\n }\n }\n } catch {\n // Non-fatal: interactive detection is best-effort\n }\n }\n\n if (hooks?.onPermission) {\n try {\n const res = await fetch(`http://localhost:${port}/permission`);\n if (res.ok) {\n const permissions = (await res.json()) as OpenCodePermission[];\n for (const p of permissions) {\n if (p.sessionID === sessionId && !reportedPermissions.has(p.id)) {\n reportedPermissions.add(p.id);\n await hooks.onPermission(p);\n }\n }\n }\n } catch {\n // Non-fatal: interactive detection is best-effort\n }\n }\n }\n };\n\n // Awaits the message endpoint; sets pollDone when done so the poll loop exits.\n const sendMessage = async (): Promise<SendMessageResult> => {\n const controller = new AbortController();\n const timer = setTimeout(() => controller.abort(), maxWaitMs);\n try {\n const res = await fetch(`http://localhost:${port}/session/${sessionId}/message`, {\n method: 'POST',\n headers: { 'Content-Type': 'application/json' },\n body: JSON.stringify(body),\n signal: controller.signal,\n });\n if (!res.ok) {\n const text = await res.text().catch(() => '');\n throw new Error(`OpenCode message failed: HTTP ${res.status}${text ? `: ${text}` : ''}`);\n }\n // Fetch the updated session title after successful completion\n const sessionRes = await fetch(`http://localhost:${port}/session/${sessionId}`).catch(\n () => null,\n );\n const session = sessionRes?.ok ? ((await sessionRes.json()) as { title?: string }) : null;\n return { title: session?.title };\n } catch (err) {\n if (err instanceof Error && err.name === 'AbortError') {\n throw new Error('Message processing timed out');\n }\n throw err;\n } finally {\n clearTimeout(timer);\n pollDone = true;\n }\n };\n\n const [result] = await Promise.all([sendMessage(), pollInteractive()]);\n return result;\n}\n","/**\n * Tunnel WebSocket Connection\n *\n * Functions for establishing and managing WebSocket tunnel connections.\n */\n\nimport WebSocket from 'ws';\nimport { getTunnelUrlConfig } from '../config.js';\nimport type { RelayToCLIMessage } from '@evident/types';\nimport { forwardToOpenCode, sendResponse } from './forwarding.js';\nimport { subscribeToOpenCodeEvents } from './events.js';\n\n// Re-export the message type\nexport type RelayMessage = RelayToCLIMessage;\n\n// Reconnection constants\nconst MAX_RECONNECT_DELAY = 30000; // 30 seconds\nconst BASE_RECONNECT_DELAY = 500; // 0.5 seconds\n\nexport interface TunnelConnectionOptions {\n agentId: string;\n authHeader: string;\n port: number;\n onConnected?: (agentId: string) => void;\n onDisconnected?: (code: number, reason: string) => void;\n onError?: (error: string) => void;\n onRequest?: (method: string, path: string, requestId: string) => void;\n onResponse?: (status: number, durationMs: number, requestId: string) => void;\n onInfo?: (message: string) => void;\n}\n\nexport interface TunnelConnection {\n ws: WebSocket;\n close: () => void;\n // Active event subscriptions: subscription_id -> AbortController\n activeEventSubscriptions: Map<string, AbortController>;\n}\n\n/**\n * Calculate reconnect delay with exponential backoff and jitter\n */\nexport function getReconnectDelay(attempt: number): number {\n const exponentialDelay = BASE_RECONNECT_DELAY * Math.pow(2, attempt);\n const jitter = Math.random() * 1000;\n return Math.min(exponentialDelay + jitter, MAX_RECONNECT_DELAY);\n}\n\n/**\n * Connect to the tunnel relay\n *\n * @returns A promise that resolves with the WebSocket connection when connected,\n * or rejects on connection failure\n */\nexport function connectTunnel(options: TunnelConnectionOptions): Promise<TunnelConnection> {\n const {\n agentId,\n authHeader,\n port,\n onConnected,\n onDisconnected,\n onError,\n onRequest,\n onResponse,\n onInfo,\n } = options;\n\n const tunnelUrl = getTunnelUrlConfig();\n const url = `${tunnelUrl}/tunnel/${agentId}/connect`;\n const activeEventSubscriptions = new Map<string, AbortController>();\n\n return new Promise((resolve, reject) => {\n const ws = new WebSocket(url, {\n headers: {\n Authorization: authHeader,\n },\n });\n\n const connectionTimeout = setTimeout(() => {\n ws.close();\n reject(new Error('Connection timeout'));\n }, 30000);\n\n ws.on('open', () => {\n onInfo?.('WebSocket connection established');\n });\n\n ws.on('message', async (data: WebSocket.RawData) => {\n try {\n const message: RelayMessage = JSON.parse(data.toString());\n\n switch (message.type) {\n case 'connected': {\n clearTimeout(connectionTimeout);\n const connectedAgentId = message.agent_id ?? agentId;\n onConnected?.(connectedAgentId);\n resolve({\n ws,\n close: () => ws.close(1000, 'CLI shutdown'),\n activeEventSubscriptions,\n });\n break;\n }\n\n case 'error':\n clearTimeout(connectionTimeout);\n onError?.(message.message || 'Unknown tunnel error');\n if (message.code === 'unauthorized') {\n ws.close();\n reject(new Error('Unauthorized'));\n }\n break;\n\n case 'ping':\n ws.send(JSON.stringify({ type: 'pong' }));\n break;\n\n case 'request':\n if (message.id && message.payload) {\n const startTime = Date.now();\n onRequest?.(message.payload.method, message.payload.path, message.id);\n\n const response = await forwardToOpenCode(port, message.payload);\n const durationMs = Date.now() - startTime;\n\n onResponse?.(response.status, durationMs, message.id);\n\n // Use sendResponse which handles chunking for large responses\n sendResponse(ws, message.id, response);\n }\n break;\n\n case 'subscribe_events':\n if (message.id) {\n const abortController = new AbortController();\n activeEventSubscriptions.set(message.id, abortController);\n onInfo?.(`Starting event subscription ${message.id.slice(0, 8)}`);\n\n subscribeToOpenCodeEvents(port, message.id, ws, abortController)\n .catch((error) => {\n if (!abortController.signal.aborted) {\n onError?.(`Event subscription failed: ${error.message}`);\n }\n })\n .finally(() => {\n activeEventSubscriptions.delete(message.id!);\n });\n }\n break;\n\n case 'unsubscribe_events':\n if (message.id) {\n const controller = activeEventSubscriptions.get(message.id);\n if (controller) {\n controller.abort();\n activeEventSubscriptions.delete(message.id);\n }\n }\n break;\n }\n } catch (error) {\n const errorMessage = error instanceof Error ? error.message : 'Unknown error';\n onError?.(`Failed to handle message: ${errorMessage}`);\n }\n });\n\n ws.on('error', (error: Error) => {\n clearTimeout(connectionTimeout);\n onError?.(`Connection error: ${error.message}`);\n reject(error);\n });\n\n ws.on('close', (code: number, reason: Buffer) => {\n const reasonStr = reason.toString() || 'No reason provided';\n onDisconnected?.(code, reasonStr);\n\n // Cancel all active event subscriptions\n for (const [, controller] of activeEventSubscriptions) {\n controller.abort();\n }\n activeEventSubscriptions.clear();\n });\n });\n}\n","/**\n * Tunnel Request Forwarding\n *\n * Functions for forwarding requests to OpenCode and handling responses.\n */\n\nimport WebSocket from 'ws';\n\n// Chunked response protocol constants (must match tunnel-relay)\nconst CHUNK_THRESHOLD = 512 * 1024; // 512KB - responses larger than this are chunked\nconst CHUNK_SIZE = 768 * 1024; // 768KB - size of each chunk\n\nexport interface ForwardRequest {\n method: string;\n path: string;\n headers?: Record<string, string>;\n body?: unknown;\n}\n\nexport interface ForwardResponse {\n status: number;\n headers?: Record<string, string>;\n body?: unknown;\n}\n\n/**\n * Forward request to local OpenCode instance\n */\nexport async function forwardToOpenCode(\n port: number,\n request: ForwardRequest,\n): Promise<ForwardResponse> {\n const url = `http://localhost:${port}${request.path}`;\n\n try {\n const response = await fetch(url, {\n method: request.method,\n headers: {\n 'Content-Type': 'application/json',\n ...request.headers,\n },\n body: request.body ? JSON.stringify(request.body) : undefined,\n });\n\n let body: unknown;\n const contentType = response.headers.get('Content-Type');\n const text = await response.text();\n\n // Handle empty responses (e.g., 204 No Content)\n if (!text || text.length === 0) {\n body = null;\n } else if (contentType?.includes('application/json')) {\n try {\n body = JSON.parse(text);\n } catch {\n // If JSON parsing fails, return as text\n body = text;\n }\n } else {\n body = text;\n }\n\n return {\n status: response.status,\n body,\n };\n } catch (error) {\n const message = error instanceof Error ? error.message : 'Unknown error';\n return {\n status: 502,\n body: { error: 'Failed to connect to OpenCode', message },\n };\n }\n}\n\n/**\n * Send a response back to the relay.\n * Automatically uses chunked protocol for large responses (>= 512KB body).\n */\nexport function sendResponse(ws: WebSocket, requestId: string, response: ForwardResponse): void {\n const bodyStr = JSON.stringify(response.body ?? null);\n const bodyBytes = Buffer.from(bodyStr, 'utf-8');\n\n if (bodyBytes.length < CHUNK_THRESHOLD) {\n // Small response: send as single message (common case)\n ws.send(\n JSON.stringify({\n type: 'response',\n id: requestId,\n payload: response,\n }),\n );\n return;\n }\n\n // Large response: use chunked protocol\n sendResponseAsChunks(ws, requestId, response, bodyBytes);\n}\n\n/**\n * Send a large response as multiple chunks.\n * Only called when response body exceeds CHUNK_THRESHOLD.\n */\nfunction sendResponseAsChunks(\n ws: WebSocket,\n requestId: string,\n response: { status: number; headers?: Record<string, string> },\n bodyBytes: Buffer,\n): void {\n const chunks = splitIntoChunks(bodyBytes, CHUNK_SIZE);\n\n // Send start message with metadata\n ws.send(\n JSON.stringify({\n type: 'response_start',\n id: requestId,\n total_chunks: chunks.length,\n total_size: bodyBytes.length,\n payload: {\n status: response.status,\n headers: response.headers,\n },\n }),\n );\n\n // Send each chunk\n for (let i = 0; i < chunks.length; i++) {\n ws.send(\n JSON.stringify({\n type: 'response_chunk',\n id: requestId,\n chunk_index: i,\n data: chunks[i].toString('base64'),\n }),\n );\n }\n\n // Send end message\n ws.send(\n JSON.stringify({\n type: 'response_end',\n id: requestId,\n }),\n );\n}\n\n/**\n * Split a buffer into chunks of the specified size\n */\nfunction splitIntoChunks(data: Buffer, chunkSize: number): Buffer[] {\n const chunks: Buffer[] = [];\n for (let i = 0; i < data.length; i += chunkSize) {\n chunks.push(data.subarray(i, i + chunkSize));\n }\n return chunks;\n}\n","/**\n * Tunnel SSE Event Subscription\n *\n * Functions for subscribing to OpenCode events and forwarding them through the WebSocket.\n */\n\nimport WebSocket from 'ws';\n\n/**\n * Subscribe to OpenCode events and forward them through the WebSocket\n *\n * @param port - OpenCode port\n * @param subscriptionId - Unique ID for this subscription\n * @param ws - WebSocket connection to relay\n * @param abortController - Controller to cancel the subscription\n */\nexport async function subscribeToOpenCodeEvents(\n port: number,\n subscriptionId: string,\n ws: WebSocket,\n abortController: AbortController,\n): Promise<void> {\n const url = `http://localhost:${port}/event`;\n\n try {\n const response = await fetch(url, {\n headers: { Accept: 'text/event-stream' },\n signal: abortController.signal,\n });\n\n if (!response.ok) {\n throw new Error(`Failed to connect to OpenCode events: ${response.status}`);\n }\n\n if (!response.body) {\n throw new Error('No response body');\n }\n\n const reader = response.body.getReader();\n const decoder = new TextDecoder();\n let buffer = '';\n\n // eslint-disable-next-line no-constant-condition\n while (true) {\n const { done, value } = await reader.read();\n\n if (done) {\n // Stream ended\n ws.send(JSON.stringify({ type: 'event_end', id: subscriptionId }));\n break;\n }\n\n buffer += decoder.decode(value, { stream: true });\n const lines = buffer.split('\\n');\n buffer = lines.pop() || '';\n\n for (const line of lines) {\n if (line.startsWith('data: ')) {\n try {\n const event = JSON.parse(line.slice(6));\n // Forward event to relay\n ws.send(JSON.stringify({ type: 'event', id: subscriptionId, event }));\n } catch {\n // Ignore parse errors for individual events\n }\n }\n }\n }\n } catch (error) {\n if (abortController.signal.aborted) {\n // Subscription was cancelled, this is expected\n return;\n }\n\n const message = error instanceof Error ? error.message : 'Unknown error';\n // Send error to relay\n ws.send(JSON.stringify({ type: 'event_error', id: subscriptionId, error: message }));\n throw error;\n }\n}\n"],"mappings":"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","names":["chalk","error","credentials","error","chalk","credentials","chalk","credentials","chalk","chalk","ora","select","credentials","error","credentials","error","execSync","chalk","execSync","chalk","error","error","error","error","chalk","select","credentials","ora"]}
|