@axlsdk/studio 0.21.1 → 0.22.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/cli.js CHANGED
@@ -1,7 +1,7 @@
1
1
  #!/usr/bin/env node
2
2
  import {
3
3
  createServer
4
- } from "./chunk-YGLWYDQ3.js";
4
+ } from "./chunk-Z374DI7D.js";
5
5
 
6
6
  // src/cli.ts
7
7
  import { resolve, extname } from "path";
@@ -160,7 +160,7 @@ Tip: Use .mts for configs with top-level await or in projects without "type": "m
160
160
  ].join("\n");
161
161
  nodeModule.register(`data:text/javascript,${encodeURIComponent(hookCode)}`);
162
162
  } catch {
163
- console.warn(`[axl-studio] Warning: --conditions requires Node.js 20.6+`);
163
+ console.warn(`[axl-studio] Warning: this Node.js runtime does not support --conditions`);
164
164
  }
165
165
  }
166
166
  console.log(`[axl-studio] Loading config from ${configPath}`);
package/dist/cli.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/cli.ts","../src/resolve-runtime.ts","../src/cli-utils.ts"],"sourcesContent":["#!/usr/bin/env node\nimport { resolve, extname } from 'node:path';\nimport { existsSync } from 'node:fs';\nimport { serve } from '@hono/node-server';\nimport { createNodeWebSocket } from '@hono/node-ws';\nimport { createServer } from './server/index.js';\nimport { resolveRuntime } from './resolve-runtime.js';\nimport {\n parseArgs,\n findConfig,\n importModule,\n CONFIG_CANDIDATES,\n STUDIO_CLI_HOST,\n isAllowedStandaloneRequest,\n withStandaloneRequestGuard,\n} from './cli-utils.js';\n\n// ── Main ────────────────────────────────────────────────────────────\n\nasync function main() {\n const args = parseArgs(process.argv);\n\n if (args.help) {\n console.log(`\nAxl Studio — Local development UI for Axl agents and workflows\n\nUsage:\n axl-studio [options]\n\nOptions:\n --port <number> Server port (default: 4400)\n --dangerously-bind <ip> Bind for a loopback-published container/local-forward tunnel\n --config <path> Path to config file (default: auto-detect)\n --conditions <list> Comma-separated Node.js import conditions (e.g., development)\n --read-only Disable all mutating endpoints (runs, imports, rescore, etc)\n --open Auto-open browser\n -h, --help Show this help message\n\nConfig auto-detection order:\n ${CONFIG_CANDIDATES.join(' → ')}\n\nTip: Use .mts for configs with top-level await or in projects without \"type\": \"module\".\n`);\n process.exit(0);\n }\n\n if (args.portError) {\n console.error(args.portError);\n process.exit(1);\n }\n\n // Resolve config path: explicit --config or auto-detect\n let configPath: string;\n if (args.config) {\n configPath = resolve(process.cwd(), args.config);\n if (!existsSync(configPath)) {\n console.error(`Config file not found: ${configPath}`);\n process.exit(1);\n }\n } else {\n const found = findConfig(process.cwd());\n if (!found) {\n console.error(`No config file found. Searched for: ${CONFIG_CANDIDATES.join(', ')}`);\n console.error(`Create an axl.config.mts that exports a default AxlRuntime instance.`);\n process.exit(1);\n }\n configPath = found;\n }\n\n // Register custom import conditions (e.g., --conditions development).\n // In monorepos, package.json \"exports\" often use the \"development\" condition\n // to point at source (.ts) instead of built dist. Without this, Studio\n // configs that import workspace packages resolve to dist files, which may\n // not exist or be stale.\n if (args.conditions.length > 0) {\n try {\n const nodeModule = await import('node:module');\n const hookCode = [\n `const extra = ${JSON.stringify(args.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: --conditions requires Node.js 20.6+`);\n }\n }\n\n console.log(`[axl-studio] Loading config from ${configPath}`);\n\n // Import the user's config via tsImport (handles ESM/CJS correctly for\n // TypeScript files without process-wide side effects)\n let runtime: import('@axlsdk/axl').AxlRuntime;\n const ext = extname(configPath);\n try {\n const mod = await importModule(configPath, import.meta.url);\n // resolveRuntime handles ESM default, CJS-to-ESM interop, and named exports\n runtime = resolveRuntime(mod) as typeof runtime;\n\n if (!runtime || typeof runtime.execute !== 'function') {\n console.error(`Config must export a default AxlRuntime instance.`);\n if (runtime) {\n const keys = Object.keys(runtime as object)\n .slice(0, 5)\n .join(', ');\n console.error(` Got: ${typeof runtime}${keys ? ` with keys: { ${keys} }` : ''}`);\n }\n console.error(\n `Example:\\n import { AxlRuntime } from '@axlsdk/axl';\\n export default new AxlRuntime({ ... });`,\n );\n process.exit(1);\n }\n } catch (err) {\n const msg = err instanceof Error ? err.message : String(err);\n if (\n /Cannot use import statement|Unexpected reserved word|top-level await|exports is not defined/.test(\n msg,\n )\n ) {\n console.error(`[axl-studio] Config failed to load due to a CJS/ESM compatibility issue.`);\n if (ext === '.ts' || ext === '.tsx') {\n console.error(\n ` Tip: try renaming to .mts to force ESM format, or ensure tsx is installed and up to date.`,\n );\n } else {\n console.error(` Tip: add \"type\": \"module\" to your package.json.`);\n }\n console.error();\n }\n console.error(`Failed to load config:`, err);\n process.exit(1);\n }\n\n // Determine static root for pre-built SPA\n const staticRoot = resolve(import.meta.dirname ?? __dirname, 'client');\n const hasStaticAssets = existsSync(resolve(staticRoot, 'index.html'));\n\n const { app, createWsHandlers } = createServer({\n runtime,\n staticRoot: hasStaticAssets ? staticRoot : undefined,\n readOnly: args.readOnly,\n cors: false,\n });\n\n if (args.readOnly) {\n console.log('[axl-studio] Read-only mode enabled — mutating endpoints are disabled.');\n }\n\n // Set up WebSocket\n const { injectWebSocket, upgradeWebSocket } = createNodeWebSocket({ app });\n const wsHandlers = createWsHandlers();\n app.use('/ws', async (c, next) => {\n if (!isAllowedStandaloneRequest(c.req.header('Host'), c.req.header('Origin'))) {\n return c.json(\n {\n ok: false,\n error: {\n code: 'FORBIDDEN_HOST_ORIGIN',\n message: 'Standalone Studio accepts WebSocket connections only locally',\n },\n },\n 403,\n );\n }\n await next();\n });\n app.get(\n '/ws',\n upgradeWebSocket(() => wsHandlers),\n );\n\n const server = serve(\n {\n fetch: withStandaloneRequestGuard((request) => app.fetch(request)),\n port: args.port,\n hostname: args.host,\n },\n (info) => {\n console.log(`[axl-studio] Server running at http://${STUDIO_CLI_HOST}:${info.port}`);\n console.log(`[axl-studio] Workflows: ${runtime.getWorkflowNames().join(', ') || '(none)'}`);\n console.log(\n `[axl-studio] Agents: ${\n runtime\n .getAgents()\n .map((a) => a._name)\n .join(', ') || '(none)'\n }`,\n );\n console.log(\n `[axl-studio] Tools: ${\n runtime\n .getTools()\n .map((t) => t.name)\n .join(', ') || '(none)'\n }`,\n );\n\n if (!hasStaticAssets) {\n console.log(\n `[axl-studio] No pre-built UI found. Run 'pnpm build:client' or use Vite dev server on port 4401.`,\n );\n }\n },\n );\n\n injectWebSocket(server);\n\n if (args.host !== STUDIO_CLI_HOST) {\n console.warn(\n `[axl-studio] WARNING: binding to ${args.host}. Use this only behind a local-only ` +\n 'container port mapping or local-forward tunnel; standalone Studio remains unauthenticated.',\n );\n }\n\n // Auto-open browser\n if (args.open) {\n const url = `http://${STUDIO_CLI_HOST}:${args.port}`;\n const { exec } = await import('node:child_process');\n const cmd =\n process.platform === 'darwin' ? 'open' : process.platform === 'win32' ? 'start' : 'xdg-open';\n exec(`${cmd} ${url}`);\n }\n\n // Graceful shutdown\n const shutdown = async () => {\n console.log('\\n[axl-studio] Shutting down...');\n await runtime.shutdown().catch(() => {});\n process.exit(0);\n };\n\n process.on('SIGINT', shutdown);\n process.on('SIGTERM', shutdown);\n}\n\nmain().catch((err) => {\n console.error('[axl-studio] Fatal error:', err);\n process.exit(1);\n});\n","/**\n * Re-exports of module-resolution helpers from `@axlsdk/axl`.\n *\n * Studio used to keep its own copy of these (alongside the duplicated copy in\n * `@axlsdk/eval`'s cli-utils). They've been lifted to `@axlsdk/axl` so a fix\n * to the ESM/CJS chain walk applies to all three consumers atomically. Kept\n * as a re-export rather than a deletion so existing imports still work and\n * the test file at `__tests__/resolve-runtime.test.ts` continues to function\n * as a tripwire on this module's path.\n */\nexport { resolveRuntime, pickDefault, pickExport } from '@axlsdk/axl';\n","/**\n * CLI utilities for `axl-studio`.\n *\n * Loader / glob / config-detection helpers now live in `@axlsdk/axl`'s\n * `cli-internals` (shared with `@axlsdk/eval` so fixes apply atomically);\n * this file holds the studio-specific arg parser and re-exports what\n * dependent modules consume.\n */\n\nexport { CONFIG_CANDIDATES, findConfig, needsTsxLoader, importModule } from '@axlsdk/axl';\n\n/** Standalone Studio is an unauthenticated local-development surface. */\nexport const STUDIO_CLI_HOST = '127.0.0.1';\n\ntype StandaloneFetch = (request: Request) => Response | Promise<Response>;\n\nfunction isLoopbackHostname(hostname: string): boolean {\n return hostname === 'localhost' || hostname === 'localhost.' || hostname === '127.0.0.1';\n}\n\n/** Reject DNS-rebinding Host values before standalone Studio serves admin data. */\nexport function isAllowedStandaloneHost(host: string | undefined): boolean {\n if (!host) return false;\n\n let url: URL;\n try {\n url = new URL(`http://${host}`);\n } catch {\n return false;\n }\n\n if (url.username || url.password || url.pathname !== '/' || url.search || url.hash) return false;\n return isLoopbackHostname(url.hostname);\n}\n\n/**\n * Browser WebSocket handshakes carry an Origin header even though they are not\n * governed by CORS. Standalone Studio accepts only local browser origins; CLI\n * and other non-browser clients may omit Origin.\n */\nexport function isAllowedStandaloneOrigin(origin: string | undefined): boolean {\n if (origin === undefined) return true;\n\n let url: URL;\n try {\n url = new URL(origin);\n } catch {\n return false;\n }\n\n if (url.protocol !== 'http:' && url.protocol !== 'https:') return false;\n if (url.username || url.password || url.pathname !== '/' || url.search || url.hash) return false;\n\n return isLoopbackHostname(url.hostname);\n}\n\n/** Standalone Studio accepts only loopback authorities and local/absent origins. */\nexport function isAllowedStandaloneRequest(\n host: string | undefined,\n origin: string | undefined,\n): boolean {\n return isAllowedStandaloneHost(host) && isAllowedStandaloneOrigin(origin);\n}\n\n/**\n * Guard the standalone HTTP boundary before Hono routing. This blocks hostile\n * simple POSTs as well as DNS-rebinding reads, and is intentionally separate\n * from CORS response headers.\n */\nexport function withStandaloneRequestGuard(fetch: StandaloneFetch): StandaloneFetch {\n return (request) => {\n const host = request.headers.get('host') ?? undefined;\n const origin = request.headers.get('origin') ?? undefined;\n if (!isAllowedStandaloneRequest(host, origin)) {\n return Response.json(\n {\n ok: false,\n error: {\n code: 'FORBIDDEN_HOST_ORIGIN',\n message: 'Standalone Studio accepts requests only through a local host and origin',\n },\n },\n { status: 403 },\n );\n }\n return fetch(request);\n };\n}\n\n// ── Parse CLI args ──────────────────────────────────────────────────\n\nexport interface CliArgs {\n port: number;\n host: string;\n config?: string;\n open: boolean;\n conditions: string[];\n readOnly: boolean;\n help: boolean;\n portError?: string;\n}\n\nexport function parseArgs(argv: string[]): CliArgs {\n let port = 4400;\n let host = STUDIO_CLI_HOST;\n let config: string | undefined;\n let open = false;\n let help = false;\n let conditions: string[] = [];\n let readOnly = false;\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 === '--dangerously-bind' && argv[i + 1]) {\n host = argv[i + 1];\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 === '--read-only' || arg === '--readonly') {\n readOnly = true;\n } else if (arg === '--help' || arg === '-h') {\n help = true;\n }\n }\n\n const result: CliArgs = { port, host, config, open, help, conditions, readOnly };\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"],"mappings":";;;;;;AACA,SAAS,SAAS,eAAe;AACjC,SAAS,kBAAkB;AAC3B,SAAS,aAAa;AACtB,SAAS,2BAA2B;;;ACMpC,SAAS,gBAAgB,aAAa,kBAAkB;;;ACDxD,SAAS,mBAAmB,YAAY,gBAAgB,oBAAoB;AAGrE,IAAM,kBAAkB;AAI/B,SAAS,mBAAmB,UAA2B;AACrD,SAAO,aAAa,eAAe,aAAa,gBAAgB,aAAa;AAC/E;AAGO,SAAS,wBAAwB,MAAmC;AACzE,MAAI,CAAC,KAAM,QAAO;AAElB,MAAI;AACJ,MAAI;AACF,UAAM,IAAI,IAAI,UAAU,IAAI,EAAE;AAAA,EAChC,QAAQ;AACN,WAAO;AAAA,EACT;AAEA,MAAI,IAAI,YAAY,IAAI,YAAY,IAAI,aAAa,OAAO,IAAI,UAAU,IAAI,KAAM,QAAO;AAC3F,SAAO,mBAAmB,IAAI,QAAQ;AACxC;AAOO,SAAS,0BAA0B,QAAqC;AAC7E,MAAI,WAAW,OAAW,QAAO;AAEjC,MAAI;AACJ,MAAI;AACF,UAAM,IAAI,IAAI,MAAM;AAAA,EACtB,QAAQ;AACN,WAAO;AAAA,EACT;AAEA,MAAI,IAAI,aAAa,WAAW,IAAI,aAAa,SAAU,QAAO;AAClE,MAAI,IAAI,YAAY,IAAI,YAAY,IAAI,aAAa,OAAO,IAAI,UAAU,IAAI,KAAM,QAAO;AAE3F,SAAO,mBAAmB,IAAI,QAAQ;AACxC;AAGO,SAAS,2BACd,MACA,QACS;AACT,SAAO,wBAAwB,IAAI,KAAK,0BAA0B,MAAM;AAC1E;AAOO,SAAS,2BAA2B,OAAyC;AAClF,SAAO,CAAC,YAAY;AAClB,UAAM,OAAO,QAAQ,QAAQ,IAAI,MAAM,KAAK;AAC5C,UAAM,SAAS,QAAQ,QAAQ,IAAI,QAAQ,KAAK;AAChD,QAAI,CAAC,2BAA2B,MAAM,MAAM,GAAG;AAC7C,aAAO,SAAS;AAAA,QACd;AAAA,UACE,IAAI;AAAA,UACJ,OAAO;AAAA,YACL,MAAM;AAAA,YACN,SAAS;AAAA,UACX;AAAA,QACF;AAAA,QACA,EAAE,QAAQ,IAAI;AAAA,MAChB;AAAA,IACF;AACA,WAAO,MAAM,OAAO;AAAA,EACtB;AACF;AAeO,SAAS,UAAU,MAAyB;AACjD,MAAI,OAAO;AACX,MAAI,OAAO;AACX,MAAI;AACJ,MAAI,OAAO;AACX,MAAI,OAAO;AACX,MAAI,aAAuB,CAAC;AAC5B,MAAI,WAAW;AAEf,WAAS,IAAI,GAAG,IAAI,KAAK,QAAQ,KAAK;AACpC,UAAM,MAAM,KAAK,CAAC;AAClB,QAAI,QAAQ,YAAY,KAAK,IAAI,CAAC,GAAG;AACnC,aAAO,SAAS,KAAK,IAAI,CAAC,GAAG,EAAE;AAC/B;AAAA,IACF,WAAW,QAAQ,wBAAwB,KAAK,IAAI,CAAC,GAAG;AACtD,aAAO,KAAK,IAAI,CAAC;AACjB;AAAA,IACF,WAAW,QAAQ,cAAc,KAAK,IAAI,CAAC,GAAG;AAC5C,eAAS,KAAK,IAAI,CAAC;AACnB;AAAA,IACF,WAAW,QAAQ,kBAAkB,KAAK,IAAI,CAAC,GAAG;AAChD,mBAAa,KAAK,IAAI,CAAC,EACpB,MAAM,GAAG,EACT,IAAI,CAAC,MAAM,EAAE,KAAK,CAAC,EACnB,OAAO,OAAO;AACjB;AAAA,IACF,WAAW,QAAQ,UAAU;AAC3B,aAAO;AAAA,IACT,WAAW,QAAQ,iBAAiB,QAAQ,cAAc;AACxD,iBAAW;AAAA,IACb,WAAW,QAAQ,YAAY,QAAQ,MAAM;AAC3C,aAAO;AAAA,IACT;AAAA,EACF;AAEA,QAAM,SAAkB,EAAE,MAAM,MAAM,QAAQ,MAAM,MAAM,YAAY,SAAS;AAE/E,MAAI,MAAM,IAAI,KAAK,OAAO,KAAK,OAAO,OAAO;AAC3C,WAAO,YAAY,iBAAiB,IAAI;AAAA,EAC1C;AAEA,SAAO;AACT;;;AF7HA,eAAe,OAAO;AACpB,QAAM,OAAO,UAAU,QAAQ,IAAI;AAEnC,MAAI,KAAK,MAAM;AACb,YAAQ,IAAI;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,IAgBZ,kBAAkB,KAAK,UAAK,CAAC;AAAA;AAAA;AAAA,CAGhC;AACG,YAAQ,KAAK,CAAC;AAAA,EAChB;AAEA,MAAI,KAAK,WAAW;AAClB,YAAQ,MAAM,KAAK,SAAS;AAC5B,YAAQ,KAAK,CAAC;AAAA,EAChB;AAGA,MAAI;AACJ,MAAI,KAAK,QAAQ;AACf,iBAAa,QAAQ,QAAQ,IAAI,GAAG,KAAK,MAAM;AAC/C,QAAI,CAAC,WAAW,UAAU,GAAG;AAC3B,cAAQ,MAAM,0BAA0B,UAAU,EAAE;AACpD,cAAQ,KAAK,CAAC;AAAA,IAChB;AAAA,EACF,OAAO;AACL,UAAM,QAAQ,WAAW,QAAQ,IAAI,CAAC;AACtC,QAAI,CAAC,OAAO;AACV,cAAQ,MAAM,uCAAuC,kBAAkB,KAAK,IAAI,CAAC,EAAE;AACnF,cAAQ,MAAM,sEAAsE;AACpF,cAAQ,KAAK,CAAC;AAAA,IAChB;AACA,iBAAa;AAAA,EACf;AAOA,MAAI,KAAK,WAAW,SAAS,GAAG;AAC9B,QAAI;AACF,YAAM,aAAa,MAAM,OAAO,QAAa;AAC7C,YAAM,WAAW;AAAA,QACf,iBAAiB,KAAK,UAAU,KAAK,UAAU,CAAC;AAAA,QAChD;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,MACF,EAAE,KAAK,IAAI;AACX,iBAAW,SAAS,wBAAwB,mBAAmB,QAAQ,CAAC,EAAE;AAAA,IAC5E,QAAQ;AACN,cAAQ,KAAK,2DAA2D;AAAA,IAC1E;AAAA,EACF;AAEA,UAAQ,IAAI,oCAAoC,UAAU,EAAE;AAI5D,MAAI;AACJ,QAAM,MAAM,QAAQ,UAAU;AAC9B,MAAI;AACF,UAAM,MAAM,MAAM,aAAa,YAAY,YAAY,GAAG;AAE1D,cAAU,eAAe,GAAG;AAE5B,QAAI,CAAC,WAAW,OAAO,QAAQ,YAAY,YAAY;AACrD,cAAQ,MAAM,mDAAmD;AACjE,UAAI,SAAS;AACX,cAAM,OAAO,OAAO,KAAK,OAAiB,EACvC,MAAM,GAAG,CAAC,EACV,KAAK,IAAI;AACZ,gBAAQ,MAAM,UAAU,OAAO,OAAO,GAAG,OAAO,iBAAiB,IAAI,OAAO,EAAE,EAAE;AAAA,MAClF;AACA,cAAQ;AAAA,QACN;AAAA;AAAA;AAAA,MACF;AACA,cAAQ,KAAK,CAAC;AAAA,IAChB;AAAA,EACF,SAAS,KAAK;AACZ,UAAM,MAAM,eAAe,QAAQ,IAAI,UAAU,OAAO,GAAG;AAC3D,QACE,8FAA8F;AAAA,MAC5F;AAAA,IACF,GACA;AACA,cAAQ,MAAM,0EAA0E;AACxF,UAAI,QAAQ,SAAS,QAAQ,QAAQ;AACnC,gBAAQ;AAAA,UACN;AAAA,QACF;AAAA,MACF,OAAO;AACL,gBAAQ,MAAM,mDAAmD;AAAA,MACnE;AACA,cAAQ,MAAM;AAAA,IAChB;AACA,YAAQ,MAAM,0BAA0B,GAAG;AAC3C,YAAQ,KAAK,CAAC;AAAA,EAChB;AAGA,QAAM,aAAa,QAAQ,YAAY,WAAW,WAAW,QAAQ;AACrE,QAAM,kBAAkB,WAAW,QAAQ,YAAY,YAAY,CAAC;AAEpE,QAAM,EAAE,KAAK,iBAAiB,IAAI,aAAa;AAAA,IAC7C;AAAA,IACA,YAAY,kBAAkB,aAAa;AAAA,IAC3C,UAAU,KAAK;AAAA,IACf,MAAM;AAAA,EACR,CAAC;AAED,MAAI,KAAK,UAAU;AACjB,YAAQ,IAAI,6EAAwE;AAAA,EACtF;AAGA,QAAM,EAAE,iBAAiB,iBAAiB,IAAI,oBAAoB,EAAE,IAAI,CAAC;AACzE,QAAM,aAAa,iBAAiB;AACpC,MAAI,IAAI,OAAO,OAAO,GAAG,SAAS;AAChC,QAAI,CAAC,2BAA2B,EAAE,IAAI,OAAO,MAAM,GAAG,EAAE,IAAI,OAAO,QAAQ,CAAC,GAAG;AAC7E,aAAO,EAAE;AAAA,QACP;AAAA,UACE,IAAI;AAAA,UACJ,OAAO;AAAA,YACL,MAAM;AAAA,YACN,SAAS;AAAA,UACX;AAAA,QACF;AAAA,QACA;AAAA,MACF;AAAA,IACF;AACA,UAAM,KAAK;AAAA,EACb,CAAC;AACD,MAAI;AAAA,IACF;AAAA,IACA,iBAAiB,MAAM,UAAU;AAAA,EACnC;AAEA,QAAM,SAAS;AAAA,IACb;AAAA,MACE,OAAO,2BAA2B,CAAC,YAAY,IAAI,MAAM,OAAO,CAAC;AAAA,MACjE,MAAM,KAAK;AAAA,MACX,UAAU,KAAK;AAAA,IACjB;AAAA,IACA,CAAC,SAAS;AACR,cAAQ,IAAI,yCAAyC,eAAe,IAAI,KAAK,IAAI,EAAE;AACnF,cAAQ,IAAI,2BAA2B,QAAQ,iBAAiB,EAAE,KAAK,IAAI,KAAK,QAAQ,EAAE;AAC1F,cAAQ;AAAA,QACN,wBACE,QACG,UAAU,EACV,IAAI,CAAC,MAAM,EAAE,KAAK,EAClB,KAAK,IAAI,KAAK,QACnB;AAAA,MACF;AACA,cAAQ;AAAA,QACN,uBACE,QACG,SAAS,EACT,IAAI,CAAC,MAAM,EAAE,IAAI,EACjB,KAAK,IAAI,KAAK,QACnB;AAAA,MACF;AAEA,UAAI,CAAC,iBAAiB;AACpB,gBAAQ;AAAA,UACN;AAAA,QACF;AAAA,MACF;AAAA,IACF;AAAA,EACF;AAEA,kBAAgB,MAAM;AAEtB,MAAI,KAAK,SAAS,iBAAiB;AACjC,YAAQ;AAAA,MACN,oCAAoC,KAAK,IAAI;AAAA,IAE/C;AAAA,EACF;AAGA,MAAI,KAAK,MAAM;AACb,UAAM,MAAM,UAAU,eAAe,IAAI,KAAK,IAAI;AAClD,UAAM,EAAE,KAAK,IAAI,MAAM,OAAO,eAAoB;AAClD,UAAM,MACJ,QAAQ,aAAa,WAAW,SAAS,QAAQ,aAAa,UAAU,UAAU;AACpF,SAAK,GAAG,GAAG,IAAI,GAAG,EAAE;AAAA,EACtB;AAGA,QAAM,WAAW,YAAY;AAC3B,YAAQ,IAAI,iCAAiC;AAC7C,UAAM,QAAQ,SAAS,EAAE,MAAM,MAAM;AAAA,IAAC,CAAC;AACvC,YAAQ,KAAK,CAAC;AAAA,EAChB;AAEA,UAAQ,GAAG,UAAU,QAAQ;AAC7B,UAAQ,GAAG,WAAW,QAAQ;AAChC;AAEA,KAAK,EAAE,MAAM,CAAC,QAAQ;AACpB,UAAQ,MAAM,6BAA6B,GAAG;AAC9C,UAAQ,KAAK,CAAC;AAChB,CAAC;","names":[]}
1
+ {"version":3,"sources":["../src/cli.ts","../src/resolve-runtime.ts","../src/cli-utils.ts"],"sourcesContent":["#!/usr/bin/env node\nimport { resolve, extname } from 'node:path';\nimport { existsSync } from 'node:fs';\nimport { serve } from '@hono/node-server';\nimport { createNodeWebSocket } from '@hono/node-ws';\nimport { createServer } from './server/index.js';\nimport { resolveRuntime } from './resolve-runtime.js';\nimport {\n parseArgs,\n findConfig,\n importModule,\n CONFIG_CANDIDATES,\n STUDIO_CLI_HOST,\n isAllowedStandaloneRequest,\n withStandaloneRequestGuard,\n} from './cli-utils.js';\n\n// ── Main ────────────────────────────────────────────────────────────\n\nasync function main() {\n const args = parseArgs(process.argv);\n\n if (args.help) {\n console.log(`\nAxl Studio — Local development UI for Axl agents and workflows\n\nUsage:\n axl-studio [options]\n\nOptions:\n --port <number> Server port (default: 4400)\n --dangerously-bind <ip> Bind for a loopback-published container/local-forward tunnel\n --config <path> Path to config file (default: auto-detect)\n --conditions <list> Comma-separated Node.js import conditions (e.g., development)\n --read-only Disable all mutating endpoints (runs, imports, rescore, etc)\n --open Auto-open browser\n -h, --help Show this help message\n\nConfig auto-detection order:\n ${CONFIG_CANDIDATES.join(' → ')}\n\nTip: Use .mts for configs with top-level await or in projects without \"type\": \"module\".\n`);\n process.exit(0);\n }\n\n if (args.portError) {\n console.error(args.portError);\n process.exit(1);\n }\n\n // Resolve config path: explicit --config or auto-detect\n let configPath: string;\n if (args.config) {\n configPath = resolve(process.cwd(), args.config);\n if (!existsSync(configPath)) {\n console.error(`Config file not found: ${configPath}`);\n process.exit(1);\n }\n } else {\n const found = findConfig(process.cwd());\n if (!found) {\n console.error(`No config file found. Searched for: ${CONFIG_CANDIDATES.join(', ')}`);\n console.error(`Create an axl.config.mts that exports a default AxlRuntime instance.`);\n process.exit(1);\n }\n configPath = found;\n }\n\n // Register custom import conditions (e.g., --conditions development).\n // In monorepos, package.json \"exports\" often use the \"development\" condition\n // to point at source (.ts) instead of built dist. Without this, Studio\n // configs that import workspace packages resolve to dist files, which may\n // not exist or be stale.\n if (args.conditions.length > 0) {\n try {\n const nodeModule = await import('node:module');\n const hookCode = [\n `const extra = ${JSON.stringify(args.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: this Node.js runtime does not support --conditions`);\n }\n }\n\n console.log(`[axl-studio] Loading config from ${configPath}`);\n\n // Import the user's config via tsImport (handles ESM/CJS correctly for\n // TypeScript files without process-wide side effects)\n let runtime: import('@axlsdk/axl').AxlRuntime;\n const ext = extname(configPath);\n try {\n const mod = await importModule(configPath, import.meta.url);\n // resolveRuntime handles ESM default, CJS-to-ESM interop, and named exports\n runtime = resolveRuntime(mod) as typeof runtime;\n\n if (!runtime || typeof runtime.execute !== 'function') {\n console.error(`Config must export a default AxlRuntime instance.`);\n if (runtime) {\n const keys = Object.keys(runtime as object)\n .slice(0, 5)\n .join(', ');\n console.error(` Got: ${typeof runtime}${keys ? ` with keys: { ${keys} }` : ''}`);\n }\n console.error(\n `Example:\\n import { AxlRuntime } from '@axlsdk/axl';\\n export default new AxlRuntime({ ... });`,\n );\n process.exit(1);\n }\n } catch (err) {\n const msg = err instanceof Error ? err.message : String(err);\n if (\n /Cannot use import statement|Unexpected reserved word|top-level await|exports is not defined/.test(\n msg,\n )\n ) {\n console.error(`[axl-studio] Config failed to load due to a CJS/ESM compatibility issue.`);\n if (ext === '.ts' || ext === '.tsx') {\n console.error(\n ` Tip: try renaming to .mts to force ESM format, or ensure tsx is installed and up to date.`,\n );\n } else {\n console.error(` Tip: add \"type\": \"module\" to your package.json.`);\n }\n console.error();\n }\n console.error(`Failed to load config:`, err);\n process.exit(1);\n }\n\n // Determine static root for pre-built SPA\n const staticRoot = resolve(import.meta.dirname ?? __dirname, 'client');\n const hasStaticAssets = existsSync(resolve(staticRoot, 'index.html'));\n\n const { app, createWsHandlers } = createServer({\n runtime,\n staticRoot: hasStaticAssets ? staticRoot : undefined,\n readOnly: args.readOnly,\n cors: false,\n });\n\n if (args.readOnly) {\n console.log('[axl-studio] Read-only mode enabled — mutating endpoints are disabled.');\n }\n\n // Set up WebSocket\n const { injectWebSocket, upgradeWebSocket } = createNodeWebSocket({ app });\n const wsHandlers = createWsHandlers();\n app.use('/ws', async (c, next) => {\n if (!isAllowedStandaloneRequest(c.req.header('Host'), c.req.header('Origin'))) {\n return c.json(\n {\n ok: false,\n error: {\n code: 'FORBIDDEN_HOST_ORIGIN',\n message: 'Standalone Studio accepts WebSocket connections only locally',\n },\n },\n 403,\n );\n }\n await next();\n });\n app.get(\n '/ws',\n upgradeWebSocket(() => wsHandlers),\n );\n\n const server = serve(\n {\n fetch: withStandaloneRequestGuard((request) => app.fetch(request)),\n port: args.port,\n hostname: args.host,\n },\n (info) => {\n console.log(`[axl-studio] Server running at http://${STUDIO_CLI_HOST}:${info.port}`);\n console.log(`[axl-studio] Workflows: ${runtime.getWorkflowNames().join(', ') || '(none)'}`);\n console.log(\n `[axl-studio] Agents: ${\n runtime\n .getAgents()\n .map((a) => a._name)\n .join(', ') || '(none)'\n }`,\n );\n console.log(\n `[axl-studio] Tools: ${\n runtime\n .getTools()\n .map((t) => t.name)\n .join(', ') || '(none)'\n }`,\n );\n\n if (!hasStaticAssets) {\n console.log(\n `[axl-studio] No pre-built UI found. Run 'pnpm build:client' or use Vite dev server on port 4401.`,\n );\n }\n },\n );\n\n injectWebSocket(server);\n\n if (args.host !== STUDIO_CLI_HOST) {\n console.warn(\n `[axl-studio] WARNING: binding to ${args.host}. Use this only behind a local-only ` +\n 'container port mapping or local-forward tunnel; standalone Studio remains unauthenticated.',\n );\n }\n\n // Auto-open browser\n if (args.open) {\n const url = `http://${STUDIO_CLI_HOST}:${args.port}`;\n const { exec } = await import('node:child_process');\n const cmd =\n process.platform === 'darwin' ? 'open' : process.platform === 'win32' ? 'start' : 'xdg-open';\n exec(`${cmd} ${url}`);\n }\n\n // Graceful shutdown\n const shutdown = async () => {\n console.log('\\n[axl-studio] Shutting down...');\n await runtime.shutdown().catch(() => {});\n process.exit(0);\n };\n\n process.on('SIGINT', shutdown);\n process.on('SIGTERM', shutdown);\n}\n\nmain().catch((err) => {\n console.error('[axl-studio] Fatal error:', err);\n process.exit(1);\n});\n","/**\n * Re-exports of module-resolution helpers from `@axlsdk/axl`.\n *\n * Studio used to keep its own copy of these (alongside the duplicated copy in\n * `@axlsdk/eval`'s cli-utils). They've been lifted to `@axlsdk/axl` so a fix\n * to the ESM/CJS chain walk applies to all three consumers atomically. Kept\n * as a re-export rather than a deletion so existing imports still work and\n * the test file at `__tests__/resolve-runtime.test.ts` continues to function\n * as a tripwire on this module's path.\n */\nexport { resolveRuntime, pickDefault, pickExport } from '@axlsdk/axl';\n","/**\n * CLI utilities for `axl-studio`.\n *\n * Loader / glob / config-detection helpers now live in `@axlsdk/axl`'s\n * `cli-internals` (shared with `@axlsdk/eval` so fixes apply atomically);\n * this file holds the studio-specific arg parser and re-exports what\n * dependent modules consume.\n */\n\nexport { CONFIG_CANDIDATES, findConfig, needsTsxLoader, importModule } from '@axlsdk/axl';\n\n/** Standalone Studio is an unauthenticated local-development surface. */\nexport const STUDIO_CLI_HOST = '127.0.0.1';\n\ntype StandaloneFetch = (request: Request) => Response | Promise<Response>;\n\nfunction isLoopbackHostname(hostname: string): boolean {\n return hostname === 'localhost' || hostname === 'localhost.' || hostname === '127.0.0.1';\n}\n\n/** Reject DNS-rebinding Host values before standalone Studio serves admin data. */\nexport function isAllowedStandaloneHost(host: string | undefined): boolean {\n if (!host) return false;\n\n let url: URL;\n try {\n url = new URL(`http://${host}`);\n } catch {\n return false;\n }\n\n if (url.username || url.password || url.pathname !== '/' || url.search || url.hash) return false;\n return isLoopbackHostname(url.hostname);\n}\n\n/**\n * Browser WebSocket handshakes carry an Origin header even though they are not\n * governed by CORS. Standalone Studio accepts only local browser origins; CLI\n * and other non-browser clients may omit Origin.\n */\nexport function isAllowedStandaloneOrigin(origin: string | undefined): boolean {\n if (origin === undefined) return true;\n\n let url: URL;\n try {\n url = new URL(origin);\n } catch {\n return false;\n }\n\n if (url.protocol !== 'http:' && url.protocol !== 'https:') return false;\n if (url.username || url.password || url.pathname !== '/' || url.search || url.hash) return false;\n\n return isLoopbackHostname(url.hostname);\n}\n\n/** Standalone Studio accepts only loopback authorities and local/absent origins. */\nexport function isAllowedStandaloneRequest(\n host: string | undefined,\n origin: string | undefined,\n): boolean {\n return isAllowedStandaloneHost(host) && isAllowedStandaloneOrigin(origin);\n}\n\n/**\n * Guard the standalone HTTP boundary before Hono routing. This blocks hostile\n * simple POSTs as well as DNS-rebinding reads, and is intentionally separate\n * from CORS response headers.\n */\nexport function withStandaloneRequestGuard(fetch: StandaloneFetch): StandaloneFetch {\n return (request) => {\n const host = request.headers.get('host') ?? undefined;\n const origin = request.headers.get('origin') ?? undefined;\n if (!isAllowedStandaloneRequest(host, origin)) {\n return Response.json(\n {\n ok: false,\n error: {\n code: 'FORBIDDEN_HOST_ORIGIN',\n message: 'Standalone Studio accepts requests only through a local host and origin',\n },\n },\n { status: 403 },\n );\n }\n return fetch(request);\n };\n}\n\n// ── Parse CLI args ──────────────────────────────────────────────────\n\nexport interface CliArgs {\n port: number;\n host: string;\n config?: string;\n open: boolean;\n conditions: string[];\n readOnly: boolean;\n help: boolean;\n portError?: string;\n}\n\nexport function parseArgs(argv: string[]): CliArgs {\n let port = 4400;\n let host = STUDIO_CLI_HOST;\n let config: string | undefined;\n let open = false;\n let help = false;\n let conditions: string[] = [];\n let readOnly = false;\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 === '--dangerously-bind' && argv[i + 1]) {\n host = argv[i + 1];\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 === '--read-only' || arg === '--readonly') {\n readOnly = true;\n } else if (arg === '--help' || arg === '-h') {\n help = true;\n }\n }\n\n const result: CliArgs = { port, host, config, open, help, conditions, readOnly };\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"],"mappings":"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","names":[]}