@cloudflare/sandbox 0.7.8 → 0.7.11

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,4 +1,4 @@
1
- import { t as Sandbox } from "../sandbox-DGAjk7r3.js";
1
+ import { t as Sandbox } from "../sandbox-BYNjxjyr.js";
2
2
  import { ApplyPatchOperation, ApplyPatchResult, Editor as Editor$1, Shell as Shell$1, ShellAction, ShellResult } from "@openai/agents";
3
3
 
4
4
  //#region src/openai/index.d.ts
@@ -1,4 +1,4 @@
1
- import { l as createLogger } from "../dist-D9B_6gn_.js";
1
+ import { u as createLogger } from "../dist-CwUZf_TJ.js";
2
2
  import { applyDiff } from "@openai/agents";
3
3
 
4
4
  //#region src/openai/index.ts
@@ -1,5 +1,5 @@
1
- import { t as Sandbox } from "../sandbox-DGAjk7r3.js";
2
- import { o as OpencodeStartupContext } from "../contexts-B0qA8qmx.js";
1
+ import { t as Sandbox } from "../sandbox-BYNjxjyr.js";
2
+ import { c as OpencodeStartupContext } from "../contexts-C5xSPEYL.js";
3
3
  import { OpencodeClient } from "@opencode-ai/sdk/v2/client";
4
4
  import { Config } from "@opencode-ai/sdk/v2";
5
5
 
@@ -1,5 +1,5 @@
1
- import { l as createLogger } from "../dist-D9B_6gn_.js";
2
- import { t as ErrorCode } from "../errors-CAZT-Gtg.js";
1
+ import { u as createLogger } from "../dist-CwUZf_TJ.js";
2
+ import { t as ErrorCode } from "../errors-8W0q5Gll.js";
3
3
 
4
4
  //#region src/opencode/types.ts
