@camstack/kernel 0.1.6 → 0.1.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.
@@ -1 +1 @@
1
- {"version":3,"sources":["../../src/worker/worker-process-manager.ts","../../src/fs-utils.ts","../../src/addon-installer.ts","../../src/worker/addon-worker-entry.ts"],"sourcesContent":["import { spawn, type ChildProcess } from 'node:child_process'\nimport type {\n WorkerToMainMessage,\n WorkerProcessStats,\n SubProcessInfo,\n} from '@camstack/types'\nimport type {\n IAddonProcessManager,\n SubProcessConfig,\n IManagedSubProcess,\n} from '@camstack/types'\n\nexport class WorkerProcessManager implements IAddonProcessManager {\n private readonly processes = new Map<number, ManagedProcess>()\n\n constructor(\n private readonly sendToMain: (msg: WorkerToMainMessage) => void,\n ) {}\n\n async spawn(config: SubProcessConfig): Promise<IManagedSubProcess> {\n const child = spawn(config.command, [...(config.args ?? [])], {\n cwd: config.cwd,\n env: config.env ? { ...process.env, ...config.env } : undefined,\n stdio: ['pipe', 'pipe', 'pipe'],\n })\n\n const managed = new ManagedProcess(child, config, this.sendToMain)\n this.processes.set(child.pid!, managed)\n\n this.sendToMain({\n type: 'SUB_PROCESS_SPAWNED',\n pid: child.pid!,\n name: config.name,\n command: config.command,\n })\n\n child.on('exit', (code) => {\n this.sendToMain({\n type: 'SUB_PROCESS_EXITED',\n pid: child.pid!,\n code,\n })\n\n if (config.autoRestart && managed.restartCount < (config.maxRestarts ?? 3)) {\n managed.restartCount++\n setTimeout(() => {\n this.spawn(config).catch(() => {})\n }, 2000)\n }\n })\n\n return managed\n }\n\n listProcesses(): readonly SubProcessInfo[] {\n return [...this.processes.values()].map((p) => p.toInfo())\n }\n\n getWorkerStats(): WorkerProcessStats {\n const mem = process.memoryUsage()\n const cpu = process.cpuUsage()\n return {\n pid: process.pid,\n cpuPercent: (cpu.user + cpu.system) / 1_000_000,\n memoryRss: mem.rss,\n heapUsed: mem.heapUsed,\n uptimeSeconds: Math.round(process.uptime()),\n restartCount: 0,\n state: 'running',\n }\n }\n\n async killAll(): Promise<void> {\n for (const [, proc] of this.processes) {\n proc.kill('SIGTERM')\n }\n this.processes.clear()\n }\n}\n\nclass ManagedProcess implements IManagedSubProcess {\n readonly pid: number\n readonly name: string\n restartCount = 0\n private readonly startedAt = Date.now()\n private exitHandlers: Array<(code: number | null) => void> = []\n private errorHandlers: Array<(error: Error) => void> = []\n\n constructor(\n private readonly child: ChildProcess,\n private readonly config: SubProcessConfig,\n private readonly sendToMain: (msg: WorkerToMainMessage) => void,\n ) {\n this.pid = child.pid!\n this.name = config.name\n\n child.on('exit', (code) => {\n for (const handler of this.exitHandlers) handler(code)\n })\n\n child.on('error', (err) => {\n for (const handler of this.errorHandlers) handler(err)\n })\n }\n\n getStats(): WorkerProcessStats {\n return {\n pid: this.pid,\n cpuPercent: 0,\n memoryRss: 0,\n uptimeSeconds: Math.round((Date.now() - this.startedAt) / 1000),\n restartCount: this.restartCount,\n state: this.child.exitCode !== null ? 'stopped' : 'running',\n }\n }\n\n write(data: Buffer): void {\n this.child.stdin?.write(data)\n }\n\n get stdout(): AsyncIterable<Buffer> {\n return this.child.stdout as AsyncIterable<Buffer>\n }\n\n get stderr(): AsyncIterable<Buffer> {\n return this.child.stderr as AsyncIterable<Buffer>\n }\n\n kill(signal: NodeJS.Signals = 'SIGTERM'): void {\n this.child.kill(signal)\n }\n\n wait(): Promise<{ code: number | null; signal: string | null }> {\n if (this.child.exitCode !== null) {\n return Promise.resolve({ code: this.child.exitCode, signal: null })\n }\n return new Promise((resolve) => {\n this.child.on('exit', (code, signal) => {\n resolve({ code, signal })\n })\n })\n }\n\n onExit(handler: (code: number | null) => void): void {\n this.exitHandlers.push(handler)\n }\n\n onError(handler: (error: Error) => void): void {\n this.errorHandlers.push(handler)\n }\n\n toInfo(): SubProcessInfo {\n return {\n pid: this.pid,\n name: this.name,\n command: this.config.command,\n state: this.child.exitCode !== null ? 'stopped' : 'running',\n cpuPercent: 0,\n memoryRss: 0,\n uptimeSeconds: Math.round((Date.now() - this.startedAt) / 1000),\n }\n }\n}\n","import { execFileSync } from 'node:child_process'\nimport * as fs from 'node:fs'\nimport * as path from 'node:path'\n\n/**\n * Ensure a directory exists (recursive).\n * Single source of truth — replaces scattered mkdirSync calls.\n */\nexport function ensureDir(dirPath: string): void {\n fs.mkdirSync(dirPath, { recursive: true })\n}\n\n/**\n * Copy a directory recursively.\n * Single source of truth — extracted from addon-installer + first-boot-installer.\n */\nexport function copyDirRecursive(src: string, dest: string): void {\n ensureDir(dest)\n const entries = fs.readdirSync(src, { withFileTypes: true })\n for (const entry of entries) {\n const srcPath = path.join(src, entry.name)\n const destPath = path.join(dest, entry.name)\n if (entry.isDirectory()) {\n copyDirRecursive(srcPath, destPath)\n } else {\n fs.copyFileSync(srcPath, destPath)\n }\n }\n}\n\n/**\n * Strip @camstack/* dependencies and devDependencies from a package.json object.\n * Used when installing addons into the addons directory — @camstack packages\n * are provided by the host runtime, not installed per-addon.\n *\n * Returns a new object (immutable).\n */\nexport function stripCamstackDeps(\n pkg: Record<string, unknown>,\n): Record<string, unknown> {\n const result = { ...pkg }\n\n for (const depType of ['dependencies', 'peerDependencies', 'devDependencies']) {\n const deps = result[depType] as Record<string, string> | undefined\n if (deps) {\n const filtered: Record<string, string> = {}\n for (const [name, version] of Object.entries(deps)) {\n if (!name.startsWith('@camstack/')) {\n filtered[name] = version\n }\n }\n result[depType] = Object.keys(filtered).length > 0 ? filtered : undefined\n }\n }\n\n // Always strip devDependencies — addons don't need them at runtime\n delete result.devDependencies\n\n return result\n}\n\n/**\n * Copy extra file directories declared in package.json \"files\" field.\n * Copies directories (not individual files) from source to destination.\n * Skips \"dist\" (already handled) and glob patterns.\n */\nexport function copyExtraFileDirs(\n pkgJson: Record<string, unknown>,\n sourceDir: string,\n destDir: string,\n): void {\n const files = pkgJson.files as string[] | undefined\n if (!files) return\n\n for (const fileEntry of files) {\n if (fileEntry === 'dist' || fileEntry.includes('*')) continue\n const srcPath = path.join(sourceDir, fileEntry)\n if (!fs.existsSync(srcPath)) continue\n\n const destPath = path.join(destDir, fileEntry)\n const stat = fs.statSync(srcPath)\n if (stat.isDirectory()) {\n copyDirRecursive(srcPath, destPath)\n } else if (stat.isFile()) {\n ensureDir(path.dirname(destPath))\n fs.copyFileSync(srcPath, destPath)\n }\n }\n}\n\n/**\n * Create symlinks in node_modules so that static `import from '@camstack/core'` works.\n * Links: node_modules/@camstack/{pkg} -> data/addons/{pkg}/\n * (not just dist -- need package.json for Node's exports resolution)\n */\nexport function symlinkAddonsToNodeModules(addonsDir: string, nodeModulesDir: string): void {\n const camstackDir = path.join(nodeModulesDir, '@camstack')\n ensureDir(camstackDir)\n\n // Link each addon that's in data/addons/ and also imported by the server\n const packagesToLink = ['core']\n\n for (const pkg of packagesToLink) {\n const addonDir = path.join(addonsDir, '@camstack', pkg)\n const linkPath = path.join(camstackDir, pkg)\n\n if (!fs.existsSync(addonDir)) continue\n\n // Remove existing link/directory\n try {\n const stat = fs.lstatSync(linkPath)\n if (stat.isSymbolicLink() || stat.isDirectory()) {\n fs.rmSync(linkPath, { recursive: true, force: true })\n }\n } catch {\n // Doesn't exist yet -- nothing to remove\n }\n\n fs.symlinkSync(addonDir, linkPath, 'dir')\n console.log(`[symlink] node_modules/@camstack/${pkg} -> ${addonDir}`)\n }\n}\n\n/**\n * Check if any file in src/ is newer than dist/.\n * Returns true if rebuild is needed.\n */\nexport function isSourceNewer(packageDir: string): boolean {\n const srcDir = path.join(packageDir, 'src')\n const distDir = path.join(packageDir, 'dist')\n if (!fs.existsSync(srcDir) || !fs.existsSync(distDir)) return true\n try {\n const distMtime = fs.statSync(distDir).mtimeMs\n const entries = fs.readdirSync(srcDir, { withFileTypes: true, recursive: true })\n for (const entry of entries) {\n if (!entry.isFile()) continue\n const filePath = path.join(entry.parentPath ?? (entry as any).path, entry.name)\n if (fs.statSync(filePath).mtimeMs > distMtime) return true\n }\n return false\n } catch {\n return true\n }\n}\n\n/**\n * Ensure a library dependency (not an addon) has a dist/ directory.\n * Does NOT rebuild — in dev mode, `npm run build` should be run separately.\n * Only checks that dist/ exists and has an index file.\n */\nexport function ensureLibraryBuilt(packageName: string, packagesDir: string): void {\n const dirName = packageName.replace('@camstack/', '')\n const sourceDir = path.join(packagesDir, dirName)\n if (!fs.existsSync(sourceDir)) return\n\n const distDir = path.join(sourceDir, 'dist')\n const hasIndex = fs.existsSync(path.join(distDir, 'index.js')) || fs.existsSync(path.join(distDir, 'index.mjs'))\n if (hasIndex) return\n\n console.warn(`[ensureLibraryBuilt] ${packageName} has no dist/ — run 'npm run build' first`)\n}\n\n/**\n * Install a single npm package into a target directory (package.json + dist/).\n * No validation on camstack.addons -- works for any @camstack/* package.\n * Uses synchronous child_process calls (suitable for first-boot and update paths).\n */\nexport function installPackageFromNpmSync(packageName: string, targetDir: string): void {\n const os = require('node:os') as typeof import('node:os')\n const tmpDir = fs.mkdtempSync(path.join(os.tmpdir(), 'camstack-install-'))\n\n try {\n // npm pack downloads the tgz without installing\n const stdout = execFileSync('npm', ['pack', packageName, '--pack-destination', tmpDir], {\n timeout: 120_000,\n encoding: 'utf-8',\n })\n\n const tgzFilename = stdout.trim().split('\\n').pop()?.trim()\n if (!tgzFilename) throw new Error('npm pack produced no output')\n\n const tgzPath = path.join(tmpDir, tgzFilename)\n\n // Extract tgz\n const extractDir = path.join(tmpDir, 'extracted')\n ensureDir(extractDir)\n execFileSync('tar', ['-xzf', tgzPath, '-C', extractDir], { timeout: 30_000 })\n\n // npm pack creates a package/ subdirectory\n const packageSubDir = path.join(extractDir, 'package')\n const srcPkgJsonDir = fs.existsSync(path.join(packageSubDir, 'package.json'))\n ? packageSubDir\n : extractDir\n\n // Copy package.json + dist/ to target\n fs.rmSync(targetDir, { recursive: true, force: true })\n ensureDir(targetDir)\n fs.copyFileSync(path.join(srcPkgJsonDir, 'package.json'), path.join(targetDir, 'package.json'))\n\n const distSrc = path.join(srcPkgJsonDir, 'dist')\n if (fs.existsSync(distSrc)) {\n copyDirRecursive(distSrc, path.join(targetDir, 'dist'))\n }\n\n // Copy extra directories from \"files\" in package.json (e.g., python/)\n try {\n const npmPkg = JSON.parse(fs.readFileSync(path.join(srcPkgJsonDir, 'package.json'), 'utf-8'))\n copyExtraFileDirs(npmPkg, srcPkgJsonDir, targetDir)\n } catch { /* non-critical */ }\n } finally {\n fs.rmSync(tmpDir, { recursive: true, force: true })\n }\n}\n","import { execFile } from 'node:child_process'\nimport { promisify } from 'node:util'\nimport * as fs from 'node:fs'\nimport * as path from 'node:path'\nimport * as os from 'node:os'\nimport { copyDirRecursive, copyExtraFileDirs, ensureDir, ensureLibraryBuilt, isSourceNewer, stripCamstackDeps } from './fs-utils.js'\n\nconst execFileAsync = promisify(execFile)\n\nexport interface AddonInstallerConfig {\n /** Directory where addons are stored (e.g., {dataDir}/addons) — each addon is a subdirectory */\n readonly addonsDir: string\n /** npm registry URL (default: https://registry.npmjs.org) */\n readonly registry?: string\n /** Workspace packages directory (e.g., /path/to/camstack-server/packages) — for dev installs */\n readonly workspacePackagesDir?: string\n}\n\nimport type { InstalledPackage } from '@camstack/types'\nexport type { InstalledPackage }\n\nexport class AddonInstaller {\n private readonly addonsDir: string\n private readonly registry: string | undefined\n private readonly workspacePackagesDir: string | undefined\n\n constructor(config: AddonInstallerConfig) {\n this.addonsDir = config.addonsDir\n this.registry = config.registry\n this.workspacePackagesDir = config.workspacePackagesDir\n }\n\n /** Required addon packages that must be installed for the server to function */\n static readonly REQUIRED_PACKAGES = [\n '@camstack/core',\n '@camstack/addon-pipeline',\n '@camstack/addon-vision',\n '@camstack/addon-admin-ui',\n '@camstack/addon-webrtc-adaptive',\n '@camstack/addon-pipeline-analysis',\n '@camstack/addon-scene-intelligence',\n '@camstack/addon-advanced-notifier',\n ] as const\n\n /** Ensure the addons directory exists */\n async initialize(): Promise<void> {\n ensureDir(this.addonsDir)\n }\n\n /**\n * Ensure all required packages are installed in the addons directory.\n * This replaces the standalone first-boot-installer.ts.\n */\n async ensureRequiredPackages(): Promise<void> {\n ensureDir(this.addonsDir)\n\n // In workspace mode, ensure library dependencies are built first\n if (this.workspacePackagesDir) {\n console.log(`[AddonInstaller] Workspace detected: ${this.workspacePackagesDir}`)\n ensureLibraryBuilt('@camstack/kernel', this.workspacePackagesDir)\n ensureLibraryBuilt('@camstack/types', this.workspacePackagesDir)\n }\n\n for (const packageName of AddonInstaller.REQUIRED_PACKAGES) {\n const addonDir = path.join(this.addonsDir, packageName)\n const pkgJsonPath = path.join(addonDir, 'package.json')\n\n // CAMSTACK_INSTALL_SOURCE=npm forces npm install even in workspace mode\n const forceNpm = process.env['CAMSTACK_INSTALL_SOURCE'] === 'npm'\n const useWorkspace = this.workspacePackagesDir && !forceNpm\n\n // Skip if already installed and up-to-date\n if (fs.existsSync(pkgJsonPath)) {\n if (!useWorkspace) {\n // Production or npm-forced: installed = done\n console.log(`[AddonInstaller] ${packageName} — already installed (npm), skipping`)\n continue\n }\n // Workspace: skip if source dist/ isn't newer than target\n const srcPkgDir = this.findWorkspacePackage(packageName)\n if (srcPkgDir && !isSourceNewer(srcPkgDir)) {\n console.log(`[AddonInstaller] ${packageName} — workspace up-to-date, skipping`)\n continue\n }\n }\n\n try {\n // Try workspace install first (dev mode), fall back to npm\n if (useWorkspace) {\n const pkgDir = this.findWorkspacePackage(packageName)\n if (pkgDir) {\n console.log(`[AddonInstaller] ${packageName} — installing from workspace`)\n await this.installFromWorkspace(packageName)\n continue\n }\n }\n\n console.log(`[AddonInstaller] ${packageName} — installing from npm`)\n await this.installFromNpm(packageName)\n } catch (err) {\n const msg = err instanceof Error ? err.message : String(err)\n // Core is essential — abort if it fails\n if (packageName === '@camstack/core') {\n throw new Error(`Required package ${packageName} failed to install: ${msg}`)\n }\n console.error(`[AddonInstaller] Failed to install ${packageName}: ${msg}`)\n }\n }\n }\n\n private findWorkspacePackage(packageName: string): string | null {\n if (!this.workspacePackagesDir) return null\n const shortName = packageName.replace('@camstack/', '')\n // Check common naming patterns\n for (const dirName of [shortName, `addon-${shortName}`, shortName.replace('addon-', '')]) {\n const candidate = path.join(this.workspacePackagesDir, dirName)\n if (fs.existsSync(path.join(candidate, 'package.json'))) {\n try {\n const pkg = JSON.parse(fs.readFileSync(path.join(candidate, 'package.json'), 'utf-8'))\n if (pkg.name === packageName) return candidate\n } catch { /* ignore */ }\n }\n }\n return null\n }\n\n /** Install addon from a tgz file (uploaded or downloaded) */\n async installFromTgz(tgzPath: string): Promise<{ name: string; version: string }> {\n // 1. Extract tgz to temp dir\n const tmpDir = fs.mkdtempSync(path.join(os.tmpdir(), 'camstack-addon-install-'))\n\n try {\n await execFileAsync('tar', ['-xzf', tgzPath, '-C', tmpDir], { timeout: 30_000 })\n\n // npm pack creates a package/ directory inside the tgz\n const extractedDir = path.join(tmpDir, 'package')\n const pkgJsonPath = fs.existsSync(path.join(extractedDir, 'package.json'))\n ? path.join(extractedDir, 'package.json')\n : path.join(tmpDir, 'package.json')\n\n if (!fs.existsSync(pkgJsonPath)) {\n throw new Error('No package.json found in tgz archive')\n }\n\n const pkgJson = JSON.parse(fs.readFileSync(pkgJsonPath, 'utf-8')) as {\n name: string\n version: string\n files?: string[]\n camstack?: { addons?: unknown[] }\n }\n\n if (!pkgJson.camstack?.addons) {\n throw new Error(`Package ${pkgJson.name} has no camstack.addons manifest`)\n }\n\n // 2. Determine target directory name (strip scope)\n const targetDir = path.join(this.addonsDir, pkgJson.name)\n\n // 3. Remove old version if present\n fs.rmSync(targetDir, { recursive: true, force: true })\n ensureDir(targetDir)\n\n // 4. Copy package.json\n const sourceDir = path.dirname(pkgJsonPath)\n fs.copyFileSync(pkgJsonPath, path.join(targetDir, 'package.json'))\n\n // 5. Copy dist/ directory\n const sourceDist = path.join(sourceDir, 'dist')\n if (fs.existsSync(sourceDist)) {\n copyDirRecursive(sourceDist, path.join(targetDir, 'dist'))\n }\n\n // 6. Copy extra directories from \"files\" in package.json (e.g., python/, reference-images/)\n copyExtraFileDirs(pkgJson, sourceDir, targetDir)\n\n return { name: pkgJson.name, version: pkgJson.version }\n } finally {\n fs.rmSync(tmpDir, { recursive: true, force: true })\n }\n }\n\n /**\n * Install addon — prefers workspace if available, falls back to npm.\n * This ensures dev builds (with vite output, etc.) are used when in workspace mode.\n */\n async install(packageName: string, version?: string): Promise<{ name: string; version: string }> {\n if (this.workspacePackagesDir) {\n // Workspace dirs use short names (e.g., packages/addon-benchmark)\n const workspaceDirName = packageName.replace('@camstack/', '')\n const sourceDir = path.join(this.workspacePackagesDir, workspaceDirName)\n if (fs.existsSync(path.join(sourceDir, 'package.json'))) {\n return this.installFromWorkspace(packageName)\n }\n }\n return this.installFromNpm(packageName, version)\n }\n\n /**\n * Install addon from workspace by copying package.json + dist/ to addons dir.\n * Does NOT build — expects dist/ to already exist (run `npm run build` separately).\n */\n async installFromWorkspace(packageName: string): Promise<{ name: string; version: string }> {\n if (!this.workspacePackagesDir) {\n throw new Error('Workspace packages directory not configured')\n }\n\n const workspaceDirName = packageName.replace('@camstack/', '')\n const sourceDir = path.join(this.workspacePackagesDir, workspaceDirName)\n const sourcePkgJson = path.join(sourceDir, 'package.json')\n\n if (!fs.existsSync(sourcePkgJson)) {\n throw new Error(`Workspace package not found: ${sourceDir}`)\n }\n\n const distDir = path.join(sourceDir, 'dist')\n if (!fs.existsSync(distDir)) {\n throw new Error(`${packageName} has no dist/ directory — run 'npm run build' first`)\n }\n\n // Copy package.json + dist/ to target (use full scoped name as dir)\n const targetDir = path.join(this.addonsDir, packageName)\n\n fs.rmSync(targetDir, { recursive: true, force: true })\n ensureDir(targetDir)\n\n // Strip @camstack/* deps from package.json\n const pkgData = JSON.parse(fs.readFileSync(sourcePkgJson, 'utf-8'))\n const strippedPkg = stripCamstackDeps(pkgData)\n fs.writeFileSync(path.join(targetDir, 'package.json'), JSON.stringify(strippedPkg, null, 2))\n\n copyDirRecursive(distDir, path.join(targetDir, 'dist'))\n\n // Copy extra directories from \"files\" in package.json (e.g., python/, reference-images/)\n copyExtraFileDirs(pkgData, sourceDir, targetDir)\n\n // Mark install source for UI display\n fs.writeFileSync(path.join(targetDir, '.install-source'), 'workspace')\n\n // Install production dependencies (non-fatal if fails)\n try {\n await execFileAsync('npm', ['install', '--omit=dev', '--ignore-scripts=false'], {\n cwd: targetDir,\n timeout: 120_000,\n })\n } catch {\n // Non-fatal — addon may not have external deps\n }\n\n return { name: pkgData.name, version: pkgData.version }\n }\n\n /** Install addon from npm (download tgz, then extract) */\n async installFromNpm(packageName: string, version?: string): Promise<{ name: string; version: string }> {\n const tmpDir = fs.mkdtempSync(path.join(os.tmpdir(), 'camstack-addon-npm-'))\n\n const packageSpec = version ? `${packageName}@${version}` : packageName\n const args = ['pack', packageSpec, '--pack-destination', tmpDir]\n if (this.registry) {\n args.push('--registry', this.registry)\n }\n\n console.log(`[AddonInstaller] npm pack ${packageSpec} → ${tmpDir}`)\n\n try {\n const { stdout } = await execFileAsync('npm', args, {\n timeout: 120_000,\n })\n\n const tgzFiles = fs.readdirSync(tmpDir).filter(f => f.endsWith('.tgz'))\n console.log(`[AddonInstaller] npm pack stdout: ${stdout.trim()}, tgzFiles: ${tgzFiles.join(', ')}`)\n if (tgzFiles.length === 0) {\n throw new Error(`npm pack produced no tgz file for ${packageSpec}. stdout: ${stdout.trim()}`)\n }\n\n const tgzPath = path.join(tmpDir, tgzFiles[0]!)\n const result = await this.installFromTgz(tgzPath)\n console.log(`[AddonInstaller] installFromTgz result: ${result.name}@${result.version} → ${path.join(this.addonsDir, result.name)}`)\n\n // Mark as npm install\n const targetDir = path.join(this.addonsDir, result.name)\n fs.writeFileSync(path.join(targetDir, '.install-source'), 'npm')\n\n return result\n } finally {\n // Clean up AFTER installFromTgz has fully completed\n fs.rmSync(tmpDir, { recursive: true, force: true })\n }\n }\n\n /** Uninstall addon (delete directory) */\n async uninstall(packageName: string): Promise<void> {\n // Support both full scoped name and short name\n const addonDir = path.join(this.addonsDir, packageName)\n if (fs.existsSync(addonDir)) {\n fs.rmSync(addonDir, { recursive: true, force: true })\n return\n }\n // Fallback: try without scope (legacy layout)\n const legacyDir = path.join(this.addonsDir, packageName.replace(/^@[^/]+\\//, ''))\n if (fs.existsSync(legacyDir)) {\n fs.rmSync(legacyDir, { recursive: true, force: true })\n }\n }\n\n /** List installed addons (directories with package.json containing camstack.addons) */\n listInstalled(): InstalledPackage[] {\n if (!fs.existsSync(this.addonsDir)) return []\n\n return fs.readdirSync(this.addonsDir, { withFileTypes: true })\n .filter(d => d.isDirectory())\n .map(d => {\n const pkgPath = path.join(this.addonsDir, d.name, 'package.json')\n if (!fs.existsSync(pkgPath)) return null\n try {\n const pkg = JSON.parse(fs.readFileSync(pkgPath, 'utf-8')) as {\n name: string\n version: string\n camstack?: { addons?: unknown[] }\n }\n if (!pkg.camstack?.addons) return null\n const sourceFile = path.join(this.addonsDir, d.name, '.install-source')\n const installSource = fs.existsSync(sourceFile)\n ? fs.readFileSync(sourceFile, 'utf-8').trim() as 'npm' | 'workspace' | 'upload'\n : undefined\n const result: InstalledPackage = { name: pkg.name, version: pkg.version, dir: path.join(this.addonsDir, d.name), ...(installSource ? { installSource } : {}) }\n return result\n } catch {\n return null\n }\n })\n .filter((item): item is InstalledPackage => item !== null)\n }\n\n /** Check if an addon is installed */\n isInstalled(packageName: string): boolean {\n // Check scoped path first, then legacy\n if (fs.existsSync(path.join(this.addonsDir, packageName, 'package.json'))) return true\n const legacy = packageName.replace(/^@[^/]+\\//, '')\n return fs.existsSync(path.join(this.addonsDir, legacy, 'package.json'))\n }\n\n /** Get installed package info */\n getInstalledPackage(packageName: string): InstalledPackage | null {\n let pkgPath = path.join(this.addonsDir, packageName, 'package.json')\n if (!fs.existsSync(pkgPath)) {\n pkgPath = path.join(this.addonsDir, packageName.replace(/^@[^/]+\\//, ''), 'package.json')\n }\n if (!fs.existsSync(pkgPath)) return null\n try {\n const pkg = JSON.parse(fs.readFileSync(pkgPath, 'utf-8')) as { name: string; version: string }\n return { name: pkg.name, version: pkg.version, dir: path.dirname(pkgPath) }\n } catch {\n return null\n }\n }\n}\n\n// copyDirRecursive, copyExtraFileDirs, ensureDir, stripCamstackDeps\n// are now imported from ./fs-utils.js (single source of truth)\n","/**\n * Worker entry point — forked by AddonWorkerHost.\n * Connects to hub via tRPC WSS, loads addon, reports heartbeat.\n *\n * Boot config passed via environment variables:\n * CAMSTACK_WORKER_HUB_URL - WSS URL (e.g., wss://localhost:4443/trpc)\n * CAMSTACK_WORKER_TOKEN - Auth token\n * CAMSTACK_ADDON_ID - Addon to load\n * CAMSTACK_ADDON_DIR - Path to addon directory\n * CAMSTACK_ADDON_CONFIG - JSON-encoded addon config\n * CAMSTACK_DATA_DIR - Data directory for this addon\n * CAMSTACK_LOCATION_PATHS - JSON-encoded location paths\n */\nimport * as os from 'node:os'\nimport * as fs from 'node:fs'\nimport * as path from 'node:path'\nimport type { ICamstackAddon, AddonContext, IScopedLogger } from '@camstack/types'\nimport { WorkerProcessManager } from './worker-process-manager.js'\n\nasync function boot(): Promise<void> {\n const hubUrl = process.env.CAMSTACK_WORKER_HUB_URL\n const token = process.env.CAMSTACK_WORKER_TOKEN ?? ''\n const addonId = process.env.CAMSTACK_ADDON_ID\n const addonDir = process.env.CAMSTACK_ADDON_DIR\n const dataDir = process.env.CAMSTACK_DATA_DIR ?? `/tmp/camstack-worker-${addonId}`\n const addonConfig = JSON.parse(process.env.CAMSTACK_ADDON_CONFIG ?? '{}')\n const locationPaths = JSON.parse(process.env.CAMSTACK_LOCATION_PATHS ?? '{}')\n\n if (!hubUrl || !addonId || !addonDir) {\n console.error('[worker] Missing required env vars: CAMSTACK_WORKER_HUB_URL, CAMSTACK_ADDON_ID, CAMSTACK_ADDON_DIR')\n process.exit(1)\n }\n\n const workerId = `worker-${addonId}-${process.pid}`\n\n // 1. Create tRPC WSS client (must use superjson transformer to match server)\n const { createTRPCClient, createWSClient, wsLink } = await import('@trpc/client')\n const superjson = (await import('superjson')).default\n\n const wsClient = createWSClient({\n url: hubUrl,\n connectionParams: () => ({ token }),\n })\n\n const api = createTRPCClient<any>({\n links: [wsLink({ client: wsClient, transformer: superjson })],\n })\n\n // 2. Register with hub\n try {\n await (api as any).agent.register.mutate({\n id: workerId,\n name: addonId,\n capabilities: [],\n platform: os.platform(),\n arch: os.arch(),\n cpuCores: os.cpus().length,\n memoryMB: Math.round(os.totalmem() / 1024 / 1024),\n pythonRuntimes: [],\n installedAddons: [addonId],\n taskTypes: [],\n host: os.hostname(),\n port: 0,\n httpPort: 0,\n })\n console.log(`[worker:${addonId}] Registered with hub as ${workerId}`)\n } catch (err) {\n console.error(`[worker:${addonId}] Failed to register:`, err instanceof Error ? err.message : err)\n process.exit(1)\n }\n\n // 3. Build logger that routes structured logs via IPC to parent's LogManager\n function createScopedLogger(scope: readonly string[]): IScopedLogger {\n const sendLog = (level: string, message: string, context?: Record<string, unknown>) => {\n if (process.send) {\n process.send({ type: 'LOG', level, message, context })\n } else {\n // Fallback if IPC not available\n const prefix = `[${scope.join(':')}]`\n if (level === 'error') console.error(prefix, message, context ?? '')\n else if (level === 'warn') console.warn(prefix, message, context ?? '')\n else if (level === 'debug') console.debug(prefix, message, context ?? '')\n else console.log(prefix, message, context ?? '')\n }\n }\n return {\n info: (msg: string, ctx?: Record<string, unknown>) => sendLog('info', msg, ctx),\n warn: (msg: string, ctx?: Record<string, unknown>) => sendLog('warn', msg, ctx),\n error: (msg: string, ctx?: Record<string, unknown>) => sendLog('error', msg, ctx),\n debug: (msg: string, ctx?: Record<string, unknown>) => sendLog('debug', msg, ctx),\n child: (childScope: string) => createScopedLogger([...scope, childScope]),\n } as IScopedLogger\n }\n const logger = createScopedLogger([addonId])\n\n // 4. Create process manager for sub-processes (no-op sender since we use tRPC now)\n const processManager = new WorkerProcessManager(() => {})\n\n // 5. Load addon\n const pkgJsonPath = path.join(addonDir, 'package.json')\n const pkgJson = JSON.parse(fs.readFileSync(pkgJsonPath, 'utf-8'))\n const manifest = pkgJson.camstack\n if (!manifest?.addons?.length) {\n console.error(`[worker:${addonId}] No camstack addon manifest in ${pkgJsonPath}`)\n process.exit(1)\n }\n\n const declaration = manifest.addons.find((a: { id: string }) => a.id === addonId)\n if (!declaration) {\n console.error(`[worker:${addonId}] Addon \"${addonId}\" not found in manifest`)\n process.exit(1)\n }\n\n const entryFile = declaration.entry\n .replace(/^\\.\\//, '')\n .replace(/^src\\//, 'dist/')\n .replace(/\\.ts$/, '.js')\n let entryPath = path.resolve(addonDir, entryFile)\n if (!fs.existsSync(entryPath)) {\n // Try .cjs fallback\n const cjsPath = entryPath.replace(/\\.js$/, '.cjs')\n if (fs.existsSync(cjsPath)) entryPath = cjsPath\n }\n\n const mod = await import(entryPath)\n const firstKey = Object.keys(mod)[0] as string | undefined\n const AddonClass = mod.default?.default ?? mod.default ?? (firstKey ? mod[firstKey] : undefined)\n if (typeof AddonClass !== 'function') {\n console.error(`[worker:${addonId}] No addon class found in ${entryPath}`)\n process.exit(1)\n }\n\n const addon: ICamstackAddon = new AddonClass()\n\n // 6. Initialize addon with context.api = tRPC client\n const context: AddonContext = {\n id: addonId,\n api: api as unknown as AddonContext['api'],\n logger,\n addonConfig,\n process: processManager,\n dataDir,\n locationPaths,\n // Legacy fields — stubs for backward compat during migration\n eventBus: { emit: () => {}, subscribe: () => () => {}, getRecent: () => [] } as any,\n storage: {} as any,\n config: { get: () => undefined, set: async () => {} } as any,\n } as AddonContext\n\n await addon.initialize(context)\n console.log(`[worker:${addonId}] Addon initialized`)\n\n // 7. Heartbeat loop — includes sub-process stats\n const heartbeatInterval = setInterval(async () => {\n try {\n const mem = process.memoryUsage()\n const subProcs = processManager.listProcesses().map(p => ({\n pid: p.pid,\n name: p.name,\n command: p.command,\n state: p.state as 'running' | 'stopped' | 'crashed',\n cpuPercent: p.cpuPercent,\n memoryRss: p.memoryRss,\n uptimeSeconds: p.uptimeSeconds,\n }))\n\n await (api as any).agent.heartbeat.mutate({\n agentId: workerId,\n cpuPercent: 0,\n memoryUsedMB: Math.round(mem.rss / 1024 / 1024),\n activeTasks: 0,\n subProcesses: subProcs,\n })\n } catch {\n // heartbeat failure is non-fatal\n }\n }, 10_000)\n\n // 8. Listen for task assignments\n try {\n ;(api as any).agent.onTaskAssignment.subscribe(undefined, {\n onData: async (task: { taskId: string; taskType: string; payload: unknown }) => {\n try {\n let result: unknown\n if (task.taskType === 'addon.install') {\n // Handle addon install\n const { AddonInstaller } = await import('../addon-installer.js')\n const installer = new AddonInstaller({ addonsDir: path.dirname(addonDir) })\n const payload = task.payload as { package: string; version?: string }\n result = await installer.installFromNpm(payload.package, payload.version)\n } else if (typeof (addon as any).handleTask === 'function') {\n result = await (addon as any).handleTask(task.taskType, task.payload)\n }\n await (api as any).agent.reportTaskResult.mutate({\n taskId: task.taskId, success: true, result,\n })\n } catch (err) {\n await (api as any).agent.reportTaskResult.mutate({\n taskId: task.taskId, success: false,\n error: err instanceof Error ? err.message : String(err),\n })\n }\n },\n })\n } catch {\n // subscription failure — tasks won't be received but worker still functions\n }\n\n // 9. Graceful shutdown\n const shutdown = async () => {\n clearInterval(heartbeatInterval)\n await processManager.killAll()\n await addon.shutdown()\n wsClient.close()\n process.exit(0)\n }\n\n process.on('SIGTERM', () => shutdown().catch(() => process.exit(1)))\n process.on('SIGINT', () => shutdown().catch(() => process.exit(1)))\n\n // Signal ready to parent (if using IPC for boot coordination)\n process.send?.({ type: 'READY' })\n}\n\n// Handle uncaught errors\nprocess.on('uncaughtException', (err) => {\n console.error('[worker] Uncaught exception:', err.message, err.stack)\n})\n\nprocess.on('unhandledRejection', (reason) => {\n const msg = reason instanceof Error ? reason.message : String(reason)\n console.error('[worker] Unhandled rejection:', msg)\n})\n\nboot().catch((err) => {\n console.error('[worker] Boot failed:', err)\n process.exit(1)\n})\n"],"mappings":"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","names":["WorkerProcessManager","exports","resolve","exports","fs","path","os","fs","path","os","exports","context"]}
1
+ {"version":3,"sources":["../../src/fs-utils.ts","../../src/addon-installer.ts","../../src/worker/addon-worker-entry.ts","../../src/worker/worker-process-manager.ts"],"sourcesContent":["import { execFileSync } from 'node:child_process'\nimport * as fs from 'node:fs'\nimport * as os from 'node:os'\nimport * as path from 'node:path'\n\n/**\n * Ensure a directory exists (recursive).\n * Single source of truth — replaces scattered mkdirSync calls.\n */\nexport function ensureDir(dirPath: string): void {\n fs.mkdirSync(dirPath, { recursive: true })\n}\n\n/**\n * Copy a directory recursively.\n * Single source of truth — extracted from addon-installer + first-boot-installer.\n */\nexport function copyDirRecursive(src: string, dest: string): void {\n ensureDir(dest)\n const entries = fs.readdirSync(src, { withFileTypes: true })\n for (const entry of entries) {\n const srcPath = path.join(src, entry.name)\n const destPath = path.join(dest, entry.name)\n if (entry.isDirectory()) {\n copyDirRecursive(srcPath, destPath)\n } else {\n fs.copyFileSync(srcPath, destPath)\n }\n }\n}\n\n/**\n * Strip @camstack/* dependencies and devDependencies from a package.json object.\n * Used when installing addons into the addons directory — @camstack packages\n * are provided by the host runtime, not installed per-addon.\n *\n * Returns a new object (immutable).\n */\nexport function stripCamstackDeps(\n pkg: Record<string, unknown>,\n): Record<string, unknown> {\n const result = { ...pkg }\n\n for (const depType of ['dependencies', 'peerDependencies', 'devDependencies']) {\n const deps = result[depType] as Record<string, string> | undefined\n if (deps) {\n const filtered: Record<string, string> = {}\n for (const [name, version] of Object.entries(deps)) {\n if (!name.startsWith('@camstack/')) {\n filtered[name] = version\n }\n }\n result[depType] = Object.keys(filtered).length > 0 ? filtered : undefined\n }\n }\n\n // Always strip devDependencies — addons don't need them at runtime\n delete result.devDependencies\n\n return result\n}\n\n/**\n * Copy extra file directories declared in package.json \"files\" field.\n * Copies directories (not individual files) from source to destination.\n * Skips \"dist\" (already handled) and glob patterns.\n */\nexport function copyExtraFileDirs(\n pkgJson: Record<string, unknown>,\n sourceDir: string,\n destDir: string,\n): void {\n const files = pkgJson.files as string[] | undefined\n if (!files) return\n\n for (const fileEntry of files) {\n if (fileEntry === 'dist' || fileEntry.includes('*')) continue\n const srcPath = path.join(sourceDir, fileEntry)\n if (!fs.existsSync(srcPath)) continue\n\n const destPath = path.join(destDir, fileEntry)\n const stat = fs.statSync(srcPath)\n if (stat.isDirectory()) {\n copyDirRecursive(srcPath, destPath)\n } else if (stat.isFile()) {\n ensureDir(path.dirname(destPath))\n fs.copyFileSync(srcPath, destPath)\n }\n }\n}\n\n/**\n * Create symlinks in node_modules so that static `import from '@camstack/core'` works.\n * Links: node_modules/@camstack/{pkg} -> data/addons/{pkg}/\n * (not just dist -- need package.json for Node's exports resolution)\n */\nexport function symlinkAddonsToNodeModules(addonsDir: string, nodeModulesDir: string): void {\n const camstackDir = path.join(nodeModulesDir, '@camstack')\n ensureDir(camstackDir)\n\n // Link each addon that's in data/addons/ and also imported by the server\n const packagesToLink = ['core']\n\n for (const pkg of packagesToLink) {\n const addonDir = path.join(addonsDir, '@camstack', pkg)\n const linkPath = path.join(camstackDir, pkg)\n\n if (!fs.existsSync(addonDir)) continue\n\n // Remove existing link/directory\n try {\n const stat = fs.lstatSync(linkPath)\n if (stat.isSymbolicLink() || stat.isDirectory()) {\n fs.rmSync(linkPath, { recursive: true, force: true })\n }\n } catch {\n // Doesn't exist yet -- nothing to remove\n }\n\n fs.symlinkSync(addonDir, linkPath, 'dir')\n console.log(`[symlink] node_modules/@camstack/${pkg} -> ${addonDir}`)\n }\n}\n\n/**\n * Check if any file in src/ is newer than dist/.\n * Returns true if rebuild is needed.\n */\nexport function isSourceNewer(packageDir: string): boolean {\n const srcDir = path.join(packageDir, 'src')\n const distDir = path.join(packageDir, 'dist')\n if (!fs.existsSync(srcDir) || !fs.existsSync(distDir)) return true\n try {\n const distMtime = fs.statSync(distDir).mtimeMs\n const entries = fs.readdirSync(srcDir, { withFileTypes: true, recursive: true })\n for (const entry of entries) {\n if (!entry.isFile()) continue\n const filePath = path.join(entry.parentPath ?? (entry as any).path, entry.name)\n if (fs.statSync(filePath).mtimeMs > distMtime) return true\n }\n return false\n } catch {\n return true\n }\n}\n\n/**\n * Ensure a library dependency (not an addon) has a dist/ directory.\n * Does NOT rebuild — in dev mode, `npm run build` should be run separately.\n * Only checks that dist/ exists and has an index file.\n */\nexport function ensureLibraryBuilt(packageName: string, packagesDir: string): void {\n const dirName = packageName.replace('@camstack/', '')\n const sourceDir = path.join(packagesDir, dirName)\n if (!fs.existsSync(sourceDir)) return\n\n const distDir = path.join(sourceDir, 'dist')\n const hasIndex = fs.existsSync(path.join(distDir, 'index.js')) || fs.existsSync(path.join(distDir, 'index.mjs'))\n if (hasIndex) return\n\n console.warn(`[ensureLibraryBuilt] ${packageName} has no dist/ — run 'npm run build' first`)\n}\n\n/**\n * Install a single npm package into a target directory (package.json + dist/).\n * No validation on camstack.addons -- works for any @camstack/* package.\n * Uses synchronous child_process calls (suitable for first-boot and update paths).\n */\nexport function installPackageFromNpmSync(packageName: string, targetDir: string): void {\n const tmpDir = fs.mkdtempSync(path.join(os.tmpdir(), 'camstack-install-'))\n\n try {\n // npm pack downloads the tgz without installing\n const stdout = execFileSync('npm', ['pack', packageName, '--pack-destination', tmpDir], {\n timeout: 120_000,\n encoding: 'utf-8',\n })\n\n const tgzFilename = stdout.trim().split('\\n').pop()?.trim()\n if (!tgzFilename) throw new Error('npm pack produced no output')\n\n const tgzPath = path.join(tmpDir, tgzFilename)\n\n // Extract tgz\n const extractDir = path.join(tmpDir, 'extracted')\n ensureDir(extractDir)\n execFileSync('tar', ['-xzf', tgzPath, '-C', extractDir], { timeout: 30_000 })\n\n // npm pack creates a package/ subdirectory\n const packageSubDir = path.join(extractDir, 'package')\n const srcPkgJsonDir = fs.existsSync(path.join(packageSubDir, 'package.json'))\n ? packageSubDir\n : extractDir\n\n // Copy package.json + dist/ to target\n fs.rmSync(targetDir, { recursive: true, force: true })\n ensureDir(targetDir)\n fs.copyFileSync(path.join(srcPkgJsonDir, 'package.json'), path.join(targetDir, 'package.json'))\n\n const distSrc = path.join(srcPkgJsonDir, 'dist')\n if (fs.existsSync(distSrc)) {\n copyDirRecursive(distSrc, path.join(targetDir, 'dist'))\n }\n\n // Copy extra directories from \"files\" in package.json (e.g., python/)\n try {\n const npmPkg = JSON.parse(fs.readFileSync(path.join(srcPkgJsonDir, 'package.json'), 'utf-8'))\n copyExtraFileDirs(npmPkg, srcPkgJsonDir, targetDir)\n } catch { /* non-critical */ }\n } finally {\n fs.rmSync(tmpDir, { recursive: true, force: true })\n }\n}\n","import { execFile } from 'node:child_process'\nimport { promisify } from 'node:util'\nimport * as fs from 'node:fs'\nimport * as path from 'node:path'\nimport * as os from 'node:os'\nimport { copyDirRecursive, copyExtraFileDirs, ensureDir, ensureLibraryBuilt, isSourceNewer, stripCamstackDeps } from './fs-utils.js'\n\nconst execFileAsync = promisify(execFile)\n\nexport interface AddonInstallerConfig {\n /** Directory where addons are stored (e.g., {dataDir}/addons) — each addon is a subdirectory */\n readonly addonsDir: string\n /** npm registry URL (default: https://registry.npmjs.org) */\n readonly registry?: string\n /** Workspace packages directory (e.g., /path/to/camstack-server/packages) — for dev installs */\n readonly workspacePackagesDir?: string\n}\n\nimport type { InstalledPackage } from '@camstack/types'\nexport type { InstalledPackage }\n\nexport class AddonInstaller {\n private readonly addonsDir: string\n private readonly registry: string | undefined\n private readonly workspacePackagesDir: string | undefined\n\n constructor(config: AddonInstallerConfig) {\n this.addonsDir = config.addonsDir\n this.registry = config.registry\n this.workspacePackagesDir = config.workspacePackagesDir\n }\n\n /** Required addon packages that must be installed for the server to function */\n static readonly REQUIRED_PACKAGES = [\n '@camstack/core',\n '@camstack/addon-stream-broker',\n '@camstack/addon-recording',\n '@camstack/addon-vision',\n '@camstack/addon-admin-ui',\n '@camstack/addon-webrtc-adaptive',\n '@camstack/addon-analytics',\n '@camstack/addon-scene-intelligence',\n '@camstack/addon-advanced-notifier',\n ] as const\n\n /** Ensure the addons directory exists */\n async initialize(): Promise<void> {\n ensureDir(this.addonsDir)\n }\n\n /**\n * Ensure all required packages are installed in the addons directory.\n * This replaces the standalone first-boot-installer.ts.\n */\n async ensureRequiredPackages(): Promise<void> {\n ensureDir(this.addonsDir)\n\n // In workspace mode, ensure library dependencies are built first\n if (this.workspacePackagesDir) {\n console.log(`[AddonInstaller] Workspace detected: ${this.workspacePackagesDir}`)\n ensureLibraryBuilt('@camstack/kernel', this.workspacePackagesDir)\n ensureLibraryBuilt('@camstack/types', this.workspacePackagesDir)\n }\n\n for (const packageName of AddonInstaller.REQUIRED_PACKAGES) {\n const addonDir = path.join(this.addonsDir, packageName)\n const pkgJsonPath = path.join(addonDir, 'package.json')\n\n // CAMSTACK_INSTALL_SOURCE=npm forces npm install even in workspace mode\n const forceNpm = process.env['CAMSTACK_INSTALL_SOURCE'] === 'npm'\n const useWorkspace = this.workspacePackagesDir && !forceNpm\n\n // Skip if already installed and up-to-date\n if (fs.existsSync(pkgJsonPath)) {\n if (!useWorkspace) {\n // Production or npm-forced: installed = done\n console.log(`[AddonInstaller] ${packageName} — already installed (npm), skipping`)\n continue\n }\n // Workspace: skip if source dist/ isn't newer than target\n const srcPkgDir = this.findWorkspacePackage(packageName)\n if (srcPkgDir && !isSourceNewer(srcPkgDir)) {\n console.log(`[AddonInstaller] ${packageName} — workspace up-to-date, skipping`)\n continue\n }\n }\n\n try {\n // Try workspace install first (dev mode), fall back to npm\n if (useWorkspace) {\n const pkgDir = this.findWorkspacePackage(packageName)\n if (pkgDir) {\n console.log(`[AddonInstaller] ${packageName} — installing from workspace`)\n await this.installFromWorkspace(packageName)\n continue\n }\n }\n\n console.log(`[AddonInstaller] ${packageName} — installing from npm`)\n await this.installFromNpm(packageName)\n } catch (err) {\n const msg = err instanceof Error ? err.message : String(err)\n // Core is essential — abort if it fails\n if (packageName === '@camstack/core') {\n throw new Error(`Required package ${packageName} failed to install: ${msg}`)\n }\n console.error(`[AddonInstaller] Failed to install ${packageName}: ${msg}`)\n }\n }\n }\n\n private findWorkspacePackage(packageName: string): string | null {\n if (!this.workspacePackagesDir) return null\n const shortName = packageName.replace('@camstack/', '')\n // Check common naming patterns\n for (const dirName of [shortName, `addon-${shortName}`, shortName.replace('addon-', '')]) {\n const candidate = path.join(this.workspacePackagesDir, dirName)\n if (fs.existsSync(path.join(candidate, 'package.json'))) {\n try {\n const pkg = JSON.parse(fs.readFileSync(path.join(candidate, 'package.json'), 'utf-8'))\n if (pkg.name === packageName) return candidate\n } catch { /* ignore */ }\n }\n }\n return null\n }\n\n /** Install addon from a tgz file (uploaded or downloaded) */\n async installFromTgz(tgzPath: string): Promise<{ name: string; version: string }> {\n // 1. Extract tgz to temp dir\n const tmpDir = fs.mkdtempSync(path.join(os.tmpdir(), 'camstack-addon-install-'))\n\n try {\n await execFileAsync('tar', ['-xzf', tgzPath, '-C', tmpDir], { timeout: 30_000 })\n\n // npm pack creates a package/ directory inside the tgz\n const extractedDir = path.join(tmpDir, 'package')\n const pkgJsonPath = fs.existsSync(path.join(extractedDir, 'package.json'))\n ? path.join(extractedDir, 'package.json')\n : path.join(tmpDir, 'package.json')\n\n if (!fs.existsSync(pkgJsonPath)) {\n throw new Error('No package.json found in tgz archive')\n }\n\n const pkgJson = JSON.parse(fs.readFileSync(pkgJsonPath, 'utf-8')) as {\n name: string\n version: string\n files?: string[]\n camstack?: { addons?: unknown[] }\n }\n\n if (!pkgJson.camstack?.addons) {\n throw new Error(`Package ${pkgJson.name} has no camstack.addons manifest`)\n }\n\n // 2. Determine target directory name (strip scope)\n const targetDir = path.join(this.addonsDir, pkgJson.name)\n\n // 3. Remove old version if present\n fs.rmSync(targetDir, { recursive: true, force: true })\n ensureDir(targetDir)\n\n // 4. Copy package.json\n const sourceDir = path.dirname(pkgJsonPath)\n fs.copyFileSync(pkgJsonPath, path.join(targetDir, 'package.json'))\n\n // 5. Copy dist/ directory\n const sourceDist = path.join(sourceDir, 'dist')\n if (fs.existsSync(sourceDist)) {\n copyDirRecursive(sourceDist, path.join(targetDir, 'dist'))\n }\n\n // 6. Copy extra directories from \"files\" in package.json (e.g., python/, reference-images/)\n copyExtraFileDirs(pkgJson, sourceDir, targetDir)\n\n return { name: pkgJson.name, version: pkgJson.version }\n } finally {\n fs.rmSync(tmpDir, { recursive: true, force: true })\n }\n }\n\n /**\n * Install addon — prefers workspace if available, falls back to npm.\n * This ensures dev builds (with vite output, etc.) are used when in workspace mode.\n */\n async install(packageName: string, version?: string): Promise<{ name: string; version: string }> {\n if (this.workspacePackagesDir) {\n // Workspace dirs use short names (e.g., packages/addon-benchmark)\n const workspaceDirName = packageName.replace('@camstack/', '')\n const sourceDir = path.join(this.workspacePackagesDir, workspaceDirName)\n if (fs.existsSync(path.join(sourceDir, 'package.json'))) {\n return this.installFromWorkspace(packageName)\n }\n }\n return this.installFromNpm(packageName, version)\n }\n\n /**\n * Install addon from workspace by copying package.json + dist/ to addons dir.\n * Does NOT build — expects dist/ to already exist (run `npm run build` separately).\n */\n async installFromWorkspace(packageName: string): Promise<{ name: string; version: string }> {\n if (!this.workspacePackagesDir) {\n throw new Error('Workspace packages directory not configured')\n }\n\n const workspaceDirName = packageName.replace('@camstack/', '')\n const sourceDir = path.join(this.workspacePackagesDir, workspaceDirName)\n const sourcePkgJson = path.join(sourceDir, 'package.json')\n\n if (!fs.existsSync(sourcePkgJson)) {\n throw new Error(`Workspace package not found: ${sourceDir}`)\n }\n\n const distDir = path.join(sourceDir, 'dist')\n if (!fs.existsSync(distDir)) {\n throw new Error(`${packageName} has no dist/ directory — run 'npm run build' first`)\n }\n\n // Copy package.json + dist/ to target (use full scoped name as dir)\n const targetDir = path.join(this.addonsDir, packageName)\n\n fs.rmSync(targetDir, { recursive: true, force: true })\n ensureDir(targetDir)\n\n // Strip @camstack/* deps from package.json\n const pkgData = JSON.parse(fs.readFileSync(sourcePkgJson, 'utf-8'))\n const strippedPkg = stripCamstackDeps(pkgData)\n fs.writeFileSync(path.join(targetDir, 'package.json'), JSON.stringify(strippedPkg, null, 2))\n\n copyDirRecursive(distDir, path.join(targetDir, 'dist'))\n\n // Copy extra directories from \"files\" in package.json (e.g., python/, reference-images/)\n copyExtraFileDirs(pkgData, sourceDir, targetDir)\n\n // Mark install source for UI display\n fs.writeFileSync(path.join(targetDir, '.install-source'), 'workspace')\n\n // Install production dependencies (non-fatal if fails)\n try {\n await execFileAsync('npm', ['install', '--omit=dev', '--ignore-scripts=false'], {\n cwd: targetDir,\n timeout: 120_000,\n })\n } catch {\n // Non-fatal — addon may not have external deps\n }\n\n return { name: pkgData.name, version: pkgData.version }\n }\n\n /** Install addon from npm (download tgz, then extract) */\n async installFromNpm(packageName: string, version?: string): Promise<{ name: string; version: string }> {\n const tmpDir = fs.mkdtempSync(path.join(os.tmpdir(), 'camstack-addon-npm-'))\n\n const packageSpec = version ? `${packageName}@${version}` : packageName\n const args = ['pack', packageSpec, '--pack-destination', tmpDir]\n if (this.registry) {\n args.push('--registry', this.registry)\n }\n\n console.log(`[AddonInstaller] npm pack ${packageSpec} → ${tmpDir}`)\n\n try {\n const { stdout } = await execFileAsync('npm', args, {\n timeout: 120_000,\n })\n\n const tgzFiles = fs.readdirSync(tmpDir).filter(f => f.endsWith('.tgz'))\n console.log(`[AddonInstaller] npm pack stdout: ${stdout.trim()}, tgzFiles: ${tgzFiles.join(', ')}`)\n if (tgzFiles.length === 0) {\n throw new Error(`npm pack produced no tgz file for ${packageSpec}. stdout: ${stdout.trim()}`)\n }\n\n const tgzPath = path.join(tmpDir, tgzFiles[0]!)\n const result = await this.installFromTgz(tgzPath)\n console.log(`[AddonInstaller] installFromTgz result: ${result.name}@${result.version} → ${path.join(this.addonsDir, result.name)}`)\n\n // Mark as npm install\n const targetDir = path.join(this.addonsDir, result.name)\n fs.writeFileSync(path.join(targetDir, '.install-source'), 'npm')\n\n return result\n } finally {\n // Clean up AFTER installFromTgz has fully completed\n fs.rmSync(tmpDir, { recursive: true, force: true })\n }\n }\n\n /** Uninstall addon (delete directory) */\n async uninstall(packageName: string): Promise<void> {\n // Support both full scoped name and short name\n const addonDir = path.join(this.addonsDir, packageName)\n if (fs.existsSync(addonDir)) {\n fs.rmSync(addonDir, { recursive: true, force: true })\n return\n }\n // Fallback: try without scope (legacy layout)\n const legacyDir = path.join(this.addonsDir, packageName.replace(/^@[^/]+\\//, ''))\n if (fs.existsSync(legacyDir)) {\n fs.rmSync(legacyDir, { recursive: true, force: true })\n }\n }\n\n /** List installed addons (directories with package.json containing camstack.addons) */\n listInstalled(): InstalledPackage[] {\n if (!fs.existsSync(this.addonsDir)) return []\n\n // Collect all package directories — handles both flat (addon-x/) and scoped (@camstack/addon-x/) layouts\n const packageDirs: string[] = []\n for (const entry of fs.readdirSync(this.addonsDir, { withFileTypes: true })) {\n if (!entry.isDirectory()) continue\n if (entry.name.startsWith('@')) {\n // Scoped directory — scan one level deeper\n const scopeDir = path.join(this.addonsDir, entry.name)\n for (const inner of fs.readdirSync(scopeDir, { withFileTypes: true })) {\n if (inner.isDirectory()) packageDirs.push(path.join(scopeDir, inner.name))\n }\n } else {\n packageDirs.push(path.join(this.addonsDir, entry.name))\n }\n }\n\n return packageDirs\n .map(dir => {\n const pkgPath = path.join(dir, 'package.json')\n if (!fs.existsSync(pkgPath)) return null\n try {\n const pkg = JSON.parse(fs.readFileSync(pkgPath, 'utf-8')) as {\n name: string\n version: string\n camstack?: { addons?: unknown[] }\n }\n if (!pkg.camstack?.addons) return null\n const sourceFile = path.join(dir, '.install-source')\n const installSource = fs.existsSync(sourceFile)\n ? fs.readFileSync(sourceFile, 'utf-8').trim() as 'npm' | 'workspace' | 'upload'\n : undefined\n const result: InstalledPackage = { name: pkg.name, version: pkg.version, dir, ...(installSource ? { installSource } : {}) }\n return result\n } catch {\n return null\n }\n })\n .filter((item): item is InstalledPackage => item !== null)\n }\n\n /** Check if an addon is installed */\n isInstalled(packageName: string): boolean {\n // Check scoped path first, then legacy\n if (fs.existsSync(path.join(this.addonsDir, packageName, 'package.json'))) return true\n const legacy = packageName.replace(/^@[^/]+\\//, '')\n return fs.existsSync(path.join(this.addonsDir, legacy, 'package.json'))\n }\n\n /** Get installed package info */\n getInstalledPackage(packageName: string): InstalledPackage | null {\n let pkgPath = path.join(this.addonsDir, packageName, 'package.json')\n if (!fs.existsSync(pkgPath)) {\n pkgPath = path.join(this.addonsDir, packageName.replace(/^@[^/]+\\//, ''), 'package.json')\n }\n if (!fs.existsSync(pkgPath)) return null\n try {\n const pkg = JSON.parse(fs.readFileSync(pkgPath, 'utf-8')) as { name: string; version: string }\n return { name: pkg.name, version: pkg.version, dir: path.dirname(pkgPath) }\n } catch {\n return null\n }\n }\n}\n\n// copyDirRecursive, copyExtraFileDirs, ensureDir, stripCamstackDeps\n// are now imported from ./fs-utils.js (single source of truth)\n","/**\n * Worker entry point — forked by AddonWorkerHost.\n * Connects to hub via tRPC WSS, loads addon, reports heartbeat.\n *\n * Boot config passed via environment variables:\n * CAMSTACK_WORKER_HUB_URL - WSS URL (e.g., wss://localhost:4443/trpc)\n * CAMSTACK_WORKER_TOKEN - Auth token\n * CAMSTACK_ADDON_ID - Addon to load\n * CAMSTACK_ADDON_DIR - Path to addon directory\n * CAMSTACK_ADDON_CONFIG - JSON-encoded addon config\n * CAMSTACK_DATA_DIR - Data directory for this addon\n * CAMSTACK_LOCATION_PATHS - JSON-encoded location paths\n */\nimport * as os from 'node:os'\nimport * as fs from 'node:fs'\nimport * as path from 'node:path'\nimport type { ICamstackAddon, AddonContext, IScopedLogger } from '@camstack/types'\nimport { WorkerProcessManager } from './worker-process-manager.js'\n\nasync function boot(): Promise<void> {\n const hubUrl = process.env.CAMSTACK_WORKER_HUB_URL\n const token = process.env.CAMSTACK_WORKER_TOKEN ?? ''\n const addonId = process.env.CAMSTACK_ADDON_ID\n const addonDir = process.env.CAMSTACK_ADDON_DIR\n const dataDir = process.env.CAMSTACK_DATA_DIR ?? `/tmp/camstack-worker-${addonId}`\n const addonConfig = JSON.parse(process.env.CAMSTACK_ADDON_CONFIG ?? '{}')\n const locationPaths = JSON.parse(process.env.CAMSTACK_LOCATION_PATHS ?? '{}')\n\n if (!hubUrl || !addonId || !addonDir) {\n console.error('[worker] Missing required env vars: CAMSTACK_WORKER_HUB_URL, CAMSTACK_ADDON_ID, CAMSTACK_ADDON_DIR')\n process.exit(1)\n }\n\n const workerId = `worker-${addonId}-${process.pid}`\n\n // 1. Create tRPC WSS client (must use superjson transformer to match server)\n const { createTRPCClient, createWSClient, wsLink } = await import('@trpc/client')\n const superjson = (await import('superjson')).default\n\n const wsClient = createWSClient({\n url: hubUrl,\n connectionParams: () => ({ token }),\n })\n\n const api = createTRPCClient<any>({\n links: [wsLink({ client: wsClient, transformer: superjson })],\n })\n\n // 2. Register with hub\n try {\n await (api as any).agent.register.mutate({\n id: workerId,\n name: addonId,\n capabilities: [],\n platform: os.platform(),\n arch: os.arch(),\n cpuCores: os.cpus().length,\n memoryMB: Math.round(os.totalmem() / 1024 / 1024),\n pythonRuntimes: [],\n installedAddons: [addonId],\n taskTypes: [],\n host: os.hostname(),\n port: 0,\n httpPort: 0,\n })\n console.log(`[worker:${addonId}] Registered with hub as ${workerId}`)\n } catch (err) {\n console.error(`[worker:${addonId}] Failed to register:`, err instanceof Error ? err.message : err)\n process.exit(1)\n }\n\n // 3. Build logger that routes structured logs via IPC to parent's LogManager\n function createScopedLogger(scope: readonly string[]): IScopedLogger {\n const sendLog = (level: string, message: string, context?: Record<string, unknown>) => {\n if (process.send) {\n process.send({ type: 'LOG', level, message, context })\n } else {\n // Fallback if IPC not available\n const prefix = `[${scope.join(':')}]`\n if (level === 'error') console.error(prefix, message, context ?? '')\n else if (level === 'warn') console.warn(prefix, message, context ?? '')\n else if (level === 'debug') console.debug(prefix, message, context ?? '')\n else console.log(prefix, message, context ?? '')\n }\n }\n return {\n info: (msg: string, ctx?: Record<string, unknown>) => sendLog('info', msg, ctx),\n warn: (msg: string, ctx?: Record<string, unknown>) => sendLog('warn', msg, ctx),\n error: (msg: string, ctx?: Record<string, unknown>) => sendLog('error', msg, ctx),\n debug: (msg: string, ctx?: Record<string, unknown>) => sendLog('debug', msg, ctx),\n child: (childScope: string) => createScopedLogger([...scope, childScope]),\n } as IScopedLogger\n }\n const logger = createScopedLogger([addonId])\n\n // 4. Create process manager for sub-processes (no-op sender since we use tRPC now)\n const processManager = new WorkerProcessManager(() => {})\n\n // 5. Load addon\n const pkgJsonPath = path.join(addonDir, 'package.json')\n const pkgJson = JSON.parse(fs.readFileSync(pkgJsonPath, 'utf-8'))\n const manifest = pkgJson.camstack\n if (!manifest?.addons?.length) {\n console.error(`[worker:${addonId}] No camstack addon manifest in ${pkgJsonPath}`)\n process.exit(1)\n }\n\n const declaration = manifest.addons.find((a: { id: string }) => a.id === addonId)\n if (!declaration) {\n console.error(`[worker:${addonId}] Addon \"${addonId}\" not found in manifest`)\n process.exit(1)\n }\n\n const entryFile = declaration.entry\n .replace(/^\\.\\//, '')\n .replace(/^src\\//, 'dist/')\n .replace(/\\.ts$/, '.js')\n let entryPath = path.resolve(addonDir, entryFile)\n if (!fs.existsSync(entryPath)) {\n // Try .cjs fallback\n const cjsPath = entryPath.replace(/\\.js$/, '.cjs')\n if (fs.existsSync(cjsPath)) entryPath = cjsPath\n }\n\n const mod = await import(entryPath)\n const firstKey = Object.keys(mod)[0] as string | undefined\n const AddonClass = mod.default?.default ?? mod.default ?? (firstKey ? mod[firstKey] : undefined)\n if (typeof AddonClass !== 'function') {\n console.error(`[worker:${addonId}] No addon class found in ${entryPath}`)\n process.exit(1)\n }\n\n const addon: ICamstackAddon = new AddonClass()\n\n // 6. Initialize addon with context.api = tRPC client\n const context: AddonContext = {\n id: addonId,\n api: api as unknown as AddonContext['api'],\n logger,\n addonConfig,\n process: processManager,\n dataDir,\n locationPaths,\n // Legacy fields — stubs for backward compat during migration\n eventBus: { emit: () => {}, subscribe: () => () => {}, getRecent: () => [] } as any,\n storage: {} as any,\n config: { get: () => undefined, set: async () => {} } as any,\n } as AddonContext\n\n await addon.initialize(context)\n console.log(`[worker:${addonId}] Addon initialized`)\n\n // 7. Heartbeat loop — includes sub-process stats\n const heartbeatInterval = setInterval(async () => {\n try {\n const mem = process.memoryUsage()\n const subProcs = processManager.listProcesses().map(p => ({\n pid: p.pid,\n name: p.name,\n command: p.command,\n state: p.state as 'running' | 'stopped' | 'crashed',\n cpuPercent: p.cpuPercent,\n memoryRss: p.memoryRss,\n uptimeSeconds: p.uptimeSeconds,\n }))\n\n await (api as any).agent.heartbeat.mutate({\n agentId: workerId,\n cpuPercent: 0,\n memoryUsedMB: Math.round(mem.rss / 1024 / 1024),\n activeTasks: 0,\n subProcesses: subProcs,\n })\n } catch {\n // heartbeat failure is non-fatal\n }\n }, 10_000)\n\n // 8. Listen for task assignments\n try {\n ;(api as any).agent.onTaskAssignment.subscribe(undefined, {\n onData: async (task: { taskId: string; taskType: string; payload: unknown }) => {\n try {\n let result: unknown\n if (task.taskType === 'addon.install') {\n // Handle addon install\n const { AddonInstaller } = await import('../addon-installer.js')\n const installer = new AddonInstaller({ addonsDir: path.dirname(addonDir) })\n const payload = task.payload as { package: string; version?: string }\n result = await installer.installFromNpm(payload.package, payload.version)\n } else if (typeof (addon as any).handleTask === 'function') {\n result = await (addon as any).handleTask(task.taskType, task.payload)\n }\n await (api as any).agent.reportTaskResult.mutate({\n taskId: task.taskId, success: true, result,\n })\n } catch (err) {\n await (api as any).agent.reportTaskResult.mutate({\n taskId: task.taskId, success: false,\n error: err instanceof Error ? err.message : String(err),\n })\n }\n },\n })\n } catch {\n // subscription failure — tasks won't be received but worker still functions\n }\n\n // 9. Graceful shutdown\n const shutdown = async () => {\n clearInterval(heartbeatInterval)\n await processManager.killAll()\n await addon.shutdown()\n wsClient.close()\n process.exit(0)\n }\n\n process.on('SIGTERM', () => shutdown().catch(() => process.exit(1)))\n process.on('SIGINT', () => shutdown().catch(() => process.exit(1)))\n\n // Signal ready to parent (if using IPC for boot coordination)\n process.send?.({ type: 'READY' })\n}\n\n// Handle uncaught errors\nprocess.on('uncaughtException', (err) => {\n console.error('[worker] Uncaught exception:', err.message, err.stack)\n})\n\nprocess.on('unhandledRejection', (reason) => {\n const msg = reason instanceof Error ? reason.message : String(reason)\n console.error('[worker] Unhandled rejection:', msg)\n})\n\nboot().catch((err) => {\n console.error('[worker] Boot failed:', err)\n process.exit(1)\n})\n","import { spawn, type ChildProcess } from 'node:child_process'\nimport type {\n WorkerToMainMessage,\n WorkerProcessStats,\n SubProcessInfo,\n} from '@camstack/types'\nimport type {\n IAddonProcessManager,\n SubProcessConfig,\n IManagedSubProcess,\n} from '@camstack/types'\n\nexport class WorkerProcessManager implements IAddonProcessManager {\n private readonly processes = new Map<number, ManagedProcess>()\n\n constructor(\n private readonly sendToMain: (msg: WorkerToMainMessage) => void,\n ) {}\n\n async spawn(config: SubProcessConfig): Promise<IManagedSubProcess> {\n const child = spawn(config.command, [...(config.args ?? [])], {\n cwd: config.cwd,\n env: config.env ? { ...process.env, ...config.env } : undefined,\n stdio: ['pipe', 'pipe', 'pipe'],\n })\n\n const managed = new ManagedProcess(child, config, this.sendToMain)\n this.processes.set(child.pid!, managed)\n\n this.sendToMain({\n type: 'SUB_PROCESS_SPAWNED',\n pid: child.pid!,\n name: config.name,\n command: config.command,\n })\n\n child.on('exit', (code) => {\n this.sendToMain({\n type: 'SUB_PROCESS_EXITED',\n pid: child.pid!,\n code,\n })\n\n if (config.autoRestart && managed.restartCount < (config.maxRestarts ?? 3)) {\n managed.restartCount++\n setTimeout(() => {\n this.spawn(config).catch(() => {})\n }, 2000)\n }\n })\n\n return managed\n }\n\n listProcesses(): readonly SubProcessInfo[] {\n return [...this.processes.values()].map((p) => p.toInfo())\n }\n\n getWorkerStats(): WorkerProcessStats {\n const mem = process.memoryUsage()\n const cpu = process.cpuUsage()\n return {\n pid: process.pid,\n cpuPercent: (cpu.user + cpu.system) / 1_000_000,\n memoryRss: mem.rss,\n heapUsed: mem.heapUsed,\n uptimeSeconds: Math.round(process.uptime()),\n restartCount: 0,\n state: 'running',\n }\n }\n\n async killAll(): Promise<void> {\n for (const [, proc] of this.processes) {\n proc.kill('SIGTERM')\n }\n this.processes.clear()\n }\n}\n\nclass ManagedProcess implements IManagedSubProcess {\n readonly pid: number\n readonly name: string\n restartCount = 0\n private readonly startedAt = Date.now()\n private exitHandlers: Array<(code: number | null) => void> = []\n private errorHandlers: Array<(error: Error) => void> = []\n\n constructor(\n private readonly child: ChildProcess,\n private readonly config: SubProcessConfig,\n private readonly sendToMain: (msg: WorkerToMainMessage) => void,\n ) {\n this.pid = child.pid!\n this.name = config.name\n\n child.on('exit', (code) => {\n for (const handler of this.exitHandlers) handler(code)\n })\n\n child.on('error', (err) => {\n for (const handler of this.errorHandlers) handler(err)\n })\n }\n\n getStats(): WorkerProcessStats {\n return {\n pid: this.pid,\n cpuPercent: 0,\n memoryRss: 0,\n uptimeSeconds: Math.round((Date.now() - this.startedAt) / 1000),\n restartCount: this.restartCount,\n state: this.child.exitCode !== null ? 'stopped' : 'running',\n }\n }\n\n write(data: Buffer): void {\n this.child.stdin?.write(data)\n }\n\n get stdout(): AsyncIterable<Buffer> {\n return this.child.stdout as AsyncIterable<Buffer>\n }\n\n get stderr(): AsyncIterable<Buffer> {\n return this.child.stderr as AsyncIterable<Buffer>\n }\n\n kill(signal: NodeJS.Signals = 'SIGTERM'): void {\n this.child.kill(signal)\n }\n\n wait(): Promise<{ code: number | null; signal: string | null }> {\n if (this.child.exitCode !== null) {\n return Promise.resolve({ code: this.child.exitCode, signal: null })\n }\n return new Promise((resolve) => {\n this.child.on('exit', (code, signal) => {\n resolve({ code, signal })\n })\n })\n }\n\n onExit(handler: (code: number | null) => void): void {\n this.exitHandlers.push(handler)\n }\n\n onError(handler: (error: Error) => void): void {\n this.errorHandlers.push(handler)\n }\n\n toInfo(): SubProcessInfo {\n return {\n pid: this.pid,\n name: this.name,\n command: this.config.command,\n state: this.child.exitCode !== null ? 'stopped' : 'running',\n cpuPercent: 0,\n memoryRss: 0,\n uptimeSeconds: Math.round((Date.now() - this.startedAt) / 1000),\n }\n }\n}\n"],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AASO,SAAS,UAAU,SAAuB;AAC/C,EAAG,aAAU,SAAS,EAAE,WAAW,KAAK,CAAC;AAC3C;AAMO,SAAS,iBAAiB,KAAa,MAAoB;AAChE,YAAU,IAAI;AACd,QAAM,UAAa,eAAY,KAAK,EAAE,eAAe,KAAK,CAAC;AAC3D,aAAW,SAAS,SAAS;AAC3B,UAAM,UAAe,UAAK,KAAK,MAAM,IAAI;AACzC,UAAM,WAAgB,UAAK,MAAM,MAAM,IAAI;AAC3C,QAAI,MAAM,YAAY,GAAG;AACvB,uBAAiB,SAAS,QAAQ;AAAA,IACpC,OAAO;AACL,MAAG,gBAAa,SAAS,QAAQ;AAAA,IACnC;AAAA,EACF;AACF;AASO,SAAS,kBACd,KACyB;AACzB,QAAM,SAAS,EAAE,GAAG,IAAI;AAExB,aAAW,WAAW,CAAC,gBAAgB,oBAAoB,iBAAiB,GAAG;AAC7E,UAAM,OAAO,OAAO,OAAO;AAC3B,QAAI,MAAM;AACR,YAAM,WAAmC,CAAC;AAC1C,iBAAW,CAAC,MAAM,OAAO,KAAK,OAAO,QAAQ,IAAI,GAAG;AAClD,YAAI,CAAC,KAAK,WAAW,YAAY,GAAG;AAClC,mBAAS,IAAI,IAAI;AAAA,QACnB;AAAA,MACF;AACA,aAAO,OAAO,IAAI,OAAO,KAAK,QAAQ,EAAE,SAAS,IAAI,WAAW;AAAA,IAClE;AAAA,EACF;AAGA,SAAO,OAAO;AAEd,SAAO;AACT;AAOO,SAAS,kBACd,SACA,WACA,SACM;AACN,QAAM,QAAQ,QAAQ;AACtB,MAAI,CAAC,MAAO;AAEZ,aAAW,aAAa,OAAO;AAC7B,QAAI,cAAc,UAAU,UAAU,SAAS,GAAG,EAAG;AACrD,UAAM,UAAe,UAAK,WAAW,SAAS;AAC9C,QAAI,CAAI,cAAW,OAAO,EAAG;AAE7B,UAAM,WAAgB,UAAK,SAAS,SAAS;AAC7C,UAAM,OAAU,YAAS,OAAO;AAChC,QAAI,KAAK,YAAY,GAAG;AACtB,uBAAiB,SAAS,QAAQ;AAAA,IACpC,WAAW,KAAK,OAAO,GAAG;AACxB,gBAAe,aAAQ,QAAQ,CAAC;AAChC,MAAG,gBAAa,SAAS,QAAQ;AAAA,IACnC;AAAA,EACF;AACF;AAuCO,SAAS,cAAc,YAA6B;AACzD,QAAM,SAAc,UAAK,YAAY,KAAK;AAC1C,QAAM,UAAe,UAAK,YAAY,MAAM;AAC5C,MAAI,CAAI,cAAW,MAAM,KAAK,CAAI,cAAW,OAAO,EAAG,QAAO;AAC9D,MAAI;AACF,UAAM,YAAe,YAAS,OAAO,EAAE;AACvC,UAAM,UAAa,eAAY,QAAQ,EAAE,eAAe,MAAM,WAAW,KAAK,CAAC;AAC/E,eAAW,SAAS,SAAS;AAC3B,UAAI,CAAC,MAAM,OAAO,EAAG;AACrB,YAAM,WAAgB,UAAK,MAAM,cAAe,MAAc,MAAM,MAAM,IAAI;AAC9E,UAAO,YAAS,QAAQ,EAAE,UAAU,UAAW,QAAO;AAAA,IACxD;AACA,WAAO;AAAA,EACT,QAAQ;AACN,WAAO;AAAA,EACT;AACF;AAOO,SAAS,mBAAmB,aAAqB,aAA2B;AACjF,QAAM,UAAU,YAAY,QAAQ,cAAc,EAAE;AACpD,QAAM,YAAiB,UAAK,aAAa,OAAO;AAChD,MAAI,CAAI,cAAW,SAAS,EAAG;AAE/B,QAAM,UAAe,UAAK,WAAW,MAAM;AAC3C,QAAM,WAAc,cAAgB,UAAK,SAAS,UAAU,CAAC,KAAQ,cAAgB,UAAK,SAAS,WAAW,CAAC;AAC/G,MAAI,SAAU;AAEd,UAAQ,KAAK,wBAAwB,WAAW,gDAA2C;AAC7F;AAjKA,IAAAA,4BACA,IACA,IACA;AAHA;AAAA;AAAA;AAAA,IAAAA,6BAA6B;AAC7B,SAAoB;AACpB,SAAoB;AACpB,WAAsB;AAAA;AAAA;;;ACHtB;AAAA;AAAA;AAAA;AAAA,IAAAC,4BACA,kBACAC,KACAC,OACAC,KAGM,eAcO;AArBb;AAAA;AAAA;AAAA,IAAAH,6BAAyB;AACzB,uBAA0B;AAC1B,IAAAC,MAAoB;AACpB,IAAAC,QAAsB;AACtB,IAAAC,MAAoB;AACpB;AAEA,IAAM,oBAAgB,4BAAU,mCAAQ;AAcjC,IAAM,iBAAN,MAAM,gBAAe;AAAA,MACT;AAAA,MACA;AAAA,MACA;AAAA,MAEjB,YAAY,QAA8B;AACxC,aAAK,YAAY,OAAO;AACxB,aAAK,WAAW,OAAO;AACvB,aAAK,uBAAuB,OAAO;AAAA,MACrC;AAAA;AAAA,MAGA,OAAgB,oBAAoB;AAAA,QAClC;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,MACF;AAAA;AAAA,MAGA,MAAM,aAA4B;AAChC,kBAAU,KAAK,SAAS;AAAA,MAC1B;AAAA;AAAA;AAAA;AAAA;AAAA,MAMA,MAAM,yBAAwC;AAC5C,kBAAU,KAAK,SAAS;AAGxB,YAAI,KAAK,sBAAsB;AAC7B,kBAAQ,IAAI,wCAAwC,KAAK,oBAAoB,EAAE;AAC/E,6BAAmB,oBAAoB,KAAK,oBAAoB;AAChE,6BAAmB,mBAAmB,KAAK,oBAAoB;AAAA,QACjE;AAEA,mBAAW,eAAe,gBAAe,mBAAmB;AAC1D,gBAAM,WAAgB,WAAK,KAAK,WAAW,WAAW;AACtD,gBAAM,cAAmB,WAAK,UAAU,cAAc;AAGtD,gBAAM,WAAW,QAAQ,IAAI,yBAAyB,MAAM;AAC5D,gBAAM,eAAe,KAAK,wBAAwB,CAAC;AAGnD,cAAO,eAAW,WAAW,GAAG;AAC9B,gBAAI,CAAC,cAAc;AAEjB,sBAAQ,IAAI,oBAAoB,WAAW,2CAAsC;AACjF;AAAA,YACF;AAEA,kBAAM,YAAY,KAAK,qBAAqB,WAAW;AACvD,gBAAI,aAAa,CAAC,cAAc,SAAS,GAAG;AAC1C,sBAAQ,IAAI,oBAAoB,WAAW,wCAAmC;AAC9E;AAAA,YACF;AAAA,UACF;AAEA,cAAI;AAEF,gBAAI,cAAc;AAChB,oBAAM,SAAS,KAAK,qBAAqB,WAAW;AACpD,kBAAI,QAAQ;AACV,wBAAQ,IAAI,oBAAoB,WAAW,mCAA8B;AACzE,sBAAM,KAAK,qBAAqB,WAAW;AAC3C;AAAA,cACF;AAAA,YACF;AAEA,oBAAQ,IAAI,oBAAoB,WAAW,6BAAwB;AACnE,kBAAM,KAAK,eAAe,WAAW;AAAA,UACvC,SAAS,KAAK;AACZ,kBAAM,MAAM,eAAe,QAAQ,IAAI,UAAU,OAAO,GAAG;AAE3D,gBAAI,gBAAgB,kBAAkB;AACpC,oBAAM,IAAI,MAAM,oBAAoB,WAAW,uBAAuB,GAAG,EAAE;AAAA,YAC7E;AACA,oBAAQ,MAAM,sCAAsC,WAAW,KAAK,GAAG,EAAE;AAAA,UAC3E;AAAA,QACF;AAAA,MACF;AAAA,MAEQ,qBAAqB,aAAoC;AAC/D,YAAI,CAAC,KAAK,qBAAsB,QAAO;AACvC,cAAM,YAAY,YAAY,QAAQ,cAAc,EAAE;AAEtD,mBAAW,WAAW,CAAC,WAAW,SAAS,SAAS,IAAI,UAAU,QAAQ,UAAU,EAAE,CAAC,GAAG;AACxF,gBAAM,YAAiB,WAAK,KAAK,sBAAsB,OAAO;AAC9D,cAAO,eAAgB,WAAK,WAAW,cAAc,CAAC,GAAG;AACvD,gBAAI;AACF,oBAAM,MAAM,KAAK,MAAS,iBAAkB,WAAK,WAAW,cAAc,GAAG,OAAO,CAAC;AACrF,kBAAI,IAAI,SAAS,YAAa,QAAO;AAAA,YACvC,QAAQ;AAAA,YAAe;AAAA,UACzB;AAAA,QACF;AACA,eAAO;AAAA,MACT;AAAA;AAAA,MAGA,MAAM,eAAe,SAA6D;AAEhF,cAAM,SAAY,gBAAiB,WAAQ,WAAO,GAAG,yBAAyB,CAAC;AAE/E,YAAI;AACF,gBAAM,cAAc,OAAO,CAAC,QAAQ,SAAS,MAAM,MAAM,GAAG,EAAE,SAAS,IAAO,CAAC;AAG/E,gBAAM,eAAoB,WAAK,QAAQ,SAAS;AAChD,gBAAM,cAAiB,eAAgB,WAAK,cAAc,cAAc,CAAC,IAChE,WAAK,cAAc,cAAc,IACjC,WAAK,QAAQ,cAAc;AAEpC,cAAI,CAAI,eAAW,WAAW,GAAG;AAC/B,kBAAM,IAAI,MAAM,sCAAsC;AAAA,UACxD;AAEA,gBAAM,UAAU,KAAK,MAAS,iBAAa,aAAa,OAAO,CAAC;AAOhE,cAAI,CAAC,QAAQ,UAAU,QAAQ;AAC7B,kBAAM,IAAI,MAAM,WAAW,QAAQ,IAAI,kCAAkC;AAAA,UAC3E;AAGA,gBAAM,YAAiB,WAAK,KAAK,WAAW,QAAQ,IAAI;AAGxD,UAAG,WAAO,WAAW,EAAE,WAAW,MAAM,OAAO,KAAK,CAAC;AACrD,oBAAU,SAAS;AAGnB,gBAAM,YAAiB,cAAQ,WAAW;AAC1C,UAAG,iBAAa,aAAkB,WAAK,WAAW,cAAc,CAAC;AAGjE,gBAAM,aAAkB,WAAK,WAAW,MAAM;AAC9C,cAAO,eAAW,UAAU,GAAG;AAC7B,6BAAiB,YAAiB,WAAK,WAAW,MAAM,CAAC;AAAA,UAC3D;AAGA,4BAAkB,SAAS,WAAW,SAAS;AAE/C,iBAAO,EAAE,MAAM,QAAQ,MAAM,SAAS,QAAQ,QAAQ;AAAA,QACxD,UAAE;AACA,UAAG,WAAO,QAAQ,EAAE,WAAW,MAAM,OAAO,KAAK,CAAC;AAAA,QACpD;AAAA,MACF;AAAA;AAAA;AAAA;AAAA;AAAA,MAMA,MAAM,QAAQ,aAAqB,SAA8D;AAC/F,YAAI,KAAK,sBAAsB;AAE7B,gBAAM,mBAAmB,YAAY,QAAQ,cAAc,EAAE;AAC7D,gBAAM,YAAiB,WAAK,KAAK,sBAAsB,gBAAgB;AACvE,cAAO,eAAgB,WAAK,WAAW,cAAc,CAAC,GAAG;AACvD,mBAAO,KAAK,qBAAqB,WAAW;AAAA,UAC9C;AAAA,QACF;AACA,eAAO,KAAK,eAAe,aAAa,OAAO;AAAA,MACjD;AAAA;AAAA;AAAA;AAAA;AAAA,MAMA,MAAM,qBAAqB,aAAiE;AAC1F,YAAI,CAAC,KAAK,sBAAsB;AAC9B,gBAAM,IAAI,MAAM,6CAA6C;AAAA,QAC/D;AAEA,cAAM,mBAAmB,YAAY,QAAQ,cAAc,EAAE;AAC7D,cAAM,YAAiB,WAAK,KAAK,sBAAsB,gBAAgB;AACvE,cAAM,gBAAqB,WAAK,WAAW,cAAc;AAEzD,YAAI,CAAI,eAAW,aAAa,GAAG;AACjC,gBAAM,IAAI,MAAM,gCAAgC,SAAS,EAAE;AAAA,QAC7D;AAEA,cAAM,UAAe,WAAK,WAAW,MAAM;AAC3C,YAAI,CAAI,eAAW,OAAO,GAAG;AAC3B,gBAAM,IAAI,MAAM,GAAG,WAAW,0DAAqD;AAAA,QACrF;AAGA,cAAM,YAAiB,WAAK,KAAK,WAAW,WAAW;AAEvD,QAAG,WAAO,WAAW,EAAE,WAAW,MAAM,OAAO,KAAK,CAAC;AACrD,kBAAU,SAAS;AAGnB,cAAM,UAAU,KAAK,MAAS,iBAAa,eAAe,OAAO,CAAC;AAClE,cAAM,cAAc,kBAAkB,OAAO;AAC7C,QAAG,kBAAmB,WAAK,WAAW,cAAc,GAAG,KAAK,UAAU,aAAa,MAAM,CAAC,CAAC;AAE3F,yBAAiB,SAAc,WAAK,WAAW,MAAM,CAAC;AAGtD,0BAAkB,SAAS,WAAW,SAAS;AAG/C,QAAG,kBAAmB,WAAK,WAAW,iBAAiB,GAAG,WAAW;AAGrE,YAAI;AACF,gBAAM,cAAc,OAAO,CAAC,WAAW,cAAc,wBAAwB,GAAG;AAAA,YAC9E,KAAK;AAAA,YACL,SAAS;AAAA,UACX,CAAC;AAAA,QACH,QAAQ;AAAA,QAER;AAEA,eAAO,EAAE,MAAM,QAAQ,MAAM,SAAS,QAAQ,QAAQ;AAAA,MACxD;AAAA;AAAA,MAGA,MAAM,eAAe,aAAqB,SAA8D;AACtG,cAAM,SAAY,gBAAiB,WAAQ,WAAO,GAAG,qBAAqB,CAAC;AAE3E,cAAM,cAAc,UAAU,GAAG,WAAW,IAAI,OAAO,KAAK;AAC5D,cAAM,OAAO,CAAC,QAAQ,aAAa,sBAAsB,MAAM;AAC/D,YAAI,KAAK,UAAU;AACjB,eAAK,KAAK,cAAc,KAAK,QAAQ;AAAA,QACvC;AAEA,gBAAQ,IAAI,6BAA6B,WAAW,WAAM,MAAM,EAAE;AAElE,YAAI;AACF,gBAAM,EAAE,OAAO,IAAI,MAAM,cAAc,OAAO,MAAM;AAAA,YAClD,SAAS;AAAA,UACX,CAAC;AAED,gBAAM,WAAc,gBAAY,MAAM,EAAE,OAAO,OAAK,EAAE,SAAS,MAAM,CAAC;AACtE,kBAAQ,IAAI,qCAAqC,OAAO,KAAK,CAAC,eAAe,SAAS,KAAK,IAAI,CAAC,EAAE;AAClG,cAAI,SAAS,WAAW,GAAG;AACzB,kBAAM,IAAI,MAAM,qCAAqC,WAAW,aAAa,OAAO,KAAK,CAAC,EAAE;AAAA,UAC9F;AAEA,gBAAM,UAAe,WAAK,QAAQ,SAAS,CAAC,CAAE;AAC9C,gBAAM,SAAS,MAAM,KAAK,eAAe,OAAO;AAChD,kBAAQ,IAAI,2CAA2C,OAAO,IAAI,IAAI,OAAO,OAAO,WAAW,WAAK,KAAK,WAAW,OAAO,IAAI,CAAC,EAAE;AAGlI,gBAAM,YAAiB,WAAK,KAAK,WAAW,OAAO,IAAI;AACvD,UAAG,kBAAmB,WAAK,WAAW,iBAAiB,GAAG,KAAK;AAE/D,iBAAO;AAAA,QACT,UAAE;AAEA,UAAG,WAAO,QAAQ,EAAE,WAAW,MAAM,OAAO,KAAK,CAAC;AAAA,QACpD;AAAA,MACF;AAAA;AAAA,MAGA,MAAM,UAAU,aAAoC;AAElD,cAAM,WAAgB,WAAK,KAAK,WAAW,WAAW;AACtD,YAAO,eAAW,QAAQ,GAAG;AAC3B,UAAG,WAAO,UAAU,EAAE,WAAW,MAAM,OAAO,KAAK,CAAC;AACpD;AAAA,QACF;AAEA,cAAM,YAAiB,WAAK,KAAK,WAAW,YAAY,QAAQ,aAAa,EAAE,CAAC;AAChF,YAAO,eAAW,SAAS,GAAG;AAC5B,UAAG,WAAO,WAAW,EAAE,WAAW,MAAM,OAAO,KAAK,CAAC;AAAA,QACvD;AAAA,MACF;AAAA;AAAA,MAGA,gBAAoC;AAClC,YAAI,CAAI,eAAW,KAAK,SAAS,EAAG,QAAO,CAAC;AAG5C,cAAM,cAAwB,CAAC;AAC/B,mBAAW,SAAY,gBAAY,KAAK,WAAW,EAAE,eAAe,KAAK,CAAC,GAAG;AAC3E,cAAI,CAAC,MAAM,YAAY,EAAG;AAC1B,cAAI,MAAM,KAAK,WAAW,GAAG,GAAG;AAE9B,kBAAM,WAAgB,WAAK,KAAK,WAAW,MAAM,IAAI;AACrD,uBAAW,SAAY,gBAAY,UAAU,EAAE,eAAe,KAAK,CAAC,GAAG;AACrE,kBAAI,MAAM,YAAY,EAAG,aAAY,KAAU,WAAK,UAAU,MAAM,IAAI,CAAC;AAAA,YAC3E;AAAA,UACF,OAAO;AACL,wBAAY,KAAU,WAAK,KAAK,WAAW,MAAM,IAAI,CAAC;AAAA,UACxD;AAAA,QACF;AAEA,eAAO,YACJ,IAAI,SAAO;AACV,gBAAM,UAAe,WAAK,KAAK,cAAc;AAC7C,cAAI,CAAI,eAAW,OAAO,EAAG,QAAO;AACpC,cAAI;AACF,kBAAM,MAAM,KAAK,MAAS,iBAAa,SAAS,OAAO,CAAC;AAKxD,gBAAI,CAAC,IAAI,UAAU,OAAQ,QAAO;AAClC,kBAAM,aAAkB,WAAK,KAAK,iBAAiB;AACnD,kBAAM,gBAAmB,eAAW,UAAU,IACvC,iBAAa,YAAY,OAAO,EAAE,KAAK,IAC1C;AACJ,kBAAM,SAA2B,EAAE,MAAM,IAAI,MAAM,SAAS,IAAI,SAAS,KAAK,GAAI,gBAAgB,EAAE,cAAc,IAAI,CAAC,EAAG;AAC1H,mBAAO;AAAA,UACT,QAAQ;AACN,mBAAO;AAAA,UACT;AAAA,QACF,CAAC,EACA,OAAO,CAAC,SAAmC,SAAS,IAAI;AAAA,MAC7D;AAAA;AAAA,MAGA,YAAY,aAA8B;AAExC,YAAO,eAAgB,WAAK,KAAK,WAAW,aAAa,cAAc,CAAC,EAAG,QAAO;AAClF,cAAM,SAAS,YAAY,QAAQ,aAAa,EAAE;AAClD,eAAU,eAAgB,WAAK,KAAK,WAAW,QAAQ,cAAc,CAAC;AAAA,MACxE;AAAA;AAAA,MAGA,oBAAoB,aAA8C;AAChE,YAAI,UAAe,WAAK,KAAK,WAAW,aAAa,cAAc;AACnE,YAAI,CAAI,eAAW,OAAO,GAAG;AAC3B,oBAAe,WAAK,KAAK,WAAW,YAAY,QAAQ,aAAa,EAAE,GAAG,cAAc;AAAA,QAC1F;AACA,YAAI,CAAI,eAAW,OAAO,EAAG,QAAO;AACpC,YAAI;AACF,gBAAM,MAAM,KAAK,MAAS,iBAAa,SAAS,OAAO,CAAC;AACxD,iBAAO,EAAE,MAAM,IAAI,MAAM,SAAS,IAAI,SAAS,KAAU,cAAQ,OAAO,EAAE;AAAA,QAC5E,QAAQ;AACN,iBAAO;AAAA,QACT;AAAA,MACF;AAAA,IACF;AAAA;AAAA;;;ACrWA,IAAAC,MAAoB;AACpB,IAAAC,MAAoB;AACpB,IAAAC,QAAsB;;;ACftB,gCAAyC;AAYlC,IAAM,uBAAN,MAA2D;AAAA,EAGhE,YACmB,YACjB;AADiB;AAAA,EAChB;AAAA,EAJc,YAAY,oBAAI,IAA4B;AAAA,EAM7D,MAAM,MAAM,QAAuD;AACjE,UAAM,YAAQ,iCAAM,OAAO,SAAS,CAAC,GAAI,OAAO,QAAQ,CAAC,CAAE,GAAG;AAAA,MAC5D,KAAK,OAAO;AAAA,MACZ,KAAK,OAAO,MAAM,EAAE,GAAG,QAAQ,KAAK,GAAG,OAAO,IAAI,IAAI;AAAA,MACtD,OAAO,CAAC,QAAQ,QAAQ,MAAM;AAAA,IAChC,CAAC;AAED,UAAM,UAAU,IAAI,eAAe,OAAO,QAAQ,KAAK,UAAU;AACjE,SAAK,UAAU,IAAI,MAAM,KAAM,OAAO;AAEtC,SAAK,WAAW;AAAA,MACd,MAAM;AAAA,MACN,KAAK,MAAM;AAAA,MACX,MAAM,OAAO;AAAA,MACb,SAAS,OAAO;AAAA,IAClB,CAAC;AAED,UAAM,GAAG,QAAQ,CAAC,SAAS;AACzB,WAAK,WAAW;AAAA,QACd,MAAM;AAAA,QACN,KAAK,MAAM;AAAA,QACX;AAAA,MACF,CAAC;AAED,UAAI,OAAO,eAAe,QAAQ,gBAAgB,OAAO,eAAe,IAAI;AAC1E,gBAAQ;AACR,mBAAW,MAAM;AACf,eAAK,MAAM,MAAM,EAAE,MAAM,MAAM;AAAA,UAAC,CAAC;AAAA,QACnC,GAAG,GAAI;AAAA,MACT;AAAA,IACF,CAAC;AAED,WAAO;AAAA,EACT;AAAA,EAEA,gBAA2C;AACzC,WAAO,CAAC,GAAG,KAAK,UAAU,OAAO,CAAC,EAAE,IAAI,CAAC,MAAM,EAAE,OAAO,CAAC;AAAA,EAC3D;AAAA,EAEA,iBAAqC;AACnC,UAAM,MAAM,QAAQ,YAAY;AAChC,UAAM,MAAM,QAAQ,SAAS;AAC7B,WAAO;AAAA,MACL,KAAK,QAAQ;AAAA,MACb,aAAa,IAAI,OAAO,IAAI,UAAU;AAAA,MACtC,WAAW,IAAI;AAAA,MACf,UAAU,IAAI;AAAA,MACd,eAAe,KAAK,MAAM,QAAQ,OAAO,CAAC;AAAA,MAC1C,cAAc;AAAA,MACd,OAAO;AAAA,IACT;AAAA,EACF;AAAA,EAEA,MAAM,UAAyB;AAC7B,eAAW,CAAC,EAAE,IAAI,KAAK,KAAK,WAAW;AACrC,WAAK,KAAK,SAAS;AAAA,IACrB;AACA,SAAK,UAAU,MAAM;AAAA,EACvB;AACF;AAEA,IAAM,iBAAN,MAAmD;AAAA,EAQjD,YACmB,OACA,QACA,YACjB;AAHiB;AACA;AACA;AAEjB,SAAK,MAAM,MAAM;AACjB,SAAK,OAAO,OAAO;AAEnB,UAAM,GAAG,QAAQ,CAAC,SAAS;AACzB,iBAAW,WAAW,KAAK,aAAc,SAAQ,IAAI;AAAA,IACvD,CAAC;AAED,UAAM,GAAG,SAAS,CAAC,QAAQ;AACzB,iBAAW,WAAW,KAAK,cAAe,SAAQ,GAAG;AAAA,IACvD,CAAC;AAAA,EACH;AAAA,EAtBS;AAAA,EACA;AAAA,EACT,eAAe;AAAA,EACE,YAAY,KAAK,IAAI;AAAA,EAC9B,eAAqD,CAAC;AAAA,EACtD,gBAA+C,CAAC;AAAA,EAmBxD,WAA+B;AAC7B,WAAO;AAAA,MACL,KAAK,KAAK;AAAA,MACV,YAAY;AAAA,MACZ,WAAW;AAAA,MACX,eAAe,KAAK,OAAO,KAAK,IAAI,IAAI,KAAK,aAAa,GAAI;AAAA,MAC9D,cAAc,KAAK;AAAA,MACnB,OAAO,KAAK,MAAM,aAAa,OAAO,YAAY;AAAA,IACpD;AAAA,EACF;AAAA,EAEA,MAAM,MAAoB;AACxB,SAAK,MAAM,OAAO,MAAM,IAAI;AAAA,EAC9B;AAAA,EAEA,IAAI,SAAgC;AAClC,WAAO,KAAK,MAAM;AAAA,EACpB;AAAA,EAEA,IAAI,SAAgC;AAClC,WAAO,KAAK,MAAM;AAAA,EACpB;AAAA,EAEA,KAAK,SAAyB,WAAiB;AAC7C,SAAK,MAAM,KAAK,MAAM;AAAA,EACxB;AAAA,EAEA,OAAgE;AAC9D,QAAI,KAAK,MAAM,aAAa,MAAM;AAChC,aAAO,QAAQ,QAAQ,EAAE,MAAM,KAAK,MAAM,UAAU,QAAQ,KAAK,CAAC;AAAA,IACpE;AACA,WAAO,IAAI,QAAQ,CAACC,aAAY;AAC9B,WAAK,MAAM,GAAG,QAAQ,CAAC,MAAM,WAAW;AACtC,QAAAA,SAAQ,EAAE,MAAM,OAAO,CAAC;AAAA,MAC1B,CAAC;AAAA,IACH,CAAC;AAAA,EACH;AAAA,EAEA,OAAO,SAA8C;AACnD,SAAK,aAAa,KAAK,OAAO;AAAA,EAChC;AAAA,EAEA,QAAQ,SAAuC;AAC7C,SAAK,cAAc,KAAK,OAAO;AAAA,EACjC;AAAA,EAEA,SAAyB;AACvB,WAAO;AAAA,MACL,KAAK,KAAK;AAAA,MACV,MAAM,KAAK;AAAA,MACX,SAAS,KAAK,OAAO;AAAA,MACrB,OAAO,KAAK,MAAM,aAAa,OAAO,YAAY;AAAA,MAClD,YAAY;AAAA,MACZ,WAAW;AAAA,MACX,eAAe,KAAK,OAAO,KAAK,IAAI,IAAI,KAAK,aAAa,GAAI;AAAA,IAChE;AAAA,EACF;AACF;;;AD/IA,eAAe,OAAsB;AACnC,QAAM,SAAS,QAAQ,IAAI;AAC3B,QAAM,QAAQ,QAAQ,IAAI,yBAAyB;AACnD,QAAM,UAAU,QAAQ,IAAI;AAC5B,QAAM,WAAW,QAAQ,IAAI;AAC7B,QAAM,UAAU,QAAQ,IAAI,qBAAqB,wBAAwB,OAAO;AAChF,QAAM,cAAc,KAAK,MAAM,QAAQ,IAAI,yBAAyB,IAAI;AACxE,QAAM,gBAAgB,KAAK,MAAM,QAAQ,IAAI,2BAA2B,IAAI;AAE5E,MAAI,CAAC,UAAU,CAAC,WAAW,CAAC,UAAU;AACpC,YAAQ,MAAM,oGAAoG;AAClH,YAAQ,KAAK,CAAC;AAAA,EAChB;AAEA,QAAM,WAAW,UAAU,OAAO,IAAI,QAAQ,GAAG;AAGjD,QAAM,EAAE,kBAAkB,gBAAgB,OAAO,IAAI,MAAM,OAAO,cAAc;AAChF,QAAM,aAAa,MAAM,OAAO,WAAW,GAAG;AAE9C,QAAM,WAAW,eAAe;AAAA,IAC9B,KAAK;AAAA,IACL,kBAAkB,OAAO,EAAE,MAAM;AAAA,EACnC,CAAC;AAED,QAAM,MAAM,iBAAsB;AAAA,IAChC,OAAO,CAAC,OAAO,EAAE,QAAQ,UAAU,aAAa,UAAU,CAAC,CAAC;AAAA,EAC9D,CAAC;AAGD,MAAI;AACF,UAAO,IAAY,MAAM,SAAS,OAAO;AAAA,MACvC,IAAI;AAAA,MACJ,MAAM;AAAA,MACN,cAAc,CAAC;AAAA,MACf,UAAa,aAAS;AAAA,MACtB,MAAS,SAAK;AAAA,MACd,UAAa,SAAK,EAAE;AAAA,MACpB,UAAU,KAAK,MAAS,aAAS,IAAI,OAAO,IAAI;AAAA,MAChD,gBAAgB,CAAC;AAAA,MACjB,iBAAiB,CAAC,OAAO;AAAA,MACzB,WAAW,CAAC;AAAA,MACZ,MAAS,aAAS;AAAA,MAClB,MAAM;AAAA,MACN,UAAU;AAAA,IACZ,CAAC;AACD,YAAQ,IAAI,WAAW,OAAO,4BAA4B,QAAQ,EAAE;AAAA,EACtE,SAAS,KAAK;AACZ,YAAQ,MAAM,WAAW,OAAO,yBAAyB,eAAe,QAAQ,IAAI,UAAU,GAAG;AACjG,YAAQ,KAAK,CAAC;AAAA,EAChB;AAGA,WAAS,mBAAmB,OAAyC;AACnE,UAAM,UAAU,CAAC,OAAe,SAAiBC,aAAsC;AACrF,UAAI,QAAQ,MAAM;AAChB,gBAAQ,KAAK,EAAE,MAAM,OAAO,OAAO,SAAS,SAAAA,SAAQ,CAAC;AAAA,MACvD,OAAO;AAEL,cAAM,SAAS,IAAI,MAAM,KAAK,GAAG,CAAC;AAClC,YAAI,UAAU,QAAS,SAAQ,MAAM,QAAQ,SAASA,YAAW,EAAE;AAAA,iBAC1D,UAAU,OAAQ,SAAQ,KAAK,QAAQ,SAASA,YAAW,EAAE;AAAA,iBAC7D,UAAU,QAAS,SAAQ,MAAM,QAAQ,SAASA,YAAW,EAAE;AAAA,YACnE,SAAQ,IAAI,QAAQ,SAASA,YAAW,EAAE;AAAA,MACjD;AAAA,IACF;AACA,WAAO;AAAA,MACL,MAAM,CAAC,KAAa,QAAkC,QAAQ,QAAQ,KAAK,GAAG;AAAA,MAC9E,MAAM,CAAC,KAAa,QAAkC,QAAQ,QAAQ,KAAK,GAAG;AAAA,MAC9E,OAAO,CAAC,KAAa,QAAkC,QAAQ,SAAS,KAAK,GAAG;AAAA,MAChF,OAAO,CAAC,KAAa,QAAkC,QAAQ,SAAS,KAAK,GAAG;AAAA,MAChF,OAAO,CAAC,eAAuB,mBAAmB,CAAC,GAAG,OAAO,UAAU,CAAC;AAAA,IAC1E;AAAA,EACF;AACA,QAAM,SAAS,mBAAmB,CAAC,OAAO,CAAC;AAG3C,QAAM,iBAAiB,IAAI,qBAAqB,MAAM;AAAA,EAAC,CAAC;AAGxD,QAAM,cAAmB,WAAK,UAAU,cAAc;AACtD,QAAM,UAAU,KAAK,MAAS,iBAAa,aAAa,OAAO,CAAC;AAChE,QAAM,WAAW,QAAQ;AACzB,MAAI,CAAC,UAAU,QAAQ,QAAQ;AAC7B,YAAQ,MAAM,WAAW,OAAO,mCAAmC,WAAW,EAAE;AAChF,YAAQ,KAAK,CAAC;AAAA,EAChB;AAEA,QAAM,cAAc,SAAS,OAAO,KAAK,CAAC,MAAsB,EAAE,OAAO,OAAO;AAChF,MAAI,CAAC,aAAa;AAChB,YAAQ,MAAM,WAAW,OAAO,YAAY,OAAO,yBAAyB;AAC5E,YAAQ,KAAK,CAAC;AAAA,EAChB;AAEA,QAAM,YAAY,YAAY,MAC3B,QAAQ,SAAS,EAAE,EACnB,QAAQ,UAAU,OAAO,EACzB,QAAQ,SAAS,KAAK;AACzB,MAAI,YAAiB,cAAQ,UAAU,SAAS;AAChD,MAAI,CAAI,eAAW,SAAS,GAAG;AAE7B,UAAM,UAAU,UAAU,QAAQ,SAAS,MAAM;AACjD,QAAO,eAAW,OAAO,EAAG,aAAY;AAAA,EAC1C;AAEA,QAAM,MAAM,MAAM,OAAO;AACzB,QAAM,WAAW,OAAO,KAAK,GAAG,EAAE,CAAC;AACnC,QAAM,aAAa,IAAI,SAAS,WAAW,IAAI,YAAY,WAAW,IAAI,QAAQ,IAAI;AACtF,MAAI,OAAO,eAAe,YAAY;AACpC,YAAQ,MAAM,WAAW,OAAO,6BAA6B,SAAS,EAAE;AACxE,YAAQ,KAAK,CAAC;AAAA,EAChB;AAEA,QAAM,QAAwB,IAAI,WAAW;AAG7C,QAAM,UAAwB;AAAA,IAC5B,IAAI;AAAA,IACJ;AAAA,IACA;AAAA,IACA;AAAA,IACA,SAAS;AAAA,IACT;AAAA,IACA;AAAA;AAAA,IAEA,UAAU,EAAE,MAAM,MAAM;AAAA,IAAC,GAAG,WAAW,MAAM,MAAM;AAAA,IAAC,GAAG,WAAW,MAAM,CAAC,EAAE;AAAA,IAC3E,SAAS,CAAC;AAAA,IACV,QAAQ,EAAE,KAAK,MAAM,QAAW,KAAK,YAAY;AAAA,IAAC,EAAE;AAAA,EACtD;AAEA,QAAM,MAAM,WAAW,OAAO;AAC9B,UAAQ,IAAI,WAAW,OAAO,qBAAqB;AAGnD,QAAM,oBAAoB,YAAY,YAAY;AAChD,QAAI;AACF,YAAM,MAAM,QAAQ,YAAY;AAChC,YAAM,WAAW,eAAe,cAAc,EAAE,IAAI,QAAM;AAAA,QACxD,KAAK,EAAE;AAAA,QACP,MAAM,EAAE;AAAA,QACR,SAAS,EAAE;AAAA,QACX,OAAO,EAAE;AAAA,QACT,YAAY,EAAE;AAAA,QACd,WAAW,EAAE;AAAA,QACb,eAAe,EAAE;AAAA,MACnB,EAAE;AAEF,YAAO,IAAY,MAAM,UAAU,OAAO;AAAA,QACxC,SAAS;AAAA,QACT,YAAY;AAAA,QACZ,cAAc,KAAK,MAAM,IAAI,MAAM,OAAO,IAAI;AAAA,QAC9C,aAAa;AAAA,QACb,cAAc;AAAA,MAChB,CAAC;AAAA,IACH,QAAQ;AAAA,IAER;AAAA,EACF,GAAG,GAAM;AAGT,MAAI;AACF;AAAC,IAAC,IAAY,MAAM,iBAAiB,UAAU,QAAW;AAAA,MACxD,QAAQ,OAAO,SAAiE;AAC9E,YAAI;AACF,cAAI;AACJ,cAAI,KAAK,aAAa,iBAAiB;AAErC,kBAAM,EAAE,gBAAAC,gBAAe,IAAI,MAAM;AACjC,kBAAM,YAAY,IAAIA,gBAAe,EAAE,WAAgB,cAAQ,QAAQ,EAAE,CAAC;AAC1E,kBAAM,UAAU,KAAK;AACrB,qBAAS,MAAM,UAAU,eAAe,QAAQ,SAAS,QAAQ,OAAO;AAAA,UAC1E,WAAW,OAAQ,MAAc,eAAe,YAAY;AAC1D,qBAAS,MAAO,MAAc,WAAW,KAAK,UAAU,KAAK,OAAO;AAAA,UACtE;AACA,gBAAO,IAAY,MAAM,iBAAiB,OAAO;AAAA,YAC/C,QAAQ,KAAK;AAAA,YAAQ,SAAS;AAAA,YAAM;AAAA,UACtC,CAAC;AAAA,QACH,SAAS,KAAK;AACZ,gBAAO,IAAY,MAAM,iBAAiB,OAAO;AAAA,YAC/C,QAAQ,KAAK;AAAA,YAAQ,SAAS;AAAA,YAC9B,OAAO,eAAe,QAAQ,IAAI,UAAU,OAAO,GAAG;AAAA,UACxD,CAAC;AAAA,QACH;AAAA,MACF;AAAA,IACF,CAAC;AAAA,EACH,QAAQ;AAAA,EAER;AAGA,QAAM,WAAW,YAAY;AAC3B,kBAAc,iBAAiB;AAC/B,UAAM,eAAe,QAAQ;AAC7B,UAAM,MAAM,SAAS;AACrB,aAAS,MAAM;AACf,YAAQ,KAAK,CAAC;AAAA,EAChB;AAEA,UAAQ,GAAG,WAAW,MAAM,SAAS,EAAE,MAAM,MAAM,QAAQ,KAAK,CAAC,CAAC,CAAC;AACnE,UAAQ,GAAG,UAAU,MAAM,SAAS,EAAE,MAAM,MAAM,QAAQ,KAAK,CAAC,CAAC,CAAC;AAGlE,UAAQ,OAAO,EAAE,MAAM,QAAQ,CAAC;AAClC;AAGA,QAAQ,GAAG,qBAAqB,CAAC,QAAQ;AACvC,UAAQ,MAAM,gCAAgC,IAAI,SAAS,IAAI,KAAK;AACtE,CAAC;AAED,QAAQ,GAAG,sBAAsB,CAAC,WAAW;AAC3C,QAAM,MAAM,kBAAkB,QAAQ,OAAO,UAAU,OAAO,MAAM;AACpE,UAAQ,MAAM,iCAAiC,GAAG;AACpD,CAAC;AAED,KAAK,EAAE,MAAM,CAAC,QAAQ;AACpB,UAAQ,MAAM,yBAAyB,GAAG;AAC1C,UAAQ,KAAK,CAAC;AAChB,CAAC;","names":["import_node_child_process","import_node_child_process","fs","path","os","os","fs","path","resolve","context","AddonInstaller"]}
@@ -1,12 +1,8 @@
1
1
  import {
2
- require_worker_process_manager
3
- } from "../chunk-RHK5CCAL.mjs";
4
- import {
5
- __toESM
6
- } from "../chunk-LZOMFHX3.mjs";
2
+ WorkerProcessManager
3
+ } from "../chunk-S5YWNNPK.mjs";
7
4
 
