@mindstudio-ai/local-model-tunnel 0.5.8 → 0.5.9
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-QALGC7T7.js → chunk-253MU7UA.js} +2 -2
- package/dist/{chunk-C3JPRLSS.js → chunk-4CMGJFH3.js} +42 -19
- package/dist/chunk-4CMGJFH3.js.map +1 -0
- package/dist/{chunk-WFQXIMTS.js → chunk-UNG63WXC.js} +17 -27
- package/dist/chunk-UNG63WXC.js.map +1 -0
- package/dist/cli.js +1 -1
- package/dist/headless.js +2 -2
- package/dist/index.js +3 -3
- package/dist/{tui-4PJCFILV.js → tui-343LXUFQ.js} +26 -39
- package/dist/{tui-4PJCFILV.js.map → tui-343LXUFQ.js.map} +1 -1
- package/package.json +3 -2
- package/dist/chunk-C3JPRLSS.js.map +0 -1
- package/dist/chunk-WFQXIMTS.js.map +0 -1
- /package/dist/{chunk-QALGC7T7.js.map → chunk-253MU7UA.js.map} +0 -0
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@mindstudio-ai/local-model-tunnel",
|
|
3
|
-
"version": "0.5.
|
|
3
|
+
"version": "0.5.9",
|
|
4
4
|
"description": "Run local AI models with MindStudio",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "dist/index.js",
|
|
@@ -35,10 +35,11 @@
|
|
|
35
35
|
"url": "https://github.com/mindstudio-ai/mindstudio-local-model-tunnel"
|
|
36
36
|
},
|
|
37
37
|
"dependencies": {
|
|
38
|
-
"esbuild": "^0.24.0",
|
|
39
38
|
"chalk": "^5.3.0",
|
|
39
|
+
"chokidar": "^5.0.0",
|
|
40
40
|
"commander": "^12.0.0",
|
|
41
41
|
"conf": "^12.0.0",
|
|
42
|
+
"esbuild": "^0.24.0",
|
|
42
43
|
"ink": "^6.6.0",
|
|
43
44
|
"ink-spinner": "^5.0.0",
|
|
44
45
|
"ink-text-input": "^6.0.0",
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/config.ts","../src/dev/logger.ts","../src/dev/api.ts","../src/dev/events.ts","../src/dev/transpiler.ts","../src/dev/executor.ts","../src/api.ts","../src/dev/runner.ts","../src/dev/proxy.ts","../src/dev/app-config.ts","../src/dev/utils.ts","../src/dev/table-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\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","// 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('transpiler Transpiling', { 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('transpiler No node_modules found', { methodPath, searchStart: dirname(absolutePath) });\n throw new Error(\n `No node_modules found near ${methodPath}. Run npm install first.`,\n );\n }\n log.debug('transpiler 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(`transpiler 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('transpiler Cleaning up', { 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('transpiler Removing orphaned 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 a transpiled method in an isolated child process.\n//\n// Each method invocation gets its own Node.js process for isolation.\n// The process runs a bootstrap .mjs script that:\n// 1. Sets up globalThis.ai (auth + database context for the SDK)\n// 2. Intercepts console.log/warn/error into a buffer (so it doesn't\n// corrupt our JSON result on stdout)\n// 3. Imports the transpiled method and calls it\n// 4. Writes the result as JSON to stdout\n//\n// This mirrors the cloud sandbox's buildIndexFile.ts pattern. The SDK\n// (@mindstudio-ai/agent) doesn't know it's running locally — it uses\n// the same env vars (CALLBACK_TOKEN, REMOTE_HOSTNAME) for db queries\n// and other platform callbacks.\n\nimport { spawn } 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_000;\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 * Build the bootstrap ESM script that sets up globalThis.ai,\n * imports the transpiled method, calls the export, and writes the result to stdout.\n */\nfunction buildBootstrapScript(opts: ExecuteMethodOptions): string {\n return `\nglobal.ai = {\n auth: ${JSON.stringify(opts.auth)},\n databases: ${JSON.stringify(opts.databases)},\n};\n\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 // Capture common extra properties from SDK/HTTP errors\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 // Capture any other enumerable properties\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// Capture console output from method code\nconst _stdout = [];\nconsole.log = (...args) => _stdout.push(args.map(String).join(' '));\nconsole.warn = (...args) => _stdout.push(args.map(String).join(' '));\nconsole.error = (...args) => _stdout.push(args.map(String).join(' '));\n\nconst _startTime = Date.now();\n\nconst { ${opts.methodExport} } = await import(${JSON.stringify(opts.transpiledPath + '?t=' + Date.now())});\n\ntry {\n const returnValue = await ${opts.methodExport}(${JSON.stringify(opts.input)});\n const _stats = { memoryUsedBytes: process.memoryUsage().heapUsed, executionTimeMs: Date.now() - _startTime };\n process.stdout.write(JSON.stringify({ success: true, output: returnValue, stdout: _stdout, stats: _stats }));\n} catch (err) {\n const _stats = { memoryUsedBytes: process.memoryUsage().heapUsed, executionTimeMs: Date.now() - _startTime };\n process.stdout.write(JSON.stringify({\n success: false,\n error: serializeError(err),\n stdout: _stdout,\n stats: _stats,\n }));\n}\n`;\n}\n\n/**\n * Execute a transpiled method file in an isolated Node.js child process.\n */\nexport async function executeMethod(\n opts: ExecuteMethodOptions,\n): Promise<ExecuteMethodResult> {\n // Write bootstrap script to a temp file\n const tempFile = join(\n tmpdir(),\n `ms-dev-${randomBytes(8).toString('hex')}.mjs`,\n );\n const script = buildBootstrapScript(opts);\n\n try {\n await writeFile(tempFile, script, 'utf-8');\n log.debug('executor Spawning node process', { methodExport: opts.methodExport, cwd: opts.projectRoot, tempFile });\n\n return await new Promise<ExecuteMethodResult>((resolve, reject) => {\n const stdoutChunks: Buffer[] = [];\n const stderrChunks: Buffer[] = [];\n\n const child = spawn('node', [tempFile], {\n cwd: opts.projectRoot,\n env: {\n ...process.env,\n // Auth + config env vars read by @mindstudio-ai/agent SDK\n // for platform callbacks (db queries, etc.)\n CALLBACK_TOKEN: opts.authorizationToken,\n REMOTE_HOSTNAME: opts.apiBaseUrl,\n ...(opts.streamId ? { STREAM_ID: opts.streamId } : {}),\n },\n stdio: ['ignore', 'pipe', 'pipe'],\n });\n\n child.stdout.on('data', (chunk) => stdoutChunks.push(chunk));\n child.stderr.on('data', (chunk) => stderrChunks.push(chunk));\n\n const timeout = setTimeout(() => {\n log.warn('executor Timeout after 30s, sending SIGKILL', { methodExport: opts.methodExport });\n child.kill('SIGKILL');\n reject(new Error('Method execution timed out after 30s'));\n }, EXECUTION_TIMEOUT_MS);\n\n child.on('close', (code) => {\n clearTimeout(timeout);\n\n const stdout = Buffer.concat(stdoutChunks).toString('utf-8').trim();\n const stderr = Buffer.concat(stderrChunks).toString('utf-8').trim();\n\n log.debug('executor Process exited', { code, stdoutLen: stdout.length, stderrLen: stderr.length });\n\n if (stdout) {\n try {\n resolve(JSON.parse(stdout) as ExecuteMethodResult);\n return;\n } catch {\n log.warn('executor Invalid JSON from stdout', { stdout: stdout.slice(0, 200) });\n }\n }\n\n // Process exited without writing valid JSON to stdout\n const errorMessage =\n stderr ||\n stdout ||\n `Method process exited with code ${code ?? 'unknown'}`;\n\n resolve({\n success: false,\n error: { message: errorMessage },\n });\n });\n\n child.on('error', (err) => {\n clearTimeout(timeout);\n log.error('executor Process error', { error: err.message });\n reject(err);\n });\n });\n } finally {\n // Clean up temp file\n await unlink(tempFile).catch(() => {});\n }\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 } from './executor';\nimport { getApiBaseUrl } from '../config';\nimport { requestDeviceAuth, pollDeviceAuth } from '../api';\nimport { setApiKey, setUserId } from '../config';\nimport { log } from './logger';\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('runner Starting session', { 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('runner 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('runner Stopping session');\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('runner Failed to stop session cleanly', { error: err instanceof Error ? err.message : String(err) });\n }\n this.session = null;\n }\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('runner Impersonating', { 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('runner Clearing impersonation');\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('runner Failed to refresh client context', { error: err instanceof Error ? err.message : String(err) });\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('runner Running scenario', { id: scenario.id, name: scenarioName });\n\n try {\n // 1. Truncate all tables (clean slate)\n log.debug('runner Truncating 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.debug('runner 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 log.debug('runner Fetching callback token for scenario');\n const authorizationToken = await fetchCallbackToken(this.appId, this.session.sessionId);\n\n log.debug('runner Executing scenario seed', { 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('runner Scenario seed failed', { id: scenario.id, error });\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.debug('runner Impersonating 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('runner Scenario complete', { id: scenario.id, duration, roles: scenario.roles });\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('runner Scenario failed', { id: scenario.id, error });\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('runner Connection 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('runner Session expired (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('runner Auth token expired (401), attempting refresh');\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('runner Auth refresh failed, stopping');\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('runner Connection lost, retrying...');\n devRequestEvents.emitConnectionWarning(\n 'Lost connection to platform, retrying...',\n );\n }\n\n log.debug('runner 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('runner Request received', { requestId: request.requestId, method: request.methodExport });\n\n try {\n // Transpile\n log.debug('runner Transpiling', { 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 log.info('runner Request complete', { requestId: request.requestId, success: result.success, duration });\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('runner Request failed', { requestId: request.requestId, 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('runner Failed to submit error result', { error: submitErr instanceof Error ? submitErr.message : String(submitErr) });\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('runner Auth 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('runner Could not open browser for auth — user must visit URL manually');\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('runner Auth refreshed successfully');\n devRequestEvents.emitAuthRefreshSuccess();\n return true;\n }\n\n if (result.status === 'expired') {\n break;\n }\n }\n\n log.error('runner Auth refresh timed out or was denied');\n devRequestEvents.emitAuthRefreshFailed();\n return false;\n } catch (err) {\n log.error('runner Auth refresh 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 for the TUI.\n * Includes extra fields like code, statusCode, cause, etc. when present.\n */\nfunction formatErrorForDisplay(error: Record<string, unknown>): 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","// 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//\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 type { Socket } from 'node:net';\nimport { log } from './logger';\n\nexport class DevProxy {\n private server: http.Server | null = null;\n private proxyPort: number | null = null;\n\n constructor(\n private readonly upstreamPort: number,\n private clientContext: Record<string, unknown>,\n private readonly bindAddress: string = '127.0.0.1',\n ) {}\n\n updateClientContext(context: Record<string, unknown>): void {\n this.clientContext = context;\n log.info('proxy Client context updated');\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 log.info('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 if (this.server) {\n log.info('proxy Stopping');\n this.server.close();\n this.server = null;\n this.proxyPort = null;\n }\n }\n\n getPort(): number | null {\n return this.proxyPort;\n }\n\n private handleRequest(\n clientReq: http.IncomingMessage,\n clientRes: http.ServerResponse,\n ): void {\n const origin = clientReq.headers.origin;\n\n // CORS preflight for Private Network Access (PNA). Chrome blocks\n // public origins (like app.mindstudio.ai) from accessing localhost\n // unless the server explicitly opts in via these headers.\n if (clientReq.method === 'OPTIONS' && origin) {\n clientRes.writeHead(204, {\n 'Access-Control-Allow-Origin': origin,\n 'Access-Control-Allow-Private-Network': 'true',\n 'Access-Control-Allow-Methods': 'GET, OPTIONS',\n 'Access-Control-Allow-Headers': '*',\n });\n clientRes.end();\n return;\n }\n\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, (upstreamRes) => {\n const contentType = upstreamRes.headers['content-type'] ?? '';\n const isHtml = contentType.startsWith('text/html');\n\n if (isHtml) {\n // Buffer HTML response, inject context, then send\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 = injectClientContext(html, this.clientContext);\n\n // Copy headers but update content-length and disable caching\n const headers = { ...upstreamRes.headers };\n headers['content-length'] = String(Buffer.byteLength(html, 'utf-8'));\n headers['cache-control'] = 'no-store, no-cache, must-revalidate';\n delete headers['content-encoding']; // buffering + injection invalidates gzip/br\n delete headers['etag'];\n if (origin) {\n headers['access-control-allow-origin'] = origin;\n headers['access-control-allow-private-network'] = 'true';\n }\n\n log.debug('proxy HTML injected', { path: clientReq.url, size: html.length });\n clientRes.writeHead(upstreamRes.statusCode ?? 200, headers);\n clientRes.end(html);\n });\n } else {\n // Non-HTML: pipe through, disable caching\n const headers = { ...upstreamRes.headers };\n headers['cache-control'] = 'no-store, no-cache, must-revalidate';\n delete headers['etag'];\n if (origin) {\n headers['access-control-allow-origin'] = origin;\n headers['access-control-allow-private-network'] = 'true';\n }\n clientRes.writeHead(upstreamRes.statusCode ?? 200, headers);\n upstreamRes.pipe(clientRes);\n }\n });\n\n upstreamReq.on('error', (err) => {\n log.warn('proxy Upstream error', { path: clientReq.url, error: err.message });\n clientRes.writeHead(502);\n clientRes.end(`Proxy error: ${err.message}`);\n });\n\n // Forward request body\n clientReq.pipe(upstreamReq);\n }\n\n private handleUpgrade(\n clientReq: http.IncomingMessage,\n clientSocket: Socket,\n head: Buffer,\n ): void {\n log.debug('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\n/**\n * Inject window.__MINDSTUDIO__ context into an HTML string.\n * Same logic as the platform's injectSessionContext.\n */\nfunction injectClientContext(\n html: string,\n context: Record<string, unknown>,\n): string {\n const script = `<script>window.__MINDSTUDIO__=${JSON.stringify(context)};</script>`;\n if (html.includes('</head>')) {\n return html.replace('</head>', `${script}\\n</head>`);\n }\n return script + '\\n' + html;\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 { execSync } from 'node:child_process';\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('config 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.debug('config Detected 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('config 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 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 {\n // Skip unreadable files\n }\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// Watches directories (not individual files) so newly created table files\n// are detected — important when an AI agent defines tables in mindstudio.json\n// before writing the actual source files.\n//\n// Directories are deduplicated: if all tables live in src/tables/, only one\n// watcher is created. Events are filtered by expected filenames.\n\nimport { watch } from 'node:fs';\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 // Build a map of directory → set of expected filenames\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 let syncTimer: ReturnType<typeof setTimeout> | undefined;\n const cleanups: Array<() => void> = [];\n\n cleanups.push(() => clearTimeout(syncTimer));\n\n for (const [dir, expectedFiles] of dirToFiles) {\n try {\n const w = watch(dir, (_eventType, filename) => {\n if (filename && !expectedFiles.has(filename)) return;\n clearTimeout(syncTimer);\n syncTimer = setTimeout(onChanged, 500);\n });\n cleanups.push(() => w.close());\n } catch {\n // Directory doesn't exist yet, skip\n }\n }\n\n log.info('table-watcher Watching directories', {\n dirs: dirToFiles.size,\n tables: tables.length,\n });\n\n return () => {\n for (const cleanup of cleanups) cleanup();\n };\n}\n"],"mappings":"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","names":["unlink","join","join","resolve","unlink","getHeaders","resolve","resolve","existsSync","join","dirname","join","existsSync","config","dirname","join","dirname","basename","join","dirname","basename"]}
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/headless.ts"],"sourcesContent":["/**\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 * ## JSON Event Protocol\n *\n * Every line written to stdout is a JSON object with an `event` field:\n *\n * | Event | When | Key Fields |\n * |------------------------|-----------------------------------------|-----------------------------------------------|\n * | `session-starting` | Session initializing | `appId`, `name` |\n * | `session-started` | Platform session active, proxy running | `sessionId`, `branch`, `proxyPort`, `proxyUrl`|\n * | `session-stopping` | Graceful shutdown initiated | |\n * | `session-stopped` | All resources cleaned up | |\n * | `session-expired` | Platform expired the dev session | |\n * | `method-started` | Method execution request received | `id`, `method` |\n * | `method-completed` | Method execution finished | `id`, `success`, `duration`, `error?` |\n * | `scenario-started` | Scenario execution started | `id`, `name` |\n * | `scenario-completed` | Scenario execution finished | `id`, `success`, `duration`, `roles`, `error?`|\n * | `schema-sync-started` | Table file changed, syncing schema | |\n * | `schema-sync-completed`| Schema synced to platform | `created`, `altered`, `errors` |\n * | `impersonation-changed`| Role override set or cleared | `roles` |\n * | `connection-lost` | Lost connection, retrying with backoff | `message` |\n * | `connection-restored` | Reconnected after connection loss | |\n * | `config-changed` | mindstudio.json changed, restarting | |\n * | `config-error` | Config invalid (non-fatal) | `message` |\n * | `command-error` | Stdin command failed (non-fatal) | `message` |\n * | `error` | Fatal startup error | `message` |\n *\n * ## Usage\n *\n * CLI:\n * ```bash\n * mindstudio-local --headless --port 5173 --bind 0.0.0.0\n * ```\n *\n * Programmatic:\n * ```typescript\n * import { startHeadless } from '@mindstudio-ai/local-model-tunnel';\n *\n * await startHeadless({\n * cwd: '/path/to/project',\n * devPort: 5173,\n * bindAddress: '0.0.0.0',\n * });\n * ```\n *\n * @module\n */\n\nimport { DevRunner } from './dev/runner';\nimport { DevProxy } from './dev/proxy';\nimport { devRequestEvents } from './dev/events';\nimport { syncSchema } from './dev/api';\nimport {\n detectAppConfig,\n getWebInterfaceConfig,\n readTableSources,\n} from './dev/app-config';\nimport type { AppConfig } from './dev/types';\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 { watch, type FSWatcher } from 'node:fs';\nimport { join } from 'node:path';\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}\n\n/** Mutable state shared across the session lifecycle, stdin commands, and file watcher. */\ninterface SessionState {\n runner: DevRunner | null;\n proxy: DevProxy | null;\n appConfig: AppConfig | null;\n proxyPort: number | null;\n unsubscribers: Array<() => void>;\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 * Start a dev session: read config, start runner, sync schema, start proxy,\n * subscribe to events. Returns true on success, false on config/startup error\n * (non-fatal — caller can retry on next config change).\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', {\n message: 'No valid mindstudio.json found in ' + cwd,\n });\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) => ({\n id: m.id,\n export: m.export,\n path: m.path,\n })),\n });\n const session = await runner.start();\n state.runner = runner;\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(\n appConfig.appId,\n session.sessionId,\n tableSources,\n );\n session.databases = syncResult.databases;\n emit('schema-sync-completed', {\n created: syncResult.created,\n altered: syncResult.altered,\n errors: syncResult.errors,\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 — sits in front of the dev server, injects __MINDSTUDIO__.\n // Only started if we have a dev server port and the platform returned clientContext.\n // In headless mode we don't start the dev server (caller manages it), but we\n // do start the proxy so the preview URL works.\n let proxyPort: number | null = null;\n if (devPort !== null && session.clientContext) {\n const proxy = new DevProxy(devPort, session.clientContext, bindAddress);\n const preferred = opts.proxyPort ?? stablePort(appConfig.appId);\n proxyPort = await proxy.start(preferred);\n runner.setProxyUrl(\n `http://${bindAddress === '0.0.0.0' ? 'localhost' : bindAddress}:${proxyPort}`,\n );\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) => ({\n id: r.id,\n name: r.name ?? r.id,\n description: r.description,\n })),\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 events and relay as JSON.\n // Store unsubscribe functions so we can clean up on restart.\n const unsubs = state.unsubscribers;\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 // 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\n/** Set up table file watchers that auto-sync schema on change. */\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('headless Table file changed, syncing schema');\n\n try {\n const tableSources = readTableSources(state.appConfig, cwd);\n if (tableSources.length > 0) {\n const result = await syncSchema(\n state.appConfig.appId,\n session.sessionId,\n tableSources,\n );\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('headless Schema synced', {\n created: result.created,\n altered: result.altered,\n });\n }\n } catch (err) {\n const message = err instanceof Error ? err.message : 'Schema sync failed';\n emit('command-error', { message });\n log.warn('headless Schema sync failed', { error: message });\n }\n });\n\n state.unsubscribers.push(cleanup);\n}\n\n/** Tear down the current session: unsubscribe events, stop proxy, stop runner. */\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\n/**\n * Start the dev tunnel in headless mode.\n *\n * Reads mindstudio.json, starts a platform session, syncs schema,\n * starts the local proxy, and enters the poll loop. Outputs JSON\n * events to stdout. Does not return until shutdown (SIGTERM/SIGINT).\n *\n * Watches mindstudio.json for changes and automatically restarts the\n * session when the config is updated (same behavior as the TUI).\n *\n * Does NOT start a dev server — the caller is responsible for that.\n *\n * @param opts - Configuration options\n *\n * @example\n * ```typescript\n * // From a C&C server — spawn and read events\n * import { startHeadless } from '@mindstudio-ai/local-model-tunnel';\n *\n * await startHeadless({\n * cwd: '/workspace/my-app',\n * devPort: 5173,\n * bindAddress: '0.0.0.0',\n * });\n * ```\n */\nexport async function startHeadless(opts: HeadlessOptions = {}): Promise<void> {\n initLoggerHeadless(opts.logLevel ?? 'info');\n\n const cwd = opts.cwd ?? process.cwd();\n\n // Log auth config so sandbox operators can diagnose issues\n const apiKey = getApiKey();\n const userId = getUserId();\n log.info('headless Auth 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 // File watcher state\n let restartTimer: ReturnType<typeof setTimeout> | undefined;\n let restarting = false;\n let watcher: FSWatcher | undefined;\n\n // Graceful shutdown\n let stopping = false;\n const shutdown = async () => {\n if (stopping) return;\n stopping = true;\n emit('session-stopping');\n clearTimeout(restartTimer);\n watcher?.close();\n await teardownSession(state);\n emit('session-stopped');\n };\n\n process.on('SIGTERM', () => {\n shutdown().then(() => process.exit(0));\n });\n process.on('SIGINT', () => {\n shutdown().then(() => process.exit(0));\n });\n\n // Initial session start\n const ok = await startSession(cwd, opts, state, shutdown);\n if (!ok && !state.appConfig) {\n // No valid config at all on first try — emit fatal error.\n // The watcher below will still start if the file exists, so the\n // process stays alive to retry on config fix.\n emit('error', { message: 'No valid mindstudio.json found in ' + cwd });\n }\n\n // Stdin command loop — reads from state so it always sees current runner/config\n setupStdinCommands(state, cwd);\n\n // Watch mindstudio.json for changes — restart session on edit (500ms debounce)\n try {\n const configPath = join(cwd, 'mindstudio.json');\n watcher = watch(configPath, () => {\n clearTimeout(restartTimer);\n restartTimer = setTimeout(async () => {\n if (stopping || restarting) return;\n restarting = true;\n try {\n log.info('headless Config changed, restarting session');\n emit('config-changed');\n await teardownSession(state);\n await startSession(cwd, opts, state, shutdown);\n } finally {\n restarting = false;\n }\n }, 500);\n });\n } catch {\n // File might not exist yet or watch not supported\n }\n\n // Keep the process alive — the poll loop runs in DevRunner\n await new Promise<void>(() => {});\n}\n\n/**\n * Read NDJSON commands from stdin and dispatch them.\n * Uses the shared state object so commands always reference the current session.\n */\nfunction setupStdinCommands(state: SessionState, cwd: string): 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 {\n action: string;\n [key: string]: unknown;\n };\n handleStdinCommand(cmd, state, cwd);\n } catch {\n emit('command-error', {\n message: `Invalid JSON on stdin: ${line.slice(0, 100)}`,\n });\n }\n }\n });\n}\n\nasync function handleStdinCommand(\n cmd: { action: string; [key: string]: unknown },\n state: SessionState,\n cwd: string,\n): Promise<void> {\n switch (cmd.action) {\n case 'run-scenario': {\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(\n (s) => s.id === cmd.scenarioId,\n );\n if (!scenario) {\n emit('command-error', {\n message: `Unknown scenario: ${cmd.scenarioId}`,\n });\n return;\n }\n // Runner emits scenario-start/complete events which are already relayed\n await state.runner.runScenario(scenario);\n break;\n }\n\n case 'impersonate': {\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 break;\n }\n\n case 'clear-impersonation': {\n if (!state.runner) {\n emit('command-error', { message: 'No active session' });\n return;\n }\n await state.runner.clearImpersonation();\n break;\n }\n\n default:\n emit('command-error', { message: `Unknown action: ${cmd.action}` });\n }\n}\n"],"mappings":"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","names":[]}
|
|
File without changes
|