5
5
  /**
@@ -73,7 +73,7 @@ async function ensureOpencodeServer(sandbox, port, directory, config) {
73
73
  try {
74
74
  await existingProcess.waitForPort(port, {
75
75
  mode: "http",
76
- path: "/global/health",
76
+ path: "/path",
77
77
  status: 200,
78
78
  timeout: OPENCODE_STARTUP_TIMEOUT_MS
79
79
  });
@@ -104,7 +104,7 @@ async function ensureOpencodeServer(sandbox, port, directory, config) {
104
104
  if (retryProcess.status === "starting") try {
105
105
  await retryProcess.waitForPort(port, {
106
106
  mode: "http",
107
- path: "/global/health",
107
+ path: "/path",
108
108
  status: 200,
109
109
  timeout: OPENCODE_STARTUP_TIMEOUT_MS
110
110
  });
@@ -156,7 +156,7 @@ async function startOpencodeServer(sandbox, port, directory, config) {
156
156
  try {
157
157
  await process.waitForPort(port, {
158
158
  mode: "http",
159
- path: "/global/health",
159
+ path: "/path",
160
160
  status: 200,
161
161
  timeout: OPENCODE_STARTUP_TIMEOUT_MS
162
162
  });
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","names":["createOpencodeClient: OpencodeClientFactory | undefined","env: Record<string, string>"],"sources":["../../src/opencode/types.ts","../../src/opencode/opencode.ts"],"sourcesContent":["import type { Config } from '@opencode-ai/sdk/v2';\nimport type { OpencodeClient } from '@opencode-ai/sdk/v2/client';\nimport { ErrorCode, type OpencodeStartupContext } from '@repo/shared/errors';\n\n/**\n * Configuration options for starting OpenCode server\n */\nexport interface OpencodeOptions {\n /** Port for OpenCode server (default: 4096) */\n port?: number;\n /** Working directory for OpenCode (default: container's cwd) */\n directory?: string;\n /** OpenCode configuration */\n config?: Config;\n}\n\n/**\n * Server lifecycle management\n */\nexport interface OpencodeServer {\n /** Port the server is running on */\n port: number;\n /** Base URL for SDK client (http://localhost:{port}) */\n url: string;\n /** Close the server gracefully */\n close(): Promise<void>;\n}\n\n/**\n * Result from createOpencode()\n * Client type comes from @opencode-ai/sdk (user's version)\n */\nexport interface OpencodeResult<TClient = OpencodeClient> {\n /** OpenCode SDK client with Sandbox transport */\n client: TClient;\n /** Server lifecycle management */\n server: OpencodeServer;\n}\n\n/**\n * Error thrown when OpenCode server fails to start\n */\nexport class OpencodeStartupError extends Error {\n public readonly code = ErrorCode.OPENCODE_STARTUP_FAILED;\n public readonly context: OpencodeStartupContext;\n\n constructor(\n message: string,\n context: OpencodeStartupContext,\n options?: ErrorOptions\n ) {\n super(message, options);\n this.name = 'OpencodeStartupError';\n this.context = context;\n }\n}\n","import type { Config } from '@opencode-ai/sdk/v2';\nimport type { OpencodeClient } from '@opencode-ai/sdk/v2/client';\nimport { createLogger, type Logger, type Process } from '@repo/shared';\nimport type { Sandbox } from '../sandbox';\nimport type { OpencodeOptions, OpencodeResult, OpencodeServer } from './types';\nimport { OpencodeStartupError } from './types';\n\n// Lazy logger creation to avoid global scope restrictions in Workers\nfunction getLogger(): Logger {\n return createLogger({ component: 'sandbox-do', operation: 'opencode' });\n}\n\nconst DEFAULT_PORT = 4096;\nconst OPENCODE_STARTUP_TIMEOUT_MS = 180_000;\nconst OPENCODE_SERVE = (port: number) =>\n `opencode serve --port ${port} --hostname 0.0.0.0`;\n\n/**\n * Build the full command, optionally with a directory prefix.\n * If directory is provided, we cd to it first so OpenCode uses it as cwd.\n */\nfunction buildOpencodeCommand(port: number, directory?: string): string {\n const serve = OPENCODE_SERVE(port);\n return directory ? `cd ${directory} && ${serve}` : serve;\n}\n\ntype OpencodeClientFactory = (options: {\n baseUrl: string;\n fetch: typeof fetch;\n directory?: string;\n}) => OpencodeClient;\n\n// Dynamic import to handle peer dependency\nlet createOpencodeClient: OpencodeClientFactory | undefined;\n\nasync function ensureSdkLoaded(): Promise<void> {\n if (createOpencodeClient) return;\n\n try {\n const sdk = await import('@opencode-ai/sdk/v2/client');\n createOpencodeClient = sdk.createOpencodeClient as OpencodeClientFactory;\n } catch {\n throw new Error(\n '@opencode-ai/sdk is required for OpenCode integration. ' +\n 'Install it with: npm install @opencode-ai/sdk'\n );\n }\n}\n\n/**\n * Find an existing OpenCode server process running on the specified port.\n * Returns the process if found and still active, null otherwise.\n * Matches by the serve command pattern since directory prefix may vary.\n */\nasync function findExistingOpencodeProcess(\n sandbox: Sandbox<unknown>,\n port: number\n): Promise<Process | null> {\n const processes = await sandbox.listProcesses();\n const serveCommand = OPENCODE_SERVE(port);\n\n for (const proc of processes) {\n // Match commands that contain the serve command (with or without cd prefix)\n if (proc.command.includes(serveCommand)) {\n if (proc.status === 'starting' || proc.status === 'running') {\n return proc;\n }\n }\n }\n\n return null;\n}\n\n/**\n * Ensures OpenCode server is running in the container.\n * Reuses existing process if one is already running on the specified port.\n * Handles concurrent startup attempts gracefully by retrying on failure.\n * Returns the process handle.\n */\nasync function ensureOpencodeServer(\n sandbox: Sandbox<unknown>,\n port: number,\n directory?: string,\n config?: Config\n): Promise<Process> {\n // Check if OpenCode is already running on this port\n const existingProcess = await findExistingOpencodeProcess(sandbox, port);\n if (existingProcess) {\n // Reuse existing process - wait for it to be ready if still starting\n if (existingProcess.status === 'starting') {\n getLogger().debug('Found starting OpenCode process, waiting for ready', {\n port,\n processId: existingProcess.id\n });\n try {\n await existingProcess.waitForPort(port, {\n mode: 'http',\n path: '/global/health',\n status: 200,\n timeout: OPENCODE_STARTUP_TIMEOUT_MS\n });\n } catch (e) {\n const logs = await existingProcess.getLogs();\n throw new OpencodeStartupError(\n `OpenCode server failed to start. Stderr: ${logs.stderr || '(empty)'}`,\n { port, stderr: logs.stderr, command: existingProcess.command },\n { cause: e }\n );\n }\n }\n getLogger().debug('Reusing existing OpenCode process', {\n port,\n processId: existingProcess.id\n });\n return existingProcess;\n }\n\n // Try to start a new OpenCode server\n try {\n return await startOpencodeServer(sandbox, port, directory, config);\n } catch (startupError) {\n // Startup failed - check if another concurrent request started the server\n // This handles the race condition where multiple requests try to start simultaneously\n const retryProcess = await findExistingOpencodeProcess(sandbox, port);\n if (retryProcess) {\n getLogger().debug(\n 'Startup failed but found concurrent process, reusing',\n {\n port,\n processId: retryProcess.id\n }\n );\n // Wait for the concurrent server to be ready\n if (retryProcess.status === 'starting') {\n try {\n await retryProcess.waitForPort(port, {\n mode: 'http',\n path: '/global/health',\n status: 200,\n timeout: OPENCODE_STARTUP_TIMEOUT_MS\n });\n } catch (e) {\n const logs = await retryProcess.getLogs();\n throw new OpencodeStartupError(\n `OpenCode server failed to start. Stderr: ${logs.stderr || '(empty)'}`,\n { port, stderr: logs.stderr, command: retryProcess.command },\n { cause: e }\n );\n }\n }\n return retryProcess;\n }\n\n // No concurrent server found - the failure was genuine\n throw startupError;\n }\n}\n\n/**\n * Internal function to start a new OpenCode server process.\n */\nasync function startOpencodeServer(\n sandbox: Sandbox<unknown>,\n port: number,\n directory?: string,\n config?: Config\n): Promise<Process> {\n getLogger().info('Starting OpenCode server', { port, directory });\n\n // Pass config via OPENCODE_CONFIG_CONTENT and also extract API keys to env vars\n // because OpenCode's provider auth looks for env vars like ANTHROPIC_API_KEY\n const env: Record<string, string> = {};\n\n if (config) {\n env.OPENCODE_CONFIG_CONTENT = JSON.stringify(config);\n\n // Extract API keys from provider config\n // Support both options.apiKey (official type) and legacy top-level apiKey\n if (\n config.provider &&\n typeof config.provider === 'object' &&\n !Array.isArray(config.provider)\n ) {\n for (const [providerId, providerConfig] of Object.entries(\n config.provider\n )) {\n if (providerId === 'cloudflare-ai-gateway') {\n continue;\n }\n\n // Try options.apiKey first (official Config type)\n let apiKey = providerConfig?.options?.apiKey;\n // Fall back to top-level apiKey for convenience\n if (!apiKey) {\n apiKey = (providerConfig as Record<string, unknown> | undefined)\n ?.apiKey as string | undefined;\n }\n if (typeof apiKey === 'string') {\n const envVar = `${providerId.toUpperCase()}_API_KEY`;\n env[envVar] = apiKey;\n }\n }\n\n const aiGatewayConfig = config.provider['cloudflare-ai-gateway'];\n if (aiGatewayConfig?.options) {\n const options = aiGatewayConfig.options as Record<string, unknown>;\n\n if (typeof options.accountId === 'string') {\n env.CLOUDFLARE_ACCOUNT_ID = options.accountId;\n }\n\n if (typeof options.gatewayId === 'string') {\n env.CLOUDFLARE_GATEWAY_ID = options.gatewayId;\n }\n\n if (typeof options.apiToken === 'string') {\n env.CLOUDFLARE_API_TOKEN = options.apiToken;\n }\n }\n }\n }\n\n const command = buildOpencodeCommand(port, directory);\n const process = await sandbox.startProcess(command, {\n env: Object.keys(env).length > 0 ? env : undefined\n });\n\n // Wait for server to be ready - check the actual health endpoint\n try {\n await process.waitForPort(port, {\n mode: 'http',\n path: '/global/health',\n status: 200,\n timeout: OPENCODE_STARTUP_TIMEOUT_MS\n });\n getLogger().info('OpenCode server started successfully', {\n port,\n processId: process.id\n });\n } catch (e) {\n const logs = await process.getLogs();\n const error = e instanceof Error ? e : undefined;\n getLogger().error('OpenCode server failed to start', error, {\n port,\n stderr: logs.stderr\n });\n throw new OpencodeStartupError(\n `OpenCode server failed to start. Stderr: ${logs.stderr || '(empty)'}`,\n { port, stderr: logs.stderr, command },\n { cause: e }\n );\n }\n\n return process;\n}\n\n/**\n * Starts an OpenCode server inside a Sandbox container.\n *\n * This function manages the server lifecycle only - use `createOpencode()` if you\n * also need a typed SDK client for programmatic access.\n *\n * If an OpenCode server is already running on the specified port, this function\n * will reuse it instead of starting a new one.\n *\n * @param sandbox - The Sandbox instance to run OpenCode in\n * @param options - Configuration options\n * @returns Promise resolving to server handle { port, url, close() }\n *\n * @example\n * ```typescript\n * import { getSandbox } from '@cloudflare/sandbox'\n * import { createOpencodeServer } from '@cloudflare/sandbox/opencode'\n *\n * const sandbox = getSandbox(env.Sandbox, 'my-agent')\n * const server = await createOpencodeServer(sandbox, {\n * directory: '/home/user/my-project',\n * config: {\n * provider: {\n * anthropic: {\n * options: { apiKey: env.ANTHROPIC_KEY }\n * },\n * // Or use Cloudflare AI Gateway (with unified billing, no provider keys needed).\n * // 'cloudflare-ai-gateway': {\n * // options: {\n * // accountId: env.CF_ACCOUNT_ID,\n * // gatewayId: env.CF_GATEWAY_ID,\n * // apiToken: env.CF_API_TOKEN\n * // },\n * // models: { 'anthropic/claude-sonnet-4-5-20250929': {} }\n * // }\n * }\n * }\n * })\n *\n * // Proxy requests to the web UI\n * return sandbox.containerFetch(request, server.port)\n *\n * // When done\n * await server.close()\n * ```\n */\nexport async function createOpencodeServer(\n sandbox: Sandbox<unknown>,\n options?: OpencodeOptions\n): Promise<OpencodeServer> {\n const port = options?.port ?? DEFAULT_PORT;\n const process = await ensureOpencodeServer(\n sandbox,\n port,\n options?.directory,\n options?.config\n );\n\n return {\n port,\n url: `http://localhost:${port}`,\n close: () => process.kill('SIGTERM')\n };\n}\n\n/**\n * Creates an OpenCode server inside a Sandbox container and returns a typed SDK client.\n *\n * This function is API-compatible with OpenCode's own createOpencode(), but uses\n * Sandbox process management instead of Node.js spawn. The returned client uses\n * a custom fetch adapter to route requests through the Sandbox container.\n *\n * If an OpenCode server is already running on the specified port, this function\n * will reuse it instead of starting a new one.\n *\n * @param sandbox - The Sandbox instance to run OpenCode in\n * @param options - Configuration options\n * @returns Promise resolving to { client, server }\n *\n * @example\n * ```typescript\n * import { getSandbox } from '@cloudflare/sandbox'\n * import { createOpencode } from '@cloudflare/sandbox/opencode'\n *\n * const sandbox = getSandbox(env.Sandbox, 'my-agent')\n * const { client, server } = await createOpencode(sandbox, {\n * directory: '/home/user/my-project',\n * config: {\n * provider: {\n * anthropic: {\n * options: { apiKey: env.ANTHROPIC_KEY }\n * },\n * // Or use Cloudflare AI Gateway (with unified billing, no provider keys needed).\n * // 'cloudflare-ai-gateway': {\n * // options: {\n * // accountId: env.CF_ACCOUNT_ID,\n * // gatewayId: env.CF_GATEWAY_ID,\n * // apiToken: env.CF_API_TOKEN\n * // },\n * // models: { 'anthropic/claude-sonnet-4-5-20250929': {} }\n * // }\n * }\n * }\n * })\n *\n * // Use the SDK client for programmatic access\n * const session = await client.session.create()\n *\n * // When done\n * await server.close()\n * ```\n */\nexport async function createOpencode<TClient = OpencodeClient>(\n sandbox: Sandbox<unknown>,\n options?: OpencodeOptions\n): Promise<OpencodeResult<TClient>> {\n await ensureSdkLoaded();\n\n const server = await createOpencodeServer(sandbox, options);\n\n const clientFactory = createOpencodeClient;\n if (!clientFactory) {\n throw new Error('OpenCode SDK client unavailable.');\n }\n\n const client = clientFactory({\n baseUrl: server.url,\n fetch: (input, init?) =>\n sandbox.containerFetch(new Request(input, init), server.port)\n });\n\n return { client: client as TClient, server };\n}\n\n/**\n * Proxy a request directly to the OpenCode server.\n *\n * Unlike `proxyToOpencode()`, this helper does not apply any web UI redirects\n * or query parameter rewrites. Use it for API/CLI traffic where raw request\n * forwarding is preferred.\n */\nexport function proxyToOpencodeServer(\n request: Request,\n sandbox: Sandbox<unknown>,\n server: OpencodeServer\n): Promise<Response> {\n return sandbox.containerFetch(request, server.port);\n}\n\n/**\n * Proxy a request to the OpenCode web UI.\n *\n * This function handles the redirect and proxying only - you must start the\n * server separately using `createOpencodeServer()`.\n *\n * Specifically handles:\n * 1. Ensuring the `?url=` parameter is set (required for OpenCode's frontend to\n * make API calls through the proxy instead of directly to localhost:4096)\n * 2. Proxying the request to the container\n *\n * @param request - The incoming HTTP request\n * @param sandbox - The Sandbox instance running OpenCode\n * @param server - The OpenCode server handle from createOpencodeServer()\n * @returns Response from OpenCode or a redirect response\n *\n * @example\n * ```typescript\n * import { getSandbox } from '@cloudflare/sandbox'\n * import { createOpencodeServer, proxyToOpencode } from '@cloudflare/sandbox/opencode'\n *\n * export default {\n * async fetch(request: Request, env: Env) {\n * const sandbox = getSandbox(env.Sandbox, 'opencode')\n * const server = await createOpencodeServer(sandbox, {\n * directory: '/home/user/project',\n * config: {\n * provider: {\n * anthropic: {\n * options: { apiKey: env.ANTHROPIC_KEY }\n * },\n * // Optional: Route all providers through Cloudflare AI Gateway\n * 'cloudflare-ai-gateway': {\n * options: {\n * accountId: env.CF_ACCOUNT_ID,\n * gatewayId: env.CF_GATEWAY_ID,\n * apiToken: env.CF_API_TOKEN\n * }\n * }\n * }\n * }\n * })\n * return proxyToOpencode(request, sandbox, server)\n * }\n * }\n * ```\n */\nexport function proxyToOpencode(\n request: Request,\n sandbox: Sandbox<unknown>,\n server: OpencodeServer\n): Response | Promise<Response> {\n const url = new URL(request.url);\n\n // OpenCode's frontend defaults to http://127.0.0.1:4096 when hostname includes\n // \"localhost\" or \"opencode.ai\". The ?url= parameter overrides this behavior.\n // We only redirect GET requests for HTML pages (initial page load).\n // API calls (POST, PATCH, etc.) and asset requests are proxied directly\n // since redirecting POST loses the request body.\n if (!url.searchParams.has('url') && request.method === 'GET') {\n const accept = request.headers.get('accept') || '';\n const isHtmlRequest = accept.includes('text/html') || url.pathname === '/';\n if (isHtmlRequest) {\n url.searchParams.set('url', url.origin);\n return Response.redirect(url.toString(), 302);\n }\n }\n\n return proxyToOpencodeServer(request, sandbox, server);\n}\n"],"mappings":"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"}
1
+ {"version":3,"file":"index.js","names":["createOpencodeClient: OpencodeClientFactory | undefined","env: Record<string, string>"],"sources":["../../src/opencode/types.ts","../../src/opencode/opencode.ts"],"sourcesContent":["import type { Config } from '@opencode-ai/sdk/v2';\nimport type { OpencodeClient } from '@opencode-ai/sdk/v2/client';\nimport { ErrorCode, type OpencodeStartupContext } from '@repo/shared/errors';\n\n/**\n * Configuration options for starting OpenCode server\n */\nexport interface OpencodeOptions {\n /** Port for OpenCode server (default: 4096) */\n port?: number;\n /** Working directory for OpenCode (default: container's cwd) */\n directory?: string;\n /** OpenCode configuration */\n config?: Config;\n}\n\n/**\n * Server lifecycle management\n */\nexport interface OpencodeServer {\n /** Port the server is running on */\n port: number;\n /** Base URL for SDK client (http://localhost:{port}) */\n url: string;\n /** Close the server gracefully */\n close(): Promise<void>;\n}\n\n/**\n * Result from createOpencode()\n * Client type comes from @opencode-ai/sdk (user's version)\n */\nexport interface OpencodeResult<TClient = OpencodeClient> {\n /** OpenCode SDK client with Sandbox transport */\n client: TClient;\n /** Server lifecycle management */\n server: OpencodeServer;\n}\n\n/**\n * Error thrown when OpenCode server fails to start\n */\nexport class OpencodeStartupError extends Error {\n public readonly code = ErrorCode.OPENCODE_STARTUP_FAILED;\n public readonly context: OpencodeStartupContext;\n\n constructor(\n message: string,\n context: OpencodeStartupContext,\n options?: ErrorOptions\n ) {\n super(message, options);\n this.name = 'OpencodeStartupError';\n this.context = context;\n }\n}\n","import type { Config } from '@opencode-ai/sdk/v2';\nimport type { OpencodeClient } from '@opencode-ai/sdk/v2/client';\nimport { createLogger, type Logger, type Process } from '@repo/shared';\nimport type { Sandbox } from '../sandbox';\nimport type { OpencodeOptions, OpencodeResult, OpencodeServer } from './types';\nimport { OpencodeStartupError } from './types';\n\n// Lazy logger creation to avoid global scope restrictions in Workers\nfunction getLogger(): Logger {\n return createLogger({ component: 'sandbox-do', operation: 'opencode' });\n}\n\nconst DEFAULT_PORT = 4096;\nconst OPENCODE_STARTUP_TIMEOUT_MS = 180_000;\nconst OPENCODE_SERVE = (port: number) =>\n `opencode serve --port ${port} --hostname 0.0.0.0`;\n\n/**\n * Build the full command, optionally with a directory prefix.\n * If directory is provided, we cd to it first so OpenCode uses it as cwd.\n */\nfunction buildOpencodeCommand(port: number, directory?: string): string {\n const serve = OPENCODE_SERVE(port);\n return directory ? `cd ${directory} && ${serve}` : serve;\n}\n\ntype OpencodeClientFactory = (options: {\n baseUrl: string;\n fetch: typeof fetch;\n directory?: string;\n}) => OpencodeClient;\n\n// Dynamic import to handle peer dependency\nlet createOpencodeClient: OpencodeClientFactory | undefined;\n\nasync function ensureSdkLoaded(): Promise<void> {\n if (createOpencodeClient) return;\n\n try {\n const sdk = await import('@opencode-ai/sdk/v2/client');\n createOpencodeClient = sdk.createOpencodeClient as OpencodeClientFactory;\n } catch {\n throw new Error(\n '@opencode-ai/sdk is required for OpenCode integration. ' +\n 'Install it with: npm install @opencode-ai/sdk'\n );\n }\n}\n\n/**\n * Find an existing OpenCode server process running on the specified port.\n * Returns the process if found and still active, null otherwise.\n * Matches by the serve command pattern since directory prefix may vary.\n */\nasync function findExistingOpencodeProcess(\n sandbox: Sandbox<unknown>,\n port: number\n): Promise<Process | null> {\n const processes = await sandbox.listProcesses();\n const serveCommand = OPENCODE_SERVE(port);\n\n for (const proc of processes) {\n // Match commands that contain the serve command (with or without cd prefix)\n if (proc.command.includes(serveCommand)) {\n if (proc.status === 'starting' || proc.status === 'running') {\n return proc;\n }\n }\n }\n\n return null;\n}\n\n/**\n * Ensures OpenCode server is running in the container.\n * Reuses existing process if one is already running on the specified port.\n * Handles concurrent startup attempts gracefully by retrying on failure.\n * Returns the process handle.\n */\nasync function ensureOpencodeServer(\n sandbox: Sandbox<unknown>,\n port: number,\n directory?: string,\n config?: Config\n): Promise<Process> {\n // Check if OpenCode is already running on this port\n const existingProcess = await findExistingOpencodeProcess(sandbox, port);\n if (existingProcess) {\n // Reuse existing process - wait for it to be ready if still starting\n if (existingProcess.status === 'starting') {\n getLogger().debug('Found starting OpenCode process, waiting for ready', {\n port,\n processId: existingProcess.id\n });\n try {\n await existingProcess.waitForPort(port, {\n mode: 'http',\n path: '/path',\n status: 200,\n timeout: OPENCODE_STARTUP_TIMEOUT_MS\n });\n } catch (e) {\n const logs = await existingProcess.getLogs();\n throw new OpencodeStartupError(\n `OpenCode server failed to start. Stderr: ${logs.stderr || '(empty)'}`,\n { port, stderr: logs.stderr, command: existingProcess.command },\n { cause: e }\n );\n }\n }\n getLogger().debug('Reusing existing OpenCode process', {\n port,\n processId: existingProcess.id\n });\n return existingProcess;\n }\n\n // Try to start a new OpenCode server\n try {\n return await startOpencodeServer(sandbox, port, directory, config);\n } catch (startupError) {\n // Startup failed - check if another concurrent request started the server\n // This handles the race condition where multiple requests try to start simultaneously\n const retryProcess = await findExistingOpencodeProcess(sandbox, port);\n if (retryProcess) {\n getLogger().debug(\n 'Startup failed but found concurrent process, reusing',\n {\n port,\n processId: retryProcess.id\n }\n );\n // Wait for the concurrent server to be ready\n if (retryProcess.status === 'starting') {\n try {\n await retryProcess.waitForPort(port, {\n mode: 'http',\n path: '/path',\n status: 200,\n timeout: OPENCODE_STARTUP_TIMEOUT_MS\n });\n } catch (e) {\n const logs = await retryProcess.getLogs();\n throw new OpencodeStartupError(\n `OpenCode server failed to start. Stderr: ${logs.stderr || '(empty)'}`,\n { port, stderr: logs.stderr, command: retryProcess.command },\n { cause: e }\n );\n }\n }\n return retryProcess;\n }\n\n // No concurrent server found - the failure was genuine\n throw startupError;\n }\n}\n\n/**\n * Internal function to start a new OpenCode server process.\n */\nasync function startOpencodeServer(\n sandbox: Sandbox<unknown>,\n port: number,\n directory?: string,\n config?: Config\n): Promise<Process> {\n getLogger().info('Starting OpenCode server', { port, directory });\n\n // Pass config via OPENCODE_CONFIG_CONTENT and also extract API keys to env vars\n // because OpenCode's provider auth looks for env vars like ANTHROPIC_API_KEY\n const env: Record<string, string> = {};\n\n if (config) {\n env.OPENCODE_CONFIG_CONTENT = JSON.stringify(config);\n\n // Extract API keys from provider config\n // Support both options.apiKey (official type) and legacy top-level apiKey\n if (\n config.provider &&\n typeof config.provider === 'object' &&\n !Array.isArray(config.provider)\n ) {\n for (const [providerId, providerConfig] of Object.entries(\n config.provider\n )) {\n if (providerId === 'cloudflare-ai-gateway') {\n continue;\n }\n\n // Try options.apiKey first (official Config type)\n let apiKey = providerConfig?.options?.apiKey;\n // Fall back to top-level apiKey for convenience\n if (!apiKey) {\n apiKey = (providerConfig as Record<string, unknown> | undefined)\n ?.apiKey as string | undefined;\n }\n if (typeof apiKey === 'string') {\n const envVar = `${providerId.toUpperCase()}_API_KEY`;\n env[envVar] = apiKey;\n }\n }\n\n const aiGatewayConfig = config.provider['cloudflare-ai-gateway'];\n if (aiGatewayConfig?.options) {\n const options = aiGatewayConfig.options as Record<string, unknown>;\n\n if (typeof options.accountId === 'string') {\n env.CLOUDFLARE_ACCOUNT_ID = options.accountId;\n }\n\n if (typeof options.gatewayId === 'string') {\n env.CLOUDFLARE_GATEWAY_ID = options.gatewayId;\n }\n\n if (typeof options.apiToken === 'string') {\n env.CLOUDFLARE_API_TOKEN = options.apiToken;\n }\n }\n }\n }\n\n const command = buildOpencodeCommand(port, directory);\n const process = await sandbox.startProcess(command, {\n env: Object.keys(env).length > 0 ? env : undefined\n });\n\n // Wait for server to be ready - check the actual health endpoint\n try {\n await process.waitForPort(port, {\n mode: 'http',\n path: '/path',\n status: 200,\n timeout: OPENCODE_STARTUP_TIMEOUT_MS\n });\n getLogger().info('OpenCode server started successfully', {\n port,\n processId: process.id\n });\n } catch (e) {\n const logs = await process.getLogs();\n const error = e instanceof Error ? e : undefined;\n getLogger().error('OpenCode server failed to start', error, {\n port,\n stderr: logs.stderr\n });\n throw new OpencodeStartupError(\n `OpenCode server failed to start. Stderr: ${logs.stderr || '(empty)'}`,\n { port, stderr: logs.stderr, command },\n { cause: e }\n );\n }\n\n return process;\n}\n\n/**\n * Starts an OpenCode server inside a Sandbox container.\n *\n * This function manages the server lifecycle only - use `createOpencode()` if you\n * also need a typed SDK client for programmatic access.\n *\n * If an OpenCode server is already running on the specified port, this function\n * will reuse it instead of starting a new one.\n *\n * @param sandbox - The Sandbox instance to run OpenCode in\n * @param options - Configuration options\n * @returns Promise resolving to server handle { port, url, close() }\n *\n * @example\n * ```typescript\n * import { getSandbox } from '@cloudflare/sandbox'\n * import { createOpencodeServer } from '@cloudflare/sandbox/opencode'\n *\n * const sandbox = getSandbox(env.Sandbox, 'my-agent')\n * const server = await createOpencodeServer(sandbox, {\n * directory: '/home/user/my-project',\n * config: {\n * provider: {\n * anthropic: {\n * options: { apiKey: env.ANTHROPIC_KEY }\n * },\n * // Or use Cloudflare AI Gateway (with unified billing, no provider keys needed).\n * // 'cloudflare-ai-gateway': {\n * // options: {\n * // accountId: env.CF_ACCOUNT_ID,\n * // gatewayId: env.CF_GATEWAY_ID,\n * // apiToken: env.CF_API_TOKEN\n * // },\n * // models: { 'anthropic/claude-sonnet-4-5-20250929': {} }\n * // }\n * }\n * }\n * })\n *\n * // Proxy requests to the web UI\n * return sandbox.containerFetch(request, server.port)\n *\n * // When done\n * await server.close()\n * ```\n */\nexport async function createOpencodeServer(\n sandbox: Sandbox<unknown>,\n options?: OpencodeOptions\n): Promise<OpencodeServer> {\n const port = options?.port ?? DEFAULT_PORT;\n const process = await ensureOpencodeServer(\n sandbox,\n port,\n options?.directory,\n options?.config\n );\n\n return {\n port,\n url: `http://localhost:${port}`,\n close: () => process.kill('SIGTERM')\n };\n}\n\n/**\n * Creates an OpenCode server inside a Sandbox container and returns a typed SDK client.\n *\n * This function is API-compatible with OpenCode's own createOpencode(), but uses\n * Sandbox process management instead of Node.js spawn. The returned client uses\n * a custom fetch adapter to route requests through the Sandbox container.\n *\n * If an OpenCode server is already running on the specified port, this function\n * will reuse it instead of starting a new one.\n *\n * @param sandbox - The Sandbox instance to run OpenCode in\n * @param options - Configuration options\n * @returns Promise resolving to { client, server }\n *\n * @example\n * ```typescript\n * import { getSandbox } from '@cloudflare/sandbox'\n * import { createOpencode } from '@cloudflare/sandbox/opencode'\n *\n * const sandbox = getSandbox(env.Sandbox, 'my-agent')\n * const { client, server } = await createOpencode(sandbox, {\n * directory: '/home/user/my-project',\n * config: {\n * provider: {\n * anthropic: {\n * options: { apiKey: env.ANTHROPIC_KEY }\n * },\n * // Or use Cloudflare AI Gateway (with unified billing, no provider keys needed).\n * // 'cloudflare-ai-gateway': {\n * // options: {\n * // accountId: env.CF_ACCOUNT_ID,\n * // gatewayId: env.CF_GATEWAY_ID,\n * // apiToken: env.CF_API_TOKEN\n * // },\n * // models: { 'anthropic/claude-sonnet-4-5-20250929': {} }\n * // }\n * }\n * }\n * })\n *\n * // Use the SDK client for programmatic access\n * const session = await client.session.create()\n *\n * // When done\n * await server.close()\n * ```\n */\nexport async function createOpencode<TClient = OpencodeClient>(\n sandbox: Sandbox<unknown>,\n options?: OpencodeOptions\n): Promise<OpencodeResult<TClient>> {\n await ensureSdkLoaded();\n\n const server = await createOpencodeServer(sandbox, options);\n\n const clientFactory = createOpencodeClient;\n if (!clientFactory) {\n throw new Error('OpenCode SDK client unavailable.');\n }\n\n const client = clientFactory({\n baseUrl: server.url,\n fetch: (input, init?) =>\n sandbox.containerFetch(new Request(input, init), server.port)\n });\n\n return { client: client as TClient, server };\n}\n\n/**\n * Proxy a request directly to the OpenCode server.\n *\n * Unlike `proxyToOpencode()`, this helper does not apply any web UI redirects\n * or query parameter rewrites. Use it for API/CLI traffic where raw request\n * forwarding is preferred.\n */\nexport function proxyToOpencodeServer(\n request: Request,\n sandbox: Sandbox<unknown>,\n server: OpencodeServer\n): Promise<Response> {\n return sandbox.containerFetch(request, server.port);\n}\n\n/**\n * Proxy a request to the OpenCode web UI.\n *\n * This function handles the redirect and proxying only - you must start the\n * server separately using `createOpencodeServer()`.\n *\n * Specifically handles:\n * 1. Ensuring the `?url=` parameter is set (required for OpenCode's frontend to\n * make API calls through the proxy instead of directly to localhost:4096)\n * 2. Proxying the request to the container\n *\n * @param request - The incoming HTTP request\n * @param sandbox - The Sandbox instance running OpenCode\n * @param server - The OpenCode server handle from createOpencodeServer()\n * @returns Response from OpenCode or a redirect response\n *\n * @example\n * ```typescript\n * import { getSandbox } from '@cloudflare/sandbox'\n * import { createOpencodeServer, proxyToOpencode } from '@cloudflare/sandbox/opencode'\n *\n * export default {\n * async fetch(request: Request, env: Env) {\n * const sandbox = getSandbox(env.Sandbox, 'opencode')\n * const server = await createOpencodeServer(sandbox, {\n * directory: '/home/user/project',\n * config: {\n * provider: {\n * anthropic: {\n * options: { apiKey: env.ANTHROPIC_KEY }\n * },\n * // Optional: Route all providers through Cloudflare AI Gateway\n * 'cloudflare-ai-gateway': {\n * options: {\n * accountId: env.CF_ACCOUNT_ID,\n * gatewayId: env.CF_GATEWAY_ID,\n * apiToken: env.CF_API_TOKEN\n * }\n * }\n * }\n * }\n * })\n * return proxyToOpencode(request, sandbox, server)\n * }\n * }\n * ```\n */\nexport function proxyToOpencode(\n request: Request,\n sandbox: Sandbox<unknown>,\n server: OpencodeServer\n): Response | Promise<Response> {\n const url = new URL(request.url);\n\n // OpenCode's frontend defaults to http://127.0.0.1:4096 when hostname includes\n // \"localhost\" or \"opencode.ai\". The ?url= parameter overrides this behavior.\n // We only redirect GET requests for HTML pages (initial page load).\n // API calls (POST, PATCH, etc.) and asset requests are proxied directly\n // since redirecting POST loses the request body.\n if (!url.searchParams.has('url') && request.method === 'GET') {\n const accept = request.headers.get('accept') || '';\n const isHtmlRequest = accept.includes('text/html') || url.pathname === '/';\n if (isHtmlRequest) {\n url.searchParams.set('url', url.origin);\n return Response.redirect(url.toString(), 302);\n }\n }\n\n return proxyToOpencodeServer(request, sandbox, server);\n}\n"],"mappings":"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"}
@@ -941,6 +941,71 @@ interface FileMetadata {
941
941
  * File stream chunk - either string (text) or Uint8Array (binary, auto-decoded)
942
942
  */
943
943
  type FileChunk = string | Uint8Array;
944
+ /**
945
+ * Options for watching a directory.
946
+ *
947
+ * `watch()` resolves only after the watcher is established on the filesystem.
948
+ * The returned SSE stream can be consumed with `parseSSEStream()`.
949
+ */
950
+ interface WatchOptions {
951
+ /**
952
+ * Watch subdirectories recursively
953
+ * @default true
954
+ */
955
+ recursive?: boolean;
956
+ /**
957
+ * Glob patterns to include (e.g., '*.ts', '*.js').
958
+ * If not specified, all files are included.
959
+ * Cannot be used together with `exclude`.
960
+ */
961
+ include?: string[];
962
+ /**
963
+ * Glob patterns to exclude (e.g., 'node_modules', '.git').
964
+ * Cannot be used together with `include`.
965
+ * @default ['.git', 'node_modules', '.DS_Store']
966
+ */
967
+ exclude?: string[];
968
+ /**
969
+ * Session to run the watch in.
970
+ * If omitted, the default session is used.
971
+ */
972
+ sessionId?: string;
973
+ }
974
+ /**
975
+ * @internal SSE event types for container communication
976
+ */
977
+ type FileWatchEventType = 'create' | 'modify' | 'delete' | 'move_from' | 'move_to' | 'attrib';
978
+ /**
979
+ * @internal Request body for starting a file watch
980
+ */
981
+ interface WatchRequest {
982
+ path: string;
983
+ recursive?: boolean;
984
+ events?: FileWatchEventType[];
985
+ include?: string[];
986
+ exclude?: string[];
987
+ sessionId?: string;
988
+ }
989
+ /**
990
+ * SSE events emitted by `sandbox.watch()`.
991
+ */
992
+ type FileWatchSSEEvent = {
993
+ type: 'watching';
994
+ path: string;
995
+ watchId: string;
996
+ } | {
997
+ type: 'event';
998
+ eventType: FileWatchEventType;
999
+ path: string;
1000
+ isDirectory: boolean;
1001
+ timestamp: string;
1002
+ } | {
1003
+ type: 'error';
1004
+ error: string;
1005
+ } | {
1006
+ type: 'stopped';
1007
+ reason: string;
1008
+ };
944
1009
  interface ProcessStartResult {
945
1010
  success: boolean;
946
1011
  processId: string;
@@ -1043,6 +1108,7 @@ interface ExecutionSession {
1043
1108
  encoding?: string;
1044
1109
  }): Promise<ReadFileResult>;
1045
1110
  readFileStream(path: string): Promise<ReadableStream<Uint8Array>>;
1111
+ watch(path: string, options?: Omit<WatchOptions, 'sessionId'>): Promise<ReadableStream<Uint8Array>>;
1046
1112
  mkdir(path: string, options?: {
1047
1113
  recursive?: boolean;
1048
1114
  }): Promise<MkdirResult>;
@@ -1193,6 +1259,7 @@ interface ISandbox {
1193
1259
  encoding?: string;
1194
1260
  }): Promise<ReadFileResult>;
