@cephalization/phoenix-insight 1.1.0 → 1.1.1

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/cli.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/cli.ts","../src/agent/index.ts","../src/prompts/system.ts","../src/snapshot/client.ts","../src/commands/px-fetch-more-spans.ts","../src/commands/px-fetch-more-trace.ts","../src/commands/report-tool.ts","../../../node_modules/.pnpm/@json-render+core@0.2.0_zod@4.3.5/node_modules/@json-render/core/src/types.ts","../../../node_modules/.pnpm/@json-render+core@0.2.0_zod@4.3.5/node_modules/@json-render/core/src/visibility.ts","../../../node_modules/.pnpm/@json-render+core@0.2.0_zod@4.3.5/node_modules/@json-render/core/src/actions.ts","../../../node_modules/.pnpm/@json-render+core@0.2.0_zod@4.3.5/node_modules/@json-render/core/src/validation.ts","../../../node_modules/.pnpm/@json-render+core@0.2.0_zod@4.3.5/node_modules/@json-render/core/src/catalog.ts","../../ui/src/lib/json-render/catalog.ts","../src/snapshot/projects.ts","../src/snapshot/spans.ts","../src/snapshot/datasets.ts","../src/snapshot/experiments.ts","../src/snapshot/prompts.ts","../src/snapshot/context.ts","../src/progress.ts","../src/snapshot/index.ts","../src/snapshot/utils.ts","../src/observability/index.ts","../src/config/schema.ts","../src/config/loader.ts","../src/config/index.ts","../src/server/ui.ts","../src/server/websocket.ts","../src/server/session.ts"],"sourcesContent":["#!/usr/bin/env node\n\nimport { Command } from \"commander\";\nimport * as readline from \"node:readline\";\nimport * as fs from \"node:fs/promises\";\nimport * as path from \"node:path\";\nimport * as os from \"node:os\";\nimport { exec } from \"node:child_process\";\nimport { createSandboxMode, createLocalMode } from \"./modes/index.js\";\nimport { createInsightAgent, runOneShotQuery } from \"./agent/index.js\";\nimport {\n createSnapshot,\n createIncrementalSnapshot,\n createPhoenixClient,\n PhoenixClientError,\n} from \"./snapshot/index.js\";\nimport { getLatestSnapshot, listSnapshots } from \"./snapshot/utils.js\";\nimport type { ExecutionMode } from \"./modes/types.js\";\nimport type { PhoenixInsightAgentConfig } from \"./agent/index.js\";\nimport { AgentProgress } from \"./progress.js\";\nimport {\n initializeObservability,\n shutdownObservability,\n} from \"./observability/index.js\";\nimport { initializeConfig, getConfig, type CliArgs } from \"./config/index.js\";\nimport { createUIServer } from \"./server/ui.js\";\nimport { createWebSocketServer } from \"./server/websocket.js\";\nimport { createSessionManager } from \"./server/session.js\";\nimport type { WebSocket } from \"ws\";\n\n// Version will be read from package.json during build\nconst VERSION = \"0.0.1\";\n\nconst program = new Command();\n\n/**\n * Format bash command for display in progress indicator\n */\nfunction formatBashCommand(command: string): string {\n if (!command) return \"\";\n\n // Split by newline and get first line\n const lines = command.split(\"\\n\");\n const firstLine = lines[0]?.trim() || \"\";\n\n // Check for pipeline first (3+ commands)\n if (firstLine.includes(\" | \") && firstLine.split(\" | \").length > 2) {\n const parts = firstLine.split(\" | \");\n const firstCmd = parts[0]?.split(\" \")[0] || \"\";\n const lastCmd = parts[parts.length - 1]?.split(\" \")[0] || \"\";\n return `${firstCmd} | ... | ${lastCmd}`;\n }\n\n // Common command patterns to display nicely\n if (firstLine.startsWith(\"cat \")) {\n const file = firstLine.substring(4).trim();\n return `cat ${file}`;\n } else if (firstLine.startsWith(\"grep \")) {\n // Extract pattern and file/directory\n const match = firstLine.match(\n /grep\\s+(?:-[^\\s]+\\s+)*['\"]?([^'\"]+)['\"]?\\s+(.+)/\n );\n if (match && match[1] && match[2]) {\n return `grep \"${match[1]}\" in ${match[2]}`;\n }\n return firstLine.substring(0, 60) + (firstLine.length > 60 ? \"...\" : \"\");\n } else if (firstLine.startsWith(\"find \")) {\n const match = firstLine.match(\n /find\\s+([^\\s]+)(?:\\s+-name\\s+['\"]?([^'\"]+)['\"]?)?/\n );\n if (match && match[1]) {\n return match[2]\n ? `find \"${match[2]}\" in ${match[1]}`\n : `find in ${match[1]}`;\n }\n return firstLine.substring(0, 60) + (firstLine.length > 60 ? \"...\" : \"\");\n } else if (firstLine.startsWith(\"ls \")) {\n const path = firstLine.substring(3).trim();\n return path ? `ls ${path}` : \"ls\";\n } else if (firstLine.startsWith(\"ls\")) {\n return \"ls\";\n } else if (firstLine.startsWith(\"jq \")) {\n return `jq processing JSON data`;\n } else if (firstLine.startsWith(\"head \") || firstLine.startsWith(\"tail \")) {\n const cmd = firstLine.split(\" \")[0];\n const fileMatch = firstLine.match(/(?:head|tail)\\s+(?:-[^\\s]+\\s+)*(.+)/);\n if (fileMatch && fileMatch[1]) {\n return `${cmd} ${fileMatch[1]}`;\n }\n return firstLine.substring(0, 60) + (firstLine.length > 60 ? \"...\" : \"\");\n } else {\n // For other commands, show up to 80 characters\n return firstLine.substring(0, 80) + (firstLine.length > 80 ? \"...\" : \"\");\n }\n}\n\n/**\n * Check if ANTHROPIC_API_KEY is set and provide a helpful error if not\n */\nfunction ensureAnthropicApiKey(): void {\n if (!process.env.ANTHROPIC_API_KEY) {\n console.error(\n \"\\n❌ Error: Missing ANTHROPIC_API_KEY environment variable\\n\"\n );\n console.error(\"The Anthropic API key is required to run the AI agent.\\n\");\n console.error(\"To fix this, set the environment variable:\\n\");\n console.error(\" export ANTHROPIC_API_KEY=sk-ant-api03-...\\n\");\n console.error(\n \"Or add it to your shell profile (~/.zshrc, ~/.bashrc, etc.):\\n\"\n );\n console.error(\n \" echo 'export ANTHROPIC_API_KEY=sk-ant-api03-...' >> ~/.zshrc\\n\"\n );\n console.error(\n \"You can get an API key from: https://console.anthropic.com/\\n\"\n );\n process.exit(1);\n }\n}\n\n/**\n * Handle errors with appropriate exit codes and user-friendly messages\n */\nfunction handleError(error: unknown, context: string): never {\n console.error(`\\n❌ Error ${context}:`);\n\n if (error instanceof PhoenixClientError) {\n switch (error.code) {\n case \"NETWORK_ERROR\":\n console.error(\n \"\\n🌐 Network Error: Unable to connect to Phoenix server\"\n );\n console.error(` Make sure Phoenix is running and accessible`);\n console.error(` You can specify a different URL with --base-url`);\n break;\n case \"AUTH_ERROR\":\n console.error(\"\\n🔒 Authentication Error: Invalid or missing API key\");\n console.error(\n ` Set the PHOENIX_API_KEY environment variable or use --api-key`\n );\n break;\n case \"INVALID_RESPONSE\":\n console.error(\n \"\\n⚠️ Invalid Response: Phoenix returned unexpected data\"\n );\n console.error(` This might be a version compatibility issue`);\n break;\n default:\n console.error(\"\\n❓ Phoenix Client Error:\", error.message);\n }\n if (error.originalError && process.env.DEBUG) {\n console.error(\"\\nOriginal error:\", error.originalError);\n }\n } else if (error instanceof Error) {\n // Check for specific error patterns\n if (error.message.includes(\"ENOENT\")) {\n console.error(\n \"\\n📁 File System Error: Required file or directory not found\"\n );\n console.error(` ${error.message}`);\n } else if (\n error.message.includes(\"EACCES\") ||\n error.message.includes(\"EPERM\")\n ) {\n console.error(\"\\n🚫 Permission Error: Insufficient permissions\");\n console.error(` ${error.message}`);\n if (error.message.includes(\".phoenix-insight\")) {\n console.error(\n ` Try running with appropriate permissions or check ~/.phoenix-insight/`\n );\n }\n } else if (\n error.message.includes(\"rate limit\") ||\n error.message.includes(\"429\")\n ) {\n console.error(\"\\n⏱️ Rate Limit Error: Too many requests to Phoenix\");\n console.error(` Please wait a moment and try again`);\n } else if (error.message.includes(\"timeout\")) {\n console.error(\"\\n⏰ Timeout Error: Request took too long\");\n console.error(` The Phoenix server might be slow or unresponsive`);\n } else {\n console.error(`\\n${error.message}`);\n }\n\n if (error.stack && process.env.DEBUG) {\n console.error(\"\\nStack trace:\", error.stack);\n }\n } else {\n console.error(\"\\nUnexpected error:\", error);\n }\n\n console.error(\"\\n💡 Tips:\");\n console.error(\" • Run with DEBUG=1 for more detailed error information\");\n console.error(\n \" • Check your Phoenix connection with: phoenix-insight snapshot --base-url <url>\"\n );\n console.error(\" • Use --help to see all available options\");\n\n process.exit(1);\n}\n\nprogram\n .name(\"phoenix-insight\")\n .description(\"A CLI for Phoenix data analysis with AI agents\")\n .version(VERSION)\n .usage(\"[options] [query]\")\n .option(\n \"--config <path>\",\n \"Path to config file (default: ~/.phoenix-insight/config.json, or set PHOENIX_INSIGHT_CONFIG env var)\"\n )\n .addHelpText(\n \"after\",\n `\nConfiguration:\n Config values are loaded with the following priority (highest to lowest):\n 1. CLI arguments (e.g., --base-url)\n 2. Environment variables (e.g., PHOENIX_BASE_URL)\n 3. Config file (~/.phoenix-insight/config.json)\n\n Use --config to specify a custom config file path.\n Set PHOENIX_INSIGHT_CONFIG env var to override the default config location.\n\nExamples:\n $ phoenix-insight # Start interactive mode\n $ phoenix-insight \"What are the slowest traces?\" # Single query (sandbox mode)\n $ phoenix-insight --interactive # Explicitly start interactive mode\n $ phoenix-insight --local \"Show me error patterns\" # Local mode with persistence\n $ phoenix-insight --local --stream \"Analyze recent experiments\" # Local mode with streaming\n $ phoenix-insight --config ./my-config.json \"Analyze traces\" # Use custom config file\n $ phoenix-insight ui # Start web UI on localhost:6007\n $ phoenix-insight ui --port 8080 # Start web UI on custom port\n $ phoenix-insight ui --no-open # Start web UI without opening browser\n $ opencode run \"Analyze my spans\" -f $(pxi snapshot latest)/_context.md # Analyze phoenix data with OpenCode agent\n $ phoenix-insight help # Show this help message\n`\n )\n .hook(\"preAction\", async (thisCommand) => {\n // Get all options from the root command\n const opts = thisCommand.opts();\n // Build CLI args from commander options\n const cliArgs: CliArgs = {\n config: opts.config,\n baseUrl: opts.baseUrl,\n apiKey: opts.apiKey,\n limit: opts.limit,\n stream: opts.stream,\n local: opts.local,\n refresh: opts.refresh,\n trace: opts.trace,\n };\n // Initialize config singleton before any command runs\n await initializeConfig(cliArgs);\n });\n\n/**\n * Shared logic for creating a snapshot.\n * Used by both 'phoenix-insight snapshot' and 'phoenix-insight snapshot create'.\n */\nasync function executeSnapshotCreate(): Promise<void> {\n const config = getConfig();\n\n // Initialize observability if trace is enabled in config\n if (config.trace) {\n initializeObservability({\n enabled: true,\n baseUrl: config.baseUrl,\n apiKey: config.apiKey,\n projectName: \"phoenix-insight-snapshot\",\n debug: !!process.env.DEBUG,\n });\n }\n\n try {\n // Determine the execution mode\n const mode: ExecutionMode = await createLocalMode();\n\n // Create snapshot with config values\n const snapshotOptions = {\n baseURL: config.baseUrl,\n apiKey: config.apiKey,\n spansPerProject: config.limit,\n showProgress: true,\n };\n\n await createSnapshot(mode, snapshotOptions);\n\n // Cleanup\n await mode.cleanup();\n\n // Shutdown observability if enabled\n await shutdownObservability();\n } catch (error) {\n handleError(error, \"creating snapshot\");\n }\n}\n\n// Create snapshot command group\nconst snapshotCmd = program\n .command(\"snapshot\")\n .description(\"Snapshot management commands\");\n\n// Default action for 'phoenix-insight snapshot' (backward compatibility alias for 'snapshot create')\nsnapshotCmd.action(async () => {\n await executeSnapshotCreate();\n});\n\n// Subcommand: snapshot create (explicit create command)\nsnapshotCmd\n .command(\"create\")\n .description(\"Create a new snapshot from Phoenix data\")\n .action(async () => {\n await executeSnapshotCreate();\n });\n\n// Subcommand: snapshot latest\nsnapshotCmd\n .command(\"latest\")\n .description(\"Print the absolute path to the latest snapshot directory\")\n .action(async () => {\n try {\n const latestSnapshot = await getLatestSnapshot();\n\n if (!latestSnapshot) {\n console.error(\"No snapshots found\");\n process.exit(1);\n }\n\n // Print only the path to stdout, no decoration\n console.log(latestSnapshot.path);\n } catch (error) {\n console.error(\n `Error: ${error instanceof Error ? error.message : String(error)}`\n );\n process.exit(1);\n }\n });\n\n// Subcommand: snapshot list\nsnapshotCmd\n .command(\"list\")\n .description(\"List all available snapshots with their timestamps\")\n .action(async () => {\n try {\n const snapshots = await listSnapshots();\n\n // Print each snapshot: <timestamp> <path>\n // Most recent first (already sorted by listSnapshots)\n for (const snapshot of snapshots) {\n // Format timestamp as ISO 8601\n const isoTimestamp = snapshot.timestamp.toISOString();\n console.log(`${isoTimestamp} ${snapshot.path}`);\n }\n\n // Exit code 0 even if empty (just print nothing)\n } catch (error) {\n console.error(\n `Error: ${error instanceof Error ? error.message : String(error)}`\n );\n process.exit(1);\n }\n });\n\nprogram\n .command(\"help\")\n .description(\"Show help information\")\n .action(() => {\n program.outputHelp();\n });\n\nprogram\n .command(\"prune\")\n .description(\n \"Delete the local snapshot directory (~/.phoenix-insight/snapshots)\"\n )\n .option(\"--dry-run\", \"Show what would be deleted without actually deleting\")\n .action(async (options) => {\n const snapshotDir = path.join(\n os.homedir(),\n \".phoenix-insight\",\n \"snapshots\"\n );\n\n try {\n // Check if the directory exists\n const stats = await fs.stat(snapshotDir).catch(() => null);\n\n if (!stats) {\n console.log(\"📁 No local snapshot directory found. Nothing to prune.\");\n return;\n }\n\n if (options.dryRun) {\n console.log(\"🔍 Dry run mode - would delete:\");\n console.log(` ${snapshotDir}`);\n\n // Show size and count of snapshots\n const snapshots = await fs.readdir(snapshotDir).catch(() => []);\n console.log(` 📊 Contains ${snapshots.length} snapshot(s)`);\n\n return;\n }\n\n // Ask for confirmation\n const rl = readline.createInterface({\n input: process.stdin,\n output: process.stdout,\n });\n\n const answer = await new Promise<string>((resolve) => {\n rl.question(\n `⚠️ This will delete all local snapshots at:\\n ${snapshotDir}\\n\\n Are you sure? (yes/no): `,\n resolve\n );\n });\n\n rl.close();\n\n if (answer.toLowerCase() !== \"yes\" && answer.toLowerCase() !== \"y\") {\n console.log(\"❌ Prune cancelled.\");\n return;\n }\n\n // Delete the directory\n await fs.rm(snapshotDir, { recursive: true, force: true });\n console.log(\"✅ Local snapshot directory deleted successfully!\");\n } catch (error) {\n console.error(\"❌ Error pruning snapshots:\");\n console.error(\n ` ${error instanceof Error ? error.message : String(error)}`\n );\n process.exit(1);\n }\n });\n\n// UI Command - starts web-based UI server\nprogram\n .command(\"ui\")\n .description(\"Start the web-based UI for interactive Phoenix analysis\")\n .option(\"--port <number>\", \"Port to run the UI server on\", parseInt)\n .option(\"--no-open\", \"Do not automatically open the browser\")\n .action(async (options) => {\n await runUIServer(options);\n });\n\nprogram\n .argument(\"[query]\", \"Query to run against Phoenix data\")\n .option(\n \"--sandbox\",\n \"Run in sandbox mode with in-memory filesystem (default)\"\n )\n .option(\"--local\", \"Run in local mode with real filesystem\")\n .option(\"--base-url <url>\", \"Phoenix base URL\")\n .option(\"--api-key <key>\", \"Phoenix API key\")\n .option(\"--refresh\", \"Force refresh of snapshot data\")\n .option(\"--limit <number>\", \"Limit number of spans to fetch\", parseInt)\n .option(\"--stream [true|false]\", \"Stream agent responses\", (v) =>\n [\"f\", \"false\"].includes(v.toLowerCase()) ? false : true\n )\n .option(\"-i, --interactive\", \"Run in interactive mode (REPL)\")\n .option(\"--trace\", \"Enable tracing of the agent to Phoenix\")\n .action(async (query, options) => {\n const config = getConfig();\n // If interactive mode is requested, ignore query argument\n if (options.interactive) {\n await runInteractiveMode();\n return;\n }\n\n // If no query is provided and no specific flag, start interactive mode\n if (!query && !options.help) {\n await runInteractiveMode();\n return;\n }\n\n // Ensure Anthropic API key is available for agent execution\n ensureAnthropicApiKey();\n\n // Initialize observability if trace is enabled in config\n if (config.trace) {\n initializeObservability({\n enabled: true,\n baseUrl: config.baseUrl,\n apiKey: config.apiKey,\n projectName: \"phoenix-insight\",\n debug: !!process.env.DEBUG,\n });\n }\n\n try {\n // Determine the execution mode\n const mode: ExecutionMode =\n config.mode === \"local\" ? await createLocalMode() : createSandboxMode();\n\n // Create Phoenix client\n const client = createPhoenixClient({\n baseURL: config.baseUrl,\n apiKey: config.apiKey,\n });\n\n // Create or update snapshot\n const snapshotOptions = {\n baseURL: config.baseUrl,\n apiKey: config.apiKey,\n spansPerProject: config.limit,\n showProgress: true,\n };\n\n if (config.refresh || config.mode !== \"local\") {\n // For sandbox mode (default) or when refresh is requested, always create a fresh snapshot\n await createSnapshot(mode, snapshotOptions);\n } else {\n // For local mode without refresh, try incremental update\n await createIncrementalSnapshot(mode, snapshotOptions);\n }\n\n // Create agent configuration\n const agentConfig: PhoenixInsightAgentConfig = {\n mode,\n client,\n maxSteps: 25,\n };\n\n // Execute the query\n const agentProgress = new AgentProgress(!config.stream);\n agentProgress.startThinking();\n\n if (config.stream) {\n // Stream mode\n const result = (await runOneShotQuery(agentConfig, query, {\n stream: true,\n onStepFinish: (step) => {\n // Show tool usage even in stream mode\n if (step.toolCalls?.length) {\n step.toolCalls.forEach((toolCall: any) => {\n const toolName = toolCall.toolName;\n if (toolName === \"bash\") {\n // Extract bash command for better visibility\n const command = toolCall.args?.command || \"\";\n const formattedCmd = formatBashCommand(command);\n agentProgress.updateTool(toolName, formattedCmd);\n } else {\n agentProgress.updateTool(toolName);\n }\n console.log();\n });\n }\n\n // Show tool results\n if (step.toolResults?.length) {\n step.toolResults.forEach((toolResult: any) => {\n agentProgress.updateToolResult(\n toolResult.toolName,\n !toolResult.isError\n );\n });\n console.log();\n }\n },\n })) as any; // Type assertion needed due to union type\n\n // Stop progress before streaming\n agentProgress.stop();\n\n // Handle streaming response\n console.log(\"\\n✨ Answer:\\n\");\n for await (const chunk of result.textStream) {\n process.stdout.write(chunk);\n }\n console.log(); // Final newline\n\n // Wait for full response to complete\n await result.response;\n } else {\n // Non-streaming mode\n const result = (await runOneShotQuery(agentConfig, query, {\n onStepFinish: (step) => {\n // Show tool usage\n if (step.toolCalls?.length) {\n step.toolCalls.forEach((toolCall: any) => {\n const toolName = toolCall.toolName;\n if (toolName === \"bash\") {\n // Extract bash command for better visibility\n const command = toolCall.args?.command || \"\";\n const formattedCmd = formatBashCommand(command);\n agentProgress.updateTool(toolName, formattedCmd);\n } else {\n agentProgress.updateTool(toolName);\n }\n });\n }\n\n // Show tool results\n if (step.toolResults?.length) {\n step.toolResults.forEach((toolResult: any) => {\n agentProgress.updateToolResult(\n toolResult.toolName,\n !toolResult.isError\n );\n });\n }\n },\n })) as any; // Type assertion needed due to union type\n\n // Stop progress and display the final answer\n agentProgress.succeed();\n console.log(\"\\n✨ Answer:\\n\");\n console.log(result.text);\n }\n\n // Cleanup\n await mode.cleanup();\n\n console.log(\"\\n✅ Done!\");\n } catch (error) {\n handleError(error, \"executing query\");\n } finally {\n // Shutdown observability if enabled\n await shutdownObservability();\n }\n });\n\n/**\n * Open a URL in the default browser\n */\nfunction openBrowser(url: string): void {\n const platform = process.platform;\n let command: string;\n\n if (platform === \"darwin\") {\n command = `open \"${url}\"`;\n } else if (platform === \"win32\") {\n command = `start \"\" \"${url}\"`;\n } else {\n // Linux and others - try xdg-open, fallback to sensible-browser\n command = `xdg-open \"${url}\" || sensible-browser \"${url}\"`;\n }\n\n exec(command, (error) => {\n if (error && process.env.DEBUG) {\n console.warn(`Could not open browser: ${error.message}`);\n }\n });\n}\n\n/**\n * Run the UI server with WebSocket support for agent interaction\n */\nasync function runUIServer(options: {\n port?: number;\n open?: boolean;\n}): Promise<void> {\n // Ensure Anthropic API key is available for agent execution\n ensureAnthropicApiKey();\n\n const config = getConfig();\n const port = options.port ?? 6007;\n const shouldOpen = options.open !== false; // Default to opening browser\n\n console.log(\"🚀 Starting Phoenix Insight UI...\\n\");\n\n // Initialize observability if trace is enabled in config\n if (config.trace) {\n initializeObservability({\n enabled: true,\n baseUrl: config.baseUrl,\n apiKey: config.apiKey,\n projectName: \"phoenix-insight-ui\",\n debug: !!process.env.DEBUG,\n });\n }\n\n try {\n // Determine the execution mode - UI always uses local mode for persistence\n const mode: ExecutionMode = await createLocalMode();\n\n // Create Phoenix client\n const client = createPhoenixClient({\n baseURL: config.baseUrl,\n apiKey: config.apiKey,\n });\n\n // Create snapshot with config values\n const snapshotOptions = {\n baseURL: config.baseUrl,\n apiKey: config.apiKey,\n spansPerProject: config.limit,\n showProgress: true,\n };\n\n // Always use incremental snapshot for UI to reuse existing data\n await createIncrementalSnapshot(mode, snapshotOptions);\n\n console.log(\"\\n✅ Snapshot ready.\\n\");\n\n // Create the UI HTTP server\n const uiServer = await createUIServer({ port, host: \"127.0.0.1\" });\n\n // Create the WebSocket server and attach to HTTP server\n const sessionManager = createSessionManager({\n mode,\n client,\n maxSteps: 25,\n });\n\n const wsServer = createWebSocketServer(uiServer.httpServer, {\n path: \"/ws\",\n onConnection: (ws: WebSocket) => {\n if (process.env.DEBUG) {\n console.log(\"WebSocket client connected\");\n }\n },\n onDisconnection: async (ws: WebSocket, code, reason) => {\n if (process.env.DEBUG) {\n console.log(`WebSocket client disconnected: ${code} ${reason}`);\n }\n // Clean up the session when client disconnects\n await sessionManager.removeSession(ws);\n },\n onMessage: async (message, ws) => {\n if (message.type === \"query\") {\n const { content, sessionId: clientSessionId } = message.payload;\n const sessionId = clientSessionId ?? `session-${Date.now()}`;\n\n // Get or create session for this client\n const session = sessionManager.getOrCreateSession(\n ws,\n sessionId,\n (msg) => wsServer.sendToClient(ws, msg)\n );\n\n // Execute the query (this is async but we don't await - let it stream)\n session.executeQuery(content).catch((error) => {\n console.error(\"Error executing query:\", error);\n wsServer.sendToClient(ws, {\n type: \"error\",\n payload: {\n message:\n error instanceof Error\n ? error.message\n : \"An error occurred while executing the query\",\n sessionId,\n },\n });\n });\n } else if (message.type === \"cancel\") {\n const session = sessionManager.getSessionForClient(ws);\n if (session) {\n session.cancel();\n }\n }\n },\n onError: (error, ws) => {\n console.error(\"WebSocket error:\", error.message);\n },\n });\n\n const url = `http://localhost:${uiServer.port}`;\n\n console.log(\"🌐 Phoenix Insight UI is running!\");\n console.log(` Local: ${url}`);\n console.log(\"\\n💡 Press Ctrl+C to stop the server\\n\");\n\n // Open browser if not disabled\n if (shouldOpen) {\n openBrowser(url);\n }\n\n // Handle graceful shutdown with timeout\n let isShuttingDown = false;\n const SHUTDOWN_TIMEOUT_MS = 3000;\n\n const shutdown = async (signal: string) => {\n if (isShuttingDown) return;\n isShuttingDown = true;\n\n console.log(`\\n\\n📥 Received ${signal}, shutting down gracefully...`);\n\n // Set up a timeout to force exit if graceful shutdown takes too long\n const forceExitTimeout = setTimeout(() => {\n console.log(\"⏱️ Shutdown timeout reached, forcing exit...\");\n wsServer.forceClose();\n uiServer.forceClose();\n process.exit(0);\n }, SHUTDOWN_TIMEOUT_MS);\n\n try {\n // Close WebSocket connections first\n await wsServer.close();\n\n // Close the UI server\n await uiServer.close();\n\n // Clean up sessions\n await sessionManager.cleanup();\n\n // Clean up execution mode\n await mode.cleanup();\n\n // Shutdown observability if enabled\n await shutdownObservability();\n\n clearTimeout(forceExitTimeout);\n console.log(\"👋 Server stopped. Goodbye!\");\n process.exit(0);\n } catch (error) {\n clearTimeout(forceExitTimeout);\n console.error(\"Error during shutdown:\", error);\n process.exit(1);\n }\n };\n\n process.on(\"SIGINT\", () => shutdown(\"SIGINT\"));\n process.on(\"SIGTERM\", () => shutdown(\"SIGTERM\"));\n\n // Keep the process running\n await new Promise(() => {\n // This promise never resolves - server runs until SIGINT/SIGTERM\n });\n } catch (error) {\n handleError(error, \"starting UI server\");\n }\n}\n\nasync function runInteractiveMode(): Promise<void> {\n // Ensure Anthropic API key is available for agent execution\n ensureAnthropicApiKey();\n\n const config = getConfig();\n\n console.log(\"🚀 Phoenix Insight Interactive Mode\");\n console.log(\n \"Type your queries below. Type 'help' for available commands or 'exit' to quit.\\n\"\n );\n\n // Prevent the process from exiting on unhandled promise rejections\n process.on(\"unhandledRejection\", (reason, promise) => {\n console.error(\"\\n⚠️ Unhandled promise rejection:\", reason);\n console.error(\n \"The interactive mode will continue. You can try another query.\"\n );\n });\n\n // Initialize observability if trace is enabled in config\n if (config.trace) {\n initializeObservability({\n enabled: true,\n baseUrl: config.baseUrl,\n apiKey: config.apiKey,\n projectName: \"phoenix-insight\",\n debug: !!process.env.DEBUG,\n });\n }\n\n // Setup mode and snapshot once for the session\n let mode: ExecutionMode;\n let agent: any;\n\n try {\n // Determine the execution mode\n mode =\n config.mode === \"local\" ? await createLocalMode() : createSandboxMode();\n\n // Create Phoenix client\n const client = createPhoenixClient({\n baseURL: config.baseUrl,\n apiKey: config.apiKey,\n });\n\n // Create or update snapshot\n const snapshotOptions = {\n baseURL: config.baseUrl,\n apiKey: config.apiKey,\n spansPerProject: config.limit,\n showProgress: true,\n };\n\n if (config.refresh || config.mode !== \"local\") {\n await createSnapshot(mode, snapshotOptions);\n } else {\n await createIncrementalSnapshot(mode, snapshotOptions);\n }\n\n console.log(\n \"\\n✅ Snapshot ready. You can now ask questions about your Phoenix data.\\n\"\n );\n\n // Create agent configuration\n const agentConfig: PhoenixInsightAgentConfig = {\n mode,\n client,\n maxSteps: 25,\n };\n\n // Create reusable agent\n agent = await createInsightAgent(agentConfig);\n\n // Setup readline interface\n const rl = readline.createInterface({\n input: process.stdin,\n output: process.stdout,\n prompt: \"phoenix> \",\n terminal: true, // Ensure terminal mode for better compatibility\n });\n\n let userExited = false;\n\n // Handle SIGINT (Ctrl+C) gracefully\n rl.on(\"SIGINT\", () => {\n if (userExited) {\n process.exit(0);\n }\n console.log(\n '\\n\\nUse \"exit\" to quit or press Ctrl+C again to force exit.'\n );\n userExited = true;\n rl.prompt();\n });\n\n // Helper function to process a single query\n const processQuery = async (query: string): Promise<boolean> => {\n if (query === \"exit\" || query === \"quit\") {\n return true; // Signal to exit\n }\n\n if (query === \"help\") {\n console.log(\"\\n📖 Interactive Mode Commands:\");\n console.log(\" help - Show this help message\");\n console.log(\" exit, quit - Exit interactive mode\");\n console.log(\n \" px-fetch-more - Fetch additional data (e.g., px-fetch-more spans --project <name> --limit <n>)\"\n );\n console.log(\"\\n💡 Usage Tips:\");\n console.log(\n \" • Ask natural language questions about your Phoenix data\"\n );\n console.log(\n \" • The agent has access to bash commands to analyze the data\"\n );\n console.log(\n \" • Use px-fetch-more commands to get additional data on-demand\"\n );\n console.log(\"\\n🔧 Options (set when starting phoenix-insight):\");\n console.log(\n \" --local - Use local mode with persistent storage\"\n );\n console.log(\n \" --stream - Stream agent responses in real-time\"\n );\n console.log(\" --refresh - Force fresh snapshot data\");\n console.log(\" --limit <n> - Set max spans per project\");\n console.log(\" --trace - Enable observability tracing\");\n return false;\n }\n\n if (query === \"\") {\n return false;\n }\n\n try {\n const agentProgress = new AgentProgress(!config.stream);\n agentProgress.startThinking();\n\n if (config.stream) {\n // Stream mode\n const result = await agent.stream(query, {\n onStepFinish: (step: any) => {\n // Show tool usage even in stream mode\n if (step.toolCalls?.length) {\n step.toolCalls.forEach((toolCall: any) => {\n const toolName = toolCall.toolName;\n if (toolName === \"bash\") {\n // Extract bash command for better visibility\n const command = toolCall.args?.command || \"\";\n const shortCmd = command.split(\"\\n\")[0].substring(0, 50);\n agentProgress.updateTool(\n toolName,\n shortCmd + (command.length > 50 ? \"...\" : \"\")\n );\n } else {\n agentProgress.updateTool(toolName);\n }\n });\n }\n\n // Show tool results\n if (step.toolResults?.length) {\n step.toolResults.forEach((toolResult: any) => {\n agentProgress.updateToolResult(\n toolResult.toolName,\n !toolResult.isError\n );\n });\n }\n },\n });\n\n // Stop progress before streaming\n agentProgress.stop();\n\n // Handle streaming response\n console.log(\"\\n✨ Answer:\\n\");\n for await (const chunk of result.textStream) {\n process.stdout.write(chunk);\n }\n console.log(); // Final newline\n\n // Wait for full response to complete\n await result.response;\n } else {\n // Non-streaming mode\n const result = await agent.generate(query, {\n onStepFinish: (step: any) => {\n // Show tool usage\n if (step.toolCalls?.length) {\n step.toolCalls.forEach((toolCall: any) => {\n const toolName = toolCall.toolName;\n if (toolName === \"bash\") {\n // Extract bash command for better visibility\n const command = toolCall.args?.command || \"\";\n const shortCmd = command.split(\"\\n\")[0].substring(0, 50);\n agentProgress.updateTool(\n toolName,\n shortCmd + (command.length > 50 ? \"...\" : \"\")\n );\n } else {\n agentProgress.updateTool(toolName);\n }\n });\n }\n\n // Show tool results\n if (step.toolResults?.length) {\n step.toolResults.forEach((toolResult: any) => {\n agentProgress.updateToolResult(\n toolResult.toolName,\n !toolResult.isError\n );\n });\n }\n },\n });\n\n // Stop progress and display the final answer\n agentProgress.succeed();\n console.log(\"\\n✨ Answer:\\n\");\n console.log(result.text);\n }\n\n console.log(\"\\n\" + \"─\".repeat(50) + \"\\n\");\n } catch (error) {\n console.error(\"\\n❌ Query Error:\");\n if (error instanceof PhoenixClientError) {\n console.error(` ${error.message}`);\n } else if (error instanceof Error) {\n console.error(` ${error.message}`);\n } else {\n console.error(` ${String(error)}`);\n }\n console.error(\" You can try again with a different query\\n\");\n }\n\n return false;\n };\n\n // Use event-based approach instead of async iterator to prevent\n // premature exit when ora/spinners interact with stdin\n await new Promise<void>((resolve) => {\n rl.on(\"line\", async (line) => {\n const query = line.trim();\n\n // Pause readline while processing to prevent queuing\n rl.pause();\n\n const shouldExit = await processQuery(query);\n\n if (shouldExit) {\n rl.close();\n } else {\n // Resume and show prompt for next input\n rl.resume();\n rl.prompt();\n }\n });\n\n rl.on(\"close\", () => {\n resolve();\n });\n\n // Show initial prompt\n rl.prompt();\n });\n\n console.log(\"\\n👋 Goodbye!\");\n\n // Cleanup\n await mode.cleanup();\n\n // Shutdown observability if enabled\n await shutdownObservability();\n } catch (error) {\n handleError(error, \"setting up interactive mode\");\n }\n}\n\nprogram.parse();\n","/**\n * Phoenix Insight AI agent setup using Vercel AI SDK\n */\n\nimport {\n generateText,\n streamText,\n tool,\n stepCountIs,\n type GenerateTextResult,\n type StreamTextResult,\n} from \"ai\";\nimport { anthropic } from \"@ai-sdk/anthropic\";\nimport { z } from \"zod\";\nimport type { ExecutionMode } from \"../modes/types.js\";\nimport { getInsightSystemPrompt } from \"../prompts/system.js\";\nimport {\n fetchMoreSpans,\n fetchMoreTrace,\n type FetchMoreSpansOptions,\n type FetchMoreTraceOptions,\n} from \"../commands/index.js\";\nimport type { PhoenixClient } from \"@arizeai/phoenix-client\";\n\n/**\n * Configuration for the Phoenix Insight agent\n */\nexport interface PhoenixInsightAgentConfig {\n /** The execution mode (sandbox or local) */\n mode: ExecutionMode;\n /** Phoenix client instance */\n client: PhoenixClient;\n /** Maximum number of agent steps before stopping (default: 25) */\n maxSteps?: number;\n /** Additional tools to include in the agent (e.g., report tool for UI mode) */\n additionalTools?: Record<string, any>;\n}\n\n/**\n * Phoenix Insight Agent\n */\nexport class PhoenixInsightAgent {\n private mode: ExecutionMode;\n private client: PhoenixClient;\n private maxSteps: number;\n private tools: Record<string, any> | null = null;\n private additionalTools: Record<string, any>;\n private model = anthropic(\"claude-sonnet-4-5\");\n private systemPrompt: string;\n\n constructor(config: PhoenixInsightAgentConfig) {\n this.mode = config.mode;\n this.client = config.client;\n this.maxSteps = config.maxSteps || 25;\n this.additionalTools = config.additionalTools || {};\n // Generate the system prompt with the snapshot root path from the mode\n this.systemPrompt = getInsightSystemPrompt(this.mode.getSnapshotRoot());\n }\n\n /**\n * Initialize the agent tools\n */\n private async initializeTools(): Promise<Record<string, any>> {\n if (this.tools) return this.tools;\n\n // Get the bash tool from the execution mode\n const bashTool = await this.mode.getBashTool();\n\n // Store references in closure for the custom tools\n const client = this.client;\n const mode = this.mode;\n\n // Create custom px-fetch-more-spans tool using AI SDK's tool function\n const pxFetchMoreSpans = tool({\n description:\n \"Fetch additional spans from Phoenix. Use when you need more span data than what's in the snapshot. You must provide both project name and optionally a limit.\",\n inputSchema: z.object({\n project: z.string().describe(\"The project name\"),\n limit: z\n .number()\n .optional()\n .describe(\"Number of spans to fetch (default: 500)\"),\n startTime: z\n .string()\n .optional()\n .describe(\"Start time filter in ISO format\"),\n endTime: z\n .string()\n .optional()\n .describe(\"End time filter in ISO format\"),\n }),\n execute: async (params) => {\n try {\n const options: FetchMoreSpansOptions = {\n project: params.project,\n limit: params.limit || 500,\n startTime: params.startTime,\n endTime: params.endTime,\n };\n\n await fetchMoreSpans(client, mode, options);\n\n return {\n success: true,\n message: `Fetched additional spans for project ${params.project}. Data saved to /phoenix/projects/${params.project}/spans/`,\n };\n } catch (error) {\n return {\n success: false,\n error: error instanceof Error ? error.message : String(error),\n };\n }\n },\n });\n\n // Create custom px-fetch-more-trace tool using AI SDK's tool function\n const pxFetchMoreTrace = tool({\n description:\n \"Fetch a specific trace by ID from Phoenix. Use when you need to examine a particular trace in detail. You must provide both the trace ID and the project name.\",\n inputSchema: z.object({\n traceId: z.string().describe(\"The trace ID to fetch\"),\n project: z.string().describe(\"The project name to search in\"),\n }),\n execute: async (params) => {\n try {\n const options: FetchMoreTraceOptions = {\n traceId: params.traceId,\n project: params.project,\n };\n\n await fetchMoreTrace(client, mode, options);\n\n return {\n success: true,\n message: `Fetched trace ${params.traceId}. Data saved to /phoenix/traces/${params.traceId}/`,\n };\n } catch (error) {\n return {\n success: false,\n error: error instanceof Error ? error.message : String(error),\n };\n }\n },\n });\n\n this.tools = {\n bash: bashTool,\n px_fetch_more_spans: pxFetchMoreSpans,\n px_fetch_more_trace: pxFetchMoreTrace,\n ...this.additionalTools,\n };\n\n return this.tools;\n }\n\n /**\n * Generate a response for a user query\n */\n async generate(\n userQuery: string,\n options?: {\n onStepFinish?: (step: any) => void;\n }\n ): Promise<GenerateTextResult<any, any>> {\n let tools;\n try {\n tools = await this.initializeTools();\n } catch (error) {\n throw new Error(\n `Failed to initialize agent tools: ${\n error instanceof Error ? error.message : String(error)\n }`\n );\n }\n\n try {\n const result = await generateText({\n model: this.model,\n system: this.systemPrompt,\n prompt: userQuery,\n tools,\n stopWhen: stepCountIs(this.maxSteps),\n onStepFinish: options?.onStepFinish,\n experimental_telemetry: {\n isEnabled: true,\n },\n });\n\n return result;\n } catch (error) {\n // Check for specific AI SDK errors\n if (error instanceof Error) {\n if (error.message.includes(\"rate limit\")) {\n throw new Error(\n \"AI model rate limit exceeded. Please wait and try again.\"\n );\n }\n if (error.message.includes(\"timeout\")) {\n throw new Error(\"AI model request timed out. Please try again.\");\n }\n if (\n error.message.includes(\"authentication\") ||\n error.message.includes(\"API key\")\n ) {\n throw new Error(\n \"AI model authentication failed. Check your API key configuration.\"\n );\n }\n }\n\n throw new Error(\n `AI generation failed: ${\n error instanceof Error ? error.message : String(error)\n }`\n );\n }\n }\n\n /**\n * Stream a response for a user query\n */\n async stream(\n userQuery: string,\n options?: {\n onStepFinish?: (step: any) => void;\n }\n ): Promise<StreamTextResult<any, any>> {\n let tools;\n try {\n tools = await this.initializeTools();\n } catch (error) {\n throw new Error(\n `Failed to initialize agent tools: ${\n error instanceof Error ? error.message : String(error)\n }`\n );\n }\n\n try {\n const result = streamText({\n model: this.model,\n system: this.systemPrompt,\n prompt: userQuery,\n tools,\n stopWhen: stepCountIs(this.maxSteps),\n onStepFinish: options?.onStepFinish,\n experimental_telemetry: {\n isEnabled: true,\n },\n });\n\n return result;\n } catch (error) {\n // Check for specific AI SDK errors\n if (error instanceof Error) {\n if (error.message.includes(\"rate limit\")) {\n throw new Error(\n \"AI model rate limit exceeded. Please wait and try again.\"\n );\n }\n if (error.message.includes(\"timeout\")) {\n throw new Error(\"AI model request timed out. Please try again.\");\n }\n if (\n error.message.includes(\"authentication\") ||\n error.message.includes(\"API key\")\n ) {\n throw new Error(\n \"AI model authentication failed. Check your API key configuration.\"\n );\n }\n }\n\n throw new Error(\n `AI streaming failed: ${\n error instanceof Error ? error.message : String(error)\n }`\n );\n }\n }\n\n /**\n * Clean up resources\n */\n async cleanup(): Promise<void> {\n await this.mode.cleanup();\n }\n}\n\n/**\n * Creates a Phoenix Insight agent\n */\nexport async function createInsightAgent(\n config: PhoenixInsightAgentConfig\n): Promise<PhoenixInsightAgent> {\n return new PhoenixInsightAgent(config);\n}\n\n/**\n * Run a query with the Phoenix Insight agent\n */\nexport async function runQuery(\n agent: PhoenixInsightAgent,\n userQuery: string,\n options?: {\n onStepFinish?: (step: any) => void;\n stream?: boolean;\n }\n): Promise<GenerateTextResult<any, any> | StreamTextResult<any, any>> {\n const { stream = false, ...callbacks } = options || {};\n\n if (stream) {\n return await agent.stream(userQuery, callbacks);\n } else {\n return await agent.generate(userQuery, callbacks);\n }\n}\n\n/**\n * Create and run a one-shot query\n */\nexport async function runOneShotQuery(\n config: PhoenixInsightAgentConfig,\n userQuery: string,\n options?: {\n onStepFinish?: (step: any) => void;\n stream?: boolean;\n }\n): Promise<GenerateTextResult<any, any> | StreamTextResult<any, any>> {\n const agent = await createInsightAgent(config);\n\n try {\n const result = await runQuery(agent, userQuery, options);\n return result;\n } finally {\n await agent.cleanup();\n }\n}\n","/**\n * System prompt for the Phoenix Insight AI agent\n * This prompt teaches the agent about the filesystem layout and available commands\n */\n\n/**\n * Generate the system prompt for the Phoenix Insight agent\n * @param snapshotRoot - The absolute path to the Phoenix snapshot root directory\n * @returns The system prompt string with the correct snapshot path\n */\nexport function getInsightSystemPrompt(snapshotRoot: string): string {\n return `You are an expert at analyzing Phoenix observability data.\n\n**START by reading ${snapshotRoot}/_context.md** - it contains a summary of what's available.\n\nYou have access to a bash shell with Phoenix data organized as files:\n\n${snapshotRoot}/\n _context.md - READ THIS FIRST: summary of available data\n /projects/{name}/spans/ - Span data (JSONL format, may be sampled)\n /datasets/ - Datasets and examples\n /experiments/ - Experiment runs and results\n /prompts/ - Prompt templates and versions\n\nUse commands like:\n- cat, head, tail: Read file contents \n- grep: Search for patterns\n- jq: Query and transform JSON/JSONL\n- ls, find: Navigate and discover data\n- sort, uniq, wc: Aggregate and count\n- awk: Complex text processing\n\nIf you need MORE data than what's in the snapshot:\n- px-fetch-more spans --project <name> --limit 500\n- px-fetch-more trace --trace-id <id>\n\nThis is a READ-ONLY snapshot. Start with _context.md, then explore to answer the question.`;\n}\n","import { createClient, type PhoenixClient } from \"@arizeai/phoenix-client\";\n\nexport class PhoenixClientError extends Error {\n public code:\n | \"NETWORK_ERROR\"\n | \"AUTH_ERROR\"\n | \"INVALID_RESPONSE\"\n | \"UNKNOWN_ERROR\";\n public originalError?: unknown;\n\n constructor(\n message: string,\n code: \"NETWORK_ERROR\" | \"AUTH_ERROR\" | \"INVALID_RESPONSE\" | \"UNKNOWN_ERROR\",\n originalError?: unknown\n ) {\n super(message);\n this.name = \"PhoenixClientError\";\n this.code = code;\n this.originalError = originalError;\n }\n}\n\nexport interface PhoenixClientConfig {\n baseURL?: string;\n apiKey?: string;\n}\n\n/**\n * Creates a wrapped Phoenix client with error handling\n */\nexport function createPhoenixClient(\n config: PhoenixClientConfig = {}\n): PhoenixClient {\n const headers: Record<string, string> = {};\n\n if (config.apiKey) {\n headers[\"api_key\"] = config.apiKey;\n }\n\n const clientOptions: Parameters<typeof createClient>[0] = {\n options: {\n baseUrl: config.baseURL,\n headers: Object.keys(headers).length > 0 ? headers : undefined,\n },\n };\n\n return createClient(clientOptions);\n}\n\n/**\n * Wraps an async operation with standardized error handling\n */\nexport async function withErrorHandling<T>(\n operation: () => Promise<T>,\n context: string\n): Promise<T> {\n try {\n return await operation();\n } catch (error) {\n // Network errors\n if (error instanceof TypeError && error.message.includes(\"fetch\")) {\n throw new PhoenixClientError(\n `Network error during ${context}: Unable to connect to Phoenix server`,\n \"NETWORK_ERROR\",\n error\n );\n }\n\n // HTTP errors from the middleware\n if (error instanceof Error && error.message.includes(\": \")) {\n const parts = error.message.split(\": \", 2);\n if (parts.length === 2 && parts[1]) {\n const [url, statusInfo] = parts;\n const statusParts = statusInfo.split(\" \");\n const statusCode = statusParts[0];\n const statusText = statusParts.slice(1).join(\" \");\n\n if (statusCode === \"401\" || statusCode === \"403\") {\n throw new PhoenixClientError(\n `Authentication error during ${context}: ${statusText}`,\n \"AUTH_ERROR\",\n error\n );\n }\n\n if (statusCode && statusCode.startsWith(\"4\")) {\n throw new PhoenixClientError(\n `Client error during ${context}: ${statusCode} ${statusText}`,\n \"INVALID_RESPONSE\",\n error\n );\n }\n\n if (statusCode && statusCode.startsWith(\"5\")) {\n throw new PhoenixClientError(\n `Server error during ${context}: ${statusCode} ${statusText}`,\n \"NETWORK_ERROR\",\n error\n );\n }\n }\n }\n\n // Unknown errors\n throw new PhoenixClientError(\n `Unexpected error during ${context}: ${error instanceof Error ? error.message : String(error)}`,\n \"UNKNOWN_ERROR\",\n error\n );\n }\n}\n\n/**\n * Helper to safely extract data from API responses\n */\nexport function extractData<T>(response: { data?: T; error?: unknown }): T {\n if (response.error) {\n throw response.error;\n }\n\n if (!response.data) {\n throw new PhoenixClientError(\n \"Invalid API response: missing data\",\n \"INVALID_RESPONSE\"\n );\n }\n\n return response.data;\n}\n","import type { PhoenixClient } from \"@arizeai/phoenix-client\";\nimport type { ExecutionMode } from \"../modes/types.js\";\nimport { withErrorHandling } from \"../snapshot/client.js\";\n\nexport interface FetchMoreSpansOptions {\n /** Project name to fetch spans for */\n project: string;\n /** Number of additional spans to fetch */\n limit: number;\n /** Inclusive lower bound time for filtering spans */\n startTime?: Date | string | null;\n /** Exclusive upper bound time for filtering spans */\n endTime?: Date | string | null;\n}\n\ninterface SpanData {\n id: string;\n name: string;\n context: {\n trace_id: string;\n span_id: string;\n };\n span_kind: string;\n parent_id: string | null;\n start_time: string;\n end_time: string;\n status_code: string;\n status_message: string;\n attributes: Record<string, unknown>;\n events: Array<unknown>;\n}\n\ninterface SpansMetadata {\n project: string;\n spanCount: number;\n startTime: string | null;\n endTime: string | null;\n snapshotTime: string;\n lastCursor?: string | null;\n}\n\n/**\n * Fetches additional spans for a specific project on-demand\n *\n * @param client - Phoenix client instance\n * @param mode - Execution mode for file operations\n * @param options - Options for fetching spans\n */\nexport async function fetchMoreSpans(\n client: PhoenixClient,\n mode: ExecutionMode,\n options: FetchMoreSpansOptions\n): Promise<void> {\n const { project, limit, startTime, endTime } = options;\n\n await withErrorHandling(async () => {\n // Try to read existing metadata to get the last cursor\n let existingMetadata: SpansMetadata | null = null;\n let existingSpans: SpanData[] = [];\n\n try {\n const metadataResult = await mode.exec(\n `cat /phoenix/projects/${project}/spans/metadata.json`\n );\n if (metadataResult.exitCode === 0 && metadataResult.stdout) {\n existingMetadata = JSON.parse(metadataResult.stdout);\n }\n } catch (error) {\n // Metadata doesn't exist, that's okay\n }\n\n // Try to read existing spans\n try {\n const spansResult = await mode.exec(\n `cat /phoenix/projects/${project}/spans/index.jsonl`\n );\n if (spansResult.exitCode === 0 && spansResult.stdout) {\n existingSpans = spansResult.stdout\n .trim()\n .split(\"\\n\")\n .filter((line) => line.length > 0)\n .map((line) => JSON.parse(line) as SpanData);\n }\n } catch (error) {\n // Spans file doesn't exist, that's okay\n }\n\n // Fetch new spans\n const newSpans: SpanData[] = [];\n let cursor: string | null = existingMetadata?.lastCursor ?? null;\n let totalFetched = 0;\n\n while (totalFetched < limit) {\n const query: Record<string, any> = {\n limit: Math.min(100, limit - totalFetched), // Fetch in chunks of 100\n };\n\n if (cursor) {\n query.cursor = cursor;\n }\n\n if (startTime) {\n query.start_time =\n startTime instanceof Date ? startTime.toISOString() : startTime;\n }\n\n if (endTime) {\n query.end_time =\n endTime instanceof Date ? endTime.toISOString() : endTime;\n }\n\n const response = await client.GET(\n \"/v1/projects/{project_identifier}/spans\",\n {\n params: {\n path: {\n project_identifier: project,\n },\n query,\n },\n }\n );\n\n if (response.error) throw response.error;\n\n const data = response.data?.data ?? [];\n newSpans.push(...(data as SpanData[]));\n totalFetched += data.length;\n\n cursor = response.data?.next_cursor ?? null;\n\n // Stop if there's no more data\n if (!cursor || data.length === 0) {\n break;\n }\n }\n\n // Combine existing and new spans\n const allSpans = [...existingSpans, ...newSpans];\n\n // Write updated spans to JSONL file\n const jsonlContent = allSpans\n .map((span) => JSON.stringify(span))\n .join(\"\\n\");\n await mode.writeFile(\n `/phoenix/projects/${project}/spans/index.jsonl`,\n jsonlContent\n );\n\n // Update metadata\n const metadata: SpansMetadata = {\n project,\n spanCount: allSpans.length,\n startTime:\n startTime instanceof Date\n ? startTime.toISOString()\n : (startTime ?? null),\n endTime:\n endTime instanceof Date ? endTime.toISOString() : (endTime ?? null),\n snapshotTime: new Date().toISOString(),\n lastCursor: cursor,\n };\n\n await mode.writeFile(\n `/phoenix/projects/${project}/spans/metadata.json`,\n JSON.stringify(metadata, null, 2)\n );\n\n console.log(\n `Fetched ${newSpans.length} additional spans for project \"${project}\"`\n );\n console.log(`Total spans for project: ${allSpans.length}`);\n }, `fetching more spans for project ${project}`);\n}\n","import type { PhoenixClient } from \"@arizeai/phoenix-client\";\nimport type { ExecutionMode } from \"../modes/types.js\";\nimport { withErrorHandling } from \"../snapshot/client.js\";\n\nexport interface FetchMoreTraceOptions {\n /** Trace ID to fetch all spans for */\n traceId: string;\n /** Project name to search in */\n project: string;\n}\n\ninterface SpanData {\n id: string;\n name: string;\n context: {\n trace_id: string;\n span_id: string;\n };\n span_kind: string;\n parent_id: string | null;\n start_time: string;\n end_time: string;\n status_code: string;\n status_message: string;\n attributes: Record<string, unknown>;\n events: Array<unknown>;\n}\n\n/**\n * Fetches all spans for a specific trace ID\n *\n * @param client - Phoenix client instance\n * @param mode - Execution mode for file operations\n * @param options - Options for fetching trace\n */\nexport async function fetchMoreTrace(\n client: PhoenixClient,\n mode: ExecutionMode,\n options: FetchMoreTraceOptions\n): Promise<void> {\n const { traceId, project } = options;\n\n await withErrorHandling(async () => {\n // First, check if the project exists in our snapshot\n const projectsResult = await mode.exec(\"cat /phoenix/projects/index.jsonl\");\n if (projectsResult.exitCode !== 0 || !projectsResult.stdout) {\n console.error(\"No projects found in snapshot. Run a snapshot first.\");\n return;\n }\n\n const projectNames = projectsResult.stdout\n .trim()\n .split(\"\\n\")\n .filter((line) => line.length > 0)\n .map((line) => JSON.parse(line).name);\n\n if (!projectNames.includes(project)) {\n console.error(\n `Project \"${project}\" not found. Available projects: ${projectNames.join(\n \", \"\n )}`\n );\n return;\n }\n\n // Fetch all spans that belong to this trace\n const traceSpans: SpanData[] = [];\n let cursor: string | null = null;\n let totalFetched = 0;\n\n console.log(`Fetching trace ${traceId} from project \"${project}\"...`);\n\n // We need to fetch spans in batches and filter by trace_id\n // Since the API doesn't support direct trace_id filtering\n while (true) {\n const query: Record<string, any> = {\n limit: 100, // Fetch in chunks\n };\n\n if (cursor) {\n query.cursor = cursor;\n }\n\n const response = await client.GET(\n \"/v1/projects/{project_identifier}/spans\",\n {\n params: {\n path: {\n project_identifier: project,\n },\n query,\n },\n }\n );\n\n if (response.error) throw response.error;\n\n const data = response.data?.data ?? [];\n totalFetched += data.length;\n\n // Filter spans that belong to our trace\n const matchingSpans = (data as SpanData[]).filter(\n (span) => span.context.trace_id === traceId\n );\n traceSpans.push(...matchingSpans);\n\n cursor = response.data?.next_cursor ?? null;\n\n // Stop if we found spans for the trace or no more data\n if (traceSpans.length > 0 || !cursor || data.length === 0) {\n // If we found some spans, continue until we have all spans from the trace\n // This is because trace spans might be spread across multiple pages\n if (traceSpans.length > 0 && cursor && data.length > 0) {\n console.log(\n `Found ${traceSpans.length} spans so far, continuing search...`\n );\n continue;\n }\n break;\n }\n\n // Show progress for large datasets\n if (totalFetched % 1000 === 0) {\n console.log(`Searched ${totalFetched} spans so far...`);\n }\n }\n\n if (traceSpans.length === 0) {\n console.log(\n `No spans found for trace ${traceId} in project \"${project}\"`\n );\n console.log(\n `Searched through ${totalFetched} spans. The trace might not exist or might be in a different project.`\n );\n return;\n }\n\n // Sort spans by start_time to show them in order\n traceSpans.sort(\n (a, b) =>\n new Date(a.start_time).getTime() - new Date(b.start_time).getTime()\n );\n\n // Write trace spans to a dedicated file\n const jsonlContent = traceSpans\n .map((span) => JSON.stringify(span))\n .join(\"\\n\");\n\n const traceDir = `/phoenix/traces/${traceId}`;\n await mode.writeFile(`${traceDir}/spans.jsonl`, jsonlContent);\n\n // Create trace metadata\n const rootSpan = traceSpans.find((span) => !span.parent_id);\n const firstSpan = traceSpans[0];\n const lastSpan = traceSpans[traceSpans.length - 1];\n const metadata = {\n traceId,\n project,\n spanCount: traceSpans.length,\n rootSpan: rootSpan ? { id: rootSpan.id, name: rootSpan.name } : null,\n startTime: firstSpan?.start_time || null,\n endTime: lastSpan?.end_time || null,\n duration:\n firstSpan && lastSpan\n ? new Date(lastSpan.end_time).getTime() -\n new Date(firstSpan.start_time).getTime()\n : 0,\n snapshotTime: new Date().toISOString(),\n };\n\n await mode.writeFile(\n `${traceDir}/metadata.json`,\n JSON.stringify(metadata, null, 2)\n );\n\n console.log(`\\nSuccessfully fetched trace ${traceId}:`);\n console.log(`- Project: ${project}`);\n console.log(`- Spans: ${traceSpans.length}`);\n console.log(`- Root span: ${rootSpan?.name || \"Unknown\"}`);\n console.log(`- Duration: ${(metadata.duration / 1000).toFixed(2)} seconds`);\n console.log(`\\nTrace data saved to: ${traceDir}/`);\n }, `fetching trace ${traceId}`);\n}\n","/**\n * Report Tool for Phoenix Insight AI Agent\n *\n * AI SDK tool that allows the agent to update the UI report panel.\n * The agent calls `generate_report` with a title and JSON-Render tree content,\n * which is validated against the catalog schema and broadcast to the UI client.\n */\n\nimport { tool } from \"ai\";\nimport { z } from \"zod\";\nimport type { ReportCallback } from \"../server/session.js\";\n\n// Import component schemas and catalog from UI package (single source of truth)\nimport {\n catalog,\n CardSchema,\n ChartSchema,\n TextSchema,\n HeadingSchema,\n ListSchema,\n TableSchema,\n MetricSchema,\n BadgeSchema,\n AlertSchema,\n SeparatorSchema,\n CodeSchema,\n} from \"@cephalization/phoenix-insight-ui/catalog\";\n\n/**\n * UIElement schema - a single element in the render tree\n * Kept in CLI for tool-specific validation needs\n */\nconst UIElementSchema = z.object({\n key: z.string(),\n type: z.enum([\n \"Card\",\n \"Chart\",\n \"Text\",\n \"Heading\",\n \"List\",\n \"Table\",\n \"Metric\",\n \"Badge\",\n \"Alert\",\n \"Separator\",\n \"Code\",\n ]),\n props: z.record(z.string(), z.unknown()),\n children: z.array(z.string()).optional(),\n parentKey: z.string().optional(),\n});\n\n/**\n * UITree schema - the full JSON-Render tree structure\n */\nconst UITreeSchema = z.object({\n root: z.string(),\n elements: z.record(z.string(), UIElementSchema),\n});\n\n/**\n * Inferred UIElement type\n */\ntype UIElement = z.infer<typeof UIElementSchema>;\n\n/**\n * Inferred UITree type\n */\ntype UITree = z.infer<typeof UITreeSchema>;\n\n// ============================================================================\n// Report Tool Types\n// ============================================================================\n\n/**\n * Report tool input type\n */\nexport interface ReportToolInput {\n title?: string;\n content: UITree;\n}\n\n/**\n * Report tool result type\n */\nexport interface ReportToolResult {\n success: boolean;\n message?: string;\n error?: string;\n}\n\n// ============================================================================\n// Validation Helpers\n// ============================================================================\n\n/**\n * Valid component types\n */\nconst VALID_COMPONENT_TYPES = [\n \"Card\",\n \"Chart\",\n \"Text\",\n \"Heading\",\n \"List\",\n \"Table\",\n \"Metric\",\n \"Badge\",\n \"Alert\",\n \"Separator\",\n \"Code\",\n] as const;\n\ntype ComponentType = (typeof VALID_COMPONENT_TYPES)[number];\n\n/**\n * Get the props schema for a specific component type\n */\nfunction getPropsSchemaForType(\n type: ComponentType\n): z.ZodType<Record<string, unknown>> {\n switch (type) {\n case \"Card\":\n return CardSchema;\n case \"Chart\":\n return ChartSchema;\n case \"Text\":\n return TextSchema;\n case \"Heading\":\n return HeadingSchema;\n case \"List\":\n return ListSchema;\n case \"Table\":\n return TableSchema;\n case \"Metric\":\n return MetricSchema;\n case \"Badge\":\n return BadgeSchema;\n case \"Alert\":\n return AlertSchema;\n case \"Separator\":\n return SeparatorSchema;\n case \"Code\":\n return CodeSchema;\n }\n}\n\n/**\n * Validate a UITree content against the json-render catalog schema\n * Returns an object with success status and optional error message\n */\nexport function validateReportContent(content: unknown): {\n success: boolean;\n error?: string;\n} {\n // First, validate the tree structure\n const treeResult = UITreeSchema.safeParse(content);\n if (!treeResult.success) {\n return {\n success: false,\n error: `Invalid tree structure: ${treeResult.error.message}`,\n };\n }\n\n const tree = treeResult.data;\n\n // Verify root element exists\n if (!tree.elements[tree.root]) {\n return {\n success: false,\n error: `Root element \"${tree.root}\" not found in elements`,\n };\n }\n\n // Validate each element's props against its component schema\n for (const [key, element] of Object.entries(tree.elements)) {\n const type = element.type as ComponentType;\n\n if (!VALID_COMPONENT_TYPES.includes(type)) {\n return {\n success: false,\n error: `Unknown component type \"${type}\" for element \"${key}\"`,\n };\n }\n\n const propsSchema = getPropsSchemaForType(type);\n const propsResult = propsSchema.safeParse(element.props);\n\n if (!propsResult.success) {\n return {\n success: false,\n error: `Invalid props for ${type} element \"${key}\": ${propsResult.error.message}`,\n };\n }\n\n // Validate children references if present\n if (element.children) {\n for (const childKey of element.children) {\n if (!tree.elements[childKey]) {\n return {\n success: false,\n error: `Child element \"${childKey}\" not found for parent \"${key}\"`,\n };\n }\n }\n }\n\n // Validate parent reference if present\n if (element.parentKey && !tree.elements[element.parentKey]) {\n return {\n success: false,\n error: `Parent element \"${element.parentKey}\" not found for element \"${key}\"`,\n };\n }\n }\n\n return { success: true };\n}\n\n// ============================================================================\n// Dynamic Component Documentation\n// ============================================================================\n\n/**\n * Extract prop names from a Zod object schema\n * Returns array of prop names with \"?\" suffix for optional props\n */\nfunction extractPropNames(schema: z.ZodTypeAny): string[] {\n // Handle ZodObject schemas\n if (schema instanceof z.ZodObject) {\n const shape = schema.shape;\n return Object.entries(shape).map(([key, value]) => {\n // Check if the prop is optional\n const isOptional = value instanceof z.ZodOptional || \n value instanceof z.ZodNullable ||\n (value as z.ZodTypeAny).isOptional?.();\n return isOptional ? `${key}?` : key;\n });\n }\n return [];\n}\n\n/**\n * Generate component documentation from the catalog\n * Iterates over catalog.components and builds a description string\n */\nexport function generateComponentDocs(\n catalogDef: typeof catalog\n): string {\n const lines: string[] = [];\n \n for (const [name, component] of Object.entries(catalogDef.components)) {\n const propNames = extractPropNames(component.props);\n const propsStr = propNames.length > 0 ? `props: ${propNames.join(\", \")}` : \"no props\";\n const childrenNote = component.hasChildren ? \"; can have children\" : \"\";\n lines.push(`- ${name}: ${component.description} (${propsStr}${childrenNote})`);\n }\n \n return lines.join(\"\\n\");\n}\n\n// ============================================================================\n// Report Tool Factory\n// ============================================================================\n\n/**\n * Create the generate_report tool for the AI agent\n *\n * @param broadcast - Callback function to send report updates to the WebSocket client\n * @returns AI SDK tool definition for generate_report\n */\nexport function createReportTool(broadcast: ReportCallback) {\n const componentDocs = generateComponentDocs(catalog);\n \n return tool({\n description: `Generate or update a structured report that will be displayed in the UI report panel. \nThe report uses a JSON-Render tree format with the following component types:\n${componentDocs}\n\nThe tree structure has a 'root' key pointing to the root element and an 'elements' map of all elements.\nEach element has: key (unique id), type (component type), props (component-specific), children? (array of child keys).\n\nUse this tool when you want to present structured analysis results, metrics, tables, or formatted reports to the user.`,\n inputSchema: z.object({\n title: z\n .string()\n .optional()\n .describe(\"Optional title for the report displayed in the header\"),\n content: UITreeSchema.describe(\"The JSON-Render tree structure\"),\n }),\n execute: async (params: {\n title?: string;\n content: UITree;\n }): Promise<ReportToolResult> => {\n const { title, content } = params;\n\n // Validate content against catalog schema\n const validation = validateReportContent(content);\n if (!validation.success) {\n return {\n success: false,\n error: validation.error,\n };\n }\n\n // Broadcast the report to the WebSocket client\n try {\n broadcast(content, title);\n return {\n success: true,\n message: title\n ? `Report \"${title}\" generated successfully`\n : \"Report generated successfully\",\n };\n } catch (error) {\n return {\n success: false,\n error: `Failed to broadcast report: ${\n error instanceof Error ? error.message : String(error)\n }`,\n };\n }\n },\n });\n}\n","import { z } from \"zod\";\n\n/**\n * Dynamic value - can be a literal or a path reference to data model\n */\nexport type DynamicValue<T = unknown> = T | { path: string };\n\n/**\n * Dynamic string value\n */\nexport type DynamicString = DynamicValue<string>;\n\n/**\n * Dynamic number value\n */\nexport type DynamicNumber = DynamicValue<number>;\n\n/**\n * Dynamic boolean value\n */\nexport type DynamicBoolean = DynamicValue<boolean>;\n\n/**\n * Zod schema for dynamic values\n */\nexport const DynamicValueSchema = z.union([\n z.string(),\n z.number(),\n z.boolean(),\n z.null(),\n z.object({ path: z.string() }),\n]);\n\nexport const DynamicStringSchema = z.union([\n z.string(),\n z.object({ path: z.string() }),\n]);\n\nexport const DynamicNumberSchema = z.union([\n z.number(),\n z.object({ path: z.string() }),\n]);\n\nexport const DynamicBooleanSchema = z.union([\n z.boolean(),\n z.object({ path: z.string() }),\n]);\n\n/**\n * Base UI element structure for v2\n */\nexport interface UIElement<\n T extends string = string,\n P = Record<string, unknown>,\n> {\n /** Unique key for reconciliation */\n key: string;\n /** Component type from the catalog */\n type: T;\n /** Component props */\n props: P;\n /** Child element keys (flat structure) */\n children?: string[];\n /** Parent element key (null for root) */\n parentKey?: string | null;\n /** Visibility condition */\n visible?: VisibilityCondition;\n}\n\n/**\n * Visibility condition types\n */\nexport type VisibilityCondition =\n | boolean\n | { path: string }\n | { auth: \"signedIn\" | \"signedOut\" }\n | LogicExpression;\n\n/**\n * Logic expression for complex conditions\n */\nexport type LogicExpression =\n | { and: LogicExpression[] }\n | { or: LogicExpression[] }\n | { not: LogicExpression }\n | { path: string }\n | { eq: [DynamicValue, DynamicValue] }\n | { neq: [DynamicValue, DynamicValue] }\n | { gt: [DynamicValue<number>, DynamicValue<number>] }\n | { gte: [DynamicValue<number>, DynamicValue<number>] }\n | { lt: [DynamicValue<number>, DynamicValue<number>] }\n | { lte: [DynamicValue<number>, DynamicValue<number>] };\n\n/**\n * Flat UI tree structure (optimized for LLM generation)\n */\nexport interface UITree {\n /** Root element key */\n root: string;\n /** Flat map of elements by key */\n elements: Record<string, UIElement>;\n}\n\n/**\n * Auth state for visibility evaluation\n */\nexport interface AuthState {\n isSignedIn: boolean;\n user?: Record<string, unknown>;\n}\n\n/**\n * Data model type\n */\nexport type DataModel = Record<string, unknown>;\n\n/**\n * Component schema definition using Zod\n */\nexport type ComponentSchema = z.ZodType<Record<string, unknown>>;\n\n/**\n * Validation mode for catalog validation\n */\nexport type ValidationMode = \"strict\" | \"warn\" | \"ignore\";\n\n/**\n * JSON patch operation types\n */\nexport type PatchOp = \"add\" | \"remove\" | \"replace\" | \"set\";\n\n/**\n * JSON patch operation\n */\nexport interface JsonPatch {\n op: PatchOp;\n path: string;\n value?: unknown;\n}\n\n/**\n * Resolve a dynamic value against a data model\n */\nexport function resolveDynamicValue<T>(\n value: DynamicValue<T>,\n dataModel: DataModel,\n): T | undefined {\n if (value === null || value === undefined) {\n return undefined;\n }\n\n if (typeof value === \"object\" && \"path\" in value) {\n return getByPath(dataModel, value.path) as T | undefined;\n }\n\n return value as T;\n}\n\n/**\n * Get a value from an object by JSON Pointer path\n */\nexport function getByPath(obj: unknown, path: string): unknown {\n if (!path || path === \"/\") {\n return obj;\n }\n\n const segments = path.startsWith(\"/\")\n ? path.slice(1).split(\"/\")\n : path.split(\"/\");\n\n let current: unknown = obj;\n\n for (const segment of segments) {\n if (current === null || current === undefined) {\n return undefined;\n }\n\n if (typeof current === \"object\") {\n current = (current as Record<string, unknown>)[segment];\n } else {\n return undefined;\n }\n }\n\n return current;\n}\n\n/**\n * Set a value in an object by JSON Pointer path\n */\nexport function setByPath(\n obj: Record<string, unknown>,\n path: string,\n value: unknown,\n): void {\n const segments = path.startsWith(\"/\")\n ? path.slice(1).split(\"/\")\n : path.split(\"/\");\n\n if (segments.length === 0) return;\n\n let current: Record<string, unknown> = obj;\n\n for (let i = 0; i < segments.length - 1; i++) {\n const segment = segments[i]!;\n if (!(segment in current) || typeof current[segment] !== \"object\") {\n current[segment] = {};\n }\n current = current[segment] as Record<string, unknown>;\n }\n\n const lastSegment = segments[segments.length - 1]!;\n current[lastSegment] = value;\n}\n","import { z } from \"zod\";\nimport type {\n VisibilityCondition,\n LogicExpression,\n DataModel,\n AuthState,\n DynamicValue,\n} from \"./types\";\nimport { resolveDynamicValue, DynamicValueSchema } from \"./types\";\n\n// Dynamic value schema for comparisons (number-focused)\nconst DynamicNumberValueSchema = z.union([\n z.number(),\n z.object({ path: z.string() }),\n]);\n\n/**\n * Logic expression schema (recursive)\n * Using a more permissive schema that aligns with runtime behavior\n */\nexport const LogicExpressionSchema: z.ZodType<LogicExpression> = z.lazy(() =>\n z.union([\n z.object({ and: z.array(LogicExpressionSchema) }),\n z.object({ or: z.array(LogicExpressionSchema) }),\n z.object({ not: LogicExpressionSchema }),\n z.object({ path: z.string() }),\n z.object({ eq: z.tuple([DynamicValueSchema, DynamicValueSchema]) }),\n z.object({ neq: z.tuple([DynamicValueSchema, DynamicValueSchema]) }),\n z.object({\n gt: z.tuple([DynamicNumberValueSchema, DynamicNumberValueSchema]),\n }),\n z.object({\n gte: z.tuple([DynamicNumberValueSchema, DynamicNumberValueSchema]),\n }),\n z.object({\n lt: z.tuple([DynamicNumberValueSchema, DynamicNumberValueSchema]),\n }),\n z.object({\n lte: z.tuple([DynamicNumberValueSchema, DynamicNumberValueSchema]),\n }),\n ]),\n) as z.ZodType<LogicExpression>;\n\n/**\n * Visibility condition schema\n */\nexport const VisibilityConditionSchema: z.ZodType<VisibilityCondition> =\n z.union([\n z.boolean(),\n z.object({ path: z.string() }),\n z.object({ auth: z.enum([\"signedIn\", \"signedOut\"]) }),\n LogicExpressionSchema,\n ]);\n\n/**\n * Context for evaluating visibility\n */\nexport interface VisibilityContext {\n dataModel: DataModel;\n authState?: AuthState;\n}\n\n/**\n * Evaluate a logic expression against data and auth state\n */\nexport function evaluateLogicExpression(\n expr: LogicExpression,\n ctx: VisibilityContext,\n): boolean {\n const { dataModel } = ctx;\n\n // AND expression\n if (\"and\" in expr) {\n return expr.and.every((subExpr) => evaluateLogicExpression(subExpr, ctx));\n }\n\n // OR expression\n if (\"or\" in expr) {\n return expr.or.some((subExpr) => evaluateLogicExpression(subExpr, ctx));\n }\n\n // NOT expression\n if (\"not\" in expr) {\n return !evaluateLogicExpression(expr.not, ctx);\n }\n\n // Path expression (resolve to boolean)\n if (\"path\" in expr) {\n const value = resolveDynamicValue({ path: expr.path }, dataModel);\n return Boolean(value);\n }\n\n // Equality comparison\n if (\"eq\" in expr) {\n const [left, right] = expr.eq;\n const leftValue = resolveDynamicValue(left, dataModel);\n const rightValue = resolveDynamicValue(right, dataModel);\n return leftValue === rightValue;\n }\n\n // Not equal comparison\n if (\"neq\" in expr) {\n const [left, right] = expr.neq;\n const leftValue = resolveDynamicValue(left, dataModel);\n const rightValue = resolveDynamicValue(right, dataModel);\n return leftValue !== rightValue;\n }\n\n // Greater than\n if (\"gt\" in expr) {\n const [left, right] = expr.gt;\n const leftValue = resolveDynamicValue(\n left as DynamicValue<number>,\n dataModel,\n );\n const rightValue = resolveDynamicValue(\n right as DynamicValue<number>,\n dataModel,\n );\n if (typeof leftValue === \"number\" && typeof rightValue === \"number\") {\n return leftValue > rightValue;\n }\n return false;\n }\n\n // Greater than or equal\n if (\"gte\" in expr) {\n const [left, right] = expr.gte;\n const leftValue = resolveDynamicValue(\n left as DynamicValue<number>,\n dataModel,\n );\n const rightValue = resolveDynamicValue(\n right as DynamicValue<number>,\n dataModel,\n );\n if (typeof leftValue === \"number\" && typeof rightValue === \"number\") {\n return leftValue >= rightValue;\n }\n return false;\n }\n\n // Less than\n if (\"lt\" in expr) {\n const [left, right] = expr.lt;\n const leftValue = resolveDynamicValue(\n left as DynamicValue<number>,\n dataModel,\n );\n const rightValue = resolveDynamicValue(\n right as DynamicValue<number>,\n dataModel,\n );\n if (typeof leftValue === \"number\" && typeof rightValue === \"number\") {\n return leftValue < rightValue;\n }\n return false;\n }\n\n // Less than or equal\n if (\"lte\" in expr) {\n const [left, right] = expr.lte;\n const leftValue = resolveDynamicValue(\n left as DynamicValue<number>,\n dataModel,\n );\n const rightValue = resolveDynamicValue(\n right as DynamicValue<number>,\n dataModel,\n );\n if (typeof leftValue === \"number\" && typeof rightValue === \"number\") {\n return leftValue <= rightValue;\n }\n return false;\n }\n\n return false;\n}\n\n/**\n * Evaluate a visibility condition\n */\nexport function evaluateVisibility(\n condition: VisibilityCondition | undefined,\n ctx: VisibilityContext,\n): boolean {\n // No condition = visible\n if (condition === undefined) {\n return true;\n }\n\n // Boolean literal\n if (typeof condition === \"boolean\") {\n return condition;\n }\n\n // Path reference\n if (\"path\" in condition && !(\"and\" in condition) && !(\"or\" in condition)) {\n const value = resolveDynamicValue({ path: condition.path }, ctx.dataModel);\n return Boolean(value);\n }\n\n // Auth condition\n if (\"auth\" in condition) {\n const isSignedIn = ctx.authState?.isSignedIn ?? false;\n if (condition.auth === \"signedIn\") {\n return isSignedIn;\n }\n if (condition.auth === \"signedOut\") {\n return !isSignedIn;\n }\n return false;\n }\n\n // Logic expression\n return evaluateLogicExpression(condition as LogicExpression, ctx);\n}\n\n/**\n * Helper to create visibility conditions\n */\nexport const visibility = {\n /** Always visible */\n always: true as const,\n\n /** Never visible */\n never: false as const,\n\n /** Visible when path is truthy */\n when: (path: string): VisibilityCondition => ({ path }),\n\n /** Visible when signed in */\n signedIn: { auth: \"signedIn\" } as const,\n\n /** Visible when signed out */\n signedOut: { auth: \"signedOut\" } as const,\n\n /** AND multiple conditions */\n and: (...conditions: LogicExpression[]): LogicExpression => ({\n and: conditions,\n }),\n\n /** OR multiple conditions */\n or: (...conditions: LogicExpression[]): LogicExpression => ({\n or: conditions,\n }),\n\n /** NOT a condition */\n not: (condition: LogicExpression): LogicExpression => ({ not: condition }),\n\n /** Equality check */\n eq: (left: DynamicValue, right: DynamicValue): LogicExpression => ({\n eq: [left, right],\n }),\n\n /** Not equal check */\n neq: (left: DynamicValue, right: DynamicValue): LogicExpression => ({\n neq: [left, right],\n }),\n\n /** Greater than */\n gt: (\n left: DynamicValue<number>,\n right: DynamicValue<number>,\n ): LogicExpression => ({ gt: [left, right] }),\n\n /** Greater than or equal */\n gte: (\n left: DynamicValue<number>,\n right: DynamicValue<number>,\n ): LogicExpression => ({ gte: [left, right] }),\n\n /** Less than */\n lt: (\n left: DynamicValue<number>,\n right: DynamicValue<number>,\n ): LogicExpression => ({ lt: [left, right] }),\n\n /** Less than or equal */\n lte: (\n left: DynamicValue<number>,\n right: DynamicValue<number>,\n ): LogicExpression => ({ lte: [left, right] }),\n};\n","import { z } from \"zod\";\nimport type { DynamicValue, DataModel } from \"./types\";\nimport { DynamicValueSchema, resolveDynamicValue } from \"./types\";\n\n/**\n * Confirmation dialog configuration\n */\nexport interface ActionConfirm {\n title: string;\n message: string;\n confirmLabel?: string;\n cancelLabel?: string;\n variant?: \"default\" | \"danger\";\n}\n\n/**\n * Action success handler\n */\nexport type ActionOnSuccess =\n | { navigate: string }\n | { set: Record<string, unknown> }\n | { action: string };\n\n/**\n * Action error handler\n */\nexport type ActionOnError =\n | { set: Record<string, unknown> }\n | { action: string };\n\n/**\n * Rich action definition\n */\nexport interface Action {\n /** Action name (must be in catalog) */\n name: string;\n /** Parameters to pass to the action handler */\n params?: Record<string, DynamicValue>;\n /** Confirmation dialog before execution */\n confirm?: ActionConfirm;\n /** Handler after successful execution */\n onSuccess?: ActionOnSuccess;\n /** Handler after failed execution */\n onError?: ActionOnError;\n}\n\n/**\n * Schema for action confirmation\n */\nexport const ActionConfirmSchema = z.object({\n title: z.string(),\n message: z.string(),\n confirmLabel: z.string().optional(),\n cancelLabel: z.string().optional(),\n variant: z.enum([\"default\", \"danger\"]).optional(),\n});\n\n/**\n * Schema for success handlers\n */\nexport const ActionOnSuccessSchema = z.union([\n z.object({ navigate: z.string() }),\n z.object({ set: z.record(z.string(), z.unknown()) }),\n z.object({ action: z.string() }),\n]);\n\n/**\n * Schema for error handlers\n */\nexport const ActionOnErrorSchema = z.union([\n z.object({ set: z.record(z.string(), z.unknown()) }),\n z.object({ action: z.string() }),\n]);\n\n/**\n * Full action schema\n */\nexport const ActionSchema = z.object({\n name: z.string(),\n params: z.record(z.string(), DynamicValueSchema).optional(),\n confirm: ActionConfirmSchema.optional(),\n onSuccess: ActionOnSuccessSchema.optional(),\n onError: ActionOnErrorSchema.optional(),\n});\n\n/**\n * Action handler function signature\n */\nexport type ActionHandler<\n TParams = Record<string, unknown>,\n TResult = unknown,\n> = (params: TParams) => Promise<TResult> | TResult;\n\n/**\n * Action definition in catalog\n */\nexport interface ActionDefinition<TParams = Record<string, unknown>> {\n /** Zod schema for params validation */\n params?: z.ZodType<TParams>;\n /** Description for AI */\n description?: string;\n}\n\n/**\n * Resolved action with all dynamic values resolved\n */\nexport interface ResolvedAction {\n name: string;\n params: Record<string, unknown>;\n confirm?: ActionConfirm;\n onSuccess?: ActionOnSuccess;\n onError?: ActionOnError;\n}\n\n/**\n * Resolve all dynamic values in an action\n */\nexport function resolveAction(\n action: Action,\n dataModel: DataModel,\n): ResolvedAction {\n const resolvedParams: Record<string, unknown> = {};\n\n if (action.params) {\n for (const [key, value] of Object.entries(action.params)) {\n resolvedParams[key] = resolveDynamicValue(value, dataModel);\n }\n }\n\n // Interpolate confirmation message if present\n let confirm = action.confirm;\n if (confirm) {\n confirm = {\n ...confirm,\n message: interpolateString(confirm.message, dataModel),\n title: interpolateString(confirm.title, dataModel),\n };\n }\n\n return {\n name: action.name,\n params: resolvedParams,\n confirm,\n onSuccess: action.onSuccess,\n onError: action.onError,\n };\n}\n\n/**\n * Interpolate ${path} expressions in a string\n */\nexport function interpolateString(\n template: string,\n dataModel: DataModel,\n): string {\n return template.replace(/\\$\\{([^}]+)\\}/g, (_, path) => {\n const value = resolveDynamicValue({ path }, dataModel);\n return String(value ?? \"\");\n });\n}\n\n/**\n * Context for action execution\n */\nexport interface ActionExecutionContext {\n /** The resolved action */\n action: ResolvedAction;\n /** The action handler from the host */\n handler: ActionHandler;\n /** Function to update data model */\n setData: (path: string, value: unknown) => void;\n /** Function to navigate */\n navigate?: (path: string) => void;\n /** Function to execute another action */\n executeAction?: (name: string) => Promise<void>;\n}\n\n/**\n * Execute an action with all callbacks\n */\nexport async function executeAction(\n ctx: ActionExecutionContext,\n): Promise<void> {\n const { action, handler, setData, navigate, executeAction } = ctx;\n\n try {\n await handler(action.params);\n\n // Handle success\n if (action.onSuccess) {\n if (\"navigate\" in action.onSuccess && navigate) {\n navigate(action.onSuccess.navigate);\n } else if (\"set\" in action.onSuccess) {\n for (const [path, value] of Object.entries(action.onSuccess.set)) {\n setData(path, value);\n }\n } else if (\"action\" in action.onSuccess && executeAction) {\n await executeAction(action.onSuccess.action);\n }\n }\n } catch (error) {\n // Handle error\n if (action.onError) {\n if (\"set\" in action.onError) {\n for (const [path, value] of Object.entries(action.onError.set)) {\n // Replace $error.message with actual error\n const resolvedValue =\n typeof value === \"string\" && value === \"$error.message\"\n ? (error as Error).message\n : value;\n setData(path, resolvedValue);\n }\n } else if (\"action\" in action.onError && executeAction) {\n await executeAction(action.onError.action);\n }\n } else {\n throw error;\n }\n }\n}\n\n/**\n * Helper to create actions\n */\nexport const action = {\n /** Create a simple action */\n simple: (name: string, params?: Record<string, DynamicValue>): Action => ({\n name,\n params,\n }),\n\n /** Create an action with confirmation */\n withConfirm: (\n name: string,\n confirm: ActionConfirm,\n params?: Record<string, DynamicValue>,\n ): Action => ({\n name,\n params,\n confirm,\n }),\n\n /** Create an action with success handler */\n withSuccess: (\n name: string,\n onSuccess: ActionOnSuccess,\n params?: Record<string, DynamicValue>,\n ): Action => ({\n name,\n params,\n onSuccess,\n }),\n};\n","import { z } from \"zod\";\nimport type { DynamicValue, DataModel, LogicExpression } from \"./types\";\nimport { DynamicValueSchema, resolveDynamicValue } from \"./types\";\nimport { LogicExpressionSchema, evaluateLogicExpression } from \"./visibility\";\n\n/**\n * Validation check definition\n */\nexport interface ValidationCheck {\n /** Function name (built-in or from catalog) */\n fn: string;\n /** Additional arguments for the function */\n args?: Record<string, DynamicValue>;\n /** Error message to display if check fails */\n message: string;\n}\n\n/**\n * Validation configuration for a field\n */\nexport interface ValidationConfig {\n /** Array of checks to run */\n checks?: ValidationCheck[];\n /** When to run validation */\n validateOn?: \"change\" | \"blur\" | \"submit\";\n /** Condition for when validation is enabled */\n enabled?: LogicExpression;\n}\n\n/**\n * Schema for validation check\n */\nexport const ValidationCheckSchema = z.object({\n fn: z.string(),\n args: z.record(z.string(), DynamicValueSchema).optional(),\n message: z.string(),\n});\n\n/**\n * Schema for validation config\n */\nexport const ValidationConfigSchema = z.object({\n checks: z.array(ValidationCheckSchema).optional(),\n validateOn: z.enum([\"change\", \"blur\", \"submit\"]).optional(),\n enabled: LogicExpressionSchema.optional(),\n});\n\n/**\n * Validation function signature\n */\nexport type ValidationFunction = (\n value: unknown,\n args?: Record<string, unknown>,\n) => boolean;\n\n/**\n * Validation function definition in catalog\n */\nexport interface ValidationFunctionDefinition {\n /** The validation function */\n validate: ValidationFunction;\n /** Description for AI */\n description?: string;\n}\n\n/**\n * Built-in validation functions\n */\nexport const builtInValidationFunctions: Record<string, ValidationFunction> = {\n /**\n * Check if value is not null, undefined, or empty string\n */\n required: (value: unknown) => {\n if (value === null || value === undefined) return false;\n if (typeof value === \"string\") return value.trim().length > 0;\n if (Array.isArray(value)) return value.length > 0;\n return true;\n },\n\n /**\n * Check if value is a valid email address\n */\n email: (value: unknown) => {\n if (typeof value !== \"string\") return false;\n return /^[^\\s@]+@[^\\s@]+\\.[^\\s@]+$/.test(value);\n },\n\n /**\n * Check minimum string length\n */\n minLength: (value: unknown, args?: Record<string, unknown>) => {\n if (typeof value !== \"string\") return false;\n const min = args?.min;\n if (typeof min !== \"number\") return false;\n return value.length >= min;\n },\n\n /**\n * Check maximum string length\n */\n maxLength: (value: unknown, args?: Record<string, unknown>) => {\n if (typeof value !== \"string\") return false;\n const max = args?.max;\n if (typeof max !== \"number\") return false;\n return value.length <= max;\n },\n\n /**\n * Check if string matches a regex pattern\n */\n pattern: (value: unknown, args?: Record<string, unknown>) => {\n if (typeof value !== \"string\") return false;\n const pattern = args?.pattern;\n if (typeof pattern !== \"string\") return false;\n try {\n return new RegExp(pattern).test(value);\n } catch {\n return false;\n }\n },\n\n /**\n * Check minimum numeric value\n */\n min: (value: unknown, args?: Record<string, unknown>) => {\n if (typeof value !== \"number\") return false;\n const min = args?.min;\n if (typeof min !== \"number\") return false;\n return value >= min;\n },\n\n /**\n * Check maximum numeric value\n */\n max: (value: unknown, args?: Record<string, unknown>) => {\n if (typeof value !== \"number\") return false;\n const max = args?.max;\n if (typeof max !== \"number\") return false;\n return value <= max;\n },\n\n /**\n * Check if value is a number\n */\n numeric: (value: unknown) => {\n if (typeof value === \"number\") return !isNaN(value);\n if (typeof value === \"string\") return !isNaN(parseFloat(value));\n return false;\n },\n\n /**\n * Check if value is a valid URL\n */\n url: (value: unknown) => {\n if (typeof value !== \"string\") return false;\n try {\n new URL(value);\n return true;\n } catch {\n return false;\n }\n },\n\n /**\n * Check if value matches another field\n */\n matches: (value: unknown, args?: Record<string, unknown>) => {\n const other = args?.other;\n return value === other;\n },\n};\n\n/**\n * Validation result for a single check\n */\nexport interface ValidationCheckResult {\n fn: string;\n valid: boolean;\n message: string;\n}\n\n/**\n * Full validation result for a field\n */\nexport interface ValidationResult {\n valid: boolean;\n errors: string[];\n checks: ValidationCheckResult[];\n}\n\n/**\n * Context for running validation\n */\nexport interface ValidationContext {\n /** Current value to validate */\n value: unknown;\n /** Full data model for resolving paths */\n dataModel: DataModel;\n /** Custom validation functions from catalog */\n customFunctions?: Record<string, ValidationFunction>;\n}\n\n/**\n * Run a single validation check\n */\nexport function runValidationCheck(\n check: ValidationCheck,\n ctx: ValidationContext,\n): ValidationCheckResult {\n const { value, dataModel, customFunctions } = ctx;\n\n // Resolve args\n const resolvedArgs: Record<string, unknown> = {};\n if (check.args) {\n for (const [key, argValue] of Object.entries(check.args)) {\n resolvedArgs[key] = resolveDynamicValue(argValue, dataModel);\n }\n }\n\n // Find the validation function\n const fn =\n builtInValidationFunctions[check.fn] ?? customFunctions?.[check.fn];\n\n if (!fn) {\n console.warn(`Unknown validation function: ${check.fn}`);\n return {\n fn: check.fn,\n valid: true, // Don't fail on unknown functions\n message: check.message,\n };\n }\n\n const valid = fn(value, resolvedArgs);\n\n return {\n fn: check.fn,\n valid,\n message: check.message,\n };\n}\n\n/**\n * Run all validation checks for a field\n */\nexport function runValidation(\n config: ValidationConfig,\n ctx: ValidationContext & { authState?: { isSignedIn: boolean } },\n): ValidationResult {\n const checks: ValidationCheckResult[] = [];\n const errors: string[] = [];\n\n // Check if validation is enabled\n if (config.enabled) {\n const enabled = evaluateLogicExpression(config.enabled, {\n dataModel: ctx.dataModel,\n authState: ctx.authState,\n });\n if (!enabled) {\n return { valid: true, errors: [], checks: [] };\n }\n }\n\n // Run each check\n if (config.checks) {\n for (const check of config.checks) {\n const result = runValidationCheck(check, ctx);\n checks.push(result);\n if (!result.valid) {\n errors.push(result.message);\n }\n }\n }\n\n return {\n valid: errors.length === 0,\n errors,\n checks,\n };\n}\n\n/**\n * Helper to create validation checks\n */\nexport const check = {\n required: (message = \"This field is required\"): ValidationCheck => ({\n fn: \"required\",\n message,\n }),\n\n email: (message = \"Invalid email address\"): ValidationCheck => ({\n fn: \"email\",\n message,\n }),\n\n minLength: (min: number, message?: string): ValidationCheck => ({\n fn: \"minLength\",\n args: { min },\n message: message ?? `Must be at least ${min} characters`,\n }),\n\n maxLength: (max: number, message?: string): ValidationCheck => ({\n fn: \"maxLength\",\n args: { max },\n message: message ?? `Must be at most ${max} characters`,\n }),\n\n pattern: (pattern: string, message = \"Invalid format\"): ValidationCheck => ({\n fn: \"pattern\",\n args: { pattern },\n message,\n }),\n\n min: (min: number, message?: string): ValidationCheck => ({\n fn: \"min\",\n args: { min },\n message: message ?? `Must be at least ${min}`,\n }),\n\n max: (max: number, message?: string): ValidationCheck => ({\n fn: \"max\",\n args: { max },\n message: message ?? `Must be at most ${max}`,\n }),\n\n url: (message = \"Invalid URL\"): ValidationCheck => ({\n fn: \"url\",\n message,\n }),\n\n matches: (\n otherPath: string,\n message = \"Fields must match\",\n ): ValidationCheck => ({\n fn: \"matches\",\n args: { other: { path: otherPath } },\n message,\n }),\n};\n","import { z } from \"zod\";\nimport type {\n ComponentSchema,\n ValidationMode,\n UIElement,\n UITree,\n VisibilityCondition,\n} from \"./types\";\nimport { VisibilityConditionSchema } from \"./visibility\";\nimport { ActionSchema, type ActionDefinition } from \"./actions\";\nimport { ValidationConfigSchema, type ValidationFunction } from \"./validation\";\n\n/**\n * Component definition with visibility and validation support\n */\nexport interface ComponentDefinition<\n TProps extends ComponentSchema = ComponentSchema,\n> {\n /** Zod schema for component props */\n props: TProps;\n /** Whether this component can have children */\n hasChildren?: boolean;\n /** Description for AI generation */\n description?: string;\n}\n\n/**\n * Catalog configuration\n */\nexport interface CatalogConfig<\n TComponents extends Record<string, ComponentDefinition> = Record<\n string,\n ComponentDefinition\n >,\n TActions extends Record<string, ActionDefinition> = Record<\n string,\n ActionDefinition\n >,\n TFunctions extends Record<string, ValidationFunction> = Record<\n string,\n ValidationFunction\n >,\n> {\n /** Catalog name */\n name?: string;\n /** Component definitions */\n components: TComponents;\n /** Action definitions with param schemas */\n actions?: TActions;\n /** Custom validation functions */\n functions?: TFunctions;\n /** Validation mode */\n validation?: ValidationMode;\n}\n\n/**\n * Catalog instance\n */\nexport interface Catalog<\n TComponents extends Record<string, ComponentDefinition> = Record<\n string,\n ComponentDefinition\n >,\n TActions extends Record<string, ActionDefinition> = Record<\n string,\n ActionDefinition\n >,\n TFunctions extends Record<string, ValidationFunction> = Record<\n string,\n ValidationFunction\n >,\n> {\n /** Catalog name */\n readonly name: string;\n /** Component names */\n readonly componentNames: (keyof TComponents)[];\n /** Action names */\n readonly actionNames: (keyof TActions)[];\n /** Function names */\n readonly functionNames: (keyof TFunctions)[];\n /** Validation mode */\n readonly validation: ValidationMode;\n /** Component definitions */\n readonly components: TComponents;\n /** Action definitions */\n readonly actions: TActions;\n /** Custom validation functions */\n readonly functions: TFunctions;\n /** Full element schema for AI generation */\n readonly elementSchema: z.ZodType<UIElement>;\n /** Full UI tree schema */\n readonly treeSchema: z.ZodType<UITree>;\n /** Check if component exists */\n hasComponent(type: string): boolean;\n /** Check if action exists */\n hasAction(name: string): boolean;\n /** Check if function exists */\n hasFunction(name: string): boolean;\n /** Validate an element */\n validateElement(element: unknown): {\n success: boolean;\n data?: UIElement;\n error?: z.ZodError;\n };\n /** Validate a UI tree */\n validateTree(tree: unknown): {\n success: boolean;\n data?: UITree;\n error?: z.ZodError;\n };\n}\n\n/**\n * Create a v2 catalog with visibility, actions, and validation support\n */\nexport function createCatalog<\n TComponents extends Record<string, ComponentDefinition>,\n TActions extends Record<string, ActionDefinition> = Record<\n string,\n ActionDefinition\n >,\n TFunctions extends Record<string, ValidationFunction> = Record<\n string,\n ValidationFunction\n >,\n>(\n config: CatalogConfig<TComponents, TActions, TFunctions>,\n): Catalog<TComponents, TActions, TFunctions> {\n const {\n name = \"unnamed\",\n components,\n actions = {} as TActions,\n functions = {} as TFunctions,\n validation = \"strict\",\n } = config;\n\n const componentNames = Object.keys(components) as (keyof TComponents)[];\n const actionNames = Object.keys(actions) as (keyof TActions)[];\n const functionNames = Object.keys(functions) as (keyof TFunctions)[];\n\n // Create element schema for each component type\n const componentSchemas = componentNames.map((componentName) => {\n const def = components[componentName]!;\n\n return z.object({\n key: z.string(),\n type: z.literal(componentName as string),\n props: def.props,\n children: z.array(z.string()).optional(),\n parentKey: z.string().nullable().optional(),\n visible: VisibilityConditionSchema.optional(),\n });\n });\n\n // Create union schema for all components\n let elementSchema: z.ZodType<UIElement>;\n\n if (componentSchemas.length === 0) {\n elementSchema = z.object({\n key: z.string(),\n type: z.string(),\n props: z.record(z.string(), z.unknown()),\n children: z.array(z.string()).optional(),\n parentKey: z.string().nullable().optional(),\n visible: VisibilityConditionSchema.optional(),\n }) as unknown as z.ZodType<UIElement>;\n } else if (componentSchemas.length === 1) {\n elementSchema = componentSchemas[0] as unknown as z.ZodType<UIElement>;\n } else {\n elementSchema = z.discriminatedUnion(\"type\", [\n componentSchemas[0] as z.ZodObject<any>,\n componentSchemas[1] as z.ZodObject<any>,\n ...(componentSchemas.slice(2) as z.ZodObject<any>[]),\n ]) as unknown as z.ZodType<UIElement>;\n }\n\n // Create tree schema\n const treeSchema = z.object({\n root: z.string(),\n elements: z.record(z.string(), elementSchema),\n }) as unknown as z.ZodType<UITree>;\n\n return {\n name,\n componentNames,\n actionNames,\n functionNames,\n validation,\n components,\n actions,\n functions,\n elementSchema,\n treeSchema,\n\n hasComponent(type: string) {\n return type in components;\n },\n\n hasAction(name: string) {\n return name in actions;\n },\n\n hasFunction(name: string) {\n return name in functions;\n },\n\n validateElement(element: unknown) {\n const result = elementSchema.safeParse(element);\n if (result.success) {\n return { success: true, data: result.data };\n }\n return { success: false, error: result.error };\n },\n\n validateTree(tree: unknown) {\n const result = treeSchema.safeParse(tree);\n if (result.success) {\n return { success: true, data: result.data };\n }\n return { success: false, error: result.error };\n },\n };\n}\n\n/**\n * Generate a prompt for AI that describes the catalog\n */\nexport function generateCatalogPrompt<\n TComponents extends Record<string, ComponentDefinition>,\n TActions extends Record<string, ActionDefinition>,\n TFunctions extends Record<string, ValidationFunction>,\n>(catalog: Catalog<TComponents, TActions, TFunctions>): string {\n const lines: string[] = [\n `# ${catalog.name} Component Catalog`,\n \"\",\n \"## Available Components\",\n \"\",\n ];\n\n // Components\n for (const name of catalog.componentNames) {\n const def = catalog.components[name]!;\n lines.push(`### ${String(name)}`);\n if (def.description) {\n lines.push(def.description);\n }\n lines.push(\"\");\n }\n\n // Actions\n if (catalog.actionNames.length > 0) {\n lines.push(\"## Available Actions\");\n lines.push(\"\");\n for (const name of catalog.actionNames) {\n const def = catalog.actions[name]!;\n lines.push(\n `- \\`${String(name)}\\`${def.description ? `: ${def.description}` : \"\"}`,\n );\n }\n lines.push(\"\");\n }\n\n // Visibility\n lines.push(\"## Visibility Conditions\");\n lines.push(\"\");\n lines.push(\"Components can have a `visible` property:\");\n lines.push(\"- `true` / `false` - Always visible/hidden\");\n lines.push('- `{ \"path\": \"/data/path\" }` - Visible when path is truthy');\n lines.push('- `{ \"auth\": \"signedIn\" }` - Visible when user is signed in');\n lines.push('- `{ \"and\": [...] }` - All conditions must be true');\n lines.push('- `{ \"or\": [...] }` - Any condition must be true');\n lines.push('- `{ \"not\": {...} }` - Negates a condition');\n lines.push('- `{ \"eq\": [a, b] }` - Equality check');\n lines.push(\"\");\n\n // Validation\n lines.push(\"## Validation Functions\");\n lines.push(\"\");\n lines.push(\n \"Built-in: `required`, `email`, `minLength`, `maxLength`, `pattern`, `min`, `max`, `url`\",\n );\n if (catalog.functionNames.length > 0) {\n lines.push(`Custom: ${catalog.functionNames.map(String).join(\", \")}`);\n }\n lines.push(\"\");\n\n return lines.join(\"\\n\");\n}\n\n/**\n * Type helper to infer component props from catalog\n */\nexport type InferCatalogComponentProps<\n C extends Catalog<Record<string, ComponentDefinition>>,\n> = {\n [K in keyof C[\"components\"]]: z.infer<C[\"components\"][K][\"props\"]>;\n};\n","/**\n * JSON-Render Catalog for Phoenix Insight UI\n *\n * Defines the allowed components that can be rendered from AI-generated JSON.\n * Uses zod schemas for props validation.\n */\n\nimport { createCatalog } from \"@json-render/core\";\nimport { z } from \"zod\";\n\n/**\n * Card component - container for grouping related content\n */\nconst CardSchema = z.object({\n title: z.string().optional(),\n description: z.string().optional(),\n});\n\n/**\n * Text component - for paragraphs and inline text\n */\nconst TextSchema = z.object({\n content: z.string(),\n variant: z.enum([\"default\", \"muted\", \"lead\"]).optional(),\n});\n\n/**\n * Heading component - for section headers (h1-h6)\n */\nconst HeadingSchema = z.object({\n content: z.string(),\n level: z.coerce.number().int().min(1).max(6).optional(),\n});\n\n/**\n * List component - ordered and unordered lists\n */\nconst ListSchema = z.object({\n items: z.array(z.string()),\n ordered: z.boolean().optional(),\n});\n\n/**\n * Table component - tabular data display\n */\nconst TableSchema = z.object({\n headers: z.array(z.string()),\n rows: z.array(z.array(z.string())),\n caption: z.string().optional(),\n});\n\n/**\n * Metric component - displays a key metric value\n */\nconst MetricSchema = z.object({\n label: z.string(),\n value: z.string(),\n change: z.string().optional(),\n changeType: z.enum([\"positive\", \"negative\", \"neutral\"]).optional(),\n});\n\n/**\n * Badge component - inline status or category indicator\n */\nconst BadgeSchema = z.object({\n content: z.string(),\n variant: z\n .enum([\"default\", \"secondary\", \"destructive\", \"outline\"])\n .optional(),\n});\n\n/**\n * Alert component - important messages or warnings\n */\nconst AlertSchema = z.object({\n title: z.string().optional(),\n description: z.string(),\n variant: z.enum([\"default\", \"destructive\"]).optional(),\n});\n\n/**\n * Separator component - visual divider\n */\nconst SeparatorSchema = z.object({\n orientation: z.enum([\"horizontal\", \"vertical\"]).optional(),\n});\n\n/**\n * Code component - code blocks with syntax highlighting\n */\nconst CodeSchema = z.object({\n content: z.string(),\n language: z.string().optional(),\n});\n\n/**\n * Chart component - displays a chart from array data\n */\nconst ChartSchema = z.object({\n type: z.enum([\"bar\", \"line\", \"pie\", \"area\"]),\n data: z.array(z.object({ label: z.string(), value: z.number() })),\n title: z.string().nullable(),\n height: z.number().nullable(),\n});\n\n/**\n * The Phoenix Insight UI catalog\n *\n * Defines all components that AI can generate for reports.\n * Each component has a zod schema for props validation.\n */\nexport const catalog = createCatalog({\n name: \"phoenix-insight-ui\",\n components: {\n Card: {\n props: CardSchema,\n hasChildren: true,\n description:\n \"Container for grouping related content with optional title and description\",\n },\n Chart: {\n props: ChartSchema,\n hasChildren: false,\n description:\n \"Chart display from array data with optional title and height\",\n },\n Text: {\n props: TextSchema,\n hasChildren: false,\n description:\n \"Text paragraph with optional styling variants (default, muted, lead)\",\n },\n Heading: {\n props: HeadingSchema,\n hasChildren: false,\n description: \"Section heading with configurable level (1-6)\",\n },\n List: {\n props: ListSchema,\n hasChildren: false,\n description: \"Ordered or unordered list of items\",\n },\n Table: {\n props: TableSchema,\n hasChildren: false,\n description:\n \"Tabular data display with headers, rows, and optional caption\",\n },\n Metric: {\n props: MetricSchema,\n hasChildren: false,\n description:\n \"Key metric display with label, value, and optional change indicator\",\n },\n Badge: {\n props: BadgeSchema,\n hasChildren: false,\n description: \"Inline status or category indicator with variant styling\",\n },\n Alert: {\n props: AlertSchema,\n hasChildren: false,\n description:\n \"Important message or warning with optional title and variant\",\n },\n Separator: {\n props: SeparatorSchema,\n hasChildren: false,\n description: \"Visual divider between sections\",\n },\n Code: {\n props: CodeSchema,\n hasChildren: false,\n description: \"Code block with optional syntax highlighting\",\n },\n },\n});\n\n// Export individual schemas for use in other parts of the application\nexport {\n CardSchema,\n ChartSchema,\n TextSchema,\n HeadingSchema,\n ListSchema,\n TableSchema,\n MetricSchema,\n BadgeSchema,\n AlertSchema,\n SeparatorSchema,\n CodeSchema,\n};\n\n// Export the catalog type for use in other modules\nexport type PhoenixInsightCatalog = typeof catalog;\n\n// Re-export useful types from json-render\nexport type { UITree, UIElement } from \"@json-render/core\";\n","import type { PhoenixClient } from \"@arizeai/phoenix-client\";\nimport type { ExecutionMode } from \"../modes/types.js\";\nimport { withErrorHandling } from \"./client.js\";\n\n/**\n * Converts an array of items to JSONL format (one JSON object per line)\n */\nfunction toJSONL(items: unknown[]): string {\n return items.map((item) => JSON.stringify(item)).join(\"\\n\");\n}\n\n/**\n * Fetches all projects and writes them to the filesystem\n * @param client - The Phoenix client instance\n * @param mode - The execution mode (sandbox or local)\n */\nexport async function fetchProjects(\n client: PhoenixClient,\n mode: ExecutionMode\n): Promise<void> {\n // Fetch all projects with error handling\n const projectsData = await withErrorHandling(async () => {\n const response = await client.GET(\"/v1/projects\", {\n params: {\n query: {\n include_experiment_projects: false,\n },\n },\n });\n\n if (!response.data) {\n throw new Error(\"No data returned from projects endpoint\");\n }\n\n return response.data;\n }, \"fetching projects\");\n\n // Extract projects from the response\n const projects = projectsData.data || [];\n\n // Write projects list as JSONL to /phoenix/projects/index.jsonl\n const projectsPath = \"/phoenix/projects/index.jsonl\";\n await mode.writeFile(projectsPath, toJSONL(projects));\n\n // For each project, create a metadata.json file\n for (const project of projects) {\n const projectDir = `/phoenix/projects/${project.name}`;\n const metadataPath = `${projectDir}/metadata.json`;\n\n // Write project metadata\n await mode.writeFile(metadataPath, JSON.stringify(project, null, 2));\n\n // Create empty spans directory (will be populated by snapshot-spans task)\n const spansDir = `${projectDir}/spans`;\n // Create directory by writing a placeholder that will be overwritten later\n await mode.writeFile(`${spansDir}/.gitkeep`, \"\");\n }\n}\n","import type { PhoenixClient } from \"@arizeai/phoenix-client\";\nimport type { ExecutionMode } from \"../modes/types.js\";\nimport { withErrorHandling } from \"./client.js\";\n\nexport interface SnapshotSpansOptions {\n /** Inclusive lower bound time for filtering spans */\n startTime?: Date | string | null;\n /** Exclusive upper bound time for filtering spans */\n endTime?: Date | string | null;\n /** Maximum number of spans to fetch per project (default: 1000) */\n spansPerProject?: number;\n /** Enable debug logging (default: uses DEBUG env var) */\n debug?: boolean;\n}\n\n/**\n * Debug logger that respects the debug flag or DEBUG environment variable\n */\nfunction createDebugLogger(debug?: boolean) {\n const isDebugEnabled = debug ?? !!process.env.DEBUG;\n return {\n log: (message: string) => {\n if (isDebugEnabled) {\n console.log(`[snapshotSpans] ${message}`);\n }\n },\n };\n}\n\ninterface SpanData {\n id: string;\n name: string;\n context: {\n trace_id: string;\n span_id: string;\n };\n span_kind: string;\n parent_id: string | null;\n start_time: string;\n end_time: string;\n status_code: string;\n status_message: string;\n attributes: Record<string, unknown>;\n events: Array<unknown>;\n}\n\ninterface ProjectMetadata {\n name: string;\n}\n\n/**\n * Fetches spans for all projects and writes them to the snapshot\n *\n * @param client - Phoenix client instance\n * @param mode - Execution mode for file operations\n * @param options - Options for filtering and limiting spans\n */\nexport async function snapshotSpans(\n client: PhoenixClient,\n mode: ExecutionMode,\n options: SnapshotSpansOptions = {}\n): Promise<void> {\n const { startTime, endTime, spansPerProject = 1000, debug } = options;\n const logger = createDebugLogger(debug);\n\n // Read projects index to get project names\n // Use relative path so it works with the cwd set by the execution mode\n logger.log(\"Reading projects index from projects/index.jsonl\");\n const projectsIndexContent = await mode.exec(\"cat projects/index.jsonl\");\n if (!projectsIndexContent.stdout) {\n // No projects, nothing to do\n logger.log(\"No projects found in index, skipping span fetch\");\n return;\n }\n\n const projectNames = projectsIndexContent.stdout\n .trim()\n .split(\"\\n\")\n .filter((line) => line.length > 0)\n .map((line) => {\n const project = JSON.parse(line) as ProjectMetadata;\n return project.name;\n });\n\n logger.log(`Found ${projectNames.length} project(s): ${projectNames.join(\", \")}`);\n\n // Fetch spans for each project\n for (const projectName of projectNames) {\n await withErrorHandling(async () => {\n logger.log(`Starting span fetch for project: ${projectName}`);\n const spans: SpanData[] = [];\n let cursor: string | null = null;\n let totalFetched = 0;\n\n // Paginate through spans until we reach the limit or no more data\n while (totalFetched < spansPerProject) {\n const query: Record<string, any> = {\n limit: Math.min(100, spansPerProject - totalFetched), // Fetch in chunks of 100\n };\n\n if (cursor) {\n query.cursor = cursor;\n }\n\n if (startTime) {\n query.start_time =\n startTime instanceof Date ? startTime.toISOString() : startTime;\n }\n\n if (endTime) {\n query.end_time =\n endTime instanceof Date ? endTime.toISOString() : endTime;\n }\n\n const response = await client.GET(\n \"/v1/projects/{project_identifier}/spans\",\n {\n params: {\n path: {\n project_identifier: projectName,\n },\n query,\n },\n }\n );\n\n if (response.error) throw response.error;\n\n const data = response.data?.data ?? [];\n spans.push(...(data as SpanData[]));\n totalFetched += data.length;\n\n cursor = response.data?.next_cursor ?? null;\n\n // Stop if there's no more data\n if (!cursor || data.length === 0) {\n break;\n }\n }\n\n logger.log(`Completed span fetch for project ${projectName}: ${spans.length} span(s) fetched`);\n\n // Write spans to JSONL file\n const spansFilePath = `/phoenix/projects/${projectName}/spans/index.jsonl`;\n logger.log(`Writing spans to ${spansFilePath}`);\n const jsonlContent = spans.map((span) => JSON.stringify(span)).join(\"\\n\");\n await mode.writeFile(spansFilePath, jsonlContent);\n\n // Write metadata about the spans snapshot\n const metadataFilePath = `/phoenix/projects/${projectName}/spans/metadata.json`;\n logger.log(`Writing metadata to ${metadataFilePath}`);\n const metadata = {\n project: projectName,\n spanCount: spans.length,\n startTime: startTime || null,\n endTime: endTime || null,\n snapshotTime: new Date().toISOString(),\n };\n\n await mode.writeFile(metadataFilePath, JSON.stringify(metadata, null, 2));\n }, `fetching spans for project ${projectName}`);\n }\n}\n","import type { PhoenixClient } from \"@arizeai/phoenix-client\";\nimport type { ExecutionMode } from \"../modes/types.js\";\nimport { withErrorHandling, extractData } from \"./client.js\";\n\ninterface Dataset {\n id: string;\n name: string;\n description: string | null;\n metadata: Record<string, unknown>;\n created_at: string;\n updated_at: string;\n}\n\ninterface DatasetExample {\n id: string;\n input: Record<string, unknown>;\n output: Record<string, unknown>;\n metadata: Record<string, unknown>;\n updated_at: string;\n}\n\ninterface FetchDatasetsOptions {\n limit?: number;\n}\n\n/**\n * Converts an array to JSONL format\n */\nfunction toJSONL(items: unknown[]): string {\n if (items.length === 0) {\n return \"\";\n }\n return items.map((item) => JSON.stringify(item)).join(\"\\n\");\n}\n\n/**\n * Fetches all datasets and their examples from Phoenix\n */\nexport async function fetchDatasets(\n client: PhoenixClient,\n mode: ExecutionMode,\n options: FetchDatasetsOptions = {}\n): Promise<void> {\n const { limit = 100 } = options;\n\n // Fetch all datasets with pagination\n const datasets: Dataset[] = [];\n let cursor: string | null = null;\n\n while (datasets.length < limit) {\n const query: Record<string, unknown> = {\n limit: Math.min(limit - datasets.length, 100),\n };\n if (cursor) {\n query.cursor = cursor;\n }\n\n const response = await withErrorHandling(\n () => client.GET(\"/v1/datasets\", { params: { query } }),\n \"fetching datasets\"\n );\n\n const data = extractData(response);\n datasets.push(...data.data);\n cursor = data.next_cursor;\n\n // Stop if no more data\n if (!cursor || data.data.length === 0) {\n break;\n }\n }\n\n // Write datasets index\n await mode.writeFile(\"/phoenix/datasets/index.jsonl\", toJSONL(datasets));\n\n // Fetch examples for each dataset\n for (const dataset of datasets) {\n // Write dataset metadata\n await mode.writeFile(\n `/phoenix/datasets/${dataset.name}/metadata.json`,\n JSON.stringify(\n {\n id: dataset.id,\n name: dataset.name,\n description: dataset.description,\n metadata: dataset.metadata,\n created_at: dataset.created_at,\n updated_at: dataset.updated_at,\n snapshot_timestamp: new Date().toISOString(),\n },\n null,\n 2\n )\n );\n\n // Fetch examples for this dataset\n const examplesResponse = await withErrorHandling(\n () =>\n client.GET(\"/v1/datasets/{id}/examples\", {\n params: {\n path: { id: dataset.id },\n },\n }),\n `fetching examples for dataset ${dataset.name}`\n );\n\n const examplesData = extractData(examplesResponse);\n const examples = examplesData.data.examples;\n\n // Write examples as JSONL\n await mode.writeFile(\n `/phoenix/datasets/${dataset.name}/examples.jsonl`,\n toJSONL(examples)\n );\n\n // Write dataset info with example count\n await mode.writeFile(\n `/phoenix/datasets/${dataset.name}/info.json`,\n JSON.stringify(\n {\n dataset_id: dataset.id,\n dataset_name: dataset.name,\n example_count: examples.length,\n version_id: examplesData.data.version_id,\n filtered_splits: examplesData.data.filtered_splits,\n },\n null,\n 2\n )\n );\n }\n}\n","import type { PhoenixClient } from \"@arizeai/phoenix-client\";\nimport type { ExecutionMode } from \"../modes/types.js\";\nimport { withErrorHandling, extractData } from \"./client.js\";\n\ninterface Dataset {\n id: string;\n name: string;\n}\n\ninterface Experiment {\n id: string;\n dataset_id: string;\n dataset_version_id: string;\n repetitions: number;\n metadata: Record<string, unknown>;\n project_name: string | null;\n created_at: string;\n updated_at: string;\n example_count: number;\n successful_run_count: number;\n failed_run_count: number;\n missing_run_count: number;\n}\n\ninterface ExperimentRun {\n id: string;\n experiment_id: string;\n dataset_example_id: string;\n start_time: string;\n end_time: string;\n output: unknown;\n error?: string | null;\n trace_id?: string | null;\n repetition_number?: number;\n}\n\ninterface FetchExperimentsOptions {\n /**\n * Maximum number of experiments to fetch per dataset\n */\n limit?: number;\n /**\n * Include experiment runs in the snapshot\n */\n includeRuns?: boolean;\n}\n\n/**\n * Converts an array to JSONL format\n */\nfunction toJSONL(items: unknown[]): string {\n if (items.length === 0) {\n return \"\";\n }\n return items.map((item) => JSON.stringify(item)).join(\"\\n\");\n}\n\n/**\n * Fetches all experiments and their runs from Phoenix\n * Note: Experiments are fetched per dataset since there's no direct \"all experiments\" endpoint\n */\nexport async function fetchExperiments(\n client: PhoenixClient,\n mode: ExecutionMode,\n options: FetchExperimentsOptions = {}\n): Promise<void> {\n const { limit = 100, includeRuns = true } = options;\n\n // First, we need to get all datasets to fetch their experiments\n const datasetsResponse = await withErrorHandling(\n () => client.GET(\"/v1/datasets\", { params: { query: { limit: 1000 } } }),\n \"fetching datasets for experiments\"\n );\n\n const datasetsData = extractData(datasetsResponse);\n const datasets: Dataset[] = datasetsData.data;\n\n // Collect all experiments from all datasets\n const allExperiments: Array<Experiment & { datasetName: string }> = [];\n\n for (const dataset of datasets) {\n try {\n // Fetch experiments for this dataset with pagination\n const experiments: Experiment[] = [];\n let cursor: string | null = null;\n\n do {\n const response = await withErrorHandling(\n () =>\n client.GET(\"/v1/datasets/{dataset_id}/experiments\", {\n params: {\n path: {\n dataset_id: dataset.id,\n },\n query: {\n cursor,\n limit: 50,\n },\n },\n }),\n `fetching experiments for dataset ${dataset.name}`\n );\n\n const data = extractData(response);\n experiments.push(...(data.data || []));\n cursor = data.next_cursor || null;\n\n // Stop if we've reached the overall limit\n if (allExperiments.length + experiments.length >= limit) {\n const remaining = limit - allExperiments.length;\n experiments.splice(remaining);\n cursor = null;\n }\n } while (cursor != null);\n\n // Add dataset name to each experiment for context\n const experimentsWithDatasetName = experiments.map((exp) => ({\n ...exp,\n datasetName: dataset.name,\n }));\n\n allExperiments.push(...experimentsWithDatasetName);\n\n // Apply limit if specified\n if (allExperiments.length >= limit) {\n break;\n }\n } catch (error) {\n // If fetching experiments for a dataset fails, log and continue\n console.warn(\n `Failed to fetch experiments for dataset ${dataset.name}:`,\n error\n );\n }\n }\n\n // Write experiments index\n await mode.writeFile(\n \"/phoenix/experiments/index.jsonl\",\n toJSONL(allExperiments)\n );\n\n // Fetch runs for each experiment if requested\n if (includeRuns) {\n for (const experiment of allExperiments) {\n try {\n // Write experiment metadata\n await mode.writeFile(\n `/phoenix/experiments/${experiment.id}/metadata.json`,\n JSON.stringify(\n {\n id: experiment.id,\n dataset_id: experiment.dataset_id,\n dataset_name: experiment.datasetName,\n dataset_version_id: experiment.dataset_version_id,\n repetitions: experiment.repetitions,\n metadata: experiment.metadata,\n project_name: experiment.project_name,\n created_at: experiment.created_at,\n updated_at: experiment.updated_at,\n example_count: experiment.example_count,\n successful_run_count: experiment.successful_run_count,\n failed_run_count: experiment.failed_run_count,\n missing_run_count: experiment.missing_run_count,\n snapshot_timestamp: new Date().toISOString(),\n },\n null,\n 2\n )\n );\n\n // Fetch runs for this experiment with pagination\n const runs: ExperimentRun[] = [];\n let cursor: string | null = null;\n\n do {\n const runsResponse = await withErrorHandling(\n () =>\n client.GET(\"/v1/experiments/{experiment_id}/runs\", {\n params: {\n path: {\n experiment_id: experiment.id,\n },\n query: {\n cursor,\n limit: 100,\n },\n },\n }),\n `fetching runs for experiment ${experiment.id}`\n );\n\n const runsData = extractData(runsResponse);\n runs.push(...(runsData.data || []));\n cursor = runsData.next_cursor || null;\n } while (cursor != null);\n\n // Write runs as JSONL\n await mode.writeFile(\n `/phoenix/experiments/${experiment.id}/runs.jsonl`,\n toJSONL(runs)\n );\n\n // Write experiment summary with run stats\n await mode.writeFile(\n `/phoenix/experiments/${experiment.id}/summary.json`,\n JSON.stringify(\n {\n experiment_id: experiment.id,\n dataset_name: experiment.datasetName,\n project_name: experiment.project_name,\n total_runs: runs.length,\n successful_runs: experiment.successful_run_count,\n failed_runs: experiment.failed_run_count,\n missing_runs: experiment.missing_run_count,\n created_at: experiment.created_at,\n updated_at: experiment.updated_at,\n },\n null,\n 2\n )\n );\n } catch (error) {\n // If fetching runs for an experiment fails, log and continue\n console.warn(\n `Failed to fetch runs for experiment ${experiment.id}:`,\n error\n );\n\n // Still create the experiment metadata without runs\n await mode.writeFile(\n `/phoenix/experiments/${experiment.id}/metadata.json`,\n JSON.stringify(\n {\n ...experiment,\n error: \"Failed to fetch runs\",\n snapshot_timestamp: new Date().toISOString(),\n },\n null,\n 2\n )\n );\n }\n }\n }\n}\n","import type { PhoenixClient } from \"@arizeai/phoenix-client\";\nimport type { ExecutionMode } from \"../modes/types.js\";\nimport { withErrorHandling, extractData } from \"./client.js\";\n\ninterface FetchPromptsOptions {\n limit?: number;\n}\n\n/**\n * Converts an array to JSONL format\n */\nfunction toJSONL(items: unknown[]): string {\n if (items.length === 0) {\n return \"\";\n }\n return items.map((item) => JSON.stringify(item)).join(\"\\n\");\n}\n\n/**\n * Converts a prompt template to markdown format\n */\nfunction templateToMarkdown(template: any, templateFormat: string): string {\n // Handle string template\n if (templateFormat === \"STRING\") {\n if (typeof template === \"string\") {\n return template;\n }\n // It might be wrapped in an object with type\n if (template?.template && typeof template.template === \"string\") {\n return template.template;\n }\n return JSON.stringify(template, null, 2);\n }\n\n // Handle chat template\n const messages = template?.messages || [];\n const lines: string[] = [\"# Chat Template\", \"\"];\n\n for (const message of messages) {\n lines.push(`## ${message.role}`);\n lines.push(\"\");\n\n if (typeof message.content === \"string\") {\n lines.push(message.content);\n } else if (Array.isArray(message.content)) {\n // Handle multi-part content\n for (const part of message.content) {\n if (part.type === \"text\" && part.text) {\n lines.push(part.text);\n } else {\n // For non-text parts, show as JSON\n lines.push(\"```json\");\n lines.push(JSON.stringify(part, null, 2));\n lines.push(\"```\");\n }\n }\n } else {\n // If content is not string or array, show as JSON\n lines.push(\"```json\");\n lines.push(JSON.stringify(message.content, null, 2));\n lines.push(\"```\");\n }\n lines.push(\"\");\n }\n\n return lines.join(\"\\n\");\n}\n\n/**\n * Creates a markdown representation of a prompt version\n */\nfunction createVersionMarkdown(version: any): string {\n const lines: string[] = [];\n\n // Add metadata header\n lines.push(\"---\");\n lines.push(`id: ${version.id}`);\n if (version.model_name) lines.push(`model_name: ${version.model_name}`);\n if (version.model_provider)\n lines.push(`model_provider: ${version.model_provider}`);\n if (version.template_format)\n lines.push(`template_format: ${version.template_format}`);\n if (version.description) lines.push(`description: ${version.description}`);\n lines.push(\"---\");\n lines.push(\"\");\n\n // Add template content\n if (version.template) {\n lines.push(\n templateToMarkdown(version.template, version.template_format || \"STRING\")\n );\n lines.push(\"\");\n }\n\n // Add invocation parameters if present\n if (version.invocation_parameters) {\n lines.push(\"## Invocation Parameters\");\n lines.push(\"\");\n lines.push(\"```json\");\n lines.push(JSON.stringify(version.invocation_parameters, null, 2));\n lines.push(\"```\");\n lines.push(\"\");\n }\n\n // Add tools if present\n if (version.tools) {\n lines.push(\"## Tools\");\n lines.push(\"\");\n lines.push(\"```json\");\n lines.push(JSON.stringify(version.tools, null, 2));\n lines.push(\"```\");\n lines.push(\"\");\n }\n\n // Add response format if present\n if (version.response_format) {\n lines.push(\"## Response Format\");\n lines.push(\"\");\n lines.push(\"```json\");\n lines.push(JSON.stringify(version.response_format, null, 2));\n lines.push(\"```\");\n lines.push(\"\");\n }\n\n return lines.join(\"\\n\");\n}\n\n/**\n * Fetches all prompts and their versions from Phoenix\n */\nexport async function fetchPrompts(\n client: PhoenixClient,\n mode: ExecutionMode,\n options: FetchPromptsOptions = {}\n): Promise<void> {\n const { limit = 100 } = options;\n\n // Fetch all prompts with pagination\n const prompts: any[] = [];\n let cursor: string | null = null;\n\n while (prompts.length < limit) {\n const query: Record<string, unknown> = {\n limit: Math.min(limit - prompts.length, 100),\n };\n if (cursor) {\n query.cursor = cursor;\n }\n\n const response = await withErrorHandling(\n () => client.GET(\"/v1/prompts\", { params: { query } }),\n \"fetching prompts\"\n );\n\n const data = extractData(response);\n prompts.push(...data.data);\n cursor = data.next_cursor;\n\n // Stop if no more data\n if (!cursor || data.data.length === 0) {\n break;\n }\n }\n\n // Write prompts index\n await mode.writeFile(\"/phoenix/prompts/index.jsonl\", toJSONL(prompts));\n\n // Fetch versions for each prompt\n for (const prompt of prompts) {\n const safePromptName = prompt.name.replace(/[^a-zA-Z0-9-_]/g, \"_\");\n\n // Write prompt metadata\n await mode.writeFile(\n `/phoenix/prompts/${safePromptName}/metadata.json`,\n JSON.stringify(\n {\n id: prompt.id,\n name: prompt.name,\n description: prompt.description || null,\n metadata: prompt.metadata || {},\n source_prompt_id: prompt.source_prompt_id || null,\n snapshot_timestamp: new Date().toISOString(),\n },\n null,\n 2\n )\n );\n\n // Fetch all versions for this prompt\n const versions: any[] = [];\n let versionCursor: string | null = null;\n\n while (true) {\n const versionQuery: Record<string, unknown> = {\n limit: 100,\n };\n if (versionCursor) {\n versionQuery.cursor = versionCursor;\n }\n\n const versionsResponse = await withErrorHandling(\n () =>\n client.GET(\"/v1/prompts/{prompt_identifier}/versions\", {\n params: {\n path: { prompt_identifier: prompt.id },\n query: versionQuery,\n },\n }),\n `fetching versions for prompt ${prompt.name}`\n );\n\n const versionsData = extractData(versionsResponse);\n versions.push(...versionsData.data);\n versionCursor = versionsData.next_cursor;\n\n // Stop if no more data\n if (!versionCursor || versionsData.data.length === 0) {\n break;\n }\n }\n\n // Write versions index as JSONL\n await mode.writeFile(\n `/phoenix/prompts/${safePromptName}/versions/index.jsonl`,\n toJSONL(versions)\n );\n\n // Write each version as markdown\n for (const version of versions) {\n const versionId = version.id.replace(/[^a-zA-Z0-9-_]/g, \"_\");\n const markdownContent = createVersionMarkdown(version);\n\n await mode.writeFile(\n `/phoenix/prompts/${safePromptName}/versions/${versionId}.md`,\n markdownContent\n );\n }\n\n // Fetch and save the latest version separately for convenience\n try {\n const latestResponse = await withErrorHandling(\n () =>\n client.GET(\"/v1/prompts/{prompt_identifier}/latest\", {\n params: {\n path: { prompt_identifier: prompt.id },\n },\n }),\n `fetching latest version for prompt ${prompt.name}`\n );\n\n const latestData = extractData(latestResponse);\n if (latestData.data) {\n const latestMarkdownContent = createVersionMarkdown(latestData.data);\n\n await mode.writeFile(\n `/phoenix/prompts/${safePromptName}/latest.md`,\n latestMarkdownContent\n );\n }\n } catch (error) {\n // If there's no latest version, that's okay - just skip it\n console.warn(\n `No latest version available for prompt ${prompt.name}: ${error instanceof Error ? error.message : String(error)}`\n );\n }\n }\n}\n","import type { ExecutionMode } from \"../modes/types.js\";\n\ninterface ContextMetadata {\n phoenixUrl: string;\n snapshotTime: Date;\n spansPerProject?: number;\n}\n\ninterface ProjectStats {\n name: string;\n spanCount: number;\n hasErrors?: boolean;\n recentSpans?: number;\n}\n\ninterface DatasetInfo {\n name: string;\n exampleCount: number;\n updatedAt?: string;\n}\n\ninterface ExperimentInfo {\n id: string;\n datasetName: string;\n projectName?: string;\n status: \"completed\" | \"in_progress\" | \"failed\";\n runCounts: {\n successful: number;\n failed: number;\n missing: number;\n };\n updatedAt?: string;\n}\n\ninterface PromptInfo {\n name: string;\n versionCount: number;\n latestVersion?: string;\n updatedAt?: string;\n}\n\n// =============================================================================\n// Static Section Templates\n// =============================================================================\n\n/**\n * Quick Start section for external agents - appears at the top for discoverability\n */\nconst QUICK_START_SECTION = `## Quick Start for External Agents\n\nThis is a **read-only snapshot** of Phoenix observability data. You cannot modify this data.\n\n### Key Files to Start With\n\n| File | Description |\n|------|-------------|\n| \\`/phoenix/projects/index.jsonl\\` | List of all projects with traces |\n| \\`/phoenix/datasets/index.jsonl\\` | List of all datasets |\n| \\`/phoenix/experiments/index.jsonl\\` | List of all experiments |\n| \\`/phoenix/prompts/index.jsonl\\` | List of all prompts |\n\n### How to Parse Each File Format\n\n**JSONL files** (\\`.jsonl\\`): One JSON object per line\n\\`\\`\\`bash\n# Read all lines as a JSON array\ncat /phoenix/projects/index.jsonl | jq -s '.'\n\n# Process each line individually\nwhile read -r line; do echo \"$line\" | jq '.name'; done < /phoenix/projects/index.jsonl\n\n# Get first N items\nhead -n 5 /phoenix/projects/index.jsonl | jq -s '.'\n\\`\\`\\`\n\n**JSON files** (\\`.json\\`): Standard JSON format\n\\`\\`\\`bash\n# Read and pretty-print\ncat /phoenix/projects/my-project/metadata.json | jq '.'\n\n# Extract specific field\ncat /phoenix/projects/my-project/metadata.json | jq '.name'\n\\`\\`\\`\n\n**Markdown files** (\\`.md\\`): Plain text prompt templates\n\\`\\`\\`bash\n# Read prompt template\ncat /phoenix/prompts/my-prompt/versions/v1.md\n\\`\\`\\`\n\n### Common Operations\n\n\\`\\`\\`bash\n# List all project names\ncat /phoenix/projects/index.jsonl | jq -r '.name'\n\n# Count spans in a project\nwc -l < /phoenix/projects/my-project/spans/index.jsonl\n\n# Find spans with errors\ncat /phoenix/projects/my-project/spans/index.jsonl | jq 'select(.status_code == \"ERROR\")'\n\n# Get dataset examples\ncat /phoenix/datasets/my-dataset/examples.jsonl | jq -s '.' | head -n 100\n\n# Search across all files\ngrep -r \"error\" /phoenix/\n\\`\\`\\``;\n\n/**\n * Directory Structure section showing the snapshot layout\n */\nconst DIRECTORY_STRUCTURE_SECTION = `## Directory Structure\n\n\\`\\`\\`\n/phoenix/\n _context.md # This file - start here!\n /projects/\n index.jsonl # List of all projects\n /{project_name}/\n metadata.json # Project details\n /spans/\n index.jsonl # Span data (may be sampled)\n metadata.json # Span snapshot metadata\n /datasets/\n index.jsonl # List of all datasets\n /{dataset_name}/\n metadata.json # Dataset details\n examples.jsonl # Dataset examples\n /experiments/\n index.jsonl # List of all experiments\n /{experiment_id}/\n metadata.json # Experiment details\n runs.jsonl # Experiment runs\n /prompts/\n index.jsonl # List of all prompts\n /{prompt_name}/\n metadata.json # Prompt details\n /versions/\n index.jsonl # Version list\n /{version_id}.md # Version template\n /_meta/\n snapshot.json # Snapshot metadata\n\\`\\`\\``;\n\n/**\n * What You Can Do section describing available operations\n */\nconst WHAT_YOU_CAN_DO_SECTION = `## What You Can Do\n\n- **Explore**: ls, cat, grep, find, jq, awk, sed\n- **Fetch more data**: \\`px-fetch-more spans --project <name> --limit 500\\`\n- **Fetch specific trace**: \\`px-fetch-more trace --trace-id <id>\\``;\n\n/**\n * Data Freshness section with refresh instructions\n */\nconst DATA_FRESHNESS_SECTION = `## Data Freshness\n\nThis is a **read-only snapshot**. Data may have changed since capture.\nRun with \\`--refresh\\` to get latest data.`;\n\n// =============================================================================\n// Main Context Generation\n// =============================================================================\n\n/**\n * Generates a _context.md summary file for the Phoenix snapshot\n * This provides human and agent-readable context about what data is available\n */\nexport async function generateContext(\n mode: ExecutionMode,\n metadata: ContextMetadata\n): Promise<void> {\n // Collect stats from the snapshot\n const stats = await collectSnapshotStats(mode);\n\n // Build the dynamic \"What's Here\" section\n const whatsHereSection = buildWhatsHereSection(stats, metadata);\n\n // Build the dynamic \"Recent Activity\" section (may be empty)\n const recentActivitySection = buildRecentActivitySection(stats);\n\n // Compose the full context document\n const content = [\n \"# Phoenix Snapshot Context\",\n \"\",\n QUICK_START_SECTION,\n \"\",\n whatsHereSection,\n recentActivitySection,\n DIRECTORY_STRUCTURE_SECTION,\n \"\",\n WHAT_YOU_CAN_DO_SECTION,\n \"\",\n DATA_FRESHNESS_SECTION,\n ].join(\"\\n\");\n\n // Write the context file\n await mode.writeFile(\"/phoenix/_context.md\", content);\n}\n\n// =============================================================================\n// Dynamic Section Builders\n// =============================================================================\n\n/**\n * Builds the \"What's Here\" section with project/dataset/experiment/prompt summaries\n */\nfunction buildWhatsHereSection(\n stats: {\n projects: ProjectStats[];\n datasets: DatasetInfo[];\n experiments: ExperimentInfo[];\n prompts: PromptInfo[];\n },\n metadata: ContextMetadata\n): string {\n const lines: string[] = [];\n\n lines.push(\"## What's Here\");\n lines.push(\"\");\n\n // Projects summary\n if (stats.projects.length > 0) {\n const projectSummary = stats.projects\n .map((p) => `${p.name} (${p.spanCount} spans)`)\n .join(\", \");\n lines.push(`- **${stats.projects.length} projects**: ${projectSummary}`);\n } else {\n lines.push(\"- **No projects found**\");\n }\n\n // Datasets summary\n if (stats.datasets.length > 0) {\n const datasetNames = stats.datasets.map((d) => d.name).join(\", \");\n lines.push(`- **${stats.datasets.length} datasets**: ${datasetNames}`);\n } else {\n lines.push(\"- **No datasets found**\");\n }\n\n // Experiments summary\n if (stats.experiments.length > 0) {\n const completedCount = stats.experiments.filter(\n (e) => e.status === \"completed\"\n ).length;\n const inProgressCount = stats.experiments.filter(\n (e) => e.status === \"in_progress\"\n ).length;\n const failedCount = stats.experiments.filter(\n (e) => e.status === \"failed\"\n ).length;\n\n const parts: string[] = [];\n if (completedCount > 0) parts.push(`${completedCount} completed`);\n if (inProgressCount > 0) parts.push(`${inProgressCount} in progress`);\n if (failedCount > 0) parts.push(`${failedCount} failed`);\n\n lines.push(\n `- **${stats.experiments.length} experiments**: ${parts.join(\", \")}`\n );\n } else {\n lines.push(\"- **No experiments found**\");\n }\n\n // Prompts summary\n if (stats.prompts.length > 0) {\n const promptNames = stats.prompts.map((p) => p.name).join(\", \");\n lines.push(`- **${stats.prompts.length} prompts**: ${promptNames}`);\n } else {\n lines.push(\"- **No prompts found**\");\n }\n\n // Snapshot metadata\n lines.push(\n `- **Snapshot**: Created ${formatRelativeTime(\n metadata.snapshotTime\n )} from ${metadata.phoenixUrl}`\n );\n lines.push(\"\");\n\n return lines.join(\"\\n\");\n}\n\n/**\n * Builds the \"Recent Activity\" section if there are recent updates\n * Returns an empty string if no recent activity\n */\nfunction buildRecentActivitySection(stats: {\n projects: ProjectStats[];\n datasets: DatasetInfo[];\n experiments: ExperimentInfo[];\n prompts: PromptInfo[];\n}): string {\n const activities = getRecentActivity(stats);\n\n if (activities.length === 0) {\n return \"\";\n }\n\n const lines: string[] = [];\n lines.push(\"## Recent Activity\");\n lines.push(\"\");\n for (const activity of activities) {\n lines.push(`- ${activity}`);\n }\n lines.push(\"\");\n\n return lines.join(\"\\n\");\n}\n\n// =============================================================================\n// Data Collection\n// =============================================================================\n\n/**\n * Collects statistics from the snapshot filesystem\n */\nasync function collectSnapshotStats(mode: ExecutionMode): Promise<{\n projects: ProjectStats[];\n datasets: DatasetInfo[];\n experiments: ExperimentInfo[];\n prompts: PromptInfo[];\n}> {\n const result = {\n projects: [] as ProjectStats[],\n datasets: [] as DatasetInfo[],\n experiments: [] as ExperimentInfo[],\n prompts: [] as PromptInfo[],\n };\n\n // Collect project stats\n // Use relative paths since cwd is the phoenix directory in both modes\n try {\n const projectsExec = await mode.exec(\n \"cat projects/index.jsonl 2>/dev/null || true\"\n );\n if (projectsExec.stdout) {\n const projectLines = projectsExec.stdout\n .trim()\n .split(\"\\n\")\n .filter((line) => line.length > 0);\n\n for (const line of projectLines) {\n try {\n const project = JSON.parse(line);\n const stats: ProjectStats = {\n name: project.name,\n spanCount: 0,\n };\n\n // Get span count for this project\n const spansMetaExec = await mode.exec(\n `cat projects/${project.name}/spans/metadata.json 2>/dev/null || echo \"{}\"`\n );\n if (spansMetaExec.stdout) {\n try {\n const spansMeta = JSON.parse(spansMetaExec.stdout);\n stats.spanCount = spansMeta.spanCount || 0;\n } catch (e) {\n // Ignore parse errors\n }\n }\n\n result.projects.push(stats);\n } catch (e) {\n // Skip invalid project lines\n }\n }\n }\n } catch (e) {\n // No projects file\n }\n\n // Collect dataset stats\n try {\n const datasetsExec = await mode.exec(\n \"cat datasets/index.jsonl 2>/dev/null || true\"\n );\n if (datasetsExec.stdout) {\n const datasetLines = datasetsExec.stdout\n .trim()\n .split(\"\\n\")\n .filter((line) => line.length > 0);\n\n for (const line of datasetLines) {\n try {\n const dataset = JSON.parse(line);\n\n // Get example count\n const examplesExec = await mode.exec(\n `wc -l < datasets/${dataset.name}/examples.jsonl 2>/dev/null || echo \"0\"`\n );\n const exampleCount = parseInt(examplesExec.stdout.trim()) || 0;\n\n result.datasets.push({\n name: dataset.name,\n exampleCount,\n updatedAt: dataset.updated_at,\n });\n } catch (e) {\n // Skip invalid dataset lines\n }\n }\n }\n } catch (e) {\n // No datasets file\n }\n\n // Collect experiment stats\n try {\n const experimentsExec = await mode.exec(\n \"cat experiments/index.jsonl 2>/dev/null || true\"\n );\n if (experimentsExec.stdout) {\n const experimentLines = experimentsExec.stdout\n .trim()\n .split(\"\\n\")\n .filter((line) => line.length > 0);\n\n for (const line of experimentLines) {\n try {\n const experiment = JSON.parse(line);\n const status = determineExperimentStatus(experiment);\n\n result.experiments.push({\n id: experiment.id,\n datasetName: experiment.datasetName || \"unknown\",\n projectName: experiment.project_name,\n status,\n runCounts: {\n successful: experiment.successful_run_count || 0,\n failed: experiment.failed_run_count || 0,\n missing: experiment.missing_run_count || 0,\n },\n updatedAt: experiment.updated_at,\n });\n } catch (e) {\n // Skip invalid experiment lines\n }\n }\n }\n } catch (e) {\n // No experiments file\n }\n\n // Collect prompt stats\n try {\n const promptsExec = await mode.exec(\n \"cat prompts/index.jsonl 2>/dev/null || true\"\n );\n if (promptsExec.stdout) {\n const promptLines = promptsExec.stdout\n .trim()\n .split(\"\\n\")\n .filter((line) => line.length > 0);\n\n for (const line of promptLines) {\n try {\n const prompt = JSON.parse(line);\n\n // Count versions\n const versionsExec = await mode.exec(\n `wc -l < prompts/${prompt.name}/versions/index.jsonl 2>/dev/null || echo \"0\"`\n );\n const versionCount = parseInt(versionsExec.stdout.trim()) || 0;\n\n result.prompts.push({\n name: prompt.name,\n versionCount,\n updatedAt: prompt.updated_at,\n });\n } catch (e) {\n // Skip invalid prompt lines\n }\n }\n }\n } catch (e) {\n // No prompts file\n }\n\n return result;\n}\n\n// =============================================================================\n// Helper Functions\n// =============================================================================\n\n/**\n * Determines the status of an experiment based on its run counts\n */\nfunction determineExperimentStatus(\n experiment: any\n): \"completed\" | \"in_progress\" | \"failed\" {\n const totalExpected = experiment.example_count * experiment.repetitions;\n const totalRuns =\n (experiment.successful_run_count || 0) + (experiment.failed_run_count || 0);\n\n if (totalRuns === 0) {\n return \"in_progress\";\n }\n\n // If most runs are failed, consider it failed\n if (\n (experiment.failed_run_count || 0) > (experiment.successful_run_count || 0)\n ) {\n return \"failed\";\n }\n\n if (totalRuns >= totalExpected) {\n return \"completed\";\n }\n\n return \"in_progress\";\n}\n\n/**\n * Gets recent activity highlights\n */\nfunction getRecentActivity(stats: {\n projects: ProjectStats[];\n datasets: DatasetInfo[];\n experiments: ExperimentInfo[];\n prompts: PromptInfo[];\n}): string[] {\n const activities: string[] = [];\n\n // Find recently updated experiments\n const recentExperiments = stats.experiments\n .filter((e) => e.updatedAt && isRecent(new Date(e.updatedAt), 24))\n .sort(\n (a, b) =>\n new Date(b.updatedAt!).getTime() - new Date(a.updatedAt!).getTime()\n );\n\n for (const exp of recentExperiments.slice(0, 2)) {\n const timeAgo = formatRelativeTime(new Date(exp.updatedAt!));\n activities.push(\n `${exp.projectName || exp.datasetName}: experiment \"${exp.id.slice(\n 0,\n 8\n )}...\" ${exp.status} ${timeAgo}`\n );\n }\n\n // Find recently updated datasets\n const recentDatasets = stats.datasets\n .filter((d) => d.updatedAt && isRecent(new Date(d.updatedAt), 24))\n .sort(\n (a, b) =>\n new Date(b.updatedAt!).getTime() - new Date(a.updatedAt!).getTime()\n );\n\n for (const dataset of recentDatasets.slice(0, 2)) {\n const timeAgo = formatRelativeTime(new Date(dataset.updatedAt!));\n activities.push(\n `${dataset.name}: dataset updated ${timeAgo} (${dataset.exampleCount} examples)`\n );\n }\n\n return activities.slice(0, 3); // Limit to 3 activities\n}\n\n/**\n * Checks if a date is within the specified hours from now\n */\nfunction isRecent(date: Date, hoursAgo: number): boolean {\n const now = new Date();\n const diff = now.getTime() - date.getTime();\n return diff < hoursAgo * 60 * 60 * 1000;\n}\n\n/**\n * Formats a date as relative time (e.g., \"2 hours ago\")\n */\nfunction formatRelativeTime(date: Date): string {\n const now = new Date();\n const diff = now.getTime() - date.getTime();\n\n const minutes = Math.floor(diff / (1000 * 60));\n const hours = Math.floor(diff / (1000 * 60 * 60));\n const days = Math.floor(diff / (1000 * 60 * 60 * 24));\n\n if (minutes < 1) {\n return \"just now\";\n } else if (minutes < 60) {\n return `${minutes} minute${minutes !== 1 ? \"s\" : \"\"} ago`;\n } else if (hours < 24) {\n return `${hours} hour${hours !== 1 ? \"s\" : \"\"} ago`;\n } else {\n return `${days} day${days !== 1 ? \"s\" : \"\"} ago`;\n }\n}\n","/**\n * Progress indicators for Phoenix Insight CLI\n */\nimport ora, { type Ora } from \"ora\";\n\n/**\n * Progress indicator for snapshot operations\n */\nexport class SnapshotProgress {\n private spinner: Ora | null = null;\n private enabled: boolean;\n private currentPhase: string | null = null;\n private totalSteps = 6;\n private currentStep = 0;\n\n constructor(enabled: boolean = true) {\n this.enabled = enabled;\n }\n\n /**\n * Start the progress indicator\n */\n start(message: string = \"Creating Phoenix data snapshot\") {\n if (!this.enabled) return;\n\n this.currentStep = 0;\n this.spinner = ora({\n text: message,\n spinner: \"dots\",\n color: \"blue\",\n }).start();\n }\n\n /**\n * Update progress with a new phase\n */\n update(phase: string, detail?: string) {\n if (!this.enabled || !this.spinner) return;\n\n this.currentStep++;\n this.currentPhase = phase;\n\n const progress = Math.round((this.currentStep / this.totalSteps) * 100);\n const progressBar = this.createProgressBar(progress);\n\n const message = detail\n ? `${progressBar} ${phase}: ${detail}`\n : `${progressBar} ${phase}`;\n\n this.spinner.text = message;\n }\n\n /**\n * Complete a phase successfully\n */\n succeed(message?: string) {\n if (!this.enabled || !this.spinner) return;\n\n const finalMessage =\n message || `✓ ${this.currentPhase || \"Snapshot\"} complete`;\n this.spinner.succeed(finalMessage);\n this.spinner = null;\n }\n\n /**\n * Fail with an error\n */\n fail(message?: string) {\n if (!this.enabled || !this.spinner) return;\n\n const finalMessage =\n message || `✗ ${this.currentPhase || \"Snapshot\"} failed`;\n this.spinner.fail(finalMessage);\n this.spinner = null;\n }\n\n /**\n * Stop without success/fail status\n */\n stop() {\n if (!this.enabled || !this.spinner) return;\n\n this.spinner.stop();\n this.spinner = null;\n }\n\n /**\n * Create a progress bar string\n */\n private createProgressBar(percentage: number): string {\n const width = 20;\n const filled = Math.round((percentage / 100) * width);\n const empty = width - filled;\n\n const bar = \"█\".repeat(filled) + \"░\".repeat(empty);\n return `[${bar}] ${percentage}%`;\n }\n}\n\n/**\n * Progress indicator for agent thinking\n */\nexport class AgentProgress {\n private spinner: Ora | null = null;\n private enabled: boolean;\n private stepCount = 0;\n private currentTool: string | null = null;\n\n constructor(enabled: boolean = true) {\n this.enabled = enabled;\n }\n\n /**\n * Start thinking indicator\n */\n startThinking() {\n if (!this.enabled) return;\n\n this.stepCount = 0;\n this.currentTool = null;\n this.spinner = ora({\n text: \"🤔 Analyzing...\",\n spinner: \"dots\",\n color: \"cyan\",\n }).start();\n }\n\n /**\n * Update with current tool usage\n */\n updateTool(toolName: string, detail?: string) {\n if (!this.enabled || !this.spinner) return;\n\n this.stepCount++;\n this.currentTool = toolName;\n\n // Map tool names to more user-friendly descriptions\n const friendlyNames: Record<string, string> = {\n bash: \"Running command\",\n px_fetch_more_spans: \"Fetching additional spans\",\n px_fetch_more_trace: \"Fetching trace details\",\n };\n\n const displayName = friendlyNames[toolName] || toolName;\n const message = detail\n ? `🔧 ${displayName}: ${detail}`\n : `🔧 ${displayName} (step ${this.stepCount})`;\n\n this.spinner.text = message;\n }\n\n /**\n * Update with tool result\n */\n updateToolResult(toolName: string, success: boolean = true) {\n if (!this.enabled || !this.spinner) return;\n\n const icon = success ? \"✓\" : \"✗\";\n const status = success ? \"completed\" : \"failed\";\n\n // More informative messages for each tool\n const toolMessages: Record<string, string> = {\n bash: \"Command executed\",\n px_fetch_more_spans: \"Additional spans fetched\",\n px_fetch_more_trace: \"Trace details fetched\",\n };\n\n const baseMessage = toolMessages[toolName] || `Tool ${toolName}`;\n const message = `${icon} ${baseMessage} ${status}`;\n\n // Brief flash of the result before moving on\n this.spinner.text = message;\n }\n\n /**\n * Show progress for a specific action\n */\n updateAction(action: string) {\n if (!this.enabled || !this.spinner) return;\n\n this.spinner.text = `🔍 ${action}...`;\n }\n\n /**\n * Stop the thinking indicator\n */\n stop() {\n if (!this.enabled || !this.spinner) return;\n\n this.spinner.stop();\n this.spinner = null;\n }\n\n /**\n * Complete with a success message\n */\n succeed(message: string = \"✨ Analysis complete\") {\n if (!this.enabled || !this.spinner) return;\n\n this.spinner.succeed(message);\n this.spinner = null;\n }\n}\n\n/**\n * Simple progress logger for when spinners aren't appropriate\n */\nexport class SimpleProgress {\n private enabled: boolean;\n\n constructor(enabled: boolean = true) {\n this.enabled = enabled;\n }\n\n log(message: string) {\n if (!this.enabled) return;\n console.log(`[Phoenix Insight] ${message}`);\n }\n\n info(message: string) {\n if (!this.enabled) return;\n console.log(`ℹ️ ${message}`);\n }\n\n success(message: string) {\n if (!this.enabled) return;\n console.log(`✅ ${message}`);\n }\n\n warning(message: string) {\n if (!this.enabled) return;\n console.log(`⚠️ ${message}`);\n }\n\n error(message: string) {\n if (!this.enabled) return;\n console.log(`❌ ${message}`);\n }\n}\n","// Export all snapshot modules\nexport {\n createPhoenixClient,\n PhoenixClientError,\n type PhoenixClientConfig,\n} from \"./client.js\";\nexport { fetchProjects } from \"./projects.js\";\nexport { snapshotSpans, type SnapshotSpansOptions } from \"./spans.js\";\nexport { fetchDatasets } from \"./datasets.js\";\nexport { fetchExperiments } from \"./experiments.js\";\nexport { fetchPrompts } from \"./prompts.js\";\nexport { generateContext } from \"./context.js\";\n\n// Import necessary types and modules for orchestration\nimport type { ExecutionMode } from \"../modes/types.js\";\nimport type { PhoenixClient } from \"@arizeai/phoenix-client\";\nimport {\n createPhoenixClient,\n PhoenixClientError,\n type PhoenixClientConfig,\n} from \"./client.js\";\nimport { fetchProjects } from \"./projects.js\";\nimport { snapshotSpans, type SnapshotSpansOptions } from \"./spans.js\";\nimport { fetchDatasets } from \"./datasets.js\";\nimport { fetchExperiments } from \"./experiments.js\";\nimport { fetchPrompts } from \"./prompts.js\";\nimport { generateContext } from \"./context.js\";\nimport { SnapshotProgress } from \"../progress.js\";\n\nexport interface SnapshotOptions {\n /**\n * Phoenix server base URL\n */\n baseURL: string;\n /**\n * Optional API key for authentication\n */\n apiKey?: string;\n /**\n * Maximum number of spans per project\n */\n spansPerProject?: number;\n /**\n * Time range filter for spans (ISO 8601 format)\n */\n startTime?: string;\n endTime?: string;\n /**\n * Whether to show progress indicators\n */\n showProgress?: boolean;\n}\n\nexport interface SnapshotMetadata {\n created_at: string;\n phoenix_url: string;\n cursors: {\n spans?: Record<string, { last_end_time?: string; cursor?: string }>;\n datasets?: { last_fetch: string };\n experiments?: { last_fetch: string };\n prompts?: { last_fetch: string };\n };\n limits: {\n spans_per_project: number;\n };\n}\n\n/**\n * Orchestrates all data fetchers to create a complete Phoenix snapshot\n * @param mode - The execution mode (sandbox or local)\n * @param options - Snapshot options including server URL and limits\n */\nexport async function createSnapshot(\n mode: ExecutionMode,\n options: SnapshotOptions\n): Promise<void> {\n const {\n baseURL,\n apiKey,\n spansPerProject = 1000,\n startTime,\n endTime,\n showProgress = false,\n } = options;\n\n // Create progress indicator\n const progress = new SnapshotProgress(showProgress);\n progress.start(\"Creating Phoenix data snapshot\");\n\n // Create Phoenix client\n const clientConfig: PhoenixClientConfig = {\n baseURL,\n apiKey,\n };\n const client = createPhoenixClient(clientConfig);\n\n try {\n // 1. Fetch projects first (required for spans)\n progress.update(\"Fetching projects\");\n try {\n await fetchProjects(client, mode);\n } catch (error) {\n progress.fail(\"Failed to fetch projects\");\n throw new PhoenixClientError(\n `Failed to fetch projects: ${error instanceof Error ? error.message : String(error)}`,\n error instanceof PhoenixClientError ? error.code : \"UNKNOWN_ERROR\",\n error\n );\n }\n\n // 2. Fetch spans and other data in parallel\n progress.update(\n \"Fetching all data\",\n \"spans, datasets, experiments, prompts\"\n );\n const spansOptions: SnapshotSpansOptions = {\n spansPerProject,\n startTime,\n endTime,\n };\n\n // Fetch all data types in parallel for better performance\n const results = await Promise.allSettled([\n snapshotSpans(client, mode, spansOptions),\n fetchDatasets(client, mode),\n fetchExperiments(client, mode),\n fetchPrompts(client, mode),\n ]);\n\n // Check for failures and collect errors\n const errors: Array<{ type: string; error: unknown }> = [];\n const dataTypes = [\"spans\", \"datasets\", \"experiments\", \"prompts\"];\n\n results.forEach((result, index) => {\n if (result.status === \"rejected\") {\n errors.push({\n type: dataTypes[index] || \"unknown\",\n error: result.reason,\n });\n }\n });\n\n if (errors.length > 0) {\n // Log individual errors\n errors.forEach(({ type, error }) => {\n console.error(\n `Warning: Failed to fetch ${type}:`,\n error instanceof Error ? error.message : String(error)\n );\n });\n\n // If spans failed, that's critical - throw error\n if (errors.some((e) => e.type === \"spans\")) {\n progress.fail(\"Failed to fetch spans\");\n throw new PhoenixClientError(\n `Failed to fetch spans: ${errors.find((e) => e.type === \"spans\")?.error}`,\n \"UNKNOWN_ERROR\",\n errors\n );\n }\n\n // If all other data failed, throw error. If partial success, continue with warning\n if (errors.length === 4) {\n progress.fail(\"Failed to fetch all data\");\n throw new PhoenixClientError(\n \"Failed to fetch all data types\",\n \"UNKNOWN_ERROR\",\n errors\n );\n }\n }\n\n // 4. Generate context file\n progress.update(\"Generating context\");\n await generateContext(mode, {\n phoenixUrl: baseURL,\n snapshotTime: new Date(),\n spansPerProject,\n });\n\n // 5. Write metadata file\n progress.update(\"Writing metadata\");\n const metadata: SnapshotMetadata = {\n created_at: new Date().toISOString(),\n phoenix_url: baseURL,\n cursors: {\n spans: {}, // TODO: Track span cursors when span fetching supports it\n datasets: { last_fetch: new Date().toISOString() },\n experiments: { last_fetch: new Date().toISOString() },\n prompts: { last_fetch: new Date().toISOString() },\n },\n limits: {\n spans_per_project: spansPerProject,\n },\n };\n\n await mode.writeFile(\n \"/_meta/snapshot.json\",\n JSON.stringify(metadata, null, 2)\n );\n\n progress.succeed(\"✅ Snapshot created successfully!\");\n } catch (error) {\n // Stop progress if not already stopped\n progress.stop();\n\n // Enhance error with context before rethrowing\n if (error instanceof PhoenixClientError) {\n throw error; // Already has good context\n }\n\n throw new PhoenixClientError(\n `Failed to create snapshot: ${error instanceof Error ? error.message : String(error)}`,\n \"UNKNOWN_ERROR\",\n error\n );\n }\n}\n\n/**\n * Loads existing snapshot metadata if available\n * @param mode - The execution mode (sandbox or local)\n * @returns The snapshot metadata or null if not found\n */\nexport async function loadSnapshotMetadata(\n mode: ExecutionMode\n): Promise<SnapshotMetadata | null> {\n try {\n const result = await mode.exec(\n \"cat /phoenix/_meta/snapshot.json 2>/dev/null\"\n );\n if (result.exitCode === 0) {\n return JSON.parse(result.stdout);\n }\n } catch (error) {\n // File doesn't exist or parse error\n }\n return null;\n}\n\n/**\n * Creates an incremental snapshot, fetching only new/updated data\n * @param mode - The execution mode (sandbox or local)\n * @param options - Snapshot options including server URL and limits\n */\nexport async function createIncrementalSnapshot(\n mode: ExecutionMode,\n options: SnapshotOptions\n): Promise<void> {\n // Load existing metadata to get cursors\n const existingMetadata = await loadSnapshotMetadata(mode);\n\n if (!existingMetadata) {\n // No existing snapshot, create a full one\n await createSnapshot(mode, options);\n return;\n }\n\n const {\n baseURL,\n apiKey,\n spansPerProject = 1000,\n showProgress = false,\n } = options;\n\n // Create progress indicator\n const progress = new SnapshotProgress(showProgress);\n progress.start(\"Updating Phoenix data snapshot\");\n\n // Create Phoenix client\n const clientConfig: PhoenixClientConfig = {\n baseURL,\n apiKey,\n };\n const client = createPhoenixClient(clientConfig);\n\n try {\n // Show time since last snapshot\n const lastSnapshotDate = new Date(existingMetadata.created_at);\n const timeSince = formatTimeSince(lastSnapshotDate);\n progress.update(\"Checking for updates\", `last snapshot ${timeSince} ago`);\n\n // For incremental updates, we'll need to:\n // 1. Fetch projects (always fetch all as they're small)\n progress.update(\"Updating projects\");\n await fetchProjects(client, mode);\n\n // 2. Fetch spans and other data in parallel for better performance\n progress.update(\"Fetching updates\", \"new spans and refreshing other data\");\n\n const spansOptions: SnapshotSpansOptions = {\n spansPerProject,\n // Use the last end time from previous snapshot as start time\n startTime: existingMetadata.cursors.spans\n ? Object.values(existingMetadata.cursors.spans)\n .map((cursor) => cursor.last_end_time)\n .filter(Boolean)\n .sort()\n .pop()\n : undefined,\n };\n\n // For datasets/experiments/prompts, check if they've been updated\n const datasetsLastFetch = existingMetadata.cursors.datasets?.last_fetch;\n const experimentsLastFetch =\n existingMetadata.cursors.experiments?.last_fetch;\n const promptsLastFetch = existingMetadata.cursors.prompts?.last_fetch;\n\n // Fetch all data types in parallel\n // For now, we'll refetch all as the API doesn't support filtering by updated_at\n // In a future enhancement, we could check individual items for updates\n const updateResults = await Promise.allSettled([\n snapshotSpans(client, mode, spansOptions),\n fetchDatasets(client, mode),\n fetchExperiments(client, mode),\n fetchPrompts(client, mode),\n ]);\n\n // Check for critical errors\n const updateErrors: Array<{ type: string; error: unknown }> = [];\n const updateDataTypes = [\"spans\", \"datasets\", \"experiments\", \"prompts\"];\n\n updateResults.forEach((result, index) => {\n if (result.status === \"rejected\") {\n updateErrors.push({\n type: updateDataTypes[index] || \"unknown\",\n error: result.reason,\n });\n }\n });\n\n if (updateErrors.length > 0) {\n // Log individual errors\n updateErrors.forEach(({ type, error }) => {\n console.error(\n `Warning: Failed to update ${type}:`,\n error instanceof Error ? error.message : String(error)\n );\n });\n }\n\n // 4. Regenerate context with updated data\n progress.update(\"Regenerating context\");\n await generateContext(mode, {\n phoenixUrl: baseURL,\n snapshotTime: new Date(),\n spansPerProject,\n });\n\n // 5. Update metadata\n progress.update(\"Updating metadata\");\n const updatedSpansCursors = existingMetadata.cursors.spans || {};\n const metadata: SnapshotMetadata = {\n created_at: new Date().toISOString(),\n phoenix_url: baseURL,\n cursors: {\n spans: updatedSpansCursors,\n datasets: { last_fetch: new Date().toISOString() },\n experiments: { last_fetch: new Date().toISOString() },\n prompts: { last_fetch: new Date().toISOString() },\n },\n limits: {\n spans_per_project: spansPerProject,\n },\n };\n\n await mode.writeFile(\n \"/_meta/snapshot.json\",\n JSON.stringify(metadata, null, 2)\n );\n\n progress.succeed(\"✅ Incremental update complete!\");\n } catch (error) {\n // Stop progress if not already stopped\n progress.stop();\n\n // Enhance error with context before rethrowing\n if (error instanceof PhoenixClientError) {\n throw error; // Already has good context\n }\n\n throw new PhoenixClientError(\n `Failed to create incremental snapshot: ${error instanceof Error ? error.message : String(error)}`,\n \"UNKNOWN_ERROR\",\n error\n );\n }\n}\n\n/**\n * Format time since a date in human-readable format\n */\nfunction formatTimeSince(date: Date): string {\n const seconds = Math.floor((new Date().getTime() - date.getTime()) / 1000);\n\n if (seconds < 60) return `${seconds}s`;\n const minutes = Math.floor(seconds / 60);\n if (minutes < 60) return `${minutes}m`;\n const hours = Math.floor(minutes / 60);\n if (hours < 24) return `${hours}h`;\n const days = Math.floor(hours / 24);\n return `${days}d`;\n}\n","/**\n * Snapshot discovery utilities\n *\n * Functions for listing and finding snapshots in the local filesystem.\n */\n\nimport * as fs from \"node:fs/promises\";\nimport * as path from \"node:path\";\nimport * as os from \"node:os\";\n\n/**\n * Information about a single snapshot\n */\nexport interface SnapshotInfo {\n /** Absolute path to the snapshot directory (the 'phoenix' subdirectory) */\n path: string;\n /** Timestamp when the snapshot was created (from directory name) */\n timestamp: Date;\n /** Unique identifier for the snapshot (directory name) */\n id: string;\n}\n\n/**\n * Get the base snapshots directory path\n */\nexport function getSnapshotsDir(): string {\n return path.join(os.homedir(), \".phoenix-insight\", \"snapshots\");\n}\n\n/**\n * Parse a snapshot directory name to extract timestamp\n *\n * Directory names are in format: `<timestamp>-<random>` where timestamp is Date.now()\n * Example: \"1704067200000-abc123\" -> Date(2024-01-01T00:00:00.000Z)\n *\n * @param dirName - The directory name to parse\n * @returns The parsed timestamp as Date, or null if invalid\n */\nfunction parseSnapshotDirName(dirName: string): Date | null {\n // Format: <timestamp>-<random>\n const match = dirName.match(/^(\\d+)-[\\w]+$/);\n if (!match || !match[1]) {\n return null;\n }\n\n const timestamp = parseInt(match[1], 10);\n if (isNaN(timestamp) || timestamp <= 0) {\n return null;\n }\n\n const date = new Date(timestamp);\n // Validate the date is reasonable (between year 2000 and year 3000)\n // Use UTC year to avoid timezone issues\n const year = date.getUTCFullYear();\n if (year < 2000 || year > 3000) {\n return null;\n }\n\n return date;\n}\n\n/**\n * List all available snapshots\n *\n * Scans the snapshots directory and returns information about each valid snapshot.\n * Results are sorted by timestamp descending (most recent first).\n *\n * @returns Array of snapshot info objects, sorted by timestamp descending\n */\nexport async function listSnapshots(): Promise<SnapshotInfo[]> {\n const snapshotsDir = getSnapshotsDir();\n\n // Check if snapshots directory exists\n try {\n await fs.access(snapshotsDir);\n } catch {\n // Directory doesn't exist - return empty array\n return [];\n }\n\n // Read directory contents\n let entries: string[];\n try {\n entries = await fs.readdir(snapshotsDir);\n } catch {\n // Cannot read directory - return empty array\n return [];\n }\n\n // Filter and parse valid snapshot directories\n const snapshots: SnapshotInfo[] = [];\n\n for (const entry of entries) {\n const timestamp = parseSnapshotDirName(entry);\n if (!timestamp) {\n // Invalid directory name format - skip\n continue;\n }\n\n const snapshotPath = path.join(snapshotsDir, entry, \"phoenix\");\n\n // Verify the phoenix subdirectory exists\n try {\n const stat = await fs.stat(snapshotPath);\n if (!stat.isDirectory()) {\n continue;\n }\n } catch {\n // Phoenix subdirectory doesn't exist or can't be accessed - skip\n continue;\n }\n\n snapshots.push({\n path: snapshotPath,\n timestamp,\n id: entry,\n });\n }\n\n // Sort by timestamp descending (most recent first)\n snapshots.sort((a, b) => b.timestamp.getTime() - a.timestamp.getTime());\n\n return snapshots;\n}\n\n/**\n * Get the latest (most recent) snapshot\n *\n * @returns The most recent snapshot info, or null if no snapshots exist\n */\nexport async function getLatestSnapshot(): Promise<SnapshotInfo | null> {\n const snapshots = await listSnapshots();\n\n if (snapshots.length === 0) {\n return null;\n }\n\n // First element is the most recent due to descending sort\n return snapshots[0] ?? null;\n}\n","/**\n * Phoenix Insight observability configuration\n */\n\nimport { register, type NodeTracerProvider } from \"@arizeai/phoenix-otel\";\nimport { DiagLogLevel } from \"@opentelemetry/api\";\n\n/**\n * Options for configuring observability\n */\nexport interface ObservabilityOptions {\n /** Whether to enable tracing */\n enabled: boolean;\n /** Phoenix base URL for sending traces */\n baseUrl?: string;\n /** Phoenix API key for authentication */\n apiKey?: string;\n /** Phoenix project name for organizing traces */\n projectName?: string;\n /** Whether to enable debug logging */\n debug?: boolean;\n}\n\n/**\n * Global tracer provider instance\n */\nlet tracerProvider: NodeTracerProvider | null = null;\n\n/**\n * Check if observability is enabled\n */\nexport function isObservabilityEnabled(): boolean {\n return tracerProvider !== null;\n}\n\n/**\n * Initialize observability for the Phoenix Insight agent\n */\nexport function initializeObservability(options: ObservabilityOptions): void {\n if (!options.enabled) {\n return;\n }\n\n // If already initialized, skip\n if (tracerProvider) {\n return;\n }\n\n try {\n // Configure the tracer provider\n tracerProvider = register({\n projectName: options.projectName || \"phoenix-insight\",\n url: options.baseUrl,\n apiKey: options.apiKey,\n batch: true,\n global: true,\n diagLogLevel: options.debug ? DiagLogLevel.DEBUG : undefined,\n });\n\n if (options.debug) {\n console.error(\n \"🔭 Observability enabled - traces will be sent to Phoenix\"\n );\n }\n } catch (error) {\n console.error(\"⚠️ Failed to initialize observability:\", error);\n // Don't throw - observability should not break the main functionality\n }\n}\n\n/**\n * Shutdown observability and cleanup resources\n */\nexport async function shutdownObservability(): Promise<void> {\n if (tracerProvider) {\n try {\n await tracerProvider.shutdown();\n tracerProvider = null;\n } catch (error) {\n console.error(\"⚠️ Error shutting down observability:\", error);\n }\n }\n}\n\n/**\n * Get the current tracer provider\n */\nexport function getTracerProvider(): NodeTracerProvider | null {\n return tracerProvider;\n}\n","import { z } from \"zod\";\n\n/**\n * Zod schema for Phoenix Insight CLI configuration\n *\n * Configuration values can be set via:\n * 1. Config file (~/.phoenix-insight/config.json or custom path)\n * 2. Environment variables (PHOENIX_BASE_URL, PHOENIX_API_KEY, etc.)\n * 3. CLI arguments (--base-url, --api-key, etc.)\n *\n * Priority: config file < env vars < CLI args\n */\nexport const configSchema = z.object({\n /**\n * Phoenix server base URL\n * @default \"http://localhost:6006\"\n */\n baseUrl: z.string().default(\"http://localhost:6006\"),\n\n /**\n * Phoenix API key for authentication (optional)\n */\n apiKey: z.string().optional(),\n\n /**\n * Maximum number of spans to fetch per project\n * @default 1000\n */\n limit: z.number().int().positive().default(1000),\n\n /**\n * Enable streaming responses from the agent\n * @default true\n */\n stream: z.boolean().default(true),\n\n /**\n * Execution mode: \"sandbox\" for in-memory filesystem, \"local\" for real filesystem\n * @default \"sandbox\"\n */\n mode: z.enum([\"sandbox\", \"local\"]).default(\"sandbox\"),\n\n /**\n * Force refresh of snapshot data\n * @default false\n */\n refresh: z.boolean().default(false),\n\n /**\n * Enable tracing of the agent to Phoenix\n * @default true\n */\n trace: z.boolean().default(true),\n});\n\n/**\n * Inferred TypeScript type from the config schema\n */\nexport type Config = z.infer<typeof configSchema>;\n\n/**\n * Get default configuration values\n */\nexport function getDefaultConfig(): Config {\n return configSchema.parse({});\n}\n","import * as fs from \"node:fs/promises\";\nimport * as path from \"node:path\";\nimport * as os from \"node:os\";\nimport { configSchema, getDefaultConfig, type Config } from \"./schema.js\";\n\n/**\n * Default config directory and file path\n */\nconst DEFAULT_CONFIG_DIR = path.join(os.homedir(), \".phoenix-insight\");\nconst DEFAULT_CONFIG_FILE = path.join(DEFAULT_CONFIG_DIR, \"config.json\");\n\n/**\n * Module-level storage for CLI args passed from commander\n * This is set externally before getConfigPath is called\n */\nlet cliConfigPath: string | undefined;\n\n/**\n * Set the CLI config path (called from CLI parsing)\n */\nexport function setCliConfigPath(configPath: string | undefined): void {\n cliConfigPath = configPath;\n}\n\n/**\n * Get the config file path based on priority:\n * 1. CLI argument (--config)\n * 2. Environment variable (PHOENIX_INSIGHT_CONFIG)\n * 3. Default path (~/.phoenix-insight/config.json)\n *\n * @returns The path to the config file and whether it's the default path\n */\nexport function getConfigPath(): { path: string; isDefault: boolean } {\n // Priority 1: CLI argument\n if (cliConfigPath) {\n return { path: cliConfigPath, isDefault: false };\n }\n\n // Priority 2: Environment variable\n const envConfigPath = process.env.PHOENIX_INSIGHT_CONFIG;\n if (envConfigPath) {\n return { path: envConfigPath, isDefault: false };\n }\n\n // Priority 3: Default path\n return { path: DEFAULT_CONFIG_FILE, isDefault: true };\n}\n\n/**\n * Load and parse a config file from disk\n *\n * @param configPath - Path to the config file\n * @returns Parsed JSON object or null if file not found\n * @throws Error if file exists but cannot be parsed as JSON\n */\nexport async function loadConfigFile(\n configPath: string\n): Promise<Record<string, unknown> | null> {\n try {\n const content = await fs.readFile(configPath, \"utf-8\");\n return JSON.parse(content) as Record<string, unknown>;\n } catch (error) {\n // File not found is expected - return null\n if (error instanceof Error && \"code\" in error && error.code === \"ENOENT\") {\n return null;\n }\n\n // JSON parse errors should be reported\n if (error instanceof SyntaxError) {\n console.warn(\n `Warning: Config file at ${configPath} contains invalid JSON: ${error.message}`\n );\n return null;\n }\n\n // Other errors (permissions, etc.) - warn and return null\n console.warn(\n `Warning: Could not read config file at ${configPath}: ${error instanceof Error ? error.message : String(error)}`\n );\n return null;\n }\n}\n\n/**\n * Validate a raw config object against the schema\n * Returns validated config or defaults if validation fails\n *\n * @param raw - Raw config object (or null/undefined)\n * @returns Validated config with defaults applied\n */\nexport function validateConfig(\n raw: Record<string, unknown> | null | undefined\n): Config {\n // If no raw config, return defaults\n if (!raw) {\n return getDefaultConfig();\n }\n\n try {\n // Parse with Zod schema - this applies defaults for missing fields\n return configSchema.parse(raw);\n } catch (error) {\n // Log validation errors as warnings\n if (error instanceof Error && \"issues\" in error) {\n // Zod error with issues array\n const zodError = error as {\n issues: Array<{ path: string[]; message: string }>;\n };\n zodError.issues.forEach((issue) => {\n console.warn(\n `Warning: Config validation error at '${issue.path.join(\".\")}': ${issue.message}`\n );\n });\n } else {\n console.warn(\n `Warning: Config validation failed: ${error instanceof Error ? error.message : String(error)}`\n );\n }\n\n // Return defaults on validation failure\n return getDefaultConfig();\n }\n}\n\n/**\n * Create a default config file at the given path\n * Only creates the file if it doesn't already exist\n * Only triggers for the default path, not custom paths\n *\n * @param configPath - Path where to create the config file\n * @param isDefault - Whether this is the default path (only create if true)\n * @returns true if file was created, false otherwise\n */\nexport async function createDefaultConfig(\n configPath: string,\n isDefault: boolean\n): Promise<boolean> {\n // Only create default config for the default path\n if (!isDefault) {\n return false;\n }\n\n try {\n // Check if file already exists\n await fs.access(configPath);\n // File exists, don't overwrite\n return false;\n } catch {\n // File doesn't exist, create it\n }\n\n try {\n // Create directory if needed\n const configDir = path.dirname(configPath);\n await fs.mkdir(configDir, { recursive: true });\n\n // Get default config and write it\n const defaultConfig = getDefaultConfig();\n const content = JSON.stringify(defaultConfig, null, 2);\n await fs.writeFile(configPath, content, \"utf-8\");\n\n // Log informational message to stderr\n console.error(`Created default config at ${configPath}`);\n\n return true;\n } catch (error) {\n // Log warning but don't fail - config will use defaults\n console.warn(\n `Warning: Could not create default config at ${configPath}: ${error instanceof Error ? error.message : String(error)}`\n );\n return false;\n }\n}\n","/**\n * Config singleton module for Phoenix Insight CLI\n *\n * Provides centralized configuration management with priority-based merging:\n * 1. Config file (lowest priority)\n * 2. Environment variables\n * 3. CLI arguments (highest priority)\n */\n\nimport { configSchema, type Config, getDefaultConfig } from \"./schema.js\";\nimport {\n getConfigPath,\n loadConfigFile,\n validateConfig,\n createDefaultConfig,\n setCliConfigPath,\n} from \"./loader.js\";\n\n// Re-export Config type for convenience\nexport type { Config } from \"./schema.js\";\n\n/**\n * Module-level storage for the initialized config singleton\n */\nlet configInstance: Config | null = null;\n\n/**\n * CLI arguments that can override config values\n */\nexport interface CliArgs {\n /** Custom config file path */\n config?: string;\n /** Phoenix server base URL */\n baseUrl?: string;\n /** Phoenix API key */\n apiKey?: string;\n /** Maximum spans to fetch per project */\n limit?: number;\n /** Enable streaming responses */\n stream?: boolean;\n /** Execution mode: sandbox or local */\n local?: boolean;\n /** Force refresh of snapshot data */\n refresh?: boolean;\n /** Enable tracing */\n trace?: boolean;\n}\n\n/**\n * Environment variable mappings to config keys\n */\nconst ENV_VAR_MAPPINGS: Record<string, keyof Config> = {\n PHOENIX_BASE_URL: \"baseUrl\",\n PHOENIX_API_KEY: \"apiKey\",\n PHOENIX_INSIGHT_LIMIT: \"limit\",\n PHOENIX_INSIGHT_STREAM: \"stream\",\n PHOENIX_INSIGHT_MODE: \"mode\",\n PHOENIX_INSIGHT_REFRESH: \"refresh\",\n PHOENIX_INSIGHT_TRACE: \"trace\",\n};\n\n/**\n * Parse environment variable value to appropriate type\n */\nfunction parseEnvValue(\n key: keyof Config,\n value: string\n): string | number | boolean | undefined {\n switch (key) {\n case \"baseUrl\":\n case \"apiKey\":\n return value;\n case \"limit\":\n const num = parseInt(value, 10);\n return isNaN(num) ? undefined : num;\n case \"stream\":\n case \"refresh\":\n case \"trace\":\n return value.toLowerCase() === \"true\" || value === \"1\";\n case \"mode\":\n if (value === \"sandbox\" || value === \"local\") {\n return value;\n }\n return undefined;\n default:\n return value;\n }\n}\n\n/**\n * Get config values from environment variables\n */\nfunction getEnvConfig(): Partial<Config> {\n const envConfig: Partial<Config> = {};\n\n for (const [envVar, configKey] of Object.entries(ENV_VAR_MAPPINGS)) {\n const value = process.env[envVar];\n if (value !== undefined) {\n const parsed = parseEnvValue(configKey, value);\n if (parsed !== undefined) {\n (envConfig as any)[configKey] = parsed;\n }\n }\n }\n\n return envConfig;\n}\n\n/**\n * Convert CLI args to config format\n */\nfunction cliArgsToConfig(cliArgs: CliArgs): Partial<Config> {\n const config: Partial<Config> = {};\n\n if (cliArgs.baseUrl !== undefined) {\n config.baseUrl = cliArgs.baseUrl;\n }\n if (cliArgs.apiKey !== undefined) {\n config.apiKey = cliArgs.apiKey;\n }\n if (cliArgs.limit !== undefined) {\n config.limit = cliArgs.limit;\n }\n if (cliArgs.stream !== undefined) {\n config.stream = cliArgs.stream;\n }\n if (cliArgs.local !== undefined) {\n // CLI uses --local flag, config uses mode\n config.mode = cliArgs.local ? \"local\" : \"sandbox\";\n }\n if (cliArgs.refresh !== undefined) {\n config.refresh = cliArgs.refresh;\n }\n if (cliArgs.trace !== undefined) {\n config.trace = cliArgs.trace;\n }\n\n return config;\n}\n\n/**\n * Initialize the configuration singleton\n *\n * Merges configuration from multiple sources with the following priority:\n * 1. Config file (lowest priority)\n * 2. Environment variables\n * 3. CLI arguments (highest priority)\n *\n * @param cliArgs - CLI arguments from Commander\n * @returns The initialized configuration\n */\nexport async function initializeConfig(cliArgs: CliArgs = {}): Promise<Config> {\n // Set CLI config path if provided (for getConfigPath to use)\n if (cliArgs.config) {\n setCliConfigPath(cliArgs.config);\n }\n\n // Get config file path\n const { path: configPath, isDefault } = getConfigPath();\n\n // Try to create default config if it doesn't exist (only for default path)\n if (isDefault) {\n await createDefaultConfig(configPath, isDefault);\n }\n\n // Load config file\n const fileConfig = await loadConfigFile(configPath);\n\n // Validate file config (returns defaults if null/invalid)\n const validatedFileConfig = validateConfig(fileConfig);\n\n // Get environment config\n const envConfig = getEnvConfig();\n\n // Get CLI config\n const cliConfig = cliArgsToConfig(cliArgs);\n\n // Merge configs: file < env < cli\n const mergedConfig = {\n ...validatedFileConfig,\n ...envConfig,\n ...cliConfig,\n };\n\n // Final validation with Zod\n const result = configSchema.safeParse(mergedConfig);\n\n if (result.success) {\n configInstance = result.data;\n } else {\n // Log validation issues as warnings\n result.error.issues.forEach((issue) => {\n console.warn(\n `Warning: Config validation error at '${issue.path.join(\".\")}': ${issue.message}`\n );\n });\n // Fall back to defaults\n configInstance = getDefaultConfig();\n }\n\n return configInstance;\n}\n\n/**\n * Get the initialized configuration\n *\n * @throws Error if config has not been initialized via initializeConfig()\n * @returns The configuration object\n */\nexport function getConfig(): Config {\n if (configInstance === null) {\n throw new Error(\n \"Config not initialized. Call initializeConfig() first before using getConfig().\"\n );\n }\n return configInstance;\n}\n\n/**\n * Reset the config singleton (useful for testing)\n */\nexport function resetConfig(): void {\n configInstance = null;\n setCliConfigPath(undefined);\n}\n","/**\n * HTTP server for Phoenix Insight UI.\n * Serves the static build of @cephalization/phoenix-insight-ui package.\n *\n * Binds to localhost only for security (no external network access).\n * Handles SPA routing by serving index.html for non-asset routes.\n */\n\nimport { createServer, type Server as HttpServer } from \"node:http\";\nimport { createReadStream, existsSync, statSync } from \"node:fs\";\nimport { extname, join, resolve } from \"node:path\";\nimport { fileURLToPath } from \"node:url\";\n\n// ============================================================================\n// MIME Type Mapping\n// ============================================================================\n\nconst MIME_TYPES: Record<string, string> = {\n \".html\": \"text/html; charset=utf-8\",\n \".css\": \"text/css; charset=utf-8\",\n \".js\": \"text/javascript; charset=utf-8\",\n \".mjs\": \"text/javascript; charset=utf-8\",\n \".json\": \"application/json; charset=utf-8\",\n \".svg\": \"image/svg+xml\",\n \".png\": \"image/png\",\n \".jpg\": \"image/jpeg\",\n \".jpeg\": \"image/jpeg\",\n \".gif\": \"image/gif\",\n \".ico\": \"image/x-icon\",\n \".webp\": \"image/webp\",\n \".woff\": \"font/woff\",\n \".woff2\": \"font/woff2\",\n \".ttf\": \"font/ttf\",\n \".eot\": \"application/vnd.ms-fontobject\",\n \".map\": \"application/json\",\n};\n\n/**\n * Get MIME type for a file extension\n */\nfunction getMimeType(filePath: string): string {\n const ext = extname(filePath).toLowerCase();\n return MIME_TYPES[ext] ?? \"application/octet-stream\";\n}\n\n// ============================================================================\n// Path Resolution\n// ============================================================================\n\n/**\n * Resolve the UI package dist directory path.\n * \n * Resolution order:\n * 1. Bundled dist/ui (copied during build, used for npm published package)\n * 2. import.meta.resolve (finds package in node_modules, used for development)\n * 3. Relative path fallback (for development before packages are linked)\n */\nexport function resolveUIDistPath(): string {\n const __dirname = fileURLToPath(new URL(\".\", import.meta.url));\n \n // First check for bundled UI dist (copied during CLI build)\n // This is the path when installed from npm\n // When bundled by tsup, cli.js is at dist/cli.js and UI is at dist/ui/\n const bundledPath = resolve(__dirname, \"ui\");\n if (existsSync(bundledPath) && existsSync(join(bundledPath, \"index.html\"))) {\n return bundledPath;\n }\n \n try {\n // Resolve the UI package's package.json using import.meta.resolve\n // import.meta.resolve returns a file URL (file:///...)\n const packageJsonUrl = import.meta.resolve(\n \"@cephalization/phoenix-insight-ui/package.json\"\n );\n const packageJsonPath = fileURLToPath(packageJsonUrl);\n const packageDir = resolve(packageJsonPath, \"..\");\n return join(packageDir, \"dist\");\n } catch {\n // Fallback: try to resolve relative to this file (for development)\n return resolve(__dirname, \"../../../ui/dist\");\n }\n}\n\n// ============================================================================\n// Server Options\n// ============================================================================\n\nexport interface UIServerOptions {\n /** Port to listen on (default: 6007) */\n port?: number;\n /** Host to bind to (default: \"127.0.0.1\" for localhost only) */\n host?: string;\n /** Custom path to UI dist directory (default: auto-resolved) */\n distPath?: string;\n}\n\nexport interface UIServer {\n /** The underlying HTTP server */\n httpServer: HttpServer;\n /** The port the server is listening on */\n port: number;\n /** The host the server is bound to */\n host: string;\n /** Path to the UI dist directory being served */\n distPath: string;\n /** Close the server gracefully */\n close(): Promise<void>;\n /** Force close all connections immediately */\n forceClose(): void;\n}\n\n// ============================================================================\n// Static File Server\n// ============================================================================\n\n/**\n * Determine if a path should be served as a static asset.\n * Asset paths have file extensions (e.g., .js, .css, .png).\n * Non-asset paths (routes) should get the SPA index.html.\n */\nfunction isAssetPath(urlPath: string): boolean {\n // Check for file extension in the last segment\n const lastSegment = urlPath.split(\"/\").pop() ?? \"\";\n return lastSegment.includes(\".\");\n}\n\n/**\n * Sanitize URL path to prevent directory traversal attacks.\n * Returns null if the path is invalid.\n */\nfunction sanitizePath(urlPath: string, basePath: string): string | null {\n // Decode URI and normalize slashes\n let decoded: string;\n try {\n decoded = decodeURIComponent(urlPath);\n } catch {\n return null;\n }\n\n // Remove query string and hash\n const withoutQuery = decoded.split(\"?\")[0] ?? decoded;\n decoded = withoutQuery.split(\"#\")[0] ?? withoutQuery;\n\n // Resolve the full path\n const fullPath = resolve(basePath, \".\" + decoded);\n\n // Ensure the resolved path is within the base directory\n if (!fullPath.startsWith(basePath)) {\n return null;\n }\n\n return fullPath;\n}\n\n/**\n * Create an HTTP server that serves the Phoenix Insight UI.\n *\n * Features:\n * - Serves static files from the UI package dist directory\n * - SPA fallback: non-asset routes serve index.html\n * - Binds to localhost only (127.0.0.1) for security\n * - Proper MIME types for all common web assets\n *\n * @param options - Server configuration options\n * @returns Promise resolving to UIServer instance\n */\nexport function createUIServer(options: UIServerOptions = {}): Promise<UIServer> {\n const port = options.port ?? 6007;\n const host = options.host ?? \"127.0.0.1\";\n const distPath = options.distPath ?? resolveUIDistPath();\n\n // Verify dist directory exists\n if (!existsSync(distPath)) {\n return Promise.reject(\n new Error(\n `UI dist directory not found at: ${distPath}\\n` +\n \"Make sure to build the UI package first: pnpm --filter @cephalization/phoenix-insight-ui build\"\n )\n );\n }\n\n // Verify index.html exists\n const indexPath = join(distPath, \"index.html\");\n if (!existsSync(indexPath)) {\n return Promise.reject(\n new Error(\n `UI index.html not found at: ${indexPath}\\n` +\n \"Make sure to build the UI package first: pnpm --filter @cephalization/phoenix-insight-ui build\"\n )\n );\n }\n\n return new Promise((resolve, reject) => {\n // Track active connections for force-close capability\n const activeConnections = new Set<import(\"node:net\").Socket>();\n\n const httpServer = createServer((req, res) => {\n const urlPath = req.url ?? \"/\";\n\n // Sanitize the path to prevent directory traversal\n let filePath = sanitizePath(urlPath, distPath);\n if (!filePath) {\n res.writeHead(400, { \"Content-Type\": \"text/plain\" });\n res.end(\"Bad Request\");\n return;\n }\n\n // SPA fallback: if not an asset path, serve index.html\n if (!isAssetPath(urlPath)) {\n filePath = indexPath;\n }\n\n // Check if file exists\n if (!existsSync(filePath)) {\n // For missing assets, return 404\n // For missing routes, serve index.html (SPA)\n if (isAssetPath(urlPath)) {\n res.writeHead(404, { \"Content-Type\": \"text/plain\" });\n res.end(\"Not Found\");\n return;\n }\n filePath = indexPath;\n }\n\n // Get file stats\n let stats;\n try {\n stats = statSync(filePath);\n } catch {\n res.writeHead(500, { \"Content-Type\": \"text/plain\" });\n res.end(\"Internal Server Error\");\n return;\n }\n\n // If it's a directory, serve index.html\n if (stats.isDirectory()) {\n filePath = indexPath;\n try {\n stats = statSync(filePath);\n } catch {\n res.writeHead(500, { \"Content-Type\": \"text/plain\" });\n res.end(\"Internal Server Error\");\n return;\n }\n }\n\n // Set response headers\n const mimeType = getMimeType(filePath);\n res.writeHead(200, {\n \"Content-Type\": mimeType,\n \"Content-Length\": stats.size,\n \"Cache-Control\": filePath === indexPath\n ? \"no-cache\" // Don't cache index.html for SPA\n : \"public, max-age=31536000\", // Cache assets for 1 year\n });\n\n // Stream the file\n const stream = createReadStream(filePath);\n stream.pipe(res);\n stream.on(\"error\", () => {\n res.writeHead(500, { \"Content-Type\": \"text/plain\" });\n res.end(\"Internal Server Error\");\n });\n });\n\n // Track connections to enable force-close\n httpServer.on(\"connection\", (socket) => {\n activeConnections.add(socket);\n socket.on(\"close\", () => {\n activeConnections.delete(socket);\n });\n });\n\n // Handle server errors\n httpServer.on(\"error\", (err) => {\n reject(err);\n });\n\n // Start listening\n httpServer.listen(port, host, () => {\n // Get the actual assigned port (important when port 0 is specified)\n const address = httpServer.address();\n const actualPort = typeof address === \"object\" && address !== null\n ? address.port\n : port;\n\n resolve({\n httpServer,\n port: actualPort,\n host,\n distPath,\n close(): Promise<void> {\n return new Promise((resolveClose, rejectClose) => {\n httpServer.close((err) => {\n if (err) {\n rejectClose(err);\n } else {\n resolveClose();\n }\n });\n });\n },\n forceClose(): void {\n // Destroy all active connections immediately\n for (const socket of activeConnections) {\n socket.destroy();\n }\n activeConnections.clear();\n },\n });\n });\n });\n}\n","/**\n * WebSocket server for Phoenix Insight CLI.\n * Provides bidirectional communication between the CLI agent and the web UI.\n *\n * Binds to localhost only for security (no external network access).\n * Handles HTTP upgrade requests, manages client connections, and broadcasts messages.\n */\n\nimport type { Server as HttpServer, IncomingMessage } from \"node:http\";\nimport { WebSocketServer, WebSocket } from \"ws\";\nimport type {\n ClientMessage,\n ServerMessage,\n JSONRenderTree,\n} from \"@cephalization/phoenix-insight-ui/types\";\n\n// Re-export types for consumers of this module\nexport type { ClientMessage, ServerMessage, JSONRenderTree };\n\n// ============================================================================\n// Event Handler Types\n// ============================================================================\n\nexport type ClientMessageHandler = (\n message: ClientMessage,\n client: WebSocket\n) => void;\nexport type ConnectionHandler = (client: WebSocket) => void;\nexport type DisconnectionHandler = (\n client: WebSocket,\n code: number,\n reason: string\n) => void;\nexport type ErrorHandler = (error: Error, client?: WebSocket) => void;\n\n// ============================================================================\n// WebSocket Server Options\n// ============================================================================\n\nexport interface WebSocketServerOptions {\n /** Path to accept WebSocket connections on (default: \"/ws\") */\n path?: string;\n /** Handler for incoming client messages */\n onMessage?: ClientMessageHandler;\n /** Handler for new client connections */\n onConnection?: ConnectionHandler;\n /** Handler for client disconnections */\n onDisconnection?: DisconnectionHandler;\n /** Handler for WebSocket errors */\n onError?: ErrorHandler;\n}\n\n// ============================================================================\n// Phoenix WebSocket Server\n// ============================================================================\n\n/**\n * Phoenix WebSocket server wrapper providing typed message handling\n * and connection management.\n */\nexport class PhoenixWebSocketServer {\n private wss: WebSocketServer | null = null;\n private clients: Set<WebSocket> = new Set();\n private options: Required<WebSocketServerOptions>;\n\n constructor(options: WebSocketServerOptions = {}) {\n this.options = {\n path: \"/ws\",\n onMessage: () => {},\n onConnection: () => {},\n onDisconnection: () => {},\n onError: () => {},\n ...options,\n };\n }\n\n /**\n * Attach the WebSocket server to an existing HTTP server.\n * Uses the upgrade event to handle WebSocket handshakes.\n */\n attach(httpServer: HttpServer): void {\n if (this.wss) {\n throw new Error(\"WebSocket server is already attached\");\n }\n\n // Create WebSocket server with noServer mode to handle upgrade ourselves\n this.wss = new WebSocketServer({ noServer: true });\n\n // Handle HTTP upgrade requests\n httpServer.on(\"upgrade\", (request, socket, head) => {\n this.handleUpgrade(request, socket, head);\n });\n\n // Set up WebSocket server event handlers\n this.setupEventHandlers();\n }\n\n /**\n * Handle HTTP upgrade request for WebSocket connection.\n * Only accepts connections on the configured path and from localhost.\n */\n private handleUpgrade(\n request: IncomingMessage,\n socket: import(\"node:stream\").Duplex,\n head: Buffer\n ): void {\n if (!this.wss) {\n socket.destroy();\n return;\n }\n\n // Parse the request URL\n const url = new URL(request.url ?? \"/\", `http://${request.headers.host}`);\n\n // Only accept connections on the configured path\n if (url.pathname !== this.options.path) {\n socket.destroy();\n return;\n }\n\n // Complete the WebSocket handshake\n this.wss.handleUpgrade(request, socket, head, (ws) => {\n this.wss?.emit(\"connection\", ws, request);\n });\n }\n\n /**\n * Set up event handlers for the WebSocket server.\n */\n private setupEventHandlers(): void {\n if (!this.wss) return;\n\n this.wss.on(\"connection\", (ws: WebSocket) => {\n this.clients.add(ws);\n this.options.onConnection(ws);\n\n ws.on(\"message\", (data: Buffer | ArrayBuffer | Buffer[]) => {\n this.handleMessage(data, ws);\n });\n\n ws.on(\"close\", (code: number, reason: Buffer) => {\n this.clients.delete(ws);\n this.options.onDisconnection(ws, code, reason.toString());\n });\n\n ws.on(\"error\", (error: Error) => {\n this.options.onError(error, ws);\n });\n });\n\n this.wss.on(\"error\", (error: Error) => {\n this.options.onError(error);\n });\n }\n\n /**\n * Handle incoming message from a client.\n * Parses JSON and validates message structure before calling handler.\n */\n private handleMessage(\n data: Buffer | ArrayBuffer | Buffer[],\n client: WebSocket\n ): void {\n try {\n const rawMessage = data.toString();\n const parsed = JSON.parse(rawMessage) as unknown;\n\n // Basic validation of message structure\n if (!parsed || typeof parsed !== \"object\") {\n throw new Error(\"Invalid message structure: expected object\");\n }\n\n const obj = parsed as Record<string, unknown>;\n if (!(\"type\" in obj) || typeof obj.type !== \"string\") {\n throw new Error(\"Invalid message structure: missing type field\");\n }\n\n const messageType = obj.type;\n if (messageType !== \"query\" && messageType !== \"cancel\") {\n throw new Error(`Unknown message type: ${messageType}`);\n }\n\n // Now we know this is a valid ClientMessage\n const message = parsed as ClientMessage;\n this.options.onMessage(message, client);\n } catch (error) {\n // Send error message back to the client\n const errorMessage: ServerMessage = {\n type: \"error\",\n payload: {\n message:\n error instanceof Error\n ? error.message\n : \"Failed to parse message\",\n },\n };\n this.sendToClient(client, errorMessage);\n }\n }\n\n /**\n * Send a message to a specific client.\n */\n sendToClient(client: WebSocket, message: ServerMessage): void {\n if (client.readyState === WebSocket.OPEN) {\n client.send(JSON.stringify(message));\n }\n }\n\n /**\n * Broadcast a message to all connected clients.\n */\n broadcast(message: ServerMessage): void {\n const data = JSON.stringify(message);\n for (const client of this.clients) {\n if (client.readyState === WebSocket.OPEN) {\n client.send(data);\n }\n }\n }\n\n /**\n * Broadcast a message to all clients with a specific session ID.\n * This requires tracking session-to-client mapping externally.\n * For now, it broadcasts to all clients (to be refined in cli-agent-session).\n */\n broadcastToSession(sessionId: string, message: ServerMessage): void {\n // For now, broadcast to all clients.\n // Session-to-client mapping will be implemented in cli-agent-session task.\n this.broadcast(message);\n }\n\n /**\n * Get the number of connected clients.\n */\n get clientCount(): number {\n return this.clients.size;\n }\n\n /**\n * Get all connected clients.\n */\n getClients(): Set<WebSocket> {\n return new Set(this.clients);\n }\n\n /**\n * Close the WebSocket server and disconnect all clients.\n */\n close(): Promise<void> {\n return new Promise((resolve, reject) => {\n if (!this.wss) {\n resolve();\n return;\n }\n\n // Close all client connections\n for (const client of this.clients) {\n client.close(1000, \"Server shutting down\");\n }\n this.clients.clear();\n\n // Close the WebSocket server\n this.wss.close((err) => {\n this.wss = null;\n if (err) {\n reject(err);\n } else {\n resolve();\n }\n });\n });\n }\n\n /**\n * Force terminate all WebSocket connections immediately.\n * Use this when graceful close doesn't complete in time.\n */\n forceClose(): void {\n if (!this.wss) {\n return;\n }\n\n // Terminate all client connections immediately (no close handshake)\n for (const client of this.clients) {\n client.terminate();\n }\n this.clients.clear();\n }\n}\n\n// ============================================================================\n// Factory Function\n// ============================================================================\n\n/**\n * Create and attach a WebSocket server to an HTTP server.\n * The WebSocket server binds to localhost only (through the HTTP server).\n *\n * @param httpServer - HTTP server to attach WebSocket handling to\n * @param options - WebSocket server options\n * @returns PhoenixWebSocketServer instance\n */\nexport function createWebSocketServer(\n httpServer: HttpServer,\n options?: WebSocketServerOptions\n): PhoenixWebSocketServer {\n const server = new PhoenixWebSocketServer(options);\n server.attach(httpServer);\n return server;\n}\n","/**\n * AgentSession manages a single WebSocket client's agent interaction.\n * Handles query execution, streaming responses, tool call notifications,\n * and report generation via the report tool.\n */\n\nimport type { WebSocket } from \"ws\";\nimport type { ServerMessage, JSONRenderTree } from \"./websocket.js\";\nimport {\n PhoenixInsightAgent,\n createInsightAgent,\n type PhoenixInsightAgentConfig,\n} from \"../agent/index.js\";\nimport type { ExecutionMode } from \"../modes/types.js\";\nimport type { PhoenixClient } from \"@arizeai/phoenix-client\";\nimport { createReportTool } from \"../commands/report-tool.js\";\n\n// ============================================================================\n// Types\n// ============================================================================\n\n/**\n * Message in conversation history\n */\nexport interface ConversationMessage {\n role: \"user\" | \"assistant\";\n content: string;\n timestamp: number;\n}\n\n/**\n * Callback for broadcasting messages to a WebSocket client\n */\nexport type BroadcastCallback = (message: ServerMessage) => void;\n\n/**\n * Options for creating an AgentSession\n */\nexport interface AgentSessionOptions {\n /** Unique session ID */\n sessionId: string;\n /** The execution mode (sandbox or local) */\n mode: ExecutionMode;\n /** Phoenix client instance */\n client: PhoenixClient;\n /** Maximum number of agent steps before stopping (default: 25) */\n maxSteps?: number;\n /** Callback to send messages to the client */\n broadcast: BroadcastCallback;\n}\n\n/**\n * Report generation callback that can be passed to tools\n */\nexport type ReportCallback = (content: JSONRenderTree, title?: string) => void;\n\n// ============================================================================\n// AgentSession Class\n// ============================================================================\n\n/**\n * Manages a single WebSocket client's agent interaction.\n * - Handles query execution with streaming responses\n * - Sends tool call and tool result notifications\n * - Maintains conversation history within session\n * - Supports cancellation of in-progress queries\n */\nexport class AgentSession {\n private sessionId: string;\n private mode: ExecutionMode;\n private client: PhoenixClient;\n private maxSteps: number;\n private broadcast: BroadcastCallback;\n private agent: PhoenixInsightAgent | null = null;\n private conversationHistory: ConversationMessage[] = [];\n private isExecuting = false;\n private abortController: AbortController | null = null;\n\n constructor(options: AgentSessionOptions) {\n this.sessionId = options.sessionId;\n this.mode = options.mode;\n this.client = options.client;\n this.maxSteps = options.maxSteps ?? 25;\n this.broadcast = options.broadcast;\n }\n\n /**\n * Get the session ID\n */\n get id(): string {\n return this.sessionId;\n }\n\n /**\n * Check if a query is currently being executed\n */\n get executing(): boolean {\n return this.isExecuting;\n }\n\n /**\n * Get the conversation history\n */\n get history(): ConversationMessage[] {\n return [...this.conversationHistory];\n }\n\n /**\n * Initialize the agent lazily, including the report tool for UI mode\n */\n private async getAgent(): Promise<PhoenixInsightAgent> {\n if (!this.agent) {\n // Create the report tool with a callback to send reports to the client\n const reportTool = createReportTool((content, title) => {\n this.sendReport(content, title);\n });\n\n const config: PhoenixInsightAgentConfig = {\n mode: this.mode,\n client: this.client,\n maxSteps: this.maxSteps,\n additionalTools: {\n generate_report: reportTool,\n },\n };\n this.agent = await createInsightAgent(config);\n }\n return this.agent;\n }\n\n /**\n * Send a message to the connected client\n */\n private send(message: ServerMessage): void {\n this.broadcast(message);\n }\n\n /**\n * Send a text chunk to the client\n */\n private sendText(content: string): void {\n this.send({\n type: \"text\",\n payload: { content, sessionId: this.sessionId },\n });\n }\n\n /**\n * Send a tool call notification to the client\n */\n private sendToolCall(toolName: string, args: unknown): void {\n this.send({\n type: \"tool_call\",\n payload: { toolName, args, sessionId: this.sessionId },\n });\n }\n\n /**\n * Send a tool result notification to the client\n */\n private sendToolResult(toolName: string, result: unknown): void {\n this.send({\n type: \"tool_result\",\n payload: { toolName, result, sessionId: this.sessionId },\n });\n }\n\n /**\n * Send a report update to the client\n */\n sendReport(content: JSONRenderTree, title?: string): void {\n this.send({\n type: \"report\",\n payload: { content, sessionId: this.sessionId },\n });\n }\n\n /**\n * Send an error message to the client\n */\n private sendError(message: string): void {\n this.send({\n type: \"error\",\n payload: { message, sessionId: this.sessionId },\n });\n }\n\n /**\n * Send the done signal to the client\n */\n private sendDone(): void {\n this.send({\n type: \"done\",\n payload: { sessionId: this.sessionId },\n });\n }\n\n /**\n * Add a message to the conversation history\n */\n private addToHistory(role: \"user\" | \"assistant\", content: string): void {\n this.conversationHistory.push({\n role,\n content,\n timestamp: Date.now(),\n });\n }\n\n /**\n * Get a callback function for the report tool\n * This can be passed to the report tool to send reports to the client\n */\n getReportCallback(): ReportCallback {\n return (content: JSONRenderTree, title?: string) => {\n this.sendReport(content, title);\n };\n }\n\n /**\n * Execute a query and stream the response to the client\n */\n async executeQuery(query: string): Promise<void> {\n if (this.isExecuting) {\n this.sendError(\"A query is already being executed\");\n return;\n }\n\n this.isExecuting = true;\n this.abortController = new AbortController();\n\n // Add user message to history\n this.addToHistory(\"user\", query);\n\n try {\n const agent = await this.getAgent();\n\n // Use streaming for responses\n const result = await agent.stream(query, {});\n\n // Stream using fullStream to get real-time tool call/result events\n // This ensures tool calls are sent BEFORE execution, not after\n let fullResponse = \"\";\n let lastStepHadText = false;\n\n for await (const part of result.fullStream) {\n // Check if cancelled\n if (this.abortController?.signal.aborted) {\n break;\n }\n\n switch (part.type) {\n case \"text-delta\":\n // Add step separator if needed (when previous step had text)\n if (lastStepHadText && part.text.trim().length > 0) {\n const separator = \"\\n\\n\";\n fullResponse += separator;\n this.sendText(separator);\n lastStepHadText = false;\n }\n fullResponse += part.text;\n this.sendText(part.text);\n break;\n\n case \"tool-call\":\n // Send tool call notification immediately when the model calls the tool\n // This happens BEFORE the tool executes\n // AI SDK v6 uses 'input' property for the parsed arguments\n this.sendToolCall(part.toolName, part.input ?? {});\n break;\n\n case \"tool-result\":\n // Send tool result when execution completes\n // AI SDK v6 uses 'output' property for the result\n this.sendToolResult(part.toolName, part.output);\n break;\n\n case \"text-end\":\n // A text block ended - if there was content, mark for separator\n if (fullResponse.trim().length > 0) {\n lastStepHadText = true;\n }\n break;\n }\n }\n\n // Wait for the full response to complete\n if (!this.abortController?.signal.aborted) {\n await result.response;\n }\n\n // Add assistant message to history\n if (fullResponse) {\n this.addToHistory(\"assistant\", fullResponse);\n }\n\n // Send done signal\n this.sendDone();\n } catch (error) {\n // Don't send error if we were cancelled\n if (!this.abortController?.signal.aborted) {\n const message = error instanceof Error ? error.message : String(error);\n this.sendError(`Query failed: ${message}`);\n }\n } finally {\n this.isExecuting = false;\n this.abortController = null;\n }\n }\n\n /**\n * Cancel the currently executing query\n */\n cancel(): void {\n if (this.abortController) {\n this.abortController.abort();\n this.sendDone();\n }\n }\n\n /**\n * Clear the conversation history\n */\n clearHistory(): void {\n this.conversationHistory = [];\n }\n\n /**\n * Clean up resources\n */\n async cleanup(): Promise<void> {\n // Cancel any in-progress execution\n if (this.abortController) {\n this.abortController.abort();\n }\n\n // Note: We don't clean up the mode here as it may be shared\n // The caller is responsible for cleaning up the mode\n this.agent = null;\n this.conversationHistory = [];\n }\n}\n\n// ============================================================================\n// Factory Function\n// ============================================================================\n\n/**\n * Create a new AgentSession\n */\nexport function createAgentSession(options: AgentSessionOptions): AgentSession {\n return new AgentSession(options);\n}\n\n// ============================================================================\n// Session Manager (for managing multiple sessions)\n// ============================================================================\n\n/**\n * Options for creating a SessionManager\n */\nexport interface SessionManagerOptions {\n /** The execution mode (sandbox or local) */\n mode: ExecutionMode;\n /** Phoenix client instance */\n client: PhoenixClient;\n /** Maximum number of agent steps before stopping (default: 25) */\n maxSteps?: number;\n}\n\n/**\n * Manages multiple agent sessions (one per WebSocket client)\n */\nexport class SessionManager {\n private sessions: Map<string, AgentSession> = new Map();\n private clientToSession: Map<WebSocket, string> = new Map();\n private mode: ExecutionMode;\n private client: PhoenixClient;\n private maxSteps: number;\n\n constructor(options: SessionManagerOptions) {\n this.mode = options.mode;\n this.client = options.client;\n this.maxSteps = options.maxSteps ?? 25;\n }\n\n /**\n * Get or create a session for a WebSocket client\n */\n getOrCreateSession(\n ws: WebSocket,\n sessionId: string,\n broadcast: BroadcastCallback\n ): AgentSession {\n // Check if we already have a session for this ID\n let session = this.sessions.get(sessionId);\n\n if (!session) {\n // Create a new session\n session = createAgentSession({\n sessionId,\n mode: this.mode,\n client: this.client,\n maxSteps: this.maxSteps,\n broadcast,\n });\n this.sessions.set(sessionId, session);\n }\n\n // Map the WebSocket to the session\n this.clientToSession.set(ws, sessionId);\n\n return session;\n }\n\n /**\n * Get the session for a WebSocket client\n */\n getSessionForClient(ws: WebSocket): AgentSession | undefined {\n const sessionId = this.clientToSession.get(ws);\n if (sessionId) {\n return this.sessions.get(sessionId);\n }\n return undefined;\n }\n\n /**\n * Get a session by ID\n */\n getSession(sessionId: string): AgentSession | undefined {\n return this.sessions.get(sessionId);\n }\n\n /**\n * Remove a session when a client disconnects\n */\n async removeSession(ws: WebSocket): Promise<void> {\n const sessionId = this.clientToSession.get(ws);\n if (sessionId) {\n const session = this.sessions.get(sessionId);\n if (session) {\n await session.cleanup();\n this.sessions.delete(sessionId);\n }\n this.clientToSession.delete(ws);\n }\n }\n\n /**\n * Get the number of active sessions\n */\n get sessionCount(): number {\n return this.sessions.size;\n }\n\n /**\n * Clean up all sessions\n */\n async cleanup(): Promise<void> {\n for (const session of this.sessions.values()) {\n await session.cleanup();\n }\n this.sessions.clear();\n this.clientToSession.clear();\n }\n}\n\n/**\n * Create a new SessionManager\n */\nexport function createSessionManager(\n options: SessionManagerOptions\n): SessionManager {\n return new SessionManager(options);\n}\n"],"mappings":"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","names":["fs","path","os","tool","z","z","z","z","z","z","z","name","z","z","tool","z","toJSONL","toJSONL","toJSONL","stat","z","fs","path","os","join","resolve","resolve","path","resolve"]}
1
+ {"version":3,"sources":["../src/cli.ts","../src/agent/index.ts","../src/prompts/system.ts","../src/snapshot/client.ts","../src/commands/px-fetch-more-spans.ts","../src/commands/px-fetch-more-trace.ts","../src/commands/report-tool.ts","../../../node_modules/.pnpm/@json-render+core@0.2.0_zod@4.3.5/node_modules/@json-render/core/src/types.ts","../../../node_modules/.pnpm/@json-render+core@0.2.0_zod@4.3.5/node_modules/@json-render/core/src/visibility.ts","../../../node_modules/.pnpm/@json-render+core@0.2.0_zod@4.3.5/node_modules/@json-render/core/src/actions.ts","../../../node_modules/.pnpm/@json-render+core@0.2.0_zod@4.3.5/node_modules/@json-render/core/src/validation.ts","../../../node_modules/.pnpm/@json-render+core@0.2.0_zod@4.3.5/node_modules/@json-render/core/src/catalog.ts","../../ui/src/lib/json-render/catalog.ts","../src/snapshot/projects.ts","../src/snapshot/spans.ts","../src/snapshot/datasets.ts","../src/snapshot/experiments.ts","../src/snapshot/prompts.ts","../src/snapshot/context.ts","../src/progress.ts","../src/snapshot/index.ts","../src/snapshot/utils.ts","../src/observability/index.ts","../src/config/schema.ts","../src/config/loader.ts","../src/config/index.ts","../src/server/ui.ts","../src/server/websocket.ts","../src/server/session.ts"],"sourcesContent":["#!/usr/bin/env node\n\nimport { Command } from \"commander\";\nimport * as readline from \"node:readline\";\nimport * as fs from \"node:fs/promises\";\nimport * as path from \"node:path\";\nimport * as os from \"node:os\";\nimport { exec } from \"node:child_process\";\nimport { createSandboxMode, createLocalMode } from \"./modes/index.js\";\nimport { createInsightAgent, runOneShotQuery } from \"./agent/index.js\";\nimport {\n createSnapshot,\n createIncrementalSnapshot,\n createPhoenixClient,\n PhoenixClientError,\n} from \"./snapshot/index.js\";\nimport { getLatestSnapshot, listSnapshots } from \"./snapshot/utils.js\";\nimport type { ExecutionMode } from \"./modes/types.js\";\nimport type { PhoenixInsightAgentConfig } from \"./agent/index.js\";\nimport { AgentProgress } from \"./progress.js\";\nimport {\n initializeObservability,\n shutdownObservability,\n} from \"./observability/index.js\";\nimport { initializeConfig, getConfig, type CliArgs } from \"./config/index.js\";\nimport { createUIServer } from \"./server/ui.js\";\nimport { createWebSocketServer } from \"./server/websocket.js\";\nimport { createSessionManager } from \"./server/session.js\";\nimport type { WebSocket } from \"ws\";\n\n// Version will be read from package.json during build\nconst VERSION = \"0.0.1\";\n\nconst program = new Command();\n\n/**\n * Format bash command for display in progress indicator\n */\nfunction formatBashCommand(command: string): string {\n if (!command) return \"\";\n\n // Split by newline and get first line\n const lines = command.split(\"\\n\");\n const firstLine = lines[0]?.trim() || \"\";\n\n // Check for pipeline first (3+ commands)\n if (firstLine.includes(\" | \") && firstLine.split(\" | \").length > 2) {\n const parts = firstLine.split(\" | \");\n const firstCmd = parts[0]?.split(\" \")[0] || \"\";\n const lastCmd = parts[parts.length - 1]?.split(\" \")[0] || \"\";\n return `${firstCmd} | ... | ${lastCmd}`;\n }\n\n // Common command patterns to display nicely\n if (firstLine.startsWith(\"cat \")) {\n const file = firstLine.substring(4).trim();\n return `cat ${file}`;\n } else if (firstLine.startsWith(\"grep \")) {\n // Extract pattern and file/directory\n const match = firstLine.match(\n /grep\\s+(?:-[^\\s]+\\s+)*['\"]?([^'\"]+)['\"]?\\s+(.+)/\n );\n if (match && match[1] && match[2]) {\n return `grep \"${match[1]}\" in ${match[2]}`;\n }\n return firstLine.substring(0, 60) + (firstLine.length > 60 ? \"...\" : \"\");\n } else if (firstLine.startsWith(\"find \")) {\n const match = firstLine.match(\n /find\\s+([^\\s]+)(?:\\s+-name\\s+['\"]?([^'\"]+)['\"]?)?/\n );\n if (match && match[1]) {\n return match[2]\n ? `find \"${match[2]}\" in ${match[1]}`\n : `find in ${match[1]}`;\n }\n return firstLine.substring(0, 60) + (firstLine.length > 60 ? \"...\" : \"\");\n } else if (firstLine.startsWith(\"ls \")) {\n const path = firstLine.substring(3).trim();\n return path ? `ls ${path}` : \"ls\";\n } else if (firstLine.startsWith(\"ls\")) {\n return \"ls\";\n } else if (firstLine.startsWith(\"jq \")) {\n return `jq processing JSON data`;\n } else if (firstLine.startsWith(\"head \") || firstLine.startsWith(\"tail \")) {\n const cmd = firstLine.split(\" \")[0];\n const fileMatch = firstLine.match(/(?:head|tail)\\s+(?:-[^\\s]+\\s+)*(.+)/);\n if (fileMatch && fileMatch[1]) {\n return `${cmd} ${fileMatch[1]}`;\n }\n return firstLine.substring(0, 60) + (firstLine.length > 60 ? \"...\" : \"\");\n } else {\n // For other commands, show up to 80 characters\n return firstLine.substring(0, 80) + (firstLine.length > 80 ? \"...\" : \"\");\n }\n}\n\n/**\n * Check if ANTHROPIC_API_KEY is set and provide a helpful error if not\n */\nfunction ensureAnthropicApiKey(): void {\n if (!process.env.ANTHROPIC_API_KEY) {\n console.error(\n \"\\n❌ Error: Missing ANTHROPIC_API_KEY environment variable\\n\"\n );\n console.error(\"The Anthropic API key is required to run the AI agent.\\n\");\n console.error(\"To fix this, set the environment variable:\\n\");\n console.error(\" export ANTHROPIC_API_KEY=sk-ant-api03-...\\n\");\n console.error(\n \"Or add it to your shell profile (~/.zshrc, ~/.bashrc, etc.):\\n\"\n );\n console.error(\n \" echo 'export ANTHROPIC_API_KEY=sk-ant-api03-...' >> ~/.zshrc\\n\"\n );\n console.error(\n \"You can get an API key from: https://console.anthropic.com/\\n\"\n );\n process.exit(1);\n }\n}\n\n/**\n * Handle errors with appropriate exit codes and user-friendly messages\n */\nfunction handleError(error: unknown, context: string): never {\n console.error(`\\n❌ Error ${context}:`);\n\n if (error instanceof PhoenixClientError) {\n switch (error.code) {\n case \"NETWORK_ERROR\":\n console.error(\n \"\\n🌐 Network Error: Unable to connect to Phoenix server\"\n );\n console.error(` Make sure Phoenix is running and accessible`);\n console.error(` You can specify a different URL with --base-url`);\n break;\n case \"AUTH_ERROR\":\n console.error(\"\\n🔒 Authentication Error: Invalid or missing API key\");\n console.error(\n ` Set the PHOENIX_API_KEY environment variable or use --api-key`\n );\n break;\n case \"INVALID_RESPONSE\":\n console.error(\n \"\\n⚠️ Invalid Response: Phoenix returned unexpected data\"\n );\n console.error(` This might be a version compatibility issue`);\n break;\n default:\n console.error(\"\\n❓ Phoenix Client Error:\", error.message);\n }\n if (error.originalError && process.env.DEBUG) {\n console.error(\"\\nOriginal error:\", error.originalError);\n }\n } else if (error instanceof Error) {\n // Check for specific error patterns\n if (error.message.includes(\"ENOENT\")) {\n console.error(\n \"\\n📁 File System Error: Required file or directory not found\"\n );\n console.error(` ${error.message}`);\n } else if (\n error.message.includes(\"EACCES\") ||\n error.message.includes(\"EPERM\")\n ) {\n console.error(\"\\n🚫 Permission Error: Insufficient permissions\");\n console.error(` ${error.message}`);\n if (error.message.includes(\".phoenix-insight\")) {\n console.error(\n ` Try running with appropriate permissions or check ~/.phoenix-insight/`\n );\n }\n } else if (\n error.message.includes(\"rate limit\") ||\n error.message.includes(\"429\")\n ) {\n console.error(\"\\n⏱️ Rate Limit Error: Too many requests to Phoenix\");\n console.error(` Please wait a moment and try again`);\n } else if (error.message.includes(\"timeout\")) {\n console.error(\"\\n⏰ Timeout Error: Request took too long\");\n console.error(` The Phoenix server might be slow or unresponsive`);\n } else {\n console.error(`\\n${error.message}`);\n }\n\n if (error.stack && process.env.DEBUG) {\n console.error(\"\\nStack trace:\", error.stack);\n }\n } else {\n console.error(\"\\nUnexpected error:\", error);\n }\n\n console.error(\"\\n💡 Tips:\");\n console.error(\" • Run with DEBUG=1 for more detailed error information\");\n console.error(\n \" • Check your Phoenix connection with: phoenix-insight snapshot --base-url <url>\"\n );\n console.error(\" • Use --help to see all available options\");\n\n process.exit(1);\n}\n\nprogram\n .name(\"phoenix-insight\")\n .description(\"A CLI for Phoenix data analysis with AI agents\")\n .version(VERSION)\n .usage(\"[options] [query]\")\n .option(\n \"--config <path>\",\n \"Path to config file (default: ~/.phoenix-insight/config.json, or set PHOENIX_INSIGHT_CONFIG env var)\"\n )\n .addHelpText(\n \"after\",\n `\nConfiguration:\n Config values are loaded with the following priority (highest to lowest):\n 1. CLI arguments (e.g., --base-url)\n 2. Environment variables (e.g., PHOENIX_BASE_URL)\n 3. Config file (~/.phoenix-insight/config.json)\n\n Use --config to specify a custom config file path.\n Set PHOENIX_INSIGHT_CONFIG env var to override the default config location.\n\nExamples:\n $ phoenix-insight # Start interactive mode\n $ phoenix-insight \"What are the slowest traces?\" # Single query (sandbox mode)\n $ phoenix-insight --interactive # Explicitly start interactive mode\n $ phoenix-insight --local \"Show me error patterns\" # Local mode with persistence\n $ phoenix-insight --local --stream \"Analyze recent experiments\" # Local mode with streaming\n $ phoenix-insight --config ./my-config.json \"Analyze traces\" # Use custom config file\n $ phoenix-insight ui # Start web UI on localhost:6007\n $ phoenix-insight ui --port 8080 # Start web UI on custom port\n $ phoenix-insight ui --no-open # Start web UI without opening browser\n $ opencode run \"Analyze my spans\" -f $(pxi snapshot latest)/_context.md # Analyze phoenix data with OpenCode agent\n $ phoenix-insight help # Show this help message\n`\n )\n .hook(\"preAction\", async (thisCommand) => {\n // Get all options from the root command\n const opts = thisCommand.opts();\n // Build CLI args from commander options\n const cliArgs: CliArgs = {\n config: opts.config,\n baseUrl: opts.baseUrl,\n apiKey: opts.apiKey,\n limit: opts.limit,\n stream: opts.stream,\n local: opts.local,\n refresh: opts.refresh,\n trace: opts.trace,\n };\n // Initialize config singleton before any command runs\n await initializeConfig(cliArgs);\n });\n\n/**\n * Shared logic for creating a snapshot.\n * Used by both 'phoenix-insight snapshot' and 'phoenix-insight snapshot create'.\n */\nasync function executeSnapshotCreate(): Promise<void> {\n const config = getConfig();\n\n // Initialize observability if trace is enabled in config\n if (config.trace) {\n initializeObservability({\n enabled: true,\n baseUrl: config.baseUrl,\n apiKey: config.apiKey,\n projectName: \"phoenix-insight-snapshot\",\n debug: !!process.env.DEBUG,\n });\n }\n\n try {\n // Determine the execution mode\n const mode: ExecutionMode = await createLocalMode();\n\n // Create snapshot with config values\n const snapshotOptions = {\n baseURL: config.baseUrl,\n apiKey: config.apiKey,\n spansPerProject: config.limit,\n showProgress: true,\n };\n\n await createSnapshot(mode, snapshotOptions);\n\n // Cleanup\n await mode.cleanup();\n\n // Shutdown observability if enabled\n await shutdownObservability();\n } catch (error) {\n handleError(error, \"creating snapshot\");\n }\n}\n\n// Create snapshot command group\nconst snapshotCmd = program\n .command(\"snapshot\")\n .description(\"Snapshot management commands\");\n\n// Default action for 'phoenix-insight snapshot' (backward compatibility alias for 'snapshot create')\nsnapshotCmd.action(async () => {\n await executeSnapshotCreate();\n});\n\n// Subcommand: snapshot create (explicit create command)\nsnapshotCmd\n .command(\"create\")\n .description(\"Create a new snapshot from Phoenix data\")\n .action(async () => {\n await executeSnapshotCreate();\n });\n\n// Subcommand: snapshot latest\nsnapshotCmd\n .command(\"latest\")\n .description(\"Print the absolute path to the latest snapshot directory\")\n .action(async () => {\n try {\n const latestSnapshot = await getLatestSnapshot();\n\n if (!latestSnapshot) {\n console.error(\"No snapshots found\");\n process.exit(1);\n }\n\n // Print only the path to stdout, no decoration\n console.log(latestSnapshot.path);\n } catch (error) {\n console.error(\n `Error: ${error instanceof Error ? error.message : String(error)}`\n );\n process.exit(1);\n }\n });\n\n// Subcommand: snapshot list\nsnapshotCmd\n .command(\"list\")\n .description(\"List all available snapshots with their timestamps\")\n .action(async () => {\n try {\n const snapshots = await listSnapshots();\n\n // Print each snapshot: <timestamp> <path>\n // Most recent first (already sorted by listSnapshots)\n for (const snapshot of snapshots) {\n // Format timestamp as ISO 8601\n const isoTimestamp = snapshot.timestamp.toISOString();\n console.log(`${isoTimestamp} ${snapshot.path}`);\n }\n\n // Exit code 0 even if empty (just print nothing)\n } catch (error) {\n console.error(\n `Error: ${error instanceof Error ? error.message : String(error)}`\n );\n process.exit(1);\n }\n });\n\nprogram\n .command(\"help\")\n .description(\"Show help information\")\n .action(() => {\n program.outputHelp();\n });\n\nprogram\n .command(\"prune\")\n .description(\n \"Delete the local snapshot directory (~/.phoenix-insight/snapshots)\"\n )\n .option(\"--dry-run\", \"Show what would be deleted without actually deleting\")\n .action(async (options) => {\n const snapshotDir = path.join(\n os.homedir(),\n \".phoenix-insight\",\n \"snapshots\"\n );\n\n try {\n // Check if the directory exists\n const stats = await fs.stat(snapshotDir).catch(() => null);\n\n if (!stats) {\n console.log(\"📁 No local snapshot directory found. Nothing to prune.\");\n return;\n }\n\n if (options.dryRun) {\n console.log(\"🔍 Dry run mode - would delete:\");\n console.log(` ${snapshotDir}`);\n\n // Show size and count of snapshots\n const snapshots = await fs.readdir(snapshotDir).catch(() => []);\n console.log(` 📊 Contains ${snapshots.length} snapshot(s)`);\n\n return;\n }\n\n // Ask for confirmation\n const rl = readline.createInterface({\n input: process.stdin,\n output: process.stdout,\n });\n\n const answer = await new Promise<string>((resolve) => {\n rl.question(\n `⚠️ This will delete all local snapshots at:\\n ${snapshotDir}\\n\\n Are you sure? (yes/no): `,\n resolve\n );\n });\n\n rl.close();\n\n if (answer.toLowerCase() !== \"yes\" && answer.toLowerCase() !== \"y\") {\n console.log(\"❌ Prune cancelled.\");\n return;\n }\n\n // Delete the directory\n await fs.rm(snapshotDir, { recursive: true, force: true });\n console.log(\"✅ Local snapshot directory deleted successfully!\");\n } catch (error) {\n console.error(\"❌ Error pruning snapshots:\");\n console.error(\n ` ${error instanceof Error ? error.message : String(error)}`\n );\n process.exit(1);\n }\n });\n\n// UI Command - starts web-based UI server\nprogram\n .command(\"ui\")\n .description(\"Start the web-based UI for interactive Phoenix analysis\")\n .option(\"--port <number>\", \"Port to run the UI server on\", parseInt)\n .option(\"--no-open\", \"Do not automatically open the browser\")\n .action(async (options) => {\n await runUIServer(options);\n });\n\nprogram\n .argument(\"[query]\", \"Query to run against Phoenix data\")\n .option(\n \"--sandbox\",\n \"Run in sandbox mode with in-memory filesystem (default)\"\n )\n .option(\"--local\", \"Run in local mode with real filesystem\")\n .option(\"--base-url <url>\", \"Phoenix base URL\")\n .option(\"--api-key <key>\", \"Phoenix API key\")\n .option(\"--refresh\", \"Force refresh of snapshot data\")\n .option(\"--limit <number>\", \"Limit number of spans to fetch\", parseInt)\n .option(\"--stream [true|false]\", \"Stream agent responses\", (v) =>\n [\"f\", \"false\"].includes(v.toLowerCase()) ? false : true\n )\n .option(\"-i, --interactive\", \"Run in interactive mode (REPL)\")\n .option(\"--trace\", \"Enable tracing of the agent to Phoenix\")\n .action(async (query, options) => {\n const config = getConfig();\n // If interactive mode is requested, ignore query argument\n if (options.interactive) {\n await runInteractiveMode();\n return;\n }\n\n // If no query is provided and no specific flag, start interactive mode\n if (!query && !options.help) {\n await runInteractiveMode();\n return;\n }\n\n // Ensure Anthropic API key is available for agent execution\n ensureAnthropicApiKey();\n\n // Initialize observability if trace is enabled in config\n if (config.trace) {\n initializeObservability({\n enabled: true,\n baseUrl: config.baseUrl,\n apiKey: config.apiKey,\n projectName: \"phoenix-insight\",\n debug: !!process.env.DEBUG,\n });\n }\n\n try {\n // Determine the execution mode\n const mode: ExecutionMode =\n config.mode === \"local\" ? await createLocalMode() : createSandboxMode();\n\n // Create Phoenix client\n const client = createPhoenixClient({\n baseURL: config.baseUrl,\n apiKey: config.apiKey,\n });\n\n // Create or update snapshot\n const snapshotOptions = {\n baseURL: config.baseUrl,\n apiKey: config.apiKey,\n spansPerProject: config.limit,\n showProgress: true,\n };\n\n if (config.refresh || config.mode !== \"local\") {\n // For sandbox mode (default) or when refresh is requested, always create a fresh snapshot\n await createSnapshot(mode, snapshotOptions);\n } else {\n // For local mode without refresh, try incremental update\n await createIncrementalSnapshot(mode, snapshotOptions);\n }\n\n // Create agent configuration\n const agentConfig: PhoenixInsightAgentConfig = {\n mode,\n client,\n maxSteps: 25,\n };\n\n // Execute the query\n const agentProgress = new AgentProgress(!config.stream);\n agentProgress.startThinking();\n\n if (config.stream) {\n // Stream mode\n const result = (await runOneShotQuery(agentConfig, query, {\n stream: true,\n onStepFinish: (step) => {\n // Show tool usage even in stream mode\n if (step.toolCalls?.length) {\n step.toolCalls.forEach((toolCall: any) => {\n const toolName = toolCall.toolName;\n if (toolName === \"bash\") {\n // Extract bash command for better visibility\n const command = toolCall.args?.command || \"\";\n const formattedCmd = formatBashCommand(command);\n agentProgress.updateTool(toolName, formattedCmd);\n } else {\n agentProgress.updateTool(toolName);\n }\n console.log();\n });\n }\n\n // Show tool results\n if (step.toolResults?.length) {\n step.toolResults.forEach((toolResult: any) => {\n agentProgress.updateToolResult(\n toolResult.toolName,\n !toolResult.isError\n );\n });\n console.log();\n }\n },\n })) as any; // Type assertion needed due to union type\n\n // Stop progress before streaming\n agentProgress.stop();\n\n // Handle streaming response\n console.log(\"\\n✨ Answer:\\n\");\n for await (const chunk of result.textStream) {\n process.stdout.write(chunk);\n }\n console.log(); // Final newline\n\n // Wait for full response to complete\n await result.response;\n } else {\n // Non-streaming mode\n const result = (await runOneShotQuery(agentConfig, query, {\n onStepFinish: (step) => {\n // Show tool usage\n if (step.toolCalls?.length) {\n step.toolCalls.forEach((toolCall: any) => {\n const toolName = toolCall.toolName;\n if (toolName === \"bash\") {\n // Extract bash command for better visibility\n const command = toolCall.args?.command || \"\";\n const formattedCmd = formatBashCommand(command);\n agentProgress.updateTool(toolName, formattedCmd);\n } else {\n agentProgress.updateTool(toolName);\n }\n });\n }\n\n // Show tool results\n if (step.toolResults?.length) {\n step.toolResults.forEach((toolResult: any) => {\n agentProgress.updateToolResult(\n toolResult.toolName,\n !toolResult.isError\n );\n });\n }\n },\n })) as any; // Type assertion needed due to union type\n\n // Stop progress and display the final answer\n agentProgress.succeed();\n console.log(\"\\n✨ Answer:\\n\");\n console.log(result.text);\n }\n\n // Cleanup\n await mode.cleanup();\n\n console.log(\"\\n✅ Done!\");\n } catch (error) {\n handleError(error, \"executing query\");\n } finally {\n // Shutdown observability if enabled\n await shutdownObservability();\n }\n });\n\n/**\n * Open a URL in the default browser\n */\nfunction openBrowser(url: string): void {\n const platform = process.platform;\n let command: string;\n\n if (platform === \"darwin\") {\n command = `open \"${url}\"`;\n } else if (platform === \"win32\") {\n command = `start \"\" \"${url}\"`;\n } else {\n // Linux and others - try xdg-open, fallback to sensible-browser\n command = `xdg-open \"${url}\" || sensible-browser \"${url}\"`;\n }\n\n exec(command, (error) => {\n if (error && process.env.DEBUG) {\n console.warn(`Could not open browser: ${error.message}`);\n }\n });\n}\n\n/**\n * Run the UI server with WebSocket support for agent interaction\n */\nasync function runUIServer(options: {\n port?: number;\n open?: boolean;\n}): Promise<void> {\n // Ensure Anthropic API key is available for agent execution\n ensureAnthropicApiKey();\n\n const config = getConfig();\n const port = options.port ?? 6007;\n const shouldOpen = options.open !== false; // Default to opening browser\n\n console.log(\"🚀 Starting Phoenix Insight UI...\\n\");\n\n // Initialize observability if trace is enabled in config\n if (config.trace) {\n initializeObservability({\n enabled: true,\n baseUrl: config.baseUrl,\n apiKey: config.apiKey,\n projectName: \"phoenix-insight-ui\",\n debug: !!process.env.DEBUG,\n });\n }\n\n try {\n // Determine the execution mode - UI always uses local mode for persistence\n const mode: ExecutionMode = await createLocalMode();\n\n // Create Phoenix client\n const client = createPhoenixClient({\n baseURL: config.baseUrl,\n apiKey: config.apiKey,\n });\n\n // Create snapshot with config values\n const snapshotOptions = {\n baseURL: config.baseUrl,\n apiKey: config.apiKey,\n spansPerProject: config.limit,\n showProgress: true,\n };\n\n // Always use incremental snapshot for UI to reuse existing data\n await createIncrementalSnapshot(mode, snapshotOptions);\n\n console.log(\"\\n✅ Snapshot ready.\\n\");\n\n // Create the UI HTTP server\n const uiServer = await createUIServer({ port, host: \"127.0.0.1\" });\n\n // Create the WebSocket server and attach to HTTP server\n const sessionManager = createSessionManager({\n mode,\n client,\n maxSteps: 25,\n });\n\n const wsServer = createWebSocketServer(uiServer.httpServer, {\n path: \"/ws\",\n onConnection: (ws: WebSocket) => {\n if (process.env.DEBUG) {\n console.log(\"WebSocket client connected\");\n }\n },\n onDisconnection: async (ws: WebSocket, code, reason) => {\n if (process.env.DEBUG) {\n console.log(`WebSocket client disconnected: ${code} ${reason}`);\n }\n // Clean up the session when client disconnects\n await sessionManager.removeSession(ws);\n },\n onMessage: async (message, ws) => {\n if (message.type === \"query\") {\n const { content, sessionId: clientSessionId } = message.payload;\n const sessionId = clientSessionId ?? `session-${Date.now()}`;\n\n // Get or create session for this client\n const session = sessionManager.getOrCreateSession(\n ws,\n sessionId,\n (msg) => wsServer.sendToClient(ws, msg)\n );\n\n // Execute the query (this is async but we don't await - let it stream)\n session.executeQuery(content).catch((error) => {\n console.error(\"Error executing query:\", error);\n wsServer.sendToClient(ws, {\n type: \"error\",\n payload: {\n message:\n error instanceof Error\n ? error.message\n : \"An error occurred while executing the query\",\n sessionId,\n },\n });\n });\n } else if (message.type === \"cancel\") {\n const session = sessionManager.getSessionForClient(ws);\n if (session) {\n session.cancel();\n }\n }\n },\n onError: (error, ws) => {\n console.error(\"WebSocket error:\", error.message);\n },\n });\n\n const url = `http://localhost:${uiServer.port}`;\n\n console.log(\"🌐 Phoenix Insight UI is running!\");\n console.log(` Local: ${url}`);\n console.log(\"\\n💡 Press Ctrl+C to stop the server\\n\");\n\n // Open browser if not disabled\n if (shouldOpen) {\n openBrowser(url);\n }\n\n // Handle graceful shutdown with timeout\n let isShuttingDown = false;\n const SHUTDOWN_TIMEOUT_MS = 3000;\n\n const shutdown = async (signal: string) => {\n if (isShuttingDown) return;\n isShuttingDown = true;\n\n console.log(`\\n\\n📥 Received ${signal}, shutting down gracefully...`);\n\n // Set up a timeout to force exit if graceful shutdown takes too long\n const forceExitTimeout = setTimeout(() => {\n console.log(\"⏱️ Shutdown timeout reached, forcing exit...\");\n wsServer.forceClose();\n uiServer.forceClose();\n process.exit(0);\n }, SHUTDOWN_TIMEOUT_MS);\n\n try {\n // Close WebSocket connections first\n await wsServer.close();\n\n // Close the UI server\n await uiServer.close();\n\n // Clean up sessions\n await sessionManager.cleanup();\n\n // Clean up execution mode\n await mode.cleanup();\n\n // Shutdown observability if enabled\n await shutdownObservability();\n\n clearTimeout(forceExitTimeout);\n console.log(\"👋 Server stopped. Goodbye!\");\n process.exit(0);\n } catch (error) {\n clearTimeout(forceExitTimeout);\n console.error(\"Error during shutdown:\", error);\n process.exit(1);\n }\n };\n\n process.on(\"SIGINT\", () => shutdown(\"SIGINT\"));\n process.on(\"SIGTERM\", () => shutdown(\"SIGTERM\"));\n\n // Keep the process running\n await new Promise(() => {\n // This promise never resolves - server runs until SIGINT/SIGTERM\n });\n } catch (error) {\n handleError(error, \"starting UI server\");\n }\n}\n\nasync function runInteractiveMode(): Promise<void> {\n // Ensure Anthropic API key is available for agent execution\n ensureAnthropicApiKey();\n\n const config = getConfig();\n\n console.log(\"🚀 Phoenix Insight Interactive Mode\");\n console.log(\n \"Type your queries below. Type 'help' for available commands or 'exit' to quit.\\n\"\n );\n\n // Prevent the process from exiting on unhandled promise rejections\n process.on(\"unhandledRejection\", (reason, promise) => {\n console.error(\"\\n⚠️ Unhandled promise rejection:\", reason);\n console.error(\n \"The interactive mode will continue. You can try another query.\"\n );\n });\n\n // Initialize observability if trace is enabled in config\n if (config.trace) {\n initializeObservability({\n enabled: true,\n baseUrl: config.baseUrl,\n apiKey: config.apiKey,\n projectName: \"phoenix-insight\",\n debug: !!process.env.DEBUG,\n });\n }\n\n // Setup mode and snapshot once for the session\n let mode: ExecutionMode;\n let agent: any;\n\n try {\n // Determine the execution mode\n mode =\n config.mode === \"local\" ? await createLocalMode() : createSandboxMode();\n\n // Create Phoenix client\n const client = createPhoenixClient({\n baseURL: config.baseUrl,\n apiKey: config.apiKey,\n });\n\n // Create or update snapshot\n const snapshotOptions = {\n baseURL: config.baseUrl,\n apiKey: config.apiKey,\n spansPerProject: config.limit,\n showProgress: true,\n };\n\n if (config.refresh || config.mode !== \"local\") {\n await createSnapshot(mode, snapshotOptions);\n } else {\n await createIncrementalSnapshot(mode, snapshotOptions);\n }\n\n console.log(\n \"\\n✅ Snapshot ready. You can now ask questions about your Phoenix data.\\n\"\n );\n\n // Create agent configuration\n const agentConfig: PhoenixInsightAgentConfig = {\n mode,\n client,\n maxSteps: 25,\n };\n\n // Create reusable agent\n agent = await createInsightAgent(agentConfig);\n\n // Setup readline interface\n const rl = readline.createInterface({\n input: process.stdin,\n output: process.stdout,\n prompt: \"phoenix> \",\n terminal: true, // Ensure terminal mode for better compatibility\n });\n\n let userExited = false;\n\n // Handle SIGINT (Ctrl+C) gracefully\n rl.on(\"SIGINT\", () => {\n if (userExited) {\n process.exit(0);\n }\n console.log(\n '\\n\\nUse \"exit\" to quit or press Ctrl+C again to force exit.'\n );\n userExited = true;\n rl.prompt();\n });\n\n // Helper function to process a single query\n const processQuery = async (query: string): Promise<boolean> => {\n if (query === \"exit\" || query === \"quit\") {\n return true; // Signal to exit\n }\n\n if (query === \"help\") {\n console.log(\"\\n📖 Interactive Mode Commands:\");\n console.log(\" help - Show this help message\");\n console.log(\" exit, quit - Exit interactive mode\");\n console.log(\n \" px-fetch-more - Fetch additional data (e.g., px-fetch-more spans --project <name> --limit <n>)\"\n );\n console.log(\"\\n💡 Usage Tips:\");\n console.log(\n \" • Ask natural language questions about your Phoenix data\"\n );\n console.log(\n \" • The agent has access to bash commands to analyze the data\"\n );\n console.log(\n \" • Use px-fetch-more commands to get additional data on-demand\"\n );\n console.log(\"\\n🔧 Options (set when starting phoenix-insight):\");\n console.log(\n \" --local - Use local mode with persistent storage\"\n );\n console.log(\n \" --stream - Stream agent responses in real-time\"\n );\n console.log(\" --refresh - Force fresh snapshot data\");\n console.log(\" --limit <n> - Set max spans per project\");\n console.log(\" --trace - Enable observability tracing\");\n return false;\n }\n\n if (query === \"\") {\n return false;\n }\n\n try {\n const agentProgress = new AgentProgress(!config.stream);\n agentProgress.startThinking();\n\n if (config.stream) {\n // Stream mode\n const result = await agent.stream(query, {\n onStepFinish: (step: any) => {\n // Show tool usage even in stream mode\n if (step.toolCalls?.length) {\n step.toolCalls.forEach((toolCall: any) => {\n const toolName = toolCall.toolName;\n if (toolName === \"bash\") {\n // Extract bash command for better visibility\n const command = toolCall.args?.command || \"\";\n const shortCmd = command.split(\"\\n\")[0].substring(0, 50);\n agentProgress.updateTool(\n toolName,\n shortCmd + (command.length > 50 ? \"...\" : \"\")\n );\n } else {\n agentProgress.updateTool(toolName);\n }\n });\n }\n\n // Show tool results\n if (step.toolResults?.length) {\n step.toolResults.forEach((toolResult: any) => {\n agentProgress.updateToolResult(\n toolResult.toolName,\n !toolResult.isError\n );\n });\n }\n },\n });\n\n // Stop progress before streaming\n agentProgress.stop();\n\n // Handle streaming response\n console.log(\"\\n✨ Answer:\\n\");\n for await (const chunk of result.textStream) {\n process.stdout.write(chunk);\n }\n console.log(); // Final newline\n\n // Wait for full response to complete\n await result.response;\n } else {\n // Non-streaming mode\n const result = await agent.generate(query, {\n onStepFinish: (step: any) => {\n // Show tool usage\n if (step.toolCalls?.length) {\n step.toolCalls.forEach((toolCall: any) => {\n const toolName = toolCall.toolName;\n if (toolName === \"bash\") {\n // Extract bash command for better visibility\n const command = toolCall.args?.command || \"\";\n const shortCmd = command.split(\"\\n\")[0].substring(0, 50);\n agentProgress.updateTool(\n toolName,\n shortCmd + (command.length > 50 ? \"...\" : \"\")\n );\n } else {\n agentProgress.updateTool(toolName);\n }\n });\n }\n\n // Show tool results\n if (step.toolResults?.length) {\n step.toolResults.forEach((toolResult: any) => {\n agentProgress.updateToolResult(\n toolResult.toolName,\n !toolResult.isError\n );\n });\n }\n },\n });\n\n // Stop progress and display the final answer\n agentProgress.succeed();\n console.log(\"\\n✨ Answer:\\n\");\n console.log(result.text);\n }\n\n console.log(\"\\n\" + \"─\".repeat(50) + \"\\n\");\n } catch (error) {\n console.error(\"\\n❌ Query Error:\");\n if (error instanceof PhoenixClientError) {\n console.error(` ${error.message}`);\n } else if (error instanceof Error) {\n console.error(` ${error.message}`);\n } else {\n console.error(` ${String(error)}`);\n }\n console.error(\" You can try again with a different query\\n\");\n }\n\n return false;\n };\n\n // Use event-based approach instead of async iterator to prevent\n // premature exit when ora/spinners interact with stdin\n await new Promise<void>((resolve) => {\n rl.on(\"line\", async (line) => {\n const query = line.trim();\n\n // Pause readline while processing to prevent queuing\n rl.pause();\n\n const shouldExit = await processQuery(query);\n\n if (shouldExit) {\n rl.close();\n } else {\n // Resume and show prompt for next input\n rl.resume();\n rl.prompt();\n }\n });\n\n rl.on(\"close\", () => {\n resolve();\n });\n\n // Show initial prompt\n rl.prompt();\n });\n\n console.log(\"\\n👋 Goodbye!\");\n\n // Cleanup\n await mode.cleanup();\n\n // Shutdown observability if enabled\n await shutdownObservability();\n } catch (error) {\n handleError(error, \"setting up interactive mode\");\n }\n}\n\nprogram.parse();\n","/**\n * Phoenix Insight AI agent setup using Vercel AI SDK\n */\n\nimport {\n generateText,\n streamText,\n tool,\n stepCountIs,\n type GenerateTextResult,\n type StreamTextResult,\n} from \"ai\";\nimport { anthropic } from \"@ai-sdk/anthropic\";\nimport { z } from \"zod\";\nimport type { ExecutionMode } from \"../modes/types.js\";\nimport { getInsightSystemPrompt } from \"../prompts/system.js\";\nimport {\n fetchMoreSpans,\n fetchMoreTrace,\n type FetchMoreSpansOptions,\n type FetchMoreTraceOptions,\n} from \"../commands/index.js\";\nimport type { PhoenixClient } from \"@arizeai/phoenix-client\";\n\n/**\n * Configuration for the Phoenix Insight agent\n */\nexport interface PhoenixInsightAgentConfig {\n /** The execution mode (sandbox or local) */\n mode: ExecutionMode;\n /** Phoenix client instance */\n client: PhoenixClient;\n /** Maximum number of agent steps before stopping (default: 25) */\n maxSteps?: number;\n /** Additional tools to include in the agent (e.g., report tool for UI mode) */\n additionalTools?: Record<string, any>;\n}\n\n/**\n * Phoenix Insight Agent\n */\nexport class PhoenixInsightAgent {\n private mode: ExecutionMode;\n private client: PhoenixClient;\n private maxSteps: number;\n private tools: Record<string, any> | null = null;\n private additionalTools: Record<string, any>;\n private model = anthropic(\"claude-sonnet-4-5\");\n private systemPrompt: string;\n\n constructor(config: PhoenixInsightAgentConfig) {\n this.mode = config.mode;\n this.client = config.client;\n this.maxSteps = config.maxSteps || 25;\n this.additionalTools = config.additionalTools || {};\n // Generate the system prompt with the snapshot root path from the mode\n this.systemPrompt = getInsightSystemPrompt(this.mode.getSnapshotRoot());\n }\n\n /**\n * Initialize the agent tools\n */\n private async initializeTools(): Promise<Record<string, any>> {\n if (this.tools) return this.tools;\n\n // Get the bash tool from the execution mode\n const bashTool = await this.mode.getBashTool();\n\n // Store references in closure for the custom tools\n const client = this.client;\n const mode = this.mode;\n\n // Create custom px-fetch-more-spans tool using AI SDK's tool function\n const pxFetchMoreSpans = tool({\n description:\n \"Fetch additional spans from Phoenix. Use when you need more span data than what's in the snapshot. You must provide both project name and optionally a limit.\",\n inputSchema: z.object({\n project: z.string().describe(\"The project name\"),\n limit: z\n .number()\n .optional()\n .describe(\"Number of spans to fetch (default: 500)\"),\n startTime: z\n .string()\n .optional()\n .describe(\"Start time filter in ISO format\"),\n endTime: z\n .string()\n .optional()\n .describe(\"End time filter in ISO format\"),\n }),\n execute: async (params) => {\n try {\n const options: FetchMoreSpansOptions = {\n project: params.project,\n limit: params.limit || 500,\n startTime: params.startTime,\n endTime: params.endTime,\n };\n\n await fetchMoreSpans(client, mode, options);\n\n return {\n success: true,\n message: `Fetched additional spans for project ${params.project}. Data saved to /phoenix/projects/${params.project}/spans/`,\n };\n } catch (error) {\n return {\n success: false,\n error: error instanceof Error ? error.message : String(error),\n };\n }\n },\n });\n\n // Create custom px-fetch-more-trace tool using AI SDK's tool function\n const pxFetchMoreTrace = tool({\n description:\n \"Fetch a specific trace by ID from Phoenix. Use when you need to examine a particular trace in detail. You must provide both the trace ID and the project name.\",\n inputSchema: z.object({\n traceId: z.string().describe(\"The trace ID to fetch\"),\n project: z.string().describe(\"The project name to search in\"),\n }),\n execute: async (params) => {\n try {\n const options: FetchMoreTraceOptions = {\n traceId: params.traceId,\n project: params.project,\n };\n\n await fetchMoreTrace(client, mode, options);\n\n return {\n success: true,\n message: `Fetched trace ${params.traceId}. Data saved to /phoenix/traces/${params.traceId}/`,\n };\n } catch (error) {\n return {\n success: false,\n error: error instanceof Error ? error.message : String(error),\n };\n }\n },\n });\n\n this.tools = {\n bash: bashTool,\n px_fetch_more_spans: pxFetchMoreSpans,\n px_fetch_more_trace: pxFetchMoreTrace,\n ...this.additionalTools,\n };\n\n return this.tools;\n }\n\n /**\n * Generate a response for a user query\n */\n async generate(\n userQuery: string,\n options?: {\n onStepFinish?: (step: any) => void;\n }\n ): Promise<GenerateTextResult<any, any>> {\n let tools;\n try {\n tools = await this.initializeTools();\n } catch (error) {\n throw new Error(\n `Failed to initialize agent tools: ${\n error instanceof Error ? error.message : String(error)\n }`\n );\n }\n\n try {\n const result = await generateText({\n model: this.model,\n system: this.systemPrompt,\n prompt: userQuery,\n tools,\n stopWhen: stepCountIs(this.maxSteps),\n onStepFinish: options?.onStepFinish,\n experimental_telemetry: {\n isEnabled: true,\n },\n });\n\n return result;\n } catch (error) {\n // Check for specific AI SDK errors\n if (error instanceof Error) {\n if (error.message.includes(\"rate limit\")) {\n throw new Error(\n \"AI model rate limit exceeded. Please wait and try again.\"\n );\n }\n if (error.message.includes(\"timeout\")) {\n throw new Error(\"AI model request timed out. Please try again.\");\n }\n if (\n error.message.includes(\"authentication\") ||\n error.message.includes(\"API key\")\n ) {\n throw new Error(\n \"AI model authentication failed. Check your API key configuration.\"\n );\n }\n }\n\n throw new Error(\n `AI generation failed: ${\n error instanceof Error ? error.message : String(error)\n }`\n );\n }\n }\n\n /**\n * Stream a response for a user query\n */\n async stream(\n userQuery: string,\n options?: {\n onStepFinish?: (step: any) => void;\n }\n ): Promise<StreamTextResult<any, any>> {\n let tools;\n try {\n tools = await this.initializeTools();\n } catch (error) {\n throw new Error(\n `Failed to initialize agent tools: ${\n error instanceof Error ? error.message : String(error)\n }`\n );\n }\n\n try {\n const result = streamText({\n model: this.model,\n system: this.systemPrompt,\n prompt: userQuery,\n tools,\n stopWhen: stepCountIs(this.maxSteps),\n onStepFinish: options?.onStepFinish,\n experimental_telemetry: {\n isEnabled: true,\n },\n });\n\n return result;\n } catch (error) {\n // Check for specific AI SDK errors\n if (error instanceof Error) {\n if (error.message.includes(\"rate limit\")) {\n throw new Error(\n \"AI model rate limit exceeded. Please wait and try again.\"\n );\n }\n if (error.message.includes(\"timeout\")) {\n throw new Error(\"AI model request timed out. Please try again.\");\n }\n if (\n error.message.includes(\"authentication\") ||\n error.message.includes(\"API key\")\n ) {\n throw new Error(\n \"AI model authentication failed. Check your API key configuration.\"\n );\n }\n }\n\n throw new Error(\n `AI streaming failed: ${\n error instanceof Error ? error.message : String(error)\n }`\n );\n }\n }\n\n /**\n * Clean up resources\n */\n async cleanup(): Promise<void> {\n await this.mode.cleanup();\n }\n}\n\n/**\n * Creates a Phoenix Insight agent\n */\nexport async function createInsightAgent(\n config: PhoenixInsightAgentConfig\n): Promise<PhoenixInsightAgent> {\n return new PhoenixInsightAgent(config);\n}\n\n/**\n * Run a query with the Phoenix Insight agent\n */\nexport async function runQuery(\n agent: PhoenixInsightAgent,\n userQuery: string,\n options?: {\n onStepFinish?: (step: any) => void;\n stream?: boolean;\n }\n): Promise<GenerateTextResult<any, any> | StreamTextResult<any, any>> {\n const { stream = false, ...callbacks } = options || {};\n\n if (stream) {\n return await agent.stream(userQuery, callbacks);\n } else {\n return await agent.generate(userQuery, callbacks);\n }\n}\n\n/**\n * Create and run a one-shot query\n */\nexport async function runOneShotQuery(\n config: PhoenixInsightAgentConfig,\n userQuery: string,\n options?: {\n onStepFinish?: (step: any) => void;\n stream?: boolean;\n }\n): Promise<GenerateTextResult<any, any> | StreamTextResult<any, any>> {\n const agent = await createInsightAgent(config);\n\n try {\n const result = await runQuery(agent, userQuery, options);\n return result;\n } finally {\n await agent.cleanup();\n }\n}\n","/**\n * System prompt for the Phoenix Insight AI agent\n * This prompt teaches the agent about the filesystem layout and available commands\n */\n\n/**\n * Generate the system prompt for the Phoenix Insight agent\n * @param snapshotRoot - The absolute path to the Phoenix snapshot root directory\n * @returns The system prompt string with the correct snapshot path\n */\nexport function getInsightSystemPrompt(snapshotRoot: string): string {\n return `You are an expert at analyzing Phoenix observability data.\n\n**START by reading ${snapshotRoot}/_context.md** - it contains a summary of what's available.\n\nYou have access to a bash shell with Phoenix data organized as files:\n\n${snapshotRoot}/\n _context.md - READ THIS FIRST: summary of available data\n /projects/{name}/spans/ - Span data (JSONL format, may be sampled)\n /datasets/ - Datasets and examples\n /experiments/ - Experiment runs and results\n /prompts/ - Prompt templates and versions\n\nUse commands like:\n- cat, head, tail: Read file contents \n- grep: Search for patterns\n- jq: Query and transform JSON/JSONL\n- ls, find: Navigate and discover data\n- sort, uniq, wc: Aggregate and count\n- awk: Complex text processing\n\nIf you need MORE data than what's in the snapshot:\n- px-fetch-more spans --project <name> --limit 500\n- px-fetch-more trace --trace-id <id>\n\nThis is a READ-ONLY snapshot. Start with _context.md, then explore to answer the question.`;\n}\n","import { createClient, type PhoenixClient } from \"@arizeai/phoenix-client\";\n\nexport class PhoenixClientError extends Error {\n public code:\n | \"NETWORK_ERROR\"\n | \"AUTH_ERROR\"\n | \"INVALID_RESPONSE\"\n | \"UNKNOWN_ERROR\";\n public originalError?: unknown;\n\n constructor(\n message: string,\n code: \"NETWORK_ERROR\" | \"AUTH_ERROR\" | \"INVALID_RESPONSE\" | \"UNKNOWN_ERROR\",\n originalError?: unknown\n ) {\n super(message);\n this.name = \"PhoenixClientError\";\n this.code = code;\n this.originalError = originalError;\n }\n}\n\nexport interface PhoenixClientConfig {\n baseURL?: string;\n apiKey?: string;\n}\n\n/**\n * Creates a wrapped Phoenix client with error handling\n */\nexport function createPhoenixClient(\n config: PhoenixClientConfig = {}\n): PhoenixClient {\n const headers: Record<string, string> = {};\n\n if (config.apiKey) {\n // Phoenix client expects Authorization header with Bearer token\n headers[\"Authorization\"] = `Bearer ${config.apiKey}`;\n }\n\n const clientOptions: Parameters<typeof createClient>[0] = {\n options: {\n baseUrl: config.baseURL,\n headers: Object.keys(headers).length > 0 ? headers : undefined,\n },\n };\n\n return createClient(clientOptions);\n}\n\n/**\n * Wraps an async operation with standardized error handling\n */\nexport async function withErrorHandling<T>(\n operation: () => Promise<T>,\n context: string\n): Promise<T> {\n try {\n return await operation();\n } catch (error) {\n // Network errors\n if (error instanceof TypeError && error.message.includes(\"fetch\")) {\n throw new PhoenixClientError(\n `Network error during ${context}: Unable to connect to Phoenix server`,\n \"NETWORK_ERROR\",\n error\n );\n }\n\n // HTTP errors from the middleware\n if (error instanceof Error && error.message.includes(\": \")) {\n const parts = error.message.split(\": \", 2);\n if (parts.length === 2 && parts[1]) {\n const [url, statusInfo] = parts;\n const statusParts = statusInfo.split(\" \");\n const statusCode = statusParts[0];\n const statusText = statusParts.slice(1).join(\" \");\n\n if (statusCode === \"401\" || statusCode === \"403\") {\n throw new PhoenixClientError(\n `Authentication error during ${context}: ${statusText}`,\n \"AUTH_ERROR\",\n error\n );\n }\n\n if (statusCode && statusCode.startsWith(\"4\")) {\n throw new PhoenixClientError(\n `Client error during ${context}: ${statusCode} ${statusText}`,\n \"INVALID_RESPONSE\",\n error\n );\n }\n\n if (statusCode && statusCode.startsWith(\"5\")) {\n throw new PhoenixClientError(\n `Server error during ${context}: ${statusCode} ${statusText}`,\n \"NETWORK_ERROR\",\n error\n );\n }\n }\n }\n\n // Unknown errors\n throw new PhoenixClientError(\n `Unexpected error during ${context}: ${\n error instanceof Error ? error.message : String(error)\n }`,\n \"UNKNOWN_ERROR\",\n error\n );\n }\n}\n\n/**\n * Helper to safely extract data from API responses\n */\nexport function extractData<T>(response: { data?: T; error?: unknown }): T {\n if (response.error) {\n throw response.error;\n }\n\n if (!response.data) {\n throw new PhoenixClientError(\n \"Invalid API response: missing data\",\n \"INVALID_RESPONSE\"\n );\n }\n\n return response.data;\n}\n","import type { PhoenixClient } from \"@arizeai/phoenix-client\";\nimport type { ExecutionMode } from \"../modes/types.js\";\nimport { withErrorHandling } from \"../snapshot/client.js\";\n\nexport interface FetchMoreSpansOptions {\n /** Project name to fetch spans for */\n project: string;\n /** Number of additional spans to fetch */\n limit: number;\n /** Inclusive lower bound time for filtering spans */\n startTime?: Date | string | null;\n /** Exclusive upper bound time for filtering spans */\n endTime?: Date | string | null;\n}\n\ninterface SpanData {\n id: string;\n name: string;\n context: {\n trace_id: string;\n span_id: string;\n };\n span_kind: string;\n parent_id: string | null;\n start_time: string;\n end_time: string;\n status_code: string;\n status_message: string;\n attributes: Record<string, unknown>;\n events: Array<unknown>;\n}\n\ninterface SpansMetadata {\n project: string;\n spanCount: number;\n startTime: string | null;\n endTime: string | null;\n snapshotTime: string;\n lastCursor?: string | null;\n}\n\n/**\n * Fetches additional spans for a specific project on-demand\n *\n * @param client - Phoenix client instance\n * @param mode - Execution mode for file operations\n * @param options - Options for fetching spans\n */\nexport async function fetchMoreSpans(\n client: PhoenixClient,\n mode: ExecutionMode,\n options: FetchMoreSpansOptions\n): Promise<void> {\n const { project, limit, startTime, endTime } = options;\n\n await withErrorHandling(async () => {\n // Try to read existing metadata to get the last cursor\n let existingMetadata: SpansMetadata | null = null;\n let existingSpans: SpanData[] = [];\n\n try {\n const metadataResult = await mode.exec(\n `cat /phoenix/projects/${project}/spans/metadata.json`\n );\n if (metadataResult.exitCode === 0 && metadataResult.stdout) {\n existingMetadata = JSON.parse(metadataResult.stdout);\n }\n } catch (error) {\n // Metadata doesn't exist, that's okay\n }\n\n // Try to read existing spans\n try {\n const spansResult = await mode.exec(\n `cat /phoenix/projects/${project}/spans/index.jsonl`\n );\n if (spansResult.exitCode === 0 && spansResult.stdout) {\n existingSpans = spansResult.stdout\n .trim()\n .split(\"\\n\")\n .filter((line) => line.length > 0)\n .map((line) => JSON.parse(line) as SpanData);\n }\n } catch (error) {\n // Spans file doesn't exist, that's okay\n }\n\n // Fetch new spans\n const newSpans: SpanData[] = [];\n let cursor: string | null = existingMetadata?.lastCursor ?? null;\n let totalFetched = 0;\n\n while (totalFetched < limit) {\n const query: Record<string, any> = {\n limit: Math.min(100, limit - totalFetched), // Fetch in chunks of 100\n };\n\n if (cursor) {\n query.cursor = cursor;\n }\n\n if (startTime) {\n query.start_time =\n startTime instanceof Date ? startTime.toISOString() : startTime;\n }\n\n if (endTime) {\n query.end_time =\n endTime instanceof Date ? endTime.toISOString() : endTime;\n }\n\n const response = await client.GET(\n \"/v1/projects/{project_identifier}/spans\",\n {\n params: {\n path: {\n project_identifier: project,\n },\n query,\n },\n }\n );\n\n if (response.error) throw response.error;\n\n const data = response.data?.data ?? [];\n newSpans.push(...(data as SpanData[]));\n totalFetched += data.length;\n\n cursor = response.data?.next_cursor ?? null;\n\n // Stop if there's no more data\n if (!cursor || data.length === 0) {\n break;\n }\n }\n\n // Combine existing and new spans\n const allSpans = [...existingSpans, ...newSpans];\n\n // Write updated spans to JSONL file\n const jsonlContent = allSpans\n .map((span) => JSON.stringify(span))\n .join(\"\\n\");\n await mode.writeFile(\n `/phoenix/projects/${project}/spans/index.jsonl`,\n jsonlContent\n );\n\n // Update metadata\n const metadata: SpansMetadata = {\n project,\n spanCount: allSpans.length,\n startTime:\n startTime instanceof Date\n ? startTime.toISOString()\n : (startTime ?? null),\n endTime:\n endTime instanceof Date ? endTime.toISOString() : (endTime ?? null),\n snapshotTime: new Date().toISOString(),\n lastCursor: cursor,\n };\n\n await mode.writeFile(\n `/phoenix/projects/${project}/spans/metadata.json`,\n JSON.stringify(metadata, null, 2)\n );\n\n console.log(\n `Fetched ${newSpans.length} additional spans for project \"${project}\"`\n );\n console.log(`Total spans for project: ${allSpans.length}`);\n }, `fetching more spans for project ${project}`);\n}\n","import type { PhoenixClient } from \"@arizeai/phoenix-client\";\nimport type { ExecutionMode } from \"../modes/types.js\";\nimport { withErrorHandling } from \"../snapshot/client.js\";\n\nexport interface FetchMoreTraceOptions {\n /** Trace ID to fetch all spans for */\n traceId: string;\n /** Project name to search in */\n project: string;\n}\n\ninterface SpanData {\n id: string;\n name: string;\n context: {\n trace_id: string;\n span_id: string;\n };\n span_kind: string;\n parent_id: string | null;\n start_time: string;\n end_time: string;\n status_code: string;\n status_message: string;\n attributes: Record<string, unknown>;\n events: Array<unknown>;\n}\n\n/**\n * Fetches all spans for a specific trace ID\n *\n * @param client - Phoenix client instance\n * @param mode - Execution mode for file operations\n * @param options - Options for fetching trace\n */\nexport async function fetchMoreTrace(\n client: PhoenixClient,\n mode: ExecutionMode,\n options: FetchMoreTraceOptions\n): Promise<void> {\n const { traceId, project } = options;\n\n await withErrorHandling(async () => {\n // First, check if the project exists in our snapshot\n const projectsResult = await mode.exec(\"cat /phoenix/projects/index.jsonl\");\n if (projectsResult.exitCode !== 0 || !projectsResult.stdout) {\n console.error(\"No projects found in snapshot. Run a snapshot first.\");\n return;\n }\n\n const projectNames = projectsResult.stdout\n .trim()\n .split(\"\\n\")\n .filter((line) => line.length > 0)\n .map((line) => JSON.parse(line).name);\n\n if (!projectNames.includes(project)) {\n console.error(\n `Project \"${project}\" not found. Available projects: ${projectNames.join(\n \", \"\n )}`\n );\n return;\n }\n\n // Fetch all spans that belong to this trace\n const traceSpans: SpanData[] = [];\n let cursor: string | null = null;\n let totalFetched = 0;\n\n console.log(`Fetching trace ${traceId} from project \"${project}\"...`);\n\n // We need to fetch spans in batches and filter by trace_id\n // Since the API doesn't support direct trace_id filtering\n while (true) {\n const query: Record<string, any> = {\n limit: 100, // Fetch in chunks\n };\n\n if (cursor) {\n query.cursor = cursor;\n }\n\n const response = await client.GET(\n \"/v1/projects/{project_identifier}/spans\",\n {\n params: {\n path: {\n project_identifier: project,\n },\n query,\n },\n }\n );\n\n if (response.error) throw response.error;\n\n const data = response.data?.data ?? [];\n totalFetched += data.length;\n\n // Filter spans that belong to our trace\n const matchingSpans = (data as SpanData[]).filter(\n (span) => span.context.trace_id === traceId\n );\n traceSpans.push(...matchingSpans);\n\n cursor = response.data?.next_cursor ?? null;\n\n // Stop if we found spans for the trace or no more data\n if (traceSpans.length > 0 || !cursor || data.length === 0) {\n // If we found some spans, continue until we have all spans from the trace\n // This is because trace spans might be spread across multiple pages\n if (traceSpans.length > 0 && cursor && data.length > 0) {\n console.log(\n `Found ${traceSpans.length} spans so far, continuing search...`\n );\n continue;\n }\n break;\n }\n\n // Show progress for large datasets\n if (totalFetched % 1000 === 0) {\n console.log(`Searched ${totalFetched} spans so far...`);\n }\n }\n\n if (traceSpans.length === 0) {\n console.log(\n `No spans found for trace ${traceId} in project \"${project}\"`\n );\n console.log(\n `Searched through ${totalFetched} spans. The trace might not exist or might be in a different project.`\n );\n return;\n }\n\n // Sort spans by start_time to show them in order\n traceSpans.sort(\n (a, b) =>\n new Date(a.start_time).getTime() - new Date(b.start_time).getTime()\n );\n\n // Write trace spans to a dedicated file\n const jsonlContent = traceSpans\n .map((span) => JSON.stringify(span))\n .join(\"\\n\");\n\n const traceDir = `/phoenix/traces/${traceId}`;\n await mode.writeFile(`${traceDir}/spans.jsonl`, jsonlContent);\n\n // Create trace metadata\n const rootSpan = traceSpans.find((span) => !span.parent_id);\n const firstSpan = traceSpans[0];\n const lastSpan = traceSpans[traceSpans.length - 1];\n const metadata = {\n traceId,\n project,\n spanCount: traceSpans.length,\n rootSpan: rootSpan ? { id: rootSpan.id, name: rootSpan.name } : null,\n startTime: firstSpan?.start_time || null,\n endTime: lastSpan?.end_time || null,\n duration:\n firstSpan && lastSpan\n ? new Date(lastSpan.end_time).getTime() -\n new Date(firstSpan.start_time).getTime()\n : 0,\n snapshotTime: new Date().toISOString(),\n };\n\n await mode.writeFile(\n `${traceDir}/metadata.json`,\n JSON.stringify(metadata, null, 2)\n );\n\n console.log(`\\nSuccessfully fetched trace ${traceId}:`);\n console.log(`- Project: ${project}`);\n console.log(`- Spans: ${traceSpans.length}`);\n console.log(`- Root span: ${rootSpan?.name || \"Unknown\"}`);\n console.log(`- Duration: ${(metadata.duration / 1000).toFixed(2)} seconds`);\n console.log(`\\nTrace data saved to: ${traceDir}/`);\n }, `fetching trace ${traceId}`);\n}\n","/**\n * Report Tool for Phoenix Insight AI Agent\n *\n * AI SDK tool that allows the agent to update the UI report panel.\n * The agent calls `generate_report` with a title and JSON-Render tree content,\n * which is validated against the catalog schema and broadcast to the UI client.\n */\n\nimport { tool } from \"ai\";\nimport { z } from \"zod\";\nimport type { ReportCallback } from \"../server/session.js\";\n\n// Import component schemas and catalog from UI package (single source of truth)\nimport {\n catalog,\n CardSchema,\n ChartSchema,\n TextSchema,\n HeadingSchema,\n ListSchema,\n TableSchema,\n MetricSchema,\n BadgeSchema,\n AlertSchema,\n SeparatorSchema,\n CodeSchema,\n} from \"@cephalization/phoenix-insight-ui/catalog\";\n\n/**\n * UIElement schema - a single element in the render tree\n * Kept in CLI for tool-specific validation needs\n */\nconst UIElementSchema = z.object({\n key: z.string(),\n type: z.enum([\n \"Card\",\n \"Chart\",\n \"Text\",\n \"Heading\",\n \"List\",\n \"Table\",\n \"Metric\",\n \"Badge\",\n \"Alert\",\n \"Separator\",\n \"Code\",\n ]),\n props: z.record(z.string(), z.unknown()),\n children: z.array(z.string()).optional(),\n parentKey: z.string().optional(),\n});\n\n/**\n * UITree schema - the full JSON-Render tree structure\n */\nconst UITreeSchema = z.object({\n root: z.string(),\n elements: z.record(z.string(), UIElementSchema),\n});\n\n/**\n * Inferred UIElement type\n */\ntype UIElement = z.infer<typeof UIElementSchema>;\n\n/**\n * Inferred UITree type\n */\ntype UITree = z.infer<typeof UITreeSchema>;\n\n// ============================================================================\n// Report Tool Types\n// ============================================================================\n\n/**\n * Report tool input type\n */\nexport interface ReportToolInput {\n title?: string;\n content: UITree;\n}\n\n/**\n * Report tool result type\n */\nexport interface ReportToolResult {\n success: boolean;\n message?: string;\n error?: string;\n}\n\n// ============================================================================\n// Validation Helpers\n// ============================================================================\n\n/**\n * Valid component types\n */\nconst VALID_COMPONENT_TYPES = [\n \"Card\",\n \"Chart\",\n \"Text\",\n \"Heading\",\n \"List\",\n \"Table\",\n \"Metric\",\n \"Badge\",\n \"Alert\",\n \"Separator\",\n \"Code\",\n] as const;\n\ntype ComponentType = (typeof VALID_COMPONENT_TYPES)[number];\n\n/**\n * Get the props schema for a specific component type\n */\nfunction getPropsSchemaForType(\n type: ComponentType\n): z.ZodType<Record<string, unknown>> {\n switch (type) {\n case \"Card\":\n return CardSchema;\n case \"Chart\":\n return ChartSchema;\n case \"Text\":\n return TextSchema;\n case \"Heading\":\n return HeadingSchema;\n case \"List\":\n return ListSchema;\n case \"Table\":\n return TableSchema;\n case \"Metric\":\n return MetricSchema;\n case \"Badge\":\n return BadgeSchema;\n case \"Alert\":\n return AlertSchema;\n case \"Separator\":\n return SeparatorSchema;\n case \"Code\":\n return CodeSchema;\n }\n}\n\n/**\n * Validate a UITree content against the json-render catalog schema\n * Returns an object with success status and optional error message\n */\nexport function validateReportContent(content: unknown): {\n success: boolean;\n error?: string;\n} {\n // First, validate the tree structure\n const treeResult = UITreeSchema.safeParse(content);\n if (!treeResult.success) {\n return {\n success: false,\n error: `Invalid tree structure: ${treeResult.error.message}`,\n };\n }\n\n const tree = treeResult.data;\n\n // Verify root element exists\n if (!tree.elements[tree.root]) {\n return {\n success: false,\n error: `Root element \"${tree.root}\" not found in elements`,\n };\n }\n\n // Validate each element's props against its component schema\n for (const [key, element] of Object.entries(tree.elements)) {\n const type = element.type as ComponentType;\n\n if (!VALID_COMPONENT_TYPES.includes(type)) {\n return {\n success: false,\n error: `Unknown component type \"${type}\" for element \"${key}\"`,\n };\n }\n\n const propsSchema = getPropsSchemaForType(type);\n const propsResult = propsSchema.safeParse(element.props);\n\n if (!propsResult.success) {\n return {\n success: false,\n error: `Invalid props for ${type} element \"${key}\": ${propsResult.error.message}`,\n };\n }\n\n // Validate children references if present\n if (element.children) {\n for (const childKey of element.children) {\n if (!tree.elements[childKey]) {\n return {\n success: false,\n error: `Child element \"${childKey}\" not found for parent \"${key}\"`,\n };\n }\n }\n }\n\n // Validate parent reference if present\n if (element.parentKey && !tree.elements[element.parentKey]) {\n return {\n success: false,\n error: `Parent element \"${element.parentKey}\" not found for element \"${key}\"`,\n };\n }\n }\n\n return { success: true };\n}\n\n// ============================================================================\n// Dynamic Component Documentation\n// ============================================================================\n\n/**\n * Extract prop names from a Zod object schema\n * Returns array of prop names with \"?\" suffix for optional props\n */\nfunction extractPropNames(schema: z.ZodTypeAny): string[] {\n // Handle ZodObject schemas\n if (schema instanceof z.ZodObject) {\n const shape = schema.shape;\n return Object.entries(shape).map(([key, value]) => {\n // Check if the prop is optional\n const isOptional = value instanceof z.ZodOptional || \n value instanceof z.ZodNullable ||\n (value as z.ZodTypeAny).isOptional?.();\n return isOptional ? `${key}?` : key;\n });\n }\n return [];\n}\n\n/**\n * Generate component documentation from the catalog\n * Iterates over catalog.components and builds a description string\n */\nexport function generateComponentDocs(\n catalogDef: typeof catalog\n): string {\n const lines: string[] = [];\n \n for (const [name, component] of Object.entries(catalogDef.components)) {\n const propNames = extractPropNames(component.props);\n const propsStr = propNames.length > 0 ? `props: ${propNames.join(\", \")}` : \"no props\";\n const childrenNote = component.hasChildren ? \"; can have children\" : \"\";\n lines.push(`- ${name}: ${component.description} (${propsStr}${childrenNote})`);\n }\n \n return lines.join(\"\\n\");\n}\n\n// ============================================================================\n// Report Tool Factory\n// ============================================================================\n\n/**\n * Create the generate_report tool for the AI agent\n *\n * @param broadcast - Callback function to send report updates to the WebSocket client\n * @returns AI SDK tool definition for generate_report\n */\nexport function createReportTool(broadcast: ReportCallback) {\n const componentDocs = generateComponentDocs(catalog);\n \n return tool({\n description: `Generate or update a structured report that will be displayed in the UI report panel. \nThe report uses a JSON-Render tree format with the following component types:\n${componentDocs}\n\nThe tree structure has a 'root' key pointing to the root element and an 'elements' map of all elements.\nEach element has: key (unique id), type (component type), props (component-specific), children? (array of child keys).\n\nUse this tool when you want to present structured analysis results, metrics, tables, or formatted reports to the user.`,\n inputSchema: z.object({\n title: z\n .string()\n .optional()\n .describe(\"Optional title for the report displayed in the header\"),\n content: UITreeSchema.describe(\"The JSON-Render tree structure\"),\n }),\n execute: async (params: {\n title?: string;\n content: UITree;\n }): Promise<ReportToolResult> => {\n const { title, content } = params;\n\n // Validate content against catalog schema\n const validation = validateReportContent(content);\n if (!validation.success) {\n return {\n success: false,\n error: validation.error,\n };\n }\n\n // Broadcast the report to the WebSocket client\n try {\n broadcast(content, title);\n return {\n success: true,\n message: title\n ? `Report \"${title}\" generated successfully`\n : \"Report generated successfully\",\n };\n } catch (error) {\n return {\n success: false,\n error: `Failed to broadcast report: ${\n error instanceof Error ? error.message : String(error)\n }`,\n };\n }\n },\n });\n}\n","import { z } from \"zod\";\n\n/**\n * Dynamic value - can be a literal or a path reference to data model\n */\nexport type DynamicValue<T = unknown> = T | { path: string };\n\n/**\n * Dynamic string value\n */\nexport type DynamicString = DynamicValue<string>;\n\n/**\n * Dynamic number value\n */\nexport type DynamicNumber = DynamicValue<number>;\n\n/**\n * Dynamic boolean value\n */\nexport type DynamicBoolean = DynamicValue<boolean>;\n\n/**\n * Zod schema for dynamic values\n */\nexport const DynamicValueSchema = z.union([\n z.string(),\n z.number(),\n z.boolean(),\n z.null(),\n z.object({ path: z.string() }),\n]);\n\nexport const DynamicStringSchema = z.union([\n z.string(),\n z.object({ path: z.string() }),\n]);\n\nexport const DynamicNumberSchema = z.union([\n z.number(),\n z.object({ path: z.string() }),\n]);\n\nexport const DynamicBooleanSchema = z.union([\n z.boolean(),\n z.object({ path: z.string() }),\n]);\n\n/**\n * Base UI element structure for v2\n */\nexport interface UIElement<\n T extends string = string,\n P = Record<string, unknown>,\n> {\n /** Unique key for reconciliation */\n key: string;\n /** Component type from the catalog */\n type: T;\n /** Component props */\n props: P;\n /** Child element keys (flat structure) */\n children?: string[];\n /** Parent element key (null for root) */\n parentKey?: string | null;\n /** Visibility condition */\n visible?: VisibilityCondition;\n}\n\n/**\n * Visibility condition types\n */\nexport type VisibilityCondition =\n | boolean\n | { path: string }\n | { auth: \"signedIn\" | \"signedOut\" }\n | LogicExpression;\n\n/**\n * Logic expression for complex conditions\n */\nexport type LogicExpression =\n | { and: LogicExpression[] }\n | { or: LogicExpression[] }\n | { not: LogicExpression }\n | { path: string }\n | { eq: [DynamicValue, DynamicValue] }\n | { neq: [DynamicValue, DynamicValue] }\n | { gt: [DynamicValue<number>, DynamicValue<number>] }\n | { gte: [DynamicValue<number>, DynamicValue<number>] }\n | { lt: [DynamicValue<number>, DynamicValue<number>] }\n | { lte: [DynamicValue<number>, DynamicValue<number>] };\n\n/**\n * Flat UI tree structure (optimized for LLM generation)\n */\nexport interface UITree {\n /** Root element key */\n root: string;\n /** Flat map of elements by key */\n elements: Record<string, UIElement>;\n}\n\n/**\n * Auth state for visibility evaluation\n */\nexport interface AuthState {\n isSignedIn: boolean;\n user?: Record<string, unknown>;\n}\n\n/**\n * Data model type\n */\nexport type DataModel = Record<string, unknown>;\n\n/**\n * Component schema definition using Zod\n */\nexport type ComponentSchema = z.ZodType<Record<string, unknown>>;\n\n/**\n * Validation mode for catalog validation\n */\nexport type ValidationMode = \"strict\" | \"warn\" | \"ignore\";\n\n/**\n * JSON patch operation types\n */\nexport type PatchOp = \"add\" | \"remove\" | \"replace\" | \"set\";\n\n/**\n * JSON patch operation\n */\nexport interface JsonPatch {\n op: PatchOp;\n path: string;\n value?: unknown;\n}\n\n/**\n * Resolve a dynamic value against a data model\n */\nexport function resolveDynamicValue<T>(\n value: DynamicValue<T>,\n dataModel: DataModel,\n): T | undefined {\n if (value === null || value === undefined) {\n return undefined;\n }\n\n if (typeof value === \"object\" && \"path\" in value) {\n return getByPath(dataModel, value.path) as T | undefined;\n }\n\n return value as T;\n}\n\n/**\n * Get a value from an object by JSON Pointer path\n */\nexport function getByPath(obj: unknown, path: string): unknown {\n if (!path || path === \"/\") {\n return obj;\n }\n\n const segments = path.startsWith(\"/\")\n ? path.slice(1).split(\"/\")\n : path.split(\"/\");\n\n let current: unknown = obj;\n\n for (const segment of segments) {\n if (current === null || current === undefined) {\n return undefined;\n }\n\n if (typeof current === \"object\") {\n current = (current as Record<string, unknown>)[segment];\n } else {\n return undefined;\n }\n }\n\n return current;\n}\n\n/**\n * Set a value in an object by JSON Pointer path\n */\nexport function setByPath(\n obj: Record<string, unknown>,\n path: string,\n value: unknown,\n): void {\n const segments = path.startsWith(\"/\")\n ? path.slice(1).split(\"/\")\n : path.split(\"/\");\n\n if (segments.length === 0) return;\n\n let current: Record<string, unknown> = obj;\n\n for (let i = 0; i < segments.length - 1; i++) {\n const segment = segments[i]!;\n if (!(segment in current) || typeof current[segment] !== \"object\") {\n current[segment] = {};\n }\n current = current[segment] as Record<string, unknown>;\n }\n\n const lastSegment = segments[segments.length - 1]!;\n current[lastSegment] = value;\n}\n","import { z } from \"zod\";\nimport type {\n VisibilityCondition,\n LogicExpression,\n DataModel,\n AuthState,\n DynamicValue,\n} from \"./types\";\nimport { resolveDynamicValue, DynamicValueSchema } from \"./types\";\n\n// Dynamic value schema for comparisons (number-focused)\nconst DynamicNumberValueSchema = z.union([\n z.number(),\n z.object({ path: z.string() }),\n]);\n\n/**\n * Logic expression schema (recursive)\n * Using a more permissive schema that aligns with runtime behavior\n */\nexport const LogicExpressionSchema: z.ZodType<LogicExpression> = z.lazy(() =>\n z.union([\n z.object({ and: z.array(LogicExpressionSchema) }),\n z.object({ or: z.array(LogicExpressionSchema) }),\n z.object({ not: LogicExpressionSchema }),\n z.object({ path: z.string() }),\n z.object({ eq: z.tuple([DynamicValueSchema, DynamicValueSchema]) }),\n z.object({ neq: z.tuple([DynamicValueSchema, DynamicValueSchema]) }),\n z.object({\n gt: z.tuple([DynamicNumberValueSchema, DynamicNumberValueSchema]),\n }),\n z.object({\n gte: z.tuple([DynamicNumberValueSchema, DynamicNumberValueSchema]),\n }),\n z.object({\n lt: z.tuple([DynamicNumberValueSchema, DynamicNumberValueSchema]),\n }),\n z.object({\n lte: z.tuple([DynamicNumberValueSchema, DynamicNumberValueSchema]),\n }),\n ]),\n) as z.ZodType<LogicExpression>;\n\n/**\n * Visibility condition schema\n */\nexport const VisibilityConditionSchema: z.ZodType<VisibilityCondition> =\n z.union([\n z.boolean(),\n z.object({ path: z.string() }),\n z.object({ auth: z.enum([\"signedIn\", \"signedOut\"]) }),\n LogicExpressionSchema,\n ]);\n\n/**\n * Context for evaluating visibility\n */\nexport interface VisibilityContext {\n dataModel: DataModel;\n authState?: AuthState;\n}\n\n/**\n * Evaluate a logic expression against data and auth state\n */\nexport function evaluateLogicExpression(\n expr: LogicExpression,\n ctx: VisibilityContext,\n): boolean {\n const { dataModel } = ctx;\n\n // AND expression\n if (\"and\" in expr) {\n return expr.and.every((subExpr) => evaluateLogicExpression(subExpr, ctx));\n }\n\n // OR expression\n if (\"or\" in expr) {\n return expr.or.some((subExpr) => evaluateLogicExpression(subExpr, ctx));\n }\n\n // NOT expression\n if (\"not\" in expr) {\n return !evaluateLogicExpression(expr.not, ctx);\n }\n\n // Path expression (resolve to boolean)\n if (\"path\" in expr) {\n const value = resolveDynamicValue({ path: expr.path }, dataModel);\n return Boolean(value);\n }\n\n // Equality comparison\n if (\"eq\" in expr) {\n const [left, right] = expr.eq;\n const leftValue = resolveDynamicValue(left, dataModel);\n const rightValue = resolveDynamicValue(right, dataModel);\n return leftValue === rightValue;\n }\n\n // Not equal comparison\n if (\"neq\" in expr) {\n const [left, right] = expr.neq;\n const leftValue = resolveDynamicValue(left, dataModel);\n const rightValue = resolveDynamicValue(right, dataModel);\n return leftValue !== rightValue;\n }\n\n // Greater than\n if (\"gt\" in expr) {\n const [left, right] = expr.gt;\n const leftValue = resolveDynamicValue(\n left as DynamicValue<number>,\n dataModel,\n );\n const rightValue = resolveDynamicValue(\n right as DynamicValue<number>,\n dataModel,\n );\n if (typeof leftValue === \"number\" && typeof rightValue === \"number\") {\n return leftValue > rightValue;\n }\n return false;\n }\n\n // Greater than or equal\n if (\"gte\" in expr) {\n const [left, right] = expr.gte;\n const leftValue = resolveDynamicValue(\n left as DynamicValue<number>,\n dataModel,\n );\n const rightValue = resolveDynamicValue(\n right as DynamicValue<number>,\n dataModel,\n );\n if (typeof leftValue === \"number\" && typeof rightValue === \"number\") {\n return leftValue >= rightValue;\n }\n return false;\n }\n\n // Less than\n if (\"lt\" in expr) {\n const [left, right] = expr.lt;\n const leftValue = resolveDynamicValue(\n left as DynamicValue<number>,\n dataModel,\n );\n const rightValue = resolveDynamicValue(\n right as DynamicValue<number>,\n dataModel,\n );\n if (typeof leftValue === \"number\" && typeof rightValue === \"number\") {\n return leftValue < rightValue;\n }\n return false;\n }\n\n // Less than or equal\n if (\"lte\" in expr) {\n const [left, right] = expr.lte;\n const leftValue = resolveDynamicValue(\n left as DynamicValue<number>,\n dataModel,\n );\n const rightValue = resolveDynamicValue(\n right as DynamicValue<number>,\n dataModel,\n );\n if (typeof leftValue === \"number\" && typeof rightValue === \"number\") {\n return leftValue <= rightValue;\n }\n return false;\n }\n\n return false;\n}\n\n/**\n * Evaluate a visibility condition\n */\nexport function evaluateVisibility(\n condition: VisibilityCondition | undefined,\n ctx: VisibilityContext,\n): boolean {\n // No condition = visible\n if (condition === undefined) {\n return true;\n }\n\n // Boolean literal\n if (typeof condition === \"boolean\") {\n return condition;\n }\n\n // Path reference\n if (\"path\" in condition && !(\"and\" in condition) && !(\"or\" in condition)) {\n const value = resolveDynamicValue({ path: condition.path }, ctx.dataModel);\n return Boolean(value);\n }\n\n // Auth condition\n if (\"auth\" in condition) {\n const isSignedIn = ctx.authState?.isSignedIn ?? false;\n if (condition.auth === \"signedIn\") {\n return isSignedIn;\n }\n if (condition.auth === \"signedOut\") {\n return !isSignedIn;\n }\n return false;\n }\n\n // Logic expression\n return evaluateLogicExpression(condition as LogicExpression, ctx);\n}\n\n/**\n * Helper to create visibility conditions\n */\nexport const visibility = {\n /** Always visible */\n always: true as const,\n\n /** Never visible */\n never: false as const,\n\n /** Visible when path is truthy */\n when: (path: string): VisibilityCondition => ({ path }),\n\n /** Visible when signed in */\n signedIn: { auth: \"signedIn\" } as const,\n\n /** Visible when signed out */\n signedOut: { auth: \"signedOut\" } as const,\n\n /** AND multiple conditions */\n and: (...conditions: LogicExpression[]): LogicExpression => ({\n and: conditions,\n }),\n\n /** OR multiple conditions */\n or: (...conditions: LogicExpression[]): LogicExpression => ({\n or: conditions,\n }),\n\n /** NOT a condition */\n not: (condition: LogicExpression): LogicExpression => ({ not: condition }),\n\n /** Equality check */\n eq: (left: DynamicValue, right: DynamicValue): LogicExpression => ({\n eq: [left, right],\n }),\n\n /** Not equal check */\n neq: (left: DynamicValue, right: DynamicValue): LogicExpression => ({\n neq: [left, right],\n }),\n\n /** Greater than */\n gt: (\n left: DynamicValue<number>,\n right: DynamicValue<number>,\n ): LogicExpression => ({ gt: [left, right] }),\n\n /** Greater than or equal */\n gte: (\n left: DynamicValue<number>,\n right: DynamicValue<number>,\n ): LogicExpression => ({ gte: [left, right] }),\n\n /** Less than */\n lt: (\n left: DynamicValue<number>,\n right: DynamicValue<number>,\n ): LogicExpression => ({ lt: [left, right] }),\n\n /** Less than or equal */\n lte: (\n left: DynamicValue<number>,\n right: DynamicValue<number>,\n ): LogicExpression => ({ lte: [left, right] }),\n};\n","import { z } from \"zod\";\nimport type { DynamicValue, DataModel } from \"./types\";\nimport { DynamicValueSchema, resolveDynamicValue } from \"./types\";\n\n/**\n * Confirmation dialog configuration\n */\nexport interface ActionConfirm {\n title: string;\n message: string;\n confirmLabel?: string;\n cancelLabel?: string;\n variant?: \"default\" | \"danger\";\n}\n\n/**\n * Action success handler\n */\nexport type ActionOnSuccess =\n | { navigate: string }\n | { set: Record<string, unknown> }\n | { action: string };\n\n/**\n * Action error handler\n */\nexport type ActionOnError =\n | { set: Record<string, unknown> }\n | { action: string };\n\n/**\n * Rich action definition\n */\nexport interface Action {\n /** Action name (must be in catalog) */\n name: string;\n /** Parameters to pass to the action handler */\n params?: Record<string, DynamicValue>;\n /** Confirmation dialog before execution */\n confirm?: ActionConfirm;\n /** Handler after successful execution */\n onSuccess?: ActionOnSuccess;\n /** Handler after failed execution */\n onError?: ActionOnError;\n}\n\n/**\n * Schema for action confirmation\n */\nexport const ActionConfirmSchema = z.object({\n title: z.string(),\n message: z.string(),\n confirmLabel: z.string().optional(),\n cancelLabel: z.string().optional(),\n variant: z.enum([\"default\", \"danger\"]).optional(),\n});\n\n/**\n * Schema for success handlers\n */\nexport const ActionOnSuccessSchema = z.union([\n z.object({ navigate: z.string() }),\n z.object({ set: z.record(z.string(), z.unknown()) }),\n z.object({ action: z.string() }),\n]);\n\n/**\n * Schema for error handlers\n */\nexport const ActionOnErrorSchema = z.union([\n z.object({ set: z.record(z.string(), z.unknown()) }),\n z.object({ action: z.string() }),\n]);\n\n/**\n * Full action schema\n */\nexport const ActionSchema = z.object({\n name: z.string(),\n params: z.record(z.string(), DynamicValueSchema).optional(),\n confirm: ActionConfirmSchema.optional(),\n onSuccess: ActionOnSuccessSchema.optional(),\n onError: ActionOnErrorSchema.optional(),\n});\n\n/**\n * Action handler function signature\n */\nexport type ActionHandler<\n TParams = Record<string, unknown>,\n TResult = unknown,\n> = (params: TParams) => Promise<TResult> | TResult;\n\n/**\n * Action definition in catalog\n */\nexport interface ActionDefinition<TParams = Record<string, unknown>> {\n /** Zod schema for params validation */\n params?: z.ZodType<TParams>;\n /** Description for AI */\n description?: string;\n}\n\n/**\n * Resolved action with all dynamic values resolved\n */\nexport interface ResolvedAction {\n name: string;\n params: Record<string, unknown>;\n confirm?: ActionConfirm;\n onSuccess?: ActionOnSuccess;\n onError?: ActionOnError;\n}\n\n/**\n * Resolve all dynamic values in an action\n */\nexport function resolveAction(\n action: Action,\n dataModel: DataModel,\n): ResolvedAction {\n const resolvedParams: Record<string, unknown> = {};\n\n if (action.params) {\n for (const [key, value] of Object.entries(action.params)) {\n resolvedParams[key] = resolveDynamicValue(value, dataModel);\n }\n }\n\n // Interpolate confirmation message if present\n let confirm = action.confirm;\n if (confirm) {\n confirm = {\n ...confirm,\n message: interpolateString(confirm.message, dataModel),\n title: interpolateString(confirm.title, dataModel),\n };\n }\n\n return {\n name: action.name,\n params: resolvedParams,\n confirm,\n onSuccess: action.onSuccess,\n onError: action.onError,\n };\n}\n\n/**\n * Interpolate ${path} expressions in a string\n */\nexport function interpolateString(\n template: string,\n dataModel: DataModel,\n): string {\n return template.replace(/\\$\\{([^}]+)\\}/g, (_, path) => {\n const value = resolveDynamicValue({ path }, dataModel);\n return String(value ?? \"\");\n });\n}\n\n/**\n * Context for action execution\n */\nexport interface ActionExecutionContext {\n /** The resolved action */\n action: ResolvedAction;\n /** The action handler from the host */\n handler: ActionHandler;\n /** Function to update data model */\n setData: (path: string, value: unknown) => void;\n /** Function to navigate */\n navigate?: (path: string) => void;\n /** Function to execute another action */\n executeAction?: (name: string) => Promise<void>;\n}\n\n/**\n * Execute an action with all callbacks\n */\nexport async function executeAction(\n ctx: ActionExecutionContext,\n): Promise<void> {\n const { action, handler, setData, navigate, executeAction } = ctx;\n\n try {\n await handler(action.params);\n\n // Handle success\n if (action.onSuccess) {\n if (\"navigate\" in action.onSuccess && navigate) {\n navigate(action.onSuccess.navigate);\n } else if (\"set\" in action.onSuccess) {\n for (const [path, value] of Object.entries(action.onSuccess.set)) {\n setData(path, value);\n }\n } else if (\"action\" in action.onSuccess && executeAction) {\n await executeAction(action.onSuccess.action);\n }\n }\n } catch (error) {\n // Handle error\n if (action.onError) {\n if (\"set\" in action.onError) {\n for (const [path, value] of Object.entries(action.onError.set)) {\n // Replace $error.message with actual error\n const resolvedValue =\n typeof value === \"string\" && value === \"$error.message\"\n ? (error as Error).message\n : value;\n setData(path, resolvedValue);\n }\n } else if (\"action\" in action.onError && executeAction) {\n await executeAction(action.onError.action);\n }\n } else {\n throw error;\n }\n }\n}\n\n/**\n * Helper to create actions\n */\nexport const action = {\n /** Create a simple action */\n simple: (name: string, params?: Record<string, DynamicValue>): Action => ({\n name,\n params,\n }),\n\n /** Create an action with confirmation */\n withConfirm: (\n name: string,\n confirm: ActionConfirm,\n params?: Record<string, DynamicValue>,\n ): Action => ({\n name,\n params,\n confirm,\n }),\n\n /** Create an action with success handler */\n withSuccess: (\n name: string,\n onSuccess: ActionOnSuccess,\n params?: Record<string, DynamicValue>,\n ): Action => ({\n name,\n params,\n onSuccess,\n }),\n};\n","import { z } from \"zod\";\nimport type { DynamicValue, DataModel, LogicExpression } from \"./types\";\nimport { DynamicValueSchema, resolveDynamicValue } from \"./types\";\nimport { LogicExpressionSchema, evaluateLogicExpression } from \"./visibility\";\n\n/**\n * Validation check definition\n */\nexport interface ValidationCheck {\n /** Function name (built-in or from catalog) */\n fn: string;\n /** Additional arguments for the function */\n args?: Record<string, DynamicValue>;\n /** Error message to display if check fails */\n message: string;\n}\n\n/**\n * Validation configuration for a field\n */\nexport interface ValidationConfig {\n /** Array of checks to run */\n checks?: ValidationCheck[];\n /** When to run validation */\n validateOn?: \"change\" | \"blur\" | \"submit\";\n /** Condition for when validation is enabled */\n enabled?: LogicExpression;\n}\n\n/**\n * Schema for validation check\n */\nexport const ValidationCheckSchema = z.object({\n fn: z.string(),\n args: z.record(z.string(), DynamicValueSchema).optional(),\n message: z.string(),\n});\n\n/**\n * Schema for validation config\n */\nexport const ValidationConfigSchema = z.object({\n checks: z.array(ValidationCheckSchema).optional(),\n validateOn: z.enum([\"change\", \"blur\", \"submit\"]).optional(),\n enabled: LogicExpressionSchema.optional(),\n});\n\n/**\n * Validation function signature\n */\nexport type ValidationFunction = (\n value: unknown,\n args?: Record<string, unknown>,\n) => boolean;\n\n/**\n * Validation function definition in catalog\n */\nexport interface ValidationFunctionDefinition {\n /** The validation function */\n validate: ValidationFunction;\n /** Description for AI */\n description?: string;\n}\n\n/**\n * Built-in validation functions\n */\nexport const builtInValidationFunctions: Record<string, ValidationFunction> = {\n /**\n * Check if value is not null, undefined, or empty string\n */\n required: (value: unknown) => {\n if (value === null || value === undefined) return false;\n if (typeof value === \"string\") return value.trim().length > 0;\n if (Array.isArray(value)) return value.length > 0;\n return true;\n },\n\n /**\n * Check if value is a valid email address\n */\n email: (value: unknown) => {\n if (typeof value !== \"string\") return false;\n return /^[^\\s@]+@[^\\s@]+\\.[^\\s@]+$/.test(value);\n },\n\n /**\n * Check minimum string length\n */\n minLength: (value: unknown, args?: Record<string, unknown>) => {\n if (typeof value !== \"string\") return false;\n const min = args?.min;\n if (typeof min !== \"number\") return false;\n return value.length >= min;\n },\n\n /**\n * Check maximum string length\n */\n maxLength: (value: unknown, args?: Record<string, unknown>) => {\n if (typeof value !== \"string\") return false;\n const max = args?.max;\n if (typeof max !== \"number\") return false;\n return value.length <= max;\n },\n\n /**\n * Check if string matches a regex pattern\n */\n pattern: (value: unknown, args?: Record<string, unknown>) => {\n if (typeof value !== \"string\") return false;\n const pattern = args?.pattern;\n if (typeof pattern !== \"string\") return false;\n try {\n return new RegExp(pattern).test(value);\n } catch {\n return false;\n }\n },\n\n /**\n * Check minimum numeric value\n */\n min: (value: unknown, args?: Record<string, unknown>) => {\n if (typeof value !== \"number\") return false;\n const min = args?.min;\n if (typeof min !== \"number\") return false;\n return value >= min;\n },\n\n /**\n * Check maximum numeric value\n */\n max: (value: unknown, args?: Record<string, unknown>) => {\n if (typeof value !== \"number\") return false;\n const max = args?.max;\n if (typeof max !== \"number\") return false;\n return value <= max;\n },\n\n /**\n * Check if value is a number\n */\n numeric: (value: unknown) => {\n if (typeof value === \"number\") return !isNaN(value);\n if (typeof value === \"string\") return !isNaN(parseFloat(value));\n return false;\n },\n\n /**\n * Check if value is a valid URL\n */\n url: (value: unknown) => {\n if (typeof value !== \"string\") return false;\n try {\n new URL(value);\n return true;\n } catch {\n return false;\n }\n },\n\n /**\n * Check if value matches another field\n */\n matches: (value: unknown, args?: Record<string, unknown>) => {\n const other = args?.other;\n return value === other;\n },\n};\n\n/**\n * Validation result for a single check\n */\nexport interface ValidationCheckResult {\n fn: string;\n valid: boolean;\n message: string;\n}\n\n/**\n * Full validation result for a field\n */\nexport interface ValidationResult {\n valid: boolean;\n errors: string[];\n checks: ValidationCheckResult[];\n}\n\n/**\n * Context for running validation\n */\nexport interface ValidationContext {\n /** Current value to validate */\n value: unknown;\n /** Full data model for resolving paths */\n dataModel: DataModel;\n /** Custom validation functions from catalog */\n customFunctions?: Record<string, ValidationFunction>;\n}\n\n/**\n * Run a single validation check\n */\nexport function runValidationCheck(\n check: ValidationCheck,\n ctx: ValidationContext,\n): ValidationCheckResult {\n const { value, dataModel, customFunctions } = ctx;\n\n // Resolve args\n const resolvedArgs: Record<string, unknown> = {};\n if (check.args) {\n for (const [key, argValue] of Object.entries(check.args)) {\n resolvedArgs[key] = resolveDynamicValue(argValue, dataModel);\n }\n }\n\n // Find the validation function\n const fn =\n builtInValidationFunctions[check.fn] ?? customFunctions?.[check.fn];\n\n if (!fn) {\n console.warn(`Unknown validation function: ${check.fn}`);\n return {\n fn: check.fn,\n valid: true, // Don't fail on unknown functions\n message: check.message,\n };\n }\n\n const valid = fn(value, resolvedArgs);\n\n return {\n fn: check.fn,\n valid,\n message: check.message,\n };\n}\n\n/**\n * Run all validation checks for a field\n */\nexport function runValidation(\n config: ValidationConfig,\n ctx: ValidationContext & { authState?: { isSignedIn: boolean } },\n): ValidationResult {\n const checks: ValidationCheckResult[] = [];\n const errors: string[] = [];\n\n // Check if validation is enabled\n if (config.enabled) {\n const enabled = evaluateLogicExpression(config.enabled, {\n dataModel: ctx.dataModel,\n authState: ctx.authState,\n });\n if (!enabled) {\n return { valid: true, errors: [], checks: [] };\n }\n }\n\n // Run each check\n if (config.checks) {\n for (const check of config.checks) {\n const result = runValidationCheck(check, ctx);\n checks.push(result);\n if (!result.valid) {\n errors.push(result.message);\n }\n }\n }\n\n return {\n valid: errors.length === 0,\n errors,\n checks,\n };\n}\n\n/**\n * Helper to create validation checks\n */\nexport const check = {\n required: (message = \"This field is required\"): ValidationCheck => ({\n fn: \"required\",\n message,\n }),\n\n email: (message = \"Invalid email address\"): ValidationCheck => ({\n fn: \"email\",\n message,\n }),\n\n minLength: (min: number, message?: string): ValidationCheck => ({\n fn: \"minLength\",\n args: { min },\n message: message ?? `Must be at least ${min} characters`,\n }),\n\n maxLength: (max: number, message?: string): ValidationCheck => ({\n fn: \"maxLength\",\n args: { max },\n message: message ?? `Must be at most ${max} characters`,\n }),\n\n pattern: (pattern: string, message = \"Invalid format\"): ValidationCheck => ({\n fn: \"pattern\",\n args: { pattern },\n message,\n }),\n\n min: (min: number, message?: string): ValidationCheck => ({\n fn: \"min\",\n args: { min },\n message: message ?? `Must be at least ${min}`,\n }),\n\n max: (max: number, message?: string): ValidationCheck => ({\n fn: \"max\",\n args: { max },\n message: message ?? `Must be at most ${max}`,\n }),\n\n url: (message = \"Invalid URL\"): ValidationCheck => ({\n fn: \"url\",\n message,\n }),\n\n matches: (\n otherPath: string,\n message = \"Fields must match\",\n ): ValidationCheck => ({\n fn: \"matches\",\n args: { other: { path: otherPath } },\n message,\n }),\n};\n","import { z } from \"zod\";\nimport type {\n ComponentSchema,\n ValidationMode,\n UIElement,\n UITree,\n VisibilityCondition,\n} from \"./types\";\nimport { VisibilityConditionSchema } from \"./visibility\";\nimport { ActionSchema, type ActionDefinition } from \"./actions\";\nimport { ValidationConfigSchema, type ValidationFunction } from \"./validation\";\n\n/**\n * Component definition with visibility and validation support\n */\nexport interface ComponentDefinition<\n TProps extends ComponentSchema = ComponentSchema,\n> {\n /** Zod schema for component props */\n props: TProps;\n /** Whether this component can have children */\n hasChildren?: boolean;\n /** Description for AI generation */\n description?: string;\n}\n\n/**\n * Catalog configuration\n */\nexport interface CatalogConfig<\n TComponents extends Record<string, ComponentDefinition> = Record<\n string,\n ComponentDefinition\n >,\n TActions extends Record<string, ActionDefinition> = Record<\n string,\n ActionDefinition\n >,\n TFunctions extends Record<string, ValidationFunction> = Record<\n string,\n ValidationFunction\n >,\n> {\n /** Catalog name */\n name?: string;\n /** Component definitions */\n components: TComponents;\n /** Action definitions with param schemas */\n actions?: TActions;\n /** Custom validation functions */\n functions?: TFunctions;\n /** Validation mode */\n validation?: ValidationMode;\n}\n\n/**\n * Catalog instance\n */\nexport interface Catalog<\n TComponents extends Record<string, ComponentDefinition> = Record<\n string,\n ComponentDefinition\n >,\n TActions extends Record<string, ActionDefinition> = Record<\n string,\n ActionDefinition\n >,\n TFunctions extends Record<string, ValidationFunction> = Record<\n string,\n ValidationFunction\n >,\n> {\n /** Catalog name */\n readonly name: string;\n /** Component names */\n readonly componentNames: (keyof TComponents)[];\n /** Action names */\n readonly actionNames: (keyof TActions)[];\n /** Function names */\n readonly functionNames: (keyof TFunctions)[];\n /** Validation mode */\n readonly validation: ValidationMode;\n /** Component definitions */\n readonly components: TComponents;\n /** Action definitions */\n readonly actions: TActions;\n /** Custom validation functions */\n readonly functions: TFunctions;\n /** Full element schema for AI generation */\n readonly elementSchema: z.ZodType<UIElement>;\n /** Full UI tree schema */\n readonly treeSchema: z.ZodType<UITree>;\n /** Check if component exists */\n hasComponent(type: string): boolean;\n /** Check if action exists */\n hasAction(name: string): boolean;\n /** Check if function exists */\n hasFunction(name: string): boolean;\n /** Validate an element */\n validateElement(element: unknown): {\n success: boolean;\n data?: UIElement;\n error?: z.ZodError;\n };\n /** Validate a UI tree */\n validateTree(tree: unknown): {\n success: boolean;\n data?: UITree;\n error?: z.ZodError;\n };\n}\n\n/**\n * Create a v2 catalog with visibility, actions, and validation support\n */\nexport function createCatalog<\n TComponents extends Record<string, ComponentDefinition>,\n TActions extends Record<string, ActionDefinition> = Record<\n string,\n ActionDefinition\n >,\n TFunctions extends Record<string, ValidationFunction> = Record<\n string,\n ValidationFunction\n >,\n>(\n config: CatalogConfig<TComponents, TActions, TFunctions>,\n): Catalog<TComponents, TActions, TFunctions> {\n const {\n name = \"unnamed\",\n components,\n actions = {} as TActions,\n functions = {} as TFunctions,\n validation = \"strict\",\n } = config;\n\n const componentNames = Object.keys(components) as (keyof TComponents)[];\n const actionNames = Object.keys(actions) as (keyof TActions)[];\n const functionNames = Object.keys(functions) as (keyof TFunctions)[];\n\n // Create element schema for each component type\n const componentSchemas = componentNames.map((componentName) => {\n const def = components[componentName]!;\n\n return z.object({\n key: z.string(),\n type: z.literal(componentName as string),\n props: def.props,\n children: z.array(z.string()).optional(),\n parentKey: z.string().nullable().optional(),\n visible: VisibilityConditionSchema.optional(),\n });\n });\n\n // Create union schema for all components\n let elementSchema: z.ZodType<UIElement>;\n\n if (componentSchemas.length === 0) {\n elementSchema = z.object({\n key: z.string(),\n type: z.string(),\n props: z.record(z.string(), z.unknown()),\n children: z.array(z.string()).optional(),\n parentKey: z.string().nullable().optional(),\n visible: VisibilityConditionSchema.optional(),\n }) as unknown as z.ZodType<UIElement>;\n } else if (componentSchemas.length === 1) {\n elementSchema = componentSchemas[0] as unknown as z.ZodType<UIElement>;\n } else {\n elementSchema = z.discriminatedUnion(\"type\", [\n componentSchemas[0] as z.ZodObject<any>,\n componentSchemas[1] as z.ZodObject<any>,\n ...(componentSchemas.slice(2) as z.ZodObject<any>[]),\n ]) as unknown as z.ZodType<UIElement>;\n }\n\n // Create tree schema\n const treeSchema = z.object({\n root: z.string(),\n elements: z.record(z.string(), elementSchema),\n }) as unknown as z.ZodType<UITree>;\n\n return {\n name,\n componentNames,\n actionNames,\n functionNames,\n validation,\n components,\n actions,\n functions,\n elementSchema,\n treeSchema,\n\n hasComponent(type: string) {\n return type in components;\n },\n\n hasAction(name: string) {\n return name in actions;\n },\n\n hasFunction(name: string) {\n return name in functions;\n },\n\n validateElement(element: unknown) {\n const result = elementSchema.safeParse(element);\n if (result.success) {\n return { success: true, data: result.data };\n }\n return { success: false, error: result.error };\n },\n\n validateTree(tree: unknown) {\n const result = treeSchema.safeParse(tree);\n if (result.success) {\n return { success: true, data: result.data };\n }\n return { success: false, error: result.error };\n },\n };\n}\n\n/**\n * Generate a prompt for AI that describes the catalog\n */\nexport function generateCatalogPrompt<\n TComponents extends Record<string, ComponentDefinition>,\n TActions extends Record<string, ActionDefinition>,\n TFunctions extends Record<string, ValidationFunction>,\n>(catalog: Catalog<TComponents, TActions, TFunctions>): string {\n const lines: string[] = [\n `# ${catalog.name} Component Catalog`,\n \"\",\n \"## Available Components\",\n \"\",\n ];\n\n // Components\n for (const name of catalog.componentNames) {\n const def = catalog.components[name]!;\n lines.push(`### ${String(name)}`);\n if (def.description) {\n lines.push(def.description);\n }\n lines.push(\"\");\n }\n\n // Actions\n if (catalog.actionNames.length > 0) {\n lines.push(\"## Available Actions\");\n lines.push(\"\");\n for (const name of catalog.actionNames) {\n const def = catalog.actions[name]!;\n lines.push(\n `- \\`${String(name)}\\`${def.description ? `: ${def.description}` : \"\"}`,\n );\n }\n lines.push(\"\");\n }\n\n // Visibility\n lines.push(\"## Visibility Conditions\");\n lines.push(\"\");\n lines.push(\"Components can have a `visible` property:\");\n lines.push(\"- `true` / `false` - Always visible/hidden\");\n lines.push('- `{ \"path\": \"/data/path\" }` - Visible when path is truthy');\n lines.push('- `{ \"auth\": \"signedIn\" }` - Visible when user is signed in');\n lines.push('- `{ \"and\": [...] }` - All conditions must be true');\n lines.push('- `{ \"or\": [...] }` - Any condition must be true');\n lines.push('- `{ \"not\": {...} }` - Negates a condition');\n lines.push('- `{ \"eq\": [a, b] }` - Equality check');\n lines.push(\"\");\n\n // Validation\n lines.push(\"## Validation Functions\");\n lines.push(\"\");\n lines.push(\n \"Built-in: `required`, `email`, `minLength`, `maxLength`, `pattern`, `min`, `max`, `url`\",\n );\n if (catalog.functionNames.length > 0) {\n lines.push(`Custom: ${catalog.functionNames.map(String).join(\", \")}`);\n }\n lines.push(\"\");\n\n return lines.join(\"\\n\");\n}\n\n/**\n * Type helper to infer component props from catalog\n */\nexport type InferCatalogComponentProps<\n C extends Catalog<Record<string, ComponentDefinition>>,\n> = {\n [K in keyof C[\"components\"]]: z.infer<C[\"components\"][K][\"props\"]>;\n};\n","/**\n * JSON-Render Catalog for Phoenix Insight UI\n *\n * Defines the allowed components that can be rendered from AI-generated JSON.\n * Uses zod schemas for props validation.\n */\n\nimport { createCatalog } from \"@json-render/core\";\nimport { z } from \"zod\";\n\n/**\n * Card component - container for grouping related content\n */\nconst CardSchema = z.object({\n title: z.string().optional(),\n description: z.string().optional(),\n});\n\n/**\n * Text component - for paragraphs and inline text\n */\nconst TextSchema = z.object({\n content: z.string(),\n variant: z.enum([\"default\", \"muted\", \"lead\"]).optional(),\n});\n\n/**\n * Heading component - for section headers (h1-h6)\n */\nconst HeadingSchema = z.object({\n content: z.string(),\n level: z.coerce.number().int().min(1).max(6).optional(),\n});\n\n/**\n * List component - ordered and unordered lists\n */\nconst ListSchema = z.object({\n items: z.array(z.string()),\n ordered: z.boolean().optional(),\n});\n\n/**\n * Table component - tabular data display\n */\nconst TableSchema = z.object({\n headers: z.array(z.string()),\n rows: z.array(z.array(z.string())),\n caption: z.string().optional(),\n});\n\n/**\n * Metric component - displays a key metric value\n */\nconst MetricSchema = z.object({\n label: z.string(),\n value: z.string(),\n change: z.string().optional(),\n changeType: z.enum([\"positive\", \"negative\", \"neutral\"]).optional(),\n});\n\n/**\n * Badge component - inline status or category indicator\n */\nconst BadgeSchema = z.object({\n content: z.string(),\n variant: z\n .enum([\"default\", \"secondary\", \"destructive\", \"outline\"])\n .optional(),\n});\n\n/**\n * Alert component - important messages or warnings\n */\nconst AlertSchema = z.object({\n title: z.string().optional(),\n description: z.string(),\n variant: z.enum([\"default\", \"destructive\"]).optional(),\n});\n\n/**\n * Separator component - visual divider\n */\nconst SeparatorSchema = z.object({\n orientation: z.enum([\"horizontal\", \"vertical\"]).optional(),\n});\n\n/**\n * Code component - code blocks with syntax highlighting\n */\nconst CodeSchema = z.object({\n content: z.string(),\n language: z.string().optional(),\n});\n\n/**\n * Chart component - displays a chart from array data\n */\nconst ChartSchema = z.object({\n type: z.enum([\"bar\", \"line\", \"pie\", \"area\"]),\n data: z.array(z.object({ label: z.string(), value: z.number() })),\n title: z.string().nullable(),\n height: z.number().nullable(),\n});\n\n/**\n * The Phoenix Insight UI catalog\n *\n * Defines all components that AI can generate for reports.\n * Each component has a zod schema for props validation.\n */\nexport const catalog = createCatalog({\n name: \"phoenix-insight-ui\",\n components: {\n Card: {\n props: CardSchema,\n hasChildren: true,\n description:\n \"Container for grouping related content with optional title and description\",\n },\n Chart: {\n props: ChartSchema,\n hasChildren: false,\n description:\n \"Chart display from array data with optional title and height\",\n },\n Text: {\n props: TextSchema,\n hasChildren: false,\n description:\n \"Text paragraph with optional styling variants (default, muted, lead)\",\n },\n Heading: {\n props: HeadingSchema,\n hasChildren: false,\n description: \"Section heading with configurable level (1-6)\",\n },\n List: {\n props: ListSchema,\n hasChildren: false,\n description: \"Ordered or unordered list of items\",\n },\n Table: {\n props: TableSchema,\n hasChildren: false,\n description:\n \"Tabular data display with headers, rows, and optional caption\",\n },\n Metric: {\n props: MetricSchema,\n hasChildren: false,\n description:\n \"Key metric display with label, value, and optional change indicator\",\n },\n Badge: {\n props: BadgeSchema,\n hasChildren: false,\n description: \"Inline status or category indicator with variant styling\",\n },\n Alert: {\n props: AlertSchema,\n hasChildren: false,\n description:\n \"Important message or warning with optional title and variant\",\n },\n Separator: {\n props: SeparatorSchema,\n hasChildren: false,\n description: \"Visual divider between sections\",\n },\n Code: {\n props: CodeSchema,\n hasChildren: false,\n description: \"Code block with optional syntax highlighting\",\n },\n },\n});\n\n// Export individual schemas for use in other parts of the application\nexport {\n CardSchema,\n ChartSchema,\n TextSchema,\n HeadingSchema,\n ListSchema,\n TableSchema,\n MetricSchema,\n BadgeSchema,\n AlertSchema,\n SeparatorSchema,\n CodeSchema,\n};\n\n// Export the catalog type for use in other modules\nexport type PhoenixInsightCatalog = typeof catalog;\n\n// Re-export useful types from json-render\nexport type { UITree, UIElement } from \"@json-render/core\";\n","import type { PhoenixClient } from \"@arizeai/phoenix-client\";\nimport type { ExecutionMode } from \"../modes/types.js\";\nimport { withErrorHandling } from \"./client.js\";\n\n/**\n * Converts an array of items to JSONL format (one JSON object per line)\n */\nfunction toJSONL(items: unknown[]): string {\n return items.map((item) => JSON.stringify(item)).join(\"\\n\");\n}\n\n/**\n * Fetches all projects and writes them to the filesystem\n * @param client - The Phoenix client instance\n * @param mode - The execution mode (sandbox or local)\n */\nexport async function fetchProjects(\n client: PhoenixClient,\n mode: ExecutionMode\n): Promise<void> {\n // Fetch all projects with error handling\n const projectsData = await withErrorHandling(async () => {\n const response = await client.GET(\"/v1/projects\", {\n params: {\n query: {\n include_experiment_projects: false,\n },\n },\n });\n\n if (!response.data) {\n throw new Error(\"No data returned from projects endpoint\");\n }\n\n return response.data;\n }, \"fetching projects\");\n\n // Extract projects from the response\n const projects = projectsData.data || [];\n\n // Write projects list as JSONL to /phoenix/projects/index.jsonl\n const projectsPath = \"/phoenix/projects/index.jsonl\";\n await mode.writeFile(projectsPath, toJSONL(projects));\n\n // For each project, create a metadata.json file\n for (const project of projects) {\n const projectDir = `/phoenix/projects/${project.name}`;\n const metadataPath = `${projectDir}/metadata.json`;\n\n // Write project metadata\n await mode.writeFile(metadataPath, JSON.stringify(project, null, 2));\n\n // Create empty spans directory (will be populated by snapshot-spans task)\n const spansDir = `${projectDir}/spans`;\n // Create directory by writing a placeholder that will be overwritten later\n await mode.writeFile(`${spansDir}/.gitkeep`, \"\");\n }\n}\n","import type { PhoenixClient } from \"@arizeai/phoenix-client\";\nimport type { ExecutionMode } from \"../modes/types.js\";\nimport { withErrorHandling } from \"./client.js\";\n\nexport interface SnapshotSpansOptions {\n /** Inclusive lower bound time for filtering spans */\n startTime?: Date | string | null;\n /** Exclusive upper bound time for filtering spans */\n endTime?: Date | string | null;\n /** Maximum number of spans to fetch per project (default: 1000) */\n spansPerProject?: number;\n /** Enable debug logging (default: uses DEBUG env var) */\n debug?: boolean;\n}\n\n/**\n * Debug logger that respects the debug flag or DEBUG environment variable\n */\nfunction createDebugLogger(debug?: boolean) {\n const isDebugEnabled = debug ?? !!process.env.DEBUG;\n return {\n log: (message: string) => {\n if (isDebugEnabled) {\n console.log(`[snapshotSpans] ${message}`);\n }\n },\n };\n}\n\ninterface SpanData {\n id: string;\n name: string;\n context: {\n trace_id: string;\n span_id: string;\n };\n span_kind: string;\n parent_id: string | null;\n start_time: string;\n end_time: string;\n status_code: string;\n status_message: string;\n attributes: Record<string, unknown>;\n events: Array<unknown>;\n}\n\ninterface ProjectMetadata {\n name: string;\n}\n\n/**\n * Fetches spans for all projects and writes them to the snapshot\n *\n * @param client - Phoenix client instance\n * @param mode - Execution mode for file operations\n * @param options - Options for filtering and limiting spans\n */\nexport async function snapshotSpans(\n client: PhoenixClient,\n mode: ExecutionMode,\n options: SnapshotSpansOptions = {}\n): Promise<void> {\n const { startTime, endTime, spansPerProject = 1000, debug } = options;\n const logger = createDebugLogger(debug);\n\n // Read projects index to get project names\n // Use relative path so it works with the cwd set by the execution mode\n logger.log(\"Reading projects index from projects/index.jsonl\");\n const projectsIndexContent = await mode.exec(\"cat projects/index.jsonl\");\n if (!projectsIndexContent.stdout) {\n // No projects, nothing to do\n logger.log(\"No projects found in index, skipping span fetch\");\n return;\n }\n\n const projectNames = projectsIndexContent.stdout\n .trim()\n .split(\"\\n\")\n .filter((line) => line.length > 0)\n .map((line) => {\n const project = JSON.parse(line) as ProjectMetadata;\n return project.name;\n });\n\n logger.log(`Found ${projectNames.length} project(s): ${projectNames.join(\", \")}`);\n\n // Fetch spans for each project\n for (const projectName of projectNames) {\n await withErrorHandling(async () => {\n logger.log(`Starting span fetch for project: ${projectName}`);\n const spans: SpanData[] = [];\n let cursor: string | null = null;\n let totalFetched = 0;\n\n // Paginate through spans until we reach the limit or no more data\n while (totalFetched < spansPerProject) {\n const query: Record<string, any> = {\n limit: Math.min(100, spansPerProject - totalFetched), // Fetch in chunks of 100\n };\n\n if (cursor) {\n query.cursor = cursor;\n }\n\n if (startTime) {\n query.start_time =\n startTime instanceof Date ? startTime.toISOString() : startTime;\n }\n\n if (endTime) {\n query.end_time =\n endTime instanceof Date ? endTime.toISOString() : endTime;\n }\n\n const response = await client.GET(\n \"/v1/projects/{project_identifier}/spans\",\n {\n params: {\n path: {\n project_identifier: projectName,\n },\n query,\n },\n }\n );\n\n if (response.error) throw response.error;\n\n const data = response.data?.data ?? [];\n spans.push(...(data as SpanData[]));\n totalFetched += data.length;\n\n cursor = response.data?.next_cursor ?? null;\n\n // Stop if there's no more data\n if (!cursor || data.length === 0) {\n break;\n }\n }\n\n logger.log(`Completed span fetch for project ${projectName}: ${spans.length} span(s) fetched`);\n\n // Write spans to JSONL file\n const spansFilePath = `/phoenix/projects/${projectName}/spans/index.jsonl`;\n logger.log(`Writing spans to ${spansFilePath}`);\n const jsonlContent = spans.map((span) => JSON.stringify(span)).join(\"\\n\");\n await mode.writeFile(spansFilePath, jsonlContent);\n\n // Write metadata about the spans snapshot\n const metadataFilePath = `/phoenix/projects/${projectName}/spans/metadata.json`;\n logger.log(`Writing metadata to ${metadataFilePath}`);\n const metadata = {\n project: projectName,\n spanCount: spans.length,\n startTime: startTime || null,\n endTime: endTime || null,\n snapshotTime: new Date().toISOString(),\n };\n\n await mode.writeFile(metadataFilePath, JSON.stringify(metadata, null, 2));\n }, `fetching spans for project ${projectName}`);\n }\n}\n","import type { PhoenixClient } from \"@arizeai/phoenix-client\";\nimport type { ExecutionMode } from \"../modes/types.js\";\nimport { withErrorHandling, extractData } from \"./client.js\";\n\ninterface Dataset {\n id: string;\n name: string;\n description: string | null;\n metadata: Record<string, unknown>;\n created_at: string;\n updated_at: string;\n}\n\ninterface DatasetExample {\n id: string;\n input: Record<string, unknown>;\n output: Record<string, unknown>;\n metadata: Record<string, unknown>;\n updated_at: string;\n}\n\ninterface FetchDatasetsOptions {\n limit?: number;\n}\n\n/**\n * Converts an array to JSONL format\n */\nfunction toJSONL(items: unknown[]): string {\n if (items.length === 0) {\n return \"\";\n }\n return items.map((item) => JSON.stringify(item)).join(\"\\n\");\n}\n\n/**\n * Fetches all datasets and their examples from Phoenix\n */\nexport async function fetchDatasets(\n client: PhoenixClient,\n mode: ExecutionMode,\n options: FetchDatasetsOptions = {}\n): Promise<void> {\n const { limit = 100 } = options;\n\n // Fetch all datasets with pagination\n const datasets: Dataset[] = [];\n let cursor: string | null = null;\n\n while (datasets.length < limit) {\n const query: Record<string, unknown> = {\n limit: Math.min(limit - datasets.length, 100),\n };\n if (cursor) {\n query.cursor = cursor;\n }\n\n const response = await withErrorHandling(\n () => client.GET(\"/v1/datasets\", { params: { query } }),\n \"fetching datasets\"\n );\n\n const data = extractData(response);\n datasets.push(...data.data);\n cursor = data.next_cursor;\n\n // Stop if no more data\n if (!cursor || data.data.length === 0) {\n break;\n }\n }\n\n // Write datasets index\n await mode.writeFile(\"/phoenix/datasets/index.jsonl\", toJSONL(datasets));\n\n // Fetch examples for each dataset\n for (const dataset of datasets) {\n // Write dataset metadata\n await mode.writeFile(\n `/phoenix/datasets/${dataset.name}/metadata.json`,\n JSON.stringify(\n {\n id: dataset.id,\n name: dataset.name,\n description: dataset.description,\n metadata: dataset.metadata,\n created_at: dataset.created_at,\n updated_at: dataset.updated_at,\n snapshot_timestamp: new Date().toISOString(),\n },\n null,\n 2\n )\n );\n\n // Fetch examples for this dataset\n const examplesResponse = await withErrorHandling(\n () =>\n client.GET(\"/v1/datasets/{id}/examples\", {\n params: {\n path: { id: dataset.id },\n },\n }),\n `fetching examples for dataset ${dataset.name}`\n );\n\n const examplesData = extractData(examplesResponse);\n const examples = examplesData.data.examples;\n\n // Write examples as JSONL\n await mode.writeFile(\n `/phoenix/datasets/${dataset.name}/examples.jsonl`,\n toJSONL(examples)\n );\n\n // Write dataset info with example count\n await mode.writeFile(\n `/phoenix/datasets/${dataset.name}/info.json`,\n JSON.stringify(\n {\n dataset_id: dataset.id,\n dataset_name: dataset.name,\n example_count: examples.length,\n version_id: examplesData.data.version_id,\n filtered_splits: examplesData.data.filtered_splits,\n },\n null,\n 2\n )\n );\n }\n}\n","import type { PhoenixClient } from \"@arizeai/phoenix-client\";\nimport type { ExecutionMode } from \"../modes/types.js\";\nimport { withErrorHandling, extractData } from \"./client.js\";\n\ninterface Dataset {\n id: string;\n name: string;\n}\n\ninterface Experiment {\n id: string;\n dataset_id: string;\n dataset_version_id: string;\n repetitions: number;\n metadata: Record<string, unknown>;\n project_name: string | null;\n created_at: string;\n updated_at: string;\n example_count: number;\n successful_run_count: number;\n failed_run_count: number;\n missing_run_count: number;\n}\n\ninterface ExperimentRun {\n id: string;\n experiment_id: string;\n dataset_example_id: string;\n start_time: string;\n end_time: string;\n output: unknown;\n error?: string | null;\n trace_id?: string | null;\n repetition_number?: number;\n}\n\ninterface FetchExperimentsOptions {\n /**\n * Maximum number of experiments to fetch per dataset\n */\n limit?: number;\n /**\n * Include experiment runs in the snapshot\n */\n includeRuns?: boolean;\n}\n\n/**\n * Converts an array to JSONL format\n */\nfunction toJSONL(items: unknown[]): string {\n if (items.length === 0) {\n return \"\";\n }\n return items.map((item) => JSON.stringify(item)).join(\"\\n\");\n}\n\n/**\n * Fetches all experiments and their runs from Phoenix\n * Note: Experiments are fetched per dataset since there's no direct \"all experiments\" endpoint\n */\nexport async function fetchExperiments(\n client: PhoenixClient,\n mode: ExecutionMode,\n options: FetchExperimentsOptions = {}\n): Promise<void> {\n const { limit = 100, includeRuns = true } = options;\n\n // First, we need to get all datasets to fetch their experiments\n const datasetsResponse = await withErrorHandling(\n () => client.GET(\"/v1/datasets\", { params: { query: { limit: 1000 } } }),\n \"fetching datasets for experiments\"\n );\n\n const datasetsData = extractData(datasetsResponse);\n const datasets: Dataset[] = datasetsData.data;\n\n // Collect all experiments from all datasets\n const allExperiments: Array<Experiment & { datasetName: string }> = [];\n\n for (const dataset of datasets) {\n try {\n // Fetch experiments for this dataset with pagination\n const experiments: Experiment[] = [];\n let cursor: string | null = null;\n\n do {\n const response = await withErrorHandling(\n () =>\n client.GET(\"/v1/datasets/{dataset_id}/experiments\", {\n params: {\n path: {\n dataset_id: dataset.id,\n },\n query: {\n cursor,\n limit: 50,\n },\n },\n }),\n `fetching experiments for dataset ${dataset.name}`\n );\n\n const data = extractData(response);\n experiments.push(...(data.data || []));\n cursor = data.next_cursor || null;\n\n // Stop if we've reached the overall limit\n if (allExperiments.length + experiments.length >= limit) {\n const remaining = limit - allExperiments.length;\n experiments.splice(remaining);\n cursor = null;\n }\n } while (cursor != null);\n\n // Add dataset name to each experiment for context\n const experimentsWithDatasetName = experiments.map((exp) => ({\n ...exp,\n datasetName: dataset.name,\n }));\n\n allExperiments.push(...experimentsWithDatasetName);\n\n // Apply limit if specified\n if (allExperiments.length >= limit) {\n break;\n }\n } catch (error) {\n // If fetching experiments for a dataset fails, log and continue\n console.warn(\n `Failed to fetch experiments for dataset ${dataset.name}:`,\n error\n );\n }\n }\n\n // Write experiments index\n await mode.writeFile(\n \"/phoenix/experiments/index.jsonl\",\n toJSONL(allExperiments)\n );\n\n // Fetch runs for each experiment if requested\n if (includeRuns) {\n for (const experiment of allExperiments) {\n try {\n // Write experiment metadata\n await mode.writeFile(\n `/phoenix/experiments/${experiment.id}/metadata.json`,\n JSON.stringify(\n {\n id: experiment.id,\n dataset_id: experiment.dataset_id,\n dataset_name: experiment.datasetName,\n dataset_version_id: experiment.dataset_version_id,\n repetitions: experiment.repetitions,\n metadata: experiment.metadata,\n project_name: experiment.project_name,\n created_at: experiment.created_at,\n updated_at: experiment.updated_at,\n example_count: experiment.example_count,\n successful_run_count: experiment.successful_run_count,\n failed_run_count: experiment.failed_run_count,\n missing_run_count: experiment.missing_run_count,\n snapshot_timestamp: new Date().toISOString(),\n },\n null,\n 2\n )\n );\n\n // Fetch runs for this experiment with pagination\n const runs: ExperimentRun[] = [];\n let cursor: string | null = null;\n\n do {\n const runsResponse = await withErrorHandling(\n () =>\n client.GET(\"/v1/experiments/{experiment_id}/runs\", {\n params: {\n path: {\n experiment_id: experiment.id,\n },\n query: {\n cursor,\n limit: 100,\n },\n },\n }),\n `fetching runs for experiment ${experiment.id}`\n );\n\n const runsData = extractData(runsResponse);\n runs.push(...(runsData.data || []));\n cursor = runsData.next_cursor || null;\n } while (cursor != null);\n\n // Write runs as JSONL\n await mode.writeFile(\n `/phoenix/experiments/${experiment.id}/runs.jsonl`,\n toJSONL(runs)\n );\n\n // Write experiment summary with run stats\n await mode.writeFile(\n `/phoenix/experiments/${experiment.id}/summary.json`,\n JSON.stringify(\n {\n experiment_id: experiment.id,\n dataset_name: experiment.datasetName,\n project_name: experiment.project_name,\n total_runs: runs.length,\n successful_runs: experiment.successful_run_count,\n failed_runs: experiment.failed_run_count,\n missing_runs: experiment.missing_run_count,\n created_at: experiment.created_at,\n updated_at: experiment.updated_at,\n },\n null,\n 2\n )\n );\n } catch (error) {\n // If fetching runs for an experiment fails, log and continue\n console.warn(\n `Failed to fetch runs for experiment ${experiment.id}:`,\n error\n );\n\n // Still create the experiment metadata without runs\n await mode.writeFile(\n `/phoenix/experiments/${experiment.id}/metadata.json`,\n JSON.stringify(\n {\n ...experiment,\n error: \"Failed to fetch runs\",\n snapshot_timestamp: new Date().toISOString(),\n },\n null,\n 2\n )\n );\n }\n }\n }\n}\n","import type { PhoenixClient } from \"@arizeai/phoenix-client\";\nimport type { ExecutionMode } from \"../modes/types.js\";\nimport { withErrorHandling, extractData } from \"./client.js\";\n\ninterface FetchPromptsOptions {\n limit?: number;\n}\n\n/**\n * Converts an array to JSONL format\n */\nfunction toJSONL(items: unknown[]): string {\n if (items.length === 0) {\n return \"\";\n }\n return items.map((item) => JSON.stringify(item)).join(\"\\n\");\n}\n\n/**\n * Converts a prompt template to markdown format\n */\nfunction templateToMarkdown(template: any, templateFormat: string): string {\n // Handle string template\n if (templateFormat === \"STRING\") {\n if (typeof template === \"string\") {\n return template;\n }\n // It might be wrapped in an object with type\n if (template?.template && typeof template.template === \"string\") {\n return template.template;\n }\n return JSON.stringify(template, null, 2);\n }\n\n // Handle chat template\n const messages = template?.messages || [];\n const lines: string[] = [\"# Chat Template\", \"\"];\n\n for (const message of messages) {\n lines.push(`## ${message.role}`);\n lines.push(\"\");\n\n if (typeof message.content === \"string\") {\n lines.push(message.content);\n } else if (Array.isArray(message.content)) {\n // Handle multi-part content\n for (const part of message.content) {\n if (part.type === \"text\" && part.text) {\n lines.push(part.text);\n } else {\n // For non-text parts, show as JSON\n lines.push(\"```json\");\n lines.push(JSON.stringify(part, null, 2));\n lines.push(\"```\");\n }\n }\n } else {\n // If content is not string or array, show as JSON\n lines.push(\"```json\");\n lines.push(JSON.stringify(message.content, null, 2));\n lines.push(\"```\");\n }\n lines.push(\"\");\n }\n\n return lines.join(\"\\n\");\n}\n\n/**\n * Creates a markdown representation of a prompt version\n */\nfunction createVersionMarkdown(version: any): string {\n const lines: string[] = [];\n\n // Add metadata header\n lines.push(\"---\");\n lines.push(`id: ${version.id}`);\n if (version.model_name) lines.push(`model_name: ${version.model_name}`);\n if (version.model_provider)\n lines.push(`model_provider: ${version.model_provider}`);\n if (version.template_format)\n lines.push(`template_format: ${version.template_format}`);\n if (version.description) lines.push(`description: ${version.description}`);\n lines.push(\"---\");\n lines.push(\"\");\n\n // Add template content\n if (version.template) {\n lines.push(\n templateToMarkdown(version.template, version.template_format || \"STRING\")\n );\n lines.push(\"\");\n }\n\n // Add invocation parameters if present\n if (version.invocation_parameters) {\n lines.push(\"## Invocation Parameters\");\n lines.push(\"\");\n lines.push(\"```json\");\n lines.push(JSON.stringify(version.invocation_parameters, null, 2));\n lines.push(\"```\");\n lines.push(\"\");\n }\n\n // Add tools if present\n if (version.tools) {\n lines.push(\"## Tools\");\n lines.push(\"\");\n lines.push(\"```json\");\n lines.push(JSON.stringify(version.tools, null, 2));\n lines.push(\"```\");\n lines.push(\"\");\n }\n\n // Add response format if present\n if (version.response_format) {\n lines.push(\"## Response Format\");\n lines.push(\"\");\n lines.push(\"```json\");\n lines.push(JSON.stringify(version.response_format, null, 2));\n lines.push(\"```\");\n lines.push(\"\");\n }\n\n return lines.join(\"\\n\");\n}\n\n/**\n * Fetches all prompts and their versions from Phoenix\n */\nexport async function fetchPrompts(\n client: PhoenixClient,\n mode: ExecutionMode,\n options: FetchPromptsOptions = {}\n): Promise<void> {\n const { limit = 100 } = options;\n\n // Fetch all prompts with pagination\n const prompts: any[] = [];\n let cursor: string | null = null;\n\n while (prompts.length < limit) {\n const query: Record<string, unknown> = {\n limit: Math.min(limit - prompts.length, 100),\n };\n if (cursor) {\n query.cursor = cursor;\n }\n\n const response = await withErrorHandling(\n () => client.GET(\"/v1/prompts\", { params: { query } }),\n \"fetching prompts\"\n );\n\n const data = extractData(response);\n prompts.push(...data.data);\n cursor = data.next_cursor;\n\n // Stop if no more data\n if (!cursor || data.data.length === 0) {\n break;\n }\n }\n\n // Write prompts index\n await mode.writeFile(\"/phoenix/prompts/index.jsonl\", toJSONL(prompts));\n\n // Fetch versions for each prompt\n for (const prompt of prompts) {\n const safePromptName = prompt.name.replace(/[^a-zA-Z0-9-_]/g, \"_\");\n\n // Write prompt metadata\n await mode.writeFile(\n `/phoenix/prompts/${safePromptName}/metadata.json`,\n JSON.stringify(\n {\n id: prompt.id,\n name: prompt.name,\n description: prompt.description || null,\n metadata: prompt.metadata || {},\n source_prompt_id: prompt.source_prompt_id || null,\n snapshot_timestamp: new Date().toISOString(),\n },\n null,\n 2\n )\n );\n\n // Fetch all versions for this prompt\n const versions: any[] = [];\n let versionCursor: string | null = null;\n\n while (true) {\n const versionQuery: Record<string, unknown> = {\n limit: 100,\n };\n if (versionCursor) {\n versionQuery.cursor = versionCursor;\n }\n\n const versionsResponse = await withErrorHandling(\n () =>\n client.GET(\"/v1/prompts/{prompt_identifier}/versions\", {\n params: {\n path: { prompt_identifier: prompt.id },\n query: versionQuery,\n },\n }),\n `fetching versions for prompt ${prompt.name}`\n );\n\n const versionsData = extractData(versionsResponse);\n versions.push(...versionsData.data);\n versionCursor = versionsData.next_cursor;\n\n // Stop if no more data\n if (!versionCursor || versionsData.data.length === 0) {\n break;\n }\n }\n\n // Write versions index as JSONL\n await mode.writeFile(\n `/phoenix/prompts/${safePromptName}/versions/index.jsonl`,\n toJSONL(versions)\n );\n\n // Write each version as markdown\n for (const version of versions) {\n const versionId = version.id.replace(/[^a-zA-Z0-9-_]/g, \"_\");\n const markdownContent = createVersionMarkdown(version);\n\n await mode.writeFile(\n `/phoenix/prompts/${safePromptName}/versions/${versionId}.md`,\n markdownContent\n );\n }\n\n // Fetch and save the latest version separately for convenience\n try {\n const latestResponse = await withErrorHandling(\n () =>\n client.GET(\"/v1/prompts/{prompt_identifier}/latest\", {\n params: {\n path: { prompt_identifier: prompt.id },\n },\n }),\n `fetching latest version for prompt ${prompt.name}`\n );\n\n const latestData = extractData(latestResponse);\n if (latestData.data) {\n const latestMarkdownContent = createVersionMarkdown(latestData.data);\n\n await mode.writeFile(\n `/phoenix/prompts/${safePromptName}/latest.md`,\n latestMarkdownContent\n );\n }\n } catch (error) {\n // If there's no latest version, that's okay - just skip it\n console.warn(\n `No latest version available for prompt ${prompt.name}: ${error instanceof Error ? error.message : String(error)}`\n );\n }\n }\n}\n","import type { ExecutionMode } from \"../modes/types.js\";\n\ninterface ContextMetadata {\n phoenixUrl: string;\n snapshotTime: Date;\n spansPerProject?: number;\n}\n\ninterface ProjectStats {\n name: string;\n spanCount: number;\n hasErrors?: boolean;\n recentSpans?: number;\n}\n\ninterface DatasetInfo {\n name: string;\n exampleCount: number;\n updatedAt?: string;\n}\n\ninterface ExperimentInfo {\n id: string;\n datasetName: string;\n projectName?: string;\n status: \"completed\" | \"in_progress\" | \"failed\";\n runCounts: {\n successful: number;\n failed: number;\n missing: number;\n };\n updatedAt?: string;\n}\n\ninterface PromptInfo {\n name: string;\n versionCount: number;\n latestVersion?: string;\n updatedAt?: string;\n}\n\n// =============================================================================\n// Static Section Templates\n// =============================================================================\n\n/**\n * Quick Start section for external agents - appears at the top for discoverability\n */\nconst QUICK_START_SECTION = `## Quick Start for External Agents\n\nThis is a **read-only snapshot** of Phoenix observability data. You cannot modify this data.\n\n### Key Files to Start With\n\n| File | Description |\n|------|-------------|\n| \\`/phoenix/projects/index.jsonl\\` | List of all projects with traces |\n| \\`/phoenix/datasets/index.jsonl\\` | List of all datasets |\n| \\`/phoenix/experiments/index.jsonl\\` | List of all experiments |\n| \\`/phoenix/prompts/index.jsonl\\` | List of all prompts |\n\n### How to Parse Each File Format\n\n**JSONL files** (\\`.jsonl\\`): One JSON object per line\n\\`\\`\\`bash\n# Read all lines as a JSON array\ncat /phoenix/projects/index.jsonl | jq -s '.'\n\n# Process each line individually\nwhile read -r line; do echo \"$line\" | jq '.name'; done < /phoenix/projects/index.jsonl\n\n# Get first N items\nhead -n 5 /phoenix/projects/index.jsonl | jq -s '.'\n\\`\\`\\`\n\n**JSON files** (\\`.json\\`): Standard JSON format\n\\`\\`\\`bash\n# Read and pretty-print\ncat /phoenix/projects/my-project/metadata.json | jq '.'\n\n# Extract specific field\ncat /phoenix/projects/my-project/metadata.json | jq '.name'\n\\`\\`\\`\n\n**Markdown files** (\\`.md\\`): Plain text prompt templates\n\\`\\`\\`bash\n# Read prompt template\ncat /phoenix/prompts/my-prompt/versions/v1.md\n\\`\\`\\`\n\n### Common Operations\n\n\\`\\`\\`bash\n# List all project names\ncat /phoenix/projects/index.jsonl | jq -r '.name'\n\n# Count spans in a project\nwc -l < /phoenix/projects/my-project/spans/index.jsonl\n\n# Find spans with errors\ncat /phoenix/projects/my-project/spans/index.jsonl | jq 'select(.status_code == \"ERROR\")'\n\n# Get dataset examples\ncat /phoenix/datasets/my-dataset/examples.jsonl | jq -s '.' | head -n 100\n\n# Search across all files\ngrep -r \"error\" /phoenix/\n\\`\\`\\``;\n\n/**\n * Directory Structure section showing the snapshot layout\n */\nconst DIRECTORY_STRUCTURE_SECTION = `## Directory Structure\n\n\\`\\`\\`\n/phoenix/\n _context.md # This file - start here!\n /projects/\n index.jsonl # List of all projects\n /{project_name}/\n metadata.json # Project details\n /spans/\n index.jsonl # Span data (may be sampled)\n metadata.json # Span snapshot metadata\n /datasets/\n index.jsonl # List of all datasets\n /{dataset_name}/\n metadata.json # Dataset details\n examples.jsonl # Dataset examples\n /experiments/\n index.jsonl # List of all experiments\n /{experiment_id}/\n metadata.json # Experiment details\n runs.jsonl # Experiment runs\n /prompts/\n index.jsonl # List of all prompts\n /{prompt_name}/\n metadata.json # Prompt details\n /versions/\n index.jsonl # Version list\n /{version_id}.md # Version template\n /_meta/\n snapshot.json # Snapshot metadata\n\\`\\`\\``;\n\n/**\n * What You Can Do section describing available operations\n */\nconst WHAT_YOU_CAN_DO_SECTION = `## What You Can Do\n\n- **Explore**: ls, cat, grep, find, jq, awk, sed\n- **Fetch more data**: \\`px-fetch-more spans --project <name> --limit 500\\`\n- **Fetch specific trace**: \\`px-fetch-more trace --trace-id <id>\\``;\n\n/**\n * Data Freshness section with refresh instructions\n */\nconst DATA_FRESHNESS_SECTION = `## Data Freshness\n\nThis is a **read-only snapshot**. Data may have changed since capture.\nRun with \\`--refresh\\` to get latest data.`;\n\n// =============================================================================\n// Main Context Generation\n// =============================================================================\n\n/**\n * Generates a _context.md summary file for the Phoenix snapshot\n * This provides human and agent-readable context about what data is available\n */\nexport async function generateContext(\n mode: ExecutionMode,\n metadata: ContextMetadata\n): Promise<void> {\n // Collect stats from the snapshot\n const stats = await collectSnapshotStats(mode);\n\n // Build the dynamic \"What's Here\" section\n const whatsHereSection = buildWhatsHereSection(stats, metadata);\n\n // Build the dynamic \"Recent Activity\" section (may be empty)\n const recentActivitySection = buildRecentActivitySection(stats);\n\n // Compose the full context document\n const content = [\n \"# Phoenix Snapshot Context\",\n \"\",\n QUICK_START_SECTION,\n \"\",\n whatsHereSection,\n recentActivitySection,\n DIRECTORY_STRUCTURE_SECTION,\n \"\",\n WHAT_YOU_CAN_DO_SECTION,\n \"\",\n DATA_FRESHNESS_SECTION,\n ].join(\"\\n\");\n\n // Write the context file\n await mode.writeFile(\"/phoenix/_context.md\", content);\n}\n\n// =============================================================================\n// Dynamic Section Builders\n// =============================================================================\n\n/**\n * Builds the \"What's Here\" section with project/dataset/experiment/prompt summaries\n */\nfunction buildWhatsHereSection(\n stats: {\n projects: ProjectStats[];\n datasets: DatasetInfo[];\n experiments: ExperimentInfo[];\n prompts: PromptInfo[];\n },\n metadata: ContextMetadata\n): string {\n const lines: string[] = [];\n\n lines.push(\"## What's Here\");\n lines.push(\"\");\n\n // Projects summary\n if (stats.projects.length > 0) {\n const projectSummary = stats.projects\n .map((p) => `${p.name} (${p.spanCount} spans)`)\n .join(\", \");\n lines.push(`- **${stats.projects.length} projects**: ${projectSummary}`);\n } else {\n lines.push(\"- **No projects found**\");\n }\n\n // Datasets summary\n if (stats.datasets.length > 0) {\n const datasetNames = stats.datasets.map((d) => d.name).join(\", \");\n lines.push(`- **${stats.datasets.length} datasets**: ${datasetNames}`);\n } else {\n lines.push(\"- **No datasets found**\");\n }\n\n // Experiments summary\n if (stats.experiments.length > 0) {\n const completedCount = stats.experiments.filter(\n (e) => e.status === \"completed\"\n ).length;\n const inProgressCount = stats.experiments.filter(\n (e) => e.status === \"in_progress\"\n ).length;\n const failedCount = stats.experiments.filter(\n (e) => e.status === \"failed\"\n ).length;\n\n const parts: string[] = [];\n if (completedCount > 0) parts.push(`${completedCount} completed`);\n if (inProgressCount > 0) parts.push(`${inProgressCount} in progress`);\n if (failedCount > 0) parts.push(`${failedCount} failed`);\n\n lines.push(\n `- **${stats.experiments.length} experiments**: ${parts.join(\", \")}`\n );\n } else {\n lines.push(\"- **No experiments found**\");\n }\n\n // Prompts summary\n if (stats.prompts.length > 0) {\n const promptNames = stats.prompts.map((p) => p.name).join(\", \");\n lines.push(`- **${stats.prompts.length} prompts**: ${promptNames}`);\n } else {\n lines.push(\"- **No prompts found**\");\n }\n\n // Snapshot metadata\n lines.push(\n `- **Snapshot**: Created ${formatRelativeTime(\n metadata.snapshotTime\n )} from ${metadata.phoenixUrl}`\n );\n lines.push(\"\");\n\n return lines.join(\"\\n\");\n}\n\n/**\n * Builds the \"Recent Activity\" section if there are recent updates\n * Returns an empty string if no recent activity\n */\nfunction buildRecentActivitySection(stats: {\n projects: ProjectStats[];\n datasets: DatasetInfo[];\n experiments: ExperimentInfo[];\n prompts: PromptInfo[];\n}): string {\n const activities = getRecentActivity(stats);\n\n if (activities.length === 0) {\n return \"\";\n }\n\n const lines: string[] = [];\n lines.push(\"## Recent Activity\");\n lines.push(\"\");\n for (const activity of activities) {\n lines.push(`- ${activity}`);\n }\n lines.push(\"\");\n\n return lines.join(\"\\n\");\n}\n\n// =============================================================================\n// Data Collection\n// =============================================================================\n\n/**\n * Collects statistics from the snapshot filesystem\n */\nasync function collectSnapshotStats(mode: ExecutionMode): Promise<{\n projects: ProjectStats[];\n datasets: DatasetInfo[];\n experiments: ExperimentInfo[];\n prompts: PromptInfo[];\n}> {\n const result = {\n projects: [] as ProjectStats[],\n datasets: [] as DatasetInfo[],\n experiments: [] as ExperimentInfo[],\n prompts: [] as PromptInfo[],\n };\n\n // Collect project stats\n // Use relative paths since cwd is the phoenix directory in both modes\n try {\n const projectsExec = await mode.exec(\n \"cat projects/index.jsonl 2>/dev/null || true\"\n );\n if (projectsExec.stdout) {\n const projectLines = projectsExec.stdout\n .trim()\n .split(\"\\n\")\n .filter((line) => line.length > 0);\n\n for (const line of projectLines) {\n try {\n const project = JSON.parse(line);\n const stats: ProjectStats = {\n name: project.name,\n spanCount: 0,\n };\n\n // Get span count for this project\n const spansMetaExec = await mode.exec(\n `cat projects/${project.name}/spans/metadata.json 2>/dev/null || echo \"{}\"`\n );\n if (spansMetaExec.stdout) {\n try {\n const spansMeta = JSON.parse(spansMetaExec.stdout);\n stats.spanCount = spansMeta.spanCount || 0;\n } catch (e) {\n // Ignore parse errors\n }\n }\n\n result.projects.push(stats);\n } catch (e) {\n // Skip invalid project lines\n }\n }\n }\n } catch (e) {\n // No projects file\n }\n\n // Collect dataset stats\n try {\n const datasetsExec = await mode.exec(\n \"cat datasets/index.jsonl 2>/dev/null || true\"\n );\n if (datasetsExec.stdout) {\n const datasetLines = datasetsExec.stdout\n .trim()\n .split(\"\\n\")\n .filter((line) => line.length > 0);\n\n for (const line of datasetLines) {\n try {\n const dataset = JSON.parse(line);\n\n // Get example count\n const examplesExec = await mode.exec(\n `wc -l < datasets/${dataset.name}/examples.jsonl 2>/dev/null || echo \"0\"`\n );\n const exampleCount = parseInt(examplesExec.stdout.trim()) || 0;\n\n result.datasets.push({\n name: dataset.name,\n exampleCount,\n updatedAt: dataset.updated_at,\n });\n } catch (e) {\n // Skip invalid dataset lines\n }\n }\n }\n } catch (e) {\n // No datasets file\n }\n\n // Collect experiment stats\n try {\n const experimentsExec = await mode.exec(\n \"cat experiments/index.jsonl 2>/dev/null || true\"\n );\n if (experimentsExec.stdout) {\n const experimentLines = experimentsExec.stdout\n .trim()\n .split(\"\\n\")\n .filter((line) => line.length > 0);\n\n for (const line of experimentLines) {\n try {\n const experiment = JSON.parse(line);\n const status = determineExperimentStatus(experiment);\n\n result.experiments.push({\n id: experiment.id,\n datasetName: experiment.datasetName || \"unknown\",\n projectName: experiment.project_name,\n status,\n runCounts: {\n successful: experiment.successful_run_count || 0,\n failed: experiment.failed_run_count || 0,\n missing: experiment.missing_run_count || 0,\n },\n updatedAt: experiment.updated_at,\n });\n } catch (e) {\n // Skip invalid experiment lines\n }\n }\n }\n } catch (e) {\n // No experiments file\n }\n\n // Collect prompt stats\n try {\n const promptsExec = await mode.exec(\n \"cat prompts/index.jsonl 2>/dev/null || true\"\n );\n if (promptsExec.stdout) {\n const promptLines = promptsExec.stdout\n .trim()\n .split(\"\\n\")\n .filter((line) => line.length > 0);\n\n for (const line of promptLines) {\n try {\n const prompt = JSON.parse(line);\n\n // Count versions\n const versionsExec = await mode.exec(\n `wc -l < prompts/${prompt.name}/versions/index.jsonl 2>/dev/null || echo \"0\"`\n );\n const versionCount = parseInt(versionsExec.stdout.trim()) || 0;\n\n result.prompts.push({\n name: prompt.name,\n versionCount,\n updatedAt: prompt.updated_at,\n });\n } catch (e) {\n // Skip invalid prompt lines\n }\n }\n }\n } catch (e) {\n // No prompts file\n }\n\n return result;\n}\n\n// =============================================================================\n// Helper Functions\n// =============================================================================\n\n/**\n * Determines the status of an experiment based on its run counts\n */\nfunction determineExperimentStatus(\n experiment: any\n): \"completed\" | \"in_progress\" | \"failed\" {\n const totalExpected = experiment.example_count * experiment.repetitions;\n const totalRuns =\n (experiment.successful_run_count || 0) + (experiment.failed_run_count || 0);\n\n if (totalRuns === 0) {\n return \"in_progress\";\n }\n\n // If most runs are failed, consider it failed\n if (\n (experiment.failed_run_count || 0) > (experiment.successful_run_count || 0)\n ) {\n return \"failed\";\n }\n\n if (totalRuns >= totalExpected) {\n return \"completed\";\n }\n\n return \"in_progress\";\n}\n\n/**\n * Gets recent activity highlights\n */\nfunction getRecentActivity(stats: {\n projects: ProjectStats[];\n datasets: DatasetInfo[];\n experiments: ExperimentInfo[];\n prompts: PromptInfo[];\n}): string[] {\n const activities: string[] = [];\n\n // Find recently updated experiments\n const recentExperiments = stats.experiments\n .filter((e) => e.updatedAt && isRecent(new Date(e.updatedAt), 24))\n .sort(\n (a, b) =>\n new Date(b.updatedAt!).getTime() - new Date(a.updatedAt!).getTime()\n );\n\n for (const exp of recentExperiments.slice(0, 2)) {\n const timeAgo = formatRelativeTime(new Date(exp.updatedAt!));\n activities.push(\n `${exp.projectName || exp.datasetName}: experiment \"${exp.id.slice(\n 0,\n 8\n )}...\" ${exp.status} ${timeAgo}`\n );\n }\n\n // Find recently updated datasets\n const recentDatasets = stats.datasets\n .filter((d) => d.updatedAt && isRecent(new Date(d.updatedAt), 24))\n .sort(\n (a, b) =>\n new Date(b.updatedAt!).getTime() - new Date(a.updatedAt!).getTime()\n );\n\n for (const dataset of recentDatasets.slice(0, 2)) {\n const timeAgo = formatRelativeTime(new Date(dataset.updatedAt!));\n activities.push(\n `${dataset.name}: dataset updated ${timeAgo} (${dataset.exampleCount} examples)`\n );\n }\n\n return activities.slice(0, 3); // Limit to 3 activities\n}\n\n/**\n * Checks if a date is within the specified hours from now\n */\nfunction isRecent(date: Date, hoursAgo: number): boolean {\n const now = new Date();\n const diff = now.getTime() - date.getTime();\n return diff < hoursAgo * 60 * 60 * 1000;\n}\n\n/**\n * Formats a date as relative time (e.g., \"2 hours ago\")\n */\nfunction formatRelativeTime(date: Date): string {\n const now = new Date();\n const diff = now.getTime() - date.getTime();\n\n const minutes = Math.floor(diff / (1000 * 60));\n const hours = Math.floor(diff / (1000 * 60 * 60));\n const days = Math.floor(diff / (1000 * 60 * 60 * 24));\n\n if (minutes < 1) {\n return \"just now\";\n } else if (minutes < 60) {\n return `${minutes} minute${minutes !== 1 ? \"s\" : \"\"} ago`;\n } else if (hours < 24) {\n return `${hours} hour${hours !== 1 ? \"s\" : \"\"} ago`;\n } else {\n return `${days} day${days !== 1 ? \"s\" : \"\"} ago`;\n }\n}\n","/**\n * Progress indicators for Phoenix Insight CLI\n */\nimport ora, { type Ora } from \"ora\";\n\n/**\n * Progress indicator for snapshot operations\n */\nexport class SnapshotProgress {\n private spinner: Ora | null = null;\n private enabled: boolean;\n private currentPhase: string | null = null;\n private totalSteps = 6;\n private currentStep = 0;\n\n constructor(enabled: boolean = true) {\n this.enabled = enabled;\n }\n\n /**\n * Start the progress indicator\n */\n start(message: string = \"Creating Phoenix data snapshot\") {\n if (!this.enabled) return;\n\n this.currentStep = 0;\n this.spinner = ora({\n text: message,\n spinner: \"dots\",\n color: \"blue\",\n }).start();\n }\n\n /**\n * Update progress with a new phase\n */\n update(phase: string, detail?: string) {\n if (!this.enabled || !this.spinner) return;\n\n this.currentStep++;\n this.currentPhase = phase;\n\n const progress = Math.round((this.currentStep / this.totalSteps) * 100);\n const progressBar = this.createProgressBar(progress);\n\n const message = detail\n ? `${progressBar} ${phase}: ${detail}`\n : `${progressBar} ${phase}`;\n\n this.spinner.text = message;\n }\n\n /**\n * Complete a phase successfully\n */\n succeed(message?: string) {\n if (!this.enabled || !this.spinner) return;\n\n const finalMessage =\n message || `✓ ${this.currentPhase || \"Snapshot\"} complete`;\n this.spinner.succeed(finalMessage);\n this.spinner = null;\n }\n\n /**\n * Fail with an error\n */\n fail(message?: string) {\n if (!this.enabled || !this.spinner) return;\n\n const finalMessage =\n message || `✗ ${this.currentPhase || \"Snapshot\"} failed`;\n this.spinner.fail(finalMessage);\n this.spinner = null;\n }\n\n /**\n * Stop without success/fail status\n */\n stop() {\n if (!this.enabled || !this.spinner) return;\n\n this.spinner.stop();\n this.spinner = null;\n }\n\n /**\n * Create a progress bar string\n */\n private createProgressBar(percentage: number): string {\n const width = 20;\n const filled = Math.round((percentage / 100) * width);\n const empty = width - filled;\n\n const bar = \"█\".repeat(filled) + \"░\".repeat(empty);\n return `[${bar}] ${percentage}%`;\n }\n}\n\n/**\n * Progress indicator for agent thinking\n */\nexport class AgentProgress {\n private spinner: Ora | null = null;\n private enabled: boolean;\n private stepCount = 0;\n private currentTool: string | null = null;\n\n constructor(enabled: boolean = true) {\n this.enabled = enabled;\n }\n\n /**\n * Start thinking indicator\n */\n startThinking() {\n if (!this.enabled) return;\n\n this.stepCount = 0;\n this.currentTool = null;\n this.spinner = ora({\n text: \"🤔 Analyzing...\",\n spinner: \"dots\",\n color: \"cyan\",\n }).start();\n }\n\n /**\n * Update with current tool usage\n */\n updateTool(toolName: string, detail?: string) {\n if (!this.enabled || !this.spinner) return;\n\n this.stepCount++;\n this.currentTool = toolName;\n\n // Map tool names to more user-friendly descriptions\n const friendlyNames: Record<string, string> = {\n bash: \"Running command\",\n px_fetch_more_spans: \"Fetching additional spans\",\n px_fetch_more_trace: \"Fetching trace details\",\n };\n\n const displayName = friendlyNames[toolName] || toolName;\n const message = detail\n ? `🔧 ${displayName}: ${detail}`\n : `🔧 ${displayName} (step ${this.stepCount})`;\n\n this.spinner.text = message;\n }\n\n /**\n * Update with tool result\n */\n updateToolResult(toolName: string, success: boolean = true) {\n if (!this.enabled || !this.spinner) return;\n\n const icon = success ? \"✓\" : \"✗\";\n const status = success ? \"completed\" : \"failed\";\n\n // More informative messages for each tool\n const toolMessages: Record<string, string> = {\n bash: \"Command executed\",\n px_fetch_more_spans: \"Additional spans fetched\",\n px_fetch_more_trace: \"Trace details fetched\",\n };\n\n const baseMessage = toolMessages[toolName] || `Tool ${toolName}`;\n const message = `${icon} ${baseMessage} ${status}`;\n\n // Brief flash of the result before moving on\n this.spinner.text = message;\n }\n\n /**\n * Show progress for a specific action\n */\n updateAction(action: string) {\n if (!this.enabled || !this.spinner) return;\n\n this.spinner.text = `🔍 ${action}...`;\n }\n\n /**\n * Stop the thinking indicator\n */\n stop() {\n if (!this.enabled || !this.spinner) return;\n\n this.spinner.stop();\n this.spinner = null;\n }\n\n /**\n * Complete with a success message\n */\n succeed(message: string = \"✨ Analysis complete\") {\n if (!this.enabled || !this.spinner) return;\n\n this.spinner.succeed(message);\n this.spinner = null;\n }\n}\n\n/**\n * Simple progress logger for when spinners aren't appropriate\n */\nexport class SimpleProgress {\n private enabled: boolean;\n\n constructor(enabled: boolean = true) {\n this.enabled = enabled;\n }\n\n log(message: string) {\n if (!this.enabled) return;\n console.log(`[Phoenix Insight] ${message}`);\n }\n\n info(message: string) {\n if (!this.enabled) return;\n console.log(`ℹ️ ${message}`);\n }\n\n success(message: string) {\n if (!this.enabled) return;\n console.log(`✅ ${message}`);\n }\n\n warning(message: string) {\n if (!this.enabled) return;\n console.log(`⚠️ ${message}`);\n }\n\n error(message: string) {\n if (!this.enabled) return;\n console.log(`❌ ${message}`);\n }\n}\n","// Export all snapshot modules\nexport {\n createPhoenixClient,\n PhoenixClientError,\n type PhoenixClientConfig,\n} from \"./client.js\";\nexport { fetchProjects } from \"./projects.js\";\nexport { snapshotSpans, type SnapshotSpansOptions } from \"./spans.js\";\nexport { fetchDatasets } from \"./datasets.js\";\nexport { fetchExperiments } from \"./experiments.js\";\nexport { fetchPrompts } from \"./prompts.js\";\nexport { generateContext } from \"./context.js\";\n\n// Import necessary types and modules for orchestration\nimport type { ExecutionMode } from \"../modes/types.js\";\nimport type { PhoenixClient } from \"@arizeai/phoenix-client\";\nimport {\n createPhoenixClient,\n PhoenixClientError,\n type PhoenixClientConfig,\n} from \"./client.js\";\nimport { fetchProjects } from \"./projects.js\";\nimport { snapshotSpans, type SnapshotSpansOptions } from \"./spans.js\";\nimport { fetchDatasets } from \"./datasets.js\";\nimport { fetchExperiments } from \"./experiments.js\";\nimport { fetchPrompts } from \"./prompts.js\";\nimport { generateContext } from \"./context.js\";\nimport { SnapshotProgress } from \"../progress.js\";\n\nexport interface SnapshotOptions {\n /**\n * Phoenix server base URL\n */\n baseURL: string;\n /**\n * Optional API key for authentication\n */\n apiKey?: string;\n /**\n * Maximum number of spans per project\n */\n spansPerProject?: number;\n /**\n * Time range filter for spans (ISO 8601 format)\n */\n startTime?: string;\n endTime?: string;\n /**\n * Whether to show progress indicators\n */\n showProgress?: boolean;\n}\n\nexport interface SnapshotMetadata {\n created_at: string;\n phoenix_url: string;\n cursors: {\n spans?: Record<string, { last_end_time?: string; cursor?: string }>;\n datasets?: { last_fetch: string };\n experiments?: { last_fetch: string };\n prompts?: { last_fetch: string };\n };\n limits: {\n spans_per_project: number;\n };\n}\n\n/**\n * Orchestrates all data fetchers to create a complete Phoenix snapshot\n * @param mode - The execution mode (sandbox or local)\n * @param options - Snapshot options including server URL and limits\n */\nexport async function createSnapshot(\n mode: ExecutionMode,\n options: SnapshotOptions\n): Promise<void> {\n const {\n baseURL,\n apiKey,\n spansPerProject = 1000,\n startTime,\n endTime,\n showProgress = false,\n } = options;\n\n // Create progress indicator\n const progress = new SnapshotProgress(showProgress);\n progress.start(\"Creating Phoenix data snapshot\");\n\n // Create Phoenix client\n const clientConfig: PhoenixClientConfig = {\n baseURL,\n apiKey,\n };\n const client = createPhoenixClient(clientConfig);\n\n try {\n // 1. Fetch projects first (required for spans)\n progress.update(\"Fetching projects\");\n try {\n await fetchProjects(client, mode);\n } catch (error) {\n progress.fail(\"Failed to fetch projects\");\n throw new PhoenixClientError(\n `Failed to fetch projects: ${error instanceof Error ? error.message : String(error)}`,\n error instanceof PhoenixClientError ? error.code : \"UNKNOWN_ERROR\",\n error\n );\n }\n\n // 2. Fetch spans and other data in parallel\n progress.update(\n \"Fetching all data\",\n \"spans, datasets, experiments, prompts\"\n );\n const spansOptions: SnapshotSpansOptions = {\n spansPerProject,\n startTime,\n endTime,\n };\n\n // Fetch all data types in parallel for better performance\n const results = await Promise.allSettled([\n snapshotSpans(client, mode, spansOptions),\n fetchDatasets(client, mode),\n fetchExperiments(client, mode),\n fetchPrompts(client, mode),\n ]);\n\n // Check for failures and collect errors\n const errors: Array<{ type: string; error: unknown }> = [];\n const dataTypes = [\"spans\", \"datasets\", \"experiments\", \"prompts\"];\n\n results.forEach((result, index) => {\n if (result.status === \"rejected\") {\n errors.push({\n type: dataTypes[index] || \"unknown\",\n error: result.reason,\n });\n }\n });\n\n if (errors.length > 0) {\n // Log individual errors\n errors.forEach(({ type, error }) => {\n console.error(\n `Warning: Failed to fetch ${type}:`,\n error instanceof Error ? error.message : String(error)\n );\n });\n\n // If spans failed, that's critical - throw error\n if (errors.some((e) => e.type === \"spans\")) {\n progress.fail(\"Failed to fetch spans\");\n throw new PhoenixClientError(\n `Failed to fetch spans: ${errors.find((e) => e.type === \"spans\")?.error}`,\n \"UNKNOWN_ERROR\",\n errors\n );\n }\n\n // If all other data failed, throw error. If partial success, continue with warning\n if (errors.length === 4) {\n progress.fail(\"Failed to fetch all data\");\n throw new PhoenixClientError(\n \"Failed to fetch all data types\",\n \"UNKNOWN_ERROR\",\n errors\n );\n }\n }\n\n // 4. Generate context file\n progress.update(\"Generating context\");\n await generateContext(mode, {\n phoenixUrl: baseURL,\n snapshotTime: new Date(),\n spansPerProject,\n });\n\n // 5. Write metadata file\n progress.update(\"Writing metadata\");\n const metadata: SnapshotMetadata = {\n created_at: new Date().toISOString(),\n phoenix_url: baseURL,\n cursors: {\n spans: {}, // TODO: Track span cursors when span fetching supports it\n datasets: { last_fetch: new Date().toISOString() },\n experiments: { last_fetch: new Date().toISOString() },\n prompts: { last_fetch: new Date().toISOString() },\n },\n limits: {\n spans_per_project: spansPerProject,\n },\n };\n\n await mode.writeFile(\n \"/_meta/snapshot.json\",\n JSON.stringify(metadata, null, 2)\n );\n\n progress.succeed(\"✅ Snapshot created successfully!\");\n } catch (error) {\n // Stop progress if not already stopped\n progress.stop();\n\n // Enhance error with context before rethrowing\n if (error instanceof PhoenixClientError) {\n throw error; // Already has good context\n }\n\n throw new PhoenixClientError(\n `Failed to create snapshot: ${error instanceof Error ? error.message : String(error)}`,\n \"UNKNOWN_ERROR\",\n error\n );\n }\n}\n\n/**\n * Loads existing snapshot metadata if available\n * @param mode - The execution mode (sandbox or local)\n * @returns The snapshot metadata or null if not found\n */\nexport async function loadSnapshotMetadata(\n mode: ExecutionMode\n): Promise<SnapshotMetadata | null> {\n try {\n const result = await mode.exec(\n \"cat /phoenix/_meta/snapshot.json 2>/dev/null\"\n );\n if (result.exitCode === 0) {\n return JSON.parse(result.stdout);\n }\n } catch (error) {\n // File doesn't exist or parse error\n }\n return null;\n}\n\n/**\n * Creates an incremental snapshot, fetching only new/updated data\n * @param mode - The execution mode (sandbox or local)\n * @param options - Snapshot options including server URL and limits\n */\nexport async function createIncrementalSnapshot(\n mode: ExecutionMode,\n options: SnapshotOptions\n): Promise<void> {\n // Load existing metadata to get cursors\n const existingMetadata = await loadSnapshotMetadata(mode);\n\n if (!existingMetadata) {\n // No existing snapshot, create a full one\n await createSnapshot(mode, options);\n return;\n }\n\n const {\n baseURL,\n apiKey,\n spansPerProject = 1000,\n showProgress = false,\n } = options;\n\n // Create progress indicator\n const progress = new SnapshotProgress(showProgress);\n progress.start(\"Updating Phoenix data snapshot\");\n\n // Create Phoenix client\n const clientConfig: PhoenixClientConfig = {\n baseURL,\n apiKey,\n };\n const client = createPhoenixClient(clientConfig);\n\n try {\n // Show time since last snapshot\n const lastSnapshotDate = new Date(existingMetadata.created_at);\n const timeSince = formatTimeSince(lastSnapshotDate);\n progress.update(\"Checking for updates\", `last snapshot ${timeSince} ago`);\n\n // For incremental updates, we'll need to:\n // 1. Fetch projects (always fetch all as they're small)\n progress.update(\"Updating projects\");\n await fetchProjects(client, mode);\n\n // 2. Fetch spans and other data in parallel for better performance\n progress.update(\"Fetching updates\", \"new spans and refreshing other data\");\n\n const spansOptions: SnapshotSpansOptions = {\n spansPerProject,\n // Use the last end time from previous snapshot as start time\n startTime: existingMetadata.cursors.spans\n ? Object.values(existingMetadata.cursors.spans)\n .map((cursor) => cursor.last_end_time)\n .filter(Boolean)\n .sort()\n .pop()\n : undefined,\n };\n\n // For datasets/experiments/prompts, check if they've been updated\n const datasetsLastFetch = existingMetadata.cursors.datasets?.last_fetch;\n const experimentsLastFetch =\n existingMetadata.cursors.experiments?.last_fetch;\n const promptsLastFetch = existingMetadata.cursors.prompts?.last_fetch;\n\n // Fetch all data types in parallel\n // For now, we'll refetch all as the API doesn't support filtering by updated_at\n // In a future enhancement, we could check individual items for updates\n const updateResults = await Promise.allSettled([\n snapshotSpans(client, mode, spansOptions),\n fetchDatasets(client, mode),\n fetchExperiments(client, mode),\n fetchPrompts(client, mode),\n ]);\n\n // Check for critical errors\n const updateErrors: Array<{ type: string; error: unknown }> = [];\n const updateDataTypes = [\"spans\", \"datasets\", \"experiments\", \"prompts\"];\n\n updateResults.forEach((result, index) => {\n if (result.status === \"rejected\") {\n updateErrors.push({\n type: updateDataTypes[index] || \"unknown\",\n error: result.reason,\n });\n }\n });\n\n if (updateErrors.length > 0) {\n // Log individual errors\n updateErrors.forEach(({ type, error }) => {\n console.error(\n `Warning: Failed to update ${type}:`,\n error instanceof Error ? error.message : String(error)\n );\n });\n }\n\n // 4. Regenerate context with updated data\n progress.update(\"Regenerating context\");\n await generateContext(mode, {\n phoenixUrl: baseURL,\n snapshotTime: new Date(),\n spansPerProject,\n });\n\n // 5. Update metadata\n progress.update(\"Updating metadata\");\n const updatedSpansCursors = existingMetadata.cursors.spans || {};\n const metadata: SnapshotMetadata = {\n created_at: new Date().toISOString(),\n phoenix_url: baseURL,\n cursors: {\n spans: updatedSpansCursors,\n datasets: { last_fetch: new Date().toISOString() },\n experiments: { last_fetch: new Date().toISOString() },\n prompts: { last_fetch: new Date().toISOString() },\n },\n limits: {\n spans_per_project: spansPerProject,\n },\n };\n\n await mode.writeFile(\n \"/_meta/snapshot.json\",\n JSON.stringify(metadata, null, 2)\n );\n\n progress.succeed(\"✅ Incremental update complete!\");\n } catch (error) {\n // Stop progress if not already stopped\n progress.stop();\n\n // Enhance error with context before rethrowing\n if (error instanceof PhoenixClientError) {\n throw error; // Already has good context\n }\n\n throw new PhoenixClientError(\n `Failed to create incremental snapshot: ${error instanceof Error ? error.message : String(error)}`,\n \"UNKNOWN_ERROR\",\n error\n );\n }\n}\n\n/**\n * Format time since a date in human-readable format\n */\nfunction formatTimeSince(date: Date): string {\n const seconds = Math.floor((new Date().getTime() - date.getTime()) / 1000);\n\n if (seconds < 60) return `${seconds}s`;\n const minutes = Math.floor(seconds / 60);\n if (minutes < 60) return `${minutes}m`;\n const hours = Math.floor(minutes / 60);\n if (hours < 24) return `${hours}h`;\n const days = Math.floor(hours / 24);\n return `${days}d`;\n}\n","/**\n * Snapshot discovery utilities\n *\n * Functions for listing and finding snapshots in the local filesystem.\n */\n\nimport * as fs from \"node:fs/promises\";\nimport * as path from \"node:path\";\nimport * as os from \"node:os\";\n\n/**\n * Information about a single snapshot\n */\nexport interface SnapshotInfo {\n /** Absolute path to the snapshot directory (the 'phoenix' subdirectory) */\n path: string;\n /** Timestamp when the snapshot was created (from directory name) */\n timestamp: Date;\n /** Unique identifier for the snapshot (directory name) */\n id: string;\n}\n\n/**\n * Get the base snapshots directory path\n */\nexport function getSnapshotsDir(): string {\n return path.join(os.homedir(), \".phoenix-insight\", \"snapshots\");\n}\n\n/**\n * Parse a snapshot directory name to extract timestamp\n *\n * Directory names are in format: `<timestamp>-<random>` where timestamp is Date.now()\n * Example: \"1704067200000-abc123\" -> Date(2024-01-01T00:00:00.000Z)\n *\n * @param dirName - The directory name to parse\n * @returns The parsed timestamp as Date, or null if invalid\n */\nfunction parseSnapshotDirName(dirName: string): Date | null {\n // Format: <timestamp>-<random>\n const match = dirName.match(/^(\\d+)-[\\w]+$/);\n if (!match || !match[1]) {\n return null;\n }\n\n const timestamp = parseInt(match[1], 10);\n if (isNaN(timestamp) || timestamp <= 0) {\n return null;\n }\n\n const date = new Date(timestamp);\n // Validate the date is reasonable (between year 2000 and year 3000)\n // Use UTC year to avoid timezone issues\n const year = date.getUTCFullYear();\n if (year < 2000 || year > 3000) {\n return null;\n }\n\n return date;\n}\n\n/**\n * List all available snapshots\n *\n * Scans the snapshots directory and returns information about each valid snapshot.\n * Results are sorted by timestamp descending (most recent first).\n *\n * @returns Array of snapshot info objects, sorted by timestamp descending\n */\nexport async function listSnapshots(): Promise<SnapshotInfo[]> {\n const snapshotsDir = getSnapshotsDir();\n\n // Check if snapshots directory exists\n try {\n await fs.access(snapshotsDir);\n } catch {\n // Directory doesn't exist - return empty array\n return [];\n }\n\n // Read directory contents\n let entries: string[];\n try {\n entries = await fs.readdir(snapshotsDir);\n } catch {\n // Cannot read directory - return empty array\n return [];\n }\n\n // Filter and parse valid snapshot directories\n const snapshots: SnapshotInfo[] = [];\n\n for (const entry of entries) {\n const timestamp = parseSnapshotDirName(entry);\n if (!timestamp) {\n // Invalid directory name format - skip\n continue;\n }\n\n const snapshotPath = path.join(snapshotsDir, entry, \"phoenix\");\n\n // Verify the phoenix subdirectory exists\n try {\n const stat = await fs.stat(snapshotPath);\n if (!stat.isDirectory()) {\n continue;\n }\n } catch {\n // Phoenix subdirectory doesn't exist or can't be accessed - skip\n continue;\n }\n\n snapshots.push({\n path: snapshotPath,\n timestamp,\n id: entry,\n });\n }\n\n // Sort by timestamp descending (most recent first)\n snapshots.sort((a, b) => b.timestamp.getTime() - a.timestamp.getTime());\n\n return snapshots;\n}\n\n/**\n * Get the latest (most recent) snapshot\n *\n * @returns The most recent snapshot info, or null if no snapshots exist\n */\nexport async function getLatestSnapshot(): Promise<SnapshotInfo | null> {\n const snapshots = await listSnapshots();\n\n if (snapshots.length === 0) {\n return null;\n }\n\n // First element is the most recent due to descending sort\n return snapshots[0] ?? null;\n}\n","/**\n * Phoenix Insight observability configuration\n */\n\nimport { register, type NodeTracerProvider } from \"@arizeai/phoenix-otel\";\nimport { DiagLogLevel } from \"@opentelemetry/api\";\n\n/**\n * Options for configuring observability\n */\nexport interface ObservabilityOptions {\n /** Whether to enable tracing */\n enabled: boolean;\n /** Phoenix base URL for sending traces */\n baseUrl?: string;\n /** Phoenix API key for authentication */\n apiKey?: string;\n /** Phoenix project name for organizing traces */\n projectName?: string;\n /** Whether to enable debug logging */\n debug?: boolean;\n}\n\n/**\n * Global tracer provider instance\n */\nlet tracerProvider: NodeTracerProvider | null = null;\n\n/**\n * Check if observability is enabled\n */\nexport function isObservabilityEnabled(): boolean {\n return tracerProvider !== null;\n}\n\n/**\n * Initialize observability for the Phoenix Insight agent\n */\nexport function initializeObservability(options: ObservabilityOptions): void {\n if (!options.enabled) {\n return;\n }\n\n // If already initialized, skip\n if (tracerProvider) {\n return;\n }\n\n try {\n // Configure the tracer provider\n tracerProvider = register({\n projectName: options.projectName || \"phoenix-insight\",\n url: options.baseUrl,\n apiKey: options.apiKey,\n batch: true,\n global: true,\n diagLogLevel: options.debug ? DiagLogLevel.DEBUG : undefined,\n });\n\n if (options.debug) {\n console.error(\n \"🔭 Observability enabled - traces will be sent to Phoenix\"\n );\n }\n } catch (error) {\n console.error(\"⚠️ Failed to initialize observability:\", error);\n // Don't throw - observability should not break the main functionality\n }\n}\n\n/**\n * Shutdown observability and cleanup resources\n */\nexport async function shutdownObservability(): Promise<void> {\n if (tracerProvider) {\n try {\n await tracerProvider.shutdown();\n tracerProvider = null;\n } catch (error) {\n console.error(\"⚠️ Error shutting down observability:\", error);\n }\n }\n}\n\n/**\n * Get the current tracer provider\n */\nexport function getTracerProvider(): NodeTracerProvider | null {\n return tracerProvider;\n}\n","import { z } from \"zod\";\n\n/**\n * Zod schema for Phoenix Insight CLI configuration\n *\n * Configuration values can be set via:\n * 1. Config file (~/.phoenix-insight/config.json or custom path)\n * 2. Environment variables (PHOENIX_BASE_URL, PHOENIX_API_KEY, etc.)\n * 3. CLI arguments (--base-url, --api-key, etc.)\n *\n * Priority: config file < env vars < CLI args\n */\nexport const configSchema = z.object({\n /**\n * Phoenix server base URL\n * @default \"http://localhost:6006\"\n */\n baseUrl: z.string().default(\"http://localhost:6006\"),\n\n /**\n * Phoenix API key for authentication (optional)\n */\n apiKey: z.string().optional(),\n\n /**\n * Maximum number of spans to fetch per project\n * @default 1000\n */\n limit: z.number().int().positive().default(1000),\n\n /**\n * Enable streaming responses from the agent\n * @default true\n */\n stream: z.boolean().default(true),\n\n /**\n * Execution mode: \"sandbox\" for in-memory filesystem, \"local\" for real filesystem\n * @default \"sandbox\"\n */\n mode: z.enum([\"sandbox\", \"local\"]).default(\"sandbox\"),\n\n /**\n * Force refresh of snapshot data\n * @default false\n */\n refresh: z.boolean().default(false),\n\n /**\n * Enable tracing of the agent to Phoenix\n * @default true\n */\n trace: z.boolean().default(true),\n});\n\n/**\n * Inferred TypeScript type from the config schema\n */\nexport type Config = z.infer<typeof configSchema>;\n\n/**\n * Get default configuration values\n */\nexport function getDefaultConfig(): Config {\n return configSchema.parse({});\n}\n","import * as fs from \"node:fs/promises\";\nimport * as path from \"node:path\";\nimport * as os from \"node:os\";\nimport { configSchema, getDefaultConfig, type Config } from \"./schema.js\";\n\n/**\n * Default config directory and file path\n */\nconst DEFAULT_CONFIG_DIR = path.join(os.homedir(), \".phoenix-insight\");\nconst DEFAULT_CONFIG_FILE = path.join(DEFAULT_CONFIG_DIR, \"config.json\");\n\n/**\n * Module-level storage for CLI args passed from commander\n * This is set externally before getConfigPath is called\n */\nlet cliConfigPath: string | undefined;\n\n/**\n * Set the CLI config path (called from CLI parsing)\n */\nexport function setCliConfigPath(configPath: string | undefined): void {\n cliConfigPath = configPath;\n}\n\n/**\n * Get the config file path based on priority:\n * 1. CLI argument (--config)\n * 2. Environment variable (PHOENIX_INSIGHT_CONFIG)\n * 3. Default path (~/.phoenix-insight/config.json)\n *\n * @returns The path to the config file and whether it's the default path\n */\nexport function getConfigPath(): { path: string; isDefault: boolean } {\n // Priority 1: CLI argument\n if (cliConfigPath) {\n return { path: cliConfigPath, isDefault: false };\n }\n\n // Priority 2: Environment variable\n const envConfigPath = process.env.PHOENIX_INSIGHT_CONFIG;\n if (envConfigPath) {\n return { path: envConfigPath, isDefault: false };\n }\n\n // Priority 3: Default path\n return { path: DEFAULT_CONFIG_FILE, isDefault: true };\n}\n\n/**\n * Load and parse a config file from disk\n *\n * @param configPath - Path to the config file\n * @returns Parsed JSON object or null if file not found\n * @throws Error if file exists but cannot be parsed as JSON\n */\nexport async function loadConfigFile(\n configPath: string\n): Promise<Record<string, unknown> | null> {\n try {\n const content = await fs.readFile(configPath, \"utf-8\");\n return JSON.parse(content) as Record<string, unknown>;\n } catch (error) {\n // File not found is expected - return null\n if (error instanceof Error && \"code\" in error && error.code === \"ENOENT\") {\n return null;\n }\n\n // JSON parse errors should be reported\n if (error instanceof SyntaxError) {\n console.warn(\n `Warning: Config file at ${configPath} contains invalid JSON: ${error.message}`\n );\n return null;\n }\n\n // Other errors (permissions, etc.) - warn and return null\n console.warn(\n `Warning: Could not read config file at ${configPath}: ${error instanceof Error ? error.message : String(error)}`\n );\n return null;\n }\n}\n\n/**\n * Validate a raw config object against the schema\n * Returns validated config or defaults if validation fails\n *\n * @param raw - Raw config object (or null/undefined)\n * @returns Validated config with defaults applied\n */\nexport function validateConfig(\n raw: Record<string, unknown> | null | undefined\n): Config {\n // If no raw config, return defaults\n if (!raw) {\n return getDefaultConfig();\n }\n\n try {\n // Parse with Zod schema - this applies defaults for missing fields\n return configSchema.parse(raw);\n } catch (error) {\n // Log validation errors as warnings\n if (error instanceof Error && \"issues\" in error) {\n // Zod error with issues array\n const zodError = error as {\n issues: Array<{ path: string[]; message: string }>;\n };\n zodError.issues.forEach((issue) => {\n console.warn(\n `Warning: Config validation error at '${issue.path.join(\".\")}': ${issue.message}`\n );\n });\n } else {\n console.warn(\n `Warning: Config validation failed: ${error instanceof Error ? error.message : String(error)}`\n );\n }\n\n // Return defaults on validation failure\n return getDefaultConfig();\n }\n}\n\n/**\n * Create a default config file at the given path\n * Only creates the file if it doesn't already exist\n * Only triggers for the default path, not custom paths\n *\n * @param configPath - Path where to create the config file\n * @param isDefault - Whether this is the default path (only create if true)\n * @returns true if file was created, false otherwise\n */\nexport async function createDefaultConfig(\n configPath: string,\n isDefault: boolean\n): Promise<boolean> {\n // Only create default config for the default path\n if (!isDefault) {\n return false;\n }\n\n try {\n // Check if file already exists\n await fs.access(configPath);\n // File exists, don't overwrite\n return false;\n } catch {\n // File doesn't exist, create it\n }\n\n try {\n // Create directory if needed\n const configDir = path.dirname(configPath);\n await fs.mkdir(configDir, { recursive: true });\n\n // Get default config and write it\n const defaultConfig = getDefaultConfig();\n const content = JSON.stringify(defaultConfig, null, 2);\n await fs.writeFile(configPath, content, \"utf-8\");\n\n // Log informational message to stderr\n console.error(`Created default config at ${configPath}`);\n\n return true;\n } catch (error) {\n // Log warning but don't fail - config will use defaults\n console.warn(\n `Warning: Could not create default config at ${configPath}: ${error instanceof Error ? error.message : String(error)}`\n );\n return false;\n }\n}\n","/**\n * Config singleton module for Phoenix Insight CLI\n *\n * Provides centralized configuration management with priority-based merging:\n * 1. Config file (lowest priority)\n * 2. Environment variables\n * 3. CLI arguments (highest priority)\n */\n\nimport { configSchema, type Config, getDefaultConfig } from \"./schema.js\";\nimport {\n getConfigPath,\n loadConfigFile,\n validateConfig,\n createDefaultConfig,\n setCliConfigPath,\n} from \"./loader.js\";\n\n// Re-export Config type for convenience\nexport type { Config } from \"./schema.js\";\n\n/**\n * Module-level storage for the initialized config singleton\n */\nlet configInstance: Config | null = null;\n\n/**\n * CLI arguments that can override config values\n */\nexport interface CliArgs {\n /** Custom config file path */\n config?: string;\n /** Phoenix server base URL */\n baseUrl?: string;\n /** Phoenix API key */\n apiKey?: string;\n /** Maximum spans to fetch per project */\n limit?: number;\n /** Enable streaming responses */\n stream?: boolean;\n /** Execution mode: sandbox or local */\n local?: boolean;\n /** Force refresh of snapshot data */\n refresh?: boolean;\n /** Enable tracing */\n trace?: boolean;\n}\n\n/**\n * Environment variable mappings to config keys\n */\nconst ENV_VAR_MAPPINGS: Record<string, keyof Config> = {\n PHOENIX_BASE_URL: \"baseUrl\",\n PHOENIX_API_KEY: \"apiKey\",\n PHOENIX_INSIGHT_LIMIT: \"limit\",\n PHOENIX_INSIGHT_STREAM: \"stream\",\n PHOENIX_INSIGHT_MODE: \"mode\",\n PHOENIX_INSIGHT_REFRESH: \"refresh\",\n PHOENIX_INSIGHT_TRACE: \"trace\",\n};\n\n/**\n * Parse environment variable value to appropriate type\n */\nfunction parseEnvValue(\n key: keyof Config,\n value: string\n): string | number | boolean | undefined {\n switch (key) {\n case \"baseUrl\":\n case \"apiKey\":\n return value;\n case \"limit\":\n const num = parseInt(value, 10);\n return isNaN(num) ? undefined : num;\n case \"stream\":\n case \"refresh\":\n case \"trace\":\n return value.toLowerCase() === \"true\" || value === \"1\";\n case \"mode\":\n if (value === \"sandbox\" || value === \"local\") {\n return value;\n }\n return undefined;\n default:\n return value;\n }\n}\n\n/**\n * Get config values from environment variables\n */\nfunction getEnvConfig(): Partial<Config> {\n const envConfig: Partial<Config> = {};\n\n for (const [envVar, configKey] of Object.entries(ENV_VAR_MAPPINGS)) {\n const value = process.env[envVar];\n if (value !== undefined) {\n const parsed = parseEnvValue(configKey, value);\n if (parsed !== undefined) {\n (envConfig as any)[configKey] = parsed;\n }\n }\n }\n\n return envConfig;\n}\n\n/**\n * Convert CLI args to config format\n */\nfunction cliArgsToConfig(cliArgs: CliArgs): Partial<Config> {\n const config: Partial<Config> = {};\n\n if (cliArgs.baseUrl !== undefined) {\n config.baseUrl = cliArgs.baseUrl;\n }\n if (cliArgs.apiKey !== undefined) {\n config.apiKey = cliArgs.apiKey;\n }\n if (cliArgs.limit !== undefined) {\n config.limit = cliArgs.limit;\n }\n if (cliArgs.stream !== undefined) {\n config.stream = cliArgs.stream;\n }\n if (cliArgs.local !== undefined) {\n // CLI uses --local flag, config uses mode\n config.mode = cliArgs.local ? \"local\" : \"sandbox\";\n }\n if (cliArgs.refresh !== undefined) {\n config.refresh = cliArgs.refresh;\n }\n if (cliArgs.trace !== undefined) {\n config.trace = cliArgs.trace;\n }\n\n return config;\n}\n\n/**\n * Initialize the configuration singleton\n *\n * Merges configuration from multiple sources with the following priority:\n * 1. Config file (lowest priority)\n * 2. Environment variables\n * 3. CLI arguments (highest priority)\n *\n * @param cliArgs - CLI arguments from Commander\n * @returns The initialized configuration\n */\nexport async function initializeConfig(cliArgs: CliArgs = {}): Promise<Config> {\n // Set CLI config path if provided (for getConfigPath to use)\n if (cliArgs.config) {\n setCliConfigPath(cliArgs.config);\n }\n\n // Get config file path\n const { path: configPath, isDefault } = getConfigPath();\n\n // Try to create default config if it doesn't exist (only for default path)\n if (isDefault) {\n await createDefaultConfig(configPath, isDefault);\n }\n\n // Load config file\n const fileConfig = await loadConfigFile(configPath);\n\n // Validate file config (returns defaults if null/invalid)\n const validatedFileConfig = validateConfig(fileConfig);\n\n // Get environment config\n const envConfig = getEnvConfig();\n\n // Get CLI config\n const cliConfig = cliArgsToConfig(cliArgs);\n\n // Merge configs: file < env < cli\n const mergedConfig = {\n ...validatedFileConfig,\n ...envConfig,\n ...cliConfig,\n };\n\n // Final validation with Zod\n const result = configSchema.safeParse(mergedConfig);\n\n if (result.success) {\n configInstance = result.data;\n } else {\n // Log validation issues as warnings\n result.error.issues.forEach((issue) => {\n console.warn(\n `Warning: Config validation error at '${issue.path.join(\".\")}': ${issue.message}`\n );\n });\n // Fall back to defaults\n configInstance = getDefaultConfig();\n }\n\n return configInstance;\n}\n\n/**\n * Get the initialized configuration\n *\n * @throws Error if config has not been initialized via initializeConfig()\n * @returns The configuration object\n */\nexport function getConfig(): Config {\n if (configInstance === null) {\n throw new Error(\n \"Config not initialized. Call initializeConfig() first before using getConfig().\"\n );\n }\n return configInstance;\n}\n\n/**\n * Reset the config singleton (useful for testing)\n */\nexport function resetConfig(): void {\n configInstance = null;\n setCliConfigPath(undefined);\n}\n","/**\n * HTTP server for Phoenix Insight UI.\n * Serves the static build of @cephalization/phoenix-insight-ui package.\n *\n * Binds to localhost only for security (no external network access).\n * Handles SPA routing by serving index.html for non-asset routes.\n */\n\nimport { createServer, type Server as HttpServer } from \"node:http\";\nimport { createReadStream, existsSync, statSync } from \"node:fs\";\nimport { extname, join, resolve } from \"node:path\";\nimport { fileURLToPath } from \"node:url\";\n\n// ============================================================================\n// MIME Type Mapping\n// ============================================================================\n\nconst MIME_TYPES: Record<string, string> = {\n \".html\": \"text/html; charset=utf-8\",\n \".css\": \"text/css; charset=utf-8\",\n \".js\": \"text/javascript; charset=utf-8\",\n \".mjs\": \"text/javascript; charset=utf-8\",\n \".json\": \"application/json; charset=utf-8\",\n \".svg\": \"image/svg+xml\",\n \".png\": \"image/png\",\n \".jpg\": \"image/jpeg\",\n \".jpeg\": \"image/jpeg\",\n \".gif\": \"image/gif\",\n \".ico\": \"image/x-icon\",\n \".webp\": \"image/webp\",\n \".woff\": \"font/woff\",\n \".woff2\": \"font/woff2\",\n \".ttf\": \"font/ttf\",\n \".eot\": \"application/vnd.ms-fontobject\",\n \".map\": \"application/json\",\n};\n\n/**\n * Get MIME type for a file extension\n */\nfunction getMimeType(filePath: string): string {\n const ext = extname(filePath).toLowerCase();\n return MIME_TYPES[ext] ?? \"application/octet-stream\";\n}\n\n// ============================================================================\n// Path Resolution\n// ============================================================================\n\n/**\n * Resolve the UI package dist directory path.\n * \n * Resolution order:\n * 1. Bundled dist/ui (copied during build, used for npm published package)\n * 2. import.meta.resolve (finds package in node_modules, used for development)\n * 3. Relative path fallback (for development before packages are linked)\n */\nexport function resolveUIDistPath(): string {\n const __dirname = fileURLToPath(new URL(\".\", import.meta.url));\n \n // First check for bundled UI dist (copied during CLI build)\n // This is the path when installed from npm\n // When bundled by tsup, cli.js is at dist/cli.js and UI is at dist/ui/\n const bundledPath = resolve(__dirname, \"ui\");\n if (existsSync(bundledPath) && existsSync(join(bundledPath, \"index.html\"))) {\n return bundledPath;\n }\n \n try {\n // Resolve the UI package's package.json using import.meta.resolve\n // import.meta.resolve returns a file URL (file:///...)\n const packageJsonUrl = import.meta.resolve(\n \"@cephalization/phoenix-insight-ui/package.json\"\n );\n const packageJsonPath = fileURLToPath(packageJsonUrl);\n const packageDir = resolve(packageJsonPath, \"..\");\n return join(packageDir, \"dist\");\n } catch {\n // Fallback: try to resolve relative to this file (for development)\n return resolve(__dirname, \"../../../ui/dist\");\n }\n}\n\n// ============================================================================\n// Server Options\n// ============================================================================\n\nexport interface UIServerOptions {\n /** Port to listen on (default: 6007) */\n port?: number;\n /** Host to bind to (default: \"127.0.0.1\" for localhost only) */\n host?: string;\n /** Custom path to UI dist directory (default: auto-resolved) */\n distPath?: string;\n}\n\nexport interface UIServer {\n /** The underlying HTTP server */\n httpServer: HttpServer;\n /** The port the server is listening on */\n port: number;\n /** The host the server is bound to */\n host: string;\n /** Path to the UI dist directory being served */\n distPath: string;\n /** Close the server gracefully */\n close(): Promise<void>;\n /** Force close all connections immediately */\n forceClose(): void;\n}\n\n// ============================================================================\n// Static File Server\n// ============================================================================\n\n/**\n * Determine if a path should be served as a static asset.\n * Asset paths have file extensions (e.g., .js, .css, .png).\n * Non-asset paths (routes) should get the SPA index.html.\n */\nfunction isAssetPath(urlPath: string): boolean {\n // Check for file extension in the last segment\n const lastSegment = urlPath.split(\"/\").pop() ?? \"\";\n return lastSegment.includes(\".\");\n}\n\n/**\n * Sanitize URL path to prevent directory traversal attacks.\n * Returns null if the path is invalid.\n */\nfunction sanitizePath(urlPath: string, basePath: string): string | null {\n // Decode URI and normalize slashes\n let decoded: string;\n try {\n decoded = decodeURIComponent(urlPath);\n } catch {\n return null;\n }\n\n // Remove query string and hash\n const withoutQuery = decoded.split(\"?\")[0] ?? decoded;\n decoded = withoutQuery.split(\"#\")[0] ?? withoutQuery;\n\n // Resolve the full path\n const fullPath = resolve(basePath, \".\" + decoded);\n\n // Ensure the resolved path is within the base directory\n if (!fullPath.startsWith(basePath)) {\n return null;\n }\n\n return fullPath;\n}\n\n/**\n * Create an HTTP server that serves the Phoenix Insight UI.\n *\n * Features:\n * - Serves static files from the UI package dist directory\n * - SPA fallback: non-asset routes serve index.html\n * - Binds to localhost only (127.0.0.1) for security\n * - Proper MIME types for all common web assets\n *\n * @param options - Server configuration options\n * @returns Promise resolving to UIServer instance\n */\nexport function createUIServer(options: UIServerOptions = {}): Promise<UIServer> {\n const port = options.port ?? 6007;\n const host = options.host ?? \"127.0.0.1\";\n const distPath = options.distPath ?? resolveUIDistPath();\n\n // Verify dist directory exists\n if (!existsSync(distPath)) {\n return Promise.reject(\n new Error(\n `UI dist directory not found at: ${distPath}\\n` +\n \"Make sure to build the UI package first: pnpm --filter @cephalization/phoenix-insight-ui build\"\n )\n );\n }\n\n // Verify index.html exists\n const indexPath = join(distPath, \"index.html\");\n if (!existsSync(indexPath)) {\n return Promise.reject(\n new Error(\n `UI index.html not found at: ${indexPath}\\n` +\n \"Make sure to build the UI package first: pnpm --filter @cephalization/phoenix-insight-ui build\"\n )\n );\n }\n\n return new Promise((resolve, reject) => {\n // Track active connections for force-close capability\n const activeConnections = new Set<import(\"node:net\").Socket>();\n\n const httpServer = createServer((req, res) => {\n const urlPath = req.url ?? \"/\";\n\n // Sanitize the path to prevent directory traversal\n let filePath = sanitizePath(urlPath, distPath);\n if (!filePath) {\n res.writeHead(400, { \"Content-Type\": \"text/plain\" });\n res.end(\"Bad Request\");\n return;\n }\n\n // SPA fallback: if not an asset path, serve index.html\n if (!isAssetPath(urlPath)) {\n filePath = indexPath;\n }\n\n // Check if file exists\n if (!existsSync(filePath)) {\n // For missing assets, return 404\n // For missing routes, serve index.html (SPA)\n if (isAssetPath(urlPath)) {\n res.writeHead(404, { \"Content-Type\": \"text/plain\" });\n res.end(\"Not Found\");\n return;\n }\n filePath = indexPath;\n }\n\n // Get file stats\n let stats;\n try {\n stats = statSync(filePath);\n } catch {\n res.writeHead(500, { \"Content-Type\": \"text/plain\" });\n res.end(\"Internal Server Error\");\n return;\n }\n\n // If it's a directory, serve index.html\n if (stats.isDirectory()) {\n filePath = indexPath;\n try {\n stats = statSync(filePath);\n } catch {\n res.writeHead(500, { \"Content-Type\": \"text/plain\" });\n res.end(\"Internal Server Error\");\n return;\n }\n }\n\n // Set response headers\n const mimeType = getMimeType(filePath);\n res.writeHead(200, {\n \"Content-Type\": mimeType,\n \"Content-Length\": stats.size,\n \"Cache-Control\": filePath === indexPath\n ? \"no-cache\" // Don't cache index.html for SPA\n : \"public, max-age=31536000\", // Cache assets for 1 year\n });\n\n // Stream the file\n const stream = createReadStream(filePath);\n stream.pipe(res);\n stream.on(\"error\", () => {\n res.writeHead(500, { \"Content-Type\": \"text/plain\" });\n res.end(\"Internal Server Error\");\n });\n });\n\n // Track connections to enable force-close\n httpServer.on(\"connection\", (socket) => {\n activeConnections.add(socket);\n socket.on(\"close\", () => {\n activeConnections.delete(socket);\n });\n });\n\n // Handle server errors\n httpServer.on(\"error\", (err) => {\n reject(err);\n });\n\n // Start listening\n httpServer.listen(port, host, () => {\n // Get the actual assigned port (important when port 0 is specified)\n const address = httpServer.address();\n const actualPort = typeof address === \"object\" && address !== null\n ? address.port\n : port;\n\n resolve({\n httpServer,\n port: actualPort,\n host,\n distPath,\n close(): Promise<void> {\n return new Promise((resolveClose, rejectClose) => {\n httpServer.close((err) => {\n if (err) {\n rejectClose(err);\n } else {\n resolveClose();\n }\n });\n });\n },\n forceClose(): void {\n // Destroy all active connections immediately\n for (const socket of activeConnections) {\n socket.destroy();\n }\n activeConnections.clear();\n },\n });\n });\n });\n}\n","/**\n * WebSocket server for Phoenix Insight CLI.\n * Provides bidirectional communication between the CLI agent and the web UI.\n *\n * Binds to localhost only for security (no external network access).\n * Handles HTTP upgrade requests, manages client connections, and broadcasts messages.\n */\n\nimport type { Server as HttpServer, IncomingMessage } from \"node:http\";\nimport { WebSocketServer, WebSocket } from \"ws\";\nimport type {\n ClientMessage,\n ServerMessage,\n JSONRenderTree,\n} from \"@cephalization/phoenix-insight-ui/types\";\n\n// Re-export types for consumers of this module\nexport type { ClientMessage, ServerMessage, JSONRenderTree };\n\n// ============================================================================\n// Event Handler Types\n// ============================================================================\n\nexport type ClientMessageHandler = (\n message: ClientMessage,\n client: WebSocket\n) => void;\nexport type ConnectionHandler = (client: WebSocket) => void;\nexport type DisconnectionHandler = (\n client: WebSocket,\n code: number,\n reason: string\n) => void;\nexport type ErrorHandler = (error: Error, client?: WebSocket) => void;\n\n// ============================================================================\n// WebSocket Server Options\n// ============================================================================\n\nexport interface WebSocketServerOptions {\n /** Path to accept WebSocket connections on (default: \"/ws\") */\n path?: string;\n /** Handler for incoming client messages */\n onMessage?: ClientMessageHandler;\n /** Handler for new client connections */\n onConnection?: ConnectionHandler;\n /** Handler for client disconnections */\n onDisconnection?: DisconnectionHandler;\n /** Handler for WebSocket errors */\n onError?: ErrorHandler;\n}\n\n// ============================================================================\n// Phoenix WebSocket Server\n// ============================================================================\n\n/**\n * Phoenix WebSocket server wrapper providing typed message handling\n * and connection management.\n */\nexport class PhoenixWebSocketServer {\n private wss: WebSocketServer | null = null;\n private clients: Set<WebSocket> = new Set();\n private options: Required<WebSocketServerOptions>;\n\n constructor(options: WebSocketServerOptions = {}) {\n this.options = {\n path: \"/ws\",\n onMessage: () => {},\n onConnection: () => {},\n onDisconnection: () => {},\n onError: () => {},\n ...options,\n };\n }\n\n /**\n * Attach the WebSocket server to an existing HTTP server.\n * Uses the upgrade event to handle WebSocket handshakes.\n */\n attach(httpServer: HttpServer): void {\n if (this.wss) {\n throw new Error(\"WebSocket server is already attached\");\n }\n\n // Create WebSocket server with noServer mode to handle upgrade ourselves\n this.wss = new WebSocketServer({ noServer: true });\n\n // Handle HTTP upgrade requests\n httpServer.on(\"upgrade\", (request, socket, head) => {\n this.handleUpgrade(request, socket, head);\n });\n\n // Set up WebSocket server event handlers\n this.setupEventHandlers();\n }\n\n /**\n * Handle HTTP upgrade request for WebSocket connection.\n * Only accepts connections on the configured path and from localhost.\n */\n private handleUpgrade(\n request: IncomingMessage,\n socket: import(\"node:stream\").Duplex,\n head: Buffer\n ): void {\n if (!this.wss) {\n socket.destroy();\n return;\n }\n\n // Parse the request URL\n const url = new URL(request.url ?? \"/\", `http://${request.headers.host}`);\n\n // Only accept connections on the configured path\n if (url.pathname !== this.options.path) {\n socket.destroy();\n return;\n }\n\n // Complete the WebSocket handshake\n this.wss.handleUpgrade(request, socket, head, (ws) => {\n this.wss?.emit(\"connection\", ws, request);\n });\n }\n\n /**\n * Set up event handlers for the WebSocket server.\n */\n private setupEventHandlers(): void {\n if (!this.wss) return;\n\n this.wss.on(\"connection\", (ws: WebSocket) => {\n this.clients.add(ws);\n this.options.onConnection(ws);\n\n ws.on(\"message\", (data: Buffer | ArrayBuffer | Buffer[]) => {\n this.handleMessage(data, ws);\n });\n\n ws.on(\"close\", (code: number, reason: Buffer) => {\n this.clients.delete(ws);\n this.options.onDisconnection(ws, code, reason.toString());\n });\n\n ws.on(\"error\", (error: Error) => {\n this.options.onError(error, ws);\n });\n });\n\n this.wss.on(\"error\", (error: Error) => {\n this.options.onError(error);\n });\n }\n\n /**\n * Handle incoming message from a client.\n * Parses JSON and validates message structure before calling handler.\n */\n private handleMessage(\n data: Buffer | ArrayBuffer | Buffer[],\n client: WebSocket\n ): void {\n try {\n const rawMessage = data.toString();\n const parsed = JSON.parse(rawMessage) as unknown;\n\n // Basic validation of message structure\n if (!parsed || typeof parsed !== \"object\") {\n throw new Error(\"Invalid message structure: expected object\");\n }\n\n const obj = parsed as Record<string, unknown>;\n if (!(\"type\" in obj) || typeof obj.type !== \"string\") {\n throw new Error(\"Invalid message structure: missing type field\");\n }\n\n const messageType = obj.type;\n if (messageType !== \"query\" && messageType !== \"cancel\") {\n throw new Error(`Unknown message type: ${messageType}`);\n }\n\n // Now we know this is a valid ClientMessage\n const message = parsed as ClientMessage;\n this.options.onMessage(message, client);\n } catch (error) {\n // Send error message back to the client\n const errorMessage: ServerMessage = {\n type: \"error\",\n payload: {\n message:\n error instanceof Error\n ? error.message\n : \"Failed to parse message\",\n },\n };\n this.sendToClient(client, errorMessage);\n }\n }\n\n /**\n * Send a message to a specific client.\n */\n sendToClient(client: WebSocket, message: ServerMessage): void {\n if (client.readyState === WebSocket.OPEN) {\n client.send(JSON.stringify(message));\n }\n }\n\n /**\n * Broadcast a message to all connected clients.\n */\n broadcast(message: ServerMessage): void {\n const data = JSON.stringify(message);\n for (const client of this.clients) {\n if (client.readyState === WebSocket.OPEN) {\n client.send(data);\n }\n }\n }\n\n /**\n * Broadcast a message to all clients with a specific session ID.\n * This requires tracking session-to-client mapping externally.\n * For now, it broadcasts to all clients (to be refined in cli-agent-session).\n */\n broadcastToSession(sessionId: string, message: ServerMessage): void {\n // For now, broadcast to all clients.\n // Session-to-client mapping will be implemented in cli-agent-session task.\n this.broadcast(message);\n }\n\n /**\n * Get the number of connected clients.\n */\n get clientCount(): number {\n return this.clients.size;\n }\n\n /**\n * Get all connected clients.\n */\n getClients(): Set<WebSocket> {\n return new Set(this.clients);\n }\n\n /**\n * Close the WebSocket server and disconnect all clients.\n */\n close(): Promise<void> {\n return new Promise((resolve, reject) => {\n if (!this.wss) {\n resolve();\n return;\n }\n\n // Close all client connections\n for (const client of this.clients) {\n client.close(1000, \"Server shutting down\");\n }\n this.clients.clear();\n\n // Close the WebSocket server\n this.wss.close((err) => {\n this.wss = null;\n if (err) {\n reject(err);\n } else {\n resolve();\n }\n });\n });\n }\n\n /**\n * Force terminate all WebSocket connections immediately.\n * Use this when graceful close doesn't complete in time.\n */\n forceClose(): void {\n if (!this.wss) {\n return;\n }\n\n // Terminate all client connections immediately (no close handshake)\n for (const client of this.clients) {\n client.terminate();\n }\n this.clients.clear();\n }\n}\n\n// ============================================================================\n// Factory Function\n// ============================================================================\n\n/**\n * Create and attach a WebSocket server to an HTTP server.\n * The WebSocket server binds to localhost only (through the HTTP server).\n *\n * @param httpServer - HTTP server to attach WebSocket handling to\n * @param options - WebSocket server options\n * @returns PhoenixWebSocketServer instance\n */\nexport function createWebSocketServer(\n httpServer: HttpServer,\n options?: WebSocketServerOptions\n): PhoenixWebSocketServer {\n const server = new PhoenixWebSocketServer(options);\n server.attach(httpServer);\n return server;\n}\n","/**\n * AgentSession manages a single WebSocket client's agent interaction.\n * Handles query execution, streaming responses, tool call notifications,\n * and report generation via the report tool.\n */\n\nimport type { WebSocket } from \"ws\";\nimport type { ServerMessage, JSONRenderTree } from \"./websocket.js\";\nimport {\n PhoenixInsightAgent,\n createInsightAgent,\n type PhoenixInsightAgentConfig,\n} from \"../agent/index.js\";\nimport type { ExecutionMode } from \"../modes/types.js\";\nimport type { PhoenixClient } from \"@arizeai/phoenix-client\";\nimport { createReportTool } from \"../commands/report-tool.js\";\n\n// ============================================================================\n// Types\n// ============================================================================\n\n/**\n * Message in conversation history\n */\nexport interface ConversationMessage {\n role: \"user\" | \"assistant\";\n content: string;\n timestamp: number;\n}\n\n/**\n * Callback for broadcasting messages to a WebSocket client\n */\nexport type BroadcastCallback = (message: ServerMessage) => void;\n\n/**\n * Options for creating an AgentSession\n */\nexport interface AgentSessionOptions {\n /** Unique session ID */\n sessionId: string;\n /** The execution mode (sandbox or local) */\n mode: ExecutionMode;\n /** Phoenix client instance */\n client: PhoenixClient;\n /** Maximum number of agent steps before stopping (default: 25) */\n maxSteps?: number;\n /** Callback to send messages to the client */\n broadcast: BroadcastCallback;\n}\n\n/**\n * Report generation callback that can be passed to tools\n */\nexport type ReportCallback = (content: JSONRenderTree, title?: string) => void;\n\n// ============================================================================\n// AgentSession Class\n// ============================================================================\n\n/**\n * Manages a single WebSocket client's agent interaction.\n * - Handles query execution with streaming responses\n * - Sends tool call and tool result notifications\n * - Maintains conversation history within session\n * - Supports cancellation of in-progress queries\n */\nexport class AgentSession {\n private sessionId: string;\n private mode: ExecutionMode;\n private client: PhoenixClient;\n private maxSteps: number;\n private broadcast: BroadcastCallback;\n private agent: PhoenixInsightAgent | null = null;\n private conversationHistory: ConversationMessage[] = [];\n private isExecuting = false;\n private abortController: AbortController | null = null;\n\n constructor(options: AgentSessionOptions) {\n this.sessionId = options.sessionId;\n this.mode = options.mode;\n this.client = options.client;\n this.maxSteps = options.maxSteps ?? 25;\n this.broadcast = options.broadcast;\n }\n\n /**\n * Get the session ID\n */\n get id(): string {\n return this.sessionId;\n }\n\n /**\n * Check if a query is currently being executed\n */\n get executing(): boolean {\n return this.isExecuting;\n }\n\n /**\n * Get the conversation history\n */\n get history(): ConversationMessage[] {\n return [...this.conversationHistory];\n }\n\n /**\n * Initialize the agent lazily, including the report tool for UI mode\n */\n private async getAgent(): Promise<PhoenixInsightAgent> {\n if (!this.agent) {\n // Create the report tool with a callback to send reports to the client\n const reportTool = createReportTool((content, title) => {\n this.sendReport(content, title);\n });\n\n const config: PhoenixInsightAgentConfig = {\n mode: this.mode,\n client: this.client,\n maxSteps: this.maxSteps,\n additionalTools: {\n generate_report: reportTool,\n },\n };\n this.agent = await createInsightAgent(config);\n }\n return this.agent;\n }\n\n /**\n * Send a message to the connected client\n */\n private send(message: ServerMessage): void {\n this.broadcast(message);\n }\n\n /**\n * Send a text chunk to the client\n */\n private sendText(content: string): void {\n this.send({\n type: \"text\",\n payload: { content, sessionId: this.sessionId },\n });\n }\n\n /**\n * Send a tool call notification to the client\n */\n private sendToolCall(toolName: string, args: unknown): void {\n this.send({\n type: \"tool_call\",\n payload: { toolName, args, sessionId: this.sessionId },\n });\n }\n\n /**\n * Send a tool result notification to the client\n */\n private sendToolResult(toolName: string, result: unknown): void {\n this.send({\n type: \"tool_result\",\n payload: { toolName, result, sessionId: this.sessionId },\n });\n }\n\n /**\n * Send a report update to the client\n */\n sendReport(content: JSONRenderTree, title?: string): void {\n this.send({\n type: \"report\",\n payload: { content, sessionId: this.sessionId },\n });\n }\n\n /**\n * Send an error message to the client\n */\n private sendError(message: string): void {\n this.send({\n type: \"error\",\n payload: { message, sessionId: this.sessionId },\n });\n }\n\n /**\n * Send the done signal to the client\n */\n private sendDone(): void {\n this.send({\n type: \"done\",\n payload: { sessionId: this.sessionId },\n });\n }\n\n /**\n * Add a message to the conversation history\n */\n private addToHistory(role: \"user\" | \"assistant\", content: string): void {\n this.conversationHistory.push({\n role,\n content,\n timestamp: Date.now(),\n });\n }\n\n /**\n * Get a callback function for the report tool\n * This can be passed to the report tool to send reports to the client\n */\n getReportCallback(): ReportCallback {\n return (content: JSONRenderTree, title?: string) => {\n this.sendReport(content, title);\n };\n }\n\n /**\n * Execute a query and stream the response to the client\n */\n async executeQuery(query: string): Promise<void> {\n if (this.isExecuting) {\n this.sendError(\"A query is already being executed\");\n return;\n }\n\n this.isExecuting = true;\n this.abortController = new AbortController();\n\n // Add user message to history\n this.addToHistory(\"user\", query);\n\n try {\n const agent = await this.getAgent();\n\n // Use streaming for responses\n const result = await agent.stream(query, {});\n\n // Stream using fullStream to get real-time tool call/result events\n // This ensures tool calls are sent BEFORE execution, not after\n let fullResponse = \"\";\n let lastStepHadText = false;\n\n for await (const part of result.fullStream) {\n // Check if cancelled\n if (this.abortController?.signal.aborted) {\n break;\n }\n\n switch (part.type) {\n case \"text-delta\":\n // Add step separator if needed (when previous step had text)\n if (lastStepHadText && part.text.trim().length > 0) {\n const separator = \"\\n\\n\";\n fullResponse += separator;\n this.sendText(separator);\n lastStepHadText = false;\n }\n fullResponse += part.text;\n this.sendText(part.text);\n break;\n\n case \"tool-call\":\n // Send tool call notification immediately when the model calls the tool\n // This happens BEFORE the tool executes\n // AI SDK v6 uses 'input' property for the parsed arguments\n this.sendToolCall(part.toolName, part.input ?? {});\n break;\n\n case \"tool-result\":\n // Send tool result when execution completes\n // AI SDK v6 uses 'output' property for the result\n this.sendToolResult(part.toolName, part.output);\n break;\n\n case \"text-end\":\n // A text block ended - if there was content, mark for separator\n if (fullResponse.trim().length > 0) {\n lastStepHadText = true;\n }\n break;\n }\n }\n\n // Wait for the full response to complete\n if (!this.abortController?.signal.aborted) {\n await result.response;\n }\n\n // Add assistant message to history\n if (fullResponse) {\n this.addToHistory(\"assistant\", fullResponse);\n }\n\n // Send done signal\n this.sendDone();\n } catch (error) {\n // Don't send error if we were cancelled\n if (!this.abortController?.signal.aborted) {\n const message = error instanceof Error ? error.message : String(error);\n this.sendError(`Query failed: ${message}`);\n }\n } finally {\n this.isExecuting = false;\n this.abortController = null;\n }\n }\n\n /**\n * Cancel the currently executing query\n */\n cancel(): void {\n if (this.abortController) {\n this.abortController.abort();\n this.sendDone();\n }\n }\n\n /**\n * Clear the conversation history\n */\n clearHistory(): void {\n this.conversationHistory = [];\n }\n\n /**\n * Clean up resources\n */\n async cleanup(): Promise<void> {\n // Cancel any in-progress execution\n if (this.abortController) {\n this.abortController.abort();\n }\n\n // Note: We don't clean up the mode here as it may be shared\n // The caller is responsible for cleaning up the mode\n this.agent = null;\n this.conversationHistory = [];\n }\n}\n\n// ============================================================================\n// Factory Function\n// ============================================================================\n\n/**\n * Create a new AgentSession\n */\nexport function createAgentSession(options: AgentSessionOptions): AgentSession {\n return new AgentSession(options);\n}\n\n// ============================================================================\n// Session Manager (for managing multiple sessions)\n// ============================================================================\n\n/**\n * Options for creating a SessionManager\n */\nexport interface SessionManagerOptions {\n /** The execution mode (sandbox or local) */\n mode: ExecutionMode;\n /** Phoenix client instance */\n client: PhoenixClient;\n /** Maximum number of agent steps before stopping (default: 25) */\n maxSteps?: number;\n}\n\n/**\n * Manages multiple agent sessions (one per WebSocket client)\n */\nexport class SessionManager {\n private sessions: Map<string, AgentSession> = new Map();\n private clientToSession: Map<WebSocket, string> = new Map();\n private mode: ExecutionMode;\n private client: PhoenixClient;\n private maxSteps: number;\n\n constructor(options: SessionManagerOptions) {\n this.mode = options.mode;\n this.client = options.client;\n this.maxSteps = options.maxSteps ?? 25;\n }\n\n /**\n * Get or create a session for a WebSocket client\n */\n getOrCreateSession(\n ws: WebSocket,\n sessionId: string,\n broadcast: BroadcastCallback\n ): AgentSession {\n // Check if we already have a session for this ID\n let session = this.sessions.get(sessionId);\n\n if (!session) {\n // Create a new session\n session = createAgentSession({\n sessionId,\n mode: this.mode,\n client: this.client,\n maxSteps: this.maxSteps,\n broadcast,\n });\n this.sessions.set(sessionId, session);\n }\n\n // Map the WebSocket to the session\n this.clientToSession.set(ws, sessionId);\n\n return session;\n }\n\n /**\n * Get the session for a WebSocket client\n */\n getSessionForClient(ws: WebSocket): AgentSession | undefined {\n const sessionId = this.clientToSession.get(ws);\n if (sessionId) {\n return this.sessions.get(sessionId);\n }\n return undefined;\n }\n\n /**\n * Get a session by ID\n */\n getSession(sessionId: string): AgentSession | undefined {\n return this.sessions.get(sessionId);\n }\n\n /**\n * Remove a session when a client disconnects\n */\n async removeSession(ws: WebSocket): Promise<void> {\n const sessionId = this.clientToSession.get(ws);\n if (sessionId) {\n const session = this.sessions.get(sessionId);\n if (session) {\n await session.cleanup();\n this.sessions.delete(sessionId);\n }\n this.clientToSession.delete(ws);\n }\n }\n\n /**\n * Get the number of active sessions\n */\n get sessionCount(): number {\n return this.sessions.size;\n }\n\n /**\n * Clean up all sessions\n */\n async cleanup(): Promise<void> {\n for (const session of this.sessions.values()) {\n await session.cleanup();\n }\n this.sessions.clear();\n this.clientToSession.clear();\n }\n}\n\n/**\n * Create a new SessionManager\n */\nexport function createSessionManager(\n options: SessionManagerOptions\n): SessionManager {\n return new SessionManager(options);\n}\n"],"mappings":"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","names":["fs","path","os","tool","z","z","z","z","z","z","z","name","z","z","tool","z","toJSONL","toJSONL","toJSONL","stat","z","fs","path","os","join","resolve","resolve","path","resolve"]}