8
5
  // src/worker/addon-worker-entry.ts
9
- var import_worker_process_manager = __toESM(require_worker_process_manager());
10
6
  import * as os from "os";
11
7
  import * as fs from "fs";
12
8
  import * as path from "path";
@@ -74,7 +70,7 @@ async function boot() {
74
70
  };
75
71
  }
76
72
  const logger = createScopedLogger([addonId]);
77
- const processManager = new import_worker_process_manager.WorkerProcessManager(() => {
73
+ const processManager = new WorkerProcessManager(() => {
78
74
  });
79
75
  const pkgJsonPath = path.join(addonDir, "package.json");
80
76
  const pkgJson = JSON.parse(fs.readFileSync(pkgJsonPath, "utf-8"));
@@ -149,7 +145,7 @@ async function boot() {
149
145
  try {
150
146
  let result;
151
147
  if (task.taskType === "addon.install") {
152
- const { AddonInstaller } = await import("../addon-installer-WQBOEZQT.mjs");
148
+ const { AddonInstaller } = await import("../addon-installer-2BW2KLQD.mjs");
153
149
  const installer = new AddonInstaller({ addonsDir: path.dirname(addonDir) });
154
150
  const payload = task.payload;
155
151
  result = await installer.installFromNpm(payload.package, payload.version);
@@ -1 +1 @@
1
- {"version":3,"sources":["../../src/worker/addon-worker-entry.ts"],"sourcesContent":["/**\n * Worker entry point — forked by AddonWorkerHost.\n * Connects to hub via tRPC WSS, loads addon, reports heartbeat.\n *\n * Boot config passed via environment variables:\n * CAMSTACK_WORKER_HUB_URL - WSS URL (e.g., wss://localhost:4443/trpc)\n * CAMSTACK_WORKER_TOKEN - Auth token\n * CAMSTACK_ADDON_ID - Addon to load\n * CAMSTACK_ADDON_DIR - Path to addon directory\n * CAMSTACK_ADDON_CONFIG - JSON-encoded addon config\n * CAMSTACK_DATA_DIR - Data directory for this addon\n * CAMSTACK_LOCATION_PATHS - JSON-encoded location paths\n */\nimport * as os from 'node:os'\nimport * as fs from 'node:fs'\nimport * as path from 'node:path'\nimport type { ICamstackAddon, AddonContext, IScopedLogger } from '@camstack/types'\nimport { WorkerProcessManager } from './worker-process-manager.js'\n\nasync function boot(): Promise<void> {\n const hubUrl = process.env.CAMSTACK_WORKER_HUB_URL\n const token = process.env.CAMSTACK_WORKER_TOKEN ?? ''\n const addonId = process.env.CAMSTACK_ADDON_ID\n const addonDir = process.env.CAMSTACK_ADDON_DIR\n const dataDir = process.env.CAMSTACK_DATA_DIR ?? `/tmp/camstack-worker-${addonId}`\n const addonConfig = JSON.parse(process.env.CAMSTACK_ADDON_CONFIG ?? '{}')\n const locationPaths = JSON.parse(process.env.CAMSTACK_LOCATION_PATHS ?? '{}')\n\n if (!hubUrl || !addonId || !addonDir) {\n console.error('[worker] Missing required env vars: CAMSTACK_WORKER_HUB_URL, CAMSTACK_ADDON_ID, CAMSTACK_ADDON_DIR')\n process.exit(1)\n }\n\n const workerId = `worker-${addonId}-${process.pid}`\n\n // 1. Create tRPC WSS client (must use superjson transformer to match server)\n const { createTRPCClient, createWSClient, wsLink } = await import('@trpc/client')\n const superjson = (await import('superjson')).default\n\n const wsClient = createWSClient({\n url: hubUrl,\n connectionParams: () => ({ token }),\n })\n\n const api = createTRPCClient<any>({\n links: [wsLink({ client: wsClient, transformer: superjson })],\n })\n\n // 2. Register with hub\n try {\n await (api as any).agent.register.mutate({\n id: workerId,\n name: addonId,\n capabilities: [],\n platform: os.platform(),\n arch: os.arch(),\n cpuCores: os.cpus().length,\n memoryMB: Math.round(os.totalmem() / 1024 / 1024),\n pythonRuntimes: [],\n installedAddons: [addonId],\n taskTypes: [],\n host: os.hostname(),\n port: 0,\n httpPort: 0,\n })\n console.log(`[worker:${addonId}] Registered with hub as ${workerId}`)\n } catch (err) {\n console.error(`[worker:${addonId}] Failed to register:`, err instanceof Error ? err.message : err)\n process.exit(1)\n }\n\n // 3. Build logger that routes structured logs via IPC to parent's LogManager\n function createScopedLogger(scope: readonly string[]): IScopedLogger {\n const sendLog = (level: string, message: string, context?: Record<string, unknown>) => {\n if (process.send) {\n process.send({ type: 'LOG', level, message, context })\n } else {\n // Fallback if IPC not available\n const prefix = `[${scope.join(':')}]`\n if (level === 'error') console.error(prefix, message, context ?? '')\n else if (level === 'warn') console.warn(prefix, message, context ?? '')\n else if (level === 'debug') console.debug(prefix, message, context ?? '')\n else console.log(prefix, message, context ?? '')\n }\n }\n return {\n info: (msg: string, ctx?: Record<string, unknown>) => sendLog('info', msg, ctx),\n warn: (msg: string, ctx?: Record<string, unknown>) => sendLog('warn', msg, ctx),\n error: (msg: string, ctx?: Record<string, unknown>) => sendLog('error', msg, ctx),\n debug: (msg: string, ctx?: Record<string, unknown>) => sendLog('debug', msg, ctx),\n child: (childScope: string) => createScopedLogger([...scope, childScope]),\n } as IScopedLogger\n }\n const logger = createScopedLogger([addonId])\n\n // 4. Create process manager for sub-processes (no-op sender since we use tRPC now)\n const processManager = new WorkerProcessManager(() => {})\n\n // 5. Load addon\n const pkgJsonPath = path.join(addonDir, 'package.json')\n const pkgJson = JSON.parse(fs.readFileSync(pkgJsonPath, 'utf-8'))\n const manifest = pkgJson.camstack\n if (!manifest?.addons?.length) {\n console.error(`[worker:${addonId}] No camstack addon manifest in ${pkgJsonPath}`)\n process.exit(1)\n }\n\n const declaration = manifest.addons.find((a: { id: string }) => a.id === addonId)\n if (!declaration) {\n console.error(`[worker:${addonId}] Addon \"${addonId}\" not found in manifest`)\n process.exit(1)\n }\n\n const entryFile = declaration.entry\n .replace(/^\\.\\//, '')\n .replace(/^src\\//, 'dist/')\n .replace(/\\.ts$/, '.js')\n let entryPath = path.resolve(addonDir, entryFile)\n if (!fs.existsSync(entryPath)) {\n // Try .cjs fallback\n const cjsPath = entryPath.replace(/\\.js$/, '.cjs')\n if (fs.existsSync(cjsPath)) entryPath = cjsPath\n }\n\n const mod = await import(entryPath)\n const firstKey = Object.keys(mod)[0] as string | undefined\n const AddonClass = mod.default?.default ?? mod.default ?? (firstKey ? mod[firstKey] : undefined)\n if (typeof AddonClass !== 'function') {\n console.error(`[worker:${addonId}] No addon class found in ${entryPath}`)\n process.exit(1)\n }\n\n const addon: ICamstackAddon = new AddonClass()\n\n // 6. Initialize addon with context.api = tRPC client\n const context: AddonContext = {\n id: addonId,\n api: api as unknown as AddonContext['api'],\n logger,\n addonConfig,\n process: processManager,\n dataDir,\n locationPaths,\n // Legacy fields — stubs for backward compat during migration\n eventBus: { emit: () => {}, subscribe: () => () => {}, getRecent: () => [] } as any,\n storage: {} as any,\n config: { get: () => undefined, set: async () => {} } as any,\n } as AddonContext\n\n await addon.initialize(context)\n console.log(`[worker:${addonId}] Addon initialized`)\n\n // 7. Heartbeat loop — includes sub-process stats\n const heartbeatInterval = setInterval(async () => {\n try {\n const mem = process.memoryUsage()\n const subProcs = processManager.listProcesses().map(p => ({\n pid: p.pid,\n name: p.name,\n command: p.command,\n state: p.state as 'running' | 'stopped' | 'crashed',\n cpuPercent: p.cpuPercent,\n memoryRss: p.memoryRss,\n uptimeSeconds: p.uptimeSeconds,\n }))\n\n await (api as any).agent.heartbeat.mutate({\n agentId: workerId,\n cpuPercent: 0,\n memoryUsedMB: Math.round(mem.rss / 1024 / 1024),\n activeTasks: 0,\n subProcesses: subProcs,\n })\n } catch {\n // heartbeat failure is non-fatal\n }\n }, 10_000)\n\n // 8. Listen for task assignments\n try {\n ;(api as any).agent.onTaskAssignment.subscribe(undefined, {\n onData: async (task: { taskId: string; taskType: string; payload: unknown }) => {\n try {\n let result: unknown\n if (task.taskType === 'addon.install') {\n // Handle addon install\n const { AddonInstaller } = await import('../addon-installer.js')\n const installer = new AddonInstaller({ addonsDir: path.dirname(addonDir) })\n const payload = task.payload as { package: string; version?: string }\n result = await installer.installFromNpm(payload.package, payload.version)\n } else if (typeof (addon as any).handleTask === 'function') {\n result = await (addon as any).handleTask(task.taskType, task.payload)\n }\n await (api as any).agent.reportTaskResult.mutate({\n taskId: task.taskId, success: true, result,\n })\n } catch (err) {\n await (api as any).agent.reportTaskResult.mutate({\n taskId: task.taskId, success: false,\n error: err instanceof Error ? err.message : String(err),\n })\n }\n },\n })\n } catch {\n // subscription failure — tasks won't be received but worker still functions\n }\n\n // 9. Graceful shutdown\n const shutdown = async () => {\n clearInterval(heartbeatInterval)\n await processManager.killAll()\n await addon.shutdown()\n wsClient.close()\n process.exit(0)\n }\n\n process.on('SIGTERM', () => shutdown().catch(() => process.exit(1)))\n process.on('SIGINT', () => shutdown().catch(() => process.exit(1)))\n\n // Signal ready to parent (if using IPC for boot coordination)\n process.send?.({ type: 'READY' })\n}\n\n// Handle uncaught errors\nprocess.on('uncaughtException', (err) => {\n console.error('[worker] Uncaught exception:', err.message, err.stack)\n})\n\nprocess.on('unhandledRejection', (reason) => {\n const msg = reason instanceof Error ? reason.message : String(reason)\n console.error('[worker] Unhandled rejection:', msg)\n})\n\nboot().catch((err) => {\n console.error('[worker] Boot failed:', err)\n process.exit(1)\n})\n"],"mappings":"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","names":["context"]}
1
+ {"version":3,"sources":["../../src/worker/addon-worker-entry.ts"],"sourcesContent":["/**\n * Worker entry point — forked by AddonWorkerHost.\n * Connects to hub via tRPC WSS, loads addon, reports heartbeat.\n *\n * Boot config passed via environment variables:\n * CAMSTACK_WORKER_HUB_URL - WSS URL (e.g., wss://localhost:4443/trpc)\n * CAMSTACK_WORKER_TOKEN - Auth token\n * CAMSTACK_ADDON_ID - Addon to load\n * CAMSTACK_ADDON_DIR - Path to addon directory\n * CAMSTACK_ADDON_CONFIG - JSON-encoded addon config\n * CAMSTACK_DATA_DIR - Data directory for this addon\n * CAMSTACK_LOCATION_PATHS - JSON-encoded location paths\n */\nimport * as os from 'node:os'\nimport * as fs from 'node:fs'\nimport * as path from 'node:path'\nimport type { ICamstackAddon, AddonContext, IScopedLogger } from '@camstack/types'\nimport { WorkerProcessManager } from './worker-process-manager.js'\n\nasync function boot(): Promise<void> {\n const hubUrl = process.env.CAMSTACK_WORKER_HUB_URL\n const token = process.env.CAMSTACK_WORKER_TOKEN ?? ''\n const addonId = process.env.CAMSTACK_ADDON_ID\n const addonDir = process.env.CAMSTACK_ADDON_DIR\n const dataDir = process.env.CAMSTACK_DATA_DIR ?? `/tmp/camstack-worker-${addonId}`\n const addonConfig = JSON.parse(process.env.CAMSTACK_ADDON_CONFIG ?? '{}')\n const locationPaths = JSON.parse(process.env.CAMSTACK_LOCATION_PATHS ?? '{}')\n\n if (!hubUrl || !addonId || !addonDir) {\n console.error('[worker] Missing required env vars: CAMSTACK_WORKER_HUB_URL, CAMSTACK_ADDON_ID, CAMSTACK_ADDON_DIR')\n process.exit(1)\n }\n\n const workerId = `worker-${addonId}-${process.pid}`\n\n // 1. Create tRPC WSS client (must use superjson transformer to match server)\n const { createTRPCClient, createWSClient, wsLink } = await import('@trpc/client')\n const superjson = (await import('superjson')).default\n\n const wsClient = createWSClient({\n url: hubUrl,\n connectionParams: () => ({ token }),\n })\n\n const api = createTRPCClient<any>({\n links: [wsLink({ client: wsClient, transformer: superjson })],\n })\n\n // 2. Register with hub\n try {\n await (api as any).agent.register.mutate({\n id: workerId,\n name: addonId,\n capabilities: [],\n platform: os.platform(),\n arch: os.arch(),\n cpuCores: os.cpus().length,\n memoryMB: Math.round(os.totalmem() / 1024 / 1024),\n pythonRuntimes: [],\n installedAddons: [addonId],\n taskTypes: [],\n host: os.hostname(),\n port: 0,\n httpPort: 0,\n })\n console.log(`[worker:${addonId}] Registered with hub as ${workerId}`)\n } catch (err) {\n console.error(`[worker:${addonId}] Failed to register:`, err instanceof Error ? err.message : err)\n process.exit(1)\n }\n\n // 3. Build logger that routes structured logs via IPC to parent's LogManager\n function createScopedLogger(scope: readonly string[]): IScopedLogger {\n const sendLog = (level: string, message: string, context?: Record<string, unknown>) => {\n if (process.send) {\n process.send({ type: 'LOG', level, message, context })\n } else {\n // Fallback if IPC not available\n const prefix = `[${scope.join(':')}]`\n if (level === 'error') console.error(prefix, message, context ?? '')\n else if (level === 'warn') console.warn(prefix, message, context ?? '')\n else if (level === 'debug') console.debug(prefix, message, context ?? '')\n else console.log(prefix, message, context ?? '')\n }\n }\n return {\n info: (msg: string, ctx?: Record<string, unknown>) => sendLog('info', msg, ctx),\n warn: (msg: string, ctx?: Record<string, unknown>) => sendLog('warn', msg, ctx),\n error: (msg: string, ctx?: Record<string, unknown>) => sendLog('error', msg, ctx),\n debug: (msg: string, ctx?: Record<string, unknown>) => sendLog('debug', msg, ctx),\n child: (childScope: string) => createScopedLogger([...scope, childScope]),\n } as IScopedLogger\n }\n const logger = createScopedLogger([addonId])\n\n // 4. Create process manager for sub-processes (no-op sender since we use tRPC now)\n const processManager = new WorkerProcessManager(() => {})\n\n // 5. Load addon\n const pkgJsonPath = path.join(addonDir, 'package.json')\n const pkgJson = JSON.parse(fs.readFileSync(pkgJsonPath, 'utf-8'))\n const manifest = pkgJson.camstack\n if (!manifest?.addons?.length) {\n console.error(`[worker:${addonId}] No camstack addon manifest in ${pkgJsonPath}`)\n process.exit(1)\n }\n\n const declaration = manifest.addons.find((a: { id: string }) => a.id === addonId)\n if (!declaration) {\n console.error(`[worker:${addonId}] Addon \"${addonId}\" not found in manifest`)\n process.exit(1)\n }\n\n const entryFile = declaration.entry\n .replace(/^\\.\\//, '')\n .replace(/^src\\//, 'dist/')\n .replace(/\\.ts$/, '.js')\n let entryPath = path.resolve(addonDir, entryFile)\n if (!fs.existsSync(entryPath)) {\n // Try .cjs fallback\n const cjsPath = entryPath.replace(/\\.js$/, '.cjs')\n if (fs.existsSync(cjsPath)) entryPath = cjsPath\n }\n\n const mod = await import(entryPath)\n const firstKey = Object.keys(mod)[0] as string | undefined\n const AddonClass = mod.default?.default ?? mod.default ?? (firstKey ? mod[firstKey] : undefined)\n if (typeof AddonClass !== 'function') {\n console.error(`[worker:${addonId}] No addon class found in ${entryPath}`)\n process.exit(1)\n }\n\n const addon: ICamstackAddon = new AddonClass()\n\n // 6. Initialize addon with context.api = tRPC client\n const context: AddonContext = {\n id: addonId,\n api: api as unknown as AddonContext['api'],\n logger,\n addonConfig,\n process: processManager,\n dataDir,\n locationPaths,\n // Legacy fields — stubs for backward compat during migration\n eventBus: { emit: () => {}, subscribe: () => () => {}, getRecent: () => [] } as any,\n storage: {} as any,\n config: { get: () => undefined, set: async () => {} } as any,\n } as AddonContext\n\n await addon.initialize(context)\n console.log(`[worker:${addonId}] Addon initialized`)\n\n // 7. Heartbeat loop — includes sub-process stats\n const heartbeatInterval = setInterval(async () => {\n try {\n const mem = process.memoryUsage()\n const subProcs = processManager.listProcesses().map(p => ({\n pid: p.pid,\n name: p.name,\n command: p.command,\n state: p.state as 'running' | 'stopped' | 'crashed',\n cpuPercent: p.cpuPercent,\n memoryRss: p.memoryRss,\n uptimeSeconds: p.uptimeSeconds,\n }))\n\n await (api as any).agent.heartbeat.mutate({\n agentId: workerId,\n cpuPercent: 0,\n memoryUsedMB: Math.round(mem.rss / 1024 / 1024),\n activeTasks: 0,\n subProcesses: subProcs,\n })\n } catch {\n // heartbeat failure is non-fatal\n }\n }, 10_000)\n\n // 8. Listen for task assignments\n try {\n ;(api as any).agent.onTaskAssignment.subscribe(undefined, {\n onData: async (task: { taskId: string; taskType: string; payload: unknown }) => {\n try {\n let result: unknown\n if (task.taskType === 'addon.install') {\n // Handle addon install\n const { AddonInstaller } = await import('../addon-installer.js')\n const installer = new AddonInstaller({ addonsDir: path.dirname(addonDir) })\n const payload = task.payload as { package: string; version?: string }\n result = await installer.installFromNpm(payload.package, payload.version)\n } else if (typeof (addon as any).handleTask === 'function') {\n result = await (addon as any).handleTask(task.taskType, task.payload)\n }\n await (api as any).agent.reportTaskResult.mutate({\n taskId: task.taskId, success: true, result,\n })\n } catch (err) {\n await (api as any).agent.reportTaskResult.mutate({\n taskId: task.taskId, success: false,\n error: err instanceof Error ? err.message : String(err),\n })\n }\n },\n })\n } catch {\n // subscription failure — tasks won't be received but worker still functions\n }\n\n // 9. Graceful shutdown\n const shutdown = async () => {\n clearInterval(heartbeatInterval)\n await processManager.killAll()\n await addon.shutdown()\n wsClient.close()\n process.exit(0)\n }\n\n process.on('SIGTERM', () => shutdown().catch(() => process.exit(1)))\n process.on('SIGINT', () => shutdown().catch(() => process.exit(1)))\n\n // Signal ready to parent (if using IPC for boot coordination)\n process.send?.({ type: 'READY' })\n}\n\n// Handle uncaught errors\nprocess.on('uncaughtException', (err) => {\n console.error('[worker] Uncaught exception:', err.message, err.stack)\n})\n\nprocess.on('unhandledRejection', (reason) => {\n const msg = reason instanceof Error ? reason.message : String(reason)\n console.error('[worker] Unhandled rejection:', msg)\n})\n\nboot().catch((err) => {\n console.error('[worker] Boot failed:', err)\n process.exit(1)\n})\n"],"mappings":"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","names":["context"]}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@camstack/kernel",
3
- "version": "0.1.6",
3
+ "version": "0.1.9",
4
4
  "description": "CamStack kernel — minimal bootloader for addon loading, capability registry, and config management",
5
5
  "keywords": [
6
6
  "camstack",
@@ -1,6 +0,0 @@
1
- import {
2
- require_addon_installer
3
- } from "./chunk-GJ3DKNOD.mjs";
4
- import "./chunk-LZOMFHX3.mjs";
5
- export default require_addon_installer();
6
- //# sourceMappingURL=addon-installer-WQBOEZQT.mjs.map