1195
1261
  readFileStream(path: string): Promise<ReadableStream<Uint8Array>>;
1262
+ watch(path: string, options?: WatchOptions): Promise<ReadableStream<Uint8Array>>;
1196
1263
  mkdir(path: string, options?: {
1197
1264
  recursive?: boolean;
1198
1265
  }): Promise<MkdirResult>;
@@ -1476,6 +1543,225 @@ declare class CommandClient extends BaseHttpClient {
1476
1543
  }): Promise<ReadableStream<Uint8Array>>;
1477
1544
  }
1478
1545
  //#endregion
1546
+ //#region src/clients/desktop-client.d.ts
1547
+ interface DesktopStartOptions {
1548
+ resolution?: [number, number];
1549
+ dpi?: number;
1550
+ }
1551
+ interface ScreenshotOptions {
1552
+ format?: 'base64' | 'bytes';
1553
+ imageFormat?: 'png' | 'jpeg' | 'webp';
1554
+ quality?: number;
1555
+ showCursor?: boolean;
1556
+ }
1557
+ interface ScreenshotRegion {
1558
+ x: number;
1559
+ y: number;
1560
+ width: number;
1561
+ height: number;
1562
+ }
1563
+ interface ClickOptions {
1564
+ button?: 'left' | 'right' | 'middle';
1565
+ }
1566
+ type ScrollDirection = 'up' | 'down' | 'left' | 'right';
1567
+ type KeyInput = string;
1568
+ interface TypeOptions {
1569
+ delayMs?: number;
1570
+ }
1571
+ interface DesktopStartResponse extends BaseApiResponse {
1572
+ resolution: [number, number];
1573
+ dpi: number;
1574
+ }
1575
+ interface DesktopStopResponse extends BaseApiResponse {}
1576
+ interface DesktopStatusResponse extends BaseApiResponse {
1577
+ status: 'active' | 'partial' | 'inactive';
1578
+ processes: Record<string, {
1579
+ running: boolean;
1580
+ pid?: number;
1581
+ uptime?: number;
1582
+ }>;
1583
+ resolution: [number, number] | null;
1584
+ dpi: number | null;
1585
+ }
1586
+ interface ScreenshotResponse extends BaseApiResponse {
1587
+ data: string;
1588
+ imageFormat: 'png' | 'jpeg' | 'webp';
1589
+ width: number;
1590
+ height: number;
1591
+ }
1592
+ interface ScreenshotBytesResponse extends BaseApiResponse {
1593
+ data: Uint8Array;
1594
+ imageFormat: 'png' | 'jpeg' | 'webp';
1595
+ width: number;
1596
+ height: number;
1597
+ }
1598
+ interface CursorPositionResponse extends BaseApiResponse {
1599
+ x: number;
1600
+ y: number;
1601
+ }
1602
+ interface ScreenSizeResponse extends BaseApiResponse {
1603
+ width: number;
1604
+ height: number;
1605
+ }
1606
+ /**
1607
+ * Public interface for desktop operations.
1608
+ * Returned by `sandbox.desktop` via an RpcTarget wrapper so that pipelined
1609
+ * method calls work across the Durable Object RPC boundary.
1610
+ */
1611
+ interface Desktop {
1612
+ start(options?: DesktopStartOptions): Promise<DesktopStartResponse>;
1613
+ stop(): Promise<DesktopStopResponse>;
1614
+ status(): Promise<DesktopStatusResponse>;
1615
+ screenshot(options?: ScreenshotOptions & {
1616
+ format?: 'base64';
1617
+ }): Promise<ScreenshotResponse>;
1618
+ screenshot(options: ScreenshotOptions & {
1619
+ format: 'bytes';
1620
+ }): Promise<ScreenshotBytesResponse>;
1621
+ screenshot(options?: ScreenshotOptions): Promise<ScreenshotResponse | ScreenshotBytesResponse>;
1622
+ screenshotRegion(region: ScreenshotRegion, options?: ScreenshotOptions & {
1623
+ format?: 'base64';
1624
+ }): Promise<ScreenshotResponse>;
1625
+ screenshotRegion(region: ScreenshotRegion, options: ScreenshotOptions & {
1626
+ format: 'bytes';
1627
+ }): Promise<ScreenshotBytesResponse>;
1628
+ screenshotRegion(region: ScreenshotRegion, options?: ScreenshotOptions): Promise<ScreenshotResponse | ScreenshotBytesResponse>;
1629
+ click(x: number, y: number, options?: ClickOptions): Promise<void>;
1630
+ doubleClick(x: number, y: number, options?: ClickOptions): Promise<void>;
1631
+ tripleClick(x: number, y: number, options?: ClickOptions): Promise<void>;
1632
+ rightClick(x: number, y: number): Promise<void>;
1633
+ middleClick(x: number, y: number): Promise<void>;
1634
+ mouseDown(x?: number, y?: number, options?: ClickOptions): Promise<void>;
1635
+ mouseUp(x?: number, y?: number, options?: ClickOptions): Promise<void>;
1636
+ moveMouse(x: number, y: number): Promise<void>;
1637
+ drag(startX: number, startY: number, endX: number, endY: number, options?: ClickOptions): Promise<void>;
1638
+ scroll(x: number, y: number, direction: ScrollDirection, amount?: number): Promise<void>;
1639
+ getCursorPosition(): Promise<CursorPositionResponse>;
1640
+ type(text: string, options?: TypeOptions): Promise<void>;
1641
+ press(key: KeyInput): Promise<void>;
1642
+ keyDown(key: KeyInput): Promise<void>;
1643
+ keyUp(key: KeyInput): Promise<void>;
1644
+ getScreenSize(): Promise<ScreenSizeResponse>;
1645
+ getProcessStatus(name: string): Promise<BaseApiResponse & {
1646
+ running: boolean;
1647
+ pid?: number;
1648
+ uptime?: number;
1649
+ }>;
1650
+ }
1651
+ /**
1652
+ * Client for desktop environment lifecycle, input, and screen operations
1653
+ */
1654
+ declare class DesktopClient extends BaseHttpClient {
1655
+ /**
1656
+ * Start the desktop environment with optional resolution and DPI.
1657
+ */
1658
+ start(options?: DesktopStartOptions): Promise<DesktopStartResponse>;
1659
+ /**
1660
+ * Stop the desktop environment and all related processes.
1661
+ */
1662
+ stop(): Promise<DesktopStopResponse>;
1663
+ /**
1664
+ * Get desktop lifecycle and process health status.
1665
+ */
1666
+ status(): Promise<DesktopStatusResponse>;
1667
+ /**
1668
+ * Capture a full-screen screenshot as base64 (default).
1669
+ */
1670
+ screenshot(options?: ScreenshotOptions & {
1671
+ format?: 'base64';
1672
+ }): Promise<ScreenshotResponse>;
1673
+ /**
1674
+ * Capture a full-screen screenshot as bytes.
1675
+ */
1676
+ screenshot(options: ScreenshotOptions & {
1677
+ format: 'bytes';
1678
+ }): Promise<ScreenshotBytesResponse>;
1679
+ /**
1680
+ * Capture a region screenshot as base64 (default).
1681
+ */
1682
+ screenshotRegion(region: ScreenshotRegion, options?: ScreenshotOptions & {
1683
+ format?: 'base64';
1684
+ }): Promise<ScreenshotResponse>;
1685
+ /**
1686
+ * Capture a region screenshot as bytes.
1687
+ */
1688
+ screenshotRegion(region: ScreenshotRegion, options: ScreenshotOptions & {
1689
+ format: 'bytes';
1690
+ }): Promise<ScreenshotBytesResponse>;
1691
+ /**
1692
+ * Single-click at the given coordinates.
1693
+ */
1694
+ click(x: number, y: number, options?: ClickOptions): Promise<void>;
1695
+ /**
1696
+ * Double-click at the given coordinates.
1697
+ */
1698
+ doubleClick(x: number, y: number, options?: ClickOptions): Promise<void>;
1699
+ /**
1700
+ * Triple-click at the given coordinates.
1701
+ */
1702
+ tripleClick(x: number, y: number, options?: ClickOptions): Promise<void>;
1703
+ /**
1704
+ * Right-click at the given coordinates.
1705
+ */
1706
+ rightClick(x: number, y: number): Promise<void>;
1707
+ /**
1708
+ * Middle-click at the given coordinates.
1709
+ */
1710
+ middleClick(x: number, y: number): Promise<void>;
1711
+ /**
1712
+ * Press and hold a mouse button.
1713
+ */
1714
+ mouseDown(x?: number, y?: number, options?: ClickOptions): Promise<void>;
1715
+ /**
1716
+ * Release a held mouse button.
1717
+ */
1718
+ mouseUp(x?: number, y?: number, options?: ClickOptions): Promise<void>;
1719
+ /**
1720
+ * Move the mouse cursor to coordinates.
1721
+ */
1722
+ moveMouse(x: number, y: number): Promise<void>;
1723
+ /**
1724
+ * Drag from start coordinates to end coordinates.
1725
+ */
1726
+ drag(startX: number, startY: number, endX: number, endY: number, options?: ClickOptions): Promise<void>;
1727
+ /**
1728
+ * Scroll at coordinates in the specified direction.
1729
+ */
1730
+ scroll(x: number, y: number, direction: ScrollDirection, amount?: number): Promise<void>;
1731
+ /**
1732
+ * Get the current cursor coordinates.
1733
+ */
1734
+ getCursorPosition(): Promise<CursorPositionResponse>;
1735
+ /**
1736
+ * Type text into the focused element.
1737
+ */
1738
+ type(text: string, options?: TypeOptions): Promise<void>;
1739
+ /**
1740
+ * Press and release a key or key combination.
1741
+ */
1742
+ press(key: KeyInput): Promise<void>;
1743
+ /**
1744
+ * Press and hold a key.
1745
+ */
1746
+ keyDown(key: KeyInput): Promise<void>;
1747
+ /**
1748
+ * Release a held key.
1749
+ */
1750
+ keyUp(key: KeyInput): Promise<void>;
1751
+ /**
1752
+ * Get the active desktop screen size.
1753
+ */
1754
+ getScreenSize(): Promise<ScreenSizeResponse>;
1755
+ /**
1756
+ * Get health status for a specific desktop process.
1757
+ */
1758
+ getProcessStatus(name: string): Promise<BaseApiResponse & {
1759
+ running: boolean;
1760
+ pid?: number;
1761
+ uptime?: number;
1762
+ }>;
1763
+ }
1764
+ //#endregion
1479
1765
  //#region src/clients/file-client.d.ts
