@agento-nexus/sdk 0.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/utils/logger.ts","../src/template-builder.ts","../src/utils/retry.ts","../src/openfang-client.ts","../src/claude-bridge.ts","../src/utils/events.ts","../src/fangbox.ts","../src/fleet.ts"],"sourcesContent":["export type LogLevel = \"debug\" | \"info\" | \"warn\" | \"error\";\n\nconst levels: Record<LogLevel, number> = {\n debug: 0,\n info: 1,\n warn: 2,\n error: 3,\n};\n\nexport class Logger {\n private minLevel: number;\n\n constructor(\n private prefix: string,\n level: LogLevel = \"info\",\n ) {\n this.minLevel = levels[level];\n }\n\n debug(msg: string, data?: Record<string, unknown>): void {\n this.log(\"debug\", msg, data);\n }\n\n info(msg: string, data?: Record<string, unknown>): void {\n this.log(\"info\", msg, data);\n }\n\n warn(msg: string, data?: Record<string, unknown>): void {\n this.log(\"warn\", msg, data);\n }\n\n error(msg: string, data?: Record<string, unknown>): void {\n this.log(\"error\", msg, data);\n }\n\n private log(\n level: LogLevel,\n msg: string,\n data?: Record<string, unknown>,\n ): void {\n if (levels[level] < this.minLevel) return;\n\n const entry = {\n ts: new Date().toISOString(),\n level,\n component: this.prefix,\n msg,\n ...data,\n };\n\n const out = level === \"error\" ? console.error : console.log;\n out(JSON.stringify(entry));\n }\n}\n","import { Sandbox } from \"e2b\";\nimport type { TemplateBuildConfig } from \"./types.js\";\nimport { Logger } from \"./utils/logger.js\";\n\nconst DEFAULT_BASE_TEMPLATE = \"claude\";\n\nexport class TemplateBuilder {\n private log: Logger;\n\n constructor() {\n this.log = new Logger(\"template-builder\");\n }\n\n /** Build an E2B template with OpenFang installed */\n async build(config: TemplateBuildConfig = {}): Promise<{\n templateId: string;\n openfangVersion: string;\n }> {\n const base = config.baseTemplate ?? DEFAULT_BASE_TEMPLATE;\n this.log.info(\"Building template\", { base });\n\n // Spin up a temporary sandbox from the base template\n const sandbox = await Sandbox.create(base, {\n timeoutMs: 300_000,\n });\n\n try {\n // Install OpenFang\n const installCmd = config.openfangVersion\n ? `pip install openfang==${config.openfangVersion}`\n : \"pip install openfang\";\n\n this.log.info(\"Installing OpenFang\", { cmd: installCmd });\n const installResult = await sandbox.commands.run(installCmd, {\n timeoutMs: 120_000,\n });\n\n if (installResult.exitCode !== 0) {\n throw new Error(\n `Failed to install OpenFang: ${installResult.stderr}`,\n );\n }\n\n // Install additional packages\n if (config.packages?.length) {\n const pkgCmd = `pip install ${config.packages.join(\" \")}`;\n this.log.info(\"Installing additional packages\", { cmd: pkgCmd });\n const pkgResult = await sandbox.commands.run(pkgCmd, {\n timeoutMs: 120_000,\n });\n\n if (pkgResult.exitCode !== 0) {\n throw new Error(\n `Failed to install packages: ${pkgResult.stderr}`,\n );\n }\n }\n\n // Run custom setup script\n if (config.setupScript) {\n this.log.info(\"Running custom setup script\");\n const setupResult = await sandbox.commands.run(config.setupScript, {\n timeoutMs: 120_000,\n });\n\n if (setupResult.exitCode !== 0) {\n throw new Error(\n `Setup script failed: ${setupResult.stderr}`,\n );\n }\n }\n\n // Verify installation\n const versionResult = await sandbox.commands.run(\n \"openfang --version\",\n { timeoutMs: 10_000 },\n );\n\n if (versionResult.exitCode !== 0) {\n throw new Error(\"OpenFang installation verification failed\");\n }\n\n const openfangVersion = versionResult.stdout.trim();\n this.log.info(\"OpenFang installed\", { version: openfangVersion });\n\n // Note: In production, you'd call e2b template save here.\n // The E2B CLI handles template creation from running sandboxes.\n // For programmatic builds, we return the sandbox ID for manual saving.\n\n return {\n templateId: sandbox.sandboxId,\n openfangVersion,\n };\n } finally {\n await sandbox.kill();\n }\n }\n\n /** Verify an existing template has OpenFang ready */\n async verify(templateId: string): Promise<{\n healthy: boolean;\n version?: string;\n error?: string;\n }> {\n this.log.info(\"Verifying template\", { templateId });\n\n const sandbox = await Sandbox.create(templateId, {\n timeoutMs: 60_000,\n });\n\n try {\n const result = await sandbox.commands.run(\"openfang --version\", {\n timeoutMs: 10_000,\n });\n\n if (result.exitCode !== 0) {\n return { healthy: false, error: \"openfang not found\" };\n }\n\n return { healthy: true, version: result.stdout.trim() };\n } catch (error) {\n return {\n healthy: false,\n error: error instanceof Error ? error.message : String(error),\n };\n } finally {\n await sandbox.kill();\n }\n }\n}\n","export interface RetryOptions {\n maxAttempts?: number;\n initialDelayMs?: number;\n maxDelayMs?: number;\n backoffMultiplier?: number;\n retryIf?: (error: unknown) => boolean;\n}\n\nconst defaults: Required<Omit<RetryOptions, \"retryIf\">> = {\n maxAttempts: 3,\n initialDelayMs: 500,\n maxDelayMs: 10_000,\n backoffMultiplier: 2,\n};\n\nexport async function retry<T>(\n fn: () => Promise<T>,\n opts: RetryOptions = {},\n): Promise<T> {\n const { maxAttempts, initialDelayMs, maxDelayMs, backoffMultiplier } = {\n ...defaults,\n ...opts,\n };\n const retryIf = opts.retryIf ?? (() => true);\n\n let lastError: unknown;\n let delay = initialDelayMs;\n\n for (let attempt = 1; attempt <= maxAttempts; attempt++) {\n try {\n return await fn();\n } catch (error) {\n lastError = error;\n\n if (attempt === maxAttempts || !retryIf(error)) {\n throw error;\n }\n\n await sleep(delay);\n delay = Math.min(delay * backoffMultiplier, maxDelayMs);\n }\n }\n\n throw lastError;\n}\n\nfunction sleep(ms: number): Promise<void> {\n return new Promise((resolve) => setTimeout(resolve, ms));\n}\n","import type {\n AgentInfo,\n AgentResponse,\n HandManifest,\n HealthResponse,\n ToolDefinition,\n} from \"./types.js\";\nimport { retry, type RetryOptions } from \"./utils/retry.js\";\nimport { Logger } from \"./utils/logger.js\";\n\nexport interface OpenFangClientConfig {\n /** Base URL for the OpenFang REST API */\n baseUrl: string;\n /** Request timeout in ms (default: 30000) */\n timeoutMs?: number;\n /** Retry options for failed requests */\n retryOptions?: RetryOptions;\n}\n\nexport class OpenFangClient {\n private baseUrl: string;\n private timeoutMs: number;\n private retryOpts: RetryOptions;\n private log: Logger;\n\n constructor(config: OpenFangClientConfig) {\n this.baseUrl = config.baseUrl.replace(/\\/$/, \"\");\n this.timeoutMs = config.timeoutMs ?? 30_000;\n this.retryOpts = config.retryOptions ?? { maxAttempts: 3 };\n this.log = new Logger(\"openfang-client\");\n }\n\n /** Check daemon health */\n async health(): Promise<HealthResponse> {\n return this.request<HealthResponse>(\"GET\", \"/health\");\n }\n\n /** Wait for daemon to become healthy */\n async waitForHealthy(maxWaitMs = 30_000): Promise<HealthResponse> {\n const startTime = Date.now();\n return retry(\n async () => {\n if (Date.now() - startTime > maxWaitMs) {\n throw new Error(\n `OpenFang daemon not healthy after ${maxWaitMs}ms`,\n );\n }\n return this.health();\n },\n { maxAttempts: Math.ceil(maxWaitMs / 2000), initialDelayMs: 1000 },\n );\n }\n\n /** Spawn a new agent from a Hand manifest */\n async spawnAgent(manifest: HandManifest): Promise<AgentInfo> {\n this.log.info(\"Spawning agent\", { name: manifest.name });\n return this.request<AgentInfo>(\"POST\", \"/agents\", manifest);\n }\n\n /** List all running agents */\n async listAgents(): Promise<AgentInfo[]> {\n return this.request<AgentInfo[]>(\"GET\", \"/agents\");\n }\n\n /** Get agent info by ID */\n async getAgent(agentId: string): Promise<AgentInfo> {\n return this.request<AgentInfo>(\"GET\", `/agents/${agentId}`);\n }\n\n /** Send a message to an agent */\n async messageAgent(\n agentId: string,\n content: string,\n ): Promise<AgentResponse> {\n return this.request<AgentResponse>(\n \"POST\",\n `/agents/${agentId}/messages`,\n { content },\n );\n }\n\n /** Stop an agent */\n async stopAgent(agentId: string): Promise<void> {\n await this.request(\"DELETE\", `/agents/${agentId}`);\n }\n\n /** List available tools */\n async listTools(): Promise<ToolDefinition[]> {\n return this.request<ToolDefinition[]>(\"GET\", \"/tools\");\n }\n\n private async request<T>(\n method: string,\n path: string,\n body?: unknown,\n ): Promise<T> {\n return retry(async () => {\n const controller = new AbortController();\n const timer = setTimeout(() => controller.abort(), this.timeoutMs);\n\n try {\n const res = await fetch(`${this.baseUrl}${path}`, {\n method,\n headers: body ? { \"Content-Type\": \"application/json\" } : undefined,\n body: body ? JSON.stringify(body) : undefined,\n signal: controller.signal,\n });\n\n if (!res.ok) {\n const text = await res.text().catch(() => \"\");\n throw new OpenFangError(\n `${method} ${path} returned ${res.status}: ${text}`,\n res.status,\n );\n }\n\n if (res.status === 204) return undefined as T;\n return (await res.json()) as T;\n } finally {\n clearTimeout(timer);\n }\n }, this.retryOpts);\n }\n}\n\nexport class OpenFangError extends Error {\n constructor(\n message: string,\n public statusCode: number,\n ) {\n super(message);\n this.name = \"OpenFangError\";\n }\n}\n","import type { Sandbox } from \"e2b\";\nimport type { ClaudeCodeRequest, ClaudeCodeResult } from \"./types.js\";\nimport { Logger } from \"./utils/logger.js\";\n\nexport class ClaudeBridge {\n private log: Logger;\n\n constructor(private sandbox: Sandbox) {\n this.log = new Logger(\"claude-bridge\");\n }\n\n /** Execute a Claude Code prompt inside the sandbox */\n async execute(request: ClaudeCodeRequest): Promise<ClaudeCodeResult> {\n const start = Date.now();\n const args = this.buildArgs(request);\n\n this.log.info(\"Executing Claude Code\", {\n prompt: request.prompt.slice(0, 100),\n outputFormat: request.outputFormat,\n });\n\n const result = await this.sandbox.commands.run(\n `claude ${args.join(\" \")}`,\n {\n cwd: request.cwd ?? \"/home/user\",\n timeoutMs: (request.maxTokens ?? 120) * 1000,\n },\n );\n\n const durationMs = Date.now() - start;\n const output = result.stdout;\n\n let parsed: unknown;\n if (request.outputFormat === \"json\") {\n try {\n parsed = JSON.parse(output);\n } catch {\n this.log.warn(\"Failed to parse JSON output from Claude Code\");\n }\n }\n\n return {\n output,\n exitCode: result.exitCode,\n parsed,\n durationMs,\n sessionId: request.sessionId,\n };\n }\n\n /** Check if Claude Code is installed in the sandbox */\n async isAvailable(): Promise<boolean> {\n try {\n const result = await this.sandbox.commands.run(\"claude --version\", {\n timeoutMs: 10_000,\n });\n return result.exitCode === 0;\n } catch {\n return false;\n }\n }\n\n private buildArgs(request: ClaudeCodeRequest): string[] {\n const args = [\"-p\", this.shellEscape(request.prompt)];\n\n if (request.outputFormat === \"json\") {\n args.push(\"--output-format\", \"json\");\n }\n\n if (request.sessionId) {\n args.push(\"--session-id\", request.sessionId);\n }\n\n if (request.maxTokens) {\n args.push(\"--max-tokens\", String(request.maxTokens));\n }\n\n if (request.flags) {\n args.push(...request.flags);\n }\n\n return args;\n }\n\n private shellEscape(str: string): string {\n return `'${str.replace(/'/g, \"'\\\\''\")}'`;\n }\n}\n","type Listener<T> = (event: T) => void;\n\nexport class TypedEmitter<T> {\n private listeners: Set<Listener<T>> = new Set();\n\n on(listener: Listener<T>): () => void {\n this.listeners.add(listener);\n return () => this.listeners.delete(listener);\n }\n\n emit(event: T): void {\n for (const listener of this.listeners) {\n listener(event);\n }\n }\n\n removeAll(): void {\n this.listeners.clear();\n }\n}\n","import { Sandbox } from \"e2b\";\nimport type {\n AgentInfo,\n AgentResponse,\n ClaudeCodeRequest,\n ClaudeCodeResult,\n FangBoxConfig,\n FangBoxEvent,\n HandManifest,\n HealthResponse,\n} from \"./types.js\";\nimport { OpenFangClient } from \"./openfang-client.js\";\nimport { ClaudeBridge } from \"./claude-bridge.js\";\nimport { TypedEmitter } from \"./utils/events.js\";\nimport { Logger } from \"./utils/logger.js\";\n\nconst DEFAULT_TEMPLATE = \"openfang-claude\";\nconst DEFAULT_PORT = 4200;\nconst DEFAULT_TIMEOUT = 300;\n\nexport class FangBox {\n readonly sandbox: Sandbox;\n readonly client: OpenFangClient;\n readonly claudeBridge: ClaudeBridge;\n readonly events = new TypedEmitter<FangBoxEvent>();\n private log: Logger;\n\n private constructor(\n sandbox: Sandbox,\n client: OpenFangClient,\n claudeBridge: ClaudeBridge,\n ) {\n this.sandbox = sandbox;\n this.client = client;\n this.claudeBridge = claudeBridge;\n this.log = new Logger(\"fangbox\");\n }\n\n /**\n * Create a new FangBox — spins up sandbox, starts daemon, waits for health.\n * All commands run inside the E2B cloud sandbox (not local shell).\n */\n static async create(config: FangBoxConfig = {}): Promise<FangBox> {\n const emitter = new TypedEmitter<FangBoxEvent>();\n const log = new Logger(\"fangbox\");\n const port = config.openfangPort ?? DEFAULT_PORT;\n\n emitter.emit({ type: \"sandbox:creating\" });\n log.info(\"Creating sandbox\", {\n template: config.templateId ?? DEFAULT_TEMPLATE,\n });\n\n const sandbox = await Sandbox.create(config.templateId ?? DEFAULT_TEMPLATE, {\n envs: config.envs,\n timeoutMs: (config.timeout ?? DEFAULT_TIMEOUT) * 1000,\n metadata: config.metadata,\n });\n\n const sandboxId = sandbox.sandboxId;\n emitter.emit({ type: \"sandbox:ready\", sandboxId });\n\n const baseUrl = `https://${sandboxId}-${port}.e2b.dev`;\n const client = new OpenFangClient({ baseUrl });\n const claudeBridge = new ClaudeBridge(sandbox);\n\n const box = new FangBox(sandbox, client, claudeBridge);\n box.events.on((e) => emitter.emit(e));\n\n // Start OpenFang daemon inside the sandbox.\n // E2B's sandbox.commands.run() executes inside the cloud sandbox,\n // not on the local machine — this is safe by design.\n const daemonCmd = [\"openfang\", \"serve\", \"--port\", String(port)].join(\" \");\n emitter.emit({ type: \"daemon:starting\" });\n await sandbox.commands.run(daemonCmd, { background: true });\n\n // Wait for daemon to be healthy\n try {\n const health = await client.waitForHealthy(30_000);\n emitter.emit({ type: \"daemon:healthy\", version: health.version });\n log.info(\"Daemon healthy\", { version: health.version });\n } catch (error) {\n const msg = error instanceof Error ? error.message : String(error);\n emitter.emit({ type: \"daemon:unhealthy\", error: msg });\n throw new Error(`OpenFang daemon failed to start: ${msg}`);\n }\n\n return box;\n }\n\n get sandboxId(): string {\n return this.sandbox.sandboxId;\n }\n\n /** Check daemon health */\n async health(): Promise<HealthResponse> {\n return this.client.health();\n }\n\n /** Spawn an agent from a Hand manifest or name */\n async spawnAgent(handOrName: HandManifest | string): Promise<AgentInfo> {\n const manifest: HandManifest =\n typeof handOrName === \"string\" ? { name: handOrName } : handOrName;\n\n const agent = await this.client.spawnAgent(manifest);\n this.events.emit({\n type: \"agent:spawned\",\n agentId: agent.id,\n name: agent.name,\n });\n return agent;\n }\n\n /** Send a message to a running agent */\n async messageAgent(\n agentId: string,\n content: string,\n ): Promise<AgentResponse> {\n const response = await this.client.messageAgent(agentId, content);\n this.events.emit({\n type: \"agent:message\",\n agentId,\n content: response.content,\n });\n return response;\n }\n\n /** List all running agents */\n async listAgents(): Promise<AgentInfo[]> {\n return this.client.listAgents();\n }\n\n /** Stop an agent */\n async stopAgent(agentId: string): Promise<void> {\n await this.client.stopAgent(agentId);\n this.events.emit({ type: \"agent:completed\", agentId });\n }\n\n /** Execute Claude Code in the sandbox */\n async runClaude(request: ClaudeCodeRequest): Promise<ClaudeCodeResult> {\n return this.claudeBridge.execute(request);\n }\n\n /** Upload a file to the sandbox */\n async uploadFile(path: string, content: string): Promise<void> {\n await this.sandbox.files.write(path, content);\n }\n\n /** Read a file from the sandbox */\n async readFile(path: string): Promise<string> {\n return this.sandbox.files.read(path);\n }\n\n /**\n * Run a command inside the E2B cloud sandbox.\n * This uses E2B's sandbox.commands.run() which executes remotely,\n * not on the local machine.\n */\n async runInSandbox(\n command: string,\n opts?: { cwd?: string; timeoutMs?: number },\n ): Promise<{ stdout: string; stderr: string; exitCode: number }> {\n const result = await this.sandbox.commands.run(command, opts);\n return {\n stdout: result.stdout,\n stderr: result.stderr,\n exitCode: result.exitCode,\n };\n }\n\n /** Destroy the sandbox */\n async destroy(): Promise<void> {\n const id = this.sandboxId;\n this.log.info(\"Destroying sandbox\", { sandboxId: id });\n await this.sandbox.kill();\n this.events.emit({ type: \"sandbox:destroyed\", sandboxId: id });\n this.events.removeAll();\n }\n}\n\n/** Convenience function to create a FangBox */\nexport async function createFangBox(config?: FangBoxConfig): Promise<FangBox> {\n return FangBox.create(config);\n}\n","import type {\n FleetEvent,\n StepResult,\n WorkflowDefinition,\n WorkflowResult,\n WorkflowStep,\n} from \"./types.js\";\nimport { createFangBox } from \"./fangbox.js\";\nimport { TypedEmitter } from \"./utils/events.js\";\nimport { Logger } from \"./utils/logger.js\";\n\nexport interface FleetConfig {\n /** Max concurrent sandboxes (default: 3) */\n maxConcurrency?: number;\n /** Default sandbox timeout in seconds */\n defaultTimeout?: number;\n /** Default environment variables for all sandboxes */\n envs?: Record<string, string>;\n}\n\nexport class Fleet {\n readonly events = new TypedEmitter<FleetEvent>();\n private log: Logger;\n private maxConcurrency: number;\n private defaultTimeout: number;\n private envs: Record<string, string>;\n\n constructor(config: FleetConfig = {}) {\n this.maxConcurrency = config.maxConcurrency ?? 3;\n this.defaultTimeout = config.defaultTimeout ?? 300;\n this.envs = config.envs ?? {};\n this.log = new Logger(\"fleet\");\n }\n\n /** Run a workflow from a parsed definition */\n async run(workflow: WorkflowDefinition): Promise<WorkflowResult> {\n const start = Date.now();\n this.log.info(\"Starting workflow\", { name: workflow.name });\n this.events.emit({ type: \"workflow:start\", name: workflow.name });\n\n const sorted = this.topologicalSort(workflow.steps);\n const outputs: Record<string, string> = {};\n const results: StepResult[] = [];\n const completed = new Set<string>();\n\n // Process steps respecting dependencies and concurrency\n const pending = [...sorted];\n\n while (pending.length > 0) {\n // Find steps whose dependencies are all completed\n const ready = pending.filter((step) =>\n (step.dependsOn ?? []).every((dep) => completed.has(dep)),\n );\n\n if (ready.length === 0 && pending.length > 0) {\n throw new Error(\n \"Deadlock: no steps can proceed. Check for circular dependencies.\",\n );\n }\n\n // Run ready steps in parallel up to maxConcurrency\n const batch = ready.slice(0, this.maxConcurrency);\n const batchResults = await Promise.allSettled(\n batch.map((step) => this.executeStep(step, outputs, workflow.envs)),\n );\n\n for (let i = 0; i < batch.length; i++) {\n const step = batch[i];\n const settled = batchResults[i];\n\n let result: StepResult;\n if (settled.status === \"fulfilled\") {\n result = settled.value;\n } else {\n result = {\n stepId: step.id,\n status: \"failure\",\n error:\n settled.reason instanceof Error\n ? settled.reason.message\n : String(settled.reason),\n durationMs: 0,\n };\n }\n\n results.push(result);\n completed.add(step.id);\n\n if (result.status === \"success\" && step.outputKey && result.output) {\n outputs[step.outputKey] = result.output;\n }\n\n this.events.emit({ type: \"step:complete\", stepId: step.id, result });\n\n // Remove from pending\n const idx = pending.indexOf(step);\n if (idx !== -1) pending.splice(idx, 1);\n }\n }\n\n const status = results.every((r) => r.status === \"success\")\n ? \"success\"\n : results.some((r) => r.status === \"success\")\n ? \"partial\"\n : \"failure\";\n\n const workflowResult: WorkflowResult = {\n workflowName: workflow.name,\n status,\n steps: results,\n totalDurationMs: Date.now() - start,\n outputs,\n };\n\n this.events.emit({ type: \"workflow:complete\", result: workflowResult });\n return workflowResult;\n }\n\n /** Load and run a workflow from a JSON file path */\n async runFromFile(filePath: string): Promise<WorkflowResult> {\n const fs = await import(\"node:fs/promises\");\n const content = await fs.readFile(filePath, \"utf-8\");\n const workflow = JSON.parse(content) as WorkflowDefinition;\n return this.run(workflow);\n }\n\n private async executeStep(\n step: WorkflowStep,\n outputs: Record<string, string>,\n workflowEnvs?: Record<string, string>,\n ): Promise<StepResult> {\n const start = Date.now();\n\n // Evaluate condition\n if (step.condition) {\n const shouldRun = this.evaluateCondition(step.condition, outputs);\n if (!shouldRun) {\n this.events.emit({\n type: \"step:skip\",\n stepId: step.id,\n reason: `Condition not met: ${step.condition}`,\n });\n return {\n stepId: step.id,\n status: \"skipped\",\n durationMs: Date.now() - start,\n };\n }\n }\n\n this.events.emit({ type: \"step:start\", stepId: step.id });\n this.log.info(\"Executing step\", { stepId: step.id, name: step.name });\n\n const box = await createFangBox({\n ...step.config,\n envs: { ...this.envs, ...workflowEnvs, ...step.config?.envs },\n timeout: step.timeout ?? this.defaultTimeout,\n });\n\n try {\n // Interpolate prompt with outputs from previous steps\n const prompt = this.interpolate(step.prompt, outputs);\n\n // Spawn agent and send prompt\n const manifest =\n typeof step.hand === \"string\" ? { name: step.hand } : step.hand;\n const agent = await box.spawnAgent(manifest);\n const response = await box.messageAgent(agent.id, prompt);\n\n return {\n stepId: step.id,\n status: \"success\",\n output: response.content,\n durationMs: Date.now() - start,\n };\n } catch (error) {\n return {\n stepId: step.id,\n status: \"failure\",\n error: error instanceof Error ? error.message : String(error),\n durationMs: Date.now() - start,\n };\n } finally {\n await box.destroy();\n }\n }\n\n /** Interpolate {{outputKey}} placeholders in a string */\n private interpolate(\n template: string,\n outputs: Record<string, string>,\n ): string {\n return template.replace(/\\{\\{(\\w+)\\}\\}/g, (match, key: string) => {\n return outputs[key] ?? match;\n });\n }\n\n /**\n * Evaluate a condition against available outputs.\n * Supports safe expressions: \"outputKey\", \"!outputKey\",\n * \"outputKey == 'value'\", \"outputKey != 'value'\"\n */\n private evaluateCondition(\n condition: string,\n outputs: Record<string, string>,\n ): boolean {\n const trimmed = condition.trim();\n\n // \"!key\" — key must be absent or empty\n if (trimmed.startsWith(\"!\")) {\n const key = trimmed.slice(1).trim();\n return !outputs[key];\n }\n\n // \"key == 'value'\" or 'key != \"value\"'\n const eqMatch = trimmed.match(/^(\\w+)\\s*(==|!=)\\s*['\"](.*)['\"]$/);\n if (eqMatch) {\n const [, key, op, value] = eqMatch;\n const actual = outputs[key];\n return op === \"==\" ? actual === value : actual !== value;\n }\n\n // \"key\" — key must exist and be non-empty\n return Boolean(outputs[trimmed]);\n }\n\n /** Topological sort of workflow steps using Kahn's algorithm */\n private topologicalSort(steps: WorkflowStep[]): WorkflowStep[] {\n const stepMap = new Map(steps.map((s) => [s.id, s]));\n const inDegree = new Map<string, number>();\n const adjacency = new Map<string, string[]>();\n\n for (const step of steps) {\n inDegree.set(step.id, (step.dependsOn ?? []).length);\n for (const dep of step.dependsOn ?? []) {\n const existing = adjacency.get(dep) ?? [];\n existing.push(step.id);\n adjacency.set(dep, existing);\n }\n }\n\n const queue: string[] = [];\n for (const [id, degree] of inDegree) {\n if (degree === 0) queue.push(id);\n }\n\n const sorted: WorkflowStep[] = [];\n while (queue.length > 0) {\n const id = queue.shift()!;\n sorted.push(stepMap.get(id)!);\n\n for (const neighbor of adjacency.get(id) ?? []) {\n const newDegree = (inDegree.get(neighbor) ?? 1) - 1;\n inDegree.set(neighbor, newDegree);\n if (newDegree === 0) queue.push(neighbor);\n }\n }\n\n if (sorted.length !== steps.length) {\n throw new Error(\"Workflow contains circular dependencies\");\n }\n\n return sorted;\n }\n}\n"],"mappings":"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","names":["Sandbox","Sandbox"]}
@@ -0,0 +1 @@
1
+ #!/usr/bin/env node
@@ -0,0 +1,261 @@
1
+ #!/usr/bin/env node
2
+ import {
3
+ Fleet,
4
+ TemplateBuilder,
5
+ createFangBox
6
+ } from "../chunk-UXIUTT4T.js";
7
+
8
+ // cli/index.ts
9
+ import { Command as Command7 } from "commander";
10
+
11
+ // cli/commands/init.ts
12
+ import { Command } from "commander";
13
+
14
+ // cli/formatters.ts
15
+ import chalk from "chalk";
16
+ function success(msg) {
17
+ console.log(chalk.green("\u2713"), msg);
18
+ }
19
+ function info(msg) {
20
+ console.log(chalk.blue("\u2139"), msg);
21
+ }
22
+ function warn(msg) {
23
+ console.log(chalk.yellow("\u26A0"), msg);
24
+ }
25
+ function error(msg) {
26
+ console.error(chalk.red("\u2717"), msg);
27
+ }
28
+ function header(msg) {
29
+ console.log(chalk.bold.cyan(`
30
+ ${msg}
31
+ `));
32
+ }
33
+ function table(rows) {
34
+ if (rows.length === 0) {
35
+ info("No results");
36
+ return;
37
+ }
38
+ console.table(rows);
39
+ }
40
+ function stepStatus(stepId, status, durationMs) {
41
+ const icon = status === "success" ? chalk.green("\u2713") : status === "failure" ? chalk.red("\u2717") : chalk.gray("\u25CB");
42
+ const duration = durationMs ? chalk.dim(` (${(durationMs / 1e3).toFixed(1)}s)`) : "";
43
+ console.log(` ${icon} ${stepId}${duration}`);
44
+ }
45
+
46
+ // cli/commands/init.ts
47
+ var initCommand = new Command("init").description("Build or verify E2B template with OpenFang installed").option("--base <template>", "Base E2B template", "claude").option("--version <version>", "OpenFang version to install").option("--verify <templateId>", "Verify existing template instead of building").action(async (opts) => {
48
+ const builder = new TemplateBuilder();
49
+ if (opts.verify) {
50
+ info(`Verifying template ${opts.verify}...`);
51
+ const result = await builder.verify(opts.verify);
52
+ if (result.healthy) {
53
+ success(`Template healthy \u2014 OpenFang ${result.version}`);
54
+ } else {
55
+ error(`Template unhealthy: ${result.error}`);
56
+ process.exit(1);
57
+ }
58
+ return;
59
+ }
60
+ info("Building E2B template with OpenFang...");
61
+ try {
62
+ const result = await builder.build({
63
+ baseTemplate: opts.base,
64
+ openfangVersion: opts.version
65
+ });
66
+ success(`Template built \u2014 sandbox ${result.templateId}`);
67
+ info(`OpenFang ${result.openfangVersion}`);
68
+ info("Save as template: e2b template save --sandbox-id " + result.templateId);
69
+ } catch (err) {
70
+ error(err instanceof Error ? err.message : String(err));
71
+ process.exit(1);
72
+ }
73
+ });
74
+
75
+ // cli/commands/run.ts
76
+ import { Command as Command2 } from "commander";
77
+ var runCommand = new Command2("run").description("Run a single agent (Hand) in a sandbox").argument("<hand>", "Hand name or manifest path").requiredOption("-p, --prompt <prompt>", "Prompt to send to the agent").option("-t, --template <id>", "E2B template ID", "openfang-claude").option("--timeout <seconds>", "Sandbox timeout", "300").option("--claude", "Use Claude Code instead of OpenFang agent").action(async (hand, opts) => {
78
+ info(`Creating sandbox with template ${opts.template}...`);
79
+ const envs = {};
80
+ if (process.env.ANTHROPIC_API_KEY) {
81
+ envs.ANTHROPIC_API_KEY = process.env.ANTHROPIC_API_KEY;
82
+ }
83
+ try {
84
+ const box = await createFangBox({
85
+ templateId: opts.template,
86
+ timeout: parseInt(opts.timeout, 10),
87
+ envs
88
+ });
89
+ success(`Sandbox ${box.sandboxId} ready`);
90
+ let output;
91
+ if (opts.claude) {
92
+ info("Running with Claude Code...");
93
+ const result = await box.runClaude({ prompt: opts.prompt });
94
+ output = result.output;
95
+ } else {
96
+ info(`Spawning agent: ${hand}`);
97
+ const agent = await box.spawnAgent(hand);
98
+ info(`Agent ${agent.id} running`);
99
+ const response = await box.messageAgent(agent.id, opts.prompt);
100
+ output = response.content;
101
+ }
102
+ header("Response");
103
+ console.log(output);
104
+ info("Destroying sandbox...");
105
+ await box.destroy();
106
+ success("Done");
107
+ } catch (err) {
108
+ error(err instanceof Error ? err.message : String(err));
109
+ process.exit(1);
110
+ }
111
+ });
112
+
113
+ // cli/commands/fleet.ts
114
+ import { Command as Command3 } from "commander";
115
+ var fleetCommand = new Command3("fleet").description("Run a multi-agent workflow from a JSON definition").argument("<workflow>", "Path to workflow JSON file").option("-c, --concurrency <n>", "Max concurrent sandboxes", "3").option("--timeout <seconds>", "Default step timeout", "300").action(async (workflowPath, opts) => {
116
+ const envs = {};
117
+ if (process.env.ANTHROPIC_API_KEY) {
118
+ envs.ANTHROPIC_API_KEY = process.env.ANTHROPIC_API_KEY;
119
+ }
120
+ const fleet = new Fleet({
121
+ maxConcurrency: parseInt(opts.concurrency, 10),
122
+ defaultTimeout: parseInt(opts.timeout, 10),
123
+ envs
124
+ });
125
+ fleet.events.on((event) => {
126
+ switch (event.type) {
127
+ case "workflow:start":
128
+ header(`Workflow: ${event.name}`);
129
+ break;
130
+ case "step:start":
131
+ info(`Step ${event.stepId} starting...`);
132
+ break;
133
+ case "step:complete":
134
+ stepStatus(
135
+ event.stepId,
136
+ event.result.status,
137
+ event.result.durationMs
138
+ );
139
+ break;
140
+ case "step:skip":
141
+ stepStatus(event.stepId, "skipped");
142
+ break;
143
+ case "workflow:complete":
144
+ header("Workflow Complete");
145
+ info(`Status: ${event.result.status}`);
146
+ info(
147
+ `Duration: ${(event.result.totalDurationMs / 1e3).toFixed(1)}s`
148
+ );
149
+ break;
150
+ }
151
+ });
152
+ try {
153
+ const result = await fleet.runFromFile(workflowPath);
154
+ if (Object.keys(result.outputs).length > 0) {
155
+ header("Outputs");
156
+ for (const [key, value] of Object.entries(result.outputs)) {
157
+ console.log(` ${key}: ${value.slice(0, 200)}${value.length > 200 ? "..." : ""}`);
158
+ }
159
+ }
160
+ if (result.status === "failure") {
161
+ process.exit(1);
162
+ }
163
+ } catch (err) {
164
+ error(err instanceof Error ? err.message : String(err));
165
+ process.exit(1);
166
+ }
167
+ });
168
+
169
+ // cli/commands/status.ts
170
+ import { Command as Command4 } from "commander";
171
+ import { Sandbox } from "e2b";
172
+ var statusCommand = new Command4("status").description("List running E2B sandboxes").action(async () => {
173
+ try {
174
+ const sandboxes = await Sandbox.list();
175
+ if (sandboxes.length === 0) {
176
+ info("No running sandboxes");
177
+ return;
178
+ }
179
+ header(`Running Sandboxes (${sandboxes.length})`);
180
+ table(
181
+ sandboxes.map((s) => ({
182
+ id: s.sandboxId,
183
+ template: s.templateId,
184
+ started: s.startedAt?.toISOString() ?? "unknown"
185
+ }))
186
+ );
187
+ } catch (err) {
188
+ error(err instanceof Error ? err.message : String(err));
189
+ process.exit(1);
190
+ }
191
+ });
192
+
193
+ // cli/commands/logs.ts
194
+ import { Command as Command5 } from "commander";
195
+ import { Sandbox as Sandbox2 } from "e2b";
196
+ var logsCommand = new Command5("logs").description("Stream logs from a running sandbox").argument("<id>", "Sandbox ID").option("-f, --follow", "Follow log output").action(async (id, opts) => {
197
+ try {
198
+ const sandbox = await Sandbox2.connect(id);
199
+ info(`Connected to sandbox ${id}`);
200
+ const result = await sandbox.commands.run(
201
+ "journalctl -u openfang" + (opts.follow ? " -f" : " --no-pager"),
202
+ { timeoutMs: opts.follow ? 0 : 3e4 }
203
+ );
204
+ console.log(result.stdout);
205
+ if (result.stderr) {
206
+ warn(result.stderr);
207
+ }
208
+ } catch (err) {
209
+ error(err instanceof Error ? err.message : String(err));
210
+ process.exit(1);
211
+ }
212
+ });
213
+
214
+ // cli/commands/destroy.ts
215
+ import { Command as Command6 } from "commander";
216
+ import { Sandbox as Sandbox3 } from "e2b";
217
+ var destroyCommand = new Command6("destroy").description("Tear down sandboxes").argument("[id]", "Sandbox ID (omit with --all to destroy all)").option("--all", "Destroy all running sandboxes").action(async (id, opts) => {
218
+ try {
219
+ if (opts.all) {
220
+ const sandboxes = await Sandbox3.list();
221
+ if (sandboxes.length === 0) {
222
+ info("No running sandboxes");
223
+ return;
224
+ }
225
+ info(`Destroying ${sandboxes.length} sandboxes...`);
226
+ await Promise.all(
227
+ sandboxes.map(async (s) => {
228
+ const sb = await Sandbox3.connect(s.sandboxId);
229
+ await sb.kill();
230
+ success(`Destroyed ${s.sandboxId}`);
231
+ })
232
+ );
233
+ success("All sandboxes destroyed");
234
+ return;
235
+ }
236
+ if (!id) {
237
+ error("Provide a sandbox ID or use --all");
238
+ process.exit(1);
239
+ }
240
+ info(`Destroying sandbox ${id}...`);
241
+ const sandbox = await Sandbox3.connect(id);
242
+ await sandbox.kill();
243
+ success(`Destroyed ${id}`);
244
+ } catch (err) {
245
+ error(err instanceof Error ? err.message : String(err));
246
+ process.exit(1);
247
+ }
248
+ });
249
+
250
+ // cli/index.ts
251
+ var program = new Command7().name("agento-sdk").description("Agent OS in Cloud Sandboxes \u2014 OpenFang + E2B + Claude Code").version("0.1.0");
252
+ program.addCommand(initCommand);
253
+ program.addCommand(runCommand);
254
+ program.addCommand(fleetCommand);
255
+ program.addCommand(statusCommand);
256
+ program.addCommand(logsCommand);
257
+ program.addCommand(destroyCommand);
258
+
259
+ // cli/bin.ts
260
+ program.parse();
261
+ //# sourceMappingURL=bin.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../../cli/index.ts","../../cli/commands/init.ts","../../cli/formatters.ts","../../cli/commands/run.ts","../../cli/commands/fleet.ts","../../cli/commands/status.ts","../../cli/commands/logs.ts","../../cli/commands/destroy.ts","../../cli/bin.ts"],"sourcesContent":["import { Command } from \"commander\";\nimport { initCommand } from \"./commands/init.js\";\nimport { runCommand } from \"./commands/run.js\";\nimport { fleetCommand } from \"./commands/fleet.js\";\nimport { statusCommand } from \"./commands/status.js\";\nimport { logsCommand } from \"./commands/logs.js\";\nimport { destroyCommand } from \"./commands/destroy.js\";\n\nexport const program = new Command()\n .name(\"agento-sdk\")\n .description(\"Agent OS in Cloud Sandboxes — OpenFang + E2B + Claude Code\")\n .version(\"0.1.0\");\n\nprogram.addCommand(initCommand);\nprogram.addCommand(runCommand);\nprogram.addCommand(fleetCommand);\nprogram.addCommand(statusCommand);\nprogram.addCommand(logsCommand);\nprogram.addCommand(destroyCommand);\n","import { Command } from \"commander\";\nimport { TemplateBuilder } from \"../../src/template-builder.js\";\nimport * as fmt from \"../formatters.js\";\n\nexport const initCommand = new Command(\"init\")\n .description(\"Build or verify E2B template with OpenFang installed\")\n .option(\"--base <template>\", \"Base E2B template\", \"claude\")\n .option(\"--version <version>\", \"OpenFang version to install\")\n .option(\"--verify <templateId>\", \"Verify existing template instead of building\")\n .action(async (opts) => {\n const builder = new TemplateBuilder();\n\n if (opts.verify) {\n fmt.info(`Verifying template ${opts.verify}...`);\n const result = await builder.verify(opts.verify);\n if (result.healthy) {\n fmt.success(`Template healthy — OpenFang ${result.version}`);\n } else {\n fmt.error(`Template unhealthy: ${result.error}`);\n process.exit(1);\n }\n return;\n }\n\n fmt.info(\"Building E2B template with OpenFang...\");\n try {\n const result = await builder.build({\n baseTemplate: opts.base,\n openfangVersion: opts.version,\n });\n fmt.success(`Template built — sandbox ${result.templateId}`);\n fmt.info(`OpenFang ${result.openfangVersion}`);\n fmt.info(\"Save as template: e2b template save --sandbox-id \" + result.templateId);\n } catch (err) {\n fmt.error(err instanceof Error ? err.message : String(err));\n process.exit(1);\n }\n });\n","import chalk from \"chalk\";\n\nexport function success(msg: string): void {\n console.log(chalk.green(\"✓\"), msg);\n}\n\nexport function info(msg: string): void {\n console.log(chalk.blue(\"ℹ\"), msg);\n}\n\nexport function warn(msg: string): void {\n console.log(chalk.yellow(\"⚠\"), msg);\n}\n\nexport function error(msg: string): void {\n console.error(chalk.red(\"✗\"), msg);\n}\n\nexport function header(msg: string): void {\n console.log(chalk.bold.cyan(`\\n${msg}\\n`));\n}\n\nexport function table(rows: Record<string, string>[]): void {\n if (rows.length === 0) {\n info(\"No results\");\n return;\n }\n console.table(rows);\n}\n\nexport function stepStatus(\n stepId: string,\n status: \"success\" | \"failure\" | \"skipped\",\n durationMs?: number,\n): void {\n const icon =\n status === \"success\"\n ? chalk.green(\"✓\")\n : status === \"failure\"\n ? chalk.red(\"✗\")\n : chalk.gray(\"○\");\n\n const duration = durationMs ? chalk.dim(` (${(durationMs / 1000).toFixed(1)}s)`) : \"\";\n console.log(` ${icon} ${stepId}${duration}`);\n}\n","import { Command } from \"commander\";\nimport { createFangBox } from \"../../src/fangbox.js\";\nimport * as fmt from \"../formatters.js\";\n\nexport const runCommand = new Command(\"run\")\n .description(\"Run a single agent (Hand) in a sandbox\")\n .argument(\"<hand>\", \"Hand name or manifest path\")\n .requiredOption(\"-p, --prompt <prompt>\", \"Prompt to send to the agent\")\n .option(\"-t, --template <id>\", \"E2B template ID\", \"openfang-claude\")\n .option(\"--timeout <seconds>\", \"Sandbox timeout\", \"300\")\n .option(\"--claude\", \"Use Claude Code instead of OpenFang agent\")\n .action(async (hand, opts) => {\n fmt.info(`Creating sandbox with template ${opts.template}...`);\n\n const envs: Record<string, string> = {};\n if (process.env.ANTHROPIC_API_KEY) {\n envs.ANTHROPIC_API_KEY = process.env.ANTHROPIC_API_KEY;\n }\n\n try {\n const box = await createFangBox({\n templateId: opts.template,\n timeout: parseInt(opts.timeout, 10),\n envs,\n });\n\n fmt.success(`Sandbox ${box.sandboxId} ready`);\n\n let output: string;\n\n if (opts.claude) {\n fmt.info(\"Running with Claude Code...\");\n const result = await box.runClaude({ prompt: opts.prompt });\n output = result.output;\n } else {\n fmt.info(`Spawning agent: ${hand}`);\n const agent = await box.spawnAgent(hand);\n fmt.info(`Agent ${agent.id} running`);\n\n const response = await box.messageAgent(agent.id, opts.prompt);\n output = response.content;\n }\n\n fmt.header(\"Response\");\n console.log(output);\n\n fmt.info(\"Destroying sandbox...\");\n await box.destroy();\n fmt.success(\"Done\");\n } catch (err) {\n fmt.error(err instanceof Error ? err.message : String(err));\n process.exit(1);\n }\n });\n","import { Command } from \"commander\";\nimport { Fleet } from \"../../src/fleet.js\";\nimport * as fmt from \"../formatters.js\";\n\nexport const fleetCommand = new Command(\"fleet\")\n .description(\"Run a multi-agent workflow from a JSON definition\")\n .argument(\"<workflow>\", \"Path to workflow JSON file\")\n .option(\"-c, --concurrency <n>\", \"Max concurrent sandboxes\", \"3\")\n .option(\"--timeout <seconds>\", \"Default step timeout\", \"300\")\n .action(async (workflowPath, opts) => {\n const envs: Record<string, string> = {};\n if (process.env.ANTHROPIC_API_KEY) {\n envs.ANTHROPIC_API_KEY = process.env.ANTHROPIC_API_KEY;\n }\n\n const fleet = new Fleet({\n maxConcurrency: parseInt(opts.concurrency, 10),\n defaultTimeout: parseInt(opts.timeout, 10),\n envs,\n });\n\n fleet.events.on((event) => {\n switch (event.type) {\n case \"workflow:start\":\n fmt.header(`Workflow: ${event.name}`);\n break;\n case \"step:start\":\n fmt.info(`Step ${event.stepId} starting...`);\n break;\n case \"step:complete\":\n fmt.stepStatus(\n event.stepId,\n event.result.status,\n event.result.durationMs,\n );\n break;\n case \"step:skip\":\n fmt.stepStatus(event.stepId, \"skipped\");\n break;\n case \"workflow:complete\":\n fmt.header(\"Workflow Complete\");\n fmt.info(`Status: ${event.result.status}`);\n fmt.info(\n `Duration: ${(event.result.totalDurationMs / 1000).toFixed(1)}s`,\n );\n break;\n }\n });\n\n try {\n const result = await fleet.runFromFile(workflowPath);\n\n if (Object.keys(result.outputs).length > 0) {\n fmt.header(\"Outputs\");\n for (const [key, value] of Object.entries(result.outputs)) {\n console.log(` ${key}: ${value.slice(0, 200)}${value.length > 200 ? \"...\" : \"\"}`);\n }\n }\n\n if (result.status === \"failure\") {\n process.exit(1);\n }\n } catch (err) {\n fmt.error(err instanceof Error ? err.message : String(err));\n process.exit(1);\n }\n });\n","import { Command } from \"commander\";\nimport { Sandbox } from \"e2b\";\nimport * as fmt from \"../formatters.js\";\n\nexport const statusCommand = new Command(\"status\")\n .description(\"List running E2B sandboxes\")\n .action(async () => {\n try {\n const sandboxes = await Sandbox.list();\n\n if (sandboxes.length === 0) {\n fmt.info(\"No running sandboxes\");\n return;\n }\n\n fmt.header(`Running Sandboxes (${sandboxes.length})`);\n fmt.table(\n sandboxes.map((s) => ({\n id: s.sandboxId,\n template: s.templateId,\n started: s.startedAt?.toISOString() ?? \"unknown\",\n })),\n );\n } catch (err) {\n fmt.error(err instanceof Error ? err.message : String(err));\n process.exit(1);\n }\n });\n","import { Command } from \"commander\";\nimport { Sandbox } from \"e2b\";\nimport * as fmt from \"../formatters.js\";\n\nexport const logsCommand = new Command(\"logs\")\n .description(\"Stream logs from a running sandbox\")\n .argument(\"<id>\", \"Sandbox ID\")\n .option(\"-f, --follow\", \"Follow log output\")\n .action(async (id, opts) => {\n try {\n const sandbox = await Sandbox.connect(id);\n fmt.info(`Connected to sandbox ${id}`);\n\n const result = await sandbox.commands.run(\n \"journalctl -u openfang\" + (opts.follow ? \" -f\" : \" --no-pager\"),\n { timeoutMs: opts.follow ? 0 : 30_000 },\n );\n\n console.log(result.stdout);\n\n if (result.stderr) {\n fmt.warn(result.stderr);\n }\n } catch (err) {\n fmt.error(err instanceof Error ? err.message : String(err));\n process.exit(1);\n }\n });\n","import { Command } from \"commander\";\nimport { Sandbox } from \"e2b\";\nimport * as fmt from \"../formatters.js\";\n\nexport const destroyCommand = new Command(\"destroy\")\n .description(\"Tear down sandboxes\")\n .argument(\"[id]\", \"Sandbox ID (omit with --all to destroy all)\")\n .option(\"--all\", \"Destroy all running sandboxes\")\n .action(async (id, opts) => {\n try {\n if (opts.all) {\n const sandboxes = await Sandbox.list();\n if (sandboxes.length === 0) {\n fmt.info(\"No running sandboxes\");\n return;\n }\n\n fmt.info(`Destroying ${sandboxes.length} sandboxes...`);\n await Promise.all(\n sandboxes.map(async (s) => {\n const sb = await Sandbox.connect(s.sandboxId);\n await sb.kill();\n fmt.success(`Destroyed ${s.sandboxId}`);\n }),\n );\n fmt.success(\"All sandboxes destroyed\");\n return;\n }\n\n if (!id) {\n fmt.error(\"Provide a sandbox ID or use --all\");\n process.exit(1);\n }\n\n fmt.info(`Destroying sandbox ${id}...`);\n const sandbox = await Sandbox.connect(id);\n await sandbox.kill();\n fmt.success(`Destroyed ${id}`);\n } catch (err) {\n fmt.error(err instanceof Error ? err.message : String(err));\n process.exit(1);\n }\n });\n","#!/usr/bin/env node\nimport { program } from \"./index.js\";\n\nprogram.parse();\n"],"mappings":"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","names":["Command","Command","Command","Command","Command","Command","Command","Command","Sandbox","Command","Sandbox","Command","Sandbox","Command","Sandbox","Command"]}