@axlsdk/studio 0.13.7 → 0.13.8

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.
@@ -1271,6 +1271,13 @@ function createStudioMiddleware(options) {
1271
1271
  );
1272
1272
  return;
1273
1273
  }
1274
+ const reqAny = req;
1275
+ if (reqAny.body != null && !reqAny.rawBody) {
1276
+ try {
1277
+ reqAny.rawBody = Buffer.from(JSON.stringify(reqAny.body));
1278
+ } catch {
1279
+ }
1280
+ }
1274
1281
  listener(req, res).catch((err) => {
1275
1282
  console.error("[axl-studio] Unhandled error in request handler:", err);
1276
1283
  if (!res.headersSent) {
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/middleware.ts","../src/server/index.ts","../src/server/middleware/error-handler.ts","../src/server/ws/connection-manager.ts","../src/server/ws/protocol.ts","../src/server/ws/handler.ts","../src/server/cost-aggregator.ts","../src/server/routes/health.ts","../src/server/routes/workflows.ts","../src/server/routes/executions.ts","../src/server/routes/sessions.ts","../src/server/routes/agents.ts","../src/server/routes/tools.ts","../src/server/routes/memory.ts","../src/server/routes/decisions.ts","../src/server/routes/costs.ts","../src/server/routes/evals.ts","../src/server/routes/playground.ts","../src/eval-loader.ts","../src/cli-utils.ts"],"sourcesContent":["import { resolve, dirname } from 'node:path';\nimport { existsSync } from 'node:fs';\nimport { fileURLToPath } from 'node:url';\nimport { getRequestListener } from '@hono/node-server';\nimport { WebSocketServer } from 'ws';\nimport { createServer } from './server/index.js';\nimport { handleWsMessage } from './server/ws/protocol.js';\nimport { createEvalLoader } from './eval-loader.js';\nimport type { EvalLoaderConfig } from './eval-loader.js';\nimport type { AxlRuntime } from '@axlsdk/axl';\nimport type { IncomingMessage, ServerResponse, Server } from 'node:http';\n\nexport type { EvalLoaderConfig } from './eval-loader.js';\n\nexport type StudioMiddlewareOptions = {\n /** The AxlRuntime instance to observe and control. */\n runtime: AxlRuntime;\n\n /**\n * URL path prefix where Studio is mounted.\n * Must match the mount path in your framework (Express `app.use()`,\n * Fastify `register()`, Hono `app.route()`, etc.). The framework is\n * expected to strip the prefix from `req.url` before calling the handler.\n *\n * Do not set basePath when using a raw `http.Server` as the root handler —\n * leave it empty and mount at root instead.\n *\n * Must start with '/' when non-empty. Trailing slashes are stripped.\n * Only URL-safe characters allowed: [a-zA-Z0-9/_-]\n *\n * @example '/studio'\n * @example '/admin/studio'\n * @example '' — mounted at root (default)\n */\n basePath?: string;\n\n /**\n * Serve the pre-built Studio SPA.\n * Set to false if serving the client from a CDN or separate build.\n * @default true\n */\n serveClient?: boolean;\n\n /**\n * Verify a WebSocket upgrade request before completing the handshake.\n * Return true to allow, false to reject. Throw to reject with an error.\n *\n * IMPORTANT: WebSocket upgrades bypass Express/Fastify/Koa middleware.\n * If your HTTP routes are behind auth middleware, WS connections are NOT\n * automatically protected. Use this callback to enforce authentication\n * on WebSocket connections.\n */\n verifyUpgrade?: (req: IncomingMessage) => boolean | Promise<boolean>;\n\n /**\n * Disable all mutating endpoints (execute, test, send, delete, resolve).\n * When true, Studio is observation-only.\n * @default false\n */\n readOnly?: boolean;\n\n /**\n * Lazy-load eval files for the Eval Runner panel.\n *\n * Eval files are dynamically imported on first access to eval endpoints,\n * not at middleware construction time. This means:\n * - Zero cost during normal API operation\n * - Eval files can import from any module without creating circular deps\n * in the static module graph (they're loaded as standalone entry points)\n * - `@axlsdk/eval` can remain a devDependency — eval files never enter\n * the production bundle since bundlers can't see dynamic imports\n *\n * Accepts glob patterns, explicit file paths, or an object with\n * `conditions` for monorepo source export resolution.\n *\n * Eval files are loaded once and cached for the middleware's lifetime.\n * Changes to eval files require a server restart.\n *\n * @example\n * // Single glob pattern\n * evals: 'evals/*.eval.ts'\n *\n * @example\n * // Multiple patterns\n * evals: ['libs/api/evals/*.eval.ts', 'libs/ai/evals/*.eval.ts']\n *\n * @example\n * // With import conditions for monorepo source exports\n * evals: {\n * files: 'libs/api/evals/*.eval.ts',\n * conditions: ['development'],\n * }\n */\n evals?: EvalLoaderConfig;\n};\n\n/**\n * Minimal contract a WebSocket connection must satisfy.\n * Matches the `ws` library API (de facto standard in Node.js).\n */\nexport interface StudioWebSocket {\n send(data: string): void;\n close(): void;\n on(event: 'message', fn: (data: string | Buffer) => void): void;\n on(event: 'close', fn: () => void): void;\n on(event: 'error', fn: (err: Error) => void): void;\n}\n\n// Re-export for Hono-in-Hono consumers\nexport { handleWsMessage } from './server/ws/protocol.js';\n\nexport type StudioMiddleware = ReturnType<typeof createStudioMiddleware>;\n\nexport function createStudioMiddleware(options: StudioMiddlewareOptions) {\n const { runtime, serveClient = true, verifyUpgrade, readOnly = false } = options;\n\n // Normalize basePath: strip trailing slashes, validate format\n const basePath = normalizeBasePath(options.basePath);\n\n // Resolve pre-built SPA assets from this package's dist/\n const staticRoot = serveClient ? resolveClientDist() : undefined;\n\n if (serveClient && !staticRoot) {\n const dir =\n import.meta.dirname ??\n (typeof __dirname !== 'undefined' ? __dirname : dirname(fileURLToPath(import.meta.url)));\n console.warn(\n '[axl-studio] serveClient is true but no pre-built client found at ' +\n `${resolve(dir, 'client')}. Studio UI will not be available. ` +\n 'Set serveClient: false to suppress this warning.',\n );\n }\n\n // Create lazy eval loader if eval files are configured\n const evalLoader = options.evals ? createEvalLoader(options.evals, runtime) : undefined;\n\n const { app, connMgr, traceListener } = createServer({\n runtime,\n staticRoot,\n basePath,\n readOnly,\n cors: false, // Host framework owns CORS policy\n evalLoader,\n });\n\n // Log production safety warning\n if (process.env.NODE_ENV === 'production' && !verifyUpgrade) {\n console.warn(\n '[axl-studio] WARNING: Studio middleware mounted in production without verifyUpgrade. ' +\n 'WebSocket connections are not authenticated. All registered workflows, tools, and ' +\n 'agents are accessible. See https://axlsdk.com/docs/studio/security',\n );\n }\n\n // Convert Hono app → Node.js (req, res) handler.\n // overrideGlobalObjects: false prevents replacing global.Request and\n // global.Response, which could break the host application.\n const listener = getRequestListener(app.fetch, {\n overrideGlobalObjects: false,\n });\n\n let closed = false;\n\n function handler(req: IncomingMessage, res: ServerResponse) {\n if (closed) {\n res.writeHead(503, { 'Content-Type': 'application/json' });\n res.end(\n JSON.stringify({\n ok: false,\n error: { code: 'CLOSED', message: 'Studio middleware has been shut down' },\n }),\n );\n return;\n }\n // listener returns Promise<void>. Catch async errors to prevent\n // unhandled rejections from crashing the host process.\n listener(req, res).catch((err) => {\n console.error('[axl-studio] Unhandled error in request handler:', err);\n if (!res.headersSent) {\n res.writeHead(500, { 'Content-Type': 'application/json' });\n res.end(\n JSON.stringify({\n ok: false,\n error: { code: 'INTERNAL_ERROR', message: 'Internal server error' },\n }),\n );\n }\n });\n }\n\n // Handle an individual WebSocket using the Studio protocol.\n // Adapts any StudioWebSocket to ConnectionManager's internal BroadcastTarget.\n function handleWebSocket(ws: StudioWebSocket) {\n if (closed) {\n ws.close();\n return;\n }\n const socket = {\n send: (data: string) => ws.send(data),\n close: () => ws.close(),\n };\n connMgr.add(socket);\n\n ws.on('message', (raw) => {\n const reply = handleWsMessage(String(raw), socket, connMgr);\n if (reply) ws.send(reply);\n });\n\n ws.on('close', () => connMgr.remove(socket));\n ws.on('error', () => connMgr.remove(socket));\n }\n\n // Internal WebSocketServer — created lazily by upgradeWebSocket()\n let wss: InstanceType<typeof WebSocketServer> | undefined;\n // References for cleanup: the upgrade handler and server it's attached to\n let upgradeHandler: ((...args: any[]) => void) | undefined;\n let serverRef: Server | undefined;\n\n // Convenience: attach WS handling to an http.Server.\n function upgradeWebSocket(server: Server, path?: string) {\n if (wss) {\n throw new Error(\n '[axl-studio] upgradeWebSocket() has already been called. ' +\n 'Call close() first if you need to re-attach.',\n );\n }\n\n const wsPath = path ?? (basePath ? `${basePath}/ws` : '/ws');\n\n wss = new WebSocketServer({ noServer: true });\n serverRef = server;\n\n upgradeHandler = async (req: IncomingMessage, socket: any, head: Buffer) => {\n // Match path, ignoring query string\n const pathname = new URL(req.url!, `http://${req.headers.host}`).pathname;\n if (pathname !== wsPath) return; // Let other upgrade handlers run\n\n // Apply auth verification\n if (verifyUpgrade) {\n try {\n const allowed = await verifyUpgrade(req);\n if (!allowed) {\n socket.write('HTTP/1.1 401 Unauthorized\\r\\n\\r\\n');\n socket.destroy();\n return;\n }\n } catch {\n socket.write('HTTP/1.1 403 Forbidden\\r\\n\\r\\n');\n socket.destroy();\n return;\n }\n }\n\n // Guard against close() being called during async verifyUpgrade\n if (!wss) {\n socket.destroy();\n return;\n }\n\n wss.handleUpgrade(req, socket, head, (ws) => {\n handleWebSocket(ws);\n });\n };\n\n server.on('upgrade', upgradeHandler);\n }\n\n // Cleanup function for lifecycle management.\n function close() {\n closed = true;\n\n // Close all WebSocket connections\n connMgr.closeAll();\n\n // Remove the upgrade listener from the server before closing WSS\n if (upgradeHandler && serverRef) {\n serverRef.removeListener('upgrade', upgradeHandler);\n upgradeHandler = undefined;\n serverRef = undefined;\n }\n\n // Shut down the internal WebSocketServer if one was created\n if (wss) {\n wss.close();\n wss = undefined;\n }\n\n // Remove only our trace event listener from the runtime\n if (traceListener) {\n runtime.removeListener('trace', traceListener);\n }\n }\n\n return {\n handler,\n handleWebSocket,\n upgradeWebSocket,\n app,\n connectionManager: connMgr,\n close,\n };\n}\n\n/**\n * Normalize and validate basePath.\n * - Empty string and undefined → ''\n * - Strip trailing slashes\n * - Validate leading slash when non-empty\n * - Reject unsafe characters\n */\nfunction normalizeBasePath(raw?: string): string {\n if (!raw) return '';\n\n // Strip trailing slashes\n const normalized = raw.replace(/\\/+$/, '');\n if (!normalized) return '';\n\n // Must start with /\n if (!normalized.startsWith('/')) {\n throw new Error(`basePath must start with '/' (got '${raw}'). Example: '/studio'`);\n }\n\n // Reject path traversal, consecutive slashes, and unsafe characters\n if (normalized.includes('..')) {\n throw new Error(`basePath must not contain '..' segments (got '${raw}')`);\n }\n if (normalized.includes('//')) {\n throw new Error(`basePath must not contain consecutive slashes (got '${raw}')`);\n }\n if (!/^\\/[a-zA-Z0-9/_-]*$/.test(normalized)) {\n throw new Error(\n `basePath contains invalid characters (got '${raw}'). ` +\n 'Only alphanumeric characters, /, _, and - are allowed.',\n );\n }\n\n return normalized;\n}\n\nfunction resolveClientDist(): string | undefined {\n // Resolve the directory of this file (dist/ in published package).\n const dir =\n import.meta.dirname ??\n (typeof __dirname !== 'undefined' ? __dirname : dirname(fileURLToPath(import.meta.url)));\n const candidate = resolve(dir, 'client');\n return existsSync(resolve(candidate, 'index.html')) ? candidate : undefined;\n}\n","import { existsSync, readFileSync } from 'node:fs';\nimport { resolve } from 'node:path';\nimport { Hono } from 'hono';\nimport { cors } from 'hono/cors';\nimport { serveStatic } from '@hono/node-server/serve-static';\nimport type { AxlRuntime } from '@axlsdk/axl';\nimport type { StudioEnv } from './types.js';\nimport { errorHandler } from './middleware/error-handler.js';\nimport { ConnectionManager } from './ws/connection-manager.js';\nimport { createWsHandlers } from './ws/handler.js';\nimport { CostAggregator } from './cost-aggregator.js';\nimport healthRoutes from './routes/health.js';\nimport { createWorkflowRoutes } from './routes/workflows.js';\nimport executionRoutes from './routes/executions.js';\nimport { createSessionRoutes } from './routes/sessions.js';\nimport agentRoutes from './routes/agents.js';\nimport toolRoutes from './routes/tools.js';\nimport memoryRoutes from './routes/memory.js';\nimport decisionRoutes from './routes/decisions.js';\nimport { createCostRoutes } from './routes/costs.js';\nimport { createEvalRoutes } from './routes/evals.js';\nimport { createPlaygroundRoutes } from './routes/playground.js';\n\nexport type { StudioEnv } from './types.js';\nexport { ConnectionManager } from './ws/connection-manager.js';\nexport type { BroadcastTarget } from './ws/connection-manager.js';\nexport { CostAggregator } from './cost-aggregator.js';\n\nexport type CreateServerOptions = {\n runtime: AxlRuntime;\n /** Root path for serving pre-built SPA static assets. */\n staticRoot?: string;\n /** Base URL path for client-side routing and API calls. Injected into index.html at serve time. */\n basePath?: string;\n /** When true, disable all mutating API endpoints. */\n readOnly?: boolean;\n /** Apply CORS headers. Default: true (standalone CLI). Set false for embedded middleware. */\n cors?: boolean;\n /** Lazy eval file loader. Called before eval routes access the runtime's registered evals. */\n evalLoader?: () => Promise<void>;\n};\n\nexport function createServer(options: CreateServerOptions) {\n const { runtime, staticRoot, basePath = '', readOnly = false } = options;\n const app = new Hono<StudioEnv>();\n const connMgr = new ConnectionManager();\n const costAggregator = new CostAggregator(connMgr);\n\n // ── Middleware ──────────────────────────────────────────────────────\n if (options.cors !== false) {\n app.use('*', cors());\n }\n app.use('*', errorHandler);\n app.use('*', async (c, next) => {\n c.set('runtime', runtime);\n await next();\n });\n\n // ── Read-only mode ──────────────────────────────────────────────────\n if (readOnly) {\n const blocked = [\n 'POST /api/workflows',\n 'POST /api/executions',\n 'POST /api/sessions',\n 'DELETE /api/sessions',\n 'PUT /api/memory',\n 'DELETE /api/memory',\n 'POST /api/decisions',\n 'POST /api/costs',\n 'POST /api/tools',\n 'POST /api/evals',\n 'POST /api/playground',\n ];\n app.use('/api/*', async (c, next) => {\n // c.req.path returns the full path including any parent route prefix\n // (e.g., /studio/api/workflows when mounted via app.route('/studio', ...)).\n // Extract just the /api/... portion for matching.\n const apiIdx = c.req.path.indexOf('/api/');\n const apiPath = apiIdx >= 0 ? c.req.path.slice(apiIdx) : c.req.path;\n const key = `${c.req.method} ${apiPath}`;\n if (blocked.some((b) => key.startsWith(b))) {\n return c.json(\n {\n ok: false,\n error: { code: 'READ_ONLY', message: 'Studio is mounted in read-only mode' },\n },\n 405,\n );\n }\n await next();\n });\n }\n\n // ── API Routes ─────────────────────────────────────────────────────\n const api = new Hono<StudioEnv>();\n api.route('/', healthRoutes);\n api.route('/', createWorkflowRoutes(connMgr));\n api.route('/', executionRoutes);\n api.route('/', createSessionRoutes(connMgr));\n api.route('/', agentRoutes);\n api.route('/', toolRoutes);\n api.route('/', memoryRoutes);\n api.route('/', decisionRoutes);\n api.route('/', createCostRoutes(costAggregator));\n api.route('/', createEvalRoutes(options.evalLoader));\n api.route('/', createPlaygroundRoutes(connMgr));\n\n app.route('/api', api);\n\n // ── Trace event bridging ───────────────────────────────────────────\n const traceListener = (event: unknown) => {\n const traceEvent = event as {\n executionId?: string;\n type?: string;\n agent?: string;\n model?: string;\n workflow?: string;\n cost?: number;\n tokens?: { input?: number; output?: number; reasoning?: number };\n };\n\n // Broadcast to trace channels\n if (traceEvent.executionId) {\n connMgr.broadcastWithWildcard(`trace:${traceEvent.executionId}`, traceEvent);\n }\n\n // Feed cost aggregator\n costAggregator.onTrace(traceEvent);\n\n // Broadcast pending decisions\n if (traceEvent.type === 'await_human') {\n connMgr.broadcast('decisions', traceEvent);\n }\n };\n runtime.on('trace', traceListener);\n\n // ── Static SPA serving (production) ────────────────────────────────\n if (staticRoot) {\n // Read index.html once at startup. When basePath is set, inject the <base>\n // tag and runtime config so asset paths and client-side routing work\n // regardless of whether the mount URL has a trailing slash.\n const indexPath = resolve(staticRoot, 'index.html');\n let spaHtml: string | undefined;\n\n if (!existsSync(indexPath)) {\n console.warn(`[axl-studio] index.html not found at ${indexPath}`);\n } else {\n const rawHtml = readFileSync(indexPath, 'utf-8');\n\n if (basePath) {\n // Escape '<' to prevent </script> in basePath from breaking out of\n // the script tag. JSON.stringify alone is insufficient because the\n // HTML parser processes </script> before JavaScript runs.\n const safeBasePath = JSON.stringify(basePath).replace(/</g, '\\\\u003c');\n const injected = rawHtml.replace(\n '<head>',\n `<head>\\n<base href=\"${basePath}/\">\\n` +\n `<script>window.__AXL_STUDIO_BASE__=${safeBasePath}</script>`,\n );\n\n if (injected === rawHtml) {\n console.warn(\n '[axl-studio] Could not inject basePath into index.html — ' +\n '<head> tag not found. The SPA may not route correctly.',\n );\n }\n spaHtml = injected;\n } else {\n spaHtml = rawHtml;\n }\n }\n\n // Serve static assets (JS, CSS, images). index.html is excluded so the\n // SPA fallback below always serves the version with basePath injection.\n // Without this guard, serveStatic would serve the raw index.html for root\n // requests (/ or /index.html), missing <base> and __AXL_STUDIO_BASE__.\n const staticHandler = serveStatic({\n root: staticRoot,\n rewriteRequestPath: basePath\n ? (path) => (path.startsWith(basePath) ? path.slice(basePath.length) || '/' : path)\n : undefined,\n });\n\n app.use('/*', async (c, next) => {\n const reqPath = c.req.path;\n const resolved =\n basePath && reqPath.startsWith(basePath) ? reqPath.slice(basePath.length) || '/' : reqPath;\n // Skip index.html (handled by SPA fallback) and /ws (handled by WebSocket upgrader)\n if (resolved === '/' || resolved === '/index.html' || resolved === '/ws') {\n return next();\n }\n return staticHandler(c, next);\n });\n\n // SPA fallback: serve the (possibly injected) index.html for all\n // non-API, non-static-asset routes so React Router handles routing.\n // Skip /ws so the WebSocket upgrader (registered after createServer) can handle it.\n if (spaHtml) {\n app.get('*', async (c, next) => {\n const resolved =\n basePath && c.req.path.startsWith(basePath)\n ? c.req.path.slice(basePath.length) || '/'\n : c.req.path;\n if (resolved === '/ws') return next();\n return c.html(spaHtml!);\n });\n }\n }\n\n return {\n app,\n connMgr,\n costAggregator,\n /** Create WS handlers. Call before registering static/SPA routes are reached. */\n createWsHandlers: () => createWsHandlers(connMgr),\n traceListener,\n };\n}\n","import type { Context, Next } from 'hono';\nimport type { StudioEnv, ApiError } from '../types.js';\n\nexport async function errorHandler(c: Context<StudioEnv>, next: Next) {\n try {\n await next();\n } catch (err) {\n const message = err instanceof Error ? err.message : String(err);\n const code = (err as { code?: string }).code ?? 'INTERNAL_ERROR';\n\n // Determine HTTP status from error properties\n let status = 500;\n if ('status' in (err as object)) {\n const errStatus = (err as { status: unknown }).status;\n if (typeof errStatus === 'number' && errStatus >= 400 && errStatus < 600) {\n status = errStatus;\n }\n } else if (\n code === 'NOT_FOUND' ||\n message.includes('not found') ||\n message.includes('not registered')\n ) {\n status = 404;\n } else if (\n code === 'VALIDATION_ERROR' ||\n message.includes('Expected') ||\n message.includes('invalid')\n ) {\n status = 400;\n }\n\n const body: ApiError = {\n ok: false,\n error: { code, message },\n };\n\n return c.json(body, status as 400 | 404 | 500);\n }\n}\n","/**\n * Minimal interface for a connection that can receive broadcast messages.\n * Satisfied by WSContext (Hono), ws.WebSocket (Node.js), and the middleware's\n * adapted socket. Internal to ConnectionManager — not part of the public API.\n */\nexport interface BroadcastTarget {\n send(data: string): void;\n close?(): void;\n}\n\n/**\n * Short-lived event buffer for execution streams.\n * Solves the race where a fast provider (e.g., MockProvider) completes\n * before the client's WS subscription is established. Events are buffered\n * per-channel and replayed to late subscribers.\n */\ninterface ChannelBuffer {\n events: string[]; // Pre-serialized JSON messages\n complete: boolean; // True after done/error event\n timer?: ReturnType<typeof setTimeout>;\n}\n\n/** Channels eligible for replay buffering (execution streams). */\nfunction isBufferedChannel(channel: string): boolean {\n return channel.startsWith('execution:');\n}\n\nconst BUFFER_TTL_MS = 30_000; // Clean up buffers 30s after stream completes\nconst MAX_BUFFER_EVENTS = 500; // Cap replay buffer size\n\n/**\n * Manages WebSocket connections and channel subscriptions.\n * Supports channel multiplexing: clients subscribe/unsubscribe to channels\n * and receive events only for channels they're subscribed to.\n *\n * Execution channels (`execution:*`) are replay-buffered: events are stored\n * so that late subscribers receive the full event history. Buffers are cleaned\n * up shortly after the stream completes.\n */\nexport class ConnectionManager {\n /** channel -> set of WS connections */\n private channels = new Map<string, Set<BroadcastTarget>>();\n /** ws -> set of subscribed channels (for cleanup) */\n private connections = new Map<BroadcastTarget, Set<string>>();\n /** channel -> replay buffer for execution streams */\n private buffers = new Map<string, ChannelBuffer>();\n private maxConnections = 100;\n\n /** Register a new WS connection. */\n add(ws: BroadcastTarget): void {\n if (this.connections.size >= this.maxConnections) {\n ws.close?.();\n return;\n }\n this.connections.set(ws, new Set());\n }\n\n /** Remove a WS connection and all its subscriptions. */\n remove(ws: BroadcastTarget): void {\n const channels = this.connections.get(ws);\n if (channels) {\n for (const ch of channels) {\n this.channels.get(ch)?.delete(ws);\n if (this.channels.get(ch)?.size === 0) {\n this.channels.delete(ch);\n }\n }\n }\n this.connections.delete(ws);\n }\n\n /** Subscribe a connection to a channel. Replays buffered events for execution channels. */\n subscribe(ws: BroadcastTarget, channel: string): void {\n if (!this.connections.has(ws)) return;\n let subs = this.channels.get(channel);\n if (!subs) {\n subs = new Set();\n this.channels.set(channel, subs);\n }\n subs.add(ws);\n this.connections.get(ws)!.add(channel);\n\n // Replay buffered events for late subscribers\n const buffer = this.buffers.get(channel);\n if (buffer) {\n for (const msg of buffer.events) {\n try {\n ws.send(msg);\n } catch {\n this.remove(ws);\n return;\n }\n }\n }\n }\n\n /** Unsubscribe a connection from a channel. */\n unsubscribe(ws: BroadcastTarget, channel: string): void {\n this.channels.get(channel)?.delete(ws);\n if (this.channels.get(channel)?.size === 0) {\n this.channels.delete(channel);\n }\n this.connections.get(ws)?.delete(channel);\n }\n\n /** Broadcast data to all subscribers of a channel. Buffers events for execution channels. */\n broadcast(channel: string, data: unknown): void {\n const msg = JSON.stringify({ type: 'event', channel, data });\n\n // Buffer events for execution channels so late subscribers can replay\n if (isBufferedChannel(channel)) {\n let buffer = this.buffers.get(channel);\n if (!buffer) {\n buffer = { events: [], complete: false };\n this.buffers.set(channel, buffer);\n }\n // Always buffer terminal events; skip non-terminal if at capacity\n const event = data as { type?: string };\n const isTerminal = event.type === 'done' || event.type === 'error';\n if (buffer.events.length < MAX_BUFFER_EVENTS || isTerminal) {\n buffer.events.push(msg);\n }\n\n // Schedule buffer cleanup after terminal events\n if (isTerminal) {\n buffer.complete = true;\n if (buffer.timer) clearTimeout(buffer.timer);\n buffer.timer = setTimeout(() => {\n this.buffers.delete(channel);\n }, BUFFER_TTL_MS);\n }\n }\n\n // Send to current subscribers\n const subs = this.channels.get(channel);\n if (!subs || subs.size === 0) return;\n\n for (const ws of [...subs]) {\n try {\n ws.send(msg);\n } catch {\n this.remove(ws);\n }\n }\n }\n\n /** Broadcast to channel and all wildcard subscribers (e.g., trace:* matches trace:abc). */\n broadcastWithWildcard(channel: string, data: unknown): void {\n this.broadcast(channel, data);\n\n // Check for wildcard subscribers: \"prefix:*\" matches \"prefix:anything\"\n // Send with the actual channel name so wildcard subscribers know the source.\n const colonIdx = channel.indexOf(':');\n if (colonIdx > 0) {\n const wildcardChannel = channel.substring(0, colonIdx) + ':*';\n const subs = this.channels.get(wildcardChannel);\n if (!subs || subs.size === 0) return;\n\n const msg = JSON.stringify({ type: 'event', channel, data });\n for (const ws of [...subs]) {\n try {\n ws.send(msg);\n } catch {\n this.remove(ws);\n }\n }\n }\n }\n\n /** Close all connections, clear all state and buffers. Used during shutdown. */\n closeAll(): void {\n for (const ws of this.connections.keys()) {\n ws.close?.();\n }\n for (const buffer of this.buffers.values()) {\n if (buffer.timer) clearTimeout(buffer.timer);\n }\n this.connections.clear();\n this.channels.clear();\n this.buffers.clear();\n }\n\n /** Get the number of active connections. */\n get connectionCount(): number {\n return this.connections.size;\n }\n\n /** Check if any connections are subscribed to a channel. */\n hasSubscribers(channel: string): boolean {\n return (this.channels.get(channel)?.size ?? 0) > 0;\n }\n}\n","import type { BroadcastTarget } from './connection-manager.js';\nimport type { ConnectionManager } from './connection-manager.js';\n\n/** Channel prefixes that accept suffixes (e.g., execution:abc, trace:*). */\nconst VALID_CHANNEL_PREFIXES = ['execution:', 'trace:'];\n/** Channels that must match exactly (no suffix allowed). */\nconst VALID_EXACT_CHANNELS = ['costs', 'decisions'];\nconst MAX_CHANNEL_LENGTH = 256;\n\n/**\n * Handle a single WebSocket message according to the Studio protocol.\n * Returns a JSON string to send back to the client, or null for no response.\n *\n * Used by both the Hono WS handler (ws/handler.ts) and the Node.js\n * middleware (middleware.ts) to keep the protocol in one place.\n */\nexport function handleWsMessage(\n raw: string,\n socket: BroadcastTarget,\n connMgr: ConnectionManager,\n): string | null {\n // Reject oversized messages (64KB limit)\n if (raw.length > 65536) {\n return JSON.stringify({ type: 'error', message: 'Message too large' });\n }\n\n let msg: { type: string; channel?: string };\n try {\n msg = JSON.parse(raw);\n } catch {\n return JSON.stringify({ type: 'error', message: 'Invalid JSON' });\n }\n\n switch (msg.type) {\n case 'subscribe': {\n const error = validateChannel(msg.channel);\n if (error) return JSON.stringify({ type: 'error', message: error });\n connMgr.subscribe(socket, msg.channel!);\n return JSON.stringify({ type: 'subscribed', channel: msg.channel });\n }\n case 'unsubscribe': {\n const error = validateChannel(msg.channel);\n if (error) return JSON.stringify({ type: 'error', message: error });\n connMgr.unsubscribe(socket, msg.channel!);\n return JSON.stringify({ type: 'unsubscribed', channel: msg.channel });\n }\n case 'ping':\n return JSON.stringify({ type: 'pong' });\n default:\n return JSON.stringify({ type: 'error', message: 'Unknown message type' });\n }\n}\n\nfunction validateChannel(channel: unknown): string | null {\n if (typeof channel !== 'string' || !channel) {\n return 'Missing or invalid channel';\n }\n if (channel.length > MAX_CHANNEL_LENGTH) {\n return `Channel name exceeds ${MAX_CHANNEL_LENGTH} characters`;\n }\n if (\n !VALID_EXACT_CHANNELS.includes(channel as (typeof VALID_EXACT_CHANNELS)[number]) &&\n !VALID_CHANNEL_PREFIXES.some((p) => channel.startsWith(p))\n ) {\n return `Invalid channel: ${channel}`;\n }\n return null;\n}\n","import type { WSContext } from 'hono/ws';\nimport type { ConnectionManager } from './connection-manager.js';\nimport { handleWsMessage } from './protocol.js';\n\n/** Create WS event handlers for a Hono WebSocket connection. */\nexport function createWsHandlers(connMgr: ConnectionManager) {\n return {\n onOpen(_event: Event, ws: WSContext) {\n connMgr.add(ws);\n },\n\n onMessage(event: MessageEvent, ws: WSContext) {\n const reply = handleWsMessage(String(event.data), ws, connMgr);\n if (reply) ws.send(reply);\n },\n\n onClose(_event: CloseEvent, ws: WSContext) {\n connMgr.remove(ws);\n },\n\n onError(_event: Event, ws: WSContext) {\n connMgr.remove(ws);\n },\n };\n}\n","import type { CostData } from './types.js';\nimport type { ConnectionManager } from './ws/connection-manager.js';\n\n/**\n * Accumulates cost data from trace events.\n * Broadcasts updates to the 'costs' WS channel.\n */\nexport class CostAggregator {\n private data: CostData = {\n totalCost: 0,\n totalTokens: { input: 0, output: 0, reasoning: 0 },\n byAgent: {},\n byModel: {},\n byWorkflow: {},\n };\n\n constructor(private connMgr: ConnectionManager) {}\n\n /** Process a trace event and update cost data. */\n onTrace(event: {\n type?: string;\n agent?: string;\n model?: string;\n workflow?: string;\n cost?: number;\n tokens?: { input?: number; output?: number; reasoning?: number };\n }): void {\n if (event.cost == null && !event.tokens) return;\n\n const cost = Number.isFinite(event.cost) ? event.cost! : 0;\n const tokens = event.tokens ?? {};\n\n this.data.totalCost += cost;\n this.data.totalTokens.input += tokens.input ?? 0;\n this.data.totalTokens.output += tokens.output ?? 0;\n this.data.totalTokens.reasoning += tokens.reasoning ?? 0;\n\n if (event.agent) {\n const entry = this.data.byAgent[event.agent] ?? { cost: 0, calls: 0 };\n entry.cost += cost;\n entry.calls += 1;\n this.data.byAgent[event.agent] = entry;\n }\n\n if (event.model) {\n const entry = this.data.byModel[event.model] ?? {\n cost: 0,\n calls: 0,\n tokens: { input: 0, output: 0 },\n };\n entry.cost += cost;\n entry.calls += 1;\n entry.tokens.input += tokens.input ?? 0;\n entry.tokens.output += tokens.output ?? 0;\n this.data.byModel[event.model] = entry;\n }\n\n if (event.workflow) {\n const entry = this.data.byWorkflow[event.workflow] ?? { cost: 0, executions: 0 };\n entry.cost += cost;\n if (event.type === 'workflow_start') entry.executions += 1;\n this.data.byWorkflow[event.workflow] = entry;\n }\n\n // Broadcast to WS subscribers\n this.connMgr.broadcast('costs', this.data);\n }\n\n /** Get current aggregated cost data. */\n getData(): CostData {\n return this.data;\n }\n\n /** Reset all accumulated data. */\n reset(): void {\n this.data = {\n totalCost: 0,\n totalTokens: { input: 0, output: 0, reasoning: 0 },\n byAgent: {},\n byModel: {},\n byWorkflow: {},\n };\n }\n}\n","import { Hono } from 'hono';\nimport type { StudioEnv } from '../types.js';\n\nconst app = new Hono<StudioEnv>();\n\napp.get('/health', (c) => {\n const runtime = c.get('runtime');\n return c.json({\n ok: true,\n data: {\n status: 'healthy',\n workflows: runtime.getWorkflowNames().length,\n agents: runtime.getAgents().length,\n tools: runtime.getTools().length,\n },\n });\n});\n\nexport default app;\n","import { Hono } from 'hono';\nimport { zodToJsonSchema } from '@axlsdk/axl';\nimport type { StudioEnv, WorkflowSummary } from '../types.js';\nimport type { ConnectionManager } from '../ws/connection-manager.js';\n\nexport function createWorkflowRoutes(connMgr: ConnectionManager) {\n const app = new Hono<StudioEnv>();\n\n // List all workflows\n app.get('/workflows', (c) => {\n const runtime = c.get('runtime');\n const workflows: WorkflowSummary[] = runtime.getWorkflows().map((w) => ({\n name: w.name,\n hasInputSchema: !!w.inputSchema,\n hasOutputSchema: !!w.outputSchema,\n }));\n return c.json({ ok: true, data: workflows });\n });\n\n // Get workflow detail (including schemas)\n app.get('/workflows/:name', (c) => {\n const runtime = c.get('runtime');\n const name = c.req.param('name');\n const workflow = runtime.getWorkflow(name);\n if (!workflow) {\n return c.json(\n { ok: false, error: { code: 'NOT_FOUND', message: `Workflow \"${name}\" not found` } },\n 404,\n );\n }\n\n return c.json({\n ok: true,\n data: {\n name: workflow.name,\n inputSchema: workflow.inputSchema ? zodToJsonSchema(workflow.inputSchema) : null,\n outputSchema: workflow.outputSchema ? zodToJsonSchema(workflow.outputSchema) : null,\n },\n });\n });\n\n // Execute a workflow\n app.post('/workflows/:name/execute', async (c) => {\n const runtime = c.get('runtime');\n const name = c.req.param('name');\n\n const workflow = runtime.getWorkflow(name);\n if (!workflow) {\n return c.json(\n { ok: false, error: { code: 'NOT_FOUND', message: `Workflow \"${name}\" not found` } },\n 404,\n );\n }\n\n const body = await c.req.json<{\n input?: unknown;\n stream?: boolean;\n metadata?: Record<string, unknown>;\n }>();\n\n if (body.stream) {\n // Streaming execution — pipe events to WS channel\n const stream = runtime.stream(name, body.input ?? {}, { metadata: body.metadata });\n const executionId = `stream-${Date.now()}`;\n\n // Forward stream events to WS (error events flow through the iterator)\n (async () => {\n for await (const event of stream) {\n connMgr.broadcastWithWildcard(`execution:${executionId}`, event);\n }\n })();\n\n return c.json({ ok: true, data: { executionId, streaming: true } });\n }\n\n const result = await runtime.execute(name, body.input ?? {}, { metadata: body.metadata });\n return c.json({ ok: true, data: { result } });\n });\n\n return app;\n}\n","import { Hono } from 'hono';\nimport type { StudioEnv } from '../types.js';\n\nconst app = new Hono<StudioEnv>();\n\n// List all executions\napp.get('/executions', async (c) => {\n const runtime = c.get('runtime');\n const executions = await runtime.getExecutions();\n return c.json({ ok: true, data: executions });\n});\n\n// Get execution by ID\napp.get('/executions/:id', async (c) => {\n const runtime = c.get('runtime');\n const id = c.req.param('id');\n const execution = await runtime.getExecution(id);\n if (!execution) {\n return c.json(\n { ok: false, error: { code: 'NOT_FOUND', message: `Execution \"${id}\" not found` } },\n 404,\n );\n }\n return c.json({ ok: true, data: execution });\n});\n\n// Abort a running execution\napp.post('/executions/:id/abort', (c) => {\n const runtime = c.get('runtime');\n const id = c.req.param('id');\n runtime.abort(id);\n return c.json({ ok: true, data: { aborted: true } });\n});\n\nexport default app;\n","import { Hono } from 'hono';\nimport type { StudioEnv, SessionSummary } from '../types.js';\nimport type { ConnectionManager } from '../ws/connection-manager.js';\n\nexport function createSessionRoutes(connMgr: ConnectionManager) {\n const app = new Hono<StudioEnv>();\n\n // List all sessions\n app.get('/sessions', async (c) => {\n const runtime = c.get('runtime');\n const store = runtime.getStateStore();\n if (!store.listSessions) {\n return c.json({ ok: true, data: [] });\n }\n const ids = await store.listSessions();\n const sessions: SessionSummary[] = [];\n for (const id of ids) {\n const history = await store.getSession(id);\n sessions.push({ id, messageCount: history.length });\n }\n return c.json({ ok: true, data: sessions });\n });\n\n // Get session history\n app.get('/sessions/:id', async (c) => {\n const runtime = c.get('runtime');\n const store = runtime.getStateStore();\n const id = c.req.param('id');\n const history = await store.getSession(id);\n const handoffHistory = await store.getSessionMeta(id, 'handoffHistory');\n return c.json({ ok: true, data: { id, history, handoffHistory: handoffHistory ?? [] } });\n });\n\n // Send message to session (non-streaming)\n app.post('/sessions/:id/send', async (c) => {\n const runtime = c.get('runtime');\n const id = c.req.param('id');\n const body = await c.req.json<{ message: string; workflow: string }>();\n\n const session = runtime.session(id);\n const result = await session.send(body.workflow, body.message);\n return c.json({ ok: true, data: { result } });\n });\n\n // Stream session message\n app.post('/sessions/:id/stream', async (c) => {\n const runtime = c.get('runtime');\n const id = c.req.param('id');\n const body = await c.req.json<{ message: string; workflow: string }>();\n\n const session = runtime.session(id);\n const stream = await session.stream(body.workflow, body.message);\n const executionId = `session-${id}-${Date.now()}`;\n\n // Forward stream events to WS (error events flow through the iterator)\n (async () => {\n for await (const event of stream) {\n connMgr.broadcastWithWildcard(`execution:${executionId}`, event);\n }\n })();\n\n return c.json({ ok: true, data: { executionId, streaming: true } });\n });\n\n // Delete session\n app.delete('/sessions/:id', async (c) => {\n const runtime = c.get('runtime');\n const store = runtime.getStateStore();\n const id = c.req.param('id');\n await store.deleteSession(id);\n return c.json({ ok: true, data: { deleted: true } });\n });\n\n return app;\n}\n","import { Hono } from 'hono';\nimport { zodToJsonSchema } from '@axlsdk/axl';\nimport type { StudioEnv, AgentSummary } from '../types.js';\n\nconst app = new Hono<StudioEnv>();\n\n// List all agents\napp.get('/agents', (c) => {\n const runtime = c.get('runtime');\n const agents: AgentSummary[] = runtime.getAgents().map((a) => ({\n name: a._name,\n model: a.resolveModel(),\n system: a.resolveSystem(),\n tools: a._config.tools?.map((t) => t.name) ?? [],\n handoffs:\n typeof a._config.handoffs === 'function'\n ? ['(dynamic)']\n : (a._config.handoffs?.map((h) => h.agent._name) ?? []),\n maxTurns: a._config.maxTurns,\n temperature: a._config.temperature,\n maxTokens: a._config.maxTokens,\n effort: a._config.effort,\n thinkingBudget: a._config.thinkingBudget,\n includeThoughts: a._config.includeThoughts,\n toolChoice: a._config.toolChoice,\n stop: a._config.stop,\n }));\n return c.json({ ok: true, data: agents });\n});\n\n// Get agent detail\napp.get('/agents/:name', (c) => {\n const runtime = c.get('runtime');\n const name = c.req.param('name');\n const agent = runtime.getAgent(name);\n if (!agent) {\n return c.json(\n { ok: false, error: { code: 'NOT_FOUND', message: `Agent \"${name}\" not found` } },\n 404,\n );\n }\n\n const cfg = agent._config;\n return c.json({\n ok: true,\n data: {\n name: agent._name,\n model: agent.resolveModel(),\n system: agent.resolveSystem(),\n tools:\n cfg.tools?.map((t) => ({\n name: t.name,\n description: t.description,\n inputSchema: zodToJsonSchema(t.inputSchema),\n })) ?? [],\n handoffs:\n typeof cfg.handoffs === 'function'\n ? [\n {\n agent: '(dynamic)',\n description: 'Resolved at runtime from metadata',\n mode: 'oneway' as const,\n },\n ]\n : (cfg.handoffs?.map((h) => ({\n agent: h.agent._name,\n description: h.description,\n mode: h.mode ?? 'oneway',\n })) ?? []),\n maxTurns: cfg.maxTurns,\n temperature: cfg.temperature,\n maxTokens: cfg.maxTokens,\n effort: cfg.effort,\n thinkingBudget: cfg.thinkingBudget,\n includeThoughts: cfg.includeThoughts,\n toolChoice: cfg.toolChoice,\n stop: cfg.stop,\n timeout: cfg.timeout,\n maxContext: cfg.maxContext,\n version: cfg.version,\n mcp: cfg.mcp,\n mcpTools: cfg.mcpTools,\n hasGuardrails: !!cfg.guardrails,\n guardrails: cfg.guardrails\n ? {\n hasInput: !!cfg.guardrails.input,\n hasOutput: !!cfg.guardrails.output,\n onBlock: cfg.guardrails.onBlock ?? 'throw',\n maxRetries: cfg.guardrails.maxRetries,\n }\n : null,\n },\n });\n});\n\nexport default app;\n","import { Hono } from 'hono';\nimport { zodToJsonSchema } from '@axlsdk/axl';\nimport type { StudioEnv, ToolSummary } from '../types.js';\n\nconst app = new Hono<StudioEnv>();\n\n// List all tools\napp.get('/tools', (c) => {\n const runtime = c.get('runtime');\n const tools: ToolSummary[] = runtime.getTools().map((t) => ({\n name: t.name,\n description: t.description,\n inputSchema: t.inputSchema ? zodToJsonSchema(t.inputSchema) : {},\n sensitive: t.sensitive ?? false,\n requireApproval: t.requireApproval ?? false,\n }));\n return c.json({ ok: true, data: tools });\n});\n\n// Get tool detail\napp.get('/tools/:name', (c) => {\n const runtime = c.get('runtime');\n const name = c.req.param('name');\n const tool = runtime.getTool(name);\n if (!tool) {\n return c.json(\n { ok: false, error: { code: 'NOT_FOUND', message: `Tool \"${name}\" not found` } },\n 404,\n );\n }\n\n return c.json({\n ok: true,\n data: {\n name: tool.name,\n description: tool.description,\n inputSchema: tool.inputSchema ? zodToJsonSchema(tool.inputSchema) : {},\n sensitive: tool.sensitive,\n requireApproval: tool.requireApproval,\n retry: tool.retry,\n hasHooks: !!tool.hooks,\n hooks: tool.hooks\n ? {\n hasBefore: !!tool.hooks.before,\n hasAfter: !!tool.hooks.after,\n }\n : null,\n },\n });\n});\n\n// Test a tool directly\napp.post('/tools/:name/test', async (c) => {\n const runtime = c.get('runtime');\n const name = c.req.param('name');\n const tool = runtime.getTool(name);\n if (!tool) {\n return c.json(\n { ok: false, error: { code: 'NOT_FOUND', message: `Tool \"${name}\" not found` } },\n 404,\n );\n }\n\n const body = await c.req.json<{ input: unknown }>();\n const ctx = runtime.createContext();\n const result = await tool.run(ctx, body.input);\n return c.json({ ok: true, data: { result } });\n});\n\nexport default app;\n","import { Hono } from 'hono';\nimport type { StudioEnv } from '../types.js';\n\nconst app = new Hono<StudioEnv>();\n\n// Get all memory entries for a scope\napp.get('/memory/:scope', async (c) => {\n const runtime = c.get('runtime');\n const store = runtime.getStateStore();\n const scope = c.req.param('scope');\n\n if (!store.getAllMemory) {\n return c.json({ ok: true, data: [] });\n }\n\n const entries = await store.getAllMemory(scope);\n return c.json({ ok: true, data: entries });\n});\n\n// Get a specific memory entry\napp.get('/memory/:scope/:key', async (c) => {\n const runtime = c.get('runtime');\n const store = runtime.getStateStore();\n const scope = c.req.param('scope');\n const key = c.req.param('key');\n\n if (!store.getMemory) {\n return c.json(\n { ok: false, error: { code: 'NOT_SUPPORTED', message: 'Memory not supported' } },\n 501,\n );\n }\n\n const value = await store.getMemory(scope, key);\n if (value === null) {\n return c.json(\n { ok: false, error: { code: 'NOT_FOUND', message: `Memory \"${scope}/${key}\" not found` } },\n 404,\n );\n }\n\n return c.json({ ok: true, data: { key, value } });\n});\n\n// Save a memory entry\napp.put('/memory/:scope/:key', async (c) => {\n const runtime = c.get('runtime');\n const store = runtime.getStateStore();\n const scope = c.req.param('scope');\n const key = c.req.param('key');\n\n if (!store.saveMemory) {\n return c.json(\n { ok: false, error: { code: 'NOT_SUPPORTED', message: 'Memory not supported' } },\n 501,\n );\n }\n\n const body = await c.req.json<{ value: unknown }>();\n await store.saveMemory(scope, key, body.value);\n return c.json({ ok: true, data: { saved: true } });\n});\n\n// Delete a memory entry\napp.delete('/memory/:scope/:key', async (c) => {\n const runtime = c.get('runtime');\n const store = runtime.getStateStore();\n const scope = c.req.param('scope');\n const key = c.req.param('key');\n\n if (!store.deleteMemory) {\n return c.json(\n { ok: false, error: { code: 'NOT_SUPPORTED', message: 'Memory not supported' } },\n 501,\n );\n }\n\n await store.deleteMemory(scope, key);\n return c.json({ ok: true, data: { deleted: true } });\n});\n\n// Semantic search\napp.post('/memory/search', async (c) => {\n // TODO: Connect to MemoryManager's vector search once exposed\n return c.json({\n ok: true,\n data: { results: [], message: 'Semantic search requires MemoryManager with vector store' },\n });\n});\n\nexport default app;\n","import { Hono } from 'hono';\nimport type { StudioEnv } from '../types.js';\n\nconst app = new Hono<StudioEnv>();\n\n// List pending decisions\napp.get('/decisions', async (c) => {\n const runtime = c.get('runtime');\n const decisions = await runtime.getPendingDecisions();\n return c.json({ ok: true, data: decisions });\n});\n\n// Resolve a pending decision\napp.post('/decisions/:executionId/resolve', async (c) => {\n const runtime = c.get('runtime');\n const executionId = c.req.param('executionId');\n const body = await c.req.json<{ approved: boolean; reason?: string }>();\n\n await runtime.resolveDecision(executionId, body);\n return c.json({ ok: true, data: { resolved: true } });\n});\n\nexport default app;\n","import { Hono } from 'hono';\nimport type { StudioEnv } from '../types.js';\nimport type { CostAggregator } from '../cost-aggregator.js';\n\nexport function createCostRoutes(costAggregator: CostAggregator) {\n const app = new Hono<StudioEnv>();\n\n app.get('/costs', (c) => {\n return c.json({ ok: true, data: costAggregator.getData() });\n });\n\n app.post('/costs/reset', (c) => {\n costAggregator.reset();\n return c.json({ ok: true, data: { reset: true } });\n });\n\n return app;\n}\n","import { Hono } from 'hono';\nimport type { StudioEnv } from '../types.js';\nimport type { EvalResult, Scorer } from '@axlsdk/eval';\n\nexport function createEvalRoutes(evalLoader?: () => Promise<void>) {\n const app = new Hono<StudioEnv>();\n\n // List registered eval configs\n app.get('/evals', async (c) => {\n if (evalLoader) await evalLoader();\n const runtime = c.get('runtime');\n const evals = runtime.getRegisteredEvals();\n return c.json({ ok: true, data: evals });\n });\n\n // Get eval run history\n app.get('/evals/history', async (c) => {\n const runtime = c.get('runtime');\n const history = await runtime.getEvalHistory();\n return c.json({ ok: true, data: history });\n });\n\n // Run a registered eval by name (supports optional multi-run via { runs: N })\n app.post('/evals/:name/run', async (c) => {\n if (evalLoader) await evalLoader();\n const runtime = c.get('runtime');\n const name = c.req.param('name');\n\n const entry = runtime.getRegisteredEval(name);\n if (!entry) {\n return c.json(\n { ok: false, error: { code: 'NOT_FOUND', message: `Eval \"${name}\" not found` } },\n 404,\n );\n }\n\n let runs = 1;\n try {\n const body = (await c.req.json().catch(() => ({}))) as Record<string, unknown>;\n if (typeof body.runs === 'number' && Number.isFinite(body.runs) && body.runs > 1) {\n runs = Math.min(Math.floor(body.runs), 25);\n }\n } catch {\n // No body or invalid body — single run\n }\n\n try {\n if (runs > 1) {\n const { randomUUID } = await import('node:crypto');\n const { aggregateRuns } = await import('@axlsdk/eval');\n const runGroupId = randomUUID();\n const results = [];\n for (let r = 0; r < runs; r++) {\n const result = await runtime.runRegisteredEval(name, {\n metadata: { runGroupId, runIndex: r },\n });\n results.push(result);\n }\n const typedResults = results as EvalResult[];\n const aggregate = aggregateRuns(typedResults);\n const first = typedResults[0]!;\n const result = { ...first, _multiRun: { aggregate, allRuns: typedResults } };\n return c.json({ ok: true, data: result });\n } else {\n // Runtime persists eval result to history automatically\n const result = await runtime.runRegisteredEval(name);\n return c.json({ ok: true, data: result });\n }\n } catch (err) {\n const message = err instanceof Error ? err.message : String(err);\n return c.json({ ok: false, error: { code: 'EVAL_ERROR', message } }, 400);\n }\n });\n\n // Rescore: re-run scorers on saved outputs\n app.post('/evals/:name/rescore', async (c) => {\n if (evalLoader) await evalLoader();\n const runtime = c.get('runtime');\n const name = c.req.param('name');\n const body = await c.req.json<{ resultId: string }>();\n\n if (!body.resultId || typeof body.resultId !== 'string') {\n return c.json(\n { ok: false, error: { code: 'BAD_REQUEST', message: 'resultId is required' } },\n 400,\n );\n }\n\n const entry = runtime.getRegisteredEval(name);\n if (!entry) {\n return c.json(\n { ok: false, error: { code: 'NOT_FOUND', message: `Eval \"${name}\" not found` } },\n 404,\n );\n }\n\n const history = await runtime.getEvalHistory();\n const historyEntry = history.find((h) => h.id === body.resultId);\n if (!historyEntry) {\n return c.json(\n { ok: false, error: { code: 'NOT_FOUND', message: `Result \"${body.resultId}\" not found` } },\n 404,\n );\n }\n\n try {\n const { rescore } = await import('@axlsdk/eval');\n const config = entry.config as { scorers?: unknown[] };\n const result = await rescore(\n historyEntry.data as EvalResult,\n config.scorers as Scorer[],\n runtime,\n );\n await runtime.saveEvalResult({\n id: result.id,\n eval: name,\n timestamp: Date.now(),\n data: result,\n });\n return c.json({ ok: true, data: result });\n } catch (err) {\n const message = err instanceof Error ? err.message : String(err);\n return c.json({ ok: false, error: { code: 'EVAL_ERROR', message } }, 400);\n }\n });\n\n // Compare eval results\n app.post('/evals/compare', async (c) => {\n const runtime = c.get('runtime');\n const body = await c.req.json<{\n baseline: unknown;\n candidate: unknown;\n options?: { thresholds?: Record<string, number> | number };\n }>();\n\n try {\n const result = await runtime.evalCompare(body.baseline, body.candidate, body.options);\n return c.json({ ok: true, data: result });\n } catch (err) {\n const message = err instanceof Error ? err.message : String(err);\n return c.json({ ok: false, error: { code: 'EVAL_ERROR', message } }, 400);\n }\n });\n\n return app;\n}\n","import { Hono } from 'hono';\nimport type { StudioEnv } from '../types.js';\nimport type { ConnectionManager } from '../ws/connection-manager.js';\n\nexport function createPlaygroundRoutes(connMgr: ConnectionManager) {\n const app = new Hono<StudioEnv>();\n\n // Chat with an agent directly — no workflow required\n app.post('/playground/chat', async (c) => {\n const runtime = c.get('runtime');\n const body = await c.req.json<{\n sessionId?: string;\n message: string;\n agent?: string;\n }>();\n\n if (!body.message || typeof body.message !== 'string' || !body.message.trim()) {\n return c.json(\n {\n ok: false,\n error: {\n code: 'INVALID_INPUT',\n message: 'message is required and must be a non-empty string',\n },\n },\n 400,\n );\n }\n\n const agents = runtime.getAgents();\n const agent = body.agent ? agents.find((a) => a._name === body.agent) : agents[0];\n if (!agent) {\n return c.json(\n {\n ok: false,\n error: { code: 'NO_AGENT', message: `Agent \"${body.agent ?? ''}\" not found` },\n },\n 400,\n );\n }\n\n const sessionId = body.sessionId ?? `playground-${Date.now()}`;\n const executionId = `playground-${sessionId}-${Date.now()}`;\n const store = runtime.getStateStore();\n\n // Load session history for multi-turn conversations\n const history = await store.getSession(sessionId);\n history.push({ role: 'user', content: body.message });\n\n // Create a context wired to stream events to the WS channel\n const ctx = runtime.createContext({\n sessionHistory: history,\n onToken: (token: string) => {\n connMgr.broadcastWithWildcard(`execution:${executionId}`, {\n type: 'token',\n data: token,\n });\n },\n });\n\n // Run the agent ask asynchronously, stream results via WS\n (async () => {\n try {\n const result = await ctx.ask(agent, body.message);\n const resultText = typeof result === 'string' ? result : JSON.stringify(result);\n\n // Save assistant response to session history\n history.push({ role: 'assistant', content: resultText });\n await store.saveSession(sessionId, history);\n\n connMgr.broadcastWithWildcard(`execution:${executionId}`, {\n type: 'done',\n data: resultText,\n });\n } catch (err) {\n connMgr.broadcastWithWildcard(`execution:${executionId}`, {\n type: 'error',\n message: err instanceof Error ? err.message : String(err),\n });\n }\n })();\n\n return c.json({\n ok: true,\n data: { sessionId, executionId, streaming: true },\n });\n });\n\n return app;\n}\n","import { resolve, relative, dirname, basename } from 'node:path';\nimport { readdirSync, statSync } from 'node:fs';\nimport { pathToFileURL } from 'node:url';\nimport type { AxlRuntime } from '@axlsdk/axl';\nimport { importModule } from './cli-utils.js';\n\n// In the CJS bundle, tsup stubs import.meta as {} so import.meta.url is\n// undefined. Fall back to __filename (which CJS defines) converted to a\n// file:// URL so tsImport() gets a valid parentURL.\nconst parentURL: string =\n import.meta.url ?? pathToFileURL(typeof __filename !== 'undefined' ? __filename : __dirname).href;\n\n/**\n * Configuration for lazy eval file discovery.\n *\n * - `string` — a glob pattern or explicit file path\n * - `string[]` — multiple patterns/paths\n * - `object` — patterns with optional import conditions\n */\nexport type EvalLoaderConfig =\n | string\n | string[]\n | {\n files: string | string[];\n\n /**\n * Custom Node.js import conditions (e.g., `['development']`).\n *\n * In monorepos, package.json `exports` often use the `development` condition\n * to point at source (`.ts`) instead of built dist. Without this, eval files\n * that import workspace packages resolve to dist files, which may not exist.\n *\n * **WARNING**: Conditions are registered process-wide via `module.register()`.\n * They affect all subsequent imports in the process, not just eval files.\n */\n conditions?: string[];\n };\n\n/**\n * Create a lazy eval loader that resolves file patterns and dynamically imports\n * eval files on first call, registering them with the runtime.\n *\n * The loader is idempotent — subsequent calls return the same promise.\n * Concurrent callers all await the same loading work.\n *\n * Eval files should export a default config with `{ workflow, dataset, scorers }`\n * (the result of `defineEval()` from `@axlsdk/eval`). An optional named export\n * `executeWorkflow` overrides the default `runtime.execute()` behavior.\n *\n * Eval names are the file's path relative to `cwd` (project root), minus the\n * `.eval.*` suffix. This makes names completely stable — a file's name never\n * changes regardless of what other files or patterns exist.\n *\n * @param config Glob patterns, file paths, or object with conditions\n * @param runtime The AxlRuntime to register discovered evals on\n * @param cwd Base directory for resolving patterns and deriving names (default: `process.cwd()`)\n */\nexport function createEvalLoader(\n config: EvalLoaderConfig,\n runtime: AxlRuntime,\n cwd?: string,\n): () => Promise<void> {\n let loadPromise: Promise<void> | undefined;\n const { patterns, conditions } = normalizeConfig(config);\n const baseCwd = cwd ?? process.cwd();\n\n return () => {\n if (!loadPromise) {\n loadPromise = loadEvalFiles(patterns, conditions, baseCwd, runtime).catch((err) => {\n loadPromise = undefined; // Allow retry on next request\n throw err;\n });\n }\n return loadPromise;\n };\n}\n\n// ── Core loading logic ─────────────────────────────────────────────\n\nasync function loadEvalFiles(\n patterns: string[],\n conditions: string[],\n cwd: string,\n runtime: AxlRuntime,\n): Promise<void> {\n if (conditions.length > 0) {\n await registerConditions(conditions);\n }\n\n const files = resolvePatterns(patterns, cwd);\n\n if (files.length === 0) {\n console.warn(`[axl-studio] No eval files found matching: ${patterns.join(', ')}`);\n return;\n }\n\n for (const file of files) {\n try {\n const mod = await importModule(file, parentURL);\n const evalConfig = mod.default?.default ?? mod.default ?? mod.config ?? mod;\n\n if (!evalConfig.workflow || !evalConfig.dataset || !evalConfig.scorers) {\n console.warn(\n `[axl-studio] Skipping ${file}: not a valid eval config ` +\n `(missing workflow, dataset, or scorers)`,\n );\n continue;\n }\n\n const name = deriveEvalName(file, cwd);\n\n if (runtime.getRegisteredEval(name)) {\n console.warn(\n `[axl-studio] Eval name \"${name}\" from ${file} collides with an ` +\n `already-registered eval — overwriting`,\n );\n }\n\n runtime.registerEval(name, evalConfig, mod.executeWorkflow);\n } catch (err) {\n const msg = err instanceof Error ? err.message : String(err);\n console.warn(`[axl-studio] Failed to load eval ${file}: ${msg}`);\n }\n }\n}\n\n// ── Internal helpers ───────────────────────────────────────────────\n\nfunction normalizeConfig(config: EvalLoaderConfig): {\n patterns: string[];\n conditions: string[];\n} {\n if (typeof config === 'string') {\n return { patterns: [config], conditions: [] };\n }\n if (Array.isArray(config)) {\n return { patterns: config, conditions: [] };\n }\n const files = typeof config.files === 'string' ? [config.files] : config.files;\n return { patterns: files, conditions: config.conditions ?? [] };\n}\n\n/**\n * Derive eval name from file path relative to cwd.\n *\n * Examples (cwd = `/project`):\n * - `/project/evals/suggestions.eval.ts` → `\"evals/suggestions\"`\n * - `/project/evals/api/accuracy.eval.ts` → `\"evals/api/accuracy\"`\n */\nfunction deriveEvalName(filePath: string, cwd: string): string {\n const rel = relative(cwd, filePath);\n // Normalize to forward slashes for cross-platform consistency\n const normalized = rel.replace(/\\\\/g, '/');\n // Guard: file outside cwd (symlink, absolute path) — fall back to basename\n if (normalized.startsWith('../')) {\n const base = basename(filePath);\n const stripped = base.replace(/\\.eval\\.[mc]?[jt]sx?$/, '');\n return stripped !== base ? stripped : base.replace(/\\.[mc]?[jt]sx?$/, '') || base;\n }\n // Strip .eval.ts, .eval.mjs, .eval.js, etc.\n const withoutEval = normalized.replace(/\\.eval\\.[mc]?[jt]sx?$/, '');\n if (withoutEval !== normalized) return withoutEval;\n // Fallback: strip extension\n const withoutExt = normalized.replace(/\\.[mc]?[jt]sx?$/, '');\n return withoutExt || normalized;\n}\n\n/**\n * Resolve patterns to absolute file paths.\n *\n * Supports:\n * - Explicit file paths (no wildcards)\n * - Single-directory globs: `dir/*.eval.ts`\n * - Recursive globs: `dir/**\\/*.eval.ts` or `**\\/*.eval.ts`\n *\n * Multi-segment `**` (e.g., `a/**\\/b/**\\/*.ts`) is not supported.\n */\nfunction resolvePatterns(patterns: string[], cwd: string): string[] {\n const files: string[] = [];\n const seen = new Set<string>();\n for (const pattern of patterns) {\n const resolved = pattern.includes('*') ? expandGlob(pattern, cwd) : [resolve(cwd, pattern)];\n for (const file of resolved) {\n if (!seen.has(file)) {\n seen.add(file);\n files.push(file);\n }\n }\n }\n return files;\n}\n\n/**\n * Expand a glob pattern to matching file paths.\n *\n * Supported forms:\n * - `dir/*.eval.ts` — match files in dir/\n * - `dir/**\\/*.eval.ts` — recursively match under dir/\n * - `**\\/*.eval.ts` — recursively match under cwd\n */\nfunction expandGlob(pattern: string, cwd: string): string[] {\n if (pattern.includes('**/')) {\n const sepIdx = pattern.indexOf('**/');\n const baseDir = resolve(cwd, pattern.slice(0, sepIdx) || '.');\n const fileGlob = pattern.slice(sepIdx + 3) || '*';\n return findFiles(baseDir, fileGlob, true);\n }\n\n const dir = resolve(cwd, dirname(pattern));\n const fileGlob = basename(pattern);\n return findFiles(dir, fileGlob, false);\n}\n\nconst MAX_DEPTH = 20;\n\nfunction findFiles(dir: string, fileGlob: string, recursive: boolean, depth = 0): string[] {\n if (depth > MAX_DEPTH) return [];\n const matcher = globToRegex(fileGlob);\n const results: string[] = [];\n\n try {\n const entries = readdirSync(dir);\n for (const entry of entries) {\n const full = resolve(dir, entry);\n try {\n const stat = statSync(full);\n if (stat.isFile() && matcher.test(entry)) {\n results.push(full);\n } else if (stat.isDirectory() && recursive) {\n results.push(...findFiles(full, fileGlob, true, depth + 1));\n }\n } catch {\n // Skip unreadable entries\n }\n }\n } catch {\n // Directory doesn't exist or unreadable\n }\n\n return results;\n}\n\n/** Convert a simple glob pattern (e.g., `*.eval.ts`) to a RegExp. */\nfunction globToRegex(glob: string): RegExp {\n const escaped = glob.replace(/[.+?^${}()|[\\]\\\\]/g, '\\\\$&').replace(/\\*/g, '.*');\n return new RegExp(`^${escaped}$`);\n}\n\nasync function registerConditions(conditions: string[]): Promise<void> {\n try {\n const nodeModule = await import('node:module');\n const hookCode = [\n `const extra = ${JSON.stringify(conditions)};`,\n `export async function resolve(specifier, context, nextResolve) {`,\n ` return nextResolve(specifier, {`,\n ` ...context,`,\n ` conditions: [...new Set([...context.conditions, ...extra])],`,\n ` });`,\n `}`,\n ].join('\\n');\n nodeModule.register(`data:text/javascript,${encodeURIComponent(hookCode)}`);\n } catch {\n console.warn('[axl-studio] Warning: import conditions require Node.js 20.6+');\n }\n}\n","import { resolve } from 'node:path';\nimport { existsSync } from 'node:fs';\nimport { pathToFileURL } from 'node:url';\n\n// ── Config auto-detection ──────────────────────────────────────────\n\nexport const CONFIG_CANDIDATES = [\n 'axl.config.mts',\n 'axl.config.ts',\n 'axl.config.mjs',\n 'axl.config.js',\n];\n\nexport function findConfig(cwd: string): string | undefined {\n for (const name of CONFIG_CANDIDATES) {\n const p = resolve(cwd, name);\n if (existsSync(p)) return p;\n }\n return undefined;\n}\n\n// ── Parse CLI args ──────────────────────────────────────────────────\n\nexport interface CliArgs {\n port: number;\n config?: string;\n open: boolean;\n conditions: string[];\n help: boolean;\n portError?: string;\n}\n\nexport function parseArgs(argv: string[]): CliArgs {\n let port = 4400;\n let config: string | undefined;\n let open = false;\n let help = false;\n let conditions: string[] = [];\n\n for (let i = 2; i < argv.length; i++) {\n const arg = argv[i];\n if (arg === '--port' && argv[i + 1]) {\n port = parseInt(argv[i + 1], 10);\n i++;\n } else if (arg === '--config' && argv[i + 1]) {\n config = argv[i + 1];\n i++;\n } else if (arg === '--conditions' && argv[i + 1]) {\n conditions = argv[i + 1]\n .split(',')\n .map((c) => c.trim())\n .filter(Boolean);\n i++;\n } else if (arg === '--open') {\n open = true;\n } else if (arg === '--help' || arg === '-h') {\n help = true;\n }\n }\n\n const result: CliArgs = { port, config, open, help, conditions };\n\n if (isNaN(port) || port < 1 || port > 65535) {\n result.portError = `Invalid port: ${port}. Must be between 1 and 65535.`;\n }\n\n return result;\n}\n\n// ── Extension helpers ──────────────────────────────────────────────\n\n/**\n * Returns true if the file is TypeScript and needs tsx to load.\n */\nexport function needsTsxLoader(configPath: string): boolean {\n return /\\.[mc]?tsx?$/.test(configPath);\n}\n\n// ── Module loading ────────────────────────────────────────────────\n\n// Lazily resolved tsImport function from tsx. `undefined` = not yet checked,\n// `null` = tsx not available.\nlet tsImportFn:\n | ((specifier: string, parentURL: string) => Promise<Record<string, any>>)\n | null\n | undefined;\n\n/**\n * Import a module, using tsx's `tsImport()` for TypeScript files.\n *\n * `tsImport()` handles ESM/CJS format correctly without process-wide side effects —\n * no need for `register()` hooks or ESM-forcing workarounds. Falls back to regular\n * `import()` for non-TypeScript files or when tsx is not installed.\n */\nexport async function importModule(\n filePath: string,\n parentURL: string,\n): Promise<Record<string, any>> {\n if (needsTsxLoader(filePath)) {\n if (tsImportFn === undefined) {\n try {\n const mod = await import('tsx/esm/api');\n tsImportFn = mod.tsImport ?? null;\n } catch {\n tsImportFn = null;\n console.warn(\n '[axl-studio] Warning: tsx is not installed. TypeScript config files require tsx as a dependency.\\n' +\n ' Install it with: npm install -D tsx',\n );\n }\n }\n if (tsImportFn) {\n return (await tsImportFn(pathToFileURL(filePath).href, parentURL)) as Record<string, any>;\n }\n }\n return await import(pathToFileURL(filePath).href);\n}\n"],"mappings":"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","names":["import_node_path","import_node_fs","import_node_url","import_hono","import_hono","app","import_hono","app","import_hono","app","import_hono","import_axl","app","import_hono","import_axl","app","import_hono","app","import_hono","app","import_hono","app","import_hono","app","result","import_hono","app","app","import_node_path","import_node_fs","import_node_url","import_node_path","import_node_fs","parentURL","fileGlob","import_meta","app"]}
1
+ {"version":3,"sources":["../src/middleware.ts","../src/server/index.ts","../src/server/middleware/error-handler.ts","../src/server/ws/connection-manager.ts","../src/server/ws/protocol.ts","../src/server/ws/handler.ts","../src/server/cost-aggregator.ts","../src/server/routes/health.ts","../src/server/routes/workflows.ts","../src/server/routes/executions.ts","../src/server/routes/sessions.ts","../src/server/routes/agents.ts","../src/server/routes/tools.ts","../src/server/routes/memory.ts","../src/server/routes/decisions.ts","../src/server/routes/costs.ts","../src/server/routes/evals.ts","../src/server/routes/playground.ts","../src/eval-loader.ts","../src/cli-utils.ts"],"sourcesContent":["import { resolve, dirname } from 'node:path';\nimport { existsSync } from 'node:fs';\nimport { fileURLToPath } from 'node:url';\nimport { getRequestListener } from '@hono/node-server';\nimport { WebSocketServer } from 'ws';\nimport { createServer } from './server/index.js';\nimport { handleWsMessage } from './server/ws/protocol.js';\nimport { createEvalLoader } from './eval-loader.js';\nimport type { EvalLoaderConfig } from './eval-loader.js';\nimport type { AxlRuntime } from '@axlsdk/axl';\nimport type { IncomingMessage, ServerResponse, Server } from 'node:http';\n\nexport type { EvalLoaderConfig } from './eval-loader.js';\n\nexport type StudioMiddlewareOptions = {\n /** The AxlRuntime instance to observe and control. */\n runtime: AxlRuntime;\n\n /**\n * URL path prefix where Studio is mounted.\n * Must match the mount path in your framework (Express `app.use()`,\n * Fastify `register()`, Hono `app.route()`, etc.). The framework is\n * expected to strip the prefix from `req.url` before calling the handler.\n *\n * Do not set basePath when using a raw `http.Server` as the root handler —\n * leave it empty and mount at root instead.\n *\n * Must start with '/' when non-empty. Trailing slashes are stripped.\n * Only URL-safe characters allowed: [a-zA-Z0-9/_-]\n *\n * @example '/studio'\n * @example '/admin/studio'\n * @example '' — mounted at root (default)\n */\n basePath?: string;\n\n /**\n * Serve the pre-built Studio SPA.\n * Set to false if serving the client from a CDN or separate build.\n * @default true\n */\n serveClient?: boolean;\n\n /**\n * Verify a WebSocket upgrade request before completing the handshake.\n * Return true to allow, false to reject. Throw to reject with an error.\n *\n * IMPORTANT: WebSocket upgrades bypass Express/Fastify/Koa middleware.\n * If your HTTP routes are behind auth middleware, WS connections are NOT\n * automatically protected. Use this callback to enforce authentication\n * on WebSocket connections.\n */\n verifyUpgrade?: (req: IncomingMessage) => boolean | Promise<boolean>;\n\n /**\n * Disable all mutating endpoints (execute, test, send, delete, resolve).\n * When true, Studio is observation-only.\n * @default false\n */\n readOnly?: boolean;\n\n /**\n * Lazy-load eval files for the Eval Runner panel.\n *\n * Eval files are dynamically imported on first access to eval endpoints,\n * not at middleware construction time. This means:\n * - Zero cost during normal API operation\n * - Eval files can import from any module without creating circular deps\n * in the static module graph (they're loaded as standalone entry points)\n * - `@axlsdk/eval` can remain a devDependency — eval files never enter\n * the production bundle since bundlers can't see dynamic imports\n *\n * Accepts glob patterns, explicit file paths, or an object with\n * `conditions` for monorepo source export resolution.\n *\n * Eval files are loaded once and cached for the middleware's lifetime.\n * Changes to eval files require a server restart.\n *\n * @example\n * // Single glob pattern\n * evals: 'evals/*.eval.ts'\n *\n * @example\n * // Multiple patterns\n * evals: ['libs/api/evals/*.eval.ts', 'libs/ai/evals/*.eval.ts']\n *\n * @example\n * // With import conditions for monorepo source exports\n * evals: {\n * files: 'libs/api/evals/*.eval.ts',\n * conditions: ['development'],\n * }\n */\n evals?: EvalLoaderConfig;\n};\n\n/**\n * Minimal contract a WebSocket connection must satisfy.\n * Matches the `ws` library API (de facto standard in Node.js).\n */\nexport interface StudioWebSocket {\n send(data: string): void;\n close(): void;\n on(event: 'message', fn: (data: string | Buffer) => void): void;\n on(event: 'close', fn: () => void): void;\n on(event: 'error', fn: (err: Error) => void): void;\n}\n\n// Re-export for Hono-in-Hono consumers\nexport { handleWsMessage } from './server/ws/protocol.js';\n\nexport type StudioMiddleware = ReturnType<typeof createStudioMiddleware>;\n\nexport function createStudioMiddleware(options: StudioMiddlewareOptions) {\n const { runtime, serveClient = true, verifyUpgrade, readOnly = false } = options;\n\n // Normalize basePath: strip trailing slashes, validate format\n const basePath = normalizeBasePath(options.basePath);\n\n // Resolve pre-built SPA assets from this package's dist/\n const staticRoot = serveClient ? resolveClientDist() : undefined;\n\n if (serveClient && !staticRoot) {\n const dir =\n import.meta.dirname ??\n (typeof __dirname !== 'undefined' ? __dirname : dirname(fileURLToPath(import.meta.url)));\n console.warn(\n '[axl-studio] serveClient is true but no pre-built client found at ' +\n `${resolve(dir, 'client')}. Studio UI will not be available. ` +\n 'Set serveClient: false to suppress this warning.',\n );\n }\n\n // Create lazy eval loader if eval files are configured\n const evalLoader = options.evals ? createEvalLoader(options.evals, runtime) : undefined;\n\n const { app, connMgr, traceListener } = createServer({\n runtime,\n staticRoot,\n basePath,\n readOnly,\n cors: false, // Host framework owns CORS policy\n evalLoader,\n });\n\n // Log production safety warning\n if (process.env.NODE_ENV === 'production' && !verifyUpgrade) {\n console.warn(\n '[axl-studio] WARNING: Studio middleware mounted in production without verifyUpgrade. ' +\n 'WebSocket connections are not authenticated. All registered workflows, tools, and ' +\n 'agents are accessible. See https://axlsdk.com/docs/studio/security',\n );\n }\n\n // Convert Hono app → Node.js (req, res) handler via @hono/node-server.\n // overrideGlobalObjects: false prevents replacing global.Request/Response,\n // which could break the host application.\n const listener = getRequestListener(app.fetch, {\n overrideGlobalObjects: false,\n });\n\n let closed = false;\n\n function handler(req: IncomingMessage, res: ServerResponse) {\n if (closed) {\n res.writeHead(503, { 'Content-Type': 'application/json' });\n res.end(\n JSON.stringify({\n ok: false,\n error: { code: 'CLOSED', message: 'Studio middleware has been shut down' },\n }),\n );\n return;\n }\n\n // Express/NestJS/Koa body parsers consume the raw IncomingMessage stream\n // and store the parsed result on req.body. When that happens,\n // @hono/node-server's getRequestListener reads an empty stream and Hono\n // sees no body. To fix this, we re-serialize req.body as req.rawBody —\n // a Buffer that getRequestListener checks before falling back to the\n // stream (see newRequestFromIncoming in @hono/node-server/dist/listener.js).\n //\n // Verified against @hono/node-server@1.19.9. If this breaks after an\n // upgrade, check whether the rawBody instanceof Buffer check still exists\n // in newRequestFromIncoming.\n const reqAny = req as unknown as Record<string, unknown>;\n if (reqAny.body != null && !reqAny.rawBody) {\n try {\n reqAny.rawBody = Buffer.from(JSON.stringify(reqAny.body));\n } catch {\n // Non-serializable body — Hono will see an empty body\n }\n }\n\n listener(req, res).catch((err) => {\n console.error('[axl-studio] Unhandled error in request handler:', err);\n if (!res.headersSent) {\n res.writeHead(500, { 'Content-Type': 'application/json' });\n res.end(\n JSON.stringify({\n ok: false,\n error: { code: 'INTERNAL_ERROR', message: 'Internal server error' },\n }),\n );\n }\n });\n }\n\n // Handle an individual WebSocket using the Studio protocol.\n // Adapts any StudioWebSocket to ConnectionManager's internal BroadcastTarget.\n function handleWebSocket(ws: StudioWebSocket) {\n if (closed) {\n ws.close();\n return;\n }\n const socket = {\n send: (data: string) => ws.send(data),\n close: () => ws.close(),\n };\n connMgr.add(socket);\n\n ws.on('message', (raw) => {\n const reply = handleWsMessage(String(raw), socket, connMgr);\n if (reply) ws.send(reply);\n });\n\n ws.on('close', () => connMgr.remove(socket));\n ws.on('error', () => connMgr.remove(socket));\n }\n\n // Internal WebSocketServer — created lazily by upgradeWebSocket()\n let wss: InstanceType<typeof WebSocketServer> | undefined;\n // References for cleanup: the upgrade handler and server it's attached to\n let upgradeHandler: ((...args: any[]) => void) | undefined;\n let serverRef: Server | undefined;\n\n // Convenience: attach WS handling to an http.Server.\n function upgradeWebSocket(server: Server, path?: string) {\n if (wss) {\n throw new Error(\n '[axl-studio] upgradeWebSocket() has already been called. ' +\n 'Call close() first if you need to re-attach.',\n );\n }\n\n const wsPath = path ?? (basePath ? `${basePath}/ws` : '/ws');\n\n wss = new WebSocketServer({ noServer: true });\n serverRef = server;\n\n upgradeHandler = async (req: IncomingMessage, socket: any, head: Buffer) => {\n // Match path, ignoring query string\n const pathname = new URL(req.url!, `http://${req.headers.host}`).pathname;\n if (pathname !== wsPath) return; // Let other upgrade handlers run\n\n // Apply auth verification\n if (verifyUpgrade) {\n try {\n const allowed = await verifyUpgrade(req);\n if (!allowed) {\n socket.write('HTTP/1.1 401 Unauthorized\\r\\n\\r\\n');\n socket.destroy();\n return;\n }\n } catch {\n socket.write('HTTP/1.1 403 Forbidden\\r\\n\\r\\n');\n socket.destroy();\n return;\n }\n }\n\n // Guard against close() being called during async verifyUpgrade\n if (!wss) {\n socket.destroy();\n return;\n }\n\n wss.handleUpgrade(req, socket, head, (ws) => {\n handleWebSocket(ws);\n });\n };\n\n server.on('upgrade', upgradeHandler);\n }\n\n // Cleanup function for lifecycle management.\n function close() {\n closed = true;\n\n // Close all WebSocket connections\n connMgr.closeAll();\n\n // Remove the upgrade listener from the server before closing WSS\n if (upgradeHandler && serverRef) {\n serverRef.removeListener('upgrade', upgradeHandler);\n upgradeHandler = undefined;\n serverRef = undefined;\n }\n\n // Shut down the internal WebSocketServer if one was created\n if (wss) {\n wss.close();\n wss = undefined;\n }\n\n // Remove only our trace event listener from the runtime\n if (traceListener) {\n runtime.removeListener('trace', traceListener);\n }\n }\n\n return {\n handler,\n handleWebSocket,\n upgradeWebSocket,\n app,\n connectionManager: connMgr,\n close,\n };\n}\n\n/**\n * Normalize and validate basePath.\n * - Empty string and undefined → ''\n * - Strip trailing slashes\n * - Validate leading slash when non-empty\n * - Reject unsafe characters\n */\nfunction normalizeBasePath(raw?: string): string {\n if (!raw) return '';\n\n // Strip trailing slashes\n const normalized = raw.replace(/\\/+$/, '');\n if (!normalized) return '';\n\n // Must start with /\n if (!normalized.startsWith('/')) {\n throw new Error(`basePath must start with '/' (got '${raw}'). Example: '/studio'`);\n }\n\n // Reject path traversal, consecutive slashes, and unsafe characters\n if (normalized.includes('..')) {\n throw new Error(`basePath must not contain '..' segments (got '${raw}')`);\n }\n if (normalized.includes('//')) {\n throw new Error(`basePath must not contain consecutive slashes (got '${raw}')`);\n }\n if (!/^\\/[a-zA-Z0-9/_-]*$/.test(normalized)) {\n throw new Error(\n `basePath contains invalid characters (got '${raw}'). ` +\n 'Only alphanumeric characters, /, _, and - are allowed.',\n );\n }\n\n return normalized;\n}\n\nfunction resolveClientDist(): string | undefined {\n // Resolve the directory of this file (dist/ in published package).\n const dir =\n import.meta.dirname ??\n (typeof __dirname !== 'undefined' ? __dirname : dirname(fileURLToPath(import.meta.url)));\n const candidate = resolve(dir, 'client');\n return existsSync(resolve(candidate, 'index.html')) ? candidate : undefined;\n}\n","import { existsSync, readFileSync } from 'node:fs';\nimport { resolve } from 'node:path';\nimport { Hono } from 'hono';\nimport { cors } from 'hono/cors';\nimport { serveStatic } from '@hono/node-server/serve-static';\nimport type { AxlRuntime } from '@axlsdk/axl';\nimport type { StudioEnv } from './types.js';\nimport { errorHandler } from './middleware/error-handler.js';\nimport { ConnectionManager } from './ws/connection-manager.js';\nimport { createWsHandlers } from './ws/handler.js';\nimport { CostAggregator } from './cost-aggregator.js';\nimport healthRoutes from './routes/health.js';\nimport { createWorkflowRoutes } from './routes/workflows.js';\nimport executionRoutes from './routes/executions.js';\nimport { createSessionRoutes } from './routes/sessions.js';\nimport agentRoutes from './routes/agents.js';\nimport toolRoutes from './routes/tools.js';\nimport memoryRoutes from './routes/memory.js';\nimport decisionRoutes from './routes/decisions.js';\nimport { createCostRoutes } from './routes/costs.js';\nimport { createEvalRoutes } from './routes/evals.js';\nimport { createPlaygroundRoutes } from './routes/playground.js';\n\nexport type { StudioEnv } from './types.js';\nexport { ConnectionManager } from './ws/connection-manager.js';\nexport type { BroadcastTarget } from './ws/connection-manager.js';\nexport { CostAggregator } from './cost-aggregator.js';\n\nexport type CreateServerOptions = {\n runtime: AxlRuntime;\n /** Root path for serving pre-built SPA static assets. */\n staticRoot?: string;\n /** Base URL path for client-side routing and API calls. Injected into index.html at serve time. */\n basePath?: string;\n /** When true, disable all mutating API endpoints. */\n readOnly?: boolean;\n /** Apply CORS headers. Default: true (standalone CLI). Set false for embedded middleware. */\n cors?: boolean;\n /** Lazy eval file loader. Called before eval routes access the runtime's registered evals. */\n evalLoader?: () => Promise<void>;\n};\n\nexport function createServer(options: CreateServerOptions) {\n const { runtime, staticRoot, basePath = '', readOnly = false } = options;\n const app = new Hono<StudioEnv>();\n const connMgr = new ConnectionManager();\n const costAggregator = new CostAggregator(connMgr);\n\n // ── Middleware ──────────────────────────────────────────────────────\n if (options.cors !== false) {\n app.use('*', cors());\n }\n app.use('*', errorHandler);\n app.use('*', async (c, next) => {\n c.set('runtime', runtime);\n await next();\n });\n\n // ── Read-only mode ──────────────────────────────────────────────────\n if (readOnly) {\n const blocked = [\n 'POST /api/workflows',\n 'POST /api/executions',\n 'POST /api/sessions',\n 'DELETE /api/sessions',\n 'PUT /api/memory',\n 'DELETE /api/memory',\n 'POST /api/decisions',\n 'POST /api/costs',\n 'POST /api/tools',\n 'POST /api/evals',\n 'POST /api/playground',\n ];\n app.use('/api/*', async (c, next) => {\n // c.req.path returns the full path including any parent route prefix\n // (e.g., /studio/api/workflows when mounted via app.route('/studio', ...)).\n // Extract just the /api/... portion for matching.\n const apiIdx = c.req.path.indexOf('/api/');\n const apiPath = apiIdx >= 0 ? c.req.path.slice(apiIdx) : c.req.path;\n const key = `${c.req.method} ${apiPath}`;\n if (blocked.some((b) => key.startsWith(b))) {\n return c.json(\n {\n ok: false,\n error: { code: 'READ_ONLY', message: 'Studio is mounted in read-only mode' },\n },\n 405,\n );\n }\n await next();\n });\n }\n\n // ── API Routes ─────────────────────────────────────────────────────\n const api = new Hono<StudioEnv>();\n api.route('/', healthRoutes);\n api.route('/', createWorkflowRoutes(connMgr));\n api.route('/', executionRoutes);\n api.route('/', createSessionRoutes(connMgr));\n api.route('/', agentRoutes);\n api.route('/', toolRoutes);\n api.route('/', memoryRoutes);\n api.route('/', decisionRoutes);\n api.route('/', createCostRoutes(costAggregator));\n api.route('/', createEvalRoutes(options.evalLoader));\n api.route('/', createPlaygroundRoutes(connMgr));\n\n app.route('/api', api);\n\n // ── Trace event bridging ───────────────────────────────────────────\n const traceListener = (event: unknown) => {\n const traceEvent = event as {\n executionId?: string;\n type?: string;\n agent?: string;\n model?: string;\n workflow?: string;\n cost?: number;\n tokens?: { input?: number; output?: number; reasoning?: number };\n };\n\n // Broadcast to trace channels\n if (traceEvent.executionId) {\n connMgr.broadcastWithWildcard(`trace:${traceEvent.executionId}`, traceEvent);\n }\n\n // Feed cost aggregator\n costAggregator.onTrace(traceEvent);\n\n // Broadcast pending decisions\n if (traceEvent.type === 'await_human') {\n connMgr.broadcast('decisions', traceEvent);\n }\n };\n runtime.on('trace', traceListener);\n\n // ── Static SPA serving (production) ────────────────────────────────\n if (staticRoot) {\n // Read index.html once at startup. When basePath is set, inject the <base>\n // tag and runtime config so asset paths and client-side routing work\n // regardless of whether the mount URL has a trailing slash.\n const indexPath = resolve(staticRoot, 'index.html');\n let spaHtml: string | undefined;\n\n if (!existsSync(indexPath)) {\n console.warn(`[axl-studio] index.html not found at ${indexPath}`);\n } else {\n const rawHtml = readFileSync(indexPath, 'utf-8');\n\n if (basePath) {\n // Escape '<' to prevent </script> in basePath from breaking out of\n // the script tag. JSON.stringify alone is insufficient because the\n // HTML parser processes </script> before JavaScript runs.\n const safeBasePath = JSON.stringify(basePath).replace(/</g, '\\\\u003c');\n const injected = rawHtml.replace(\n '<head>',\n `<head>\\n<base href=\"${basePath}/\">\\n` +\n `<script>window.__AXL_STUDIO_BASE__=${safeBasePath}</script>`,\n );\n\n if (injected === rawHtml) {\n console.warn(\n '[axl-studio] Could not inject basePath into index.html — ' +\n '<head> tag not found. The SPA may not route correctly.',\n );\n }\n spaHtml = injected;\n } else {\n spaHtml = rawHtml;\n }\n }\n\n // Serve static assets (JS, CSS, images). index.html is excluded so the\n // SPA fallback below always serves the version with basePath injection.\n // Without this guard, serveStatic would serve the raw index.html for root\n // requests (/ or /index.html), missing <base> and __AXL_STUDIO_BASE__.\n const staticHandler = serveStatic({\n root: staticRoot,\n rewriteRequestPath: basePath\n ? (path) => (path.startsWith(basePath) ? path.slice(basePath.length) || '/' : path)\n : undefined,\n });\n\n app.use('/*', async (c, next) => {\n const reqPath = c.req.path;\n const resolved =\n basePath && reqPath.startsWith(basePath) ? reqPath.slice(basePath.length) || '/' : reqPath;\n // Skip index.html (handled by SPA fallback) and /ws (handled by WebSocket upgrader)\n if (resolved === '/' || resolved === '/index.html' || resolved === '/ws') {\n return next();\n }\n return staticHandler(c, next);\n });\n\n // SPA fallback: serve the (possibly injected) index.html for all\n // non-API, non-static-asset routes so React Router handles routing.\n // Skip /ws so the WebSocket upgrader (registered after createServer) can handle it.\n if (spaHtml) {\n app.get('*', async (c, next) => {\n const resolved =\n basePath && c.req.path.startsWith(basePath)\n ? c.req.path.slice(basePath.length) || '/'\n : c.req.path;\n if (resolved === '/ws') return next();\n return c.html(spaHtml!);\n });\n }\n }\n\n return {\n app,\n connMgr,\n costAggregator,\n /** Create WS handlers. Call before registering static/SPA routes are reached. */\n createWsHandlers: () => createWsHandlers(connMgr),\n traceListener,\n };\n}\n","import type { Context, Next } from 'hono';\nimport type { StudioEnv, ApiError } from '../types.js';\n\nexport async function errorHandler(c: Context<StudioEnv>, next: Next) {\n try {\n await next();\n } catch (err) {\n const message = err instanceof Error ? err.message : String(err);\n const code = (err as { code?: string }).code ?? 'INTERNAL_ERROR';\n\n // Determine HTTP status from error properties\n let status = 500;\n if ('status' in (err as object)) {\n const errStatus = (err as { status: unknown }).status;\n if (typeof errStatus === 'number' && errStatus >= 400 && errStatus < 600) {\n status = errStatus;\n }\n } else if (\n code === 'NOT_FOUND' ||\n message.includes('not found') ||\n message.includes('not registered')\n ) {\n status = 404;\n } else if (\n code === 'VALIDATION_ERROR' ||\n message.includes('Expected') ||\n message.includes('invalid')\n ) {\n status = 400;\n }\n\n const body: ApiError = {\n ok: false,\n error: { code, message },\n };\n\n return c.json(body, status as 400 | 404 | 500);\n }\n}\n","/**\n * Minimal interface for a connection that can receive broadcast messages.\n * Satisfied by WSContext (Hono), ws.WebSocket (Node.js), and the middleware's\n * adapted socket. Internal to ConnectionManager — not part of the public API.\n */\nexport interface BroadcastTarget {\n send(data: string): void;\n close?(): void;\n}\n\n/**\n * Short-lived event buffer for execution streams.\n * Solves the race where a fast provider (e.g., MockProvider) completes\n * before the client's WS subscription is established. Events are buffered\n * per-channel and replayed to late subscribers.\n */\ninterface ChannelBuffer {\n events: string[]; // Pre-serialized JSON messages\n complete: boolean; // True after done/error event\n timer?: ReturnType<typeof setTimeout>;\n}\n\n/** Channels eligible for replay buffering (execution streams). */\nfunction isBufferedChannel(channel: string): boolean {\n return channel.startsWith('execution:');\n}\n\nconst BUFFER_TTL_MS = 30_000; // Clean up buffers 30s after stream completes\nconst MAX_BUFFER_EVENTS = 500; // Cap replay buffer size\n\n/**\n * Manages WebSocket connections and channel subscriptions.\n * Supports channel multiplexing: clients subscribe/unsubscribe to channels\n * and receive events only for channels they're subscribed to.\n *\n * Execution channels (`execution:*`) are replay-buffered: events are stored\n * so that late subscribers receive the full event history. Buffers are cleaned\n * up shortly after the stream completes.\n */\nexport class ConnectionManager {\n /** channel -> set of WS connections */\n private channels = new Map<string, Set<BroadcastTarget>>();\n /** ws -> set of subscribed channels (for cleanup) */\n private connections = new Map<BroadcastTarget, Set<string>>();\n /** channel -> replay buffer for execution streams */\n private buffers = new Map<string, ChannelBuffer>();\n private maxConnections = 100;\n\n /** Register a new WS connection. */\n add(ws: BroadcastTarget): void {\n if (this.connections.size >= this.maxConnections) {\n ws.close?.();\n return;\n }\n this.connections.set(ws, new Set());\n }\n\n /** Remove a WS connection and all its subscriptions. */\n remove(ws: BroadcastTarget): void {\n const channels = this.connections.get(ws);\n if (channels) {\n for (const ch of channels) {\n this.channels.get(ch)?.delete(ws);\n if (this.channels.get(ch)?.size === 0) {\n this.channels.delete(ch);\n }\n }\n }\n this.connections.delete(ws);\n }\n\n /** Subscribe a connection to a channel. Replays buffered events for execution channels. */\n subscribe(ws: BroadcastTarget, channel: string): void {\n if (!this.connections.has(ws)) return;\n let subs = this.channels.get(channel);\n if (!subs) {\n subs = new Set();\n this.channels.set(channel, subs);\n }\n subs.add(ws);\n this.connections.get(ws)!.add(channel);\n\n // Replay buffered events for late subscribers\n const buffer = this.buffers.get(channel);\n if (buffer) {\n for (const msg of buffer.events) {\n try {\n ws.send(msg);\n } catch {\n this.remove(ws);\n return;\n }\n }\n }\n }\n\n /** Unsubscribe a connection from a channel. */\n unsubscribe(ws: BroadcastTarget, channel: string): void {\n this.channels.get(channel)?.delete(ws);\n if (this.channels.get(channel)?.size === 0) {\n this.channels.delete(channel);\n }\n this.connections.get(ws)?.delete(channel);\n }\n\n /** Broadcast data to all subscribers of a channel. Buffers events for execution channels. */\n broadcast(channel: string, data: unknown): void {\n const msg = JSON.stringify({ type: 'event', channel, data });\n\n // Buffer events for execution channels so late subscribers can replay\n if (isBufferedChannel(channel)) {\n let buffer = this.buffers.get(channel);\n if (!buffer) {\n buffer = { events: [], complete: false };\n this.buffers.set(channel, buffer);\n }\n // Always buffer terminal events; skip non-terminal if at capacity\n const event = data as { type?: string };\n const isTerminal = event.type === 'done' || event.type === 'error';\n if (buffer.events.length < MAX_BUFFER_EVENTS || isTerminal) {\n buffer.events.push(msg);\n }\n\n // Schedule buffer cleanup after terminal events\n if (isTerminal) {\n buffer.complete = true;\n if (buffer.timer) clearTimeout(buffer.timer);\n buffer.timer = setTimeout(() => {\n this.buffers.delete(channel);\n }, BUFFER_TTL_MS);\n }\n }\n\n // Send to current subscribers\n const subs = this.channels.get(channel);\n if (!subs || subs.size === 0) return;\n\n for (const ws of [...subs]) {\n try {\n ws.send(msg);\n } catch {\n this.remove(ws);\n }\n }\n }\n\n /** Broadcast to channel and all wildcard subscribers (e.g., trace:* matches trace:abc). */\n broadcastWithWildcard(channel: string, data: unknown): void {\n this.broadcast(channel, data);\n\n // Check for wildcard subscribers: \"prefix:*\" matches \"prefix:anything\"\n // Send with the actual channel name so wildcard subscribers know the source.\n const colonIdx = channel.indexOf(':');\n if (colonIdx > 0) {\n const wildcardChannel = channel.substring(0, colonIdx) + ':*';\n const subs = this.channels.get(wildcardChannel);\n if (!subs || subs.size === 0) return;\n\n const msg = JSON.stringify({ type: 'event', channel, data });\n for (const ws of [...subs]) {\n try {\n ws.send(msg);\n } catch {\n this.remove(ws);\n }\n }\n }\n }\n\n /** Close all connections, clear all state and buffers. Used during shutdown. */\n closeAll(): void {\n for (const ws of this.connections.keys()) {\n ws.close?.();\n }\n for (const buffer of this.buffers.values()) {\n if (buffer.timer) clearTimeout(buffer.timer);\n }\n this.connections.clear();\n this.channels.clear();\n this.buffers.clear();\n }\n\n /** Get the number of active connections. */\n get connectionCount(): number {\n return this.connections.size;\n }\n\n /** Check if any connections are subscribed to a channel. */\n hasSubscribers(channel: string): boolean {\n return (this.channels.get(channel)?.size ?? 0) > 0;\n }\n}\n","import type { BroadcastTarget } from './connection-manager.js';\nimport type { ConnectionManager } from './connection-manager.js';\n\n/** Channel prefixes that accept suffixes (e.g., execution:abc, trace:*). */\nconst VALID_CHANNEL_PREFIXES = ['execution:', 'trace:'];\n/** Channels that must match exactly (no suffix allowed). */\nconst VALID_EXACT_CHANNELS = ['costs', 'decisions'];\nconst MAX_CHANNEL_LENGTH = 256;\n\n/**\n * Handle a single WebSocket message according to the Studio protocol.\n * Returns a JSON string to send back to the client, or null for no response.\n *\n * Used by both the Hono WS handler (ws/handler.ts) and the Node.js\n * middleware (middleware.ts) to keep the protocol in one place.\n */\nexport function handleWsMessage(\n raw: string,\n socket: BroadcastTarget,\n connMgr: ConnectionManager,\n): string | null {\n // Reject oversized messages (64KB limit)\n if (raw.length > 65536) {\n return JSON.stringify({ type: 'error', message: 'Message too large' });\n }\n\n let msg: { type: string; channel?: string };\n try {\n msg = JSON.parse(raw);\n } catch {\n return JSON.stringify({ type: 'error', message: 'Invalid JSON' });\n }\n\n switch (msg.type) {\n case 'subscribe': {\n const error = validateChannel(msg.channel);\n if (error) return JSON.stringify({ type: 'error', message: error });\n connMgr.subscribe(socket, msg.channel!);\n return JSON.stringify({ type: 'subscribed', channel: msg.channel });\n }\n case 'unsubscribe': {\n const error = validateChannel(msg.channel);\n if (error) return JSON.stringify({ type: 'error', message: error });\n connMgr.unsubscribe(socket, msg.channel!);\n return JSON.stringify({ type: 'unsubscribed', channel: msg.channel });\n }\n case 'ping':\n return JSON.stringify({ type: 'pong' });\n default:\n return JSON.stringify({ type: 'error', message: 'Unknown message type' });\n }\n}\n\nfunction validateChannel(channel: unknown): string | null {\n if (typeof channel !== 'string' || !channel) {\n return 'Missing or invalid channel';\n }\n if (channel.length > MAX_CHANNEL_LENGTH) {\n return `Channel name exceeds ${MAX_CHANNEL_LENGTH} characters`;\n }\n if (\n !VALID_EXACT_CHANNELS.includes(channel as (typeof VALID_EXACT_CHANNELS)[number]) &&\n !VALID_CHANNEL_PREFIXES.some((p) => channel.startsWith(p))\n ) {\n return `Invalid channel: ${channel}`;\n }\n return null;\n}\n","import type { WSContext } from 'hono/ws';\nimport type { ConnectionManager } from './connection-manager.js';\nimport { handleWsMessage } from './protocol.js';\n\n/** Create WS event handlers for a Hono WebSocket connection. */\nexport function createWsHandlers(connMgr: ConnectionManager) {\n return {\n onOpen(_event: Event, ws: WSContext) {\n connMgr.add(ws);\n },\n\n onMessage(event: MessageEvent, ws: WSContext) {\n const reply = handleWsMessage(String(event.data), ws, connMgr);\n if (reply) ws.send(reply);\n },\n\n onClose(_event: CloseEvent, ws: WSContext) {\n connMgr.remove(ws);\n },\n\n onError(_event: Event, ws: WSContext) {\n connMgr.remove(ws);\n },\n };\n}\n","import type { CostData } from './types.js';\nimport type { ConnectionManager } from './ws/connection-manager.js';\n\n/**\n * Accumulates cost data from trace events.\n * Broadcasts updates to the 'costs' WS channel.\n */\nexport class CostAggregator {\n private data: CostData = {\n totalCost: 0,\n totalTokens: { input: 0, output: 0, reasoning: 0 },\n byAgent: {},\n byModel: {},\n byWorkflow: {},\n };\n\n constructor(private connMgr: ConnectionManager) {}\n\n /** Process a trace event and update cost data. */\n onTrace(event: {\n type?: string;\n agent?: string;\n model?: string;\n workflow?: string;\n cost?: number;\n tokens?: { input?: number; output?: number; reasoning?: number };\n }): void {\n if (event.cost == null && !event.tokens) return;\n\n const cost = Number.isFinite(event.cost) ? event.cost! : 0;\n const tokens = event.tokens ?? {};\n\n this.data.totalCost += cost;\n this.data.totalTokens.input += tokens.input ?? 0;\n this.data.totalTokens.output += tokens.output ?? 0;\n this.data.totalTokens.reasoning += tokens.reasoning ?? 0;\n\n if (event.agent) {\n const entry = this.data.byAgent[event.agent] ?? { cost: 0, calls: 0 };\n entry.cost += cost;\n entry.calls += 1;\n this.data.byAgent[event.agent] = entry;\n }\n\n if (event.model) {\n const entry = this.data.byModel[event.model] ?? {\n cost: 0,\n calls: 0,\n tokens: { input: 0, output: 0 },\n };\n entry.cost += cost;\n entry.calls += 1;\n entry.tokens.input += tokens.input ?? 0;\n entry.tokens.output += tokens.output ?? 0;\n this.data.byModel[event.model] = entry;\n }\n\n if (event.workflow) {\n const entry = this.data.byWorkflow[event.workflow] ?? { cost: 0, executions: 0 };\n entry.cost += cost;\n if (event.type === 'workflow_start') entry.executions += 1;\n this.data.byWorkflow[event.workflow] = entry;\n }\n\n // Broadcast to WS subscribers\n this.connMgr.broadcast('costs', this.data);\n }\n\n /** Get current aggregated cost data. */\n getData(): CostData {\n return this.data;\n }\n\n /** Reset all accumulated data. */\n reset(): void {\n this.data = {\n totalCost: 0,\n totalTokens: { input: 0, output: 0, reasoning: 0 },\n byAgent: {},\n byModel: {},\n byWorkflow: {},\n };\n }\n}\n","import { Hono } from 'hono';\nimport type { StudioEnv } from '../types.js';\n\nconst app = new Hono<StudioEnv>();\n\napp.get('/health', (c) => {\n const runtime = c.get('runtime');\n return c.json({\n ok: true,\n data: {\n status: 'healthy',\n workflows: runtime.getWorkflowNames().length,\n agents: runtime.getAgents().length,\n tools: runtime.getTools().length,\n },\n });\n});\n\nexport default app;\n","import { Hono } from 'hono';\nimport { zodToJsonSchema } from '@axlsdk/axl';\nimport type { StudioEnv, WorkflowSummary } from '../types.js';\nimport type { ConnectionManager } from '../ws/connection-manager.js';\n\nexport function createWorkflowRoutes(connMgr: ConnectionManager) {\n const app = new Hono<StudioEnv>();\n\n // List all workflows\n app.get('/workflows', (c) => {\n const runtime = c.get('runtime');\n const workflows: WorkflowSummary[] = runtime.getWorkflows().map((w) => ({\n name: w.name,\n hasInputSchema: !!w.inputSchema,\n hasOutputSchema: !!w.outputSchema,\n }));\n return c.json({ ok: true, data: workflows });\n });\n\n // Get workflow detail (including schemas)\n app.get('/workflows/:name', (c) => {\n const runtime = c.get('runtime');\n const name = c.req.param('name');\n const workflow = runtime.getWorkflow(name);\n if (!workflow) {\n return c.json(\n { ok: false, error: { code: 'NOT_FOUND', message: `Workflow \"${name}\" not found` } },\n 404,\n );\n }\n\n return c.json({\n ok: true,\n data: {\n name: workflow.name,\n inputSchema: workflow.inputSchema ? zodToJsonSchema(workflow.inputSchema) : null,\n outputSchema: workflow.outputSchema ? zodToJsonSchema(workflow.outputSchema) : null,\n },\n });\n });\n\n // Execute a workflow\n app.post('/workflows/:name/execute', async (c) => {\n const runtime = c.get('runtime');\n const name = c.req.param('name');\n\n const workflow = runtime.getWorkflow(name);\n if (!workflow) {\n return c.json(\n { ok: false, error: { code: 'NOT_FOUND', message: `Workflow \"${name}\" not found` } },\n 404,\n );\n }\n\n const body = await c.req.json<{\n input?: unknown;\n stream?: boolean;\n metadata?: Record<string, unknown>;\n }>();\n\n if (body.stream) {\n // Streaming execution — pipe events to WS channel\n const stream = runtime.stream(name, body.input ?? {}, { metadata: body.metadata });\n const executionId = `stream-${Date.now()}`;\n\n // Forward stream events to WS (error events flow through the iterator)\n (async () => {\n for await (const event of stream) {\n connMgr.broadcastWithWildcard(`execution:${executionId}`, event);\n }\n })();\n\n return c.json({ ok: true, data: { executionId, streaming: true } });\n }\n\n const result = await runtime.execute(name, body.input ?? {}, { metadata: body.metadata });\n return c.json({ ok: true, data: { result } });\n });\n\n return app;\n}\n","import { Hono } from 'hono';\nimport type { StudioEnv } from '../types.js';\n\nconst app = new Hono<StudioEnv>();\n\n// List all executions\napp.get('/executions', async (c) => {\n const runtime = c.get('runtime');\n const executions = await runtime.getExecutions();\n return c.json({ ok: true, data: executions });\n});\n\n// Get execution by ID\napp.get('/executions/:id', async (c) => {\n const runtime = c.get('runtime');\n const id = c.req.param('id');\n const execution = await runtime.getExecution(id);\n if (!execution) {\n return c.json(\n { ok: false, error: { code: 'NOT_FOUND', message: `Execution \"${id}\" not found` } },\n 404,\n );\n }\n return c.json({ ok: true, data: execution });\n});\n\n// Abort a running execution\napp.post('/executions/:id/abort', (c) => {\n const runtime = c.get('runtime');\n const id = c.req.param('id');\n runtime.abort(id);\n return c.json({ ok: true, data: { aborted: true } });\n});\n\nexport default app;\n","import { Hono } from 'hono';\nimport type { StudioEnv, SessionSummary } from '../types.js';\nimport type { ConnectionManager } from '../ws/connection-manager.js';\n\nexport function createSessionRoutes(connMgr: ConnectionManager) {\n const app = new Hono<StudioEnv>();\n\n // List all sessions\n app.get('/sessions', async (c) => {\n const runtime = c.get('runtime');\n const store = runtime.getStateStore();\n if (!store.listSessions) {\n return c.json({ ok: true, data: [] });\n }\n const ids = await store.listSessions();\n const sessions: SessionSummary[] = [];\n for (const id of ids) {\n const history = await store.getSession(id);\n sessions.push({ id, messageCount: history.length });\n }\n return c.json({ ok: true, data: sessions });\n });\n\n // Get session history\n app.get('/sessions/:id', async (c) => {\n const runtime = c.get('runtime');\n const store = runtime.getStateStore();\n const id = c.req.param('id');\n const history = await store.getSession(id);\n const handoffHistory = await store.getSessionMeta(id, 'handoffHistory');\n return c.json({ ok: true, data: { id, history, handoffHistory: handoffHistory ?? [] } });\n });\n\n // Send message to session (non-streaming)\n app.post('/sessions/:id/send', async (c) => {\n const runtime = c.get('runtime');\n const id = c.req.param('id');\n const body = await c.req.json<{ message: string; workflow: string }>();\n\n const session = runtime.session(id);\n const result = await session.send(body.workflow, body.message);\n return c.json({ ok: true, data: { result } });\n });\n\n // Stream session message\n app.post('/sessions/:id/stream', async (c) => {\n const runtime = c.get('runtime');\n const id = c.req.param('id');\n const body = await c.req.json<{ message: string; workflow: string }>();\n\n const session = runtime.session(id);\n const stream = await session.stream(body.workflow, body.message);\n const executionId = `session-${id}-${Date.now()}`;\n\n // Forward stream events to WS (error events flow through the iterator)\n (async () => {\n for await (const event of stream) {\n connMgr.broadcastWithWildcard(`execution:${executionId}`, event);\n }\n })();\n\n return c.json({ ok: true, data: { executionId, streaming: true } });\n });\n\n // Delete session\n app.delete('/sessions/:id', async (c) => {\n const runtime = c.get('runtime');\n const store = runtime.getStateStore();\n const id = c.req.param('id');\n await store.deleteSession(id);\n return c.json({ ok: true, data: { deleted: true } });\n });\n\n return app;\n}\n","import { Hono } from 'hono';\nimport { zodToJsonSchema } from '@axlsdk/axl';\nimport type { StudioEnv, AgentSummary } from '../types.js';\n\nconst app = new Hono<StudioEnv>();\n\n// List all agents\napp.get('/agents', (c) => {\n const runtime = c.get('runtime');\n const agents: AgentSummary[] = runtime.getAgents().map((a) => ({\n name: a._name,\n model: a.resolveModel(),\n system: a.resolveSystem(),\n tools: a._config.tools?.map((t) => t.name) ?? [],\n handoffs:\n typeof a._config.handoffs === 'function'\n ? ['(dynamic)']\n : (a._config.handoffs?.map((h) => h.agent._name) ?? []),\n maxTurns: a._config.maxTurns,\n temperature: a._config.temperature,\n maxTokens: a._config.maxTokens,\n effort: a._config.effort,\n thinkingBudget: a._config.thinkingBudget,\n includeThoughts: a._config.includeThoughts,\n toolChoice: a._config.toolChoice,\n stop: a._config.stop,\n }));\n return c.json({ ok: true, data: agents });\n});\n\n// Get agent detail\napp.get('/agents/:name', (c) => {\n const runtime = c.get('runtime');\n const name = c.req.param('name');\n const agent = runtime.getAgent(name);\n if (!agent) {\n return c.json(\n { ok: false, error: { code: 'NOT_FOUND', message: `Agent \"${name}\" not found` } },\n 404,\n );\n }\n\n const cfg = agent._config;\n return c.json({\n ok: true,\n data: {\n name: agent._name,\n model: agent.resolveModel(),\n system: agent.resolveSystem(),\n tools:\n cfg.tools?.map((t) => ({\n name: t.name,\n description: t.description,\n inputSchema: zodToJsonSchema(t.inputSchema),\n })) ?? [],\n handoffs:\n typeof cfg.handoffs === 'function'\n ? [\n {\n agent: '(dynamic)',\n description: 'Resolved at runtime from metadata',\n mode: 'oneway' as const,\n },\n ]\n : (cfg.handoffs?.map((h) => ({\n agent: h.agent._name,\n description: h.description,\n mode: h.mode ?? 'oneway',\n })) ?? []),\n maxTurns: cfg.maxTurns,\n temperature: cfg.temperature,\n maxTokens: cfg.maxTokens,\n effort: cfg.effort,\n thinkingBudget: cfg.thinkingBudget,\n includeThoughts: cfg.includeThoughts,\n toolChoice: cfg.toolChoice,\n stop: cfg.stop,\n timeout: cfg.timeout,\n maxContext: cfg.maxContext,\n version: cfg.version,\n mcp: cfg.mcp,\n mcpTools: cfg.mcpTools,\n hasGuardrails: !!cfg.guardrails,\n guardrails: cfg.guardrails\n ? {\n hasInput: !!cfg.guardrails.input,\n hasOutput: !!cfg.guardrails.output,\n onBlock: cfg.guardrails.onBlock ?? 'throw',\n maxRetries: cfg.guardrails.maxRetries,\n }\n : null,\n },\n });\n});\n\nexport default app;\n","import { Hono } from 'hono';\nimport { zodToJsonSchema } from '@axlsdk/axl';\nimport type { StudioEnv, ToolSummary } from '../types.js';\n\nconst app = new Hono<StudioEnv>();\n\n// List all tools\napp.get('/tools', (c) => {\n const runtime = c.get('runtime');\n const tools: ToolSummary[] = runtime.getTools().map((t) => ({\n name: t.name,\n description: t.description,\n inputSchema: t.inputSchema ? zodToJsonSchema(t.inputSchema) : {},\n sensitive: t.sensitive ?? false,\n requireApproval: t.requireApproval ?? false,\n }));\n return c.json({ ok: true, data: tools });\n});\n\n// Get tool detail\napp.get('/tools/:name', (c) => {\n const runtime = c.get('runtime');\n const name = c.req.param('name');\n const tool = runtime.getTool(name);\n if (!tool) {\n return c.json(\n { ok: false, error: { code: 'NOT_FOUND', message: `Tool \"${name}\" not found` } },\n 404,\n );\n }\n\n return c.json({\n ok: true,\n data: {\n name: tool.name,\n description: tool.description,\n inputSchema: tool.inputSchema ? zodToJsonSchema(tool.inputSchema) : {},\n sensitive: tool.sensitive,\n requireApproval: tool.requireApproval,\n retry: tool.retry,\n hasHooks: !!tool.hooks,\n hooks: tool.hooks\n ? {\n hasBefore: !!tool.hooks.before,\n hasAfter: !!tool.hooks.after,\n }\n : null,\n },\n });\n});\n\n// Test a tool directly\napp.post('/tools/:name/test', async (c) => {\n const runtime = c.get('runtime');\n const name = c.req.param('name');\n const tool = runtime.getTool(name);\n if (!tool) {\n return c.json(\n { ok: false, error: { code: 'NOT_FOUND', message: `Tool \"${name}\" not found` } },\n 404,\n );\n }\n\n const body = await c.req.json<{ input: unknown }>();\n const ctx = runtime.createContext();\n const result = await tool.run(ctx, body.input);\n return c.json({ ok: true, data: { result } });\n});\n\nexport default app;\n","import { Hono } from 'hono';\nimport type { StudioEnv } from '../types.js';\n\nconst app = new Hono<StudioEnv>();\n\n// Get all memory entries for a scope\napp.get('/memory/:scope', async (c) => {\n const runtime = c.get('runtime');\n const store = runtime.getStateStore();\n const scope = c.req.param('scope');\n\n if (!store.getAllMemory) {\n return c.json({ ok: true, data: [] });\n }\n\n const entries = await store.getAllMemory(scope);\n return c.json({ ok: true, data: entries });\n});\n\n// Get a specific memory entry\napp.get('/memory/:scope/:key', async (c) => {\n const runtime = c.get('runtime');\n const store = runtime.getStateStore();\n const scope = c.req.param('scope');\n const key = c.req.param('key');\n\n if (!store.getMemory) {\n return c.json(\n { ok: false, error: { code: 'NOT_SUPPORTED', message: 'Memory not supported' } },\n 501,\n );\n }\n\n const value = await store.getMemory(scope, key);\n if (value === null) {\n return c.json(\n { ok: false, error: { code: 'NOT_FOUND', message: `Memory \"${scope}/${key}\" not found` } },\n 404,\n );\n }\n\n return c.json({ ok: true, data: { key, value } });\n});\n\n// Save a memory entry\napp.put('/memory/:scope/:key', async (c) => {\n const runtime = c.get('runtime');\n const store = runtime.getStateStore();\n const scope = c.req.param('scope');\n const key = c.req.param('key');\n\n if (!store.saveMemory) {\n return c.json(\n { ok: false, error: { code: 'NOT_SUPPORTED', message: 'Memory not supported' } },\n 501,\n );\n }\n\n const body = await c.req.json<{ value: unknown }>();\n await store.saveMemory(scope, key, body.value);\n return c.json({ ok: true, data: { saved: true } });\n});\n\n// Delete a memory entry\napp.delete('/memory/:scope/:key', async (c) => {\n const runtime = c.get('runtime');\n const store = runtime.getStateStore();\n const scope = c.req.param('scope');\n const key = c.req.param('key');\n\n if (!store.deleteMemory) {\n return c.json(\n { ok: false, error: { code: 'NOT_SUPPORTED', message: 'Memory not supported' } },\n 501,\n );\n }\n\n await store.deleteMemory(scope, key);\n return c.json({ ok: true, data: { deleted: true } });\n});\n\n// Semantic search\napp.post('/memory/search', async (c) => {\n // TODO: Connect to MemoryManager's vector search once exposed\n return c.json({\n ok: true,\n data: { results: [], message: 'Semantic search requires MemoryManager with vector store' },\n });\n});\n\nexport default app;\n","import { Hono } from 'hono';\nimport type { StudioEnv } from '../types.js';\n\nconst app = new Hono<StudioEnv>();\n\n// List pending decisions\napp.get('/decisions', async (c) => {\n const runtime = c.get('runtime');\n const decisions = await runtime.getPendingDecisions();\n return c.json({ ok: true, data: decisions });\n});\n\n// Resolve a pending decision\napp.post('/decisions/:executionId/resolve', async (c) => {\n const runtime = c.get('runtime');\n const executionId = c.req.param('executionId');\n const body = await c.req.json<{ approved: boolean; reason?: string }>();\n\n await runtime.resolveDecision(executionId, body);\n return c.json({ ok: true, data: { resolved: true } });\n});\n\nexport default app;\n","import { Hono } from 'hono';\nimport type { StudioEnv } from '../types.js';\nimport type { CostAggregator } from '../cost-aggregator.js';\n\nexport function createCostRoutes(costAggregator: CostAggregator) {\n const app = new Hono<StudioEnv>();\n\n app.get('/costs', (c) => {\n return c.json({ ok: true, data: costAggregator.getData() });\n });\n\n app.post('/costs/reset', (c) => {\n costAggregator.reset();\n return c.json({ ok: true, data: { reset: true } });\n });\n\n return app;\n}\n","import { Hono } from 'hono';\nimport type { StudioEnv } from '../types.js';\nimport type { EvalResult, Scorer } from '@axlsdk/eval';\n\nexport function createEvalRoutes(evalLoader?: () => Promise<void>) {\n const app = new Hono<StudioEnv>();\n\n // List registered eval configs\n app.get('/evals', async (c) => {\n if (evalLoader) await evalLoader();\n const runtime = c.get('runtime');\n const evals = runtime.getRegisteredEvals();\n return c.json({ ok: true, data: evals });\n });\n\n // Get eval run history\n app.get('/evals/history', async (c) => {\n const runtime = c.get('runtime');\n const history = await runtime.getEvalHistory();\n return c.json({ ok: true, data: history });\n });\n\n // Run a registered eval by name (supports optional multi-run via { runs: N })\n app.post('/evals/:name/run', async (c) => {\n if (evalLoader) await evalLoader();\n const runtime = c.get('runtime');\n const name = c.req.param('name');\n\n const entry = runtime.getRegisteredEval(name);\n if (!entry) {\n return c.json(\n { ok: false, error: { code: 'NOT_FOUND', message: `Eval \"${name}\" not found` } },\n 404,\n );\n }\n\n let runs = 1;\n try {\n const body = (await c.req.json().catch(() => ({}))) as Record<string, unknown>;\n if (typeof body.runs === 'number' && Number.isFinite(body.runs) && body.runs > 1) {\n runs = Math.min(Math.floor(body.runs), 25);\n }\n } catch {\n // No body or invalid body — single run\n }\n\n try {\n if (runs > 1) {\n const { randomUUID } = await import('node:crypto');\n const { aggregateRuns } = await import('@axlsdk/eval');\n const runGroupId = randomUUID();\n const results = [];\n for (let r = 0; r < runs; r++) {\n const result = await runtime.runRegisteredEval(name, {\n metadata: { runGroupId, runIndex: r },\n });\n results.push(result);\n }\n const typedResults = results as EvalResult[];\n const aggregate = aggregateRuns(typedResults);\n const first = typedResults[0]!;\n const result = { ...first, _multiRun: { aggregate, allRuns: typedResults } };\n return c.json({ ok: true, data: result });\n } else {\n // Runtime persists eval result to history automatically\n const result = await runtime.runRegisteredEval(name);\n return c.json({ ok: true, data: result });\n }\n } catch (err) {\n const message = err instanceof Error ? err.message : String(err);\n return c.json({ ok: false, error: { code: 'EVAL_ERROR', message } }, 400);\n }\n });\n\n // Rescore: re-run scorers on saved outputs\n app.post('/evals/:name/rescore', async (c) => {\n if (evalLoader) await evalLoader();\n const runtime = c.get('runtime');\n const name = c.req.param('name');\n const body = await c.req.json<{ resultId: string }>();\n\n if (!body.resultId || typeof body.resultId !== 'string') {\n return c.json(\n { ok: false, error: { code: 'BAD_REQUEST', message: 'resultId is required' } },\n 400,\n );\n }\n\n const entry = runtime.getRegisteredEval(name);\n if (!entry) {\n return c.json(\n { ok: false, error: { code: 'NOT_FOUND', message: `Eval \"${name}\" not found` } },\n 404,\n );\n }\n\n const history = await runtime.getEvalHistory();\n const historyEntry = history.find((h) => h.id === body.resultId);\n if (!historyEntry) {\n return c.json(\n { ok: false, error: { code: 'NOT_FOUND', message: `Result \"${body.resultId}\" not found` } },\n 404,\n );\n }\n\n try {\n const { rescore } = await import('@axlsdk/eval');\n const config = entry.config as { scorers?: unknown[] };\n const result = await rescore(\n historyEntry.data as EvalResult,\n config.scorers as Scorer[],\n runtime,\n );\n await runtime.saveEvalResult({\n id: result.id,\n eval: name,\n timestamp: Date.now(),\n data: result,\n });\n return c.json({ ok: true, data: result });\n } catch (err) {\n const message = err instanceof Error ? err.message : String(err);\n return c.json({ ok: false, error: { code: 'EVAL_ERROR', message } }, 400);\n }\n });\n\n // Compare eval results\n app.post('/evals/compare', async (c) => {\n const runtime = c.get('runtime');\n const body = await c.req.json<{\n baseline: unknown;\n candidate: unknown;\n options?: { thresholds?: Record<string, number> | number };\n }>();\n\n try {\n const result = await runtime.evalCompare(body.baseline, body.candidate, body.options);\n return c.json({ ok: true, data: result });\n } catch (err) {\n const message = err instanceof Error ? err.message : String(err);\n return c.json({ ok: false, error: { code: 'EVAL_ERROR', message } }, 400);\n }\n });\n\n return app;\n}\n","import { Hono } from 'hono';\nimport type { StudioEnv } from '../types.js';\nimport type { ConnectionManager } from '../ws/connection-manager.js';\n\nexport function createPlaygroundRoutes(connMgr: ConnectionManager) {\n const app = new Hono<StudioEnv>();\n\n // Chat with an agent directly — no workflow required\n app.post('/playground/chat', async (c) => {\n const runtime = c.get('runtime');\n const body = await c.req.json<{\n sessionId?: string;\n message: string;\n agent?: string;\n }>();\n\n if (!body.message || typeof body.message !== 'string' || !body.message.trim()) {\n return c.json(\n {\n ok: false,\n error: {\n code: 'INVALID_INPUT',\n message: 'message is required and must be a non-empty string',\n },\n },\n 400,\n );\n }\n\n const agents = runtime.getAgents();\n const agent = body.agent ? agents.find((a) => a._name === body.agent) : agents[0];\n if (!agent) {\n return c.json(\n {\n ok: false,\n error: { code: 'NO_AGENT', message: `Agent \"${body.agent ?? ''}\" not found` },\n },\n 400,\n );\n }\n\n const sessionId = body.sessionId ?? `playground-${Date.now()}`;\n const executionId = `playground-${sessionId}-${Date.now()}`;\n const store = runtime.getStateStore();\n\n // Load session history for multi-turn conversations\n const history = await store.getSession(sessionId);\n history.push({ role: 'user', content: body.message });\n\n // Create a context wired to stream events to the WS channel\n const ctx = runtime.createContext({\n sessionHistory: history,\n onToken: (token: string) => {\n connMgr.broadcastWithWildcard(`execution:${executionId}`, {\n type: 'token',\n data: token,\n });\n },\n });\n\n // Run the agent ask asynchronously, stream results via WS\n (async () => {\n try {\n const result = await ctx.ask(agent, body.message);\n const resultText = typeof result === 'string' ? result : JSON.stringify(result);\n\n // Save assistant response to session history\n history.push({ role: 'assistant', content: resultText });\n await store.saveSession(sessionId, history);\n\n connMgr.broadcastWithWildcard(`execution:${executionId}`, {\n type: 'done',\n data: resultText,\n });\n } catch (err) {\n connMgr.broadcastWithWildcard(`execution:${executionId}`, {\n type: 'error',\n message: err instanceof Error ? err.message : String(err),\n });\n }\n })();\n\n return c.json({\n ok: true,\n data: { sessionId, executionId, streaming: true },\n });\n });\n\n return app;\n}\n","import { resolve, relative, dirname, basename } from 'node:path';\nimport { readdirSync, statSync } from 'node:fs';\nimport { pathToFileURL } from 'node:url';\nimport type { AxlRuntime } from '@axlsdk/axl';\nimport { importModule } from './cli-utils.js';\n\n// In the CJS bundle, tsup stubs import.meta as {} so import.meta.url is\n// undefined. Fall back to __filename (which CJS defines) converted to a\n// file:// URL so tsImport() gets a valid parentURL.\nconst parentURL: string =\n import.meta.url ?? pathToFileURL(typeof __filename !== 'undefined' ? __filename : __dirname).href;\n\n/**\n * Configuration for lazy eval file discovery.\n *\n * - `string` — a glob pattern or explicit file path\n * - `string[]` — multiple patterns/paths\n * - `object` — patterns with optional import conditions\n */\nexport type EvalLoaderConfig =\n | string\n | string[]\n | {\n files: string | string[];\n\n /**\n * Custom Node.js import conditions (e.g., `['development']`).\n *\n * In monorepos, package.json `exports` often use the `development` condition\n * to point at source (`.ts`) instead of built dist. Without this, eval files\n * that import workspace packages resolve to dist files, which may not exist.\n *\n * **WARNING**: Conditions are registered process-wide via `module.register()`.\n * They affect all subsequent imports in the process, not just eval files.\n */\n conditions?: string[];\n };\n\n/**\n * Create a lazy eval loader that resolves file patterns and dynamically imports\n * eval files on first call, registering them with the runtime.\n *\n * The loader is idempotent — subsequent calls return the same promise.\n * Concurrent callers all await the same loading work.\n *\n * Eval files should export a default config with `{ workflow, dataset, scorers }`\n * (the result of `defineEval()` from `@axlsdk/eval`). An optional named export\n * `executeWorkflow` overrides the default `runtime.execute()` behavior.\n *\n * Eval names are the file's path relative to `cwd` (project root), minus the\n * `.eval.*` suffix. This makes names completely stable — a file's name never\n * changes regardless of what other files or patterns exist.\n *\n * @param config Glob patterns, file paths, or object with conditions\n * @param runtime The AxlRuntime to register discovered evals on\n * @param cwd Base directory for resolving patterns and deriving names (default: `process.cwd()`)\n */\nexport function createEvalLoader(\n config: EvalLoaderConfig,\n runtime: AxlRuntime,\n cwd?: string,\n): () => Promise<void> {\n let loadPromise: Promise<void> | undefined;\n const { patterns, conditions } = normalizeConfig(config);\n const baseCwd = cwd ?? process.cwd();\n\n return () => {\n if (!loadPromise) {\n loadPromise = loadEvalFiles(patterns, conditions, baseCwd, runtime).catch((err) => {\n loadPromise = undefined; // Allow retry on next request\n throw err;\n });\n }\n return loadPromise;\n };\n}\n\n// ── Core loading logic ─────────────────────────────────────────────\n\nasync function loadEvalFiles(\n patterns: string[],\n conditions: string[],\n cwd: string,\n runtime: AxlRuntime,\n): Promise<void> {\n if (conditions.length > 0) {\n await registerConditions(conditions);\n }\n\n const files = resolvePatterns(patterns, cwd);\n\n if (files.length === 0) {\n console.warn(`[axl-studio] No eval files found matching: ${patterns.join(', ')}`);\n return;\n }\n\n for (const file of files) {\n try {\n const mod = await importModule(file, parentURL);\n const evalConfig = mod.default?.default ?? mod.default ?? mod.config ?? mod;\n\n if (!evalConfig.workflow || !evalConfig.dataset || !evalConfig.scorers) {\n console.warn(\n `[axl-studio] Skipping ${file}: not a valid eval config ` +\n `(missing workflow, dataset, or scorers)`,\n );\n continue;\n }\n\n const name = deriveEvalName(file, cwd);\n\n if (runtime.getRegisteredEval(name)) {\n console.warn(\n `[axl-studio] Eval name \"${name}\" from ${file} collides with an ` +\n `already-registered eval — overwriting`,\n );\n }\n\n runtime.registerEval(name, evalConfig, mod.executeWorkflow);\n } catch (err) {\n const msg = err instanceof Error ? err.message : String(err);\n console.warn(`[axl-studio] Failed to load eval ${file}: ${msg}`);\n }\n }\n}\n\n// ── Internal helpers ───────────────────────────────────────────────\n\nfunction normalizeConfig(config: EvalLoaderConfig): {\n patterns: string[];\n conditions: string[];\n} {\n if (typeof config === 'string') {\n return { patterns: [config], conditions: [] };\n }\n if (Array.isArray(config)) {\n return { patterns: config, conditions: [] };\n }\n const files = typeof config.files === 'string' ? [config.files] : config.files;\n return { patterns: files, conditions: config.conditions ?? [] };\n}\n\n/**\n * Derive eval name from file path relative to cwd.\n *\n * Examples (cwd = `/project`):\n * - `/project/evals/suggestions.eval.ts` → `\"evals/suggestions\"`\n * - `/project/evals/api/accuracy.eval.ts` → `\"evals/api/accuracy\"`\n */\nfunction deriveEvalName(filePath: string, cwd: string): string {\n const rel = relative(cwd, filePath);\n // Normalize to forward slashes for cross-platform consistency\n const normalized = rel.replace(/\\\\/g, '/');\n // Guard: file outside cwd (symlink, absolute path) — fall back to basename\n if (normalized.startsWith('../')) {\n const base = basename(filePath);\n const stripped = base.replace(/\\.eval\\.[mc]?[jt]sx?$/, '');\n return stripped !== base ? stripped : base.replace(/\\.[mc]?[jt]sx?$/, '') || base;\n }\n // Strip .eval.ts, .eval.mjs, .eval.js, etc.\n const withoutEval = normalized.replace(/\\.eval\\.[mc]?[jt]sx?$/, '');\n if (withoutEval !== normalized) return withoutEval;\n // Fallback: strip extension\n const withoutExt = normalized.replace(/\\.[mc]?[jt]sx?$/, '');\n return withoutExt || normalized;\n}\n\n/**\n * Resolve patterns to absolute file paths.\n *\n * Supports:\n * - Explicit file paths (no wildcards)\n * - Single-directory globs: `dir/*.eval.ts`\n * - Recursive globs: `dir/**\\/*.eval.ts` or `**\\/*.eval.ts`\n *\n * Multi-segment `**` (e.g., `a/**\\/b/**\\/*.ts`) is not supported.\n */\nfunction resolvePatterns(patterns: string[], cwd: string): string[] {\n const files: string[] = [];\n const seen = new Set<string>();\n for (const pattern of patterns) {\n const resolved = pattern.includes('*') ? expandGlob(pattern, cwd) : [resolve(cwd, pattern)];\n for (const file of resolved) {\n if (!seen.has(file)) {\n seen.add(file);\n files.push(file);\n }\n }\n }\n return files;\n}\n\n/**\n * Expand a glob pattern to matching file paths.\n *\n * Supported forms:\n * - `dir/*.eval.ts` — match files in dir/\n * - `dir/**\\/*.eval.ts` — recursively match under dir/\n * - `**\\/*.eval.ts` — recursively match under cwd\n */\nfunction expandGlob(pattern: string, cwd: string): string[] {\n if (pattern.includes('**/')) {\n const sepIdx = pattern.indexOf('**/');\n const baseDir = resolve(cwd, pattern.slice(0, sepIdx) || '.');\n const fileGlob = pattern.slice(sepIdx + 3) || '*';\n return findFiles(baseDir, fileGlob, true);\n }\n\n const dir = resolve(cwd, dirname(pattern));\n const fileGlob = basename(pattern);\n return findFiles(dir, fileGlob, false);\n}\n\nconst MAX_DEPTH = 20;\n\nfunction findFiles(dir: string, fileGlob: string, recursive: boolean, depth = 0): string[] {\n if (depth > MAX_DEPTH) return [];\n const matcher = globToRegex(fileGlob);\n const results: string[] = [];\n\n try {\n const entries = readdirSync(dir);\n for (const entry of entries) {\n const full = resolve(dir, entry);\n try {\n const stat = statSync(full);\n if (stat.isFile() && matcher.test(entry)) {\n results.push(full);\n } else if (stat.isDirectory() && recursive) {\n results.push(...findFiles(full, fileGlob, true, depth + 1));\n }\n } catch {\n // Skip unreadable entries\n }\n }\n } catch {\n // Directory doesn't exist or unreadable\n }\n\n return results;\n}\n\n/** Convert a simple glob pattern (e.g., `*.eval.ts`) to a RegExp. */\nfunction globToRegex(glob: string): RegExp {\n const escaped = glob.replace(/[.+?^${}()|[\\]\\\\]/g, '\\\\$&').replace(/\\*/g, '.*');\n return new RegExp(`^${escaped}$`);\n}\n\nasync function registerConditions(conditions: string[]): Promise<void> {\n try {\n const nodeModule = await import('node:module');\n const hookCode = [\n `const extra = ${JSON.stringify(conditions)};`,\n `export async function resolve(specifier, context, nextResolve) {`,\n ` return nextResolve(specifier, {`,\n ` ...context,`,\n ` conditions: [...new Set([...context.conditions, ...extra])],`,\n ` });`,\n `}`,\n ].join('\\n');\n nodeModule.register(`data:text/javascript,${encodeURIComponent(hookCode)}`);\n } catch {\n console.warn('[axl-studio] Warning: import conditions require Node.js 20.6+');\n }\n}\n","import { resolve } from 'node:path';\nimport { existsSync } from 'node:fs';\nimport { pathToFileURL } from 'node:url';\n\n// ── Config auto-detection ──────────────────────────────────────────\n\nexport const CONFIG_CANDIDATES = [\n 'axl.config.mts',\n 'axl.config.ts',\n 'axl.config.mjs',\n 'axl.config.js',\n];\n\nexport function findConfig(cwd: string): string | undefined {\n for (const name of CONFIG_CANDIDATES) {\n const p = resolve(cwd, name);\n if (existsSync(p)) return p;\n }\n return undefined;\n}\n\n// ── Parse CLI args ──────────────────────────────────────────────────\n\nexport interface CliArgs {\n port: number;\n config?: string;\n open: boolean;\n conditions: string[];\n help: boolean;\n portError?: string;\n}\n\nexport function parseArgs(argv: string[]): CliArgs {\n let port = 4400;\n let config: string | undefined;\n let open = false;\n let help = false;\n let conditions: string[] = [];\n\n for (let i = 2; i < argv.length; i++) {\n const arg = argv[i];\n if (arg === '--port' && argv[i + 1]) {\n port = parseInt(argv[i + 1], 10);\n i++;\n } else if (arg === '--config' && argv[i + 1]) {\n config = argv[i + 1];\n i++;\n } else if (arg === '--conditions' && argv[i + 1]) {\n conditions = argv[i + 1]\n .split(',')\n .map((c) => c.trim())\n .filter(Boolean);\n i++;\n } else if (arg === '--open') {\n open = true;\n } else if (arg === '--help' || arg === '-h') {\n help = true;\n }\n }\n\n const result: CliArgs = { port, config, open, help, conditions };\n\n if (isNaN(port) || port < 1 || port > 65535) {\n result.portError = `Invalid port: ${port}. Must be between 1 and 65535.`;\n }\n\n return result;\n}\n\n// ── Extension helpers ──────────────────────────────────────────────\n\n/**\n * Returns true if the file is TypeScript and needs tsx to load.\n */\nexport function needsTsxLoader(configPath: string): boolean {\n return /\\.[mc]?tsx?$/.test(configPath);\n}\n\n// ── Module loading ────────────────────────────────────────────────\n\n// Lazily resolved tsImport function from tsx. `undefined` = not yet checked,\n// `null` = tsx not available.\nlet tsImportFn:\n | ((specifier: string, parentURL: string) => Promise<Record<string, any>>)\n | null\n | undefined;\n\n/**\n * Import a module, using tsx's `tsImport()` for TypeScript files.\n *\n * `tsImport()` handles ESM/CJS format correctly without process-wide side effects —\n * no need for `register()` hooks or ESM-forcing workarounds. Falls back to regular\n * `import()` for non-TypeScript files or when tsx is not installed.\n */\nexport async function importModule(\n filePath: string,\n parentURL: string,\n): Promise<Record<string, any>> {\n if (needsTsxLoader(filePath)) {\n if (tsImportFn === undefined) {\n try {\n const mod = await import('tsx/esm/api');\n tsImportFn = mod.tsImport ?? null;\n } catch {\n tsImportFn = null;\n console.warn(\n '[axl-studio] Warning: tsx is not installed. TypeScript config files require tsx as a dependency.\\n' +\n ' Install it with: npm install -D tsx',\n );\n }\n }\n if (tsImportFn) {\n return (await tsImportFn(pathToFileURL(filePath).href, parentURL)) as Record<string, any>;\n }\n }\n return await import(pathToFileURL(filePath).href);\n}\n"],"mappings":"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","names":["import_node_path","import_node_fs","import_node_url","import_hono","import_hono","app","import_hono","app","import_hono","app","import_hono","import_axl","app","import_hono","import_axl","app","import_hono","app","import_hono","app","import_hono","app","import_hono","app","result","import_hono","app","app","import_node_path","import_node_fs","import_node_url","import_node_path","import_node_fs","parentURL","fileGlob","import_meta","app"]}
@@ -198,6 +198,13 @@ function createStudioMiddleware(options) {
198
198
  );
199
199
  return;
200
200
  }
201
+ const reqAny = req;
202
+ if (reqAny.body != null && !reqAny.rawBody) {
203
+ try {
204
+ reqAny.rawBody = Buffer.from(JSON.stringify(reqAny.body));
205
+ } catch {
206
+ }
207
+ }
201
208
  listener(req, res).catch((err) => {
202
209
  console.error("[axl-studio] Unhandled error in request handler:", err);
203
210
  if (!res.headersSent) {
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/middleware.ts","../src/eval-loader.ts"],"sourcesContent":["import { resolve, dirname } from 'node:path';\nimport { existsSync } from 'node:fs';\nimport { fileURLToPath } from 'node:url';\nimport { getRequestListener } from '@hono/node-server';\nimport { WebSocketServer } from 'ws';\nimport { createServer } from './server/index.js';\nimport { handleWsMessage } from './server/ws/protocol.js';\nimport { createEvalLoader } from './eval-loader.js';\nimport type { EvalLoaderConfig } from './eval-loader.js';\nimport type { AxlRuntime } from '@axlsdk/axl';\nimport type { IncomingMessage, ServerResponse, Server } from 'node:http';\n\nexport type { EvalLoaderConfig } from './eval-loader.js';\n\nexport type StudioMiddlewareOptions = {\n /** The AxlRuntime instance to observe and control. */\n runtime: AxlRuntime;\n\n /**\n * URL path prefix where Studio is mounted.\n * Must match the mount path in your framework (Express `app.use()`,\n * Fastify `register()`, Hono `app.route()`, etc.). The framework is\n * expected to strip the prefix from `req.url` before calling the handler.\n *\n * Do not set basePath when using a raw `http.Server` as the root handler —\n * leave it empty and mount at root instead.\n *\n * Must start with '/' when non-empty. Trailing slashes are stripped.\n * Only URL-safe characters allowed: [a-zA-Z0-9/_-]\n *\n * @example '/studio'\n * @example '/admin/studio'\n * @example '' — mounted at root (default)\n */\n basePath?: string;\n\n /**\n * Serve the pre-built Studio SPA.\n * Set to false if serving the client from a CDN or separate build.\n * @default true\n */\n serveClient?: boolean;\n\n /**\n * Verify a WebSocket upgrade request before completing the handshake.\n * Return true to allow, false to reject. Throw to reject with an error.\n *\n * IMPORTANT: WebSocket upgrades bypass Express/Fastify/Koa middleware.\n * If your HTTP routes are behind auth middleware, WS connections are NOT\n * automatically protected. Use this callback to enforce authentication\n * on WebSocket connections.\n */\n verifyUpgrade?: (req: IncomingMessage) => boolean | Promise<boolean>;\n\n /**\n * Disable all mutating endpoints (execute, test, send, delete, resolve).\n * When true, Studio is observation-only.\n * @default false\n */\n readOnly?: boolean;\n\n /**\n * Lazy-load eval files for the Eval Runner panel.\n *\n * Eval files are dynamically imported on first access to eval endpoints,\n * not at middleware construction time. This means:\n * - Zero cost during normal API operation\n * - Eval files can import from any module without creating circular deps\n * in the static module graph (they're loaded as standalone entry points)\n * - `@axlsdk/eval` can remain a devDependency — eval files never enter\n * the production bundle since bundlers can't see dynamic imports\n *\n * Accepts glob patterns, explicit file paths, or an object with\n * `conditions` for monorepo source export resolution.\n *\n * Eval files are loaded once and cached for the middleware's lifetime.\n * Changes to eval files require a server restart.\n *\n * @example\n * // Single glob pattern\n * evals: 'evals/*.eval.ts'\n *\n * @example\n * // Multiple patterns\n * evals: ['libs/api/evals/*.eval.ts', 'libs/ai/evals/*.eval.ts']\n *\n * @example\n * // With import conditions for monorepo source exports\n * evals: {\n * files: 'libs/api/evals/*.eval.ts',\n * conditions: ['development'],\n * }\n */\n evals?: EvalLoaderConfig;\n};\n\n/**\n * Minimal contract a WebSocket connection must satisfy.\n * Matches the `ws` library API (de facto standard in Node.js).\n */\nexport interface StudioWebSocket {\n send(data: string): void;\n close(): void;\n on(event: 'message', fn: (data: string | Buffer) => void): void;\n on(event: 'close', fn: () => void): void;\n on(event: 'error', fn: (err: Error) => void): void;\n}\n\n// Re-export for Hono-in-Hono consumers\nexport { handleWsMessage } from './server/ws/protocol.js';\n\nexport type StudioMiddleware = ReturnType<typeof createStudioMiddleware>;\n\nexport function createStudioMiddleware(options: StudioMiddlewareOptions) {\n const { runtime, serveClient = true, verifyUpgrade, readOnly = false } = options;\n\n // Normalize basePath: strip trailing slashes, validate format\n const basePath = normalizeBasePath(options.basePath);\n\n // Resolve pre-built SPA assets from this package's dist/\n const staticRoot = serveClient ? resolveClientDist() : undefined;\n\n if (serveClient && !staticRoot) {\n const dir =\n import.meta.dirname ??\n (typeof __dirname !== 'undefined' ? __dirname : dirname(fileURLToPath(import.meta.url)));\n console.warn(\n '[axl-studio] serveClient is true but no pre-built client found at ' +\n `${resolve(dir, 'client')}. Studio UI will not be available. ` +\n 'Set serveClient: false to suppress this warning.',\n );\n }\n\n // Create lazy eval loader if eval files are configured\n const evalLoader = options.evals ? createEvalLoader(options.evals, runtime) : undefined;\n\n const { app, connMgr, traceListener } = createServer({\n runtime,\n staticRoot,\n basePath,\n readOnly,\n cors: false, // Host framework owns CORS policy\n evalLoader,\n });\n\n // Log production safety warning\n if (process.env.NODE_ENV === 'production' && !verifyUpgrade) {\n console.warn(\n '[axl-studio] WARNING: Studio middleware mounted in production without verifyUpgrade. ' +\n 'WebSocket connections are not authenticated. All registered workflows, tools, and ' +\n 'agents are accessible. See https://axlsdk.com/docs/studio/security',\n );\n }\n\n // Convert Hono app → Node.js (req, res) handler.\n // overrideGlobalObjects: false prevents replacing global.Request and\n // global.Response, which could break the host application.\n const listener = getRequestListener(app.fetch, {\n overrideGlobalObjects: false,\n });\n\n let closed = false;\n\n function handler(req: IncomingMessage, res: ServerResponse) {\n if (closed) {\n res.writeHead(503, { 'Content-Type': 'application/json' });\n res.end(\n JSON.stringify({\n ok: false,\n error: { code: 'CLOSED', message: 'Studio middleware has been shut down' },\n }),\n );\n return;\n }\n // listener returns Promise<void>. Catch async errors to prevent\n // unhandled rejections from crashing the host process.\n listener(req, res).catch((err) => {\n console.error('[axl-studio] Unhandled error in request handler:', err);\n if (!res.headersSent) {\n res.writeHead(500, { 'Content-Type': 'application/json' });\n res.end(\n JSON.stringify({\n ok: false,\n error: { code: 'INTERNAL_ERROR', message: 'Internal server error' },\n }),\n );\n }\n });\n }\n\n // Handle an individual WebSocket using the Studio protocol.\n // Adapts any StudioWebSocket to ConnectionManager's internal BroadcastTarget.\n function handleWebSocket(ws: StudioWebSocket) {\n if (closed) {\n ws.close();\n return;\n }\n const socket = {\n send: (data: string) => ws.send(data),\n close: () => ws.close(),\n };\n connMgr.add(socket);\n\n ws.on('message', (raw) => {\n const reply = handleWsMessage(String(raw), socket, connMgr);\n if (reply) ws.send(reply);\n });\n\n ws.on('close', () => connMgr.remove(socket));\n ws.on('error', () => connMgr.remove(socket));\n }\n\n // Internal WebSocketServer — created lazily by upgradeWebSocket()\n let wss: InstanceType<typeof WebSocketServer> | undefined;\n // References for cleanup: the upgrade handler and server it's attached to\n let upgradeHandler: ((...args: any[]) => void) | undefined;\n let serverRef: Server | undefined;\n\n // Convenience: attach WS handling to an http.Server.\n function upgradeWebSocket(server: Server, path?: string) {\n if (wss) {\n throw new Error(\n '[axl-studio] upgradeWebSocket() has already been called. ' +\n 'Call close() first if you need to re-attach.',\n );\n }\n\n const wsPath = path ?? (basePath ? `${basePath}/ws` : '/ws');\n\n wss = new WebSocketServer({ noServer: true });\n serverRef = server;\n\n upgradeHandler = async (req: IncomingMessage, socket: any, head: Buffer) => {\n // Match path, ignoring query string\n const pathname = new URL(req.url!, `http://${req.headers.host}`).pathname;\n if (pathname !== wsPath) return; // Let other upgrade handlers run\n\n // Apply auth verification\n if (verifyUpgrade) {\n try {\n const allowed = await verifyUpgrade(req);\n if (!allowed) {\n socket.write('HTTP/1.1 401 Unauthorized\\r\\n\\r\\n');\n socket.destroy();\n return;\n }\n } catch {\n socket.write('HTTP/1.1 403 Forbidden\\r\\n\\r\\n');\n socket.destroy();\n return;\n }\n }\n\n // Guard against close() being called during async verifyUpgrade\n if (!wss) {\n socket.destroy();\n return;\n }\n\n wss.handleUpgrade(req, socket, head, (ws) => {\n handleWebSocket(ws);\n });\n };\n\n server.on('upgrade', upgradeHandler);\n }\n\n // Cleanup function for lifecycle management.\n function close() {\n closed = true;\n\n // Close all WebSocket connections\n connMgr.closeAll();\n\n // Remove the upgrade listener from the server before closing WSS\n if (upgradeHandler && serverRef) {\n serverRef.removeListener('upgrade', upgradeHandler);\n upgradeHandler = undefined;\n serverRef = undefined;\n }\n\n // Shut down the internal WebSocketServer if one was created\n if (wss) {\n wss.close();\n wss = undefined;\n }\n\n // Remove only our trace event listener from the runtime\n if (traceListener) {\n runtime.removeListener('trace', traceListener);\n }\n }\n\n return {\n handler,\n handleWebSocket,\n upgradeWebSocket,\n app,\n connectionManager: connMgr,\n close,\n };\n}\n\n/**\n * Normalize and validate basePath.\n * - Empty string and undefined → ''\n * - Strip trailing slashes\n * - Validate leading slash when non-empty\n * - Reject unsafe characters\n */\nfunction normalizeBasePath(raw?: string): string {\n if (!raw) return '';\n\n // Strip trailing slashes\n const normalized = raw.replace(/\\/+$/, '');\n if (!normalized) return '';\n\n // Must start with /\n if (!normalized.startsWith('/')) {\n throw new Error(`basePath must start with '/' (got '${raw}'). Example: '/studio'`);\n }\n\n // Reject path traversal, consecutive slashes, and unsafe characters\n if (normalized.includes('..')) {\n throw new Error(`basePath must not contain '..' segments (got '${raw}')`);\n }\n if (normalized.includes('//')) {\n throw new Error(`basePath must not contain consecutive slashes (got '${raw}')`);\n }\n if (!/^\\/[a-zA-Z0-9/_-]*$/.test(normalized)) {\n throw new Error(\n `basePath contains invalid characters (got '${raw}'). ` +\n 'Only alphanumeric characters, /, _, and - are allowed.',\n );\n }\n\n return normalized;\n}\n\nfunction resolveClientDist(): string | undefined {\n // Resolve the directory of this file (dist/ in published package).\n const dir =\n import.meta.dirname ??\n (typeof __dirname !== 'undefined' ? __dirname : dirname(fileURLToPath(import.meta.url)));\n const candidate = resolve(dir, 'client');\n return existsSync(resolve(candidate, 'index.html')) ? candidate : undefined;\n}\n","import { resolve, relative, dirname, basename } from 'node:path';\nimport { readdirSync, statSync } from 'node:fs';\nimport { pathToFileURL } from 'node:url';\nimport type { AxlRuntime } from '@axlsdk/axl';\nimport { importModule } from './cli-utils.js';\n\n// In the CJS bundle, tsup stubs import.meta as {} so import.meta.url is\n// undefined. Fall back to __filename (which CJS defines) converted to a\n// file:// URL so tsImport() gets a valid parentURL.\nconst parentURL: string =\n import.meta.url ?? pathToFileURL(typeof __filename !== 'undefined' ? __filename : __dirname).href;\n\n/**\n * Configuration for lazy eval file discovery.\n *\n * - `string` — a glob pattern or explicit file path\n * - `string[]` — multiple patterns/paths\n * - `object` — patterns with optional import conditions\n */\nexport type EvalLoaderConfig =\n | string\n | string[]\n | {\n files: string | string[];\n\n /**\n * Custom Node.js import conditions (e.g., `['development']`).\n *\n * In monorepos, package.json `exports` often use the `development` condition\n * to point at source (`.ts`) instead of built dist. Without this, eval files\n * that import workspace packages resolve to dist files, which may not exist.\n *\n * **WARNING**: Conditions are registered process-wide via `module.register()`.\n * They affect all subsequent imports in the process, not just eval files.\n */\n conditions?: string[];\n };\n\n/**\n * Create a lazy eval loader that resolves file patterns and dynamically imports\n * eval files on first call, registering them with the runtime.\n *\n * The loader is idempotent — subsequent calls return the same promise.\n * Concurrent callers all await the same loading work.\n *\n * Eval files should export a default config with `{ workflow, dataset, scorers }`\n * (the result of `defineEval()` from `@axlsdk/eval`). An optional named export\n * `executeWorkflow` overrides the default `runtime.execute()` behavior.\n *\n * Eval names are the file's path relative to `cwd` (project root), minus the\n * `.eval.*` suffix. This makes names completely stable — a file's name never\n * changes regardless of what other files or patterns exist.\n *\n * @param config Glob patterns, file paths, or object with conditions\n * @param runtime The AxlRuntime to register discovered evals on\n * @param cwd Base directory for resolving patterns and deriving names (default: `process.cwd()`)\n */\nexport function createEvalLoader(\n config: EvalLoaderConfig,\n runtime: AxlRuntime,\n cwd?: string,\n): () => Promise<void> {\n let loadPromise: Promise<void> | undefined;\n const { patterns, conditions } = normalizeConfig(config);\n const baseCwd = cwd ?? process.cwd();\n\n return () => {\n if (!loadPromise) {\n loadPromise = loadEvalFiles(patterns, conditions, baseCwd, runtime).catch((err) => {\n loadPromise = undefined; // Allow retry on next request\n throw err;\n });\n }\n return loadPromise;\n };\n}\n\n// ── Core loading logic ─────────────────────────────────────────────\n\nasync function loadEvalFiles(\n patterns: string[],\n conditions: string[],\n cwd: string,\n runtime: AxlRuntime,\n): Promise<void> {\n if (conditions.length > 0) {\n await registerConditions(conditions);\n }\n\n const files = resolvePatterns(patterns, cwd);\n\n if (files.length === 0) {\n console.warn(`[axl-studio] No eval files found matching: ${patterns.join(', ')}`);\n return;\n }\n\n for (const file of files) {\n try {\n const mod = await importModule(file, parentURL);\n const evalConfig = mod.default?.default ?? mod.default ?? mod.config ?? mod;\n\n if (!evalConfig.workflow || !evalConfig.dataset || !evalConfig.scorers) {\n console.warn(\n `[axl-studio] Skipping ${file}: not a valid eval config ` +\n `(missing workflow, dataset, or scorers)`,\n );\n continue;\n }\n\n const name = deriveEvalName(file, cwd);\n\n if (runtime.getRegisteredEval(name)) {\n console.warn(\n `[axl-studio] Eval name \"${name}\" from ${file} collides with an ` +\n `already-registered eval — overwriting`,\n );\n }\n\n runtime.registerEval(name, evalConfig, mod.executeWorkflow);\n } catch (err) {\n const msg = err instanceof Error ? err.message : String(err);\n console.warn(`[axl-studio] Failed to load eval ${file}: ${msg}`);\n }\n }\n}\n\n// ── Internal helpers ───────────────────────────────────────────────\n\nfunction normalizeConfig(config: EvalLoaderConfig): {\n patterns: string[];\n conditions: string[];\n} {\n if (typeof config === 'string') {\n return { patterns: [config], conditions: [] };\n }\n if (Array.isArray(config)) {\n return { patterns: config, conditions: [] };\n }\n const files = typeof config.files === 'string' ? [config.files] : config.files;\n return { patterns: files, conditions: config.conditions ?? [] };\n}\n\n/**\n * Derive eval name from file path relative to cwd.\n *\n * Examples (cwd = `/project`):\n * - `/project/evals/suggestions.eval.ts` → `\"evals/suggestions\"`\n * - `/project/evals/api/accuracy.eval.ts` → `\"evals/api/accuracy\"`\n */\nfunction deriveEvalName(filePath: string, cwd: string): string {\n const rel = relative(cwd, filePath);\n // Normalize to forward slashes for cross-platform consistency\n const normalized = rel.replace(/\\\\/g, '/');\n // Guard: file outside cwd (symlink, absolute path) — fall back to basename\n if (normalized.startsWith('../')) {\n const base = basename(filePath);\n const stripped = base.replace(/\\.eval\\.[mc]?[jt]sx?$/, '');\n return stripped !== base ? stripped : base.replace(/\\.[mc]?[jt]sx?$/, '') || base;\n }\n // Strip .eval.ts, .eval.mjs, .eval.js, etc.\n const withoutEval = normalized.replace(/\\.eval\\.[mc]?[jt]sx?$/, '');\n if (withoutEval !== normalized) return withoutEval;\n // Fallback: strip extension\n const withoutExt = normalized.replace(/\\.[mc]?[jt]sx?$/, '');\n return withoutExt || normalized;\n}\n\n/**\n * Resolve patterns to absolute file paths.\n *\n * Supports:\n * - Explicit file paths (no wildcards)\n * - Single-directory globs: `dir/*.eval.ts`\n * - Recursive globs: `dir/**\\/*.eval.ts` or `**\\/*.eval.ts`\n *\n * Multi-segment `**` (e.g., `a/**\\/b/**\\/*.ts`) is not supported.\n */\nfunction resolvePatterns(patterns: string[], cwd: string): string[] {\n const files: string[] = [];\n const seen = new Set<string>();\n for (const pattern of patterns) {\n const resolved = pattern.includes('*') ? expandGlob(pattern, cwd) : [resolve(cwd, pattern)];\n for (const file of resolved) {\n if (!seen.has(file)) {\n seen.add(file);\n files.push(file);\n }\n }\n }\n return files;\n}\n\n/**\n * Expand a glob pattern to matching file paths.\n *\n * Supported forms:\n * - `dir/*.eval.ts` — match files in dir/\n * - `dir/**\\/*.eval.ts` — recursively match under dir/\n * - `**\\/*.eval.ts` — recursively match under cwd\n */\nfunction expandGlob(pattern: string, cwd: string): string[] {\n if (pattern.includes('**/')) {\n const sepIdx = pattern.indexOf('**/');\n const baseDir = resolve(cwd, pattern.slice(0, sepIdx) || '.');\n const fileGlob = pattern.slice(sepIdx + 3) || '*';\n return findFiles(baseDir, fileGlob, true);\n }\n\n const dir = resolve(cwd, dirname(pattern));\n const fileGlob = basename(pattern);\n return findFiles(dir, fileGlob, false);\n}\n\nconst MAX_DEPTH = 20;\n\nfunction findFiles(dir: string, fileGlob: string, recursive: boolean, depth = 0): string[] {\n if (depth > MAX_DEPTH) return [];\n const matcher = globToRegex(fileGlob);\n const results: string[] = [];\n\n try {\n const entries = readdirSync(dir);\n for (const entry of entries) {\n const full = resolve(dir, entry);\n try {\n const stat = statSync(full);\n if (stat.isFile() && matcher.test(entry)) {\n results.push(full);\n } else if (stat.isDirectory() && recursive) {\n results.push(...findFiles(full, fileGlob, true, depth + 1));\n }\n } catch {\n // Skip unreadable entries\n }\n }\n } catch {\n // Directory doesn't exist or unreadable\n }\n\n return results;\n}\n\n/** Convert a simple glob pattern (e.g., `*.eval.ts`) to a RegExp. */\nfunction globToRegex(glob: string): RegExp {\n const escaped = glob.replace(/[.+?^${}()|[\\]\\\\]/g, '\\\\$&').replace(/\\*/g, '.*');\n return new RegExp(`^${escaped}$`);\n}\n\nasync function registerConditions(conditions: string[]): Promise<void> {\n try {\n const nodeModule = await import('node:module');\n const hookCode = [\n `const extra = ${JSON.stringify(conditions)};`,\n `export async function resolve(specifier, context, nextResolve) {`,\n ` return nextResolve(specifier, {`,\n ` ...context,`,\n ` conditions: [...new Set([...context.conditions, ...extra])],`,\n ` });`,\n `}`,\n ].join('\\n');\n nodeModule.register(`data:text/javascript,${encodeURIComponent(hookCode)}`);\n } catch {\n console.warn('[axl-studio] Warning: import conditions require Node.js 20.6+');\n }\n}\n"],"mappings":"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","names":["resolve","dirname","fileGlob","dirname","resolve"]}
1
+ {"version":3,"sources":["../src/middleware.ts","../src/eval-loader.ts"],"sourcesContent":["import { resolve, dirname } from 'node:path';\nimport { existsSync } from 'node:fs';\nimport { fileURLToPath } from 'node:url';\nimport { getRequestListener } from '@hono/node-server';\nimport { WebSocketServer } from 'ws';\nimport { createServer } from './server/index.js';\nimport { handleWsMessage } from './server/ws/protocol.js';\nimport { createEvalLoader } from './eval-loader.js';\nimport type { EvalLoaderConfig } from './eval-loader.js';\nimport type { AxlRuntime } from '@axlsdk/axl';\nimport type { IncomingMessage, ServerResponse, Server } from 'node:http';\n\nexport type { EvalLoaderConfig } from './eval-loader.js';\n\nexport type StudioMiddlewareOptions = {\n /** The AxlRuntime instance to observe and control. */\n runtime: AxlRuntime;\n\n /**\n * URL path prefix where Studio is mounted.\n * Must match the mount path in your framework (Express `app.use()`,\n * Fastify `register()`, Hono `app.route()`, etc.). The framework is\n * expected to strip the prefix from `req.url` before calling the handler.\n *\n * Do not set basePath when using a raw `http.Server` as the root handler —\n * leave it empty and mount at root instead.\n *\n * Must start with '/' when non-empty. Trailing slashes are stripped.\n * Only URL-safe characters allowed: [a-zA-Z0-9/_-]\n *\n * @example '/studio'\n * @example '/admin/studio'\n * @example '' — mounted at root (default)\n */\n basePath?: string;\n\n /**\n * Serve the pre-built Studio SPA.\n * Set to false if serving the client from a CDN or separate build.\n * @default true\n */\n serveClient?: boolean;\n\n /**\n * Verify a WebSocket upgrade request before completing the handshake.\n * Return true to allow, false to reject. Throw to reject with an error.\n *\n * IMPORTANT: WebSocket upgrades bypass Express/Fastify/Koa middleware.\n * If your HTTP routes are behind auth middleware, WS connections are NOT\n * automatically protected. Use this callback to enforce authentication\n * on WebSocket connections.\n */\n verifyUpgrade?: (req: IncomingMessage) => boolean | Promise<boolean>;\n\n /**\n * Disable all mutating endpoints (execute, test, send, delete, resolve).\n * When true, Studio is observation-only.\n * @default false\n */\n readOnly?: boolean;\n\n /**\n * Lazy-load eval files for the Eval Runner panel.\n *\n * Eval files are dynamically imported on first access to eval endpoints,\n * not at middleware construction time. This means:\n * - Zero cost during normal API operation\n * - Eval files can import from any module without creating circular deps\n * in the static module graph (they're loaded as standalone entry points)\n * - `@axlsdk/eval` can remain a devDependency — eval files never enter\n * the production bundle since bundlers can't see dynamic imports\n *\n * Accepts glob patterns, explicit file paths, or an object with\n * `conditions` for monorepo source export resolution.\n *\n * Eval files are loaded once and cached for the middleware's lifetime.\n * Changes to eval files require a server restart.\n *\n * @example\n * // Single glob pattern\n * evals: 'evals/*.eval.ts'\n *\n * @example\n * // Multiple patterns\n * evals: ['libs/api/evals/*.eval.ts', 'libs/ai/evals/*.eval.ts']\n *\n * @example\n * // With import conditions for monorepo source exports\n * evals: {\n * files: 'libs/api/evals/*.eval.ts',\n * conditions: ['development'],\n * }\n */\n evals?: EvalLoaderConfig;\n};\n\n/**\n * Minimal contract a WebSocket connection must satisfy.\n * Matches the `ws` library API (de facto standard in Node.js).\n */\nexport interface StudioWebSocket {\n send(data: string): void;\n close(): void;\n on(event: 'message', fn: (data: string | Buffer) => void): void;\n on(event: 'close', fn: () => void): void;\n on(event: 'error', fn: (err: Error) => void): void;\n}\n\n// Re-export for Hono-in-Hono consumers\nexport { handleWsMessage } from './server/ws/protocol.js';\n\nexport type StudioMiddleware = ReturnType<typeof createStudioMiddleware>;\n\nexport function createStudioMiddleware(options: StudioMiddlewareOptions) {\n const { runtime, serveClient = true, verifyUpgrade, readOnly = false } = options;\n\n // Normalize basePath: strip trailing slashes, validate format\n const basePath = normalizeBasePath(options.basePath);\n\n // Resolve pre-built SPA assets from this package's dist/\n const staticRoot = serveClient ? resolveClientDist() : undefined;\n\n if (serveClient && !staticRoot) {\n const dir =\n import.meta.dirname ??\n (typeof __dirname !== 'undefined' ? __dirname : dirname(fileURLToPath(import.meta.url)));\n console.warn(\n '[axl-studio] serveClient is true but no pre-built client found at ' +\n `${resolve(dir, 'client')}. Studio UI will not be available. ` +\n 'Set serveClient: false to suppress this warning.',\n );\n }\n\n // Create lazy eval loader if eval files are configured\n const evalLoader = options.evals ? createEvalLoader(options.evals, runtime) : undefined;\n\n const { app, connMgr, traceListener } = createServer({\n runtime,\n staticRoot,\n basePath,\n readOnly,\n cors: false, // Host framework owns CORS policy\n evalLoader,\n });\n\n // Log production safety warning\n if (process.env.NODE_ENV === 'production' && !verifyUpgrade) {\n console.warn(\n '[axl-studio] WARNING: Studio middleware mounted in production without verifyUpgrade. ' +\n 'WebSocket connections are not authenticated. All registered workflows, tools, and ' +\n 'agents are accessible. See https://axlsdk.com/docs/studio/security',\n );\n }\n\n // Convert Hono app → Node.js (req, res) handler via @hono/node-server.\n // overrideGlobalObjects: false prevents replacing global.Request/Response,\n // which could break the host application.\n const listener = getRequestListener(app.fetch, {\n overrideGlobalObjects: false,\n });\n\n let closed = false;\n\n function handler(req: IncomingMessage, res: ServerResponse) {\n if (closed) {\n res.writeHead(503, { 'Content-Type': 'application/json' });\n res.end(\n JSON.stringify({\n ok: false,\n error: { code: 'CLOSED', message: 'Studio middleware has been shut down' },\n }),\n );\n return;\n }\n\n // Express/NestJS/Koa body parsers consume the raw IncomingMessage stream\n // and store the parsed result on req.body. When that happens,\n // @hono/node-server's getRequestListener reads an empty stream and Hono\n // sees no body. To fix this, we re-serialize req.body as req.rawBody —\n // a Buffer that getRequestListener checks before falling back to the\n // stream (see newRequestFromIncoming in @hono/node-server/dist/listener.js).\n //\n // Verified against @hono/node-server@1.19.9. If this breaks after an\n // upgrade, check whether the rawBody instanceof Buffer check still exists\n // in newRequestFromIncoming.\n const reqAny = req as unknown as Record<string, unknown>;\n if (reqAny.body != null && !reqAny.rawBody) {\n try {\n reqAny.rawBody = Buffer.from(JSON.stringify(reqAny.body));\n } catch {\n // Non-serializable body — Hono will see an empty body\n }\n }\n\n listener(req, res).catch((err) => {\n console.error('[axl-studio] Unhandled error in request handler:', err);\n if (!res.headersSent) {\n res.writeHead(500, { 'Content-Type': 'application/json' });\n res.end(\n JSON.stringify({\n ok: false,\n error: { code: 'INTERNAL_ERROR', message: 'Internal server error' },\n }),\n );\n }\n });\n }\n\n // Handle an individual WebSocket using the Studio protocol.\n // Adapts any StudioWebSocket to ConnectionManager's internal BroadcastTarget.\n function handleWebSocket(ws: StudioWebSocket) {\n if (closed) {\n ws.close();\n return;\n }\n const socket = {\n send: (data: string) => ws.send(data),\n close: () => ws.close(),\n };\n connMgr.add(socket);\n\n ws.on('message', (raw) => {\n const reply = handleWsMessage(String(raw), socket, connMgr);\n if (reply) ws.send(reply);\n });\n\n ws.on('close', () => connMgr.remove(socket));\n ws.on('error', () => connMgr.remove(socket));\n }\n\n // Internal WebSocketServer — created lazily by upgradeWebSocket()\n let wss: InstanceType<typeof WebSocketServer> | undefined;\n // References for cleanup: the upgrade handler and server it's attached to\n let upgradeHandler: ((...args: any[]) => void) | undefined;\n let serverRef: Server | undefined;\n\n // Convenience: attach WS handling to an http.Server.\n function upgradeWebSocket(server: Server, path?: string) {\n if (wss) {\n throw new Error(\n '[axl-studio] upgradeWebSocket() has already been called. ' +\n 'Call close() first if you need to re-attach.',\n );\n }\n\n const wsPath = path ?? (basePath ? `${basePath}/ws` : '/ws');\n\n wss = new WebSocketServer({ noServer: true });\n serverRef = server;\n\n upgradeHandler = async (req: IncomingMessage, socket: any, head: Buffer) => {\n // Match path, ignoring query string\n const pathname = new URL(req.url!, `http://${req.headers.host}`).pathname;\n if (pathname !== wsPath) return; // Let other upgrade handlers run\n\n // Apply auth verification\n if (verifyUpgrade) {\n try {\n const allowed = await verifyUpgrade(req);\n if (!allowed) {\n socket.write('HTTP/1.1 401 Unauthorized\\r\\n\\r\\n');\n socket.destroy();\n return;\n }\n } catch {\n socket.write('HTTP/1.1 403 Forbidden\\r\\n\\r\\n');\n socket.destroy();\n return;\n }\n }\n\n // Guard against close() being called during async verifyUpgrade\n if (!wss) {\n socket.destroy();\n return;\n }\n\n wss.handleUpgrade(req, socket, head, (ws) => {\n handleWebSocket(ws);\n });\n };\n\n server.on('upgrade', upgradeHandler);\n }\n\n // Cleanup function for lifecycle management.\n function close() {\n closed = true;\n\n // Close all WebSocket connections\n connMgr.closeAll();\n\n // Remove the upgrade listener from the server before closing WSS\n if (upgradeHandler && serverRef) {\n serverRef.removeListener('upgrade', upgradeHandler);\n upgradeHandler = undefined;\n serverRef = undefined;\n }\n\n // Shut down the internal WebSocketServer if one was created\n if (wss) {\n wss.close();\n wss = undefined;\n }\n\n // Remove only our trace event listener from the runtime\n if (traceListener) {\n runtime.removeListener('trace', traceListener);\n }\n }\n\n return {\n handler,\n handleWebSocket,\n upgradeWebSocket,\n app,\n connectionManager: connMgr,\n close,\n };\n}\n\n/**\n * Normalize and validate basePath.\n * - Empty string and undefined → ''\n * - Strip trailing slashes\n * - Validate leading slash when non-empty\n * - Reject unsafe characters\n */\nfunction normalizeBasePath(raw?: string): string {\n if (!raw) return '';\n\n // Strip trailing slashes\n const normalized = raw.replace(/\\/+$/, '');\n if (!normalized) return '';\n\n // Must start with /\n if (!normalized.startsWith('/')) {\n throw new Error(`basePath must start with '/' (got '${raw}'). Example: '/studio'`);\n }\n\n // Reject path traversal, consecutive slashes, and unsafe characters\n if (normalized.includes('..')) {\n throw new Error(`basePath must not contain '..' segments (got '${raw}')`);\n }\n if (normalized.includes('//')) {\n throw new Error(`basePath must not contain consecutive slashes (got '${raw}')`);\n }\n if (!/^\\/[a-zA-Z0-9/_-]*$/.test(normalized)) {\n throw new Error(\n `basePath contains invalid characters (got '${raw}'). ` +\n 'Only alphanumeric characters, /, _, and - are allowed.',\n );\n }\n\n return normalized;\n}\n\nfunction resolveClientDist(): string | undefined {\n // Resolve the directory of this file (dist/ in published package).\n const dir =\n import.meta.dirname ??\n (typeof __dirname !== 'undefined' ? __dirname : dirname(fileURLToPath(import.meta.url)));\n const candidate = resolve(dir, 'client');\n return existsSync(resolve(candidate, 'index.html')) ? candidate : undefined;\n}\n","import { resolve, relative, dirname, basename } from 'node:path';\nimport { readdirSync, statSync } from 'node:fs';\nimport { pathToFileURL } from 'node:url';\nimport type { AxlRuntime } from '@axlsdk/axl';\nimport { importModule } from './cli-utils.js';\n\n// In the CJS bundle, tsup stubs import.meta as {} so import.meta.url is\n// undefined. Fall back to __filename (which CJS defines) converted to a\n// file:// URL so tsImport() gets a valid parentURL.\nconst parentURL: string =\n import.meta.url ?? pathToFileURL(typeof __filename !== 'undefined' ? __filename : __dirname).href;\n\n/**\n * Configuration for lazy eval file discovery.\n *\n * - `string` — a glob pattern or explicit file path\n * - `string[]` — multiple patterns/paths\n * - `object` — patterns with optional import conditions\n */\nexport type EvalLoaderConfig =\n | string\n | string[]\n | {\n files: string | string[];\n\n /**\n * Custom Node.js import conditions (e.g., `['development']`).\n *\n * In monorepos, package.json `exports` often use the `development` condition\n * to point at source (`.ts`) instead of built dist. Without this, eval files\n * that import workspace packages resolve to dist files, which may not exist.\n *\n * **WARNING**: Conditions are registered process-wide via `module.register()`.\n * They affect all subsequent imports in the process, not just eval files.\n */\n conditions?: string[];\n };\n\n/**\n * Create a lazy eval loader that resolves file patterns and dynamically imports\n * eval files on first call, registering them with the runtime.\n *\n * The loader is idempotent — subsequent calls return the same promise.\n * Concurrent callers all await the same loading work.\n *\n * Eval files should export a default config with `{ workflow, dataset, scorers }`\n * (the result of `defineEval()` from `@axlsdk/eval`). An optional named export\n * `executeWorkflow` overrides the default `runtime.execute()` behavior.\n *\n * Eval names are the file's path relative to `cwd` (project root), minus the\n * `.eval.*` suffix. This makes names completely stable — a file's name never\n * changes regardless of what other files or patterns exist.\n *\n * @param config Glob patterns, file paths, or object with conditions\n * @param runtime The AxlRuntime to register discovered evals on\n * @param cwd Base directory for resolving patterns and deriving names (default: `process.cwd()`)\n */\nexport function createEvalLoader(\n config: EvalLoaderConfig,\n runtime: AxlRuntime,\n cwd?: string,\n): () => Promise<void> {\n let loadPromise: Promise<void> | undefined;\n const { patterns, conditions } = normalizeConfig(config);\n const baseCwd = cwd ?? process.cwd();\n\n return () => {\n if (!loadPromise) {\n loadPromise = loadEvalFiles(patterns, conditions, baseCwd, runtime).catch((err) => {\n loadPromise = undefined; // Allow retry on next request\n throw err;\n });\n }\n return loadPromise;\n };\n}\n\n// ── Core loading logic ─────────────────────────────────────────────\n\nasync function loadEvalFiles(\n patterns: string[],\n conditions: string[],\n cwd: string,\n runtime: AxlRuntime,\n): Promise<void> {\n if (conditions.length > 0) {\n await registerConditions(conditions);\n }\n\n const files = resolvePatterns(patterns, cwd);\n\n if (files.length === 0) {\n console.warn(`[axl-studio] No eval files found matching: ${patterns.join(', ')}`);\n return;\n }\n\n for (const file of files) {\n try {\n const mod = await importModule(file, parentURL);\n const evalConfig = mod.default?.default ?? mod.default ?? mod.config ?? mod;\n\n if (!evalConfig.workflow || !evalConfig.dataset || !evalConfig.scorers) {\n console.warn(\n `[axl-studio] Skipping ${file}: not a valid eval config ` +\n `(missing workflow, dataset, or scorers)`,\n );\n continue;\n }\n\n const name = deriveEvalName(file, cwd);\n\n if (runtime.getRegisteredEval(name)) {\n console.warn(\n `[axl-studio] Eval name \"${name}\" from ${file} collides with an ` +\n `already-registered eval — overwriting`,\n );\n }\n\n runtime.registerEval(name, evalConfig, mod.executeWorkflow);\n } catch (err) {\n const msg = err instanceof Error ? err.message : String(err);\n console.warn(`[axl-studio] Failed to load eval ${file}: ${msg}`);\n }\n }\n}\n\n// ── Internal helpers ───────────────────────────────────────────────\n\nfunction normalizeConfig(config: EvalLoaderConfig): {\n patterns: string[];\n conditions: string[];\n} {\n if (typeof config === 'string') {\n return { patterns: [config], conditions: [] };\n }\n if (Array.isArray(config)) {\n return { patterns: config, conditions: [] };\n }\n const files = typeof config.files === 'string' ? [config.files] : config.files;\n return { patterns: files, conditions: config.conditions ?? [] };\n}\n\n/**\n * Derive eval name from file path relative to cwd.\n *\n * Examples (cwd = `/project`):\n * - `/project/evals/suggestions.eval.ts` → `\"evals/suggestions\"`\n * - `/project/evals/api/accuracy.eval.ts` → `\"evals/api/accuracy\"`\n */\nfunction deriveEvalName(filePath: string, cwd: string): string {\n const rel = relative(cwd, filePath);\n // Normalize to forward slashes for cross-platform consistency\n const normalized = rel.replace(/\\\\/g, '/');\n // Guard: file outside cwd (symlink, absolute path) — fall back to basename\n if (normalized.startsWith('../')) {\n const base = basename(filePath);\n const stripped = base.replace(/\\.eval\\.[mc]?[jt]sx?$/, '');\n return stripped !== base ? stripped : base.replace(/\\.[mc]?[jt]sx?$/, '') || base;\n }\n // Strip .eval.ts, .eval.mjs, .eval.js, etc.\n const withoutEval = normalized.replace(/\\.eval\\.[mc]?[jt]sx?$/, '');\n if (withoutEval !== normalized) return withoutEval;\n // Fallback: strip extension\n const withoutExt = normalized.replace(/\\.[mc]?[jt]sx?$/, '');\n return withoutExt || normalized;\n}\n\n/**\n * Resolve patterns to absolute file paths.\n *\n * Supports:\n * - Explicit file paths (no wildcards)\n * - Single-directory globs: `dir/*.eval.ts`\n * - Recursive globs: `dir/**\\/*.eval.ts` or `**\\/*.eval.ts`\n *\n * Multi-segment `**` (e.g., `a/**\\/b/**\\/*.ts`) is not supported.\n */\nfunction resolvePatterns(patterns: string[], cwd: string): string[] {\n const files: string[] = [];\n const seen = new Set<string>();\n for (const pattern of patterns) {\n const resolved = pattern.includes('*') ? expandGlob(pattern, cwd) : [resolve(cwd, pattern)];\n for (const file of resolved) {\n if (!seen.has(file)) {\n seen.add(file);\n files.push(file);\n }\n }\n }\n return files;\n}\n\n/**\n * Expand a glob pattern to matching file paths.\n *\n * Supported forms:\n * - `dir/*.eval.ts` — match files in dir/\n * - `dir/**\\/*.eval.ts` — recursively match under dir/\n * - `**\\/*.eval.ts` — recursively match under cwd\n */\nfunction expandGlob(pattern: string, cwd: string): string[] {\n if (pattern.includes('**/')) {\n const sepIdx = pattern.indexOf('**/');\n const baseDir = resolve(cwd, pattern.slice(0, sepIdx) || '.');\n const fileGlob = pattern.slice(sepIdx + 3) || '*';\n return findFiles(baseDir, fileGlob, true);\n }\n\n const dir = resolve(cwd, dirname(pattern));\n const fileGlob = basename(pattern);\n return findFiles(dir, fileGlob, false);\n}\n\nconst MAX_DEPTH = 20;\n\nfunction findFiles(dir: string, fileGlob: string, recursive: boolean, depth = 0): string[] {\n if (depth > MAX_DEPTH) return [];\n const matcher = globToRegex(fileGlob);\n const results: string[] = [];\n\n try {\n const entries = readdirSync(dir);\n for (const entry of entries) {\n const full = resolve(dir, entry);\n try {\n const stat = statSync(full);\n if (stat.isFile() && matcher.test(entry)) {\n results.push(full);\n } else if (stat.isDirectory() && recursive) {\n results.push(...findFiles(full, fileGlob, true, depth + 1));\n }\n } catch {\n // Skip unreadable entries\n }\n }\n } catch {\n // Directory doesn't exist or unreadable\n }\n\n return results;\n}\n\n/** Convert a simple glob pattern (e.g., `*.eval.ts`) to a RegExp. */\nfunction globToRegex(glob: string): RegExp {\n const escaped = glob.replace(/[.+?^${}()|[\\]\\\\]/g, '\\\\$&').replace(/\\*/g, '.*');\n return new RegExp(`^${escaped}$`);\n}\n\nasync function registerConditions(conditions: string[]): Promise<void> {\n try {\n const nodeModule = await import('node:module');\n const hookCode = [\n `const extra = ${JSON.stringify(conditions)};`,\n `export async function resolve(specifier, context, nextResolve) {`,\n ` return nextResolve(specifier, {`,\n ` ...context,`,\n ` conditions: [...new Set([...context.conditions, ...extra])],`,\n ` });`,\n `}`,\n ].join('\\n');\n nodeModule.register(`data:text/javascript,${encodeURIComponent(hookCode)}`);\n } catch {\n console.warn('[axl-studio] Warning: import conditions require Node.js 20.6+');\n }\n}\n"],"mappings":"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","names":["resolve","dirname","fileGlob","dirname","resolve"]}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@axlsdk/studio",
3
- "version": "0.13.7",
3
+ "version": "0.13.8",
4
4
  "description": "Local development UI for debugging, testing, and iterating on Axl agents and workflows",
5
5
  "type": "module",
6
6
  "main": "./dist/server/index.cjs",
@@ -40,7 +40,7 @@
40
40
  "@hono/node-ws": "^1.1.0",
41
41
  "tsx": "^4.19.0",
42
42
  "ws": "^8.0.0",
43
- "@axlsdk/axl": "0.13.7"
43
+ "@axlsdk/axl": "0.13.8"
44
44
  },
45
45
  "devDependencies": {
46
46
  "@tailwindcss/vite": "^4.1.0",
@@ -61,10 +61,10 @@
61
61
  "vite": "^6.0.0",
62
62
  "vitest": "^3.0.0",
63
63
  "zod": "^4.0.0",
64
- "@axlsdk/testing": "0.13.7"
64
+ "@axlsdk/testing": "0.13.8"
65
65
  },
66
66
  "peerDependencies": {
67
- "@axlsdk/eval": "0.13.7"
67
+ "@axlsdk/eval": "0.13.8"
68
68
  },
69
69
  "peerDependenciesMeta": {
70
70
  "@axlsdk/eval": {