1480
1766
  /**
1481
1767
  * Request interface for creating directories
@@ -1796,6 +2082,33 @@ declare class UtilityClient extends BaseHttpClient {
1796
2082
  getVersion(): Promise<string>;
1797
2083
  }
1798
2084
  //#endregion
2085
+ //#region src/clients/watch-client.d.ts
2086
+ /**
2087
+ * Client for file watch operations
2088
+ * Uses inotify under the hood for native filesystem event notifications
2089
+ *
2090
+ * @internal This client is used internally by the SDK.
2091
+ * Users should use `sandbox.watch()` instead.
2092
+ */
2093
+ declare class WatchClient extends BaseHttpClient {
2094
+ /**
2095
+ * Start watching a directory for changes.
2096
+ * The returned promise resolves only after the watcher is established
2097
+ * on the filesystem (i.e. the `watching` SSE event has been received).
2098
+ * The returned stream still contains the `watching` event so consumers
2099
+ * using `parseSSEStream` will see the full event sequence.
2100
+ *
2101
+ * @param request - Watch request with path and options
2102
+ */
2103
+ watch(request: WatchRequest): Promise<ReadableStream<Uint8Array>>;
2104
+ /**
2105
+ * Read SSE chunks until the `watching` event appears, then return a
2106
+ * wrapper stream that replays the buffered chunks followed by the
2107
+ * remaining original stream data.
2108
+ */
2109
+ private waitForReadiness;
2110
+ }
2111
+ //#endregion
1799
2112
  //#region src/clients/sandbox-client.d.ts
