@mindstudio-ai/local-model-tunnel 0.5.20 → 0.5.22
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/{chunk-2SAYHQSZ.js → chunk-ENSNEBJJ.js} +7 -6
- package/dist/chunk-ENSNEBJJ.js.map +1 -0
- package/dist/{chunk-LLIAITJF.js → chunk-TMIU4S53.js} +2 -2
- package/dist/{chunk-RH4AYDSL.js → chunk-VJTZSOKC.js} +49 -1
- package/dist/{chunk-RH4AYDSL.js.map → chunk-VJTZSOKC.js.map} +1 -1
- package/dist/cli.js +1 -1
- package/dist/headless.js +2 -2
- package/dist/index.js +3 -3
- package/dist/{tui-GT26IIIW.js → tui-ZUGRCB5V.js} +6 -6
- package/package.json +1 -1
- package/dist/chunk-2SAYHQSZ.js.map +0 -1
- /package/dist/{chunk-LLIAITJF.js.map → chunk-TMIU4S53.js.map} +0 -0
- /package/dist/{tui-GT26IIIW.js.map → tui-ZUGRCB5V.js.map} +0 -0
|
@@ -22,7 +22,7 @@ import {
|
|
|
22
22
|
syncSchema,
|
|
23
23
|
watchConfigFile,
|
|
24
24
|
watchTableFiles
|
|
25
|
-
} from "./chunk-
|
|
25
|
+
} from "./chunk-VJTZSOKC.js";
|
|
26
26
|
|
|
27
27
|
// src/dev/session-events.ts
|
|
28
28
|
function subscribeDevEvents(emit2, shutdown) {
|
|
@@ -129,6 +129,7 @@ async function handleRunMethod(state, cwd, cmd, emit2) {
|
|
|
129
129
|
emit2("command-error", { message: `Unknown method: ${methodName}` });
|
|
130
130
|
return;
|
|
131
131
|
}
|
|
132
|
+
emit2("method-run-started", { method: method.export });
|
|
132
133
|
const result = await state.runner.runMethod({
|
|
133
134
|
methodExport: method.export,
|
|
134
135
|
methodPath: method.path,
|
|
@@ -216,7 +217,7 @@ async function handleScreenshot(state, emit2) {
|
|
|
216
217
|
}
|
|
217
218
|
try {
|
|
218
219
|
const startTime = Date.now();
|
|
219
|
-
const result = await state.proxy.dispatchBrowserCommand([{ command: "screenshot" }]);
|
|
220
|
+
const result = await state.proxy.dispatchBrowserCommand([{ command: "screenshot" }], 12e4);
|
|
220
221
|
const stepResult = result.steps?.[0]?.result;
|
|
221
222
|
if (!stepResult?.image) {
|
|
222
223
|
fail("Screenshot capture returned no image data");
|
|
@@ -226,15 +227,15 @@ async function handleScreenshot(state, emit2) {
|
|
|
226
227
|
const { uploadUrl, uploadFields, publicUrl } = await getUploadUrl(
|
|
227
228
|
state.appConfig.appId,
|
|
228
229
|
session.sessionId,
|
|
229
|
-
"
|
|
230
|
-
"image/
|
|
230
|
+
"jpg",
|
|
231
|
+
"image/jpeg"
|
|
231
232
|
);
|
|
232
233
|
const imageBuffer = Buffer.from(stepResult.image, "base64");
|
|
233
234
|
const form = new FormData();
|
|
234
235
|
for (const [key, value] of Object.entries(uploadFields)) {
|
|
235
236
|
form.append(key, value);
|
|
236
237
|
}
|
|
237
|
-
form.append("file", new Blob([imageBuffer], { type: "image/
|
|
238
|
+
form.append("file", new Blob([imageBuffer], { type: "image/jpeg" }), "screenshot.jpg");
|
|
238
239
|
const uploadResult = await fetch(uploadUrl, { method: "POST", body: form });
|
|
239
240
|
if (!uploadResult.ok) {
|
|
240
241
|
fail(`S3 upload failed: ${uploadResult.status}`);
|
|
@@ -534,4 +535,4 @@ async function startHeadless(opts = {}) {
|
|
|
534
535
|
export {
|
|
535
536
|
startHeadless
|
|
536
537
|
};
|
|
537
|
-
//# sourceMappingURL=chunk-
|
|
538
|
+
//# sourceMappingURL=chunk-ENSNEBJJ.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/dev/session-events.ts","../src/dev/stdin-commands/run-scenario.ts","../src/dev/stdin-commands/run-method.ts","../src/dev/stdin-commands/impersonate.ts","../src/dev/stdin-commands/browser.ts","../src/dev/stdin-commands/screenshot.ts","../src/dev/stdin-commands/dev-server-restarting.ts","../src/dev/stdin-commands/browser-status.ts","../src/dev/stdin-commands/reset-browser.ts","../src/dev/stdin-commands/index.ts","../src/headless.ts"],"sourcesContent":["/**\n * Subscribe to DevRunner events and relay them as JSON to stdout.\n * Returns an array of unsubscribe functions for cleanup on teardown.\n */\n\nimport { devRequestEvents } from './events';\n\ntype EmitFn = (event: string, data?: Record<string, unknown>) => void;\n\nexport function subscribeDevEvents(\n emit: EmitFn,\n shutdown: () => Promise<void>,\n): Array<() => void> {\n const unsubs: Array<() => void> = [];\n\n unsubs.push(\n devRequestEvents.onStart((event) => {\n emit('method-started', { id: event.id, method: event.method });\n }),\n );\n\n unsubs.push(\n devRequestEvents.onComplete((event) => {\n emit('method-completed', {\n id: event.id,\n success: event.success,\n duration: event.duration,\n ...(event.error ? { error: event.error } : {}),\n });\n }),\n );\n\n unsubs.push(\n devRequestEvents.onConnectionWarning((message) => {\n emit('connection-lost', { message });\n }),\n );\n\n unsubs.push(\n devRequestEvents.onConnectionRestored(() => {\n emit('connection-restored');\n }),\n );\n\n unsubs.push(\n devRequestEvents.onSessionExpired(() => {\n emit('session-expired');\n shutdown().then(() => process.exit(1));\n }),\n );\n\n unsubs.push(\n devRequestEvents.onAuthRefreshStart((url) => {\n emit('auth-refresh-start', { url });\n }),\n );\n\n unsubs.push(\n devRequestEvents.onAuthRefreshSuccess(() => {\n emit('auth-refresh-success');\n }),\n );\n\n unsubs.push(\n devRequestEvents.onAuthRefreshFailed(() => {\n emit('auth-refresh-failed');\n }),\n );\n\n unsubs.push(\n devRequestEvents.onImpersonate((event) => {\n emit('impersonation-changed', { roles: event.roles });\n }),\n );\n\n unsubs.push(\n devRequestEvents.onScenarioStart((event) => {\n emit('scenario-started', { id: event.id, name: event.name });\n }),\n );\n\n unsubs.push(\n devRequestEvents.onScenarioComplete((event) => {\n emit('scenario-completed', {\n id: event.id,\n success: event.success,\n duration: event.duration,\n roles: event.roles,\n ...(event.error ? { error: event.error } : {}),\n });\n }),\n );\n\n return unsubs;\n}\n","import { detectAppConfig } from '../app-config';\nimport type { SessionState, EmitFn } from './types';\n\nexport async function handleRunScenario(\n state: SessionState,\n cwd: string,\n cmd: Record<string, unknown>,\n emit: EmitFn,\n): Promise<void> {\n if (!state.runner) {\n emit('command-error', { message: 'No active session' });\n return;\n }\n const freshConfig = detectAppConfig(cwd) ?? state.appConfig;\n const scenario = freshConfig?.scenarios.find((s) => s.id === cmd.scenarioId);\n if (!scenario) {\n emit('command-error', { message: `Unknown scenario: ${cmd.scenarioId}` });\n return;\n }\n await state.runner.runScenario(scenario);\n}\n","import { detectAppConfig } from '../app-config';\nimport type { SessionState, EmitFn } from './types';\n\nexport async function handleRunMethod(\n state: SessionState,\n cwd: string,\n cmd: Record<string, unknown>,\n emit: EmitFn,\n): Promise<void> {\n if (!state.runner) {\n emit('command-error', { message: 'No active session' });\n return;\n }\n const methodName = cmd.method as string;\n if (!methodName) {\n emit('command-error', { message: 'run-method requires \"method\" (export name or ID)' });\n return;\n }\n const freshConfig = detectAppConfig(cwd) ?? state.appConfig;\n const method =\n freshConfig?.methods.find((m) => m.export === methodName) ??\n freshConfig?.methods.find((m) => m.id === methodName);\n if (!method) {\n emit('command-error', { message: `Unknown method: ${methodName}` });\n return;\n }\n emit('method-run-started', { method: method.export });\n const result = await state.runner.runMethod({\n methodExport: method.export,\n methodPath: method.path,\n input: cmd.input ?? {},\n });\n emit('method-run-completed', {\n method: method.export,\n success: result.success,\n output: result.output ?? null,\n error: result.error ?? null,\n stdout: result.stdout ?? [],\n duration: result.duration,\n });\n}\n","import type { SessionState, EmitFn } from './types';\n\nexport async function handleImpersonate(\n state: SessionState,\n cmd: Record<string, unknown>,\n emit: EmitFn,\n): Promise<void> {\n if (!state.runner) {\n emit('command-error', { message: 'No active session' });\n return;\n }\n const roles = cmd.roles as string[];\n if (!Array.isArray(roles)) {\n emit('command-error', { message: 'impersonate requires roles array' });\n return;\n }\n await state.runner.setImpersonation(roles);\n}\n\nexport async function handleClearImpersonation(\n state: SessionState,\n emit: EmitFn,\n): Promise<void> {\n if (!state.runner) {\n emit('command-error', { message: 'No active session' });\n return;\n }\n await state.runner.clearImpersonation();\n}\n","import type { SessionState, EmitFn } from './types';\n\nexport async function handleBrowser(\n state: SessionState,\n cmd: Record<string, unknown>,\n emit: EmitFn,\n): Promise<void> {\n if (!state.proxy) {\n emit('command-error', { message: 'No active proxy — browser commands require a web interface' });\n return;\n }\n const steps = cmd.steps as Array<Record<string, unknown>>;\n if (!Array.isArray(steps) || steps.length === 0) {\n emit('command-error', { message: 'browser action requires a non-empty \"steps\" array' });\n return;\n }\n try {\n const result = await state.proxy.dispatchBrowserCommand(steps);\n emit('browser-completed', {\n steps: result.steps,\n snapshot: result.snapshot,\n logs: result.logs,\n duration: result.duration,\n });\n } catch (err) {\n emit('command-error', {\n message: err instanceof Error ? err.message : 'Browser command failed',\n });\n }\n}\n","import { getUploadUrl } from '../api';\nimport type { SessionState, EmitFn } from './types';\n\nexport async function handleScreenshot(\n state: SessionState,\n emit: EmitFn,\n): Promise<void> {\n const fail = (message: string) => {\n emit('screenshot-completed', {\n url: '',\n width: 0,\n height: 0,\n duration: 0,\n error: message,\n });\n };\n\n if (!state.proxy) {\n fail('No active proxy');\n return;\n }\n if (!state.proxy.isBrowserConnected()) {\n fail('No browser connected, please refresh the MindStudio preview');\n return;\n }\n if (!state.runner?.getSession() || !state.appConfig?.appId) {\n fail('No active session');\n return;\n }\n\n try {\n const startTime = Date.now();\n\n // 1. Dispatch screenshot command to browser\n // Full-page screenshots scroll through the page and capture chunks — can take minutes\n const result = await state.proxy.dispatchBrowserCommand([{ command: 'screenshot' }], 120_000);\n const stepResult = (result.steps as Array<Record<string, unknown>>)?.[0]\n ?.result as { image: string; width: number; height: number };\n\n if (!stepResult?.image) {\n fail('Screenshot capture returned no image data');\n return;\n }\n\n // 2. Get presigned upload URL\n const session = state.runner.getSession()!;\n const { uploadUrl, uploadFields, publicUrl } = await getUploadUrl(\n state.appConfig.appId,\n session.sessionId,\n 'jpg',\n 'image/jpeg',\n );\n\n // 3. Upload to S3\n const imageBuffer = Buffer.from(stepResult.image, 'base64');\n const form = new FormData();\n for (const [key, value] of Object.entries(uploadFields)) {\n form.append(key, value);\n }\n form.append('file', new Blob([imageBuffer], { type: 'image/jpeg' }), 'screenshot.jpg');\n const uploadResult = await fetch(uploadUrl, { method: 'POST', body: form });\n\n if (!uploadResult.ok) {\n fail(`S3 upload failed: ${uploadResult.status}`);\n return;\n }\n\n // 4. Emit result\n emit('screenshot-completed', {\n url: publicUrl,\n width: stepResult.width,\n height: stepResult.height,\n duration: Date.now() - startTime,\n });\n } catch (err) {\n fail(err instanceof Error ? err.message : 'Screenshot failed');\n }\n}\n","import type { SessionState, EmitFn } from './types';\n\n/**\n * Handle explicit signal that the upstream dev server is restarting.\n * Marks the upstream as down so the proxy's health check will detect\n * when it's back and auto-reload the browser.\n */\nexport async function handleDevServerRestarting(\n state: SessionState,\n emit: EmitFn,\n): Promise<void> {\n if (!state.proxy) {\n emit('command-error', { message: 'No active proxy' });\n return;\n }\n state.proxy.markUpstreamDown();\n emit('dev-server-restarting-ack', {});\n}\n","import type { SessionState, EmitFn } from './types';\n\nexport function handleBrowserStatus(\n state: SessionState,\n emit: EmitFn,\n): void {\n emit('browser-status', {\n connected: state.proxy?.isBrowserConnected() ?? false,\n });\n}\n","import type { SessionState, EmitFn } from './types';\n\n/**\n * Reset the browser to a clean state by reloading the page.\n * The agent sends this explicitly when done testing.\n * Fire-and-forget — the reload kills the page so no result comes back.\n */\nexport function handleResetBrowser(\n state: SessionState,\n emit: EmitFn,\n): void {\n if (!state.proxy) {\n emit('command-error', { message: 'No active proxy' });\n return;\n }\n if (!state.proxy.isBrowserConnected()) {\n emit('command-error', { message: 'No browser connected' });\n return;\n }\n state.proxy.dispatchBrowserCommand([{ command: 'reload' }]).catch(() => {});\n emit('reset-browser-completed', {});\n}\n","/**\n * Stdin command router for headless mode.\n *\n * Reads NDJSON commands from stdin and dispatches to individual handlers.\n * Each command lives in its own file for isolation and testability.\n */\n\nimport { handleRunScenario } from './run-scenario';\nimport { handleRunMethod } from './run-method';\nimport { handleImpersonate, handleClearImpersonation } from './impersonate';\nimport { handleBrowser } from './browser';\nimport { handleScreenshot } from './screenshot';\nimport { handleDevServerRestarting } from './dev-server-restarting';\nimport { handleBrowserStatus } from './browser-status';\nimport { handleResetBrowser } from './reset-browser';\nimport type { SessionState, EmitFn } from './types';\n\nexport type { SessionState, EmitFn } from './types';\n\nexport function setupStdinCommands(\n state: SessionState,\n cwd: string,\n emit: EmitFn,\n): void {\n if (!process.stdin.readable) return;\n\n let buffer = '';\n process.stdin.setEncoding('utf-8');\n process.stdin.on('data', (chunk: string) => {\n buffer += chunk;\n let idx: number;\n while ((idx = buffer.indexOf('\\n')) !== -1) {\n const line = buffer.slice(0, idx).trim();\n buffer = buffer.slice(idx + 1);\n if (!line) continue;\n\n try {\n const cmd = JSON.parse(line) as { action: string; [key: string]: unknown };\n handleStdinCommand(cmd, state, cwd, emit);\n } catch {\n emit('command-error', { message: `Invalid JSON on stdin: ${line.slice(0, 100)}` });\n }\n }\n });\n}\n\nasync function handleStdinCommand(\n cmd: { action: string; [key: string]: unknown },\n state: SessionState,\n cwd: string,\n emit: EmitFn,\n): Promise<void> {\n switch (cmd.action) {\n case 'run-scenario':\n return handleRunScenario(state, cwd, cmd, emit);\n case 'run-method':\n return handleRunMethod(state, cwd, cmd, emit);\n case 'impersonate':\n return handleImpersonate(state, cmd, emit);\n case 'clear-impersonation':\n return handleClearImpersonation(state, emit);\n case 'browser':\n return handleBrowser(state, cmd, emit);\n case 'screenshot':\n return handleScreenshot(state, emit);\n case 'dev-server-restarting':\n return handleDevServerRestarting(state, emit);\n case 'browser-status':\n return handleBrowserStatus(state, emit);\n case 'reset-browser':\n return handleResetBrowser(state, emit);\n default:\n emit('command-error', { message: `Unknown action: ${cmd.action}` });\n }\n}\n","/**\n * Headless Dev Mode\n *\n * Runs the MindStudio dev tunnel without a TUI. Designed for programmatic\n * control by a parent process (e.g., a sandbox C&C server or CI pipeline).\n *\n * Outputs structured JSON events to stdout (one per line, newline-delimited).\n * The parent process reads these to track session state, method execution,\n * errors, and connection health.\n *\n * Does NOT start a dev server — the parent process manages that separately.\n * The tunnel just needs to know which port to proxy to.\n *\n * @module\n */\n\nimport { DevRunner } from './dev/runner';\nimport { DevProxy } from './dev/proxy';\nimport { syncSchema } from './dev/api';\nimport {\n detectAppConfig,\n getWebInterfaceConfig,\n readTableSources,\n} from './dev/app-config';\nimport { initRequestLog, closeRequestLog } from './dev/request-log';\nimport { initBrowserLog, closeBrowserLog } from './dev/browser-log';\nimport { subscribeDevEvents } from './dev/session-events';\nimport { setupStdinCommands, type SessionState } from './dev/stdin-commands';\nimport {\n getApiKey,\n getApiBaseUrl,\n getUserId,\n getEnvironment,\n getConfigPath,\n} from './config';\nimport { initLoggerHeadless, log, type LogLevel } from './dev/logger';\nimport { stablePort, detectGitBranch } from './dev/utils';\nimport { watchTableFiles } from './dev/table-watcher';\nimport { watchConfigFile } from './dev/config-watcher';\n\n/**\n * Options for headless dev mode.\n */\nexport interface HeadlessOptions {\n /** Working directory containing mindstudio.json. Defaults to process.cwd(). */\n cwd?: string;\n /** Port the dev server is running on. If omitted, reads from web.json. If neither, proxy is skipped. */\n devPort?: number;\n /** Preferred port for the local proxy. Defaults to a stable port derived from the app ID. */\n proxyPort?: number;\n /** Bind address for the proxy server. Use '0.0.0.0' for hosted sandboxes. Defaults to '127.0.0.1'. */\n bindAddress?: string;\n /** Log level for stderr output. Defaults to 'info'. */\n logLevel?: LogLevel;\n /** URL for the browser agent script. Defaults to unpkg latest. Set to an ngrok URL for development. */\n browserAgentUrl?: string;\n}\n\n/** Write a JSON event to stdout. */\nfunction emit(event: string, data?: Record<string, unknown>): void {\n process.stdout.write(JSON.stringify({ event, ...data }) + '\\n');\n}\n\n// ---------------------------------------------------------------------------\n// Session lifecycle\n// ---------------------------------------------------------------------------\n\nasync function startSession(\n cwd: string,\n opts: HeadlessOptions,\n state: SessionState,\n shutdown: () => Promise<void>,\n): Promise<boolean> {\n const bindAddress = opts.bindAddress ?? '127.0.0.1';\n\n // Read fresh config\n const appConfig = detectAppConfig(cwd);\n if (!appConfig) {\n emit('config-error', { message: 'No valid mindstudio.json found in ' + cwd });\n return false;\n }\n\n if (!appConfig.appId) {\n emit('config-error', { message: 'Missing \"appId\" in mindstudio.json' });\n return false;\n }\n\n state.appConfig = appConfig;\n\n // Resolve dev port\n let devPort = opts.devPort ?? null;\n if (devPort === null) {\n const webConfig = getWebInterfaceConfig(appConfig, cwd);\n devPort = webConfig?.devPort ?? null;\n }\n\n emit('session-starting', { appId: appConfig.appId, name: appConfig.name });\n\n try {\n // Start platform session\n const branch = detectGitBranch();\n const runner = new DevRunner(appConfig.appId, cwd, {\n branch,\n methods: appConfig.methods.map((m) => ({ id: m.id, export: m.export, path: m.path })),\n });\n const session = await runner.start();\n state.runner = runner;\n\n // Initialize logs\n initRequestLog(cwd);\n initBrowserLog(cwd);\n\n // Sync schema\n if (appConfig.tables.length > 0) {\n try {\n const tableSources = readTableSources(appConfig, cwd);\n if (tableSources.length > 0) {\n const syncResult = await syncSchema(appConfig.appId, session.sessionId, tableSources);\n session.databases = syncResult.databases;\n emit('schema-sync-completed', {\n created: syncResult.created,\n altered: syncResult.altered,\n errors: syncResult.errors,\n });\n } else {\n log.warn('No table source files found, skipping schema sync', {\n expected: appConfig.tables.map((t) => t.path),\n });\n }\n } catch (err) {\n emit('schema-sync-completed', {\n created: [],\n altered: [],\n errors: [err instanceof Error ? err.message : 'Schema sync failed'],\n });\n }\n }\n\n // Start proxy\n let proxyPort: number | null = null;\n if (devPort !== null && session.clientContext) {\n const proxy = new DevProxy(devPort, session.clientContext, bindAddress, opts.browserAgentUrl);\n const preferred = opts.proxyPort ?? stablePort(appConfig.appId);\n proxyPort = await proxy.start(preferred);\n runner.setProxyUrl(`http://${bindAddress === '0.0.0.0' ? 'localhost' : bindAddress}:${proxyPort}`);\n runner.setProxy(proxy);\n state.proxy = proxy;\n }\n state.proxyPort = proxyPort;\n\n emit('session-started', {\n sessionId: session.sessionId,\n releaseId: session.releaseId,\n branch: session.branch,\n proxyPort,\n proxyUrl: proxyPort\n ? `http://${bindAddress === '0.0.0.0' ? 'localhost' : bindAddress}:${proxyPort}/`\n : null,\n webInterfaceUrl: session.webInterfaceUrl,\n roles: appConfig.roles.map((r) => ({ id: r.id, name: r.name ?? r.id, description: r.description })),\n scenarios: appConfig.scenarios.map((s) => ({\n id: s.id,\n name: s.name ?? s.export,\n description: s.description,\n path: s.path,\n roles: s.roles,\n })),\n });\n\n // Subscribe to runner events\n state.unsubscribers.push(...subscribeDevEvents(emit, shutdown));\n\n // Watch table source files for changes — auto-sync without session restart\n setupTableWatchers(cwd, state);\n\n return true;\n } catch (err) {\n emit('config-error', {\n message: err instanceof Error ? err.message : 'Failed to start session',\n });\n return false;\n }\n}\n\nfunction setupTableWatchers(cwd: string, state: SessionState): void {\n if (!state.appConfig || state.appConfig.tables.length === 0) return;\n\n const cleanup = watchTableFiles(state.appConfig.tables, cwd, async () => {\n if (!state.runner || !state.appConfig?.appId) return;\n const session = state.runner.getSession();\n if (!session) return;\n\n emit('schema-sync-started');\n log.info('Table source file changed, syncing schema');\n\n try {\n const tableSources = readTableSources(state.appConfig, cwd);\n if (tableSources.length > 0) {\n const result = await syncSchema(state.appConfig.appId, session.sessionId, tableSources);\n session.databases = result.databases;\n emit('schema-sync-completed', {\n created: result.created,\n altered: result.altered,\n errors: result.errors,\n });\n log.info('Schema sync complete', { created: result.created, altered: result.altered });\n } else {\n log.warn('Table source file change detected but file(s) still missing', {\n expected: state.appConfig.tables.map((t) => t.path),\n });\n }\n } catch (err) {\n const message = err instanceof Error ? err.message : 'Schema sync failed';\n emit('command-error', { message });\n log.warn('Schema sync failed', { error: message });\n }\n });\n\n state.unsubscribers.push(cleanup);\n}\n\nasync function teardownSession(state: SessionState): Promise<void> {\n for (const unsub of state.unsubscribers) unsub();\n state.unsubscribers = [];\n\n state.proxy?.stop();\n state.proxy = null;\n state.proxyPort = null;\n\n if (state.runner) {\n await state.runner.stop().catch(() => {});\n state.runner = null;\n }\n\n closeRequestLog();\n closeBrowserLog();\n}\n\n// ---------------------------------------------------------------------------\n// Entry point\n// ---------------------------------------------------------------------------\n\n/**\n * Start the dev tunnel in headless mode.\n */\nexport async function startHeadless(opts: HeadlessOptions = {}): Promise<void> {\n initLoggerHeadless(opts.logLevel ?? 'info');\n\n const cwd = opts.cwd ?? process.cwd();\n\n const apiKey = getApiKey();\n const userId = getUserId();\n log.info('Startup config', {\n configPath: getConfigPath(),\n environment: getEnvironment(),\n apiBaseUrl: getApiBaseUrl(),\n hasApiKey: !!apiKey,\n apiKeyPrefix: apiKey ? apiKey.slice(0, 8) + '...' : null,\n hasUserId: !!userId,\n userId: userId ?? null,\n cwd,\n });\n\n const state: SessionState = {\n runner: null,\n proxy: null,\n appConfig: null,\n proxyPort: null,\n unsubscribers: [],\n };\n\n let restarting = false;\n let cleanupConfigWatcher: (() => void) | undefined;\n\n let stopping = false;\n const shutdown = async () => {\n if (stopping) return;\n stopping = true;\n emit('session-stopping');\n cleanupConfigWatcher?.();\n await teardownSession(state);\n emit('session-stopped');\n };\n\n process.on('SIGTERM', () => { shutdown().then(() => process.exit(0)); });\n process.on('SIGINT', () => { shutdown().then(() => process.exit(0)); });\n\n // Initial session start — crash if it fails so the process manager can retry\n const ok = await startSession(cwd, opts, state, shutdown);\n if (!ok) {\n process.exit(1);\n }\n\n // Stdin command loop\n setupStdinCommands(state, cwd, emit);\n\n // Watch mindstudio.json for changes\n cleanupConfigWatcher = watchConfigFile(cwd, async () => {\n if (stopping || restarting) return;\n restarting = true;\n try {\n log.info('mindstudio.json changed, restarting dev session');\n emit('config-changed');\n await teardownSession(state);\n const ok = await startSession(cwd, opts, state, shutdown);\n if (ok && state.proxy) {\n state.proxy.dispatchBrowserCommand([{ command: 'reload' }]).catch(() => {});\n }\n } finally {\n restarting = false;\n }\n });\n\n // Keep the process alive — the poll loop runs in DevRunner\n await new Promise<void>(() => {});\n}\n"],"mappings":"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","names":["emit","emit","emit","emit","emit","emit","emit","emit","emit","emit","ok"]}
|
|
@@ -7,7 +7,7 @@ import {
|
|
|
7
7
|
setProviderInstallPath,
|
|
8
8
|
submitProgress,
|
|
9
9
|
submitResult
|
|
10
|
-
} from "./chunk-
|
|
10
|
+
} from "./chunk-VJTZSOKC.js";
|
|
11
11
|
|
|
12
12
|
// src/providers/ollama/index.ts
|
|
13
13
|
import { Ollama } from "ollama";
|
|
@@ -1395,4 +1395,4 @@ export {
|
|
|
1395
1395
|
requestEvents,
|
|
1396
1396
|
TunnelRunner
|
|
1397
1397
|
};
|
|
1398
|
-
//# sourceMappingURL=chunk-
|
|
1398
|
+
//# sourceMappingURL=chunk-TMIU4S53.js.map
|
|
@@ -1678,6 +1678,10 @@ var DevProxy = class _DevProxy {
|
|
|
1678
1678
|
this.handlePostResult(clientReq, clientRes);
|
|
1679
1679
|
return;
|
|
1680
1680
|
}
|
|
1681
|
+
if (clientReq.url?.startsWith("/__mindstudio_dev__/font-proxy?") && clientReq.method === "GET") {
|
|
1682
|
+
this.handleFontProxy(clientReq, clientRes);
|
|
1683
|
+
return;
|
|
1684
|
+
}
|
|
1681
1685
|
}
|
|
1682
1686
|
if (clientReq.method === "OPTIONS" && clientReq.headers.origin) {
|
|
1683
1687
|
clientRes.writeHead(204, {
|
|
@@ -1762,6 +1766,50 @@ var DevProxy = class _DevProxy {
|
|
|
1762
1766
|
clientRes.end();
|
|
1763
1767
|
});
|
|
1764
1768
|
}
|
|
1769
|
+
/**
|
|
1770
|
+
* Proxy a cross-origin font stylesheet or font file through our server,
|
|
1771
|
+
* adding CORS headers so the browser agent can read the @font-face rules.
|
|
1772
|
+
*/
|
|
1773
|
+
async handleFontProxy(clientReq, clientRes) {
|
|
1774
|
+
const cors = this.corsHeaders(clientReq);
|
|
1775
|
+
try {
|
|
1776
|
+
const parsed = new URL(clientReq.url, `http://localhost`);
|
|
1777
|
+
const targetUrl = parsed.searchParams.get("url");
|
|
1778
|
+
if (!targetUrl) {
|
|
1779
|
+
clientRes.writeHead(400, cors);
|
|
1780
|
+
clientRes.end("Missing url parameter");
|
|
1781
|
+
return;
|
|
1782
|
+
}
|
|
1783
|
+
const response = await fetch(targetUrl);
|
|
1784
|
+
if (!response.ok) {
|
|
1785
|
+
clientRes.writeHead(response.status, cors);
|
|
1786
|
+
clientRes.end(`Upstream error: ${response.status}`);
|
|
1787
|
+
return;
|
|
1788
|
+
}
|
|
1789
|
+
const contentType = response.headers.get("content-type") || "text/css";
|
|
1790
|
+
let body;
|
|
1791
|
+
if (contentType.includes("css")) {
|
|
1792
|
+
let css = await response.text();
|
|
1793
|
+
css = css.replace(
|
|
1794
|
+
/url\(\s*(['"]?)(https?:\/\/[^)'"]+)\1\s*\)/g,
|
|
1795
|
+
(_, quote, url) => `url(${quote}/__mindstudio_dev__/font-proxy?url=${encodeURIComponent(url)}${quote})`
|
|
1796
|
+
);
|
|
1797
|
+
body = css;
|
|
1798
|
+
} else {
|
|
1799
|
+
const arrayBuf = await response.arrayBuffer();
|
|
1800
|
+
body = Buffer.from(arrayBuf);
|
|
1801
|
+
}
|
|
1802
|
+
clientRes.writeHead(200, {
|
|
1803
|
+
...cors,
|
|
1804
|
+
"content-type": contentType,
|
|
1805
|
+
"cache-control": "public, max-age=86400"
|
|
1806
|
+
});
|
|
1807
|
+
clientRes.end(body);
|
|
1808
|
+
} catch (err) {
|
|
1809
|
+
clientRes.writeHead(502, cors);
|
|
1810
|
+
clientRes.end(`Font proxy error: ${err instanceof Error ? err.message : String(err)}`);
|
|
1811
|
+
}
|
|
1812
|
+
}
|
|
1765
1813
|
handleGetCommand(clientReq, clientRes) {
|
|
1766
1814
|
this.lastBrowserPoll = Date.now();
|
|
1767
1815
|
const command = this.commandQueue.shift();
|
|
@@ -2141,4 +2189,4 @@ export {
|
|
|
2141
2189
|
watchTableFiles,
|
|
2142
2190
|
watchConfigFile
|
|
2143
2191
|
};
|
|
2144
|
-
//# sourceMappingURL=chunk-
|
|
2192
|
+
//# sourceMappingURL=chunk-VJTZSOKC.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/config.ts","../src/dev/logger.ts","../src/dev/api.ts","../src/dev/ndjson-log.ts","../src/dev/request-log.ts","../src/dev/events.ts","../src/dev/transpiler.ts","../src/dev/executor.ts","../src/api.ts","../src/dev/runner.ts","../src/dev/format-error.ts","../src/dev/browser-log.ts","../src/dev/proxy.ts","../src/dev/app-config.ts","../src/dev/utils.ts","../src/dev/table-watcher.ts","../src/dev/config-watcher.ts"],"sourcesContent":["import Conf from 'conf';\nimport os from 'node:os';\nimport path from 'node:path';\n\nexport type Environment = 'prod' | 'local';\n\ninterface EnvironmentConfig {\n apiKey?: string;\n userId?: string;\n apiBaseUrl: string;\n}\n\ninterface ConfigSchema {\n environment: Environment;\n providerBaseUrls: Record<string, string>;\n providerInstallPaths: Record<string, string>;\n localInterfaces: Record<string, string>;\n environments: {\n prod: EnvironmentConfig;\n local: EnvironmentConfig;\n };\n}\n\nexport const config = new Conf<ConfigSchema>({\n projectName: 'mindstudio-local',\n cwd: path.join(os.homedir(), '.mindstudio-local-tunnel'),\n configName: 'config',\n defaults: {\n environment: 'prod',\n providerBaseUrls: {},\n providerInstallPaths: {},\n localInterfaces: {},\n environments: {\n prod: {\n apiBaseUrl: 'https://api.mindstudio.ai',\n },\n local: {\n apiBaseUrl: 'http://localhost:3129',\n },\n },\n },\n});\n\n// Environment management\nexport function getEnvironment(): Environment {\n return config.get('environment');\n}\n\nexport function setEnvironment(env: Environment): void {\n config.set('environment', env);\n}\n\n// Get config for current environment\nfunction getEnvConfig(): EnvironmentConfig {\n const env = getEnvironment();\n return config.get(`environments.${env}`) as EnvironmentConfig;\n}\n\nfunction setEnvConfig(key: keyof EnvironmentConfig, value: string): void {\n const env = getEnvironment();\n config.set(`environments.${env}.${key}`, value);\n}\n\n// API Key (per environment)\nexport function getApiKey(): string | undefined {\n return getEnvConfig().apiKey;\n}\n\nexport function setApiKey(key: string): void {\n setEnvConfig('apiKey', key);\n}\n\nexport function clearApiKey(): void {\n const env = getEnvironment();\n config.delete(`environments.${env}.apiKey` as keyof ConfigSchema);\n}\n\n// User ID (per environment)\nexport function getUserId(): string | undefined {\n return getEnvConfig().userId;\n}\n\nexport function setUserId(id: string): void {\n setEnvConfig('userId', id);\n}\n\nexport function clearUserId(): void {\n const env = getEnvironment();\n config.delete(`environments.${env}.userId` as keyof ConfigSchema);\n}\n\n// API Base URL (per environment)\nexport function getApiBaseUrl(): string {\n return getEnvConfig().apiBaseUrl;\n}\n\nexport function setApiBaseUrl(url: string): void {\n setEnvConfig('apiBaseUrl', url);\n}\n\nexport function getConfigPath(): string {\n return config.path;\n}\n\n// Provider helpers\nexport function getProviderBaseUrl(name: string, defaultUrl: string): string {\n const urls = config.get('providerBaseUrls');\n return urls[name] ?? defaultUrl;\n}\n\nexport function setProviderBaseUrl(name: string, url: string): void {\n const urls = config.get('providerBaseUrls');\n urls[name] = url;\n config.set('providerBaseUrls', urls);\n}\n\nexport function getProviderInstallPath(name: string): string | undefined {\n const paths = config.get('providerInstallPaths');\n return paths[name];\n}\n\nexport function setProviderInstallPath(\n name: string,\n installPath: string,\n): void {\n const paths = config.get('providerInstallPaths');\n paths[name] = installPath;\n config.set('providerInstallPaths', paths);\n}\n\n// Local interface helpers\nexport function getLocalInterfacesDir(): string {\n return path.join(os.homedir(), '.mindstudio-local-tunnel', 'interfaces');\n}\n\nexport function getLocalInterfacePath(key: string): string | undefined {\n const interfaces = config.get('localInterfaces');\n return interfaces[key];\n}\n\nexport function setLocalInterfacePath(key: string, dirPath: string): void {\n const interfaces = config.get('localInterfaces');\n interfaces[key] = dirPath;\n config.set('localInterfaces', interfaces);\n}\n\nexport function deleteLocalInterfacePath(key: string): void {\n const interfaces = config.get('localInterfaces');\n delete interfaces[key];\n config.set('localInterfaces', interfaces);\n}\n\n// Get all environment info for display\nexport function getEnvironmentInfo(): {\n current: Environment;\n apiBaseUrl: string;\n hasApiKey: boolean;\n} {\n const env = getEnvironment();\n const envConfig = getEnvConfig();\n return {\n current: env,\n apiBaseUrl: envConfig.apiBaseUrl,\n hasApiKey: !!envConfig.apiKey,\n };\n}\n","/**\n * Structured logger with configurable level and output target.\n *\n * - Headless mode: writes to stderr (stdout reserved for JSON events)\n * - Interactive mode: writes to .mindstudio-dev.log in cwd (won't interfere with Ink TUI)\n *\n * Levels: error > warn > info > debug\n */\n\nimport fs from 'node:fs';\n\nexport type LogLevel = 'error' | 'warn' | 'info' | 'debug';\n\nconst LEVELS: Record<LogLevel, number> = {\n error: 0,\n warn: 1,\n info: 2,\n debug: 3,\n};\n\nlet currentLevel: number = LEVELS.error;\nlet writeFn: (line: string) => void = () => {};\n\nfunction timestamp(): string {\n return new Date().toISOString();\n}\n\nfunction write(level: LogLevel, msg: string, data?: Record<string, unknown>) {\n if (LEVELS[level] > currentLevel) {\n return;\n }\n const parts = [`[${timestamp()}]`, level.toUpperCase().padEnd(5), msg];\n if (data) {\n parts.push(JSON.stringify(data));\n }\n writeFn(parts.join(' '));\n}\n\nexport const log = {\n error(msg: string, data?: Record<string, unknown>) {\n write('error', msg, data);\n },\n warn(msg: string, data?: Record<string, unknown>) {\n write('warn', msg, data);\n },\n info(msg: string, data?: Record<string, unknown>) {\n write('info', msg, data);\n },\n debug(msg: string, data?: Record<string, unknown>) {\n write('debug', msg, data);\n },\n};\n\n/** Configure logger for headless mode — writes to stderr. */\nexport function initLoggerHeadless(level: LogLevel = 'info'): void {\n currentLevel = LEVELS[level];\n writeFn = (line) => {\n process.stderr.write(line + '\\n');\n };\n}\n\n/** Configure logger for interactive mode — writes to .mindstudio-dev.log. */\nexport function initLoggerInteractive(level: LogLevel = 'error'): void {\n currentLevel = LEVELS[level];\n let fd: number | null = null;\n writeFn = (line) => {\n try {\n if (fd === null) {\n fd = fs.openSync('.mindstudio-dev.log', 'a');\n }\n fs.writeSync(fd, line + '\\n');\n } catch {\n // Best-effort — don't crash if we can't write logs\n }\n };\n}\n","// Platform API client for dev sessions.\n//\n// All endpoints are under /_internal/v2/apps/{appId}/dev/.\n// Auth: Bearer token (API key), plus x-dev-session header for session-scoped endpoints.\n// The dev session IS a release — sessionId and releaseId are the same UUID.\n\nimport { getApiKey, getApiBaseUrl } from '../config';\nimport { log } from './logger';\nimport type { DevSession, DevRequest, DevResult, SyncSchemaResponse } from './types';\n\n// ---------------------------------------------------------------------------\n// Internal helpers\n// ---------------------------------------------------------------------------\n\nfunction getHeaders(sessionId?: string): Record<string, string> {\n const apiKey = getApiKey();\n if (!apiKey) {\n throw new Error('Not authenticated. Run mindstudio-local to set up.');\n }\n\n const headers: Record<string, string> = {\n Authorization: `Bearer ${apiKey}`,\n 'Content-Type': 'application/json',\n };\n\n if (sessionId) headers['x-dev-session'] = sessionId;\n\n return headers;\n}\n\nfunction basePath(appId: string): string {\n return `${getApiBaseUrl()}/_internal/v2/apps/${appId}/dev`;\n}\n\n/**\n * Generic API request with consistent logging, timing, and error handling.\n * Returns null for 204 responses. Throws on non-ok status.\n */\nasync function apiRequest<T>(\n method: string,\n url: string,\n headers: Record<string, string>,\n body?: unknown,\n): Promise<T> {\n const start = Date.now();\n const logTag = `${method} ${url.replace(getApiBaseUrl(), '')}`;\n\n const response = await fetch(url, {\n method,\n headers,\n ...(body !== undefined ? { body: JSON.stringify(body) } : {}),\n });\n\n const duration = Date.now() - start;\n\n if (response.status === 204) {\n log.debug(`api ${logTag} → 204 (${duration}ms)`);\n return null as T;\n }\n\n if (!response.ok) {\n const error = await response.text();\n log.error(`api ${logTag} → ${response.status} (${duration}ms)`, { error });\n throw new ApiError(`${logTag} failed: ${response.status} ${error}`, response.status);\n }\n\n const data = (await response.json()) as T;\n log.info(`api ${logTag} → ${response.status} (${duration}ms)`);\n return data;\n}\n\n// ---------------------------------------------------------------------------\n// Public API\n// ---------------------------------------------------------------------------\n\nexport async function startDevSession(\n appId: string,\n opts?: {\n branch?: string;\n proxyUrl?: string;\n methods?: Array<{ id: string; export: string; path: string }>;\n },\n): Promise<DevSession> {\n const body: Record<string, unknown> = {};\n if (opts?.branch) body.branch = opts.branch;\n if (opts?.proxyUrl) body.proxyUrl = opts.proxyUrl;\n if (opts?.methods) body.methods = opts.methods;\n\n return apiRequest<DevSession>('POST', `${basePath(appId)}/manage/start`, getHeaders(), body);\n}\n\nexport async function stopDevSession(\n appId: string,\n sessionId: string,\n): Promise<void> {\n await apiRequest<void>('POST', `${basePath(appId)}/manage/stop`, getHeaders(sessionId));\n}\n\nexport async function pollDevRequest(\n appId: string,\n sessionId: string,\n proxyUrl?: string,\n): Promise<DevRequest | null> {\n const url = proxyUrl\n ? `${basePath(appId)}/poll?proxyUrl=${encodeURIComponent(proxyUrl)}`\n : `${basePath(appId)}/poll`;\n\n try {\n return await apiRequest<DevRequest | null>('GET', url, getHeaders(sessionId));\n } catch (err) {\n // Re-throw as DevPollError so the runner can detect session expiry (404)\n if (err instanceof ApiError) {\n throw new DevPollError(err.message, err.statusCode);\n }\n throw err;\n }\n}\n\nexport async function submitDevResult(\n appId: string,\n sessionId: string,\n requestId: string,\n result: DevResult,\n): Promise<void> {\n await apiRequest<void>(\n 'POST',\n `${basePath(appId)}/result/${requestId}`,\n getHeaders(sessionId),\n result,\n );\n}\n\nexport async function syncSchema(\n appId: string,\n sessionId: string,\n tables: Array<{ name: string; source: string }>,\n): Promise<SyncSchemaResponse> {\n return apiRequest<SyncSchemaResponse>(\n 'POST',\n `${basePath(appId)}/manage/sync-schema`,\n getHeaders(sessionId),\n { tables },\n );\n}\n\nexport async function resetDevDatabase(\n appId: string,\n sessionId: string,\n mode: 'snapshot' | 'truncate' = 'snapshot',\n): Promise<DevSession['databases']> {\n const data = await apiRequest<{ databases: DevSession['databases'] }>(\n 'POST',\n `${basePath(appId)}/manage/reset?mode=${mode}`,\n getHeaders(sessionId),\n );\n return data.databases;\n}\n\nexport async function impersonate(\n appId: string,\n sessionId: string,\n roles: string[] | null,\n): Promise<{ roles: string[] | null }> {\n return apiRequest<{ roles: string[] | null }>(\n 'POST',\n `${basePath(appId)}/manage/impersonate`,\n getHeaders(sessionId),\n { roles: roles && roles.length > 0 ? roles : null },\n );\n}\n\nexport async function refreshContext(\n appId: string,\n sessionId: string,\n): Promise<Record<string, unknown>> {\n const data = await apiRequest<{ clientContext: Record<string, unknown> }>(\n 'POST',\n `${basePath(appId)}/manage/refresh-context`,\n getHeaders(sessionId),\n );\n return data.clientContext;\n}\n\n// Fetch a callback token for one-off executions (scenarios, etc.)\n// that don't come from the poll loop.\nexport async function fetchCallbackToken(\n appId: string,\n sessionId: string,\n): Promise<string> {\n const data = await apiRequest<{ authorizationToken: string }>(\n 'POST',\n `${basePath(appId)}/manage/token`,\n getHeaders(sessionId),\n );\n return data.authorizationToken;\n}\n\nexport async function getUploadUrl(\n appId: string,\n sessionId: string,\n extension: string,\n contentType: string,\n): Promise<{ uploadUrl: string; uploadFields: Record<string, string>; publicUrl: string }> {\n return apiRequest(\n 'POST',\n `${basePath(appId)}/manage/upload`,\n getHeaders(sessionId),\n { extension, contentType },\n );\n}\n\n// ---------------------------------------------------------------------------\n// Error classes\n// ---------------------------------------------------------------------------\n\n/** API request error with HTTP status code. */\nexport class ApiError extends Error {\n constructor(\n message: string,\n public readonly statusCode: number,\n ) {\n super(message);\n this.name = 'ApiError';\n }\n}\n\n/** Poll-specific error — runner checks statusCode to detect session expiry (404). */\nexport class DevPollError extends Error {\n constructor(\n message: string,\n public readonly statusCode: number,\n ) {\n super(message);\n this.name = 'DevPollError';\n }\n}\n","/**\n * Shared NDJSON log writer with rotation.\n *\n * Used by browser-log.ts and request-log.ts. Handles fd management,\n * line counting, append, and rotation when the file exceeds limits.\n */\n\nimport fs from 'node:fs';\nimport { join } from 'node:path';\nimport { log } from './logger';\n\nexport class NdjsonLog {\n private fd: number | null = null;\n private logPath: string | null = null;\n private lineCount = 0;\n private rotating = false;\n\n constructor(\n private readonly filename: string,\n private readonly maxLines = 500,\n private readonly keepLines = 300,\n private readonly maxBytes = 2 * 1024 * 1024,\n ) {}\n\n init(projectRoot: string): void {\n this.close();\n\n try {\n const logsDir = join(projectRoot, '.logs');\n fs.mkdirSync(logsDir, { recursive: true });\n\n this.logPath = join(logsDir, this.filename);\n\n if (fs.existsSync(this.logPath)) {\n const content = fs.readFileSync(this.logPath, 'utf-8');\n this.lineCount = content.split('\\n').filter((l) => l.trim()).length;\n } else {\n this.lineCount = 0;\n }\n\n this.fd = fs.openSync(this.logPath, 'a');\n log.info(`${this.filename} log initialized`, {\n path: this.logPath,\n existingEntries: this.lineCount,\n });\n } catch (err) {\n log.warn(`Failed to initialize ${this.filename} log`, {\n error: err instanceof Error ? err.message : String(err),\n });\n this.fd = null;\n this.logPath = null;\n }\n }\n\n append(record: Record<string, unknown>): void {\n if (this.fd === null) return;\n\n try {\n const line = JSON.stringify(record) + '\\n';\n fs.writeSync(this.fd, line);\n this.lineCount++;\n this.maybeRotate();\n } catch (err) {\n log.debug(`Failed to write ${this.filename} log entry`, {\n error: err instanceof Error ? err.message : String(err),\n });\n }\n }\n\n close(): void {\n if (this.fd !== null) {\n try {\n fs.closeSync(this.fd);\n } catch {\n // Best effort\n }\n this.fd = null;\n }\n this.logPath = null;\n this.lineCount = 0;\n this.rotating = false;\n }\n\n private maybeRotate(): void {\n if (this.fd === null || this.logPath === null || this.rotating) return;\n\n try {\n let needsRotation = this.lineCount > this.maxLines;\n\n if (!needsRotation) {\n const stat = fs.fstatSync(this.fd);\n needsRotation = stat.size > this.maxBytes;\n }\n\n if (!needsRotation) return;\n\n this.rotating = true;\n\n const content = fs.readFileSync(this.logPath, 'utf-8');\n const lines = content.split('\\n').filter((l) => l.trim());\n const kept = lines.slice(-this.keepLines);\n\n fs.closeSync(this.fd);\n fs.writeFileSync(this.logPath, kept.join('\\n') + '\\n', 'utf-8');\n this.fd = fs.openSync(this.logPath, 'a');\n this.lineCount = kept.length;\n\n log.debug(`${this.filename} log rotated`, { kept: this.lineCount });\n } catch (err) {\n log.debug(`${this.filename} log rotation failed`, {\n error: err instanceof Error ? err.message : String(err),\n });\n } finally {\n this.rotating = false;\n }\n }\n}\n","/**\n * NDJSON request log for method and scenario executions.\n * Thin wrapper around NdjsonLog.\n */\n\nimport { NdjsonLog } from './ndjson-log';\nimport type { DevSession, AppScenario } from './types';\nimport type { ExecuteMethodResult } from './executor';\n\n// ---------------------------------------------------------------------------\n// Types\n// ---------------------------------------------------------------------------\n\nexport interface MethodLogEntry {\n requestId: string;\n sessionId: string;\n methodExport: string;\n methodPath: string;\n input: unknown;\n roleOverride?: string[];\n authorizationToken: string;\n databases: DevSession['databases'];\n result: ExecuteMethodResult;\n duration: number;\n}\n\nexport interface ScenarioLogEntry {\n sessionId: string;\n scenario: AppScenario;\n databases: DevSession['databases'];\n result: ExecuteMethodResult | null;\n infrastructureError?: string;\n duration: number;\n}\n\n// ---------------------------------------------------------------------------\n// Log instance\n// ---------------------------------------------------------------------------\n\nconst ndjsonLog = new NdjsonLog('requests.ndjson');\n\nexport function initRequestLog(projectRoot: string): void {\n ndjsonLog.init(projectRoot);\n}\n\nexport function logMethodExecution(entry: MethodLogEntry): void {\n ndjsonLog.append({\n type: 'method',\n timestamp: new Date().toISOString(),\n requestId: entry.requestId,\n sessionId: entry.sessionId,\n method: entry.methodExport,\n path: entry.methodPath,\n input: entry.input,\n roleOverride: entry.roleOverride ?? null,\n authorizationToken: entry.authorizationToken,\n databases: entry.databases,\n success: entry.result.success,\n output: entry.result.output ?? null,\n error: entry.result.error ?? null,\n stdout: entry.result.stdout ?? [],\n duration: entry.duration,\n stats: entry.result.stats ?? null,\n });\n}\n\nexport function logScenarioExecution(entry: ScenarioLogEntry): void {\n ndjsonLog.append({\n type: 'scenario',\n timestamp: new Date().toISOString(),\n sessionId: entry.sessionId,\n scenario: {\n id: entry.scenario.id,\n name: entry.scenario.name ?? entry.scenario.export,\n export: entry.scenario.export,\n path: entry.scenario.path,\n },\n databases: entry.databases,\n success: entry.result?.success ?? false,\n output: entry.result?.output ?? null,\n error:\n entry.result?.error ??\n (entry.infrastructureError\n ? { message: entry.infrastructureError }\n : null),\n stdout: entry.result?.stdout ?? [],\n duration: entry.duration,\n stats: entry.result?.stats ?? null,\n });\n}\n\nexport function closeRequestLog(): void {\n ndjsonLog.close();\n}\n","// Event bridge between the DevRunner (backend) and the TUI/headless UI.\n//\n// The runner emits events as methods execute. The TUI hooks subscribe\n// to update the request log. Headless mode subscribes to relay events\n// as JSON to stdout. This decoupling means the runner doesn't need to\n// know whether it's running in a TUI or headless context.\n//\n// Singleton — one emitter shared across the process.\n\nimport { EventEmitter } from 'events';\n\nexport interface DevRequestStartEvent {\n id: string;\n type: 'execute';\n method?: string;\n timestamp: number;\n}\n\nexport interface DevRequestCompleteEvent {\n id: string;\n success: boolean;\n duration: number;\n error?: string;\n}\n\nexport interface DevScenarioStartEvent {\n id: string;\n name?: string;\n timestamp: number;\n}\n\nexport interface DevImpersonateEvent {\n roles: string[] | null;\n}\n\nexport interface DevScenarioCompleteEvent {\n id: string;\n success: boolean;\n duration: number;\n roles: string[];\n error?: string;\n}\n\nclass DevEventEmitter extends EventEmitter {\n emitStart(event: DevRequestStartEvent) {\n this.emit('dev:start', event);\n }\n\n emitComplete(event: DevRequestCompleteEvent) {\n this.emit('dev:complete', event);\n }\n\n emitSessionExpired() {\n this.emit('dev:session-expired');\n }\n\n emitAuthRefreshStart(url: string) {\n this.emit('dev:auth-refresh-start', url);\n }\n\n emitAuthRefreshSuccess() {\n this.emit('dev:auth-refresh-success');\n }\n\n emitAuthRefreshFailed() {\n this.emit('dev:auth-refresh-failed');\n }\n\n emitConnectionWarning(message: string) {\n this.emit('dev:connection-warning', message);\n }\n\n emitConnectionRestored() {\n this.emit('dev:connection-restored');\n }\n\n emitImpersonate(event: DevImpersonateEvent) {\n this.emit('dev:impersonate', event);\n }\n\n emitScenarioStart(event: DevScenarioStartEvent) {\n this.emit('dev:scenario-start', event);\n }\n\n emitScenarioComplete(event: DevScenarioCompleteEvent) {\n this.emit('dev:scenario-complete', event);\n }\n\n onStart(handler: (event: DevRequestStartEvent) => void) {\n this.on('dev:start', handler);\n return () => this.off('dev:start', handler);\n }\n\n onComplete(handler: (event: DevRequestCompleteEvent) => void) {\n this.on('dev:complete', handler);\n return () => this.off('dev:complete', handler);\n }\n\n onSessionExpired(handler: () => void) {\n this.on('dev:session-expired', handler);\n return () => this.off('dev:session-expired', handler);\n }\n\n onAuthRefreshStart(handler: (url: string) => void) {\n this.on('dev:auth-refresh-start', handler);\n return () => this.off('dev:auth-refresh-start', handler);\n }\n\n onAuthRefreshSuccess(handler: () => void) {\n this.on('dev:auth-refresh-success', handler);\n return () => this.off('dev:auth-refresh-success', handler);\n }\n\n onAuthRefreshFailed(handler: () => void) {\n this.on('dev:auth-refresh-failed', handler);\n return () => this.off('dev:auth-refresh-failed', handler);\n }\n\n onConnectionWarning(handler: (message: string) => void) {\n this.on('dev:connection-warning', handler);\n return () => this.off('dev:connection-warning', handler);\n }\n\n onConnectionRestored(handler: () => void) {\n this.on('dev:connection-restored', handler);\n return () => this.off('dev:connection-restored', handler);\n }\n\n onImpersonate(handler: (event: DevImpersonateEvent) => void) {\n this.on('dev:impersonate', handler);\n return () => this.off('dev:impersonate', handler);\n }\n\n onScenarioStart(handler: (event: DevScenarioStartEvent) => void) {\n this.on('dev:scenario-start', handler);\n return () => this.off('dev:scenario-start', handler);\n }\n\n onScenarioComplete(handler: (event: DevScenarioCompleteEvent) => void) {\n this.on('dev:scenario-complete', handler);\n return () => this.off('dev:scenario-complete', handler);\n }\n}\n\nexport const devRequestEvents = new DevEventEmitter();\n","// esbuild-based TypeScript transpiler. Always transpiles fresh (no mtime cache).\n//\n// Output goes to {nearest node_modules}/.cache/mindstudio-dev/ so that:\n// 1. Node's ESM resolver can find @mindstudio-ai/agent (walks up to node_modules)\n// 2. The repo stays clean (.cache/ is conventionally gitignored)\n//\n// @mindstudio-ai/agent is marked external so it resolves from the project's\n// installed version at runtime, not bundled into the output. This is critical\n// because the SDK reads globalThis.ai and env vars set by the executor.\n\nimport { unlink, mkdir, readdir } from 'node:fs/promises';\nimport { existsSync } from 'node:fs';\nimport { resolve, dirname, basename, join } from 'node:path';\nimport { build } from 'esbuild';\nimport { log } from './logger';\n\nexport class Transpiler {\n private projectRoot: string;\n private outputFiles: Set<string> = new Set();\n\n constructor(projectRoot: string) {\n this.projectRoot = projectRoot;\n // Clean up orphaned .__ms_dev__.mjs files from previous runs\n // (or from the old transpiler that wrote next to source files)\n this.cleanupOrphans();\n }\n\n /** Remove any .__ms_dev__.mjs files found in the project source tree (not in node_modules/.cache). */\n private async cleanupOrphans(): Promise<void> {\n try {\n await removeOrphanedDevFiles(this.projectRoot);\n } catch {\n // Best effort\n }\n }\n\n /**\n * Transpile a method file to ESM JavaScript.\n * Returns the absolute path to the output .mjs file.\n * Output is written inside the nearest node_modules/.cache/mindstudio-dev/\n * so ESM resolver can find packages and the repo stays clean.\n */\n async transpile(methodPath: string): Promise<string> {\n const start = Date.now();\n const absolutePath = resolve(this.projectRoot, methodPath);\n const name = basename(absolutePath).replace(/\\.[^.]+$/, '');\n\n log.debug('Transpiling method', { methodPath });\n\n // Find nearest node_modules by walking up from the source file\n const nodeModulesDir = findNearestNodeModules(dirname(absolutePath));\n if (!nodeModulesDir) {\n log.error('Cannot find node_modules for method', { methodPath, searchStart: dirname(absolutePath) });\n throw new Error(\n `No node_modules found near ${methodPath}. Run npm install first.`,\n );\n }\n log.debug('Found node_modules', { path: nodeModulesDir });\n\n const outDir = join(nodeModulesDir, '.cache', 'mindstudio-dev');\n await mkdir(outDir, { recursive: true });\n\n const outfile = join(outDir, `${name}.__ms_dev__.mjs`);\n\n await build({\n entryPoints: [absolutePath],\n bundle: true,\n format: 'esm',\n platform: 'node',\n target: 'node22',\n outfile,\n external: ['@mindstudio-ai/agent'],\n absWorkingDir: this.projectRoot,\n logLevel: 'silent',\n });\n\n this.outputFiles.add(outfile);\n log.info(`Method transpiled in ${Date.now() - start}ms`, { methodPath, outfile });\n return outfile;\n }\n\n /**\n * Clean up all transpiled output files.\n */\n async cleanup(): Promise<void> {\n log.debug('Cleaning up transpiled files', { fileCount: this.outputFiles.size });\n for (const file of this.outputFiles) {\n await unlink(file).catch(() => {});\n }\n this.outputFiles.clear();\n }\n}\n\n/**\n * Recursively remove .__ms_dev__.mjs files from the project tree,\n * skipping node_modules (where they belong if in .cache/).\n */\nasync function removeOrphanedDevFiles(dir: string): Promise<void> {\n const entries = await readdir(dir, { withFileTypes: true });\n for (const entry of entries) {\n if (entry.name === 'node_modules' || entry.name === '.git') continue;\n const fullPath = join(dir, entry.name);\n if (entry.isDirectory()) {\n await removeOrphanedDevFiles(fullPath);\n } else if (entry.name.endsWith('.__ms_dev__.mjs')) {\n log.debug('Removing orphaned transpiled file', { path: fullPath });\n await unlink(fullPath).catch(() => {});\n }\n }\n}\n\n/**\n * Walk up from a directory to find the nearest node_modules.\n */\nfunction findNearestNodeModules(startDir: string): string | null {\n let dir = startDir;\n while (true) {\n const candidate = join(dir, 'node_modules');\n if (existsSync(candidate)) {\n return candidate;\n }\n const parent = dirname(dir);\n if (parent === dir) break; // reached root\n dir = parent;\n }\n return null;\n}\n","// Execute transpiled methods in a persistent worker process.\n//\n// Instead of spawning a new Node.js process per request (which costs ~1-2s in\n// cold start), we keep a single long-lived worker that receives requests over\n// IPC. The Node runtime and SDK modules stay warm across invocations.\n//\n// Concurrent requests are supported — the worker handles multiple async\n// invocations in parallel, matched by request ID.\n//\n// The worker is lazily spawned on first use, respawned if it dies, and killed\n// on cleanup. Per-request state (env vars, global.ai) is set before each call.\n\nimport { fork, type ChildProcess } from 'node:child_process';\nimport { writeFile, unlink } from 'node:fs/promises';\nimport { join } from 'node:path';\nimport { tmpdir } from 'node:os';\nimport { randomBytes } from 'node:crypto';\nimport { log } from './logger';\nimport type { DevSession } from './types';\n\nconst EXECUTION_TIMEOUT_MS = 30 * 60 * 1000; // 30 minutes — matches prod\n\nexport interface ExecuteMethodOptions {\n transpiledPath: string;\n methodExport: string;\n input: unknown;\n auth: DevSession['auth'];\n databases: DevSession['databases'];\n authorizationToken: string;\n apiBaseUrl: string;\n projectRoot: string;\n streamId?: string;\n}\n\nexport interface ExecuteMethodResult {\n success: boolean;\n output?: unknown;\n error?: { message: string; stack?: string };\n stdout?: string[];\n stats?: { memoryUsedBytes: number; executionTimeMs: number };\n}\n\n// ---------------------------------------------------------------------------\n// Worker management\n// ---------------------------------------------------------------------------\n\n/** Pending request waiting for a response from the worker. */\ninterface PendingRequest {\n resolve: (result: ExecuteMethodResult) => void;\n timer: ReturnType<typeof setTimeout>;\n}\n\nlet worker: ChildProcess | null = null;\nlet workerScriptPath: string | null = null;\nlet workerProjectRoot: string | null = null;\nconst pending = new Map<string, PendingRequest>();\n\n/** Build the persistent worker script. */\nfunction buildWorkerScript(): string {\n return `\nfunction serializeError(err) {\n if (!err) return { message: 'Unknown error' };\n\n const serialized = {\n message: String(err.message ?? err),\n stack: err.stack,\n };\n\n if (err.code !== undefined) serialized.code = err.code;\n if (err.statusCode !== undefined) serialized.statusCode = err.statusCode;\n if (err.status !== undefined) serialized.status = err.status;\n if (err.response !== undefined) {\n try { serialized.response = typeof err.response === 'string' ? err.response : JSON.stringify(err.response); } catch {}\n }\n if (err.body !== undefined) {\n try { serialized.body = typeof err.body === 'string' ? err.body : JSON.stringify(err.body); } catch {}\n }\n if (err.cause !== undefined) {\n serialized.cause = serializeError(err.cause);\n }\n\n for (const key of Object.keys(err)) {\n if (!(key in serialized)) {\n try {\n const val = err[key];\n if (val !== undefined && typeof val !== 'function') {\n serialized[key] = typeof val === 'object' ? JSON.stringify(val) : val;\n }\n } catch {}\n }\n }\n\n return serialized;\n}\n\n// Save original console methods so we can restore after each request\nconst _origLog = console.log;\nconst _origWarn = console.warn;\nconst _origError = console.error;\n\nprocess.on('message', async (msg) => {\n const { id, transpiledPath, methodExport, input, auth, databases, authorizationToken, apiBaseUrl, streamId } = msg;\n\n // Update per-request env vars\n process.env.CALLBACK_TOKEN = authorizationToken;\n process.env.REMOTE_HOSTNAME = apiBaseUrl;\n if (streamId) process.env.STREAM_ID = streamId;\n else delete process.env.STREAM_ID;\n\n // Update global context\n global.ai = { auth, databases };\n\n // Capture console output for this request\n const stdout = [];\n console.log = (...args) => stdout.push(args.map(String).join(' '));\n console.warn = (...args) => stdout.push(args.map(String).join(' '));\n console.error = (...args) => stdout.push(args.map(String).join(' '));\n\n const startTime = Date.now();\n\n try {\n // Cache-bust so code changes are picked up\n const mod = await import(transpiledPath + '?t=' + Date.now());\n const fn = mod[methodExport];\n if (typeof fn !== 'function') {\n throw new Error(methodExport + ' is not a function (got ' + typeof fn + ')');\n }\n const returnValue = await fn(input);\n const stats = { memoryUsedBytes: process.memoryUsage().heapUsed, executionTimeMs: Date.now() - startTime };\n process.send({ id, success: true, output: returnValue, stdout, stats });\n } catch (err) {\n const stats = { memoryUsedBytes: process.memoryUsage().heapUsed, executionTimeMs: Date.now() - startTime };\n process.send({ id, success: false, error: serializeError(err), stdout, stats });\n } finally {\n // Restore console\n console.log = _origLog;\n console.warn = _origWarn;\n console.error = _origError;\n }\n});\n\n// Signal ready\nprocess.send({ type: 'ready' });\n`;\n}\n\n/** Ensure a live worker process exists; spawn one if needed. */\nasync function ensureWorker(projectRoot: string): Promise<ChildProcess> {\n // Respawn if worker died or project root changed\n if (worker?.connected && workerProjectRoot === projectRoot) {\n return worker;\n }\n\n // Clean up old worker\n if (worker) {\n worker.removeAllListeners();\n worker.kill();\n worker = null;\n }\n\n // Clean up old script\n if (workerScriptPath) {\n await unlink(workerScriptPath).catch(() => {});\n workerScriptPath = null;\n }\n\n // Write worker script\n const scriptPath = join(\n tmpdir(),\n `ms-dev-worker-${randomBytes(4).toString('hex')}.mjs`,\n );\n await writeFile(scriptPath, buildWorkerScript(), 'utf-8');\n workerScriptPath = scriptPath;\n workerProjectRoot = projectRoot;\n\n log.debug('Spawning method execution process', { cwd: projectRoot, scriptPath });\n\n const child = fork(scriptPath, [], {\n cwd: projectRoot,\n stdio: ['ignore', 'pipe', 'pipe', 'ipc'],\n env: { ...process.env },\n });\n\n // Wait for ready signal\n await new Promise<void>((resolve, reject) => {\n const onMessage = (msg: any) => {\n if (msg?.type === 'ready') {\n child.off('message', onMessage);\n resolve();\n }\n };\n child.on('message', onMessage);\n child.on('error', reject);\n child.on('exit', (code) => reject(new Error(`Worker exited during startup with code ${code}`)));\n });\n\n // Route responses to pending requests\n child.on('message', (msg: any) => {\n if (!msg?.id) return;\n const req = pending.get(msg.id);\n if (!req) return;\n pending.delete(msg.id);\n clearTimeout(req.timer);\n req.resolve(msg as ExecuteMethodResult);\n });\n\n // If worker dies unexpectedly, reject all pending requests\n child.on('exit', (code) => {\n log.warn('Method execution process exited unexpectedly', { code });\n for (const [id, req] of pending) {\n clearTimeout(req.timer);\n req.resolve({ success: false, error: { message: `Worker process exited with code ${code}` } });\n }\n pending.clear();\n worker = null;\n });\n\n // Capture stderr for debugging\n child.stderr?.on('data', (chunk: Buffer) => {\n const text = chunk.toString().trim();\n if (text) log.warn('Method process stderr', { text: text.slice(0, 500) });\n });\n\n worker = child;\n log.info('Method execution process ready', { pid: child.pid });\n return child;\n}\n\n// ---------------------------------------------------------------------------\n// Public API\n// ---------------------------------------------------------------------------\n\n/**\n * Execute a transpiled method in the persistent worker process.\n */\nexport async function executeMethod(\n opts: ExecuteMethodOptions,\n): Promise<ExecuteMethodResult> {\n const w = await ensureWorker(opts.projectRoot);\n\n const id = randomBytes(8).toString('hex');\n\n log.debug('Sending method to execution process', { id, methodExport: opts.methodExport });\n\n return new Promise<ExecuteMethodResult>((resolve) => {\n const timer = setTimeout(() => {\n pending.delete(id);\n log.warn('Method execution timed out', { id, methodExport: opts.methodExport });\n resolve({\n success: false,\n error: { message: 'Method execution timed out after 30s' },\n });\n }, EXECUTION_TIMEOUT_MS);\n\n pending.set(id, { resolve, timer });\n\n w.send({\n id,\n transpiledPath: opts.transpiledPath,\n methodExport: opts.methodExport,\n input: opts.input,\n auth: opts.auth,\n databases: opts.databases,\n authorizationToken: opts.authorizationToken,\n apiBaseUrl: opts.apiBaseUrl,\n streamId: opts.streamId,\n });\n });\n}\n\n/**\n * Kill the persistent worker. Called on session stop / cleanup.\n */\nexport async function cleanupWorker(): Promise<void> {\n if (worker) {\n worker.removeAllListeners();\n worker.kill();\n worker = null;\n }\n if (workerScriptPath) {\n await unlink(workerScriptPath).catch(() => {});\n workerScriptPath = null;\n }\n workerProjectRoot = null;\n for (const [, req] of pending) {\n clearTimeout(req.timer);\n }\n pending.clear();\n}\n","import { getApiKey, getApiBaseUrl, getUserId } from './config';\n\nexport interface LocalModelRequest {\n id: string;\n organizationId: string;\n modelId: string;\n requestType: 'llm_chat' | 'image_generation' | 'video_generation';\n payload: {\n messages?: Array<{ role: string; content: string }>;\n prompt?: string;\n temperature?: number;\n maxTokens?: number;\n config?: Record<string, unknown>;\n };\n createdAt: number;\n}\n\nfunction getHeaders(): Record<string, string> {\n const apiKey = getApiKey();\n if (!apiKey) {\n throw new Error('Not authenticated. Run: mindstudio-local auth');\n }\n\n const headers: Record<string, string> = {\n Authorization: `Bearer ${apiKey}`,\n 'Content-Type': 'application/json',\n };\n\n const userId = getUserId();\n if (userId) {\n headers['x-user-id'] = userId;\n }\n\n return headers;\n}\n\nexport async function pollForRequest(\n modelIds: string[],\n): Promise<LocalModelRequest | null> {\n const baseUrl = getApiBaseUrl();\n const modelIdsParam = modelIds.join(',');\n\n const response = await fetch(\n `${baseUrl}/v1/local-models/poll?modelIds=${encodeURIComponent(modelIdsParam)}`,\n {\n method: 'GET',\n headers: getHeaders(),\n },\n );\n\n if (response.status === 204) {\n return null;\n }\n\n if (!response.ok) {\n const error = await response.text();\n throw new Error(`Poll failed: ${response.status} ${error}`);\n }\n const data = (await response.json()) as { request: LocalModelRequest };\n return data.request;\n}\n\n/**\n * Submit a progress update for a running request.\n * @param type - 'chunk' for streaming text content, 'log' for raw log lines\n */\nexport async function submitProgress(\n requestId: string,\n content: string,\n type: 'chunk' | 'log' = 'chunk',\n): Promise<void> {\n const baseUrl = getApiBaseUrl();\n\n const response = await fetch(\n `${baseUrl}/v1/local-models/requests/${requestId}/progress`,\n {\n method: 'POST',\n headers: getHeaders(),\n body: JSON.stringify({ type, content }),\n },\n );\n\n if (!response.ok) {\n console.warn(`Progress update failed: ${response.status}`);\n }\n}\n\n/**\n * Result for text/chat completions\n */\nexport interface TextResult {\n content?: string;\n usage?: { promptTokens: number; completionTokens: number };\n}\n\n/**\n * Result for image generation\n */\nexport interface ImageResult {\n /** Base64-encoded image data */\n imageBase64: string;\n /** MIME type (e.g., \"image/png\") */\n mimeType: string;\n /** Seed used for generation */\n seed?: number;\n}\n\n/**\n * Result for video generation\n */\nexport interface VideoResult {\n /** Base64-encoded video data */\n videoBase64: string;\n /** MIME type (e.g., \"video/webp\", \"video/mp4\") */\n mimeType: string;\n /** Duration in seconds */\n duration?: number;\n /** Frames per second */\n fps?: number;\n /** Seed used for generation */\n seed?: number;\n}\n\n/**\n * Combined result type\n */\nexport type RequestResult = TextResult | ImageResult | VideoResult;\n\nexport async function submitResult(\n requestId: string,\n success: boolean,\n result?: RequestResult,\n error?: string,\n): Promise<void> {\n const baseUrl = getApiBaseUrl();\n\n const response = await fetch(\n `${baseUrl}/v1/local-models/requests/${requestId}/result`,\n {\n method: 'POST',\n headers: getHeaders(),\n body: JSON.stringify({ success, result, error }),\n },\n );\n\n if (!response.ok) {\n const errorText = await response.text();\n throw new Error(\n `Result submission failed: ${response.status} ${errorText}`,\n );\n }\n}\n\nexport async function verifyApiKey(): Promise<boolean> {\n const baseUrl = getApiBaseUrl();\n\n try {\n const response = await fetch(`${baseUrl}/v1/local-models/verify-api-key`, {\n method: 'GET',\n headers: getHeaders(),\n });\n\n return response.status === 204 || response.ok;\n } catch {\n return false;\n }\n}\n\nexport type ModelTypeMindStudio =\n | 'llm_chat'\n | 'image_generation'\n | 'video_generation';\n\nexport interface SyncModelEntry {\n name: string;\n provider: string;\n type: ModelTypeMindStudio;\n parameters?: unknown[];\n}\n\nexport async function syncModels(models: SyncModelEntry[]): Promise<void> {\n const baseUrl = getApiBaseUrl();\n\n const response = await fetch(`${baseUrl}/v1/local-models/models/sync`, {\n method: 'POST',\n headers: getHeaders(),\n body: JSON.stringify({ models }),\n });\n\n if (!response.ok) {\n const errorText = await response.text();\n throw new Error(`Sync failed: ${response.status} ${errorText}`);\n }\n}\n\nexport interface SyncedModel {\n id: string;\n name: string;\n}\n\nexport async function getSyncedModels(): Promise<SyncedModel[]> {\n const baseUrl = getApiBaseUrl();\n\n const response = await fetch(`${baseUrl}/v1/local-models/models`, {\n method: 'GET',\n headers: getHeaders(),\n });\n\n if (!response.ok) {\n const errorText = await response.text();\n throw new Error(\n `Failed to fetch synced models: ${response.status} ${errorText}`,\n );\n }\n\n const data = (await response.json()) as { models: SyncedModel[] };\n return data.models;\n}\n\nexport async function requestDeviceAuth(): Promise<{\n url: string;\n token: string;\n}> {\n const baseUrl = getApiBaseUrl();\n\n const response = await fetch(`${baseUrl}/developer/v2/request-auth-url`, {\n method: 'GET',\n headers: { 'Content-Type': 'application/json' },\n });\n\n if (!response.ok) {\n const error = await response.text();\n throw new Error(`Device auth request failed: ${response.status} ${error}`);\n }\n\n const data = (await response.json()) as {\n url: string;\n token: string;\n };\n\n return data;\n}\n\nexport async function pollDeviceAuth(token: string): Promise<{\n status: 'pending' | 'completed' | 'expired';\n apiKey: string | null;\n userId: string | null;\n}> {\n const baseUrl = getApiBaseUrl();\n\n const response = await fetch(`${baseUrl}/developer/v2/poll-auth-url`, {\n method: 'POST',\n headers: { 'Content-Type': 'application/json' },\n body: JSON.stringify({ token }),\n });\n\n if (!response.ok) {\n const error = await response.text();\n throw new Error(`Device auth poll failed: ${response.status} ${error}`);\n }\n\n const data = (await response.json()) as {\n status: 'pending' | 'completed' | 'expired';\n apiKey: string | null;\n userId: string | null;\n };\n\n return data;\n}\n\nexport interface SpaEditorSessionInfo {\n sessionId: string;\n status: string;\n previewDomain: string | null;\n hotUpdateDomain: string | null;\n}\n\nexport interface CustomInterfaceStepInfo {\n stepId: string;\n stepType: string;\n displayName: string;\n workflowId: string;\n workflowName: string;\n spaEditorSession: SpaEditorSessionInfo | null;\n}\n\nexport interface ScriptStepInfo {\n stepId: string;\n displayName: string;\n workflowId: string;\n workflowName: string;\n files: Record<string, string>;\n entryFile: string;\n}\n\nexport interface EditorSession {\n appId: string;\n appName: string;\n customInterfaceSteps: CustomInterfaceStepInfo[];\n scriptSteps: ScriptStepInfo[];\n}\n\nexport async function getEditorSessions(): Promise<EditorSession[]> {\n const baseUrl = getApiBaseUrl();\n\n const response = await fetch(`${baseUrl}/v1/local-editor/sessions`, {\n method: 'GET',\n headers: getHeaders(),\n });\n\n if (!response.ok) {\n const errorText = await response.text();\n throw new Error(\n `Failed to fetch editor sessions: ${response.status} ${errorText}`,\n );\n }\n\n const data = (await response.json()) as { editors: EditorSession[] };\n return data.editors;\n}\n\nexport async function disconnectHeartbeat(): Promise<void> {\n const baseUrl = getApiBaseUrl();\n\n const response = await fetch(`${baseUrl}/v1/local-models/disconnect`, {\n method: 'POST',\n headers: getHeaders(),\n });\n\n if (!response.ok) {\n const error = await response.text();\n throw new Error(`Heartbeat disconnect failed: ${response.status} ${error}`);\n }\n}\n","// DevRunner — the core of dev mode.\n//\n// Lifecycle: start() → pollLoop() → handleRequest() → stop()\n//\n// The runner polls the platform for method execution requests, transpiles\n// TypeScript on the fly, executes methods in isolated child processes, and\n// posts results back. It does NOT handle the frontend (that's the proxy).\n//\n// The poll loop runs continuously. Requests are handled in the background\n// so multiple methods can execute in parallel without blocking the poll.\n// Connection issues trigger exponential backoff; 404 = session expired.\n\nimport {\n startDevSession,\n stopDevSession,\n pollDevRequest,\n submitDevResult,\n resetDevDatabase,\n impersonate,\n refreshContext,\n fetchCallbackToken,\n ApiError,\n DevPollError,\n} from './api';\nimport { devRequestEvents } from './events';\nimport { Transpiler } from './transpiler';\nimport { executeMethod, cleanupWorker } from './executor';\nimport { getApiBaseUrl } from '../config';\nimport { requestDeviceAuth, pollDeviceAuth } from '../api';\nimport { setApiKey, setUserId } from '../config';\nimport { randomBytes } from 'node:crypto';\nimport { log } from './logger';\nimport { logMethodExecution, logScenarioExecution } from './request-log';\nimport { formatErrorForDisplay } from './format-error';\nimport type { DevProxy } from './proxy';\nimport type { DevSession, DevRequest, DevResult, AppScenario } from './types';\n\nexport class DevRunner {\n private isRunning = false;\n private session: DevSession | null = null;\n private transpiler: Transpiler | null = null;\n private backoffMs = 1000;\n private hadConnectionWarning = false;\n private proxyUrl: string | undefined;\n private proxy: DevProxy | null = null;\n\n constructor(\n private readonly appId: string,\n private readonly projectRoot: string,\n private readonly startOpts: {\n branch?: string;\n proxyUrl?: string;\n methods?: Array<{ id: string; export: string; path: string }>;\n } = {},\n ) {}\n\n // proxyUrl is sent on every poll request so the platform dashboard can\n // show the developer's preview URL. Also included in the start request\n // so the dashboard sees it immediately without waiting for the first poll.\n setProxyUrl(url: string): void {\n this.proxyUrl = url;\n this.startOpts.proxyUrl = url;\n }\n\n setProxy(proxy: DevProxy): void {\n this.proxy = proxy;\n }\n\n async start(): Promise<DevSession> {\n if (this.isRunning) {\n throw new Error('DevRunner is already running');\n }\n\n log.info('Dev session starting', { appId: this.appId, branch: this.startOpts.branch });\n const session = await startDevSession(this.appId, this.startOpts);\n this.session = session;\n this.transpiler = new Transpiler(this.projectRoot);\n this.isRunning = true;\n this.backoffMs = 1000;\n\n log.info('Dev session started', { sessionId: session.sessionId, branch: session.branch });\n\n // Start poll loop in background\n this.pollLoop();\n\n return session;\n }\n\n async stop(): Promise<void> {\n log.info('Dev session stopping');\n this.isRunning = false;\n\n if (this.session) {\n try {\n await stopDevSession(this.appId, this.session.sessionId);\n } catch (err) {\n log.warn('Failed to stop dev session cleanly', { error: err instanceof Error ? err.message : String(err) });\n }\n this.session = null;\n }\n\n await cleanupWorker();\n\n if (this.transpiler) {\n await this.transpiler.cleanup();\n this.transpiler = null;\n }\n }\n\n getSession(): DevSession | null {\n return this.session;\n }\n\n // Set role override for subsequent method executions.\n async setImpersonation(roles: string[]): Promise<void> {\n if (!this.session) return;\n log.info('Setting role override', { roles });\n const result = await impersonate(this.appId, this.session.sessionId, roles);\n await this.refreshClientContext();\n devRequestEvents.emitImpersonate({ roles: result.roles });\n }\n\n // Clear role override — revert to session's default roles.\n async clearImpersonation(): Promise<void> {\n if (!this.session) return;\n log.info('Clearing role override');\n const result = await impersonate(this.appId, this.session.sessionId, null);\n await this.refreshClientContext();\n devRequestEvents.emitImpersonate({ roles: result.roles });\n }\n\n // Fetch fresh clientContext from platform and update the proxy.\n // Called after impersonation changes so the browser gets a new ms_iface token.\n private async refreshClientContext(): Promise<void> {\n if (!this.session || !this.proxy) return;\n try {\n const context = await refreshContext(this.appId, this.session.sessionId);\n this.session.clientContext = context;\n this.proxy.updateClientContext(context);\n } catch (err) {\n log.warn('Failed to refresh session context after role change', { error: err instanceof Error ? err.message : String(err) });\n }\n }\n\n // Run a method directly (not via poll loop). Used by headless stdin commands\n // and programmatic callers to test methods without a browser.\n async runMethod(opts: {\n methodExport: string;\n methodPath: string;\n input: unknown;\n }): Promise<{ success: boolean; output?: unknown; error?: Record<string, unknown> | null; stdout?: string[]; duration: number }> {\n if (!this.session || !this.transpiler) {\n return { success: false, error: { message: 'Session not started' }, duration: 0 };\n }\n\n const requestId = randomBytes(8).toString('hex');\n const startTime = Date.now();\n\n devRequestEvents.emitStart({\n id: requestId,\n type: 'execute',\n method: opts.methodExport,\n timestamp: startTime,\n });\n\n log.info('Method received (direct)', { requestId, method: opts.methodExport });\n\n try {\n const authorizationToken = await fetchCallbackToken(this.appId, this.session.sessionId);\n const transpiledPath = await this.transpiler.transpile(opts.methodPath);\n\n const result = await executeMethod({\n transpiledPath,\n methodExport: opts.methodExport,\n input: opts.input,\n auth: this.session.auth,\n databases: this.session.databases,\n authorizationToken,\n apiBaseUrl: getApiBaseUrl(),\n projectRoot: this.projectRoot,\n });\n\n const duration = Date.now() - startTime;\n\n if (result.success) {\n log.info('Method complete', { requestId, method: opts.methodExport, duration });\n } else {\n log.warn('Method failed', {\n requestId,\n method: opts.methodExport,\n duration,\n error: result.error ? formatErrorForDisplay(result.error) : undefined,\n });\n }\n\n logMethodExecution({\n requestId,\n sessionId: this.session.sessionId,\n methodExport: opts.methodExport,\n methodPath: opts.methodPath,\n input: opts.input,\n authorizationToken,\n databases: this.session.databases,\n result,\n duration,\n });\n\n devRequestEvents.emitComplete({\n id: requestId,\n success: result.success,\n duration,\n error: result.error ? formatErrorForDisplay(result.error) : undefined,\n });\n\n return {\n success: result.success,\n output: result.output,\n error: result.error ?? null,\n stdout: result.stdout,\n duration,\n };\n } catch (err) {\n const message = err instanceof Error ? err.message : 'Unknown error';\n const duration = Date.now() - startTime;\n log.error('Method error', { requestId, method: opts.methodExport, duration, error: message });\n\n logMethodExecution({\n requestId,\n sessionId: this.session.sessionId,\n methodExport: opts.methodExport,\n methodPath: opts.methodPath,\n input: opts.input,\n authorizationToken: '',\n databases: this.session.databases,\n result: { success: false, error: { message } },\n duration,\n });\n\n devRequestEvents.emitComplete({\n id: requestId,\n success: false,\n duration,\n error: message,\n });\n\n return { success: false, error: { message }, duration };\n }\n }\n\n // Run a scenario: truncate tables → execute seed → impersonate roles.\n // Called directly (not via poll loop) by the TUI or headless stdin.\n async runScenario(scenario: AppScenario): Promise<{\n success: boolean;\n databases: DevSession['databases'];\n error?: string;\n }> {\n if (!this.session || !this.transpiler) {\n return { success: false, databases: [], error: 'Session not started' };\n }\n\n const startTime = Date.now();\n const scenarioName = scenario.name ?? scenario.export;\n devRequestEvents.emitScenarioStart({\n id: scenario.id,\n name: scenarioName,\n timestamp: startTime,\n });\n\n log.info('Scenario starting', { id: scenario.id, name: scenarioName });\n\n try {\n // 1. Truncate all tables (clean slate)\n log.info('Resetting database for scenario');\n const databases = await resetDevDatabase(this.appId, this.session.sessionId, 'truncate');\n this.session.databases = databases;\n\n // 2. Transpile and execute the seed function\n log.info('Transpiling scenario', { path: scenario.path });\n const transpiledPath = await this.transpiler.transpile(scenario.path);\n\n // Fetch a callback token for the seed execution — same scoping as\n // poll-based tokens, but not tied to a poll request.\n const authorizationToken = await fetchCallbackToken(this.appId, this.session.sessionId);\n\n log.info('Running scenario seed function', { export: scenario.export });\n const result = await executeMethod({\n transpiledPath,\n methodExport: scenario.export,\n input: {},\n auth: this.session.auth,\n databases: this.session.databases,\n authorizationToken,\n apiBaseUrl: getApiBaseUrl(),\n projectRoot: this.projectRoot,\n });\n\n if (!result.success) {\n const error = result.error?.message ?? 'Scenario seed failed';\n log.error('Scenario seed function failed', { id: scenario.id, error });\n logScenarioExecution({\n sessionId: this.session.sessionId,\n scenario,\n databases: this.session.databases,\n result,\n duration: Date.now() - startTime,\n });\n devRequestEvents.emitScenarioComplete({\n id: scenario.id,\n success: false,\n duration: Date.now() - startTime,\n roles: scenario.roles,\n error,\n });\n return { success: false, databases, error };\n }\n\n // 3. Impersonate the scenario's roles\n if (scenario.roles.length > 0) {\n log.info('Setting role override for scenario', { roles: scenario.roles });\n await impersonate(this.appId, this.session.sessionId, scenario.roles);\n await this.refreshClientContext();\n }\n\n const duration = Date.now() - startTime;\n log.info('Scenario complete', { id: scenario.id, duration, roles: scenario.roles });\n logScenarioExecution({\n sessionId: this.session.sessionId,\n scenario,\n databases: this.session.databases,\n result,\n duration,\n });\n devRequestEvents.emitScenarioComplete({\n id: scenario.id,\n success: true,\n duration,\n roles: scenario.roles,\n });\n\n return { success: true, databases };\n } catch (err) {\n const error = err instanceof Error ? err.message : 'Unknown error';\n log.error('Scenario failed', { id: scenario.id, error });\n logScenarioExecution({\n sessionId: this.session.sessionId,\n scenario,\n databases: this.session.databases,\n result: null,\n infrastructureError: error,\n duration: Date.now() - startTime,\n });\n devRequestEvents.emitScenarioComplete({\n id: scenario.id,\n success: false,\n duration: Date.now() - startTime,\n roles: scenario.roles,\n error,\n });\n return { success: false, databases: this.session.databases, error };\n }\n }\n\n private async pollLoop(): Promise<void> {\n while (this.isRunning) {\n try {\n const request = await pollDevRequest(\n this.appId,\n this.session!.sessionId,\n this.proxyUrl,\n );\n\n if (this.hadConnectionWarning) {\n this.hadConnectionWarning = false;\n log.info('Connection to platform restored');\n devRequestEvents.emitConnectionRestored();\n }\n\n if (request) {\n // Process in background — don't block the poll loop\n this.handleRequest(request);\n }\n\n this.backoffMs = 1000;\n } catch (error) {\n // Session expired\n if (error instanceof DevPollError && error.statusCode === 404) {\n log.error('Dev session expired', { statusCode: 404 });\n devRequestEvents.emitSessionExpired();\n this.isRunning = false;\n return;\n }\n\n // Auth token expired — attempt automatic refresh\n if (\n (error instanceof DevPollError || error instanceof ApiError) &&\n error.statusCode === 401\n ) {\n log.warn('Session token expired, re-authenticating');\n const refreshed = await this.refreshAuth();\n if (refreshed) {\n // Token refreshed — reset backoff and continue polling\n this.backoffMs = 1000;\n continue;\n }\n // Refresh failed — treat as session expired\n log.error('Re-authentication failed');\n devRequestEvents.emitSessionExpired();\n this.isRunning = false;\n return;\n }\n\n // Connection issue — backoff and retry\n if (!this.hadConnectionWarning) {\n this.hadConnectionWarning = true;\n log.warn('Lost connection to platform, retrying');\n devRequestEvents.emitConnectionWarning(\n 'Lost connection to platform, retrying...',\n );\n }\n\n log.debug('Backing off', { ms: this.backoffMs });\n await this.sleep(this.backoffMs);\n this.backoffMs = Math.min(this.backoffMs * 2, 30_000);\n }\n }\n }\n\n private async handleRequest(request: DevRequest): Promise<void> {\n const startTime = Date.now();\n\n devRequestEvents.emitStart({\n id: request.requestId,\n type: request.type,\n method: request.methodExport,\n timestamp: startTime,\n });\n\n log.info('Method received', { requestId: request.requestId, method: request.methodExport });\n\n try {\n // Transpile\n log.debug('Transpiling method', { path: request.methodPath });\n const transpiledPath = await this.transpiler!.transpile(request.methodPath);\n\n // Role override lets the platform test methods as different users/roles\n // without restarting the session. If present, we build a custom auth\n // context with the overridden roles; otherwise use the session default.\n const auth = request.roleOverride\n ? {\n userId: this.session!.auth.userId,\n roleAssignments: request.roleOverride.map((roleName) => ({\n userId: this.session!.auth.userId,\n roleName,\n })),\n }\n : this.session!.auth;\n\n // Execute in isolated child process\n const result = await executeMethod({\n transpiledPath,\n methodExport: request.methodExport,\n input: request.input,\n auth,\n databases: this.session!.databases,\n authorizationToken: request.authorizationToken,\n apiBaseUrl: getApiBaseUrl(),\n projectRoot: this.projectRoot,\n streamId: request.streamId,\n });\n\n const devResult: DevResult = {\n type: 'execute',\n success: result.success,\n output: result.output,\n error: result.error,\n stdout: result.stdout,\n stats: result.stats,\n };\n\n await submitDevResult(\n this.appId,\n this.session!.sessionId,\n request.requestId,\n devResult,\n );\n\n const duration = Date.now() - startTime;\n if (result.success) {\n log.info('Method complete', { requestId: request.requestId, method: request.methodExport, duration });\n } else {\n log.warn('Method failed', {\n requestId: request.requestId,\n method: request.methodExport,\n duration,\n error: result.error ? formatErrorForDisplay(result.error) : undefined,\n });\n }\n\n logMethodExecution({\n requestId: request.requestId,\n sessionId: this.session!.sessionId,\n methodExport: request.methodExport,\n methodPath: request.methodPath,\n input: request.input,\n roleOverride: request.roleOverride,\n authorizationToken: request.authorizationToken,\n databases: this.session!.databases,\n result,\n duration,\n });\n\n devRequestEvents.emitComplete({\n id: request.requestId,\n success: result.success,\n duration,\n error: result.error ? formatErrorForDisplay(result.error) : undefined,\n });\n } catch (error) {\n const message =\n error instanceof Error ? error.message : 'Unknown error';\n const duration = Date.now() - startTime;\n log.error('Method error', { requestId: request.requestId, method: request.methodExport, duration, error: message });\n\n try {\n await submitDevResult(\n this.appId,\n this.session!.sessionId,\n request.requestId,\n {\n type: 'execute',\n success: false,\n error: { message },\n },\n );\n } catch (submitErr) {\n log.error('Failed to report method error to platform', { error: submitErr instanceof Error ? submitErr.message : String(submitErr) });\n }\n\n logMethodExecution({\n requestId: request.requestId,\n sessionId: this.session!.sessionId,\n methodExport: request.methodExport,\n methodPath: request.methodPath,\n input: request.input,\n roleOverride: request.roleOverride,\n authorizationToken: request.authorizationToken,\n databases: this.session!.databases,\n result: { success: false, error: { message } },\n duration: Date.now() - startTime,\n });\n\n devRequestEvents.emitComplete({\n id: request.requestId,\n success: false,\n duration: Date.now() - startTime,\n error: message,\n });\n }\n }\n\n /**\n * Attempt to refresh expired auth credentials via the device auth flow.\n * Opens the browser for the user to re-authorize, polls for the new token.\n * Returns true if refresh succeeded.\n */\n private async refreshAuth(): Promise<boolean> {\n const POLL_INTERVAL = 2000;\n const MAX_ATTEMPTS = 30;\n\n try {\n log.info('Session token expired, requesting re-authentication');\n const { url, token } = await requestDeviceAuth();\n\n devRequestEvents.emitAuthRefreshStart(url);\n\n // Try to open the browser — not fatal if it fails (headless, SSH, etc.)\n try {\n const open = (await import('open')).default;\n await open(url);\n } catch {\n log.warn('Could not open browser — visit URL to re-authenticate');\n }\n\n for (let i = 0; i < MAX_ATTEMPTS; i++) {\n await this.sleep(POLL_INTERVAL);\n if (!this.isRunning) return false;\n\n const result = await pollDeviceAuth(token);\n\n if (result.status === 'completed' && result.apiKey) {\n setApiKey(result.apiKey);\n if (result.userId) {\n setUserId(result.userId);\n }\n log.info('Re-authentication successful');\n devRequestEvents.emitAuthRefreshSuccess();\n return true;\n }\n\n if (result.status === 'expired') {\n break;\n }\n }\n\n log.error('Re-authentication timed out or was denied');\n devRequestEvents.emitAuthRefreshFailed();\n return false;\n } catch (err) {\n log.error('Re-authentication failed', { error: err instanceof Error ? err.message : String(err) });\n devRequestEvents.emitAuthRefreshFailed();\n return false;\n }\n }\n\n private sleep(ms: number): Promise<void> {\n return new Promise((resolve) => setTimeout(resolve, ms));\n }\n}\n\n","/**\n * Format an error object from the executor into a readable string.\n * Includes extra fields like code, statusCode, cause, etc. when present.\n */\nexport function formatErrorForDisplay(\n error: Record<string, unknown>,\n): string {\n const parts: string[] = [];\n\n // Main message\n if (error.message) {\n parts.push(String(error.message));\n }\n\n // Status/code info\n const code = error.code ?? error.statusCode ?? error.status;\n if (code !== undefined) {\n parts.push(`(code: ${code})`);\n }\n\n // Response body from HTTP errors\n if (error.body) {\n parts.push(`Response: ${String(error.body).slice(0, 200)}`);\n } else if (error.response) {\n parts.push(`Response: ${String(error.response).slice(0, 200)}`);\n }\n\n // Cause chain\n if (error.cause && typeof error.cause === 'object') {\n const cause = error.cause as Record<string, unknown>;\n if (cause.message) {\n parts.push(`Caused by: ${cause.message}`);\n }\n }\n\n return parts.join('\\n');\n}\n","/**\n * NDJSON log for browser-side events (console, errors, network, clicks).\n * Thin wrapper around NdjsonLog.\n */\n\nimport { NdjsonLog } from './ndjson-log';\n\nconst ndjsonLog = new NdjsonLog('browser.ndjson');\n\nexport function initBrowserLog(projectRoot: string): void {\n ndjsonLog.init(projectRoot);\n}\n\nexport function appendBrowserLogEntries(\n entries: Array<Record<string, unknown>>,\n): void {\n for (const entry of entries) {\n ndjsonLog.append({\n timestamp: new Date().toISOString(),\n ...entry,\n });\n }\n}\n\nexport function closeBrowserLog(): void {\n ndjsonLog.close();\n}\n","// Local dev proxy — sits between the browser and the upstream dev server.\n//\n// Why: the MindStudio frontend SDK needs window.__MINDSTUDIO__ (session\n// token, API URL, method mappings) to function. In production, the platform\n// injects this into HTML served from S3. In dev mode, the proxy does it\n// locally so the browser gets the same context without a platform round-trip.\n//\n// How it works:\n// - HTML responses: buffered, __MINDSTUDIO__ injected before </head>, served\n// - Everything else (JS, CSS, images, fonts): piped through unmodified\n// - WebSocket upgrades: forwarded transparently (enables HMR for any framework)\n// - CORS/PNA headers: added so the proxy works inside iframes from app.mindstudio.ai\n// - Caching disabled on all responses (this is local dev, always fresh)\n// - /__mindstudio_dev__/*: intercepted locally for browser agent communication\n//\n// The proxy is framework-agnostic — it doesn't know or care what dev server\n// is upstream. Detection is by content-type header, not URL patterns.\n\nimport http from 'node:http';\nimport { randomBytes } from 'node:crypto';\nimport type { Socket } from 'node:net';\nimport { log } from './logger';\nimport { appendBrowserLogEntries } from './browser-log';\n\ninterface PendingCommand {\n id: string;\n steps: Array<Record<string, unknown>>;\n}\n\ninterface PendingResult {\n resolve: (result: Record<string, unknown>) => void;\n timeout: ReturnType<typeof setTimeout>;\n}\n\nexport class DevProxy {\n private server: http.Server | null = null;\n private proxyPort: number | null = null;\n private commandQueue: PendingCommand[] = [];\n private pendingResults = new Map<string, PendingResult>();\n private lastBrowserPoll = 0;\n /** Long-poll waiters — browser agents waiting for the next command. */\n private commandWaiters: Array<{\n req: http.IncomingMessage;\n res: http.ServerResponse;\n timer: ReturnType<typeof setTimeout>;\n }> = [];\n\n /** Upstream dev server health tracking. */\n private upstreamUp = true;\n private healthCheckTimer: ReturnType<typeof setTimeout> | null = null;\n\n private static readonly HEALTH_CHECK_INTERVAL = 3_000;\n private static readonly HEALTH_CHECK_INTERVAL_DOWN = 1_000;\n private static readonly HEALTH_CHECK_TIMEOUT = 2_000;\n\n constructor(\n private readonly upstreamPort: number,\n private clientContext: Record<string, unknown>,\n private readonly bindAddress: string = '127.0.0.1',\n // Dev override: 'https://seankoji-msba.ngrok.io/index.js'\n private readonly browserAgentUrl?: string,\n ) {}\n\n updateClientContext(context: Record<string, unknown>): void {\n this.clientContext = context;\n log.info('Dev proxy context updated after role change');\n }\n\n /**\n * Whether a browser agent is actively connected.\n * True if there's a long-poll waiter or we've seen activity recently.\n */\n isBrowserConnected(): boolean {\n return this.commandWaiters.length > 0 || Date.now() - this.lastBrowserPoll < 500;\n }\n\n /**\n * Dispatch a browser command and wait for the result.\n * The command is queued for the browser agent to pick up via polling.\n * Returns a promise that resolves when the browser posts the result back.\n */\n dispatchBrowserCommand(\n steps: Array<Record<string, unknown>>,\n timeoutMs = 30_000,\n ): Promise<Record<string, unknown>> {\n if (!this.isBrowserConnected()) {\n return Promise.reject(\n new Error('No browser connected, please refresh the MindStudio preview'),\n );\n }\n\n const id = randomBytes(4).toString('hex');\n\n log.info('Browser command queued', { id, stepCount: steps.length, commands: steps.map((s) => s.command) });\n\n return new Promise((resolve, reject) => {\n const timeout = setTimeout(() => {\n this.pendingResults.delete(id);\n log.warn('Browser command timed out', { id, pendingCount: this.pendingResults.size, queueLength: this.commandQueue.length });\n reject(new Error('Browser command timed out'));\n }, timeoutMs);\n\n this.pendingResults.set(id, { resolve, timeout });\n this.commandQueue.push({ id, steps });\n this.flushCommandToWaiter();\n });\n }\n\n async start(preferredPort?: number): Promise<number> {\n const server = http.createServer((req, res) => {\n this.handleRequest(req, res);\n });\n\n // WebSocket upgrade forwarding\n server.on('upgrade', (req, socket, head) => {\n this.handleUpgrade(req, socket as Socket, head);\n });\n\n // Try the preferred port first, fall back to OS-assigned\n const portsToTry = preferredPort\n ? [preferredPort, 0]\n : [0];\n\n for (const port of portsToTry) {\n try {\n const assignedPort = await this.listenOnPort(server, port);\n this.server = server;\n this.proxyPort = assignedPort;\n this.startHealthCheck();\n log.info('Dev proxy started', { port: assignedPort, bind: this.bindAddress });\n return assignedPort;\n } catch {\n log.warn('Proxy port in use, trying next', { port });\n // Port in use — try next\n }\n }\n\n throw new Error('Failed to start proxy server');\n }\n\n private listenOnPort(server: http.Server, port: number): Promise<number> {\n return new Promise((resolve, reject) => {\n const onError = (err: Error) => {\n server.removeListener('error', onError);\n reject(err);\n };\n server.on('error', onError);\n\n server.listen(port, this.bindAddress, () => {\n server.removeListener('error', onError);\n const addr = server.address();\n if (!addr || typeof addr === 'string') {\n reject(new Error('Failed to get proxy server address'));\n return;\n }\n resolve(addr.port);\n });\n });\n }\n\n stop(): void {\n this.stopHealthCheck();\n\n if (this.server) {\n log.info('Dev proxy stopping');\n this.server.close();\n this.server = null;\n this.proxyPort = null;\n }\n\n // Reject pending commands so callers don't hang\n for (const [id, pending] of this.pendingResults) {\n clearTimeout(pending.timeout);\n pending.resolve({ id, steps: [], error: 'Proxy stopped' });\n }\n this.pendingResults.clear();\n this.commandQueue.length = 0;\n\n // Close any long-poll waiters\n for (const waiter of this.commandWaiters) {\n clearTimeout(waiter.timer);\n if (!waiter.res.writableEnded) {\n waiter.res.writeHead(204).end();\n }\n }\n this.commandWaiters.length = 0;\n }\n\n getPort(): number | null {\n return this.proxyPort;\n }\n\n // ---------------------------------------------------------------------------\n // Upstream health check\n // ---------------------------------------------------------------------------\n\n /**\n * Explicitly mark the upstream dev server as down.\n * Used by the stdin `dev-server-restarting` action when the parent process\n * knows a restart is happening (may be too fast for the health check to catch).\n * The health check will detect recovery and reload the browser.\n */\n markUpstreamDown(): void {\n if (!this.upstreamUp) return;\n this.upstreamUp = false;\n log.info('Upstream dev server marked as down (explicit signal)');\n this.scheduleHealthCheck(DevProxy.HEALTH_CHECK_INTERVAL_DOWN);\n }\n\n private startHealthCheck(): void {\n this.scheduleHealthCheck(DevProxy.HEALTH_CHECK_INTERVAL);\n }\n\n private stopHealthCheck(): void {\n if (this.healthCheckTimer) {\n clearTimeout(this.healthCheckTimer);\n this.healthCheckTimer = null;\n }\n }\n\n private scheduleHealthCheck(delayMs: number): void {\n this.stopHealthCheck();\n this.healthCheckTimer = setTimeout(() => this.checkUpstream(), delayMs);\n }\n\n private async checkUpstream(): Promise<void> {\n const wasUp = this.upstreamUp;\n\n try {\n const res = await fetch(`http://127.0.0.1:${this.upstreamPort}/`, {\n signal: AbortSignal.timeout(DevProxy.HEALTH_CHECK_TIMEOUT),\n });\n // Any response (even 404/500) means the server is alive\n this.upstreamUp = true;\n } catch {\n this.upstreamUp = false;\n }\n\n // Handle state transitions\n if (wasUp && !this.upstreamUp) {\n log.warn('Upstream dev server is down');\n } else if (!wasUp && this.upstreamUp) {\n log.info('Upstream dev server is back up, reloading browser');\n this.dispatchBrowserCommand([{ command: 'reload' }]).catch(() => {});\n }\n\n // Poll faster when down to catch recovery quickly\n const interval = this.upstreamUp\n ? DevProxy.HEALTH_CHECK_INTERVAL\n : DevProxy.HEALTH_CHECK_INTERVAL_DOWN;\n this.scheduleHealthCheck(interval);\n }\n\n // ---------------------------------------------------------------------------\n // CORS helper\n // ---------------------------------------------------------------------------\n\n private corsHeaders(req: http.IncomingMessage): Record<string, string> {\n const origin = req.headers.origin;\n if (!origin) return {};\n return {\n 'access-control-allow-origin': origin,\n 'access-control-allow-private-network': 'true',\n };\n }\n\n // ---------------------------------------------------------------------------\n // Request routing\n // ---------------------------------------------------------------------------\n\n private handleRequest(\n clientReq: http.IncomingMessage,\n clientRes: http.ServerResponse,\n ): void {\n // Browser agent endpoints — intercepted locally, never forwarded upstream\n if (clientReq.url?.startsWith('/__mindstudio_dev__/')) {\n if (clientReq.url === '/__mindstudio_dev__/logs' && clientReq.method === 'POST') {\n this.handleBrowserLogs(clientReq, clientRes);\n return;\n }\n if (clientReq.url === '/__mindstudio_dev__/commands' && clientReq.method === 'GET') {\n this.handleGetCommand(clientReq, clientRes);\n return;\n }\n if (clientReq.url === '/__mindstudio_dev__/results' && clientReq.method === 'POST') {\n this.handlePostResult(clientReq, clientRes);\n return;\n }\n }\n\n // CORS preflight\n if (clientReq.method === 'OPTIONS' && clientReq.headers.origin) {\n clientRes.writeHead(204, {\n ...this.corsHeaders(clientReq),\n 'access-control-allow-methods': 'GET, POST, OPTIONS',\n 'access-control-allow-headers': '*',\n });\n clientRes.end();\n return;\n }\n\n // Forward to upstream dev server\n this.forwardToUpstream(clientReq, clientRes);\n }\n\n // ---------------------------------------------------------------------------\n // Upstream forwarding\n // ---------------------------------------------------------------------------\n\n private forwardToUpstream(\n clientReq: http.IncomingMessage,\n clientRes: http.ServerResponse,\n ): void {\n const cors = this.corsHeaders(clientReq);\n\n const upstreamReq = http.request(\n {\n hostname: '127.0.0.1',\n port: this.upstreamPort,\n path: clientReq.url,\n method: clientReq.method,\n headers: { ...clientReq.headers, host: `localhost:${this.upstreamPort}` },\n },\n (upstreamRes) => {\n const contentType = upstreamRes.headers['content-type'] ?? '';\n const isHtml = contentType.startsWith('text/html');\n\n if (isHtml) {\n const chunks: Buffer[] = [];\n upstreamRes.on('data', (chunk) => chunks.push(chunk));\n upstreamRes.on('end', () => {\n let html = Buffer.concat(chunks).toString('utf-8');\n html = this.injectScripts(html);\n\n const headers = {\n ...upstreamRes.headers,\n ...cors,\n 'content-length': String(Buffer.byteLength(html, 'utf-8')),\n 'cache-control': 'no-store, no-cache, must-revalidate',\n };\n delete headers['content-encoding'];\n delete headers['etag'];\n\n log.debug('Dev proxy injected context into HTML', { path: clientReq.url, size: html.length });\n clientRes.writeHead(upstreamRes.statusCode ?? 200, headers);\n clientRes.end(html);\n });\n } else {\n const headers = {\n ...upstreamRes.headers,\n ...cors,\n 'cache-control': 'no-store, no-cache, must-revalidate',\n };\n delete headers['etag'];\n clientRes.writeHead(upstreamRes.statusCode ?? 200, headers);\n upstreamRes.pipe(clientRes);\n }\n },\n );\n\n upstreamReq.on('error', (err) => {\n log.warn('Dev proxy cannot reach dev server', { path: clientReq.url, error: err.message });\n clientRes.writeHead(502);\n clientRes.end(`Proxy error: ${err.message}`);\n });\n\n clientReq.pipe(upstreamReq);\n }\n\n // ---------------------------------------------------------------------------\n // Browser agent endpoints\n // ---------------------------------------------------------------------------\n\n private handleBrowserLogs(\n clientReq: http.IncomingMessage,\n clientRes: http.ServerResponse,\n ): void {\n const chunks: Buffer[] = [];\n clientReq.on('data', (chunk) => chunks.push(chunk));\n clientReq.on('end', () => {\n try {\n const body = Buffer.concat(chunks).toString('utf-8');\n const entries = JSON.parse(body);\n if (Array.isArray(entries)) {\n appendBrowserLogEntries(entries);\n }\n } catch {\n // Malformed payload — ignore\n }\n clientRes.writeHead(204, this.corsHeaders(clientReq));\n clientRes.end();\n });\n }\n\n private handleGetCommand(\n clientReq: http.IncomingMessage,\n clientRes: http.ServerResponse,\n ): void {\n this.lastBrowserPoll = Date.now();\n\n // If a command is already queued, respond immediately\n const command = this.commandQueue.shift();\n if (command) {\n log.info('Browser command dispatched to agent', { id: command.id, commands: command.steps.map((s) => s.command) });\n clientRes.writeHead(200, {\n ...this.corsHeaders(clientReq),\n 'content-type': 'application/json',\n 'cache-control': 'no-store',\n });\n clientRes.end(JSON.stringify(command));\n return;\n }\n\n // No command available — hold the connection open (long poll).\n // Respond with 204 after 25s so the browser can reconnect.\n const timer = setTimeout(() => {\n this.removeCommandWaiter(clientRes);\n clientRes.writeHead(204, {\n ...this.corsHeaders(clientReq),\n 'cache-control': 'no-store',\n });\n clientRes.end();\n }, 25_000);\n\n this.commandWaiters.push({ req: clientReq, res: clientRes, timer });\n\n // If the client disconnects, clean up\n clientReq.on('close', () => {\n this.removeCommandWaiter(clientRes);\n });\n }\n\n /**\n * Flush a queued command to a waiting long-poll connection, if any.\n */\n private flushCommandToWaiter(): void {\n while (this.commandWaiters.length > 0 && this.commandQueue.length > 0) {\n const waiter = this.commandWaiters.shift()!;\n clearTimeout(waiter.timer);\n\n // Skip if the connection was already closed\n if (waiter.res.writableEnded) continue;\n\n const command = this.commandQueue.shift()!;\n this.lastBrowserPoll = Date.now();\n log.info('Browser command dispatched to agent', { id: command.id, commands: command.steps.map((s) => s.command) });\n waiter.res.writeHead(200, {\n ...this.corsHeaders(waiter.req),\n 'content-type': 'application/json',\n 'cache-control': 'no-store',\n });\n waiter.res.end(JSON.stringify(command));\n return;\n }\n }\n\n private removeCommandWaiter(res: http.ServerResponse): void {\n const idx = this.commandWaiters.findIndex((w) => w.res === res);\n if (idx !== -1) {\n clearTimeout(this.commandWaiters[idx].timer);\n this.commandWaiters.splice(idx, 1);\n }\n }\n\n private handlePostResult(\n clientReq: http.IncomingMessage,\n clientRes: http.ServerResponse,\n ): void {\n const chunks: Buffer[] = [];\n clientReq.on('data', (chunk) => chunks.push(chunk));\n clientReq.on('end', () => {\n try {\n const body = Buffer.concat(chunks).toString('utf-8');\n const result = JSON.parse(body);\n if (result?.id) {\n const pending = this.pendingResults.get(result.id);\n if (pending) {\n log.info('Browser command result received', { id: result.id, stepCount: result.steps?.length, duration: result.duration });\n clearTimeout(pending.timeout);\n this.pendingResults.delete(result.id);\n pending.resolve(result);\n } else {\n log.warn('Browser command result received but no pending command found', { id: result.id, pendingIds: [...this.pendingResults.keys()] });\n }\n } else {\n log.warn('Browser command result received with no id', { bodyLength: body.length });\n }\n } catch (err) {\n log.warn('Browser command result parse error', { error: err instanceof Error ? err.message : String(err) });\n }\n clientRes.writeHead(204, this.corsHeaders(clientReq));\n clientRes.end();\n });\n }\n\n /**\n * Inject window.__MINDSTUDIO__ context and browser agent script tag into HTML.\n */\n private injectScripts(html: string): string {\n const contextScript = `<script>window.__MINDSTUDIO__=${JSON.stringify(this.clientContext)};</script>`;\n const agentUrl = this.browserAgentUrl || 'https://unpkg.com/@mindstudio-ai/browser-agent/dist/index.js';\n const agentScript = `<script async src=\"${agentUrl}\"></script>`;\n const injection = `${contextScript}\\n${agentScript}`;\n if (html.includes('</head>')) {\n return html.replace('</head>', `${injection}\\n</head>`);\n }\n return injection + '\\n' + html;\n }\n\n private handleUpgrade(\n clientReq: http.IncomingMessage,\n clientSocket: Socket,\n head: Buffer,\n ): void {\n log.debug('Dev proxy WebSocket upgrade', { path: clientReq.url });\n const options: http.RequestOptions = {\n hostname: '127.0.0.1',\n port: this.upstreamPort,\n path: clientReq.url,\n method: clientReq.method,\n headers: { ...clientReq.headers, host: `localhost:${this.upstreamPort}` },\n };\n\n const upstreamReq = http.request(options);\n\n upstreamReq.on('upgrade', (upstreamRes, upstreamSocket, upgradeHead) => {\n // Send the 101 response back to the client\n let responseHead = `HTTP/${upstreamRes.httpVersion} ${upstreamRes.statusCode} ${upstreamRes.statusMessage}\\r\\n`;\n for (let i = 0; i < upstreamRes.rawHeaders.length; i += 2) {\n responseHead += `${upstreamRes.rawHeaders[i]}: ${upstreamRes.rawHeaders[i + 1]}\\r\\n`;\n }\n responseHead += '\\r\\n';\n\n clientSocket.write(responseHead);\n\n if (upgradeHead.length > 0) {\n clientSocket.write(upgradeHead);\n }\n if (head.length > 0) {\n upstreamSocket.write(head);\n }\n\n // Pipe both directions\n upstreamSocket.pipe(clientSocket);\n clientSocket.pipe(upstreamSocket);\n\n // Clean up on close\n clientSocket.on('close', () => upstreamSocket.destroy());\n upstreamSocket.on('close', () => clientSocket.destroy());\n clientSocket.on('error', () => upstreamSocket.destroy());\n upstreamSocket.on('error', () => clientSocket.destroy());\n });\n\n upstreamReq.on('error', () => {\n clientSocket.destroy();\n });\n\n upstreamReq.end();\n }\n}\n","// Reads the project's mindstudio.json manifest and related config files.\n//\n// mindstudio.json is the source of truth for the app — it declares methods,\n// tables, interfaces, and the appId. The CLI reads it on startup to know\n// what to transpile, which dev server to start, and what to send to the platform.\n//\n// Web interface config (e.g. dist/interfaces/web/web.json) provides devPort\n// and devCommand for the frontend dev server.\n\nimport { readFileSync, existsSync } from 'node:fs';\nimport { join, dirname } from 'node:path';\nimport { log } from './logger';\nimport type { AppConfig, WebInterfaceConfig } from './types';\n\n/**\n * Read and parse mindstudio.json from the given directory.\n * Returns null if not found or invalid.\n */\nexport function detectAppConfig(cwd: string = process.cwd()): AppConfig | null {\n const appJsonPath = join(cwd, 'mindstudio.json');\n if (!existsSync(appJsonPath)) {\n log.debug('mindstudio.json not found', { path: appJsonPath });\n return null;\n }\n\n try {\n const raw = readFileSync(appJsonPath, 'utf-8');\n const parsed = JSON.parse(raw);\n\n // Minimum validation: must have name and methods\n if (!parsed.name || !Array.isArray(parsed.methods)) {\n return null;\n }\n\n const config = {\n appId: parsed.appId,\n name: parsed.name,\n description: parsed.description,\n roles: parsed.roles ?? [],\n tables: parsed.tables ?? [],\n methods: parsed.methods,\n scenarios: parsed.scenarios ?? [],\n interfaces: parsed.interfaces ?? [],\n };\n log.info('Loaded mindstudio.json', {\n appId: config.appId,\n roles: config.roles.length,\n methods: config.methods.length,\n tables: config.tables.length,\n scenarios: config.scenarios.length,\n interfaces: config.interfaces.length,\n });\n return config;\n } catch (err) {\n log.warn('Failed to parse mindstudio.json', { error: err instanceof Error ? err.message : String(err) });\n return null;\n }\n}\n\n/**\n * Find the web interface config from mindstudio.json and read its devPort/devCommand.\n * Returns null if no web interface is declared or config file doesn't exist.\n */\nexport function getWebInterfaceConfig(\n appConfig: AppConfig,\n cwd: string = process.cwd(),\n): WebInterfaceConfig | null {\n const webInterface = appConfig.interfaces.find(\n (i) => i.type === 'web' && i.enabled !== false,\n );\n if (!webInterface) {\n return null;\n }\n\n const configPath = join(cwd, webInterface.path);\n if (!existsSync(configPath)) {\n return null;\n }\n\n try {\n const raw = readFileSync(configPath, 'utf-8');\n const parsed = JSON.parse(raw);\n const web = parsed.web;\n if (!web || typeof web !== 'object') {\n return null;\n }\n\n return {\n devPort: typeof web.devPort === 'number' ? web.devPort : undefined,\n devCommand: typeof web.devCommand === 'string' ? web.devCommand : undefined,\n };\n } catch {\n return null;\n }\n}\n\n/**\n * Get the web interface project directory from mindstudio.json.\n * The convention is that the config file lives inside the web project directory.\n */\nexport function getWebProjectDir(\n appConfig: AppConfig,\n cwd: string = process.cwd(),\n): string | null {\n const webInterface = appConfig.interfaces.find(\n (i) => i.type === 'web' && i.enabled !== false,\n );\n if (!webInterface) {\n return null;\n }\n\n return dirname(join(cwd, webInterface.path));\n}\n\n/**\n * Read raw TypeScript source for each table file listed in mindstudio.json.\n * Returns array of { name, source } for sending to sync-schema endpoint.\n * Skips files that don't exist.\n */\nexport function readTableSources(\n appConfig: AppConfig,\n cwd: string = process.cwd(),\n): Array<{ name: string; source: string }> {\n const results: Array<{ name: string; source: string }> = [];\n\n for (const table of appConfig.tables) {\n const filePath = join(cwd, table.path);\n if (!existsSync(filePath)) {\n log.warn('Table source file not found', { table: table.export, path: table.path });\n continue;\n }\n\n try {\n const source = readFileSync(filePath, 'utf-8');\n // Use the export name as the table name for error reporting\n const name = table.export;\n results.push({ name, source });\n } catch (err) {\n log.warn('Table source file unreadable', { table: table.export, path: table.path, error: err instanceof Error ? err.message : String(err) });\n }\n }\n\n if (results.length < appConfig.tables.length) {\n log.warn('Missing ' + (appConfig.tables.length - results.length) + ' table source file(s)', { found: results.length, expected: appConfig.tables.length });\n }\n\n return results;\n}\n\n/**\n * Find project directories that have a package.json but no node_modules.\n * Returns paths that need `npm install`.\n */\nexport function findDirsNeedingInstall(\n appConfig: AppConfig,\n cwd: string = process.cwd(),\n): string[] {\n const dirs: string[] = [];\n\n // Backend directory (derived from first method path, e.g. dist/backend/src/foo.ts → dist/backend)\n if (appConfig.methods.length > 0) {\n const firstMethodPath = appConfig.methods[0].path;\n // Walk up from the method file to find the nearest package.json\n const parts = firstMethodPath.split('/');\n for (let i = parts.length - 1; i >= 1; i--) {\n const candidate = join(cwd, ...parts.slice(0, i));\n if (existsSync(join(candidate, 'package.json'))) {\n if (!existsSync(join(candidate, 'node_modules'))) {\n dirs.push(candidate);\n }\n break;\n }\n }\n }\n\n // Web frontend directory\n const webProjectDir = getWebProjectDir(appConfig, cwd);\n if (webProjectDir && existsSync(join(webProjectDir, 'package.json'))) {\n if (!existsSync(join(webProjectDir, 'node_modules'))) {\n dirs.push(webProjectDir);\n }\n }\n\n return dirs;\n}\n","// Shared utilities for dev mode — used by both headless and TUI orchestrators.\n\nimport { execSync } from 'node:child_process';\n\n/** Derive a stable port number (3100-3999) from the app ID so the proxy URL is consistent. */\nexport function stablePort(appId: string): number {\n let hash = 0;\n for (let i = 0; i < appId.length; i++) {\n hash = ((hash << 5) - hash + appId.charCodeAt(i)) | 0;\n }\n return 3100 + (Math.abs(hash) % 900);\n}\n\n/** Detect current git branch, or undefined if not in a git repo. */\nexport function detectGitBranch(): string | undefined {\n try {\n return execSync('git rev-parse --abbrev-ref HEAD', {\n encoding: 'utf-8',\n stdio: ['ignore', 'pipe', 'ignore'],\n }).trim() || undefined;\n } catch {\n return undefined;\n }\n}\n","// Watches directories containing table source files and triggers a callback\n// when a declared table file is created or modified. Used by both headless\n// and TUI modes to auto-sync schema without session restart.\n//\n// Uses chokidar instead of fs.watch so that:\n// - Atomic file replacements (write-tmp + rename) are detected on Linux\n// - Directories that don't exist yet are watched once created\n// - Events are deduplicated and debounced reliably\n\nimport { watch } from 'chokidar';\nimport { join, dirname, basename } from 'node:path';\nimport { log } from './logger';\nimport type { AppTable } from './types';\n\n/**\n * Watch table source directories for changes.\n *\n * @param tables - Table entries from appConfig.tables\n * @param cwd - Project root directory\n * @param onChanged - Called (debounced 500ms) when a table file changes\n * @returns Cleanup function that closes all watchers and clears timers\n */\nexport function watchTableFiles(\n tables: AppTable[],\n cwd: string,\n onChanged: () => void,\n): () => void {\n if (tables.length === 0) return () => {};\n\n // Resolve absolute paths for each table file\n const filePaths = tables.map((t) => join(cwd, t.path));\n\n let syncTimer: ReturnType<typeof setTimeout> | undefined;\n\n const watcher = watch(filePaths, {\n ignoreInitial: true,\n // Don't fail if files don't exist yet — watch for creation\n disableGlobbing: true,\n });\n\n watcher.on('all', () => {\n clearTimeout(syncTimer);\n syncTimer = setTimeout(onChanged, 500);\n });\n\n // Build a map for logging\n const dirToFiles = new Map<string, Set<string>>();\n for (const table of tables) {\n const absPath = join(cwd, table.path);\n const dir = dirname(absPath);\n const file = basename(absPath);\n if (!dirToFiles.has(dir)) dirToFiles.set(dir, new Set());\n dirToFiles.get(dir)!.add(file);\n }\n\n log.info('Watching table source files', {\n dirs: dirToFiles.size,\n tables: tables.length,\n });\n\n return () => {\n clearTimeout(syncTimer);\n watcher.close();\n };\n}\n","// Watches mindstudio.json for changes and triggers a callback.\n//\n// Uses chokidar instead of fs.watch so that atomic file replacements\n// (write-tmp + rename) are detected on Linux. fs.watch watches the inode,\n// so a rename-based write silently kills the watcher.\n\nimport { watch } from 'chokidar';\nimport { join } from 'node:path';\nimport { log } from './logger';\n\n/**\n * Watch mindstudio.json for changes.\n *\n * @param cwd - Project root directory\n * @param onChanged - Called (debounced 500ms) when the config file changes\n * @returns Cleanup function that closes the watcher and clears timers\n */\nexport function watchConfigFile(\n cwd: string,\n onChanged: () => void,\n): () => void {\n const configPath = join(cwd, 'mindstudio.json');\n\n let debounceTimer: ReturnType<typeof setTimeout> | undefined;\n\n const watcher = watch(configPath, {\n ignoreInitial: true,\n disableGlobbing: true,\n });\n\n watcher.on('all', () => {\n clearTimeout(debounceTimer);\n debounceTimer = setTimeout(() => {\n onChanged();\n }, 500);\n });\n\n log.info('Watching mindstudio.json for changes', { path: configPath });\n\n return () => {\n clearTimeout(debounceTimer);\n watcher.close();\n };\n}\n"],"mappings":"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","names":["fs","fs","join","join","unlink","join","unlink","join","resolve","getHeaders","randomBytes","randomBytes","resolve","ndjsonLog","randomBytes","randomBytes","resolve","pending","existsSync","join","dirname","join","existsSync","config","dirname","join","dirname","basename","join","dirname","basename","watch","join","join","watch"]}
|
|
1
|
+
{"version":3,"sources":["../src/config.ts","../src/dev/logger.ts","../src/dev/api.ts","../src/dev/ndjson-log.ts","../src/dev/request-log.ts","../src/dev/events.ts","../src/dev/transpiler.ts","../src/dev/executor.ts","../src/api.ts","../src/dev/runner.ts","../src/dev/format-error.ts","../src/dev/browser-log.ts","../src/dev/proxy.ts","../src/dev/app-config.ts","../src/dev/utils.ts","../src/dev/table-watcher.ts","../src/dev/config-watcher.ts"],"sourcesContent":["import Conf from 'conf';\nimport os from 'node:os';\nimport path from 'node:path';\n\nexport type Environment = 'prod' | 'local';\n\ninterface EnvironmentConfig {\n apiKey?: string;\n userId?: string;\n apiBaseUrl: string;\n}\n\ninterface ConfigSchema {\n environment: Environment;\n providerBaseUrls: Record<string, string>;\n providerInstallPaths: Record<string, string>;\n localInterfaces: Record<string, string>;\n environments: {\n prod: EnvironmentConfig;\n local: EnvironmentConfig;\n };\n}\n\nexport const config = new Conf<ConfigSchema>({\n projectName: 'mindstudio-local',\n cwd: path.join(os.homedir(), '.mindstudio-local-tunnel'),\n configName: 'config',\n defaults: {\n environment: 'prod',\n providerBaseUrls: {},\n providerInstallPaths: {},\n localInterfaces: {},\n environments: {\n prod: {\n apiBaseUrl: 'https://api.mindstudio.ai',\n },\n local: {\n apiBaseUrl: 'http://localhost:3129',\n },\n },\n },\n});\n\n// Environment management\nexport function getEnvironment(): Environment {\n return config.get('environment');\n}\n\nexport function setEnvironment(env: Environment): void {\n config.set('environment', env);\n}\n\n// Get config for current environment\nfunction getEnvConfig(): EnvironmentConfig {\n const env = getEnvironment();\n return config.get(`environments.${env}`) as EnvironmentConfig;\n}\n\nfunction setEnvConfig(key: keyof EnvironmentConfig, value: string): void {\n const env = getEnvironment();\n config.set(`environments.${env}.${key}`, value);\n}\n\n// API Key (per environment)\nexport function getApiKey(): string | undefined {\n return getEnvConfig().apiKey;\n}\n\nexport function setApiKey(key: string): void {\n setEnvConfig('apiKey', key);\n}\n\nexport function clearApiKey(): void {\n const env = getEnvironment();\n config.delete(`environments.${env}.apiKey` as keyof ConfigSchema);\n}\n\n// User ID (per environment)\nexport function getUserId(): string | undefined {\n return getEnvConfig().userId;\n}\n\nexport function setUserId(id: string): void {\n setEnvConfig('userId', id);\n}\n\nexport function clearUserId(): void {\n const env = getEnvironment();\n config.delete(`environments.${env}.userId` as keyof ConfigSchema);\n}\n\n// API Base URL (per environment)\nexport function getApiBaseUrl(): string {\n return getEnvConfig().apiBaseUrl;\n}\n\nexport function setApiBaseUrl(url: string): void {\n setEnvConfig('apiBaseUrl', url);\n}\n\nexport function getConfigPath(): string {\n return config.path;\n}\n\n// Provider helpers\nexport function getProviderBaseUrl(name: string, defaultUrl: string): string {\n const urls = config.get('providerBaseUrls');\n return urls[name] ?? defaultUrl;\n}\n\nexport function setProviderBaseUrl(name: string, url: string): void {\n const urls = config.get('providerBaseUrls');\n urls[name] = url;\n config.set('providerBaseUrls', urls);\n}\n\nexport function getProviderInstallPath(name: string): string | undefined {\n const paths = config.get('providerInstallPaths');\n return paths[name];\n}\n\nexport function setProviderInstallPath(\n name: string,\n installPath: string,\n): void {\n const paths = config.get('providerInstallPaths');\n paths[name] = installPath;\n config.set('providerInstallPaths', paths);\n}\n\n// Local interface helpers\nexport function getLocalInterfacesDir(): string {\n return path.join(os.homedir(), '.mindstudio-local-tunnel', 'interfaces');\n}\n\nexport function getLocalInterfacePath(key: string): string | undefined {\n const interfaces = config.get('localInterfaces');\n return interfaces[key];\n}\n\nexport function setLocalInterfacePath(key: string, dirPath: string): void {\n const interfaces = config.get('localInterfaces');\n interfaces[key] = dirPath;\n config.set('localInterfaces', interfaces);\n}\n\nexport function deleteLocalInterfacePath(key: string): void {\n const interfaces = config.get('localInterfaces');\n delete interfaces[key];\n config.set('localInterfaces', interfaces);\n}\n\n// Get all environment info for display\nexport function getEnvironmentInfo(): {\n current: Environment;\n apiBaseUrl: string;\n hasApiKey: boolean;\n} {\n const env = getEnvironment();\n const envConfig = getEnvConfig();\n return {\n current: env,\n apiBaseUrl: envConfig.apiBaseUrl,\n hasApiKey: !!envConfig.apiKey,\n };\n}\n","/**\n * Structured logger with configurable level and output target.\n *\n * - Headless mode: writes to stderr (stdout reserved for JSON events)\n * - Interactive mode: writes to .mindstudio-dev.log in cwd (won't interfere with Ink TUI)\n *\n * Levels: error > warn > info > debug\n */\n\nimport fs from 'node:fs';\n\nexport type LogLevel = 'error' | 'warn' | 'info' | 'debug';\n\nconst LEVELS: Record<LogLevel, number> = {\n error: 0,\n warn: 1,\n info: 2,\n debug: 3,\n};\n\nlet currentLevel: number = LEVELS.error;\nlet writeFn: (line: string) => void = () => {};\n\nfunction timestamp(): string {\n return new Date().toISOString();\n}\n\nfunction write(level: LogLevel, msg: string, data?: Record<string, unknown>) {\n if (LEVELS[level] > currentLevel) {\n return;\n }\n const parts = [`[${timestamp()}]`, level.toUpperCase().padEnd(5), msg];\n if (data) {\n parts.push(JSON.stringify(data));\n }\n writeFn(parts.join(' '));\n}\n\nexport const log = {\n error(msg: string, data?: Record<string, unknown>) {\n write('error', msg, data);\n },\n warn(msg: string, data?: Record<string, unknown>) {\n write('warn', msg, data);\n },\n info(msg: string, data?: Record<string, unknown>) {\n write('info', msg, data);\n },\n debug(msg: string, data?: Record<string, unknown>) {\n write('debug', msg, data);\n },\n};\n\n/** Configure logger for headless mode — writes to stderr. */\nexport function initLoggerHeadless(level: LogLevel = 'info'): void {\n currentLevel = LEVELS[level];\n writeFn = (line) => {\n process.stderr.write(line + '\\n');\n };\n}\n\n/** Configure logger for interactive mode — writes to .mindstudio-dev.log. */\nexport function initLoggerInteractive(level: LogLevel = 'error'): void {\n currentLevel = LEVELS[level];\n let fd: number | null = null;\n writeFn = (line) => {\n try {\n if (fd === null) {\n fd = fs.openSync('.mindstudio-dev.log', 'a');\n }\n fs.writeSync(fd, line + '\\n');\n } catch {\n // Best-effort — don't crash if we can't write logs\n }\n };\n}\n","// Platform API client for dev sessions.\n//\n// All endpoints are under /_internal/v2/apps/{appId}/dev/.\n// Auth: Bearer token (API key), plus x-dev-session header for session-scoped endpoints.\n// The dev session IS a release — sessionId and releaseId are the same UUID.\n\nimport { getApiKey, getApiBaseUrl } from '../config';\nimport { log } from './logger';\nimport type { DevSession, DevRequest, DevResult, SyncSchemaResponse } from './types';\n\n// ---------------------------------------------------------------------------\n// Internal helpers\n// ---------------------------------------------------------------------------\n\nfunction getHeaders(sessionId?: string): Record<string, string> {\n const apiKey = getApiKey();\n if (!apiKey) {\n throw new Error('Not authenticated. Run mindstudio-local to set up.');\n }\n\n const headers: Record<string, string> = {\n Authorization: `Bearer ${apiKey}`,\n 'Content-Type': 'application/json',\n };\n\n if (sessionId) headers['x-dev-session'] = sessionId;\n\n return headers;\n}\n\nfunction basePath(appId: string): string {\n return `${getApiBaseUrl()}/_internal/v2/apps/${appId}/dev`;\n}\n\n/**\n * Generic API request with consistent logging, timing, and error handling.\n * Returns null for 204 responses. Throws on non-ok status.\n */\nasync function apiRequest<T>(\n method: string,\n url: string,\n headers: Record<string, string>,\n body?: unknown,\n): Promise<T> {\n const start = Date.now();\n const logTag = `${method} ${url.replace(getApiBaseUrl(), '')}`;\n\n const response = await fetch(url, {\n method,\n headers,\n ...(body !== undefined ? { body: JSON.stringify(body) } : {}),\n });\n\n const duration = Date.now() - start;\n\n if (response.status === 204) {\n log.debug(`api ${logTag} → 204 (${duration}ms)`);\n return null as T;\n }\n\n if (!response.ok) {\n const error = await response.text();\n log.error(`api ${logTag} → ${response.status} (${duration}ms)`, { error });\n throw new ApiError(`${logTag} failed: ${response.status} ${error}`, response.status);\n }\n\n const data = (await response.json()) as T;\n log.info(`api ${logTag} → ${response.status} (${duration}ms)`);\n return data;\n}\n\n// ---------------------------------------------------------------------------\n// Public API\n// ---------------------------------------------------------------------------\n\nexport async function startDevSession(\n appId: string,\n opts?: {\n branch?: string;\n proxyUrl?: string;\n methods?: Array<{ id: string; export: string; path: string }>;\n },\n): Promise<DevSession> {\n const body: Record<string, unknown> = {};\n if (opts?.branch) body.branch = opts.branch;\n if (opts?.proxyUrl) body.proxyUrl = opts.proxyUrl;\n if (opts?.methods) body.methods = opts.methods;\n\n return apiRequest<DevSession>('POST', `${basePath(appId)}/manage/start`, getHeaders(), body);\n}\n\nexport async function stopDevSession(\n appId: string,\n sessionId: string,\n): Promise<void> {\n await apiRequest<void>('POST', `${basePath(appId)}/manage/stop`, getHeaders(sessionId));\n}\n\nexport async function pollDevRequest(\n appId: string,\n sessionId: string,\n proxyUrl?: string,\n): Promise<DevRequest | null> {\n const url = proxyUrl\n ? `${basePath(appId)}/poll?proxyUrl=${encodeURIComponent(proxyUrl)}`\n : `${basePath(appId)}/poll`;\n\n try {\n return await apiRequest<DevRequest | null>('GET', url, getHeaders(sessionId));\n } catch (err) {\n // Re-throw as DevPollError so the runner can detect session expiry (404)\n if (err instanceof ApiError) {\n throw new DevPollError(err.message, err.statusCode);\n }\n throw err;\n }\n}\n\nexport async function submitDevResult(\n appId: string,\n sessionId: string,\n requestId: string,\n result: DevResult,\n): Promise<void> {\n await apiRequest<void>(\n 'POST',\n `${basePath(appId)}/result/${requestId}`,\n getHeaders(sessionId),\n result,\n );\n}\n\nexport async function syncSchema(\n appId: string,\n sessionId: string,\n tables: Array<{ name: string; source: string }>,\n): Promise<SyncSchemaResponse> {\n return apiRequest<SyncSchemaResponse>(\n 'POST',\n `${basePath(appId)}/manage/sync-schema`,\n getHeaders(sessionId),\n { tables },\n );\n}\n\nexport async function resetDevDatabase(\n appId: string,\n sessionId: string,\n mode: 'snapshot' | 'truncate' = 'snapshot',\n): Promise<DevSession['databases']> {\n const data = await apiRequest<{ databases: DevSession['databases'] }>(\n 'POST',\n `${basePath(appId)}/manage/reset?mode=${mode}`,\n getHeaders(sessionId),\n );\n return data.databases;\n}\n\nexport async function impersonate(\n appId: string,\n sessionId: string,\n roles: string[] | null,\n): Promise<{ roles: string[] | null }> {\n return apiRequest<{ roles: string[] | null }>(\n 'POST',\n `${basePath(appId)}/manage/impersonate`,\n getHeaders(sessionId),\n { roles: roles && roles.length > 0 ? roles : null },\n );\n}\n\nexport async function refreshContext(\n appId: string,\n sessionId: string,\n): Promise<Record<string, unknown>> {\n const data = await apiRequest<{ clientContext: Record<string, unknown> }>(\n 'POST',\n `${basePath(appId)}/manage/refresh-context`,\n getHeaders(sessionId),\n );\n return data.clientContext;\n}\n\n// Fetch a callback token for one-off executions (scenarios, etc.)\n// that don't come from the poll loop.\nexport async function fetchCallbackToken(\n appId: string,\n sessionId: string,\n): Promise<string> {\n const data = await apiRequest<{ authorizationToken: string }>(\n 'POST',\n `${basePath(appId)}/manage/token`,\n getHeaders(sessionId),\n );\n return data.authorizationToken;\n}\n\nexport async function getUploadUrl(\n appId: string,\n sessionId: string,\n extension: string,\n contentType: string,\n): Promise<{ uploadUrl: string; uploadFields: Record<string, string>; publicUrl: string }> {\n return apiRequest(\n 'POST',\n `${basePath(appId)}/manage/upload`,\n getHeaders(sessionId),\n { extension, contentType },\n );\n}\n\n// ---------------------------------------------------------------------------\n// Error classes\n// ---------------------------------------------------------------------------\n\n/** API request error with HTTP status code. */\nexport class ApiError extends Error {\n constructor(\n message: string,\n public readonly statusCode: number,\n ) {\n super(message);\n this.name = 'ApiError';\n }\n}\n\n/** Poll-specific error — runner checks statusCode to detect session expiry (404). */\nexport class DevPollError extends Error {\n constructor(\n message: string,\n public readonly statusCode: number,\n ) {\n super(message);\n this.name = 'DevPollError';\n }\n}\n","/**\n * Shared NDJSON log writer with rotation.\n *\n * Used by browser-log.ts and request-log.ts. Handles fd management,\n * line counting, append, and rotation when the file exceeds limits.\n */\n\nimport fs from 'node:fs';\nimport { join } from 'node:path';\nimport { log } from './logger';\n\nexport class NdjsonLog {\n private fd: number | null = null;\n private logPath: string | null = null;\n private lineCount = 0;\n private rotating = false;\n\n constructor(\n private readonly filename: string,\n private readonly maxLines = 500,\n private readonly keepLines = 300,\n private readonly maxBytes = 2 * 1024 * 1024,\n ) {}\n\n init(projectRoot: string): void {\n this.close();\n\n try {\n const logsDir = join(projectRoot, '.logs');\n fs.mkdirSync(logsDir, { recursive: true });\n\n this.logPath = join(logsDir, this.filename);\n\n if (fs.existsSync(this.logPath)) {\n const content = fs.readFileSync(this.logPath, 'utf-8');\n this.lineCount = content.split('\\n').filter((l) => l.trim()).length;\n } else {\n this.lineCount = 0;\n }\n\n this.fd = fs.openSync(this.logPath, 'a');\n log.info(`${this.filename} log initialized`, {\n path: this.logPath,\n existingEntries: this.lineCount,\n });\n } catch (err) {\n log.warn(`Failed to initialize ${this.filename} log`, {\n error: err instanceof Error ? err.message : String(err),\n });\n this.fd = null;\n this.logPath = null;\n }\n }\n\n append(record: Record<string, unknown>): void {\n if (this.fd === null) return;\n\n try {\n const line = JSON.stringify(record) + '\\n';\n fs.writeSync(this.fd, line);\n this.lineCount++;\n this.maybeRotate();\n } catch (err) {\n log.debug(`Failed to write ${this.filename} log entry`, {\n error: err instanceof Error ? err.message : String(err),\n });\n }\n }\n\n close(): void {\n if (this.fd !== null) {\n try {\n fs.closeSync(this.fd);\n } catch {\n // Best effort\n }\n this.fd = null;\n }\n this.logPath = null;\n this.lineCount = 0;\n this.rotating = false;\n }\n\n private maybeRotate(): void {\n if (this.fd === null || this.logPath === null || this.rotating) return;\n\n try {\n let needsRotation = this.lineCount > this.maxLines;\n\n if (!needsRotation) {\n const stat = fs.fstatSync(this.fd);\n needsRotation = stat.size > this.maxBytes;\n }\n\n if (!needsRotation) return;\n\n this.rotating = true;\n\n const content = fs.readFileSync(this.logPath, 'utf-8');\n const lines = content.split('\\n').filter((l) => l.trim());\n const kept = lines.slice(-this.keepLines);\n\n fs.closeSync(this.fd);\n fs.writeFileSync(this.logPath, kept.join('\\n') + '\\n', 'utf-8');\n this.fd = fs.openSync(this.logPath, 'a');\n this.lineCount = kept.length;\n\n log.debug(`${this.filename} log rotated`, { kept: this.lineCount });\n } catch (err) {\n log.debug(`${this.filename} log rotation failed`, {\n error: err instanceof Error ? err.message : String(err),\n });\n } finally {\n this.rotating = false;\n }\n }\n}\n","/**\n * NDJSON request log for method and scenario executions.\n * Thin wrapper around NdjsonLog.\n */\n\nimport { NdjsonLog } from './ndjson-log';\nimport type { DevSession, AppScenario } from './types';\nimport type { ExecuteMethodResult } from './executor';\n\n// ---------------------------------------------------------------------------\n// Types\n// ---------------------------------------------------------------------------\n\nexport interface MethodLogEntry {\n requestId: string;\n sessionId: string;\n methodExport: string;\n methodPath: string;\n input: unknown;\n roleOverride?: string[];\n authorizationToken: string;\n databases: DevSession['databases'];\n result: ExecuteMethodResult;\n duration: number;\n}\n\nexport interface ScenarioLogEntry {\n sessionId: string;\n scenario: AppScenario;\n databases: DevSession['databases'];\n result: ExecuteMethodResult | null;\n infrastructureError?: string;\n duration: number;\n}\n\n// ---------------------------------------------------------------------------\n// Log instance\n// ---------------------------------------------------------------------------\n\nconst ndjsonLog = new NdjsonLog('requests.ndjson');\n\nexport function initRequestLog(projectRoot: string): void {\n ndjsonLog.init(projectRoot);\n}\n\nexport function logMethodExecution(entry: MethodLogEntry): void {\n ndjsonLog.append({\n type: 'method',\n timestamp: new Date().toISOString(),\n requestId: entry.requestId,\n sessionId: entry.sessionId,\n method: entry.methodExport,\n path: entry.methodPath,\n input: entry.input,\n roleOverride: entry.roleOverride ?? null,\n authorizationToken: entry.authorizationToken,\n databases: entry.databases,\n success: entry.result.success,\n output: entry.result.output ?? null,\n error: entry.result.error ?? null,\n stdout: entry.result.stdout ?? [],\n duration: entry.duration,\n stats: entry.result.stats ?? null,\n });\n}\n\nexport function logScenarioExecution(entry: ScenarioLogEntry): void {\n ndjsonLog.append({\n type: 'scenario',\n timestamp: new Date().toISOString(),\n sessionId: entry.sessionId,\n scenario: {\n id: entry.scenario.id,\n name: entry.scenario.name ?? entry.scenario.export,\n export: entry.scenario.export,\n path: entry.scenario.path,\n },\n databases: entry.databases,\n success: entry.result?.success ?? false,\n output: entry.result?.output ?? null,\n error:\n entry.result?.error ??\n (entry.infrastructureError\n ? { message: entry.infrastructureError }\n : null),\n stdout: entry.result?.stdout ?? [],\n duration: entry.duration,\n stats: entry.result?.stats ?? null,\n });\n}\n\nexport function closeRequestLog(): void {\n ndjsonLog.close();\n}\n","// Event bridge between the DevRunner (backend) and the TUI/headless UI.\n//\n// The runner emits events as methods execute. The TUI hooks subscribe\n// to update the request log. Headless mode subscribes to relay events\n// as JSON to stdout. This decoupling means the runner doesn't need to\n// know whether it's running in a TUI or headless context.\n//\n// Singleton — one emitter shared across the process.\n\nimport { EventEmitter } from 'events';\n\nexport interface DevRequestStartEvent {\n id: string;\n type: 'execute';\n method?: string;\n timestamp: number;\n}\n\nexport interface DevRequestCompleteEvent {\n id: string;\n success: boolean;\n duration: number;\n error?: string;\n}\n\nexport interface DevScenarioStartEvent {\n id: string;\n name?: string;\n timestamp: number;\n}\n\nexport interface DevImpersonateEvent {\n roles: string[] | null;\n}\n\nexport interface DevScenarioCompleteEvent {\n id: string;\n success: boolean;\n duration: number;\n roles: string[];\n error?: string;\n}\n\nclass DevEventEmitter extends EventEmitter {\n emitStart(event: DevRequestStartEvent) {\n this.emit('dev:start', event);\n }\n\n emitComplete(event: DevRequestCompleteEvent) {\n this.emit('dev:complete', event);\n }\n\n emitSessionExpired() {\n this.emit('dev:session-expired');\n }\n\n emitAuthRefreshStart(url: string) {\n this.emit('dev:auth-refresh-start', url);\n }\n\n emitAuthRefreshSuccess() {\n this.emit('dev:auth-refresh-success');\n }\n\n emitAuthRefreshFailed() {\n this.emit('dev:auth-refresh-failed');\n }\n\n emitConnectionWarning(message: string) {\n this.emit('dev:connection-warning', message);\n }\n\n emitConnectionRestored() {\n this.emit('dev:connection-restored');\n }\n\n emitImpersonate(event: DevImpersonateEvent) {\n this.emit('dev:impersonate', event);\n }\n\n emitScenarioStart(event: DevScenarioStartEvent) {\n this.emit('dev:scenario-start', event);\n }\n\n emitScenarioComplete(event: DevScenarioCompleteEvent) {\n this.emit('dev:scenario-complete', event);\n }\n\n onStart(handler: (event: DevRequestStartEvent) => void) {\n this.on('dev:start', handler);\n return () => this.off('dev:start', handler);\n }\n\n onComplete(handler: (event: DevRequestCompleteEvent) => void) {\n this.on('dev:complete', handler);\n return () => this.off('dev:complete', handler);\n }\n\n onSessionExpired(handler: () => void) {\n this.on('dev:session-expired', handler);\n return () => this.off('dev:session-expired', handler);\n }\n\n onAuthRefreshStart(handler: (url: string) => void) {\n this.on('dev:auth-refresh-start', handler);\n return () => this.off('dev:auth-refresh-start', handler);\n }\n\n onAuthRefreshSuccess(handler: () => void) {\n this.on('dev:auth-refresh-success', handler);\n return () => this.off('dev:auth-refresh-success', handler);\n }\n\n onAuthRefreshFailed(handler: () => void) {\n this.on('dev:auth-refresh-failed', handler);\n return () => this.off('dev:auth-refresh-failed', handler);\n }\n\n onConnectionWarning(handler: (message: string) => void) {\n this.on('dev:connection-warning', handler);\n return () => this.off('dev:connection-warning', handler);\n }\n\n onConnectionRestored(handler: () => void) {\n this.on('dev:connection-restored', handler);\n return () => this.off('dev:connection-restored', handler);\n }\n\n onImpersonate(handler: (event: DevImpersonateEvent) => void) {\n this.on('dev:impersonate', handler);\n return () => this.off('dev:impersonate', handler);\n }\n\n onScenarioStart(handler: (event: DevScenarioStartEvent) => void) {\n this.on('dev:scenario-start', handler);\n return () => this.off('dev:scenario-start', handler);\n }\n\n onScenarioComplete(handler: (event: DevScenarioCompleteEvent) => void) {\n this.on('dev:scenario-complete', handler);\n return () => this.off('dev:scenario-complete', handler);\n }\n}\n\nexport const devRequestEvents = new DevEventEmitter();\n","// esbuild-based TypeScript transpiler. Always transpiles fresh (no mtime cache).\n//\n// Output goes to {nearest node_modules}/.cache/mindstudio-dev/ so that:\n// 1. Node's ESM resolver can find @mindstudio-ai/agent (walks up to node_modules)\n// 2. The repo stays clean (.cache/ is conventionally gitignored)\n//\n// @mindstudio-ai/agent is marked external so it resolves from the project's\n// installed version at runtime, not bundled into the output. This is critical\n// because the SDK reads globalThis.ai and env vars set by the executor.\n\nimport { unlink, mkdir, readdir } from 'node:fs/promises';\nimport { existsSync } from 'node:fs';\nimport { resolve, dirname, basename, join } from 'node:path';\nimport { build } from 'esbuild';\nimport { log } from './logger';\n\nexport class Transpiler {\n private projectRoot: string;\n private outputFiles: Set<string> = new Set();\n\n constructor(projectRoot: string) {\n this.projectRoot = projectRoot;\n // Clean up orphaned .__ms_dev__.mjs files from previous runs\n // (or from the old transpiler that wrote next to source files)\n this.cleanupOrphans();\n }\n\n /** Remove any .__ms_dev__.mjs files found in the project source tree (not in node_modules/.cache). */\n private async cleanupOrphans(): Promise<void> {\n try {\n await removeOrphanedDevFiles(this.projectRoot);\n } catch {\n // Best effort\n }\n }\n\n /**\n * Transpile a method file to ESM JavaScript.\n * Returns the absolute path to the output .mjs file.\n * Output is written inside the nearest node_modules/.cache/mindstudio-dev/\n * so ESM resolver can find packages and the repo stays clean.\n */\n async transpile(methodPath: string): Promise<string> {\n const start = Date.now();\n const absolutePath = resolve(this.projectRoot, methodPath);\n const name = basename(absolutePath).replace(/\\.[^.]+$/, '');\n\n log.debug('Transpiling method', { methodPath });\n\n // Find nearest node_modules by walking up from the source file\n const nodeModulesDir = findNearestNodeModules(dirname(absolutePath));\n if (!nodeModulesDir) {\n log.error('Cannot find node_modules for method', { methodPath, searchStart: dirname(absolutePath) });\n throw new Error(\n `No node_modules found near ${methodPath}. Run npm install first.`,\n );\n }\n log.debug('Found node_modules', { path: nodeModulesDir });\n\n const outDir = join(nodeModulesDir, '.cache', 'mindstudio-dev');\n await mkdir(outDir, { recursive: true });\n\n const outfile = join(outDir, `${name}.__ms_dev__.mjs`);\n\n await build({\n entryPoints: [absolutePath],\n bundle: true,\n format: 'esm',\n platform: 'node',\n target: 'node22',\n outfile,\n external: ['@mindstudio-ai/agent'],\n absWorkingDir: this.projectRoot,\n logLevel: 'silent',\n });\n\n this.outputFiles.add(outfile);\n log.info(`Method transpiled in ${Date.now() - start}ms`, { methodPath, outfile });\n return outfile;\n }\n\n /**\n * Clean up all transpiled output files.\n */\n async cleanup(): Promise<void> {\n log.debug('Cleaning up transpiled files', { fileCount: this.outputFiles.size });\n for (const file of this.outputFiles) {\n await unlink(file).catch(() => {});\n }\n this.outputFiles.clear();\n }\n}\n\n/**\n * Recursively remove .__ms_dev__.mjs files from the project tree,\n * skipping node_modules (where they belong if in .cache/).\n */\nasync function removeOrphanedDevFiles(dir: string): Promise<void> {\n const entries = await readdir(dir, { withFileTypes: true });\n for (const entry of entries) {\n if (entry.name === 'node_modules' || entry.name === '.git') continue;\n const fullPath = join(dir, entry.name);\n if (entry.isDirectory()) {\n await removeOrphanedDevFiles(fullPath);\n } else if (entry.name.endsWith('.__ms_dev__.mjs')) {\n log.debug('Removing orphaned transpiled file', { path: fullPath });\n await unlink(fullPath).catch(() => {});\n }\n }\n}\n\n/**\n * Walk up from a directory to find the nearest node_modules.\n */\nfunction findNearestNodeModules(startDir: string): string | null {\n let dir = startDir;\n while (true) {\n const candidate = join(dir, 'node_modules');\n if (existsSync(candidate)) {\n return candidate;\n }\n const parent = dirname(dir);\n if (parent === dir) break; // reached root\n dir = parent;\n }\n return null;\n}\n","// Execute transpiled methods in a persistent worker process.\n//\n// Instead of spawning a new Node.js process per request (which costs ~1-2s in\n// cold start), we keep a single long-lived worker that receives requests over\n// IPC. The Node runtime and SDK modules stay warm across invocations.\n//\n// Concurrent requests are supported — the worker handles multiple async\n// invocations in parallel, matched by request ID.\n//\n// The worker is lazily spawned on first use, respawned if it dies, and killed\n// on cleanup. Per-request state (env vars, global.ai) is set before each call.\n\nimport { fork, type ChildProcess } from 'node:child_process';\nimport { writeFile, unlink } from 'node:fs/promises';\nimport { join } from 'node:path';\nimport { tmpdir } from 'node:os';\nimport { randomBytes } from 'node:crypto';\nimport { log } from './logger';\nimport type { DevSession } from './types';\n\nconst EXECUTION_TIMEOUT_MS = 30 * 60 * 1000; // 30 minutes — matches prod\n\nexport interface ExecuteMethodOptions {\n transpiledPath: string;\n methodExport: string;\n input: unknown;\n auth: DevSession['auth'];\n databases: DevSession['databases'];\n authorizationToken: string;\n apiBaseUrl: string;\n projectRoot: string;\n streamId?: string;\n}\n\nexport interface ExecuteMethodResult {\n success: boolean;\n output?: unknown;\n error?: { message: string; stack?: string };\n stdout?: string[];\n stats?: { memoryUsedBytes: number; executionTimeMs: number };\n}\n\n// ---------------------------------------------------------------------------\n// Worker management\n// ---------------------------------------------------------------------------\n\n/** Pending request waiting for a response from the worker. */\ninterface PendingRequest {\n resolve: (result: ExecuteMethodResult) => void;\n timer: ReturnType<typeof setTimeout>;\n}\n\nlet worker: ChildProcess | null = null;\nlet workerScriptPath: string | null = null;\nlet workerProjectRoot: string | null = null;\nconst pending = new Map<string, PendingRequest>();\n\n/** Build the persistent worker script. */\nfunction buildWorkerScript(): string {\n return `\nfunction serializeError(err) {\n if (!err) return { message: 'Unknown error' };\n\n const serialized = {\n message: String(err.message ?? err),\n stack: err.stack,\n };\n\n if (err.code !== undefined) serialized.code = err.code;\n if (err.statusCode !== undefined) serialized.statusCode = err.statusCode;\n if (err.status !== undefined) serialized.status = err.status;\n if (err.response !== undefined) {\n try { serialized.response = typeof err.response === 'string' ? err.response : JSON.stringify(err.response); } catch {}\n }\n if (err.body !== undefined) {\n try { serialized.body = typeof err.body === 'string' ? err.body : JSON.stringify(err.body); } catch {}\n }\n if (err.cause !== undefined) {\n serialized.cause = serializeError(err.cause);\n }\n\n for (const key of Object.keys(err)) {\n if (!(key in serialized)) {\n try {\n const val = err[key];\n if (val !== undefined && typeof val !== 'function') {\n serialized[key] = typeof val === 'object' ? JSON.stringify(val) : val;\n }\n } catch {}\n }\n }\n\n return serialized;\n}\n\n// Save original console methods so we can restore after each request\nconst _origLog = console.log;\nconst _origWarn = console.warn;\nconst _origError = console.error;\n\nprocess.on('message', async (msg) => {\n const { id, transpiledPath, methodExport, input, auth, databases, authorizationToken, apiBaseUrl, streamId } = msg;\n\n // Update per-request env vars\n process.env.CALLBACK_TOKEN = authorizationToken;\n process.env.REMOTE_HOSTNAME = apiBaseUrl;\n if (streamId) process.env.STREAM_ID = streamId;\n else delete process.env.STREAM_ID;\n\n // Update global context\n global.ai = { auth, databases };\n\n // Capture console output for this request\n const stdout = [];\n console.log = (...args) => stdout.push(args.map(String).join(' '));\n console.warn = (...args) => stdout.push(args.map(String).join(' '));\n console.error = (...args) => stdout.push(args.map(String).join(' '));\n\n const startTime = Date.now();\n\n try {\n // Cache-bust so code changes are picked up\n const mod = await import(transpiledPath + '?t=' + Date.now());\n const fn = mod[methodExport];\n if (typeof fn !== 'function') {\n throw new Error(methodExport + ' is not a function (got ' + typeof fn + ')');\n }\n const returnValue = await fn(input);\n const stats = { memoryUsedBytes: process.memoryUsage().heapUsed, executionTimeMs: Date.now() - startTime };\n process.send({ id, success: true, output: returnValue, stdout, stats });\n } catch (err) {\n const stats = { memoryUsedBytes: process.memoryUsage().heapUsed, executionTimeMs: Date.now() - startTime };\n process.send({ id, success: false, error: serializeError(err), stdout, stats });\n } finally {\n // Restore console\n console.log = _origLog;\n console.warn = _origWarn;\n console.error = _origError;\n }\n});\n\n// Signal ready\nprocess.send({ type: 'ready' });\n`;\n}\n\n/** Ensure a live worker process exists; spawn one if needed. */\nasync function ensureWorker(projectRoot: string): Promise<ChildProcess> {\n // Respawn if worker died or project root changed\n if (worker?.connected && workerProjectRoot === projectRoot) {\n return worker;\n }\n\n // Clean up old worker\n if (worker) {\n worker.removeAllListeners();\n worker.kill();\n worker = null;\n }\n\n // Clean up old script\n if (workerScriptPath) {\n await unlink(workerScriptPath).catch(() => {});\n workerScriptPath = null;\n }\n\n // Write worker script\n const scriptPath = join(\n tmpdir(),\n `ms-dev-worker-${randomBytes(4).toString('hex')}.mjs`,\n );\n await writeFile(scriptPath, buildWorkerScript(), 'utf-8');\n workerScriptPath = scriptPath;\n workerProjectRoot = projectRoot;\n\n log.debug('Spawning method execution process', { cwd: projectRoot, scriptPath });\n\n const child = fork(scriptPath, [], {\n cwd: projectRoot,\n stdio: ['ignore', 'pipe', 'pipe', 'ipc'],\n env: { ...process.env },\n });\n\n // Wait for ready signal\n await new Promise<void>((resolve, reject) => {\n const onMessage = (msg: any) => {\n if (msg?.type === 'ready') {\n child.off('message', onMessage);\n resolve();\n }\n };\n child.on('message', onMessage);\n child.on('error', reject);\n child.on('exit', (code) => reject(new Error(`Worker exited during startup with code ${code}`)));\n });\n\n // Route responses to pending requests\n child.on('message', (msg: any) => {\n if (!msg?.id) return;\n const req = pending.get(msg.id);\n if (!req) return;\n pending.delete(msg.id);\n clearTimeout(req.timer);\n req.resolve(msg as ExecuteMethodResult);\n });\n\n // If worker dies unexpectedly, reject all pending requests\n child.on('exit', (code) => {\n log.warn('Method execution process exited unexpectedly', { code });\n for (const [id, req] of pending) {\n clearTimeout(req.timer);\n req.resolve({ success: false, error: { message: `Worker process exited with code ${code}` } });\n }\n pending.clear();\n worker = null;\n });\n\n // Capture stderr for debugging\n child.stderr?.on('data', (chunk: Buffer) => {\n const text = chunk.toString().trim();\n if (text) log.warn('Method process stderr', { text: text.slice(0, 500) });\n });\n\n worker = child;\n log.info('Method execution process ready', { pid: child.pid });\n return child;\n}\n\n// ---------------------------------------------------------------------------\n// Public API\n// ---------------------------------------------------------------------------\n\n/**\n * Execute a transpiled method in the persistent worker process.\n */\nexport async function executeMethod(\n opts: ExecuteMethodOptions,\n): Promise<ExecuteMethodResult> {\n const w = await ensureWorker(opts.projectRoot);\n\n const id = randomBytes(8).toString('hex');\n\n log.debug('Sending method to execution process', { id, methodExport: opts.methodExport });\n\n return new Promise<ExecuteMethodResult>((resolve) => {\n const timer = setTimeout(() => {\n pending.delete(id);\n log.warn('Method execution timed out', { id, methodExport: opts.methodExport });\n resolve({\n success: false,\n error: { message: 'Method execution timed out after 30s' },\n });\n }, EXECUTION_TIMEOUT_MS);\n\n pending.set(id, { resolve, timer });\n\n w.send({\n id,\n transpiledPath: opts.transpiledPath,\n methodExport: opts.methodExport,\n input: opts.input,\n auth: opts.auth,\n databases: opts.databases,\n authorizationToken: opts.authorizationToken,\n apiBaseUrl: opts.apiBaseUrl,\n streamId: opts.streamId,\n });\n });\n}\n\n/**\n * Kill the persistent worker. Called on session stop / cleanup.\n */\nexport async function cleanupWorker(): Promise<void> {\n if (worker) {\n worker.removeAllListeners();\n worker.kill();\n worker = null;\n }\n if (workerScriptPath) {\n await unlink(workerScriptPath).catch(() => {});\n workerScriptPath = null;\n }\n workerProjectRoot = null;\n for (const [, req] of pending) {\n clearTimeout(req.timer);\n }\n pending.clear();\n}\n","import { getApiKey, getApiBaseUrl, getUserId } from './config';\n\nexport interface LocalModelRequest {\n id: string;\n organizationId: string;\n modelId: string;\n requestType: 'llm_chat' | 'image_generation' | 'video_generation';\n payload: {\n messages?: Array<{ role: string; content: string }>;\n prompt?: string;\n temperature?: number;\n maxTokens?: number;\n config?: Record<string, unknown>;\n };\n createdAt: number;\n}\n\nfunction getHeaders(): Record<string, string> {\n const apiKey = getApiKey();\n if (!apiKey) {\n throw new Error('Not authenticated. Run: mindstudio-local auth');\n }\n\n const headers: Record<string, string> = {\n Authorization: `Bearer ${apiKey}`,\n 'Content-Type': 'application/json',\n };\n\n const userId = getUserId();\n if (userId) {\n headers['x-user-id'] = userId;\n }\n\n return headers;\n}\n\nexport async function pollForRequest(\n modelIds: string[],\n): Promise<LocalModelRequest | null> {\n const baseUrl = getApiBaseUrl();\n const modelIdsParam = modelIds.join(',');\n\n const response = await fetch(\n `${baseUrl}/v1/local-models/poll?modelIds=${encodeURIComponent(modelIdsParam)}`,\n {\n method: 'GET',\n headers: getHeaders(),\n },\n );\n\n if (response.status === 204) {\n return null;\n }\n\n if (!response.ok) {\n const error = await response.text();\n throw new Error(`Poll failed: ${response.status} ${error}`);\n }\n const data = (await response.json()) as { request: LocalModelRequest };\n return data.request;\n}\n\n/**\n * Submit a progress update for a running request.\n * @param type - 'chunk' for streaming text content, 'log' for raw log lines\n */\nexport async function submitProgress(\n requestId: string,\n content: string,\n type: 'chunk' | 'log' = 'chunk',\n): Promise<void> {\n const baseUrl = getApiBaseUrl();\n\n const response = await fetch(\n `${baseUrl}/v1/local-models/requests/${requestId}/progress`,\n {\n method: 'POST',\n headers: getHeaders(),\n body: JSON.stringify({ type, content }),\n },\n );\n\n if (!response.ok) {\n console.warn(`Progress update failed: ${response.status}`);\n }\n}\n\n/**\n * Result for text/chat completions\n */\nexport interface TextResult {\n content?: string;\n usage?: { promptTokens: number; completionTokens: number };\n}\n\n/**\n * Result for image generation\n */\nexport interface ImageResult {\n /** Base64-encoded image data */\n imageBase64: string;\n /** MIME type (e.g., \"image/png\") */\n mimeType: string;\n /** Seed used for generation */\n seed?: number;\n}\n\n/**\n * Result for video generation\n */\nexport interface VideoResult {\n /** Base64-encoded video data */\n videoBase64: string;\n /** MIME type (e.g., \"video/webp\", \"video/mp4\") */\n mimeType: string;\n /** Duration in seconds */\n duration?: number;\n /** Frames per second */\n fps?: number;\n /** Seed used for generation */\n seed?: number;\n}\n\n/**\n * Combined result type\n */\nexport type RequestResult = TextResult | ImageResult | VideoResult;\n\nexport async function submitResult(\n requestId: string,\n success: boolean,\n result?: RequestResult,\n error?: string,\n): Promise<void> {\n const baseUrl = getApiBaseUrl();\n\n const response = await fetch(\n `${baseUrl}/v1/local-models/requests/${requestId}/result`,\n {\n method: 'POST',\n headers: getHeaders(),\n body: JSON.stringify({ success, result, error }),\n },\n );\n\n if (!response.ok) {\n const errorText = await response.text();\n throw new Error(\n `Result submission failed: ${response.status} ${errorText}`,\n );\n }\n}\n\nexport async function verifyApiKey(): Promise<boolean> {\n const baseUrl = getApiBaseUrl();\n\n try {\n const response = await fetch(`${baseUrl}/v1/local-models/verify-api-key`, {\n method: 'GET',\n headers: getHeaders(),\n });\n\n return response.status === 204 || response.ok;\n } catch {\n return false;\n }\n}\n\nexport type ModelTypeMindStudio =\n | 'llm_chat'\n | 'image_generation'\n | 'video_generation';\n\nexport interface SyncModelEntry {\n name: string;\n provider: string;\n type: ModelTypeMindStudio;\n parameters?: unknown[];\n}\n\nexport async function syncModels(models: SyncModelEntry[]): Promise<void> {\n const baseUrl = getApiBaseUrl();\n\n const response = await fetch(`${baseUrl}/v1/local-models/models/sync`, {\n method: 'POST',\n headers: getHeaders(),\n body: JSON.stringify({ models }),\n });\n\n if (!response.ok) {\n const errorText = await response.text();\n throw new Error(`Sync failed: ${response.status} ${errorText}`);\n }\n}\n\nexport interface SyncedModel {\n id: string;\n name: string;\n}\n\nexport async function getSyncedModels(): Promise<SyncedModel[]> {\n const baseUrl = getApiBaseUrl();\n\n const response = await fetch(`${baseUrl}/v1/local-models/models`, {\n method: 'GET',\n headers: getHeaders(),\n });\n\n if (!response.ok) {\n const errorText = await response.text();\n throw new Error(\n `Failed to fetch synced models: ${response.status} ${errorText}`,\n );\n }\n\n const data = (await response.json()) as { models: SyncedModel[] };\n return data.models;\n}\n\nexport async function requestDeviceAuth(): Promise<{\n url: string;\n token: string;\n}> {\n const baseUrl = getApiBaseUrl();\n\n const response = await fetch(`${baseUrl}/developer/v2/request-auth-url`, {\n method: 'GET',\n headers: { 'Content-Type': 'application/json' },\n });\n\n if (!response.ok) {\n const error = await response.text();\n throw new Error(`Device auth request failed: ${response.status} ${error}`);\n }\n\n const data = (await response.json()) as {\n url: string;\n token: string;\n };\n\n return data;\n}\n\nexport async function pollDeviceAuth(token: string): Promise<{\n status: 'pending' | 'completed' | 'expired';\n apiKey: string | null;\n userId: string | null;\n}> {\n const baseUrl = getApiBaseUrl();\n\n const response = await fetch(`${baseUrl}/developer/v2/poll-auth-url`, {\n method: 'POST',\n headers: { 'Content-Type': 'application/json' },\n body: JSON.stringify({ token }),\n });\n\n if (!response.ok) {\n const error = await response.text();\n throw new Error(`Device auth poll failed: ${response.status} ${error}`);\n }\n\n const data = (await response.json()) as {\n status: 'pending' | 'completed' | 'expired';\n apiKey: string | null;\n userId: string | null;\n };\n\n return data;\n}\n\nexport interface SpaEditorSessionInfo {\n sessionId: string;\n status: string;\n previewDomain: string | null;\n hotUpdateDomain: string | null;\n}\n\nexport interface CustomInterfaceStepInfo {\n stepId: string;\n stepType: string;\n displayName: string;\n workflowId: string;\n workflowName: string;\n spaEditorSession: SpaEditorSessionInfo | null;\n}\n\nexport interface ScriptStepInfo {\n stepId: string;\n displayName: string;\n workflowId: string;\n workflowName: string;\n files: Record<string, string>;\n entryFile: string;\n}\n\nexport interface EditorSession {\n appId: string;\n appName: string;\n customInterfaceSteps: CustomInterfaceStepInfo[];\n scriptSteps: ScriptStepInfo[];\n}\n\nexport async function getEditorSessions(): Promise<EditorSession[]> {\n const baseUrl = getApiBaseUrl();\n\n const response = await fetch(`${baseUrl}/v1/local-editor/sessions`, {\n method: 'GET',\n headers: getHeaders(),\n });\n\n if (!response.ok) {\n const errorText = await response.text();\n throw new Error(\n `Failed to fetch editor sessions: ${response.status} ${errorText}`,\n );\n }\n\n const data = (await response.json()) as { editors: EditorSession[] };\n return data.editors;\n}\n\nexport async function disconnectHeartbeat(): Promise<void> {\n const baseUrl = getApiBaseUrl();\n\n const response = await fetch(`${baseUrl}/v1/local-models/disconnect`, {\n method: 'POST',\n headers: getHeaders(),\n });\n\n if (!response.ok) {\n const error = await response.text();\n throw new Error(`Heartbeat disconnect failed: ${response.status} ${error}`);\n }\n}\n","// DevRunner — the core of dev mode.\n//\n// Lifecycle: start() → pollLoop() → handleRequest() → stop()\n//\n// The runner polls the platform for method execution requests, transpiles\n// TypeScript on the fly, executes methods in isolated child processes, and\n// posts results back. It does NOT handle the frontend (that's the proxy).\n//\n// The poll loop runs continuously. Requests are handled in the background\n// so multiple methods can execute in parallel without blocking the poll.\n// Connection issues trigger exponential backoff; 404 = session expired.\n\nimport {\n startDevSession,\n stopDevSession,\n pollDevRequest,\n submitDevResult,\n resetDevDatabase,\n impersonate,\n refreshContext,\n fetchCallbackToken,\n ApiError,\n DevPollError,\n} from './api';\nimport { devRequestEvents } from './events';\nimport { Transpiler } from './transpiler';\nimport { executeMethod, cleanupWorker } from './executor';\nimport { getApiBaseUrl } from '../config';\nimport { requestDeviceAuth, pollDeviceAuth } from '../api';\nimport { setApiKey, setUserId } from '../config';\nimport { randomBytes } from 'node:crypto';\nimport { log } from './logger';\nimport { logMethodExecution, logScenarioExecution } from './request-log';\nimport { formatErrorForDisplay } from './format-error';\nimport type { DevProxy } from './proxy';\nimport type { DevSession, DevRequest, DevResult, AppScenario } from './types';\n\nexport class DevRunner {\n private isRunning = false;\n private session: DevSession | null = null;\n private transpiler: Transpiler | null = null;\n private backoffMs = 1000;\n private hadConnectionWarning = false;\n private proxyUrl: string | undefined;\n private proxy: DevProxy | null = null;\n\n constructor(\n private readonly appId: string,\n private readonly projectRoot: string,\n private readonly startOpts: {\n branch?: string;\n proxyUrl?: string;\n methods?: Array<{ id: string; export: string; path: string }>;\n } = {},\n ) {}\n\n // proxyUrl is sent on every poll request so the platform dashboard can\n // show the developer's preview URL. Also included in the start request\n // so the dashboard sees it immediately without waiting for the first poll.\n setProxyUrl(url: string): void {\n this.proxyUrl = url;\n this.startOpts.proxyUrl = url;\n }\n\n setProxy(proxy: DevProxy): void {\n this.proxy = proxy;\n }\n\n async start(): Promise<DevSession> {\n if (this.isRunning) {\n throw new Error('DevRunner is already running');\n }\n\n log.info('Dev session starting', { appId: this.appId, branch: this.startOpts.branch });\n const session = await startDevSession(this.appId, this.startOpts);\n this.session = session;\n this.transpiler = new Transpiler(this.projectRoot);\n this.isRunning = true;\n this.backoffMs = 1000;\n\n log.info('Dev session started', { sessionId: session.sessionId, branch: session.branch });\n\n // Start poll loop in background\n this.pollLoop();\n\n return session;\n }\n\n async stop(): Promise<void> {\n log.info('Dev session stopping');\n this.isRunning = false;\n\n if (this.session) {\n try {\n await stopDevSession(this.appId, this.session.sessionId);\n } catch (err) {\n log.warn('Failed to stop dev session cleanly', { error: err instanceof Error ? err.message : String(err) });\n }\n this.session = null;\n }\n\n await cleanupWorker();\n\n if (this.transpiler) {\n await this.transpiler.cleanup();\n this.transpiler = null;\n }\n }\n\n getSession(): DevSession | null {\n return this.session;\n }\n\n // Set role override for subsequent method executions.\n async setImpersonation(roles: string[]): Promise<void> {\n if (!this.session) return;\n log.info('Setting role override', { roles });\n const result = await impersonate(this.appId, this.session.sessionId, roles);\n await this.refreshClientContext();\n devRequestEvents.emitImpersonate({ roles: result.roles });\n }\n\n // Clear role override — revert to session's default roles.\n async clearImpersonation(): Promise<void> {\n if (!this.session) return;\n log.info('Clearing role override');\n const result = await impersonate(this.appId, this.session.sessionId, null);\n await this.refreshClientContext();\n devRequestEvents.emitImpersonate({ roles: result.roles });\n }\n\n // Fetch fresh clientContext from platform and update the proxy.\n // Called after impersonation changes so the browser gets a new ms_iface token.\n private async refreshClientContext(): Promise<void> {\n if (!this.session || !this.proxy) return;\n try {\n const context = await refreshContext(this.appId, this.session.sessionId);\n this.session.clientContext = context;\n this.proxy.updateClientContext(context);\n } catch (err) {\n log.warn('Failed to refresh session context after role change', { error: err instanceof Error ? err.message : String(err) });\n }\n }\n\n // Run a method directly (not via poll loop). Used by headless stdin commands\n // and programmatic callers to test methods without a browser.\n async runMethod(opts: {\n methodExport: string;\n methodPath: string;\n input: unknown;\n }): Promise<{ success: boolean; output?: unknown; error?: Record<string, unknown> | null; stdout?: string[]; duration: number }> {\n if (!this.session || !this.transpiler) {\n return { success: false, error: { message: 'Session not started' }, duration: 0 };\n }\n\n const requestId = randomBytes(8).toString('hex');\n const startTime = Date.now();\n\n devRequestEvents.emitStart({\n id: requestId,\n type: 'execute',\n method: opts.methodExport,\n timestamp: startTime,\n });\n\n log.info('Method received (direct)', { requestId, method: opts.methodExport });\n\n try {\n const authorizationToken = await fetchCallbackToken(this.appId, this.session.sessionId);\n const transpiledPath = await this.transpiler.transpile(opts.methodPath);\n\n const result = await executeMethod({\n transpiledPath,\n methodExport: opts.methodExport,\n input: opts.input,\n auth: this.session.auth,\n databases: this.session.databases,\n authorizationToken,\n apiBaseUrl: getApiBaseUrl(),\n projectRoot: this.projectRoot,\n });\n\n const duration = Date.now() - startTime;\n\n if (result.success) {\n log.info('Method complete', { requestId, method: opts.methodExport, duration });\n } else {\n log.warn('Method failed', {\n requestId,\n method: opts.methodExport,\n duration,\n error: result.error ? formatErrorForDisplay(result.error) : undefined,\n });\n }\n\n logMethodExecution({\n requestId,\n sessionId: this.session.sessionId,\n methodExport: opts.methodExport,\n methodPath: opts.methodPath,\n input: opts.input,\n authorizationToken,\n databases: this.session.databases,\n result,\n duration,\n });\n\n devRequestEvents.emitComplete({\n id: requestId,\n success: result.success,\n duration,\n error: result.error ? formatErrorForDisplay(result.error) : undefined,\n });\n\n return {\n success: result.success,\n output: result.output,\n error: result.error ?? null,\n stdout: result.stdout,\n duration,\n };\n } catch (err) {\n const message = err instanceof Error ? err.message : 'Unknown error';\n const duration = Date.now() - startTime;\n log.error('Method error', { requestId, method: opts.methodExport, duration, error: message });\n\n logMethodExecution({\n requestId,\n sessionId: this.session.sessionId,\n methodExport: opts.methodExport,\n methodPath: opts.methodPath,\n input: opts.input,\n authorizationToken: '',\n databases: this.session.databases,\n result: { success: false, error: { message } },\n duration,\n });\n\n devRequestEvents.emitComplete({\n id: requestId,\n success: false,\n duration,\n error: message,\n });\n\n return { success: false, error: { message }, duration };\n }\n }\n\n // Run a scenario: truncate tables → execute seed → impersonate roles.\n // Called directly (not via poll loop) by the TUI or headless stdin.\n async runScenario(scenario: AppScenario): Promise<{\n success: boolean;\n databases: DevSession['databases'];\n error?: string;\n }> {\n if (!this.session || !this.transpiler) {\n return { success: false, databases: [], error: 'Session not started' };\n }\n\n const startTime = Date.now();\n const scenarioName = scenario.name ?? scenario.export;\n devRequestEvents.emitScenarioStart({\n id: scenario.id,\n name: scenarioName,\n timestamp: startTime,\n });\n\n log.info('Scenario starting', { id: scenario.id, name: scenarioName });\n\n try {\n // 1. Truncate all tables (clean slate)\n log.info('Resetting database for scenario');\n const databases = await resetDevDatabase(this.appId, this.session.sessionId, 'truncate');\n this.session.databases = databases;\n\n // 2. Transpile and execute the seed function\n log.info('Transpiling scenario', { path: scenario.path });\n const transpiledPath = await this.transpiler.transpile(scenario.path);\n\n // Fetch a callback token for the seed execution — same scoping as\n // poll-based tokens, but not tied to a poll request.\n const authorizationToken = await fetchCallbackToken(this.appId, this.session.sessionId);\n\n log.info('Running scenario seed function', { export: scenario.export });\n const result = await executeMethod({\n transpiledPath,\n methodExport: scenario.export,\n input: {},\n auth: this.session.auth,\n databases: this.session.databases,\n authorizationToken,\n apiBaseUrl: getApiBaseUrl(),\n projectRoot: this.projectRoot,\n });\n\n if (!result.success) {\n const error = result.error?.message ?? 'Scenario seed failed';\n log.error('Scenario seed function failed', { id: scenario.id, error });\n logScenarioExecution({\n sessionId: this.session.sessionId,\n scenario,\n databases: this.session.databases,\n result,\n duration: Date.now() - startTime,\n });\n devRequestEvents.emitScenarioComplete({\n id: scenario.id,\n success: false,\n duration: Date.now() - startTime,\n roles: scenario.roles,\n error,\n });\n return { success: false, databases, error };\n }\n\n // 3. Impersonate the scenario's roles\n if (scenario.roles.length > 0) {\n log.info('Setting role override for scenario', { roles: scenario.roles });\n await impersonate(this.appId, this.session.sessionId, scenario.roles);\n await this.refreshClientContext();\n }\n\n const duration = Date.now() - startTime;\n log.info('Scenario complete', { id: scenario.id, duration, roles: scenario.roles });\n logScenarioExecution({\n sessionId: this.session.sessionId,\n scenario,\n databases: this.session.databases,\n result,\n duration,\n });\n devRequestEvents.emitScenarioComplete({\n id: scenario.id,\n success: true,\n duration,\n roles: scenario.roles,\n });\n\n return { success: true, databases };\n } catch (err) {\n const error = err instanceof Error ? err.message : 'Unknown error';\n log.error('Scenario failed', { id: scenario.id, error });\n logScenarioExecution({\n sessionId: this.session.sessionId,\n scenario,\n databases: this.session.databases,\n result: null,\n infrastructureError: error,\n duration: Date.now() - startTime,\n });\n devRequestEvents.emitScenarioComplete({\n id: scenario.id,\n success: false,\n duration: Date.now() - startTime,\n roles: scenario.roles,\n error,\n });\n return { success: false, databases: this.session.databases, error };\n }\n }\n\n private async pollLoop(): Promise<void> {\n while (this.isRunning) {\n try {\n const request = await pollDevRequest(\n this.appId,\n this.session!.sessionId,\n this.proxyUrl,\n );\n\n if (this.hadConnectionWarning) {\n this.hadConnectionWarning = false;\n log.info('Connection to platform restored');\n devRequestEvents.emitConnectionRestored();\n }\n\n if (request) {\n // Process in background — don't block the poll loop\n this.handleRequest(request);\n }\n\n this.backoffMs = 1000;\n } catch (error) {\n // Session expired\n if (error instanceof DevPollError && error.statusCode === 404) {\n log.error('Dev session expired', { statusCode: 404 });\n devRequestEvents.emitSessionExpired();\n this.isRunning = false;\n return;\n }\n\n // Auth token expired — attempt automatic refresh\n if (\n (error instanceof DevPollError || error instanceof ApiError) &&\n error.statusCode === 401\n ) {\n log.warn('Session token expired, re-authenticating');\n const refreshed = await this.refreshAuth();\n if (refreshed) {\n // Token refreshed — reset backoff and continue polling\n this.backoffMs = 1000;\n continue;\n }\n // Refresh failed — treat as session expired\n log.error('Re-authentication failed');\n devRequestEvents.emitSessionExpired();\n this.isRunning = false;\n return;\n }\n\n // Connection issue — backoff and retry\n if (!this.hadConnectionWarning) {\n this.hadConnectionWarning = true;\n log.warn('Lost connection to platform, retrying');\n devRequestEvents.emitConnectionWarning(\n 'Lost connection to platform, retrying...',\n );\n }\n\n log.debug('Backing off', { ms: this.backoffMs });\n await this.sleep(this.backoffMs);\n this.backoffMs = Math.min(this.backoffMs * 2, 30_000);\n }\n }\n }\n\n private async handleRequest(request: DevRequest): Promise<void> {\n const startTime = Date.now();\n\n devRequestEvents.emitStart({\n id: request.requestId,\n type: request.type,\n method: request.methodExport,\n timestamp: startTime,\n });\n\n log.info('Method received', { requestId: request.requestId, method: request.methodExport });\n\n try {\n // Transpile\n log.debug('Transpiling method', { path: request.methodPath });\n const transpiledPath = await this.transpiler!.transpile(request.methodPath);\n\n // Role override lets the platform test methods as different users/roles\n // without restarting the session. If present, we build a custom auth\n // context with the overridden roles; otherwise use the session default.\n const auth = request.roleOverride\n ? {\n userId: this.session!.auth.userId,\n roleAssignments: request.roleOverride.map((roleName) => ({\n userId: this.session!.auth.userId,\n roleName,\n })),\n }\n : this.session!.auth;\n\n // Execute in isolated child process\n const result = await executeMethod({\n transpiledPath,\n methodExport: request.methodExport,\n input: request.input,\n auth,\n databases: this.session!.databases,\n authorizationToken: request.authorizationToken,\n apiBaseUrl: getApiBaseUrl(),\n projectRoot: this.projectRoot,\n streamId: request.streamId,\n });\n\n const devResult: DevResult = {\n type: 'execute',\n success: result.success,\n output: result.output,\n error: result.error,\n stdout: result.stdout,\n stats: result.stats,\n };\n\n await submitDevResult(\n this.appId,\n this.session!.sessionId,\n request.requestId,\n devResult,\n );\n\n const duration = Date.now() - startTime;\n if (result.success) {\n log.info('Method complete', { requestId: request.requestId, method: request.methodExport, duration });\n } else {\n log.warn('Method failed', {\n requestId: request.requestId,\n method: request.methodExport,\n duration,\n error: result.error ? formatErrorForDisplay(result.error) : undefined,\n });\n }\n\n logMethodExecution({\n requestId: request.requestId,\n sessionId: this.session!.sessionId,\n methodExport: request.methodExport,\n methodPath: request.methodPath,\n input: request.input,\n roleOverride: request.roleOverride,\n authorizationToken: request.authorizationToken,\n databases: this.session!.databases,\n result,\n duration,\n });\n\n devRequestEvents.emitComplete({\n id: request.requestId,\n success: result.success,\n duration,\n error: result.error ? formatErrorForDisplay(result.error) : undefined,\n });\n } catch (error) {\n const message =\n error instanceof Error ? error.message : 'Unknown error';\n const duration = Date.now() - startTime;\n log.error('Method error', { requestId: request.requestId, method: request.methodExport, duration, error: message });\n\n try {\n await submitDevResult(\n this.appId,\n this.session!.sessionId,\n request.requestId,\n {\n type: 'execute',\n success: false,\n error: { message },\n },\n );\n } catch (submitErr) {\n log.error('Failed to report method error to platform', { error: submitErr instanceof Error ? submitErr.message : String(submitErr) });\n }\n\n logMethodExecution({\n requestId: request.requestId,\n sessionId: this.session!.sessionId,\n methodExport: request.methodExport,\n methodPath: request.methodPath,\n input: request.input,\n roleOverride: request.roleOverride,\n authorizationToken: request.authorizationToken,\n databases: this.session!.databases,\n result: { success: false, error: { message } },\n duration: Date.now() - startTime,\n });\n\n devRequestEvents.emitComplete({\n id: request.requestId,\n success: false,\n duration: Date.now() - startTime,\n error: message,\n });\n }\n }\n\n /**\n * Attempt to refresh expired auth credentials via the device auth flow.\n * Opens the browser for the user to re-authorize, polls for the new token.\n * Returns true if refresh succeeded.\n */\n private async refreshAuth(): Promise<boolean> {\n const POLL_INTERVAL = 2000;\n const MAX_ATTEMPTS = 30;\n\n try {\n log.info('Session token expired, requesting re-authentication');\n const { url, token } = await requestDeviceAuth();\n\n devRequestEvents.emitAuthRefreshStart(url);\n\n // Try to open the browser — not fatal if it fails (headless, SSH, etc.)\n try {\n const open = (await import('open')).default;\n await open(url);\n } catch {\n log.warn('Could not open browser — visit URL to re-authenticate');\n }\n\n for (let i = 0; i < MAX_ATTEMPTS; i++) {\n await this.sleep(POLL_INTERVAL);\n if (!this.isRunning) return false;\n\n const result = await pollDeviceAuth(token);\n\n if (result.status === 'completed' && result.apiKey) {\n setApiKey(result.apiKey);\n if (result.userId) {\n setUserId(result.userId);\n }\n log.info('Re-authentication successful');\n devRequestEvents.emitAuthRefreshSuccess();\n return true;\n }\n\n if (result.status === 'expired') {\n break;\n }\n }\n\n log.error('Re-authentication timed out or was denied');\n devRequestEvents.emitAuthRefreshFailed();\n return false;\n } catch (err) {\n log.error('Re-authentication failed', { error: err instanceof Error ? err.message : String(err) });\n devRequestEvents.emitAuthRefreshFailed();\n return false;\n }\n }\n\n private sleep(ms: number): Promise<void> {\n return new Promise((resolve) => setTimeout(resolve, ms));\n }\n}\n\n","/**\n * Format an error object from the executor into a readable string.\n * Includes extra fields like code, statusCode, cause, etc. when present.\n */\nexport function formatErrorForDisplay(\n error: Record<string, unknown>,\n): string {\n const parts: string[] = [];\n\n // Main message\n if (error.message) {\n parts.push(String(error.message));\n }\n\n // Status/code info\n const code = error.code ?? error.statusCode ?? error.status;\n if (code !== undefined) {\n parts.push(`(code: ${code})`);\n }\n\n // Response body from HTTP errors\n if (error.body) {\n parts.push(`Response: ${String(error.body).slice(0, 200)}`);\n } else if (error.response) {\n parts.push(`Response: ${String(error.response).slice(0, 200)}`);\n }\n\n // Cause chain\n if (error.cause && typeof error.cause === 'object') {\n const cause = error.cause as Record<string, unknown>;\n if (cause.message) {\n parts.push(`Caused by: ${cause.message}`);\n }\n }\n\n return parts.join('\\n');\n}\n","/**\n * NDJSON log for browser-side events (console, errors, network, clicks).\n * Thin wrapper around NdjsonLog.\n */\n\nimport { NdjsonLog } from './ndjson-log';\n\nconst ndjsonLog = new NdjsonLog('browser.ndjson');\n\nexport function initBrowserLog(projectRoot: string): void {\n ndjsonLog.init(projectRoot);\n}\n\nexport function appendBrowserLogEntries(\n entries: Array<Record<string, unknown>>,\n): void {\n for (const entry of entries) {\n ndjsonLog.append({\n timestamp: new Date().toISOString(),\n ...entry,\n });\n }\n}\n\nexport function closeBrowserLog(): void {\n ndjsonLog.close();\n}\n","// Local dev proxy — sits between the browser and the upstream dev server.\n//\n// Why: the MindStudio frontend SDK needs window.__MINDSTUDIO__ (session\n// token, API URL, method mappings) to function. In production, the platform\n// injects this into HTML served from S3. In dev mode, the proxy does it\n// locally so the browser gets the same context without a platform round-trip.\n//\n// How it works:\n// - HTML responses: buffered, __MINDSTUDIO__ injected before </head>, served\n// - Everything else (JS, CSS, images, fonts): piped through unmodified\n// - WebSocket upgrades: forwarded transparently (enables HMR for any framework)\n// - CORS/PNA headers: added so the proxy works inside iframes from app.mindstudio.ai\n// - Caching disabled on all responses (this is local dev, always fresh)\n// - /__mindstudio_dev__/*: intercepted locally for browser agent communication\n//\n// The proxy is framework-agnostic — it doesn't know or care what dev server\n// is upstream. Detection is by content-type header, not URL patterns.\n\nimport http from 'node:http';\nimport { randomBytes } from 'node:crypto';\nimport type { Socket } from 'node:net';\nimport { log } from './logger';\nimport { appendBrowserLogEntries } from './browser-log';\n\ninterface PendingCommand {\n id: string;\n steps: Array<Record<string, unknown>>;\n}\n\ninterface PendingResult {\n resolve: (result: Record<string, unknown>) => void;\n timeout: ReturnType<typeof setTimeout>;\n}\n\nexport class DevProxy {\n private server: http.Server | null = null;\n private proxyPort: number | null = null;\n private commandQueue: PendingCommand[] = [];\n private pendingResults = new Map<string, PendingResult>();\n private lastBrowserPoll = 0;\n /** Long-poll waiters — browser agents waiting for the next command. */\n private commandWaiters: Array<{\n req: http.IncomingMessage;\n res: http.ServerResponse;\n timer: ReturnType<typeof setTimeout>;\n }> = [];\n\n /** Upstream dev server health tracking. */\n private upstreamUp = true;\n private healthCheckTimer: ReturnType<typeof setTimeout> | null = null;\n\n private static readonly HEALTH_CHECK_INTERVAL = 3_000;\n private static readonly HEALTH_CHECK_INTERVAL_DOWN = 1_000;\n private static readonly HEALTH_CHECK_TIMEOUT = 2_000;\n\n constructor(\n private readonly upstreamPort: number,\n private clientContext: Record<string, unknown>,\n private readonly bindAddress: string = '127.0.0.1',\n // Dev override: 'https://seankoji-msba.ngrok.io/index.js'\n private readonly browserAgentUrl?: string,\n ) {}\n\n updateClientContext(context: Record<string, unknown>): void {\n this.clientContext = context;\n log.info('Dev proxy context updated after role change');\n }\n\n /**\n * Whether a browser agent is actively connected.\n * True if there's a long-poll waiter or we've seen activity recently.\n */\n isBrowserConnected(): boolean {\n return this.commandWaiters.length > 0 || Date.now() - this.lastBrowserPoll < 500;\n }\n\n /**\n * Dispatch a browser command and wait for the result.\n * The command is queued for the browser agent to pick up via polling.\n * Returns a promise that resolves when the browser posts the result back.\n */\n dispatchBrowserCommand(\n steps: Array<Record<string, unknown>>,\n timeoutMs = 30_000,\n ): Promise<Record<string, unknown>> {\n if (!this.isBrowserConnected()) {\n return Promise.reject(\n new Error('No browser connected, please refresh the MindStudio preview'),\n );\n }\n\n const id = randomBytes(4).toString('hex');\n\n log.info('Browser command queued', { id, stepCount: steps.length, commands: steps.map((s) => s.command) });\n\n return new Promise((resolve, reject) => {\n const timeout = setTimeout(() => {\n this.pendingResults.delete(id);\n log.warn('Browser command timed out', { id, pendingCount: this.pendingResults.size, queueLength: this.commandQueue.length });\n reject(new Error('Browser command timed out'));\n }, timeoutMs);\n\n this.pendingResults.set(id, { resolve, timeout });\n this.commandQueue.push({ id, steps });\n this.flushCommandToWaiter();\n });\n }\n\n async start(preferredPort?: number): Promise<number> {\n const server = http.createServer((req, res) => {\n this.handleRequest(req, res);\n });\n\n // WebSocket upgrade forwarding\n server.on('upgrade', (req, socket, head) => {\n this.handleUpgrade(req, socket as Socket, head);\n });\n\n // Try the preferred port first, fall back to OS-assigned\n const portsToTry = preferredPort\n ? [preferredPort, 0]\n : [0];\n\n for (const port of portsToTry) {\n try {\n const assignedPort = await this.listenOnPort(server, port);\n this.server = server;\n this.proxyPort = assignedPort;\n this.startHealthCheck();\n log.info('Dev proxy started', { port: assignedPort, bind: this.bindAddress });\n return assignedPort;\n } catch {\n log.warn('Proxy port in use, trying next', { port });\n // Port in use — try next\n }\n }\n\n throw new Error('Failed to start proxy server');\n }\n\n private listenOnPort(server: http.Server, port: number): Promise<number> {\n return new Promise((resolve, reject) => {\n const onError = (err: Error) => {\n server.removeListener('error', onError);\n reject(err);\n };\n server.on('error', onError);\n\n server.listen(port, this.bindAddress, () => {\n server.removeListener('error', onError);\n const addr = server.address();\n if (!addr || typeof addr === 'string') {\n reject(new Error('Failed to get proxy server address'));\n return;\n }\n resolve(addr.port);\n });\n });\n }\n\n stop(): void {\n this.stopHealthCheck();\n\n if (this.server) {\n log.info('Dev proxy stopping');\n this.server.close();\n this.server = null;\n this.proxyPort = null;\n }\n\n // Reject pending commands so callers don't hang\n for (const [id, pending] of this.pendingResults) {\n clearTimeout(pending.timeout);\n pending.resolve({ id, steps: [], error: 'Proxy stopped' });\n }\n this.pendingResults.clear();\n this.commandQueue.length = 0;\n\n // Close any long-poll waiters\n for (const waiter of this.commandWaiters) {\n clearTimeout(waiter.timer);\n if (!waiter.res.writableEnded) {\n waiter.res.writeHead(204).end();\n }\n }\n this.commandWaiters.length = 0;\n }\n\n getPort(): number | null {\n return this.proxyPort;\n }\n\n // ---------------------------------------------------------------------------\n // Upstream health check\n // ---------------------------------------------------------------------------\n\n /**\n * Explicitly mark the upstream dev server as down.\n * Used by the stdin `dev-server-restarting` action when the parent process\n * knows a restart is happening (may be too fast for the health check to catch).\n * The health check will detect recovery and reload the browser.\n */\n markUpstreamDown(): void {\n if (!this.upstreamUp) return;\n this.upstreamUp = false;\n log.info('Upstream dev server marked as down (explicit signal)');\n this.scheduleHealthCheck(DevProxy.HEALTH_CHECK_INTERVAL_DOWN);\n }\n\n private startHealthCheck(): void {\n this.scheduleHealthCheck(DevProxy.HEALTH_CHECK_INTERVAL);\n }\n\n private stopHealthCheck(): void {\n if (this.healthCheckTimer) {\n clearTimeout(this.healthCheckTimer);\n this.healthCheckTimer = null;\n }\n }\n\n private scheduleHealthCheck(delayMs: number): void {\n this.stopHealthCheck();\n this.healthCheckTimer = setTimeout(() => this.checkUpstream(), delayMs);\n }\n\n private async checkUpstream(): Promise<void> {\n const wasUp = this.upstreamUp;\n\n try {\n const res = await fetch(`http://127.0.0.1:${this.upstreamPort}/`, {\n signal: AbortSignal.timeout(DevProxy.HEALTH_CHECK_TIMEOUT),\n });\n // Any response (even 404/500) means the server is alive\n this.upstreamUp = true;\n } catch {\n this.upstreamUp = false;\n }\n\n // Handle state transitions\n if (wasUp && !this.upstreamUp) {\n log.warn('Upstream dev server is down');\n } else if (!wasUp && this.upstreamUp) {\n log.info('Upstream dev server is back up, reloading browser');\n this.dispatchBrowserCommand([{ command: 'reload' }]).catch(() => {});\n }\n\n // Poll faster when down to catch recovery quickly\n const interval = this.upstreamUp\n ? DevProxy.HEALTH_CHECK_INTERVAL\n : DevProxy.HEALTH_CHECK_INTERVAL_DOWN;\n this.scheduleHealthCheck(interval);\n }\n\n // ---------------------------------------------------------------------------\n // CORS helper\n // ---------------------------------------------------------------------------\n\n private corsHeaders(req: http.IncomingMessage): Record<string, string> {\n const origin = req.headers.origin;\n if (!origin) return {};\n return {\n 'access-control-allow-origin': origin,\n 'access-control-allow-private-network': 'true',\n };\n }\n\n // ---------------------------------------------------------------------------\n // Request routing\n // ---------------------------------------------------------------------------\n\n private handleRequest(\n clientReq: http.IncomingMessage,\n clientRes: http.ServerResponse,\n ): void {\n // Browser agent endpoints — intercepted locally, never forwarded upstream\n if (clientReq.url?.startsWith('/__mindstudio_dev__/')) {\n if (clientReq.url === '/__mindstudio_dev__/logs' && clientReq.method === 'POST') {\n this.handleBrowserLogs(clientReq, clientRes);\n return;\n }\n if (clientReq.url === '/__mindstudio_dev__/commands' && clientReq.method === 'GET') {\n this.handleGetCommand(clientReq, clientRes);\n return;\n }\n if (clientReq.url === '/__mindstudio_dev__/results' && clientReq.method === 'POST') {\n this.handlePostResult(clientReq, clientRes);\n return;\n }\n if (clientReq.url?.startsWith('/__mindstudio_dev__/font-proxy?') && clientReq.method === 'GET') {\n this.handleFontProxy(clientReq, clientRes);\n return;\n }\n }\n\n // CORS preflight\n if (clientReq.method === 'OPTIONS' && clientReq.headers.origin) {\n clientRes.writeHead(204, {\n ...this.corsHeaders(clientReq),\n 'access-control-allow-methods': 'GET, POST, OPTIONS',\n 'access-control-allow-headers': '*',\n });\n clientRes.end();\n return;\n }\n\n // Forward to upstream dev server\n this.forwardToUpstream(clientReq, clientRes);\n }\n\n // ---------------------------------------------------------------------------\n // Upstream forwarding\n // ---------------------------------------------------------------------------\n\n private forwardToUpstream(\n clientReq: http.IncomingMessage,\n clientRes: http.ServerResponse,\n ): void {\n const cors = this.corsHeaders(clientReq);\n\n const upstreamReq = http.request(\n {\n hostname: '127.0.0.1',\n port: this.upstreamPort,\n path: clientReq.url,\n method: clientReq.method,\n headers: { ...clientReq.headers, host: `localhost:${this.upstreamPort}` },\n },\n (upstreamRes) => {\n const contentType = upstreamRes.headers['content-type'] ?? '';\n const isHtml = contentType.startsWith('text/html');\n\n if (isHtml) {\n const chunks: Buffer[] = [];\n upstreamRes.on('data', (chunk) => chunks.push(chunk));\n upstreamRes.on('end', () => {\n let html = Buffer.concat(chunks).toString('utf-8');\n html = this.injectScripts(html);\n\n const headers = {\n ...upstreamRes.headers,\n ...cors,\n 'content-length': String(Buffer.byteLength(html, 'utf-8')),\n 'cache-control': 'no-store, no-cache, must-revalidate',\n };\n delete headers['content-encoding'];\n delete headers['etag'];\n\n log.debug('Dev proxy injected context into HTML', { path: clientReq.url, size: html.length });\n clientRes.writeHead(upstreamRes.statusCode ?? 200, headers);\n clientRes.end(html);\n });\n } else {\n const headers = {\n ...upstreamRes.headers,\n ...cors,\n 'cache-control': 'no-store, no-cache, must-revalidate',\n };\n delete headers['etag'];\n clientRes.writeHead(upstreamRes.statusCode ?? 200, headers);\n upstreamRes.pipe(clientRes);\n }\n },\n );\n\n upstreamReq.on('error', (err) => {\n log.warn('Dev proxy cannot reach dev server', { path: clientReq.url, error: err.message });\n clientRes.writeHead(502);\n clientRes.end(`Proxy error: ${err.message}`);\n });\n\n clientReq.pipe(upstreamReq);\n }\n\n // ---------------------------------------------------------------------------\n // Browser agent endpoints\n // ---------------------------------------------------------------------------\n\n private handleBrowserLogs(\n clientReq: http.IncomingMessage,\n clientRes: http.ServerResponse,\n ): void {\n const chunks: Buffer[] = [];\n clientReq.on('data', (chunk) => chunks.push(chunk));\n clientReq.on('end', () => {\n try {\n const body = Buffer.concat(chunks).toString('utf-8');\n const entries = JSON.parse(body);\n if (Array.isArray(entries)) {\n appendBrowserLogEntries(entries);\n }\n } catch {\n // Malformed payload — ignore\n }\n clientRes.writeHead(204, this.corsHeaders(clientReq));\n clientRes.end();\n });\n }\n\n /**\n * Proxy a cross-origin font stylesheet or font file through our server,\n * adding CORS headers so the browser agent can read the @font-face rules.\n */\n private async handleFontProxy(\n clientReq: http.IncomingMessage,\n clientRes: http.ServerResponse,\n ): Promise<void> {\n const cors = this.corsHeaders(clientReq);\n try {\n const parsed = new URL(clientReq.url!, `http://localhost`);\n const targetUrl = parsed.searchParams.get('url');\n if (!targetUrl) {\n clientRes.writeHead(400, cors);\n clientRes.end('Missing url parameter');\n return;\n }\n\n const response = await fetch(targetUrl);\n if (!response.ok) {\n clientRes.writeHead(response.status, cors);\n clientRes.end(`Upstream error: ${response.status}`);\n return;\n }\n\n const contentType = response.headers.get('content-type') || 'text/css';\n let body: string | Buffer;\n\n if (contentType.includes('css')) {\n // Rewrite font URLs inside CSS to also go through our proxy\n let css = await response.text();\n css = css.replace(\n /url\\(\\s*(['\"]?)(https?:\\/\\/[^)'\"]+)\\1\\s*\\)/g,\n (_, quote, url) => `url(${quote}/__mindstudio_dev__/font-proxy?url=${encodeURIComponent(url)}${quote})`,\n );\n body = css;\n } else {\n // Binary font file — pass through as-is\n const arrayBuf = await response.arrayBuffer();\n body = Buffer.from(arrayBuf);\n }\n\n clientRes.writeHead(200, {\n ...cors,\n 'content-type': contentType,\n 'cache-control': 'public, max-age=86400',\n });\n clientRes.end(body);\n } catch (err) {\n clientRes.writeHead(502, cors);\n clientRes.end(`Font proxy error: ${err instanceof Error ? err.message : String(err)}`);\n }\n }\n\n private handleGetCommand(\n clientReq: http.IncomingMessage,\n clientRes: http.ServerResponse,\n ): void {\n this.lastBrowserPoll = Date.now();\n\n // If a command is already queued, respond immediately\n const command = this.commandQueue.shift();\n if (command) {\n log.info('Browser command dispatched to agent', { id: command.id, commands: command.steps.map((s) => s.command) });\n clientRes.writeHead(200, {\n ...this.corsHeaders(clientReq),\n 'content-type': 'application/json',\n 'cache-control': 'no-store',\n });\n clientRes.end(JSON.stringify(command));\n return;\n }\n\n // No command available — hold the connection open (long poll).\n // Respond with 204 after 25s so the browser can reconnect.\n const timer = setTimeout(() => {\n this.removeCommandWaiter(clientRes);\n clientRes.writeHead(204, {\n ...this.corsHeaders(clientReq),\n 'cache-control': 'no-store',\n });\n clientRes.end();\n }, 25_000);\n\n this.commandWaiters.push({ req: clientReq, res: clientRes, timer });\n\n // If the client disconnects, clean up\n clientReq.on('close', () => {\n this.removeCommandWaiter(clientRes);\n });\n }\n\n /**\n * Flush a queued command to a waiting long-poll connection, if any.\n */\n private flushCommandToWaiter(): void {\n while (this.commandWaiters.length > 0 && this.commandQueue.length > 0) {\n const waiter = this.commandWaiters.shift()!;\n clearTimeout(waiter.timer);\n\n // Skip if the connection was already closed\n if (waiter.res.writableEnded) continue;\n\n const command = this.commandQueue.shift()!;\n this.lastBrowserPoll = Date.now();\n log.info('Browser command dispatched to agent', { id: command.id, commands: command.steps.map((s) => s.command) });\n waiter.res.writeHead(200, {\n ...this.corsHeaders(waiter.req),\n 'content-type': 'application/json',\n 'cache-control': 'no-store',\n });\n waiter.res.end(JSON.stringify(command));\n return;\n }\n }\n\n private removeCommandWaiter(res: http.ServerResponse): void {\n const idx = this.commandWaiters.findIndex((w) => w.res === res);\n if (idx !== -1) {\n clearTimeout(this.commandWaiters[idx].timer);\n this.commandWaiters.splice(idx, 1);\n }\n }\n\n private handlePostResult(\n clientReq: http.IncomingMessage,\n clientRes: http.ServerResponse,\n ): void {\n const chunks: Buffer[] = [];\n clientReq.on('data', (chunk) => chunks.push(chunk));\n clientReq.on('end', () => {\n try {\n const body = Buffer.concat(chunks).toString('utf-8');\n const result = JSON.parse(body);\n if (result?.id) {\n const pending = this.pendingResults.get(result.id);\n if (pending) {\n log.info('Browser command result received', { id: result.id, stepCount: result.steps?.length, duration: result.duration });\n clearTimeout(pending.timeout);\n this.pendingResults.delete(result.id);\n pending.resolve(result);\n } else {\n log.warn('Browser command result received but no pending command found', { id: result.id, pendingIds: [...this.pendingResults.keys()] });\n }\n } else {\n log.warn('Browser command result received with no id', { bodyLength: body.length });\n }\n } catch (err) {\n log.warn('Browser command result parse error', { error: err instanceof Error ? err.message : String(err) });\n }\n clientRes.writeHead(204, this.corsHeaders(clientReq));\n clientRes.end();\n });\n }\n\n /**\n * Inject window.__MINDSTUDIO__ context and browser agent script tag into HTML.\n */\n private injectScripts(html: string): string {\n const contextScript = `<script>window.__MINDSTUDIO__=${JSON.stringify(this.clientContext)};</script>`;\n const agentUrl = this.browserAgentUrl || 'https://unpkg.com/@mindstudio-ai/browser-agent/dist/index.js';\n const agentScript = `<script async src=\"${agentUrl}\"></script>`;\n const injection = `${contextScript}\\n${agentScript}`;\n if (html.includes('</head>')) {\n return html.replace('</head>', `${injection}\\n</head>`);\n }\n return injection + '\\n' + html;\n }\n\n private handleUpgrade(\n clientReq: http.IncomingMessage,\n clientSocket: Socket,\n head: Buffer,\n ): void {\n log.debug('Dev proxy WebSocket upgrade', { path: clientReq.url });\n const options: http.RequestOptions = {\n hostname: '127.0.0.1',\n port: this.upstreamPort,\n path: clientReq.url,\n method: clientReq.method,\n headers: { ...clientReq.headers, host: `localhost:${this.upstreamPort}` },\n };\n\n const upstreamReq = http.request(options);\n\n upstreamReq.on('upgrade', (upstreamRes, upstreamSocket, upgradeHead) => {\n // Send the 101 response back to the client\n let responseHead = `HTTP/${upstreamRes.httpVersion} ${upstreamRes.statusCode} ${upstreamRes.statusMessage}\\r\\n`;\n for (let i = 0; i < upstreamRes.rawHeaders.length; i += 2) {\n responseHead += `${upstreamRes.rawHeaders[i]}: ${upstreamRes.rawHeaders[i + 1]}\\r\\n`;\n }\n responseHead += '\\r\\n';\n\n clientSocket.write(responseHead);\n\n if (upgradeHead.length > 0) {\n clientSocket.write(upgradeHead);\n }\n if (head.length > 0) {\n upstreamSocket.write(head);\n }\n\n // Pipe both directions\n upstreamSocket.pipe(clientSocket);\n clientSocket.pipe(upstreamSocket);\n\n // Clean up on close\n clientSocket.on('close', () => upstreamSocket.destroy());\n upstreamSocket.on('close', () => clientSocket.destroy());\n clientSocket.on('error', () => upstreamSocket.destroy());\n upstreamSocket.on('error', () => clientSocket.destroy());\n });\n\n upstreamReq.on('error', () => {\n clientSocket.destroy();\n });\n\n upstreamReq.end();\n }\n}\n","// Reads the project's mindstudio.json manifest and related config files.\n//\n// mindstudio.json is the source of truth for the app — it declares methods,\n// tables, interfaces, and the appId. The CLI reads it on startup to know\n// what to transpile, which dev server to start, and what to send to the platform.\n//\n// Web interface config (e.g. dist/interfaces/web/web.json) provides devPort\n// and devCommand for the frontend dev server.\n\nimport { readFileSync, existsSync } from 'node:fs';\nimport { join, dirname } from 'node:path';\nimport { log } from './logger';\nimport type { AppConfig, WebInterfaceConfig } from './types';\n\n/**\n * Read and parse mindstudio.json from the given directory.\n * Returns null if not found or invalid.\n */\nexport function detectAppConfig(cwd: string = process.cwd()): AppConfig | null {\n const appJsonPath = join(cwd, 'mindstudio.json');\n if (!existsSync(appJsonPath)) {\n log.debug('mindstudio.json not found', { path: appJsonPath });\n return null;\n }\n\n try {\n const raw = readFileSync(appJsonPath, 'utf-8');\n const parsed = JSON.parse(raw);\n\n // Minimum validation: must have name and methods\n if (!parsed.name || !Array.isArray(parsed.methods)) {\n return null;\n }\n\n const config = {\n appId: parsed.appId,\n name: parsed.name,\n description: parsed.description,\n roles: parsed.roles ?? [],\n tables: parsed.tables ?? [],\n methods: parsed.methods,\n scenarios: parsed.scenarios ?? [],\n interfaces: parsed.interfaces ?? [],\n };\n log.info('Loaded mindstudio.json', {\n appId: config.appId,\n roles: config.roles.length,\n methods: config.methods.length,\n tables: config.tables.length,\n scenarios: config.scenarios.length,\n interfaces: config.interfaces.length,\n });\n return config;\n } catch (err) {\n log.warn('Failed to parse mindstudio.json', { error: err instanceof Error ? err.message : String(err) });\n return null;\n }\n}\n\n/**\n * Find the web interface config from mindstudio.json and read its devPort/devCommand.\n * Returns null if no web interface is declared or config file doesn't exist.\n */\nexport function getWebInterfaceConfig(\n appConfig: AppConfig,\n cwd: string = process.cwd(),\n): WebInterfaceConfig | null {\n const webInterface = appConfig.interfaces.find(\n (i) => i.type === 'web' && i.enabled !== false,\n );\n if (!webInterface) {\n return null;\n }\n\n const configPath = join(cwd, webInterface.path);\n if (!existsSync(configPath)) {\n return null;\n }\n\n try {\n const raw = readFileSync(configPath, 'utf-8');\n const parsed = JSON.parse(raw);\n const web = parsed.web;\n if (!web || typeof web !== 'object') {\n return null;\n }\n\n return {\n devPort: typeof web.devPort === 'number' ? web.devPort : undefined,\n devCommand: typeof web.devCommand === 'string' ? web.devCommand : undefined,\n };\n } catch {\n return null;\n }\n}\n\n/**\n * Get the web interface project directory from mindstudio.json.\n * The convention is that the config file lives inside the web project directory.\n */\nexport function getWebProjectDir(\n appConfig: AppConfig,\n cwd: string = process.cwd(),\n): string | null {\n const webInterface = appConfig.interfaces.find(\n (i) => i.type === 'web' && i.enabled !== false,\n );\n if (!webInterface) {\n return null;\n }\n\n return dirname(join(cwd, webInterface.path));\n}\n\n/**\n * Read raw TypeScript source for each table file listed in mindstudio.json.\n * Returns array of { name, source } for sending to sync-schema endpoint.\n * Skips files that don't exist.\n */\nexport function readTableSources(\n appConfig: AppConfig,\n cwd: string = process.cwd(),\n): Array<{ name: string; source: string }> {\n const results: Array<{ name: string; source: string }> = [];\n\n for (const table of appConfig.tables) {\n const filePath = join(cwd, table.path);\n if (!existsSync(filePath)) {\n log.warn('Table source file not found', { table: table.export, path: table.path });\n continue;\n }\n\n try {\n const source = readFileSync(filePath, 'utf-8');\n // Use the export name as the table name for error reporting\n const name = table.export;\n results.push({ name, source });\n } catch (err) {\n log.warn('Table source file unreadable', { table: table.export, path: table.path, error: err instanceof Error ? err.message : String(err) });\n }\n }\n\n if (results.length < appConfig.tables.length) {\n log.warn('Missing ' + (appConfig.tables.length - results.length) + ' table source file(s)', { found: results.length, expected: appConfig.tables.length });\n }\n\n return results;\n}\n\n/**\n * Find project directories that have a package.json but no node_modules.\n * Returns paths that need `npm install`.\n */\nexport function findDirsNeedingInstall(\n appConfig: AppConfig,\n cwd: string = process.cwd(),\n): string[] {\n const dirs: string[] = [];\n\n // Backend directory (derived from first method path, e.g. dist/backend/src/foo.ts → dist/backend)\n if (appConfig.methods.length > 0) {\n const firstMethodPath = appConfig.methods[0].path;\n // Walk up from the method file to find the nearest package.json\n const parts = firstMethodPath.split('/');\n for (let i = parts.length - 1; i >= 1; i--) {\n const candidate = join(cwd, ...parts.slice(0, i));\n if (existsSync(join(candidate, 'package.json'))) {\n if (!existsSync(join(candidate, 'node_modules'))) {\n dirs.push(candidate);\n }\n break;\n }\n }\n }\n\n // Web frontend directory\n const webProjectDir = getWebProjectDir(appConfig, cwd);\n if (webProjectDir && existsSync(join(webProjectDir, 'package.json'))) {\n if (!existsSync(join(webProjectDir, 'node_modules'))) {\n dirs.push(webProjectDir);\n }\n }\n\n return dirs;\n}\n","// Shared utilities for dev mode — used by both headless and TUI orchestrators.\n\nimport { execSync } from 'node:child_process';\n\n/** Derive a stable port number (3100-3999) from the app ID so the proxy URL is consistent. */\nexport function stablePort(appId: string): number {\n let hash = 0;\n for (let i = 0; i < appId.length; i++) {\n hash = ((hash << 5) - hash + appId.charCodeAt(i)) | 0;\n }\n return 3100 + (Math.abs(hash) % 900);\n}\n\n/** Detect current git branch, or undefined if not in a git repo. */\nexport function detectGitBranch(): string | undefined {\n try {\n return execSync('git rev-parse --abbrev-ref HEAD', {\n encoding: 'utf-8',\n stdio: ['ignore', 'pipe', 'ignore'],\n }).trim() || undefined;\n } catch {\n return undefined;\n }\n}\n","// Watches directories containing table source files and triggers a callback\n// when a declared table file is created or modified. Used by both headless\n// and TUI modes to auto-sync schema without session restart.\n//\n// Uses chokidar instead of fs.watch so that:\n// - Atomic file replacements (write-tmp + rename) are detected on Linux\n// - Directories that don't exist yet are watched once created\n// - Events are deduplicated and debounced reliably\n\nimport { watch } from 'chokidar';\nimport { join, dirname, basename } from 'node:path';\nimport { log } from './logger';\nimport type { AppTable } from './types';\n\n/**\n * Watch table source directories for changes.\n *\n * @param tables - Table entries from appConfig.tables\n * @param cwd - Project root directory\n * @param onChanged - Called (debounced 500ms) when a table file changes\n * @returns Cleanup function that closes all watchers and clears timers\n */\nexport function watchTableFiles(\n tables: AppTable[],\n cwd: string,\n onChanged: () => void,\n): () => void {\n if (tables.length === 0) return () => {};\n\n // Resolve absolute paths for each table file\n const filePaths = tables.map((t) => join(cwd, t.path));\n\n let syncTimer: ReturnType<typeof setTimeout> | undefined;\n\n const watcher = watch(filePaths, {\n ignoreInitial: true,\n // Don't fail if files don't exist yet — watch for creation\n disableGlobbing: true,\n });\n\n watcher.on('all', () => {\n clearTimeout(syncTimer);\n syncTimer = setTimeout(onChanged, 500);\n });\n\n // Build a map for logging\n const dirToFiles = new Map<string, Set<string>>();\n for (const table of tables) {\n const absPath = join(cwd, table.path);\n const dir = dirname(absPath);\n const file = basename(absPath);\n if (!dirToFiles.has(dir)) dirToFiles.set(dir, new Set());\n dirToFiles.get(dir)!.add(file);\n }\n\n log.info('Watching table source files', {\n dirs: dirToFiles.size,\n tables: tables.length,\n });\n\n return () => {\n clearTimeout(syncTimer);\n watcher.close();\n };\n}\n","// Watches mindstudio.json for changes and triggers a callback.\n//\n// Uses chokidar instead of fs.watch so that atomic file replacements\n// (write-tmp + rename) are detected on Linux. fs.watch watches the inode,\n// so a rename-based write silently kills the watcher.\n\nimport { watch } from 'chokidar';\nimport { join } from 'node:path';\nimport { log } from './logger';\n\n/**\n * Watch mindstudio.json for changes.\n *\n * @param cwd - Project root directory\n * @param onChanged - Called (debounced 500ms) when the config file changes\n * @returns Cleanup function that closes the watcher and clears timers\n */\nexport function watchConfigFile(\n cwd: string,\n onChanged: () => void,\n): () => void {\n const configPath = join(cwd, 'mindstudio.json');\n\n let debounceTimer: ReturnType<typeof setTimeout> | undefined;\n\n const watcher = watch(configPath, {\n ignoreInitial: true,\n disableGlobbing: true,\n });\n\n watcher.on('all', () => {\n clearTimeout(debounceTimer);\n debounceTimer = setTimeout(() => {\n onChanged();\n }, 500);\n });\n\n log.info('Watching mindstudio.json for changes', { path: configPath });\n\n return () => {\n clearTimeout(debounceTimer);\n watcher.close();\n };\n}\n"],"mappings":"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","names":["fs","fs","join","join","unlink","join","unlink","join","resolve","getHeaders","randomBytes","randomBytes","resolve","ndjsonLog","randomBytes","randomBytes","resolve","pending","existsSync","join","dirname","join","existsSync","config","dirname","join","dirname","basename","join","dirname","basename","watch","join","join","watch"]}
|
package/dist/cli.js
CHANGED
package/dist/headless.js
CHANGED
package/dist/index.js
CHANGED
|
@@ -1,10 +1,10 @@
|
|
|
1
1
|
import {
|
|
2
2
|
startHeadless
|
|
3
|
-
} from "./chunk-
|
|
3
|
+
} from "./chunk-ENSNEBJJ.js";
|
|
4
4
|
import {
|
|
5
5
|
TunnelRunner
|
|
6
|
-
} from "./chunk-
|
|
7
|
-
import "./chunk-
|
|
6
|
+
} from "./chunk-TMIU4S53.js";
|
|
7
|
+
import "./chunk-VJTZSOKC.js";
|
|
8
8
|
export {
|
|
9
9
|
TunnelRunner,
|
|
10
10
|
startHeadless
|
|
@@ -3,7 +3,7 @@ import {
|
|
|
3
3
|
detectAllProviderStatuses,
|
|
4
4
|
discoverAllModelsWithParameters,
|
|
5
5
|
requestEvents
|
|
6
|
-
} from "./chunk-
|
|
6
|
+
} from "./chunk-TMIU4S53.js";
|
|
7
7
|
import {
|
|
8
8
|
DevProxy,
|
|
9
9
|
DevRunner,
|
|
@@ -36,7 +36,7 @@ import {
|
|
|
36
36
|
verifyApiKey,
|
|
37
37
|
watchConfigFile,
|
|
38
38
|
watchTableFiles
|
|
39
|
-
} from "./chunk-
|
|
39
|
+
} from "./chunk-VJTZSOKC.js";
|
|
40
40
|
|
|
41
41
|
// src/tui/index.tsx
|
|
42
42
|
import { render } from "ink";
|
|
@@ -151,7 +151,7 @@ function Header({
|
|
|
151
151
|
/* @__PURE__ */ jsx(Text, { bold: true, color: "white", children: "MindStudio Local Tunnel" }),
|
|
152
152
|
compact && /* @__PURE__ */ jsxs(Text, { color: "gray", children: [
|
|
153
153
|
" v",
|
|
154
|
-
"0.5.
|
|
154
|
+
"0.5.22"
|
|
155
155
|
] }),
|
|
156
156
|
environment !== "prod" && /* @__PURE__ */ jsxs(Fragment, { children: [
|
|
157
157
|
/* @__PURE__ */ jsx(Text, { children: " " }),
|
|
@@ -169,7 +169,7 @@ function Header({
|
|
|
169
169
|
] }),
|
|
170
170
|
!compact && /* @__PURE__ */ jsxs(Text, { color: "gray", children: [
|
|
171
171
|
"v",
|
|
172
|
-
"0.5.
|
|
172
|
+
"0.5.22"
|
|
173
173
|
] })
|
|
174
174
|
] })
|
|
175
175
|
]
|
|
@@ -3790,7 +3790,7 @@ function getInstallMethod() {
|
|
|
3790
3790
|
return "npm";
|
|
3791
3791
|
}
|
|
3792
3792
|
function getCurrentVersion() {
|
|
3793
|
-
return "0.5.
|
|
3793
|
+
return "0.5.22";
|
|
3794
3794
|
}
|
|
3795
3795
|
async function fetchLatestVersion() {
|
|
3796
3796
|
try {
|
|
@@ -4032,4 +4032,4 @@ async function startTUI() {
|
|
|
4032
4032
|
export {
|
|
4033
4033
|
startTUI
|
|
4034
4034
|
};
|
|
4035
|
-
//# sourceMappingURL=tui-
|
|
4035
|
+
//# sourceMappingURL=tui-ZUGRCB5V.js.map
|
package/package.json
CHANGED
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/dev/session-events.ts","../src/dev/stdin-commands/run-scenario.ts","../src/dev/stdin-commands/run-method.ts","../src/dev/stdin-commands/impersonate.ts","../src/dev/stdin-commands/browser.ts","../src/dev/stdin-commands/screenshot.ts","../src/dev/stdin-commands/dev-server-restarting.ts","../src/dev/stdin-commands/browser-status.ts","../src/dev/stdin-commands/reset-browser.ts","../src/dev/stdin-commands/index.ts","../src/headless.ts"],"sourcesContent":["/**\n * Subscribe to DevRunner events and relay them as JSON to stdout.\n * Returns an array of unsubscribe functions for cleanup on teardown.\n */\n\nimport { devRequestEvents } from './events';\n\ntype EmitFn = (event: string, data?: Record<string, unknown>) => void;\n\nexport function subscribeDevEvents(\n emit: EmitFn,\n shutdown: () => Promise<void>,\n): Array<() => void> {\n const unsubs: Array<() => void> = [];\n\n unsubs.push(\n devRequestEvents.onStart((event) => {\n emit('method-started', { id: event.id, method: event.method });\n }),\n );\n\n unsubs.push(\n devRequestEvents.onComplete((event) => {\n emit('method-completed', {\n id: event.id,\n success: event.success,\n duration: event.duration,\n ...(event.error ? { error: event.error } : {}),\n });\n }),\n );\n\n unsubs.push(\n devRequestEvents.onConnectionWarning((message) => {\n emit('connection-lost', { message });\n }),\n );\n\n unsubs.push(\n devRequestEvents.onConnectionRestored(() => {\n emit('connection-restored');\n }),\n );\n\n unsubs.push(\n devRequestEvents.onSessionExpired(() => {\n emit('session-expired');\n shutdown().then(() => process.exit(1));\n }),\n );\n\n unsubs.push(\n devRequestEvents.onAuthRefreshStart((url) => {\n emit('auth-refresh-start', { url });\n }),\n );\n\n unsubs.push(\n devRequestEvents.onAuthRefreshSuccess(() => {\n emit('auth-refresh-success');\n }),\n );\n\n unsubs.push(\n devRequestEvents.onAuthRefreshFailed(() => {\n emit('auth-refresh-failed');\n }),\n );\n\n unsubs.push(\n devRequestEvents.onImpersonate((event) => {\n emit('impersonation-changed', { roles: event.roles });\n }),\n );\n\n unsubs.push(\n devRequestEvents.onScenarioStart((event) => {\n emit('scenario-started', { id: event.id, name: event.name });\n }),\n );\n\n unsubs.push(\n devRequestEvents.onScenarioComplete((event) => {\n emit('scenario-completed', {\n id: event.id,\n success: event.success,\n duration: event.duration,\n roles: event.roles,\n ...(event.error ? { error: event.error } : {}),\n });\n }),\n );\n\n return unsubs;\n}\n","import { detectAppConfig } from '../app-config';\nimport type { SessionState, EmitFn } from './types';\n\nexport async function handleRunScenario(\n state: SessionState,\n cwd: string,\n cmd: Record<string, unknown>,\n emit: EmitFn,\n): Promise<void> {\n if (!state.runner) {\n emit('command-error', { message: 'No active session' });\n return;\n }\n const freshConfig = detectAppConfig(cwd) ?? state.appConfig;\n const scenario = freshConfig?.scenarios.find((s) => s.id === cmd.scenarioId);\n if (!scenario) {\n emit('command-error', { message: `Unknown scenario: ${cmd.scenarioId}` });\n return;\n }\n await state.runner.runScenario(scenario);\n}\n","import { detectAppConfig } from '../app-config';\nimport type { SessionState, EmitFn } from './types';\n\nexport async function handleRunMethod(\n state: SessionState,\n cwd: string,\n cmd: Record<string, unknown>,\n emit: EmitFn,\n): Promise<void> {\n if (!state.runner) {\n emit('command-error', { message: 'No active session' });\n return;\n }\n const methodName = cmd.method as string;\n if (!methodName) {\n emit('command-error', { message: 'run-method requires \"method\" (export name or ID)' });\n return;\n }\n const freshConfig = detectAppConfig(cwd) ?? state.appConfig;\n const method =\n freshConfig?.methods.find((m) => m.export === methodName) ??\n freshConfig?.methods.find((m) => m.id === methodName);\n if (!method) {\n emit('command-error', { message: `Unknown method: ${methodName}` });\n return;\n }\n const result = await state.runner.runMethod({\n methodExport: method.export,\n methodPath: method.path,\n input: cmd.input ?? {},\n });\n emit('method-run-completed', {\n method: method.export,\n success: result.success,\n output: result.output ?? null,\n error: result.error ?? null,\n stdout: result.stdout ?? [],\n duration: result.duration,\n });\n}\n","import type { SessionState, EmitFn } from './types';\n\nexport async function handleImpersonate(\n state: SessionState,\n cmd: Record<string, unknown>,\n emit: EmitFn,\n): Promise<void> {\n if (!state.runner) {\n emit('command-error', { message: 'No active session' });\n return;\n }\n const roles = cmd.roles as string[];\n if (!Array.isArray(roles)) {\n emit('command-error', { message: 'impersonate requires roles array' });\n return;\n }\n await state.runner.setImpersonation(roles);\n}\n\nexport async function handleClearImpersonation(\n state: SessionState,\n emit: EmitFn,\n): Promise<void> {\n if (!state.runner) {\n emit('command-error', { message: 'No active session' });\n return;\n }\n await state.runner.clearImpersonation();\n}\n","import type { SessionState, EmitFn } from './types';\n\nexport async function handleBrowser(\n state: SessionState,\n cmd: Record<string, unknown>,\n emit: EmitFn,\n): Promise<void> {\n if (!state.proxy) {\n emit('command-error', { message: 'No active proxy — browser commands require a web interface' });\n return;\n }\n const steps = cmd.steps as Array<Record<string, unknown>>;\n if (!Array.isArray(steps) || steps.length === 0) {\n emit('command-error', { message: 'browser action requires a non-empty \"steps\" array' });\n return;\n }\n try {\n const result = await state.proxy.dispatchBrowserCommand(steps);\n emit('browser-completed', {\n steps: result.steps,\n snapshot: result.snapshot,\n logs: result.logs,\n duration: result.duration,\n });\n } catch (err) {\n emit('command-error', {\n message: err instanceof Error ? err.message : 'Browser command failed',\n });\n }\n}\n","import { getUploadUrl } from '../api';\nimport type { SessionState, EmitFn } from './types';\n\nexport async function handleScreenshot(\n state: SessionState,\n emit: EmitFn,\n): Promise<void> {\n const fail = (message: string) => {\n emit('screenshot-completed', {\n url: '',\n width: 0,\n height: 0,\n duration: 0,\n error: message,\n });\n };\n\n if (!state.proxy) {\n fail('No active proxy');\n return;\n }\n if (!state.proxy.isBrowserConnected()) {\n fail('No browser connected, please refresh the MindStudio preview');\n return;\n }\n if (!state.runner?.getSession() || !state.appConfig?.appId) {\n fail('No active session');\n return;\n }\n\n try {\n const startTime = Date.now();\n\n // 1. Dispatch screenshot command to browser\n const result = await state.proxy.dispatchBrowserCommand([{ command: 'screenshot' }]);\n const stepResult = (result.steps as Array<Record<string, unknown>>)?.[0]\n ?.result as { image: string; width: number; height: number };\n\n if (!stepResult?.image) {\n fail('Screenshot capture returned no image data');\n return;\n }\n\n // 2. Get presigned upload URL\n const session = state.runner.getSession()!;\n const { uploadUrl, uploadFields, publicUrl } = await getUploadUrl(\n state.appConfig.appId,\n session.sessionId,\n 'png',\n 'image/png',\n );\n\n // 3. Upload to S3\n const imageBuffer = Buffer.from(stepResult.image, 'base64');\n const form = new FormData();\n for (const [key, value] of Object.entries(uploadFields)) {\n form.append(key, value);\n }\n form.append('file', new Blob([imageBuffer], { type: 'image/png' }), 'screenshot.png');\n const uploadResult = await fetch(uploadUrl, { method: 'POST', body: form });\n\n if (!uploadResult.ok) {\n fail(`S3 upload failed: ${uploadResult.status}`);\n return;\n }\n\n // 4. Emit result\n emit('screenshot-completed', {\n url: publicUrl,\n width: stepResult.width,\n height: stepResult.height,\n duration: Date.now() - startTime,\n });\n } catch (err) {\n fail(err instanceof Error ? err.message : 'Screenshot failed');\n }\n}\n","import type { SessionState, EmitFn } from './types';\n\n/**\n * Handle explicit signal that the upstream dev server is restarting.\n * Marks the upstream as down so the proxy's health check will detect\n * when it's back and auto-reload the browser.\n */\nexport async function handleDevServerRestarting(\n state: SessionState,\n emit: EmitFn,\n): Promise<void> {\n if (!state.proxy) {\n emit('command-error', { message: 'No active proxy' });\n return;\n }\n state.proxy.markUpstreamDown();\n emit('dev-server-restarting-ack', {});\n}\n","import type { SessionState, EmitFn } from './types';\n\nexport function handleBrowserStatus(\n state: SessionState,\n emit: EmitFn,\n): void {\n emit('browser-status', {\n connected: state.proxy?.isBrowserConnected() ?? false,\n });\n}\n","import type { SessionState, EmitFn } from './types';\n\n/**\n * Reset the browser to a clean state by reloading the page.\n * The agent sends this explicitly when done testing.\n * Fire-and-forget — the reload kills the page so no result comes back.\n */\nexport function handleResetBrowser(\n state: SessionState,\n emit: EmitFn,\n): void {\n if (!state.proxy) {\n emit('command-error', { message: 'No active proxy' });\n return;\n }\n if (!state.proxy.isBrowserConnected()) {\n emit('command-error', { message: 'No browser connected' });\n return;\n }\n state.proxy.dispatchBrowserCommand([{ command: 'reload' }]).catch(() => {});\n emit('reset-browser-completed', {});\n}\n","/**\n * Stdin command router for headless mode.\n *\n * Reads NDJSON commands from stdin and dispatches to individual handlers.\n * Each command lives in its own file for isolation and testability.\n */\n\nimport { handleRunScenario } from './run-scenario';\nimport { handleRunMethod } from './run-method';\nimport { handleImpersonate, handleClearImpersonation } from './impersonate';\nimport { handleBrowser } from './browser';\nimport { handleScreenshot } from './screenshot';\nimport { handleDevServerRestarting } from './dev-server-restarting';\nimport { handleBrowserStatus } from './browser-status';\nimport { handleResetBrowser } from './reset-browser';\nimport type { SessionState, EmitFn } from './types';\n\nexport type { SessionState, EmitFn } from './types';\n\nexport function setupStdinCommands(\n state: SessionState,\n cwd: string,\n emit: EmitFn,\n): void {\n if (!process.stdin.readable) return;\n\n let buffer = '';\n process.stdin.setEncoding('utf-8');\n process.stdin.on('data', (chunk: string) => {\n buffer += chunk;\n let idx: number;\n while ((idx = buffer.indexOf('\\n')) !== -1) {\n const line = buffer.slice(0, idx).trim();\n buffer = buffer.slice(idx + 1);\n if (!line) continue;\n\n try {\n const cmd = JSON.parse(line) as { action: string; [key: string]: unknown };\n handleStdinCommand(cmd, state, cwd, emit);\n } catch {\n emit('command-error', { message: `Invalid JSON on stdin: ${line.slice(0, 100)}` });\n }\n }\n });\n}\n\nasync function handleStdinCommand(\n cmd: { action: string; [key: string]: unknown },\n state: SessionState,\n cwd: string,\n emit: EmitFn,\n): Promise<void> {\n switch (cmd.action) {\n case 'run-scenario':\n return handleRunScenario(state, cwd, cmd, emit);\n case 'run-method':\n return handleRunMethod(state, cwd, cmd, emit);\n case 'impersonate':\n return handleImpersonate(state, cmd, emit);\n case 'clear-impersonation':\n return handleClearImpersonation(state, emit);\n case 'browser':\n return handleBrowser(state, cmd, emit);\n case 'screenshot':\n return handleScreenshot(state, emit);\n case 'dev-server-restarting':\n return handleDevServerRestarting(state, emit);\n case 'browser-status':\n return handleBrowserStatus(state, emit);\n case 'reset-browser':\n return handleResetBrowser(state, emit);\n default:\n emit('command-error', { message: `Unknown action: ${cmd.action}` });\n }\n}\n","/**\n * Headless Dev Mode\n *\n * Runs the MindStudio dev tunnel without a TUI. Designed for programmatic\n * control by a parent process (e.g., a sandbox C&C server or CI pipeline).\n *\n * Outputs structured JSON events to stdout (one per line, newline-delimited).\n * The parent process reads these to track session state, method execution,\n * errors, and connection health.\n *\n * Does NOT start a dev server — the parent process manages that separately.\n * The tunnel just needs to know which port to proxy to.\n *\n * @module\n */\n\nimport { DevRunner } from './dev/runner';\nimport { DevProxy } from './dev/proxy';\nimport { syncSchema } from './dev/api';\nimport {\n detectAppConfig,\n getWebInterfaceConfig,\n readTableSources,\n} from './dev/app-config';\nimport { initRequestLog, closeRequestLog } from './dev/request-log';\nimport { initBrowserLog, closeBrowserLog } from './dev/browser-log';\nimport { subscribeDevEvents } from './dev/session-events';\nimport { setupStdinCommands, type SessionState } from './dev/stdin-commands';\nimport {\n getApiKey,\n getApiBaseUrl,\n getUserId,\n getEnvironment,\n getConfigPath,\n} from './config';\nimport { initLoggerHeadless, log, type LogLevel } from './dev/logger';\nimport { stablePort, detectGitBranch } from './dev/utils';\nimport { watchTableFiles } from './dev/table-watcher';\nimport { watchConfigFile } from './dev/config-watcher';\n\n/**\n * Options for headless dev mode.\n */\nexport interface HeadlessOptions {\n /** Working directory containing mindstudio.json. Defaults to process.cwd(). */\n cwd?: string;\n /** Port the dev server is running on. If omitted, reads from web.json. If neither, proxy is skipped. */\n devPort?: number;\n /** Preferred port for the local proxy. Defaults to a stable port derived from the app ID. */\n proxyPort?: number;\n /** Bind address for the proxy server. Use '0.0.0.0' for hosted sandboxes. Defaults to '127.0.0.1'. */\n bindAddress?: string;\n /** Log level for stderr output. Defaults to 'info'. */\n logLevel?: LogLevel;\n /** URL for the browser agent script. Defaults to unpkg latest. Set to an ngrok URL for development. */\n browserAgentUrl?: string;\n}\n\n/** Write a JSON event to stdout. */\nfunction emit(event: string, data?: Record<string, unknown>): void {\n process.stdout.write(JSON.stringify({ event, ...data }) + '\\n');\n}\n\n// ---------------------------------------------------------------------------\n// Session lifecycle\n// ---------------------------------------------------------------------------\n\nasync function startSession(\n cwd: string,\n opts: HeadlessOptions,\n state: SessionState,\n shutdown: () => Promise<void>,\n): Promise<boolean> {\n const bindAddress = opts.bindAddress ?? '127.0.0.1';\n\n // Read fresh config\n const appConfig = detectAppConfig(cwd);\n if (!appConfig) {\n emit('config-error', { message: 'No valid mindstudio.json found in ' + cwd });\n return false;\n }\n\n if (!appConfig.appId) {\n emit('config-error', { message: 'Missing \"appId\" in mindstudio.json' });\n return false;\n }\n\n state.appConfig = appConfig;\n\n // Resolve dev port\n let devPort = opts.devPort ?? null;\n if (devPort === null) {\n const webConfig = getWebInterfaceConfig(appConfig, cwd);\n devPort = webConfig?.devPort ?? null;\n }\n\n emit('session-starting', { appId: appConfig.appId, name: appConfig.name });\n\n try {\n // Start platform session\n const branch = detectGitBranch();\n const runner = new DevRunner(appConfig.appId, cwd, {\n branch,\n methods: appConfig.methods.map((m) => ({ id: m.id, export: m.export, path: m.path })),\n });\n const session = await runner.start();\n state.runner = runner;\n\n // Initialize logs\n initRequestLog(cwd);\n initBrowserLog(cwd);\n\n // Sync schema\n if (appConfig.tables.length > 0) {\n try {\n const tableSources = readTableSources(appConfig, cwd);\n if (tableSources.length > 0) {\n const syncResult = await syncSchema(appConfig.appId, session.sessionId, tableSources);\n session.databases = syncResult.databases;\n emit('schema-sync-completed', {\n created: syncResult.created,\n altered: syncResult.altered,\n errors: syncResult.errors,\n });\n } else {\n log.warn('No table source files found, skipping schema sync', {\n expected: appConfig.tables.map((t) => t.path),\n });\n }\n } catch (err) {\n emit('schema-sync-completed', {\n created: [],\n altered: [],\n errors: [err instanceof Error ? err.message : 'Schema sync failed'],\n });\n }\n }\n\n // Start proxy\n let proxyPort: number | null = null;\n if (devPort !== null && session.clientContext) {\n const proxy = new DevProxy(devPort, session.clientContext, bindAddress, opts.browserAgentUrl);\n const preferred = opts.proxyPort ?? stablePort(appConfig.appId);\n proxyPort = await proxy.start(preferred);\n runner.setProxyUrl(`http://${bindAddress === '0.0.0.0' ? 'localhost' : bindAddress}:${proxyPort}`);\n runner.setProxy(proxy);\n state.proxy = proxy;\n }\n state.proxyPort = proxyPort;\n\n emit('session-started', {\n sessionId: session.sessionId,\n releaseId: session.releaseId,\n branch: session.branch,\n proxyPort,\n proxyUrl: proxyPort\n ? `http://${bindAddress === '0.0.0.0' ? 'localhost' : bindAddress}:${proxyPort}/`\n : null,\n webInterfaceUrl: session.webInterfaceUrl,\n roles: appConfig.roles.map((r) => ({ id: r.id, name: r.name ?? r.id, description: r.description })),\n scenarios: appConfig.scenarios.map((s) => ({\n id: s.id,\n name: s.name ?? s.export,\n description: s.description,\n path: s.path,\n roles: s.roles,\n })),\n });\n\n // Subscribe to runner events\n state.unsubscribers.push(...subscribeDevEvents(emit, shutdown));\n\n // Watch table source files for changes — auto-sync without session restart\n setupTableWatchers(cwd, state);\n\n return true;\n } catch (err) {\n emit('config-error', {\n message: err instanceof Error ? err.message : 'Failed to start session',\n });\n return false;\n }\n}\n\nfunction setupTableWatchers(cwd: string, state: SessionState): void {\n if (!state.appConfig || state.appConfig.tables.length === 0) return;\n\n const cleanup = watchTableFiles(state.appConfig.tables, cwd, async () => {\n if (!state.runner || !state.appConfig?.appId) return;\n const session = state.runner.getSession();\n if (!session) return;\n\n emit('schema-sync-started');\n log.info('Table source file changed, syncing schema');\n\n try {\n const tableSources = readTableSources(state.appConfig, cwd);\n if (tableSources.length > 0) {\n const result = await syncSchema(state.appConfig.appId, session.sessionId, tableSources);\n session.databases = result.databases;\n emit('schema-sync-completed', {\n created: result.created,\n altered: result.altered,\n errors: result.errors,\n });\n log.info('Schema sync complete', { created: result.created, altered: result.altered });\n } else {\n log.warn('Table source file change detected but file(s) still missing', {\n expected: state.appConfig.tables.map((t) => t.path),\n });\n }\n } catch (err) {\n const message = err instanceof Error ? err.message : 'Schema sync failed';\n emit('command-error', { message });\n log.warn('Schema sync failed', { error: message });\n }\n });\n\n state.unsubscribers.push(cleanup);\n}\n\nasync function teardownSession(state: SessionState): Promise<void> {\n for (const unsub of state.unsubscribers) unsub();\n state.unsubscribers = [];\n\n state.proxy?.stop();\n state.proxy = null;\n state.proxyPort = null;\n\n if (state.runner) {\n await state.runner.stop().catch(() => {});\n state.runner = null;\n }\n\n closeRequestLog();\n closeBrowserLog();\n}\n\n// ---------------------------------------------------------------------------\n// Entry point\n// ---------------------------------------------------------------------------\n\n/**\n * Start the dev tunnel in headless mode.\n */\nexport async function startHeadless(opts: HeadlessOptions = {}): Promise<void> {\n initLoggerHeadless(opts.logLevel ?? 'info');\n\n const cwd = opts.cwd ?? process.cwd();\n\n const apiKey = getApiKey();\n const userId = getUserId();\n log.info('Startup config', {\n configPath: getConfigPath(),\n environment: getEnvironment(),\n apiBaseUrl: getApiBaseUrl(),\n hasApiKey: !!apiKey,\n apiKeyPrefix: apiKey ? apiKey.slice(0, 8) + '...' : null,\n hasUserId: !!userId,\n userId: userId ?? null,\n cwd,\n });\n\n const state: SessionState = {\n runner: null,\n proxy: null,\n appConfig: null,\n proxyPort: null,\n unsubscribers: [],\n };\n\n let restarting = false;\n let cleanupConfigWatcher: (() => void) | undefined;\n\n let stopping = false;\n const shutdown = async () => {\n if (stopping) return;\n stopping = true;\n emit('session-stopping');\n cleanupConfigWatcher?.();\n await teardownSession(state);\n emit('session-stopped');\n };\n\n process.on('SIGTERM', () => { shutdown().then(() => process.exit(0)); });\n process.on('SIGINT', () => { shutdown().then(() => process.exit(0)); });\n\n // Initial session start — crash if it fails so the process manager can retry\n const ok = await startSession(cwd, opts, state, shutdown);\n if (!ok) {\n process.exit(1);\n }\n\n // Stdin command loop\n setupStdinCommands(state, cwd, emit);\n\n // Watch mindstudio.json for changes\n cleanupConfigWatcher = watchConfigFile(cwd, async () => {\n if (stopping || restarting) return;\n restarting = true;\n try {\n log.info('mindstudio.json changed, restarting dev session');\n emit('config-changed');\n await teardownSession(state);\n const ok = await startSession(cwd, opts, state, shutdown);\n if (ok && state.proxy) {\n state.proxy.dispatchBrowserCommand([{ command: 'reload' }]).catch(() => {});\n }\n } finally {\n restarting = false;\n }\n });\n\n // Keep the process alive — the poll loop runs in DevRunner\n await new Promise<void>(() => {});\n}\n"],"mappings":"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","names":["emit","emit","emit","emit","emit","emit","emit","emit","emit","emit","ok"]}
|
|
File without changes
|
|
File without changes
|