@axlsdk/studio 0.20.1 → 0.21.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +29 -7
- package/dist/{chunk-KQ3HBRTC.js → chunk-YGLWYDQ3.js} +11 -4
- package/dist/chunk-YGLWYDQ3.js.map +1 -0
- package/dist/cli.cjs +92 -9
- package/dist/cli.cjs.map +1 -1
- package/dist/cli.js +83 -7
- package/dist/cli.js.map +1 -1
- package/dist/middleware.cjs +18 -5
- package/dist/middleware.cjs.map +1 -1
- package/dist/middleware.d.cts +8 -0
- package/dist/middleware.d.ts +8 -0
- package/dist/middleware.js +9 -3
- package/dist/middleware.js.map +1 -1
- package/dist/server/index.cjs +10 -3
- package/dist/server/index.cjs.map +1 -1
- package/dist/server/index.d.cts +1 -1
- package/dist/server/index.d.ts +1 -1
- package/dist/server/index.js +1 -1
- package/package.json +4 -4
- package/dist/chunk-KQ3HBRTC.js.map +0 -1
package/dist/cli.js
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
2
|
import {
|
|
3
3
|
createServer
|
|
4
|
-
} from "./chunk-
|
|
4
|
+
} from "./chunk-YGLWYDQ3.js";
|
|
5
5
|
|
|
6
6
|
// src/cli.ts
|
|
7
7
|
import { resolve, extname } from "path";
|
|
@@ -14,8 +14,58 @@ import { resolveRuntime, pickDefault, pickExport } from "@axlsdk/axl";
|
|
|
14
14
|
|
|
15
15
|
// src/cli-utils.ts
|
|
16
16
|
import { CONFIG_CANDIDATES, findConfig, needsTsxLoader, importModule } from "@axlsdk/axl";
|
|
17
|
+
var STUDIO_CLI_HOST = "127.0.0.1";
|
|
18
|
+
function isLoopbackHostname(hostname) {
|
|
19
|
+
return hostname === "localhost" || hostname === "localhost." || hostname === "127.0.0.1";
|
|
20
|
+
}
|
|
21
|
+
function isAllowedStandaloneHost(host) {
|
|
22
|
+
if (!host) return false;
|
|
23
|
+
let url;
|
|
24
|
+
try {
|
|
25
|
+
url = new URL(`http://${host}`);
|
|
26
|
+
} catch {
|
|
27
|
+
return false;
|
|
28
|
+
}
|
|
29
|
+
if (url.username || url.password || url.pathname !== "/" || url.search || url.hash) return false;
|
|
30
|
+
return isLoopbackHostname(url.hostname);
|
|
31
|
+
}
|
|
32
|
+
function isAllowedStandaloneOrigin(origin) {
|
|
33
|
+
if (origin === void 0) return true;
|
|
34
|
+
let url;
|
|
35
|
+
try {
|
|
36
|
+
url = new URL(origin);
|
|
37
|
+
} catch {
|
|
38
|
+
return false;
|
|
39
|
+
}
|
|
40
|
+
if (url.protocol !== "http:" && url.protocol !== "https:") return false;
|
|
41
|
+
if (url.username || url.password || url.pathname !== "/" || url.search || url.hash) return false;
|
|
42
|
+
return isLoopbackHostname(url.hostname);
|
|
43
|
+
}
|
|
44
|
+
function isAllowedStandaloneRequest(host, origin) {
|
|
45
|
+
return isAllowedStandaloneHost(host) && isAllowedStandaloneOrigin(origin);
|
|
46
|
+
}
|
|
47
|
+
function withStandaloneRequestGuard(fetch) {
|
|
48
|
+
return (request) => {
|
|
49
|
+
const host = request.headers.get("host") ?? void 0;
|
|
50
|
+
const origin = request.headers.get("origin") ?? void 0;
|
|
51
|
+
if (!isAllowedStandaloneRequest(host, origin)) {
|
|
52
|
+
return Response.json(
|
|
53
|
+
{
|
|
54
|
+
ok: false,
|
|
55
|
+
error: {
|
|
56
|
+
code: "FORBIDDEN_HOST_ORIGIN",
|
|
57
|
+
message: "Standalone Studio accepts requests only through a local host and origin"
|
|
58
|
+
}
|
|
59
|
+
},
|
|
60
|
+
{ status: 403 }
|
|
61
|
+
);
|
|
62
|
+
}
|
|
63
|
+
return fetch(request);
|
|
64
|
+
};
|
|
65
|
+
}
|
|
17
66
|
function parseArgs(argv) {
|
|
18
67
|
let port = 4400;
|
|
68
|
+
let host = STUDIO_CLI_HOST;
|
|
19
69
|
let config;
|
|
20
70
|
let open = false;
|
|
21
71
|
let help = false;
|
|
@@ -26,6 +76,9 @@ function parseArgs(argv) {
|
|
|
26
76
|
if (arg === "--port" && argv[i + 1]) {
|
|
27
77
|
port = parseInt(argv[i + 1], 10);
|
|
28
78
|
i++;
|
|
79
|
+
} else if (arg === "--dangerously-bind" && argv[i + 1]) {
|
|
80
|
+
host = argv[i + 1];
|
|
81
|
+
i++;
|
|
29
82
|
} else if (arg === "--config" && argv[i + 1]) {
|
|
30
83
|
config = argv[i + 1];
|
|
31
84
|
i++;
|
|
@@ -40,7 +93,7 @@ function parseArgs(argv) {
|
|
|
40
93
|
help = true;
|
|
41
94
|
}
|
|
42
95
|
}
|
|
43
|
-
const result = { port, config, open, help, conditions, readOnly };
|
|
96
|
+
const result = { port, host, config, open, help, conditions, readOnly };
|
|
44
97
|
if (isNaN(port) || port < 1 || port > 65535) {
|
|
45
98
|
result.portError = `Invalid port: ${port}. Must be between 1 and 65535.`;
|
|
46
99
|
}
|
|
@@ -59,6 +112,7 @@ Usage:
|
|
|
59
112
|
|
|
60
113
|
Options:
|
|
61
114
|
--port <number> Server port (default: 4400)
|
|
115
|
+
--dangerously-bind <ip> Bind for a loopback-published container/local-forward tunnel
|
|
62
116
|
--config <path> Path to config file (default: auto-detect)
|
|
63
117
|
--conditions <list> Comma-separated Node.js import conditions (e.g., development)
|
|
64
118
|
--read-only Disable all mutating endpoints (runs, imports, rescore, etc)
|
|
@@ -151,24 +205,41 @@ Tip: Use .mts for configs with top-level await or in projects without "type": "m
|
|
|
151
205
|
const { app, createWsHandlers } = createServer({
|
|
152
206
|
runtime,
|
|
153
207
|
staticRoot: hasStaticAssets ? staticRoot : void 0,
|
|
154
|
-
readOnly: args.readOnly
|
|
208
|
+
readOnly: args.readOnly,
|
|
209
|
+
cors: false
|
|
155
210
|
});
|
|
156
211
|
if (args.readOnly) {
|
|
157
212
|
console.log("[axl-studio] Read-only mode enabled \u2014 mutating endpoints are disabled.");
|
|
158
213
|
}
|
|
159
214
|
const { injectWebSocket, upgradeWebSocket } = createNodeWebSocket({ app });
|
|
160
215
|
const wsHandlers = createWsHandlers();
|
|
216
|
+
app.use("/ws", async (c, next) => {
|
|
217
|
+
if (!isAllowedStandaloneRequest(c.req.header("Host"), c.req.header("Origin"))) {
|
|
218
|
+
return c.json(
|
|
219
|
+
{
|
|
220
|
+
ok: false,
|
|
221
|
+
error: {
|
|
222
|
+
code: "FORBIDDEN_HOST_ORIGIN",
|
|
223
|
+
message: "Standalone Studio accepts WebSocket connections only locally"
|
|
224
|
+
}
|
|
225
|
+
},
|
|
226
|
+
403
|
|
227
|
+
);
|
|
228
|
+
}
|
|
229
|
+
await next();
|
|
230
|
+
});
|
|
161
231
|
app.get(
|
|
162
232
|
"/ws",
|
|
163
233
|
upgradeWebSocket(() => wsHandlers)
|
|
164
234
|
);
|
|
165
235
|
const server = serve(
|
|
166
236
|
{
|
|
167
|
-
fetch: app.fetch,
|
|
168
|
-
port: args.port
|
|
237
|
+
fetch: withStandaloneRequestGuard((request) => app.fetch(request)),
|
|
238
|
+
port: args.port,
|
|
239
|
+
hostname: args.host
|
|
169
240
|
},
|
|
170
241
|
(info) => {
|
|
171
|
-
console.log(`[axl-studio] Server running at http
|
|
242
|
+
console.log(`[axl-studio] Server running at http://${STUDIO_CLI_HOST}:${info.port}`);
|
|
172
243
|
console.log(`[axl-studio] Workflows: ${runtime.getWorkflowNames().join(", ") || "(none)"}`);
|
|
173
244
|
console.log(
|
|
174
245
|
`[axl-studio] Agents: ${runtime.getAgents().map((a) => a._name).join(", ") || "(none)"}`
|
|
@@ -184,8 +255,13 @@ Tip: Use .mts for configs with top-level await or in projects without "type": "m
|
|
|
184
255
|
}
|
|
185
256
|
);
|
|
186
257
|
injectWebSocket(server);
|
|
258
|
+
if (args.host !== STUDIO_CLI_HOST) {
|
|
259
|
+
console.warn(
|
|
260
|
+
`[axl-studio] WARNING: binding to ${args.host}. Use this only behind a local-only container port mapping or local-forward tunnel; standalone Studio remains unauthenticated.`
|
|
261
|
+
);
|
|
262
|
+
}
|
|
187
263
|
if (args.open) {
|
|
188
|
-
const url = `http
|
|
264
|
+
const url = `http://${STUDIO_CLI_HOST}:${args.port}`;
|
|
189
265
|
const { exec } = await import("child_process");
|
|
190
266
|
const cmd = process.platform === "darwin" ? "open" : process.platform === "win32" ? "start" : "xdg-open";
|
|
191
267
|
exec(`${cmd} ${url}`);
|
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 { parseArgs, findConfig, importModule, CONFIG_CANDIDATES } 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 --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 });\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.get(\n '/ws',\n upgradeWebSocket(() => wsHandlers),\n );\n\n const server = serve(\n {\n fetch: app.fetch,\n port: args.port,\n },\n (info) => {\n console.log(`[axl-studio] Server running at http://localhost:${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 // Auto-open browser\n if (args.open) {\n const url = `http://localhost:${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// ── Parse CLI args ──────────────────────────────────────────────────\n\nexport interface CliArgs {\n port: number;\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 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 === '--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, 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":[]}
|
|
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":"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","names":[]}
|
package/dist/middleware.cjs
CHANGED
|
@@ -1399,7 +1399,10 @@ function createSessionRoutes(connMgr) {
|
|
|
1399
1399
|
const body = await c.req.json();
|
|
1400
1400
|
const session = runtime.session(id);
|
|
1401
1401
|
const result = await session.send(body.workflow, body.message);
|
|
1402
|
-
return c.json({
|
|
1402
|
+
return c.json({
|
|
1403
|
+
ok: true,
|
|
1404
|
+
data: { result: redactValue(result, runtime.isRedactEnabled()) }
|
|
1405
|
+
});
|
|
1403
1406
|
});
|
|
1404
1407
|
app5.post("/sessions/:id/stream", async (c) => {
|
|
1405
1408
|
const runtime = c.get("runtime");
|
|
@@ -1408,9 +1411,13 @@ function createSessionRoutes(connMgr) {
|
|
|
1408
1411
|
const session = runtime.session(id);
|
|
1409
1412
|
const stream = await session.stream(body.workflow, body.message);
|
|
1410
1413
|
const executionId = `session-${id}-${Date.now()}`;
|
|
1414
|
+
const redactOn = runtime.isRedactEnabled();
|
|
1411
1415
|
(async () => {
|
|
1412
1416
|
for await (const event of stream) {
|
|
1413
|
-
connMgr.broadcastWithWildcard(
|
|
1417
|
+
connMgr.broadcastWithWildcard(
|
|
1418
|
+
`execution:${executionId}`,
|
|
1419
|
+
redactStreamEvent(event, redactOn)
|
|
1420
|
+
);
|
|
1414
1421
|
}
|
|
1415
1422
|
})();
|
|
1416
1423
|
return c.json({ ok: true, data: { executionId, streaming: true } });
|
|
@@ -16116,7 +16123,7 @@ function createServer(options) {
|
|
|
16116
16123
|
emptyState: emptyEvalTrendData,
|
|
16117
16124
|
windows
|
|
16118
16125
|
});
|
|
16119
|
-
if (options.cors
|
|
16126
|
+
if (options.cors === true) {
|
|
16120
16127
|
app5.use("*", (0, import_cors.cors)());
|
|
16121
16128
|
}
|
|
16122
16129
|
app5.onError(errorHandler);
|
|
@@ -16392,6 +16399,7 @@ function createStudioMiddleware(options) {
|
|
|
16392
16399
|
runtime,
|
|
16393
16400
|
serveClient = true,
|
|
16394
16401
|
verifyUpgrade,
|
|
16402
|
+
dangerouslyAllowUnauthenticatedWebSockets = false,
|
|
16395
16403
|
readOnly = false,
|
|
16396
16404
|
filterTraceEvent
|
|
16397
16405
|
} = options;
|
|
@@ -16417,9 +16425,9 @@ function createStudioMiddleware(options) {
|
|
|
16417
16425
|
if (filterTraceEvent) {
|
|
16418
16426
|
connMgr.setFilter(filterTraceEvent);
|
|
16419
16427
|
}
|
|
16420
|
-
if (process.env.NODE_ENV === "production" && !verifyUpgrade) {
|
|
16428
|
+
if (process.env.NODE_ENV === "production" && !verifyUpgrade && !dangerouslyAllowUnauthenticatedWebSockets) {
|
|
16421
16429
|
console.warn(
|
|
16422
|
-
"[axl-studio] WARNING: Studio middleware mounted in production without verifyUpgrade.
|
|
16430
|
+
"[axl-studio] WARNING: Studio middleware mounted in production without verifyUpgrade. upgradeWebSocket() will refuse to attach. Provide verifyUpgrade or explicitly set dangerouslyAllowUnauthenticatedWebSockets: true only when an outer upgrade gate is guaranteed."
|
|
16423
16431
|
);
|
|
16424
16432
|
}
|
|
16425
16433
|
const listener = (0, import_node_server.getRequestListener)(app5.fetch, {
|
|
@@ -16481,6 +16489,11 @@ function createStudioMiddleware(options) {
|
|
|
16481
16489
|
let upgradeHandler;
|
|
16482
16490
|
let serverRef;
|
|
16483
16491
|
function upgradeWebSocket(server, path) {
|
|
16492
|
+
if (process.env.NODE_ENV === "production" && !verifyUpgrade && !dangerouslyAllowUnauthenticatedWebSockets) {
|
|
16493
|
+
throw new Error(
|
|
16494
|
+
"[axl-studio] Refusing unauthenticated WebSocket upgrades in production. Provide verifyUpgrade or explicitly set dangerouslyAllowUnauthenticatedWebSockets: true."
|
|
16495
|
+
);
|
|
16496
|
+
}
|
|
16484
16497
|
if (wss) {
|
|
16485
16498
|
throw new Error(
|
|
16486
16499
|
"[axl-studio] upgradeWebSocket() has already been called. Call close() first if you need to re-attach."
|