1800
2113
  /**
1801
2114
  * Main sandbox client that composes all domain-specific clients
@@ -1816,6 +2129,8 @@ declare class SandboxClient {
1816
2129
  readonly git: GitClient;
1817
2130
  readonly interpreter: InterpreterClient;
1818
2131
  readonly utils: UtilityClient;
2132
+ readonly desktop: DesktopClient;
2133
+ readonly watch: WatchClient;
1819
2134
  private transport;
1820
2135
  constructor(options: HttpClientOptions);
1821
2136
  /**
@@ -1883,6 +2198,25 @@ declare class Sandbox<Env = unknown> extends Container<Env> implements ISandbox
1883
2198
  * Can be set via options, env vars, or defaults
1884
2199
  */
1885
2200
  private containerTimeouts;
2201
+ /**
2202
+ * Desktop environment operations.
2203
+ * Within the DO, this getter provides direct access to DesktopClient.
2204
+ * Over RPC, the getSandbox() proxy intercepts this property and routes
2205
+ * calls through callDesktop() instead.
2206
+ */
2207
+ get desktop(): Desktop;
2208
+ /**
2209
+ * Allowed desktop methods — derived from the Desktop interface.
2210
+ * Restricts callDesktop() to a known set of operations.
2211
+ */
2212
+ private static readonly DESKTOP_METHODS;
2213
+ /**
2214
+ * Dispatch method for desktop operations.
2215
+ * Called by the client-side proxy created in getSandbox() to provide
2216
+ * the `sandbox.desktop.status()` API without relying on RPC pipelining
2217
+ * through property getters.
2218
+ */
2219
+ callDesktop(method: string, args: unknown[]): Promise<unknown>;
1886
2220
  /**
1887
2221
  * Create a SandboxClient with current transport settings
1888
2222
  */
@@ -2100,6 +2434,37 @@ declare class Sandbox<Env = unknown> extends Container<Env> implements ISandbox
2100
2434
  includeHidden?: boolean;
2101
2435
  }): Promise<ListFilesResult>;
2102
2436
  exists(path: string, sessionId?: string): Promise<FileExistsResult>;
2437
+ /**
2438
+ * Get the noVNC preview URL for browser-based desktop viewing.
2439
+ * Confirms desktop is active, then uses exposePort() to generate
2440
+ * a token-authenticated preview URL for the noVNC port (6080).
2441
+ *
2442
+ * @param hostname - The custom domain hostname for preview URLs
2443
+ * (e.g., 'preview.example.com'). Required because preview URLs
2444
+ * use subdomain patterns that .workers.dev doesn't support.
2445
+ * @param options - Optional settings
2446
+ * @param options.token - Reuse an existing token instead of generating a new one
2447
+ * @returns The authenticated noVNC preview URL
2448
+ */
2449
+ getDesktopStreamUrl(hostname: string, options?: {
2450
+ token?: string;
2451
+ }): Promise<{
2452
+ url: string;
2453
+ }>;
2454
+ /**
2455
+ * Watch a directory for file system changes using native inotify.
2456
+ *
2457
+ * The returned promise resolves only after the watcher is established on the
2458
+ * filesystem, so callers can immediately perform actions that depend on the
2459
+ * watch being active. The returned stream contains the full event sequence
2460
+ * starting with the `watching` event.
2461
+ *
2462
+ * Consume the stream with `parseSSEStream<FileWatchSSEEvent>(stream)`.
2463
+ *
2464
+ * @param path - Path to watch (absolute or relative to /workspace)
2465
+ * @param options - Watch options
2466
+ */
2467
+ watch(path: string, options?: WatchOptions): Promise<ReadableStream<Uint8Array>>;
2103
2468
  /**
2104
2469
  * Expose a port and get a preview URL for accessing services running in the sandbox
2105
2470
  *
@@ -2283,5 +2648,5 @@ declare class Sandbox<Env = unknown> extends Container<Env> implements ISandbox
2283
2648
  private doRestoreBackup;
2284
2649
  }
2285
2650
  //#endregion
2286
- export { Process as $, RequestConfig as A, ExecResult as B, CommandClient as C, Execution as Ct, ContainerStub as D, BaseApiResponse as E, BucketCredentials as F, GitCheckoutResult as G, FileChunk as H, BucketProvider as I, LogEvent as J, ISandbox as K, DirectoryBackup as L, SessionRequest as M, BackupOptions as N, ErrorResponse as O, BaseExecOptions as P, PortListResult as Q, ExecEvent as R, WriteFileRequest as S, CreateContextOptions as St, BackupClient as T, RunCodeOptions as Tt, FileMetadata as U, ExecutionSession as V, FileStreamEvent as W, PortCloseResult as X, MountBucketOptions as Y, PortExposeResult as Z, GitClient as _, ExecuteRequest as _t, CreateSessionRequest as a, ProcessOptions as at, MkdirRequest as b, PtyOptions as bt, DeleteSessionResponse as c, RestoreBackupResult as ct, ProcessClient as d, StreamOptions as dt, ProcessCleanupResult as et, PortClient as f, WaitForLogResult as ft, GitCheckoutRequest as g, isProcessStatus as gt, InterpreterClient as h, isProcess as ht, CommandsResponse as i, ProcessLogsResult as it, ResponseHandler as j, HttpClientOptions as k, PingResponse as l, SandboxOptions as lt, ExecutionCallbacks as m, isExecResult as mt, getSandbox as n, ProcessKillResult as nt, CreateSessionResponse as o, ProcessStartResult as ot, UnexposePortRequest as p, WaitForPortOptions as pt, ListFilesOptions as q, SandboxClient as r, ProcessListResult as rt, DeleteSessionRequest as s, ProcessStatus as st, Sandbox as t, ProcessInfoResult as tt, UtilityClient as u, SessionOptions as ut, FileClient as v, ExposePortRequest as vt, ExecuteResponse as w, ExecutionResult as wt, ReadFileRequest as x, CodeContext as xt, FileOperationRequest as y, StartProcessRequest as yt, ExecOptions as z };
2287
- //# sourceMappingURL=sandbox-DGAjk7r3.d.ts.map
2651
+ export { DirectoryBackup as $, DesktopStopResponse as A, WaitForPortOptions as At, ExecuteResponse as B, CreateContextOptions as Bt, ClickOptions as C, ProcessStartResult as Ct, DesktopStartOptions as D, SessionOptions as Dt, DesktopClient as E, SandboxOptions as Et, ScreenshotRegion as F, ExecuteRequest as Ft, HttpClientOptions as G, BaseApiResponse as H, ExecutionResult as Ht, ScreenshotResponse as I, ExposePortRequest as It, SessionRequest as J, RequestConfig as K, ScrollDirection as L, StartProcessRequest as Lt, ScreenSizeResponse as M, isExecResult as Mt, ScreenshotBytesResponse as N, isProcess as Nt, DesktopStartResponse as O, StreamOptions as Ot, ScreenshotOptions as P, isProcessStatus as Pt, BucketProvider as Q, TypeOptions as R, PtyOptions as Rt, WriteFileRequest as S, ProcessOptions as St, Desktop as T, RestoreBackupResult as Tt, ContainerStub as U, RunCodeOptions as Ut, BackupClient as V, Execution as Vt, ErrorResponse as W, BaseExecOptions as X, BackupOptions as Y, BucketCredentials as Z, GitClient as _, ProcessCleanupResult as _t, CreateSessionRequest as a, FileMetadata as at, MkdirRequest as b, ProcessListResult as bt, DeleteSessionResponse as c, GitCheckoutResult as ct, ProcessClient as d, LogEvent as dt, ExecEvent as et, PortClient as f, MountBucketOptions as ft, GitCheckoutRequest as g, Process as gt, InterpreterClient as h, PortListResult as ht, CommandsResponse as i, FileChunk as it, KeyInput as j, WatchOptions as jt, DesktopStatusResponse as k, WaitForLogResult as kt, PingResponse as l, ISandbox as lt, ExecutionCallbacks as m, PortExposeResult as mt, getSandbox as n, ExecResult as nt, CreateSessionResponse as o, FileStreamEvent as ot, UnexposePortRequest as p, PortCloseResult as pt, ResponseHandler as q, SandboxClient as r, ExecutionSession as rt, DeleteSessionRequest as s, FileWatchSSEEvent as st, Sandbox as t, ExecOptions as tt, UtilityClient as u, ListFilesOptions as ut, FileClient as v, ProcessInfoResult as vt, CursorPositionResponse as w, ProcessStatus as wt, ReadFileRequest as x, ProcessLogsResult as xt, FileOperationRequest as y, ProcessKillResult as yt, CommandClient as z, CodeContext as zt };
2652
+ //# sourceMappingURL=sandbox-BYNjxjyr.d.ts.map