agents 0.7.6 → 0.7.7

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 { r as Agent } from "../index-WBy5hmm3.js";
1
+ import { r as Agent } from "../index-DBW341gU.js";
2
2
  //#region src/experimental/forever.d.ts
3
3
  type FiberState = {
4
4
  id: string;
@@ -1,4 +1,4 @@
1
- import { Command, CommandContext, CustomCommand, ExecResult, NetworkConfig, defineCommand } from "just-bash";
1
+ import { Command, CommandContext, CustomCommand, ExecResult, NetworkConfig, defineCommand } from "@cloudflare/shell";
2
2
 
3
3
  //#region src/experimental/workspace.d.ts
4
4
  /**
@@ -45,7 +45,7 @@ interface WorkspaceOptions {
45
45
  r2Prefix?: string;
46
46
  /** Byte threshold for spilling files to R2 (default: 1_500_000 = 1.5 MB). */
47
47
  inlineThreshold?: number;
48
- /** Bash execution limits (requires just-bash). */
48
+ /** Bash execution limits (requires @cloudflare/shell). */
49
49
  bashLimits?: {
50
50
  maxCommandCount?: number;
51
51
  maxLoopIterations?: number;
@@ -1,5 +1,5 @@
1
1
  import { channel } from "node:diagnostics_channel";
2
- import { Bash, defineCommand } from "just-bash";
2
+ import { Shell, defineCommand } from "@cloudflare/shell";
3
3
  //#region src/experimental/workspace.ts
4
4
  let _Symbol$dispose;
5
5
  const DEFAULT_INLINE_THRESHOLD = 15e5;
@@ -739,7 +739,7 @@ var Workspace = class {
739
739
  async bash(command, options) {
740
740
  this.ensureInit();
741
741
  const { commands, env, network } = this._resolveBashConfig(options);
742
- const bashInstance = new Bash({
742
+ const bashInstance = new Shell({
743
743
  fs: new WorkspaceFileSystem(this),
744
744
  cwd: options?.cwd ?? "/",
745
745
  executionLimits: this.bashLimits,
@@ -876,7 +876,7 @@ var BashSession = class {
876
876
  }
877
877
  async exec(command) {
878
878
  if (this._closed) throw new Error("BashSession is closed");
879
- const bash = new Bash({
879
+ const bash = new Shell({
880
880
  fs: this._fs,
881
881
  cwd: this._currentCwd,
882
882
  env: Object.keys(this._currentEnv).length > 0 ? this._currentEnv : void 0,
@@ -1 +1 @@
1
- {"version":3,"file":"workspace.js","names":[],"sources":["../../src/experimental/workspace.ts"],"sourcesContent":["import { channel } from \"node:diagnostics_channel\";\nimport { Bash, defineCommand } from \"just-bash\";\nimport type {\n Command,\n CommandContext,\n ExecResult,\n CustomCommand\n} from \"just-bash\";\nimport type { NetworkConfig } from \"just-bash\";\n\nexport { defineCommand };\nexport type { Command, CommandContext, ExecResult, NetworkConfig };\n\n/**\n * Workspace — durable file storage for any Agent.\n *\n * Hybrid storage:\n * - Files < threshold: stored inline in SQLite (fast, no external calls)\n * - Files ≥ threshold: metadata in SQLite, content in R2 (avoids row limit)\n *\n * Usage:\n * ```ts\n * import { Agent } from \"agents\";\n * import { Workspace } from \"agents/experimental/workspace\";\n *\n * class MyAgent extends Agent<Env> {\n * workspace = new Workspace(this, {\n * r2: this.env.WORKSPACE_FILES,\n * // r2Prefix defaults to this.name (the Durable Object ID)\n * });\n *\n * async onMessage(conn, msg) {\n * await this.workspace.writeFile(\"/hello.txt\", \"world\");\n * const content = await this.workspace.readFile(\"/hello.txt\");\n * }\n * }\n * ```\n *\n * R2 is optional — if the configured binding isn't present, all files are\n * stored inline regardless of size (with a warning for large files).\n *\n * @module agents/workspace\n */\n\n// ── Host interface ───────────────────────────────────────────────────\n//\n// Only requires `sql` which is public on Agent (via partyserver's Server).\n// We store the host reference so that `host.sql` calls preserve the\n// correct `this` binding (sql is a method, not a standalone function).\n\nexport interface WorkspaceHost {\n sql: <T = Record<string, string | number | boolean | null>>(\n strings: TemplateStringsArray,\n ...values: (string | number | boolean | null)[]\n ) => T[];\n /** Durable Object ID / name — used as the default R2 key prefix when r2Prefix is not set. Read lazily (not at construction time). */\n name?: string;\n}\n\n// ── Options ──────────────────────────────────────────────────────────\n\nexport interface WorkspaceOptions {\n /** Namespace to isolate this workspace's tables (default: \"default\"). */\n namespace?: string;\n /** R2 bucket for large-file storage (optional). */\n r2?: R2Bucket;\n /** Prefix for R2 object keys. Defaults to `host.name` (the Durable Object ID) when omitted. */\n r2Prefix?: string;\n /** Byte threshold for spilling files to R2 (default: 1_500_000 = 1.5 MB). */\n inlineThreshold?: number;\n /** Bash execution limits (requires just-bash). */\n bashLimits?: {\n maxCommandCount?: number;\n maxLoopIterations?: number;\n maxCallDepth?: number;\n };\n /** Custom commands available in every bash() call. */\n commands?: CustomCommand[];\n /** Environment variables available in every bash() call. */\n env?: Record<string, string>;\n /** Network configuration for curl (URL allow-list, methods, timeouts). */\n network?: NetworkConfig;\n /** Called when files/directories change. Wire to agent.broadcast() for real-time sync. */\n onChange?: (event: WorkspaceChangeEvent) => void;\n}\n\n// ── Public types ─────────────────────────────────────────────────────\n\nexport type EntryType = \"file\" | \"directory\" | \"symlink\";\n\nexport type FileInfo = {\n path: string;\n name: string;\n type: EntryType;\n mimeType: string;\n size: number;\n createdAt: number;\n updatedAt: number;\n target?: string;\n};\n\nexport type FileStat = FileInfo;\n\nexport type BashResult = {\n stdout: string;\n stderr: string;\n exitCode: number;\n};\n\nexport interface BashOptions {\n cwd?: string;\n commands?: CustomCommand[];\n env?: Record<string, string>;\n network?: NetworkConfig;\n}\n\n/** @deprecated Use {@link BashOptions} instead. */\nexport type BashSessionOptions = BashOptions;\n\nexport type WorkspaceChangeType = \"create\" | \"update\" | \"delete\";\n\nexport type WorkspaceChangeEvent = {\n type: WorkspaceChangeType;\n path: string;\n entryType: EntryType;\n};\n\n// ── Constants ────────────────────────────────────────────────────────\n\nconst DEFAULT_INLINE_THRESHOLD = 1_500_000; // 1.5 MB\nconst TEXT_ENCODER = new TextEncoder();\nconst TEXT_DECODER = new TextDecoder();\n\nconst MAX_SYMLINK_DEPTH = 40;\n\nconst DEFAULT_BASH_LIMITS = {\n maxCommandCount: 5000,\n maxLoopIterations: 2000,\n maxCallDepth: 50\n};\n\nconst VALID_NAMESPACE = /^[a-zA-Z][a-zA-Z0-9_]*$/;\n\nconst LIKE_ESCAPE = \"\\\\\";\n\nconst MAX_STREAM_SIZE = 100 * 1024 * 1024; // 100 MB\nconst MAX_DIFF_LINES = 10_000;\nconst MAX_PATH_LENGTH = 4096;\nconst MAX_SYMLINK_TARGET_LENGTH = 4096;\nconst MAX_MKDIR_DEPTH = 100;\n\nconst SESS_STATE_BEGIN = \"__BASHSESSION_STATE_BEGIN__\";\nconst SESS_STATE_END = \"__BASHSESSION_STATE_END__\";\nconst SESS_CWD_PREFIX = \"__SESS_CWD__=\";\n\n// Tracks which namespaces have been registered per host (agent) instance.\nconst workspaceRegistry = new WeakMap<WorkspaceHost, Set<string>>();\n\nconst wsChannel = channel(\"agents:workspace\");\n\n// ── Workspace class ──────────────────────────────────────────────────\n\nexport class Workspace {\n private readonly host: WorkspaceHost;\n private readonly namespace: string;\n private readonly tableName: string;\n private readonly indexName: string;\n private readonly r2: R2Bucket | null;\n private readonly r2Prefix: string | undefined;\n private readonly threshold: number;\n private readonly bashLimits: {\n maxCommandCount: number;\n maxLoopIterations: number;\n maxCallDepth: number;\n };\n private readonly commands: CustomCommand[];\n private readonly env: Record<string, string>;\n private readonly network: NetworkConfig | undefined;\n private readonly onChange:\n | ((event: WorkspaceChangeEvent) => void)\n | undefined;\n private initialized = false;\n private readonly sqlCache = new Map<\n TemplateStringsArray,\n TemplateStringsArray\n >();\n\n /**\n * @param host - Any object with a `sql` tagged-template method (typically your Agent: `this`).\n * @param options - Optional configuration (namespace, R2 bucket, thresholds, etc.).\n *\n * ```ts\n * class MyAgent extends Agent<Env> {\n * workspace = new Workspace(this, {\n * r2: this.env.WORKSPACE_FILES,\n * // r2Prefix defaults to this.name (the Durable Object ID)\n * });\n * }\n * ```\n */\n constructor(host: WorkspaceHost, options?: WorkspaceOptions) {\n const ns = options?.namespace ?? \"default\";\n if (!VALID_NAMESPACE.test(ns)) {\n throw new Error(\n `Invalid workspace namespace \"${ns}\": must start with a letter and contain only alphanumeric characters or underscores`\n );\n }\n\n // Detect duplicate registrations on the same agent\n const registered = workspaceRegistry.get(host) ?? new Set<string>();\n if (registered.has(ns)) {\n throw new Error(\n `Workspace namespace \"${ns}\" is already registered on this agent`\n );\n }\n registered.add(ns);\n workspaceRegistry.set(host, registered);\n\n this.host = host;\n this.namespace = ns;\n this.tableName = `cf_workspace_${ns}`;\n this.indexName = `cf_workspace_${ns}_parent`;\n this.r2 = options?.r2 ?? null;\n this.r2Prefix = options?.r2Prefix;\n this.threshold = options?.inlineThreshold ?? DEFAULT_INLINE_THRESHOLD;\n this.bashLimits = {\n ...DEFAULT_BASH_LIMITS,\n ...options?.bashLimits\n };\n this.commands = options?.commands ?? [];\n this.env = options?.env ?? {};\n this.network = options?.network;\n this.onChange = options?.onChange;\n }\n\n private emit(\n type: WorkspaceChangeType,\n path: string,\n entryType: EntryType\n ): void {\n if (this.onChange) this.onChange({ type, path, entryType });\n }\n\n private _observe(type: string, payload: Record<string, unknown>): void {\n wsChannel.publish({\n type,\n name: this.host.name,\n payload: { ...payload, namespace: this.namespace },\n timestamp: Date.now()\n });\n }\n\n // ── SQL helper ─────────────────────────────────────────────────\n //\n // Replaces __TABLE__ / __INDEX__ in the static template parts\n // with the namespace-scoped names. The namespace is validated\n // at construction time (alphanumeric only), so this is safe.\n\n private sql<T = Record<string, string | number | boolean | null>>(\n strings: TemplateStringsArray,\n ...values: (string | number | boolean | null)[]\n ): T[] {\n let tsa = this.sqlCache.get(strings);\n if (!tsa) {\n const replaced = strings.map((s) =>\n s\n .replace(/__TABLE__/g, this.tableName)\n .replace(/__INDEX__/g, this.indexName)\n );\n tsa = Object.assign(replaced, {\n raw: replaced\n }) as unknown as TemplateStringsArray;\n this.sqlCache.set(strings, tsa);\n }\n return this.host.sql<T>(tsa, ...values);\n }\n\n // ── Lazy table init ─────────────────────────────────────────────\n\n private ensureInit(): void {\n if (this.initialized) return;\n this.initialized = true;\n\n this.sql`\n CREATE TABLE IF NOT EXISTS __TABLE__ (\n path TEXT PRIMARY KEY,\n parent_path TEXT NOT NULL,\n name TEXT NOT NULL,\n type TEXT NOT NULL CHECK(type IN ('file','directory','symlink')),\n mime_type TEXT NOT NULL DEFAULT 'text/plain',\n size INTEGER NOT NULL DEFAULT 0,\n storage_backend TEXT NOT NULL DEFAULT 'inline' CHECK(storage_backend IN ('inline','r2')),\n r2_key TEXT,\n target TEXT,\n content_encoding TEXT NOT NULL DEFAULT 'utf8',\n content TEXT,\n created_at INTEGER NOT NULL DEFAULT (unixepoch()),\n modified_at INTEGER NOT NULL DEFAULT (unixepoch())\n )\n `;\n\n this.sql`\n CREATE INDEX IF NOT EXISTS __INDEX__\n ON __TABLE__(parent_path)\n `;\n\n // Root directory always exists\n const hasRoot =\n this.sql<{ cnt: number }>`\n SELECT COUNT(*) AS cnt FROM __TABLE__ WHERE path = '/'\n `[0]?.cnt ?? 0;\n\n if (hasRoot === 0) {\n const now = Math.floor(Date.now() / 1000);\n this.sql`\n INSERT INTO __TABLE__\n (path, parent_path, name, type, size, created_at, modified_at)\n VALUES ('/', '', '', 'directory', 0, ${now}, ${now})\n `;\n }\n }\n\n // ── R2 helpers ─────────────────────────────────────────────────\n\n private getR2(): R2Bucket | null {\n return this.r2;\n }\n\n private resolveR2Prefix(): string {\n if (this.r2Prefix !== undefined) return this.r2Prefix;\n const name = this.host.name;\n if (!name) {\n throw new Error(\n \"[Workspace] R2 is configured but no r2Prefix was provided and host.name is not available. \" +\n \"Either pass r2Prefix in WorkspaceOptions or ensure the host exposes a name property.\"\n );\n }\n return name;\n }\n\n private r2Key(filePath: string): string {\n return `${this.resolveR2Prefix()}/${this.namespace}${filePath}`;\n }\n\n // ── Symlink resolution ────────────────────────────────────────\n\n private resolveSymlink(path: string, depth = 0): string {\n if (depth > MAX_SYMLINK_DEPTH) {\n throw new Error(`ELOOP: too many levels of symbolic links: ${path}`);\n }\n const rows = this.sql<{ type: string; target: string | null }>`\n SELECT type, target FROM __TABLE__ WHERE path = ${path}\n `;\n const r = rows[0];\n if (!r || r.type !== \"symlink\" || !r.target) return path;\n const resolved = r.target.startsWith(\"/\")\n ? normalizePath(r.target)\n : normalizePath(getParent(path) + \"/\" + r.target);\n return this.resolveSymlink(resolved, depth + 1);\n }\n\n // ── Symlink API ───────────────────────────────────────────────\n\n symlink(target: string, linkPath: string): void {\n this.ensureInit();\n if (!target || target.trim().length === 0) {\n throw new Error(\"EINVAL: symlink target must not be empty\");\n }\n if (target.length > MAX_SYMLINK_TARGET_LENGTH) {\n throw new Error(\n `ENAMETOOLONG: symlink target exceeds ${MAX_SYMLINK_TARGET_LENGTH} characters`\n );\n }\n const normalized = normalizePath(linkPath);\n if (normalized === \"/\")\n throw new Error(\"EPERM: cannot create symlink at root\");\n\n const parentPath = getParent(normalized);\n const name = getBasename(normalized);\n const now = Math.floor(Date.now() / 1000);\n\n this.ensureParentDir(parentPath);\n\n const existing = this.sql<{ type: string }>`\n SELECT type FROM __TABLE__ WHERE path = ${normalized}\n `[0];\n if (existing) {\n throw new Error(`EEXIST: path already exists: ${linkPath}`);\n }\n\n this.sql`\n INSERT INTO __TABLE__\n (path, parent_path, name, type, target, size, created_at, modified_at)\n VALUES\n (${normalized}, ${parentPath}, ${name}, 'symlink', ${target}, 0, ${now}, ${now})\n `;\n this.emit(\"create\", normalized, \"symlink\");\n }\n\n readlink(path: string): string {\n this.ensureInit();\n const normalized = normalizePath(path);\n const rows = this.sql<{ type: string; target: string | null }>`\n SELECT type, target FROM __TABLE__ WHERE path = ${normalized}\n `;\n const r = rows[0];\n if (!r) throw new Error(`ENOENT: no such file or directory: ${path}`);\n if (r.type !== \"symlink\" || !r.target)\n throw new Error(`EINVAL: not a symlink: ${path}`);\n return r.target;\n }\n\n lstat(path: string): FileStat | null {\n this.ensureInit();\n const normalized = normalizePath(path);\n const rows = this.sql<{\n path: string;\n name: string;\n type: string;\n mime_type: string;\n size: number;\n created_at: number;\n modified_at: number;\n target: string | null;\n }>`\n SELECT path, name, type, mime_type, size, created_at, modified_at, target\n FROM __TABLE__ WHERE path = ${normalized}\n `;\n const r = rows[0];\n if (!r) return null;\n return toFileInfo(r);\n }\n\n // ── Metadata ───────────────────────────────────────────────────\n\n stat(path: string): FileStat | null {\n this.ensureInit();\n const normalized = normalizePath(path);\n const resolved = this.resolveSymlink(normalized);\n const rows = this.sql<{\n path: string;\n name: string;\n type: string;\n mime_type: string;\n size: number;\n created_at: number;\n modified_at: number;\n target: string | null;\n }>`\n SELECT path, name, type, mime_type, size, created_at, modified_at, target\n FROM __TABLE__ WHERE path = ${resolved}\n `;\n const r = rows[0];\n if (!r) return null;\n return toFileInfo(r);\n }\n\n // ── File I/O ───────────────────────────────────────────────────\n\n async readFile(path: string): Promise<string | null> {\n this.ensureInit();\n const normalized = normalizePath(path);\n const resolved = this.resolveSymlink(normalized);\n const rows = this.sql<{\n type: string;\n storage_backend: string;\n r2_key: string | null;\n content: string | null;\n content_encoding: string;\n }>`\n SELECT type, storage_backend, r2_key, content, content_encoding\n FROM __TABLE__ WHERE path = ${resolved}\n `;\n const r = rows[0];\n if (!r) return null;\n if (r.type !== \"file\") throw new Error(`EISDIR: ${path} is a directory`);\n this._observe(\"workspace:read\", {\n path: resolved,\n storage: r.storage_backend as \"inline\" | \"r2\"\n });\n\n if (r.storage_backend === \"r2\" && r.r2_key) {\n const r2 = this.getR2();\n if (!r2) {\n throw new Error(\n `File ${path} is stored in R2 but no R2 bucket was provided`\n );\n }\n const obj = await r2.get(r.r2_key);\n if (!obj) return \"\";\n return await obj.text();\n }\n\n if (r.content_encoding === \"base64\" && r.content) {\n const bytes = base64ToBytes(r.content);\n return TEXT_DECODER.decode(bytes);\n }\n return r.content ?? \"\";\n }\n\n async readFileBytes(path: string): Promise<Uint8Array | null> {\n this.ensureInit();\n const normalized = normalizePath(path);\n const resolved = this.resolveSymlink(normalized);\n const rows = this.sql<{\n type: string;\n storage_backend: string;\n r2_key: string | null;\n content: string | null;\n content_encoding: string;\n }>`\n SELECT type, storage_backend, r2_key, content, content_encoding\n FROM __TABLE__ WHERE path = ${resolved}\n `;\n const r = rows[0];\n if (!r) return null;\n if (r.type !== \"file\") throw new Error(`EISDIR: ${path} is a directory`);\n this._observe(\"workspace:read\", {\n path: resolved,\n storage: r.storage_backend as \"inline\" | \"r2\"\n });\n\n if (r.storage_backend === \"r2\" && r.r2_key) {\n const r2 = this.getR2();\n if (!r2) {\n throw new Error(\n `File ${path} is stored in R2 but no R2 bucket was provided`\n );\n }\n const obj = await r2.get(r.r2_key);\n if (!obj) return new Uint8Array(0);\n return new Uint8Array(await obj.arrayBuffer());\n }\n\n if (r.content_encoding === \"base64\" && r.content) {\n return base64ToBytes(r.content);\n }\n return TEXT_ENCODER.encode(r.content ?? \"\");\n }\n\n async writeFileBytes(\n path: string,\n data: Uint8Array | ArrayBuffer,\n mimeType = \"application/octet-stream\"\n ): Promise<void> {\n this.ensureInit();\n const normalized = this.resolveSymlink(normalizePath(path));\n if (normalized === \"/\")\n throw new Error(\"EISDIR: cannot write to root directory\");\n\n const bytes = data instanceof ArrayBuffer ? new Uint8Array(data) : data;\n const size = bytes.byteLength;\n const parentPath = getParent(normalized);\n const name = getBasename(normalized);\n const now = Math.floor(Date.now() / 1000);\n\n this.ensureParentDir(parentPath);\n\n const existing = this.sql<{\n storage_backend: string;\n r2_key: string | null;\n }>`\n SELECT storage_backend, r2_key FROM __TABLE__ WHERE path = ${normalized}\n `[0];\n\n const r2 = this.getR2();\n\n if (size >= this.threshold && r2) {\n const key = this.r2Key(normalized);\n if (existing?.storage_backend === \"r2\" && existing.r2_key !== key) {\n await r2.delete(existing.r2_key!);\n }\n await r2.put(key, bytes, {\n httpMetadata: { contentType: mimeType }\n });\n try {\n this.sql`\n INSERT INTO __TABLE__\n (path, parent_path, name, type, mime_type, size,\n storage_backend, r2_key, content_encoding, content, created_at, modified_at)\n VALUES\n (${normalized}, ${parentPath}, ${name}, 'file', ${mimeType}, ${size},\n 'r2', ${key}, 'base64', NULL, ${now}, ${now})\n ON CONFLICT(path) DO UPDATE SET\n mime_type = excluded.mime_type,\n size = excluded.size,\n storage_backend = 'r2',\n r2_key = excluded.r2_key,\n content_encoding = 'base64',\n content = NULL,\n modified_at = excluded.modified_at\n `;\n } catch (sqlErr) {\n try {\n await r2.delete(key);\n } catch {\n console.error(\n `[Workspace] Failed to clean up orphaned R2 object ${key} after SQL error`\n );\n }\n throw sqlErr;\n }\n this.emit(existing ? \"update\" : \"create\", normalized, \"file\");\n this._observe(\"workspace:write\", {\n path: normalized,\n size,\n storage: \"r2\" as const,\n update: !!existing\n });\n } else {\n if (size >= this.threshold && !r2) {\n console.warn(\n `[Workspace] File ${path} is ${size} bytes but no R2 bucket was provided. Storing inline.`\n );\n }\n if (existing?.storage_backend === \"r2\" && existing.r2_key && r2) {\n await r2.delete(existing.r2_key);\n }\n const b64 = bytesToBase64(bytes);\n this.sql`\n INSERT INTO __TABLE__\n (path, parent_path, name, type, mime_type, size,\n storage_backend, r2_key, content_encoding, content, created_at, modified_at)\n VALUES\n (${normalized}, ${parentPath}, ${name}, 'file', ${mimeType}, ${size},\n 'inline', NULL, 'base64', ${b64}, ${now}, ${now})\n ON CONFLICT(path) DO UPDATE SET\n mime_type = excluded.mime_type,\n size = excluded.size,\n storage_backend = 'inline',\n r2_key = NULL,\n content_encoding = 'base64',\n content = excluded.content,\n modified_at = excluded.modified_at\n `;\n this.emit(existing ? \"update\" : \"create\", normalized, \"file\");\n this._observe(\"workspace:write\", {\n path: normalized,\n size,\n storage: \"inline\" as const,\n update: !!existing\n });\n }\n }\n\n async writeFile(\n path: string,\n content: string,\n mimeType = \"text/plain\"\n ): Promise<void> {\n this.ensureInit();\n const normalized = this.resolveSymlink(normalizePath(path));\n if (normalized === \"/\")\n throw new Error(\"EISDIR: cannot write to root directory\");\n\n const parentPath = getParent(normalized);\n const name = getBasename(normalized);\n const bytes = TEXT_ENCODER.encode(content);\n const size = bytes.byteLength;\n const now = Math.floor(Date.now() / 1000);\n\n this.ensureParentDir(parentPath);\n\n // Check if there's an existing R2 file that may need cleanup\n const existing = this.sql<{\n storage_backend: string;\n r2_key: string | null;\n }>`\n SELECT storage_backend, r2_key FROM __TABLE__ WHERE path = ${normalized}\n `[0];\n\n const r2 = this.getR2();\n\n if (size >= this.threshold && r2) {\n const key = this.r2Key(normalized);\n\n if (existing?.storage_backend === \"r2\" && existing.r2_key !== key) {\n await r2.delete(existing.r2_key!);\n }\n\n // Write to R2 first. If this fails, SQL is untouched.\n await r2.put(key, bytes, {\n httpMetadata: { contentType: mimeType }\n });\n\n // Update SQL. If this fails, clean up R2.\n try {\n this.sql`\n INSERT INTO __TABLE__\n (path, parent_path, name, type, mime_type, size,\n storage_backend, r2_key, content_encoding, content, created_at, modified_at)\n VALUES\n (${normalized}, ${parentPath}, ${name}, 'file', ${mimeType}, ${size},\n 'r2', ${key}, 'utf8', NULL, ${now}, ${now})\n ON CONFLICT(path) DO UPDATE SET\n mime_type = excluded.mime_type,\n size = excluded.size,\n storage_backend = 'r2',\n r2_key = excluded.r2_key,\n content_encoding = 'utf8',\n content = NULL,\n modified_at = excluded.modified_at\n `;\n } catch (sqlErr) {\n try {\n await r2.delete(key);\n } catch {\n console.error(\n `[Workspace] Failed to clean up orphaned R2 object ${key} after SQL error`\n );\n }\n throw sqlErr;\n }\n this.emit(existing ? \"update\" : \"create\", normalized, \"file\");\n this._observe(\"workspace:write\", {\n path: normalized,\n size,\n storage: \"r2\" as const,\n update: !!existing\n });\n } else {\n if (size >= this.threshold && !r2) {\n console.warn(\n `[Workspace] File ${path} is ${size} bytes but no R2 bucket was provided. Storing inline — this may hit SQLite row limits for very large files.`\n );\n }\n\n // Going inline: delete any existing R2 object first.\n if (existing?.storage_backend === \"r2\" && existing.r2_key && r2) {\n await r2.delete(existing.r2_key);\n }\n\n this.sql`\n INSERT INTO __TABLE__\n (path, parent_path, name, type, mime_type, size,\n storage_backend, r2_key, content_encoding, content, created_at, modified_at)\n VALUES\n (${normalized}, ${parentPath}, ${name}, 'file', ${mimeType}, ${size},\n 'inline', NULL, 'utf8', ${content}, ${now}, ${now})\n ON CONFLICT(path) DO UPDATE SET\n mime_type = excluded.mime_type,\n size = excluded.size,\n storage_backend = 'inline',\n r2_key = NULL,\n content_encoding = 'utf8',\n content = excluded.content,\n modified_at = excluded.modified_at\n `;\n this.emit(existing ? \"update\" : \"create\", normalized, \"file\");\n this._observe(\"workspace:write\", {\n path: normalized,\n size,\n storage: \"inline\" as const,\n update: !!existing\n });\n }\n }\n\n async readFileStream(\n path: string\n ): Promise<ReadableStream<Uint8Array> | null> {\n this.ensureInit();\n const normalized = normalizePath(path);\n const resolved = this.resolveSymlink(normalized);\n const rows = this.sql<{\n type: string;\n storage_backend: string;\n r2_key: string | null;\n content: string | null;\n content_encoding: string;\n }>`\n SELECT type, storage_backend, r2_key, content, content_encoding\n FROM __TABLE__ WHERE path = ${resolved}\n `;\n const r = rows[0];\n if (!r) return null;\n if (r.type !== \"file\") throw new Error(`EISDIR: ${path} is a directory`);\n this._observe(\"workspace:read\", {\n path: resolved,\n storage: r.storage_backend as \"inline\" | \"r2\"\n });\n\n if (r.storage_backend === \"r2\" && r.r2_key) {\n const r2 = this.getR2();\n if (!r2) {\n throw new Error(\n `File ${path} is stored in R2 but no R2 bucket was provided`\n );\n }\n const obj = await r2.get(r.r2_key);\n if (!obj) {\n return new ReadableStream({\n start(c) {\n c.close();\n }\n });\n }\n return obj.body;\n }\n\n // Inline: wrap content in a ReadableStream\n const bytes =\n r.content_encoding === \"base64\" && r.content\n ? base64ToBytes(r.content)\n : TEXT_ENCODER.encode(r.content ?? \"\");\n return new ReadableStream({\n start(controller) {\n controller.enqueue(bytes);\n controller.close();\n }\n });\n }\n\n async writeFileStream(\n path: string,\n stream: ReadableStream<Uint8Array>,\n mimeType = \"application/octet-stream\"\n ): Promise<void> {\n // Collect stream into a single buffer (capped at MAX_STREAM_SIZE)\n const reader = stream.getReader();\n const chunks: Uint8Array[] = [];\n let totalSize = 0;\n for (;;) {\n const { done, value } = await reader.read();\n if (done) break;\n totalSize += value.byteLength;\n if (totalSize > MAX_STREAM_SIZE) {\n reader.cancel();\n throw new Error(\n `EFBIG: stream exceeds maximum size of ${MAX_STREAM_SIZE} bytes`\n );\n }\n chunks.push(value);\n }\n\n const buffer = new Uint8Array(totalSize);\n let offset = 0;\n for (const chunk of chunks) {\n buffer.set(chunk, offset);\n offset += chunk.byteLength;\n }\n\n await this.writeFileBytes(path, buffer, mimeType);\n }\n\n async appendFile(\n path: string,\n content: string,\n mimeType = \"text/plain\"\n ): Promise<void> {\n this.ensureInit();\n const normalized = this.resolveSymlink(normalizePath(path));\n\n // Check if file exists and what storage it uses\n const row = this.sql<{\n type: string;\n storage_backend: string;\n content_encoding: string;\n }>`\n SELECT type, storage_backend, content_encoding\n FROM __TABLE__ WHERE path = ${normalized}\n `[0];\n\n if (!row) {\n // File doesn't exist — create it\n await this.writeFile(path, content, mimeType);\n return;\n }\n\n if (row.type !== \"file\") {\n throw new Error(`EISDIR: ${path} is a directory`);\n }\n\n // Fast path: inline utf8 file — SQL concat avoids full read+rewrite\n if (row.storage_backend === \"inline\" && row.content_encoding === \"utf8\") {\n const appendSize = TEXT_ENCODER.encode(content).byteLength;\n const now = Math.floor(Date.now() / 1000);\n this.sql`\n UPDATE __TABLE__ SET\n content = content || ${content},\n size = size + ${appendSize},\n modified_at = ${now}\n WHERE path = ${normalized}\n `;\n this.emit(\"update\", normalized, \"file\");\n return;\n }\n\n // Slow path: R2 or base64 — full read + concat + write\n const existing = await this.readFile(path);\n await this.writeFile(path, (existing ?? \"\") + content, mimeType);\n }\n\n async deleteFile(path: string): Promise<boolean> {\n this.ensureInit();\n const normalized = normalizePath(path);\n const rows = this.sql<{\n type: string;\n storage_backend: string;\n r2_key: string | null;\n }>`\n SELECT type, storage_backend, r2_key FROM __TABLE__ WHERE path = ${normalized}\n `;\n if (!rows[0]) return false;\n if (rows[0].type === \"directory\")\n throw new Error(`EISDIR: ${path} is a directory — use rm() instead`);\n\n if (rows[0].storage_backend === \"r2\" && rows[0].r2_key) {\n const r2 = this.getR2();\n if (r2) await r2.delete(rows[0].r2_key);\n }\n\n this.sql`DELETE FROM __TABLE__ WHERE path = ${normalized}`;\n this.emit(\"delete\", normalized, rows[0].type as EntryType);\n this._observe(\"workspace:delete\", { path: normalized });\n return true;\n }\n\n fileExists(path: string): boolean {\n this.ensureInit();\n const resolved = this.resolveSymlink(normalizePath(path));\n const rows = this.sql<{ type: string }>`\n SELECT type FROM __TABLE__ WHERE path = ${resolved}\n `;\n return rows.length > 0 && rows[0].type === \"file\";\n }\n\n exists(path: string): boolean {\n this.ensureInit();\n const normalized = normalizePath(path);\n const rows = this.sql<{ cnt: number }>`\n SELECT COUNT(*) AS cnt FROM __TABLE__ WHERE path = ${normalized}\n `;\n return (rows[0]?.cnt ?? 0) > 0;\n }\n\n // ── Directory operations ───────────────────────────────────────\n\n readDir(dir = \"/\", opts?: { limit?: number; offset?: number }): FileInfo[] {\n this.ensureInit();\n const normalized = normalizePath(dir);\n const limit = opts?.limit ?? 1000;\n const offset = opts?.offset ?? 0;\n const rows = this.sql<{\n path: string;\n name: string;\n type: string;\n mime_type: string;\n size: number;\n created_at: number;\n modified_at: number;\n }>`\n SELECT path, name, type, mime_type, size, created_at, modified_at\n FROM __TABLE__\n WHERE parent_path = ${normalized}\n ORDER BY type ASC, name ASC\n LIMIT ${limit} OFFSET ${offset}\n `;\n return rows.map(toFileInfo);\n }\n\n glob(pattern: string): FileInfo[] {\n this.ensureInit();\n const normalized = normalizePath(pattern);\n const prefix = getGlobPrefix(normalized);\n const likePattern = escapeLike(prefix) + \"%\";\n const regex = globToRegex(normalized);\n\n const rows = this.sql<{\n path: string;\n name: string;\n type: string;\n mime_type: string;\n size: number;\n created_at: number;\n modified_at: number;\n target: string | null;\n }>`\n SELECT path, name, type, mime_type, size, created_at, modified_at, target\n FROM __TABLE__\n WHERE path LIKE ${likePattern} ESCAPE ${LIKE_ESCAPE}\n ORDER BY path\n `;\n\n return rows.filter((r) => regex.test(r.path)).map(toFileInfo);\n }\n\n mkdir(path: string, opts?: { recursive?: boolean }, _depth = 0): void {\n this.ensureInit();\n if (_depth > MAX_MKDIR_DEPTH) {\n throw new Error(\n `ELOOP: mkdir recursion too deep (max ${MAX_MKDIR_DEPTH} levels)`\n );\n }\n const normalized = normalizePath(path);\n if (normalized === \"/\") return;\n\n const existing = this.sql<{ type: string }>`\n SELECT type FROM __TABLE__ WHERE path = ${normalized}\n `;\n\n if (existing.length > 0) {\n if (existing[0].type === \"directory\" && opts?.recursive) return;\n throw new Error(\n existing[0].type === \"directory\"\n ? `EEXIST: directory already exists: ${path}`\n : `EEXIST: path exists as a file: ${path}`\n );\n }\n\n const parentPath = getParent(normalized);\n const parentRows = this.sql<{ type: string }>`\n SELECT type FROM __TABLE__ WHERE path = ${parentPath}\n `;\n\n if (!parentRows[0]) {\n if (opts?.recursive) {\n this.mkdir(parentPath, { recursive: true }, _depth + 1);\n } else {\n throw new Error(`ENOENT: parent directory not found: ${parentPath}`);\n }\n } else if (parentRows[0].type !== \"directory\") {\n throw new Error(`ENOTDIR: parent is not a directory: ${parentPath}`);\n }\n\n const name = getBasename(normalized);\n const now = Math.floor(Date.now() / 1000);\n this.sql`\n INSERT INTO __TABLE__\n (path, parent_path, name, type, size, created_at, modified_at)\n VALUES (${normalized}, ${parentPath}, ${name}, 'directory', 0, ${now}, ${now})\n `;\n this.emit(\"create\", normalized, \"directory\");\n this._observe(\"workspace:mkdir\", {\n path: normalized,\n recursive: !!opts?.recursive\n });\n }\n\n async rm(\n path: string,\n opts?: { recursive?: boolean; force?: boolean }\n ): Promise<void> {\n this.ensureInit();\n const normalized = normalizePath(path);\n if (normalized === \"/\")\n throw new Error(\"EPERM: cannot remove root directory\");\n\n const rows = this.sql<{ type: string }>`\n SELECT type FROM __TABLE__ WHERE path = ${normalized}\n `;\n\n if (!rows[0]) {\n if (opts?.force) return;\n throw new Error(`ENOENT: no such file or directory: ${path}`);\n }\n\n if (rows[0].type === \"directory\") {\n const children = this.sql<{ cnt: number }>`\n SELECT COUNT(*) AS cnt FROM __TABLE__ WHERE parent_path = ${normalized}\n `;\n if ((children[0]?.cnt ?? 0) > 0) {\n if (!opts?.recursive) {\n throw new Error(`ENOTEMPTY: directory not empty: ${path}`);\n }\n await this.deleteDescendants(normalized);\n }\n } else {\n const fileRow = this.sql<{\n storage_backend: string;\n r2_key: string | null;\n }>`\n SELECT storage_backend, r2_key FROM __TABLE__ WHERE path = ${normalized}\n `[0];\n if (fileRow?.storage_backend === \"r2\" && fileRow.r2_key) {\n const r2 = this.getR2();\n if (r2) await r2.delete(fileRow.r2_key);\n }\n }\n\n this.sql`DELETE FROM __TABLE__ WHERE path = ${normalized}`;\n this.emit(\"delete\", normalized, rows[0].type as EntryType);\n this._observe(\"workspace:rm\", {\n path: normalized,\n recursive: !!opts?.recursive\n });\n }\n\n // ── Copy / Move ───────────────────────────────────────────────\n\n async cp(\n src: string,\n dest: string,\n opts?: { recursive?: boolean }\n ): Promise<void> {\n this.ensureInit();\n const srcNorm = normalizePath(src);\n const destNorm = normalizePath(dest);\n const srcStat = this.lstat(srcNorm);\n if (!srcStat) throw new Error(`ENOENT: no such file or directory: ${src}`);\n\n if (srcStat.type === \"symlink\") {\n const target = this.readlink(srcNorm);\n this.symlink(target, destNorm);\n return;\n }\n\n if (srcStat.type === \"directory\") {\n if (!opts?.recursive) {\n throw new Error(\n `EISDIR: cannot copy directory without recursive: ${src}`\n );\n }\n this.mkdir(destNorm, { recursive: true });\n for (const child of this.readDir(srcNorm)) {\n await this.cp(child.path, `${destNorm}/${child.name}`, opts);\n }\n return;\n }\n\n // File: read bytes and write to dest (preserves binary/text)\n const bytes = await this.readFileBytes(srcNorm);\n if (bytes) {\n await this.writeFileBytes(destNorm, bytes, srcStat.mimeType);\n } else {\n await this.writeFile(destNorm, \"\", srcStat.mimeType);\n }\n this._observe(\"workspace:cp\", {\n src: srcNorm,\n dest: destNorm,\n recursive: !!opts?.recursive\n });\n }\n\n async mv(\n src: string,\n dest: string,\n opts?: { recursive?: boolean }\n ): Promise<void> {\n this.ensureInit();\n const srcNorm = normalizePath(src);\n const destNorm = normalizePath(dest);\n const srcStat = this.lstat(srcNorm);\n if (!srcStat) throw new Error(`ENOENT: no such file or directory: ${src}`);\n\n // Directories: fall back to cp+rm (path rewriting is complex)\n if (srcStat.type === \"directory\") {\n if (!(opts?.recursive ?? true)) {\n throw new Error(\n `EISDIR: cannot move directory without recursive: ${src}`\n );\n }\n await this.cp(src, dest, { recursive: true });\n await this.rm(src, { recursive: true, force: true });\n return;\n }\n\n // Single file or symlink: use SQL UPDATE (much faster than cp+rm)\n const destParent = getParent(destNorm);\n const destName = getBasename(destNorm);\n this.ensureParentDir(destParent);\n\n // Remove existing dest if present\n const existingDest = this.sql<{ type: string }>`\n SELECT type FROM __TABLE__ WHERE path = ${destNorm}\n `[0];\n if (existingDest) {\n if (existingDest.type === \"directory\") {\n throw new Error(`EISDIR: cannot overwrite directory: ${dest}`);\n }\n await this.deleteFile(destNorm);\n }\n\n // For R2-backed files, copy the R2 object to new key first\n if (srcStat.type === \"file\") {\n const row = this.sql<{\n storage_backend: string;\n r2_key: string | null;\n }>`\n SELECT storage_backend, r2_key FROM __TABLE__ WHERE path = ${srcNorm}\n `[0];\n if (row?.storage_backend === \"r2\" && row.r2_key) {\n const r2 = this.getR2();\n if (r2) {\n const newKey = this.r2Key(destNorm);\n const obj = await r2.get(row.r2_key);\n if (obj) {\n await r2.put(newKey, await obj.arrayBuffer(), {\n httpMetadata: obj.httpMetadata\n });\n }\n await r2.delete(row.r2_key);\n const now = Math.floor(Date.now() / 1000);\n this.sql`\n UPDATE __TABLE__ SET\n path = ${destNorm},\n parent_path = ${destParent},\n name = ${destName},\n r2_key = ${newKey},\n modified_at = ${now}\n WHERE path = ${srcNorm}\n `;\n this.emit(\"delete\", srcNorm, \"file\");\n this.emit(\"create\", destNorm, \"file\");\n this._observe(\"workspace:mv\", {\n src: srcNorm,\n dest: destNorm\n });\n return;\n }\n }\n }\n\n // Inline file or symlink: single UPDATE\n const now = Math.floor(Date.now() / 1000);\n this.sql`\n UPDATE __TABLE__ SET\n path = ${destNorm},\n parent_path = ${destParent},\n name = ${destName},\n modified_at = ${now}\n WHERE path = ${srcNorm}\n `;\n this.emit(\"delete\", srcNorm, srcStat.type);\n this.emit(\"create\", destNorm, srcStat.type);\n this._observe(\"workspace:mv\", { src: srcNorm, dest: destNorm });\n }\n\n // ── Diff ───────────────────────────────────────────────────────\n\n async diff(pathA: string, pathB: string): Promise<string> {\n const contentA = await this.readFile(pathA);\n if (contentA === null) throw new Error(`ENOENT: no such file: ${pathA}`);\n const contentB = await this.readFile(pathB);\n if (contentB === null) throw new Error(`ENOENT: no such file: ${pathB}`);\n const linesA = contentA.split(\"\\n\").length;\n const linesB = contentB.split(\"\\n\").length;\n if (linesA > MAX_DIFF_LINES || linesB > MAX_DIFF_LINES) {\n throw new Error(\n `EFBIG: files too large for diff (max ${MAX_DIFF_LINES} lines)`\n );\n }\n return unifiedDiff(\n contentA,\n contentB,\n normalizePath(pathA),\n normalizePath(pathB)\n );\n }\n\n async diffContent(path: string, newContent: string): Promise<string> {\n const existing = await this.readFile(path);\n if (existing === null) throw new Error(`ENOENT: no such file: ${path}`);\n const linesA = existing.split(\"\\n\").length;\n const linesB = newContent.split(\"\\n\").length;\n if (linesA > MAX_DIFF_LINES || linesB > MAX_DIFF_LINES) {\n throw new Error(\n `EFBIG: content too large for diff (max ${MAX_DIFF_LINES} lines)`\n );\n }\n const normalized = normalizePath(path);\n return unifiedDiff(existing, newContent, normalized, normalized);\n }\n\n // ── Bash execution ─────────────────────────────────────────────\n\n private _resolveBashConfig(options?: BashOptions): {\n commands: CustomCommand[] | undefined;\n env: Record<string, string> | undefined;\n network: NetworkConfig | undefined;\n } {\n const commands = options?.commands\n ? [...this.commands, ...options.commands]\n : this.commands.length > 0\n ? this.commands\n : undefined;\n const hasWsEnv = Object.keys(this.env).length > 0;\n const env =\n options?.env && hasWsEnv\n ? { ...this.env, ...options.env }\n : (options?.env ?? (hasWsEnv ? this.env : undefined));\n const network = options?.network ?? this.network;\n return { commands, env, network };\n }\n\n async bash(command: string, options?: BashOptions): Promise<BashResult> {\n this.ensureInit();\n const { commands, env, network } = this._resolveBashConfig(options);\n const fs = new WorkspaceFileSystem(this);\n const bashInstance = new Bash({\n fs,\n cwd: options?.cwd ?? \"/\",\n executionLimits: this.bashLimits,\n customCommands: commands,\n env,\n network\n });\n const t0 = Date.now();\n const result = await bashInstance.exec(command);\n this._observe(\"workspace:bash\", {\n command,\n exitCode: result.exitCode,\n durationMs: Date.now() - t0\n });\n return {\n stdout: result.stdout,\n stderr: result.stderr,\n exitCode: result.exitCode\n };\n }\n\n createBashSession(options?: BashOptions): BashSession {\n this.ensureInit();\n const { commands, env, network } = this._resolveBashConfig(options);\n return new BashSession({\n ws: this,\n fs: new WorkspaceFileSystem(this),\n bashLimits: this.bashLimits,\n commands,\n env: env ? { ...env } : {},\n network,\n cwd: options?.cwd ?? \"/\",\n observe: this._observe.bind(this)\n });\n }\n\n // ── Info ────────────────────────────────────────────────────────\n\n getWorkspaceInfo(): {\n fileCount: number;\n directoryCount: number;\n totalBytes: number;\n r2FileCount: number;\n } {\n this.ensureInit();\n const rows = this.sql<{\n files: number;\n dirs: number;\n total: number;\n r2files: number;\n }>`\n SELECT\n SUM(CASE WHEN type = 'file' THEN 1 ELSE 0 END) AS files,\n SUM(CASE WHEN type = 'directory' THEN 1 ELSE 0 END) AS dirs,\n COALESCE(SUM(CASE WHEN type = 'file' THEN size ELSE 0 END), 0) AS total,\n SUM(CASE WHEN type = 'file' AND storage_backend = 'r2' THEN 1 ELSE 0 END) AS r2files\n FROM __TABLE__\n `;\n return {\n fileCount: rows[0]?.files ?? 0,\n directoryCount: rows[0]?.dirs ?? 0,\n totalBytes: rows[0]?.total ?? 0,\n r2FileCount: rows[0]?.r2files ?? 0\n };\n }\n\n // ── Internal helpers (used by WorkspaceFileSystem) ─────────────\n\n /** @internal */\n _getAllPaths(): string[] {\n this.ensureInit();\n return this.sql<{ path: string }>`\n SELECT path FROM __TABLE__ ORDER BY path\n `.map((r) => r.path);\n }\n\n /** @internal */\n _updateModifiedAt(path: string, mtime: Date): void {\n this.ensureInit();\n const normalized = normalizePath(path);\n const ts = Math.floor(mtime.getTime() / 1000);\n this.sql`\n UPDATE __TABLE__ SET modified_at = ${ts} WHERE path = ${normalized}\n `;\n }\n\n // ── Private helpers ────────────────────────────────────────────\n\n private ensureParentDir(dirPath: string): void {\n if (!dirPath || dirPath === \"/\") return;\n\n // Quick check: immediate parent exists?\n const rows = this.sql<{ type: string }>`\n SELECT type FROM __TABLE__ WHERE path = ${dirPath}\n `;\n if (rows[0]) {\n if (rows[0].type !== \"directory\") {\n throw new Error(`ENOTDIR: ${dirPath} is not a directory`);\n }\n return;\n }\n\n // Walk up to find the deepest existing ancestor\n const missing: string[] = [dirPath];\n let current = getParent(dirPath);\n while (current && current !== \"/\") {\n const r = this.sql<{ type: string }>`\n SELECT type FROM __TABLE__ WHERE path = ${current}\n `;\n if (r[0]) {\n if (r[0].type !== \"directory\") {\n throw new Error(`ENOTDIR: ${current} is not a directory`);\n }\n break;\n }\n missing.push(current);\n current = getParent(current);\n }\n\n // Insert missing ancestors top-down\n const now = Math.floor(Date.now() / 1000);\n for (let i = missing.length - 1; i >= 0; i--) {\n const p = missing[i];\n const parentPath = getParent(p);\n const name = getBasename(p);\n this.sql`\n INSERT INTO __TABLE__\n (path, parent_path, name, type, size, created_at, modified_at)\n VALUES (${p}, ${parentPath}, ${name}, 'directory', 0, ${now}, ${now})\n `;\n this.emit(\"create\", p, \"directory\");\n }\n }\n\n private async deleteDescendants(dirPath: string): Promise<void> {\n const pattern = escapeLike(dirPath) + \"/%\";\n\n const r2Rows = this.sql<{ r2_key: string }>`\n SELECT r2_key FROM __TABLE__\n WHERE path LIKE ${pattern} ESCAPE ${LIKE_ESCAPE}\n AND storage_backend = 'r2'\n AND r2_key IS NOT NULL\n `;\n\n if (r2Rows.length > 0) {\n const r2 = this.getR2();\n if (r2) {\n const keys = r2Rows.map((r) => r.r2_key);\n await r2.delete(keys);\n }\n }\n\n this\n .sql`DELETE FROM __TABLE__ WHERE path LIKE ${pattern} ESCAPE ${LIKE_ESCAPE}`;\n }\n}\n\n// ── BashSession ──────────────────────────────────────────────────────\n//\n// Preserves cwd and all shell variables across multiple exec() calls.\n// Each exec() creates a fresh Bash instance seeded with the tracked state.\n// After execution, cwd and env are captured via stdout sentinels that\n// are stripped before returning the result to the caller.\n// Created via workspace.createBashSession().\n\ninterface BashSessionInit {\n ws: Workspace;\n fs: WorkspaceFileSystem;\n bashLimits: {\n maxCommandCount: number;\n maxLoopIterations: number;\n maxCallDepth: number;\n };\n commands: CustomCommand[] | undefined;\n env: Record<string, string>;\n network: NetworkConfig | undefined;\n cwd: string;\n observe: (type: string, payload: Record<string, unknown>) => void;\n}\n\nexport class BashSession {\n private readonly _ws: Workspace;\n private readonly _fs: WorkspaceFileSystem;\n private readonly _bashLimits: {\n maxCommandCount: number;\n maxLoopIterations: number;\n maxCallDepth: number;\n };\n private readonly _customCommands: CustomCommand[] | undefined;\n private readonly _networkConfig: NetworkConfig | undefined;\n private readonly _observe: (\n type: string,\n payload: Record<string, unknown>\n ) => void;\n private _currentCwd: string;\n private _currentEnv: Record<string, string>;\n private _closed = false;\n\n /** @internal — use workspace.createBashSession() instead */\n constructor(init: BashSessionInit) {\n this._ws = init.ws;\n this._fs = init.fs;\n this._bashLimits = init.bashLimits;\n this._customCommands = init.commands;\n this._networkConfig = init.network;\n this._observe = init.observe;\n this._currentCwd = init.cwd;\n this._currentEnv = init.env;\n }\n\n async exec(command: string): Promise<BashResult> {\n if (this._closed) {\n throw new Error(\"BashSession is closed\");\n }\n\n const bash = new Bash({\n fs: this._fs,\n cwd: this._currentCwd,\n env:\n Object.keys(this._currentEnv).length > 0 ? this._currentEnv : undefined,\n executionLimits: this._bashLimits,\n customCommands: this._customCommands,\n network: this._networkConfig\n });\n\n const wrapped =\n `${command}\\n__sess_rc=$?\\n` +\n `echo \"${SESS_STATE_BEGIN}\"\\n` +\n `echo \"${SESS_CWD_PREFIX}$(pwd)\"\\n` +\n `env\\n` +\n `echo \"${SESS_STATE_END}\"\\n` +\n `exit $__sess_rc`;\n\n const t0 = Date.now();\n const result = await bash.exec(wrapped);\n\n let stdout = result.stdout;\n const beginIdx = stdout.lastIndexOf(SESS_STATE_BEGIN);\n const endIdx = stdout.lastIndexOf(SESS_STATE_END);\n if (beginIdx >= 0 && endIdx > beginIdx) {\n const stateBlock = stdout.slice(\n beginIdx + SESS_STATE_BEGIN.length + 1,\n endIdx\n );\n const lines = stateBlock.split(\"\\n\");\n const newEnv: Record<string, string> = {};\n for (const line of lines) {\n if (line.startsWith(SESS_CWD_PREFIX)) {\n const cwd = line.slice(SESS_CWD_PREFIX.length).trim();\n if (cwd) this._currentCwd = cwd;\n } else if (line.includes(\"=\")) {\n const eqIdx = line.indexOf(\"=\");\n const key = line.slice(0, eqIdx);\n const value = line.slice(eqIdx + 1);\n if (key && key !== \"__sess_rc\") {\n newEnv[key] = value;\n }\n }\n }\n if (Object.keys(newEnv).length > 0) {\n this._currentEnv = newEnv;\n }\n let cutStart = beginIdx;\n if (cutStart > 0 && stdout[cutStart - 1] === \"\\n\") cutStart--;\n stdout = stdout.slice(0, cutStart);\n }\n\n this._observe(\"workspace:bash\", {\n command,\n exitCode: result.exitCode,\n durationMs: Date.now() - t0,\n session: true\n });\n\n return {\n stdout,\n stderr: result.stderr,\n exitCode: result.exitCode\n };\n }\n\n get cwd(): string {\n return this._currentCwd;\n }\n\n get env(): Record<string, string> {\n return { ...this._currentEnv };\n }\n\n get isClosed(): boolean {\n return this._closed;\n }\n\n close(): void {\n this._closed = true;\n }\n\n [Symbol.dispose](): void {\n this.close();\n }\n}\n\n// ── WorkspaceFileSystem (IFileSystem bridge for just-bash) ───────────\n//\n// Bridges the workspace's async file methods into the IFileSystem\n// interface that just-bash expects. All reads/writes go through the\n// workspace so bash commands share the same durable storage.\n//\n// We define the IFileSystem shape locally to avoid a hard dependency\n// on just-bash types at compile time.\n\ninterface FsStat {\n isFile: boolean;\n isDirectory: boolean;\n isSymbolicLink: boolean;\n mode: number;\n size: number;\n mtime: Date;\n}\n\ninterface DirentEntry {\n name: string;\n isFile: boolean;\n isDirectory: boolean;\n isSymbolicLink: boolean;\n}\n\ntype FileContent = string | Uint8Array;\ntype BufferEncoding = \"utf-8\" | \"utf8\" | \"ascii\" | \"base64\" | \"hex\" | \"latin1\";\ntype ReadFileOptions = { encoding?: BufferEncoding | null };\ntype WriteFileOptions = { encoding?: BufferEncoding };\ntype MkdirOptions = { recursive?: boolean };\ntype RmOptions = { recursive?: boolean; force?: boolean };\ntype CpOptions = { recursive?: boolean };\n\nfunction fileContentToString(content: FileContent): string {\n return typeof content === \"string\" ? content : TEXT_DECODER.decode(content);\n}\n\nclass WorkspaceFileSystem {\n constructor(private ws: Workspace) {}\n\n async readFile(\n path: string,\n _options?: ReadFileOptions | BufferEncoding\n ): Promise<string> {\n const content = await this.ws.readFile(path);\n if (content === null)\n throw Object.assign(new Error(`ENOENT: ${path}`), { code: \"ENOENT\" });\n return content;\n }\n\n async readFileBuffer(path: string): Promise<Uint8Array> {\n const bytes = await this.ws.readFileBytes(path);\n if (bytes === null)\n throw Object.assign(new Error(`ENOENT: ${path}`), { code: \"ENOENT\" });\n return bytes;\n }\n\n async writeFile(\n path: string,\n content: FileContent,\n _options?: WriteFileOptions | BufferEncoding\n ): Promise<void> {\n if (typeof content === \"string\") {\n await this.ws.writeFile(path, content);\n } else {\n await this.ws.writeFileBytes(path, content);\n }\n }\n\n async appendFile(\n path: string,\n content: FileContent,\n _options?: WriteFileOptions | BufferEncoding\n ): Promise<void> {\n await this.ws.appendFile(path, fileContentToString(content));\n }\n\n async exists(path: string): Promise<boolean> {\n return this.ws.stat(path) !== null;\n }\n\n async stat(path: string): Promise<FsStat> {\n const s = this.ws.stat(path);\n if (!s)\n throw Object.assign(new Error(`ENOENT: ${path}`), { code: \"ENOENT\" });\n return {\n isFile: s.type === \"file\",\n isDirectory: s.type === \"directory\",\n isSymbolicLink: false,\n mode: s.type === \"directory\" ? 0o755 : 0o644,\n size: s.size,\n mtime: new Date(s.updatedAt)\n };\n }\n\n async lstat(path: string): Promise<FsStat> {\n const s = this.ws.lstat(path);\n if (!s)\n throw Object.assign(new Error(`ENOENT: ${path}`), { code: \"ENOENT\" });\n return {\n isFile: s.type === \"file\",\n isDirectory: s.type === \"directory\",\n isSymbolicLink: s.type === \"symlink\",\n mode: s.type === \"directory\" ? 0o755 : 0o644,\n size: s.size,\n mtime: new Date(s.updatedAt)\n };\n }\n\n async mkdir(path: string, options?: MkdirOptions): Promise<void> {\n this.ws.mkdir(path, options);\n }\n\n async readdir(path: string): Promise<string[]> {\n return this.ws.readDir(path).map((e) => e.name);\n }\n\n async readdirWithFileTypes(path: string): Promise<DirentEntry[]> {\n return this.ws.readDir(path).map((e) => ({\n name: e.name,\n isFile: e.type === \"file\",\n isDirectory: e.type === \"directory\",\n isSymbolicLink: e.type === \"symlink\"\n }));\n }\n\n async rm(path: string, options?: RmOptions): Promise<void> {\n await this.ws.rm(path, options);\n }\n\n async cp(src: string, dest: string, options?: CpOptions): Promise<void> {\n await this.ws.cp(src, dest, options);\n }\n\n async mv(src: string, dest: string): Promise<void> {\n await this.ws.mv(src, dest);\n }\n\n resolvePath(base: string, path: string): string {\n const raw = path.startsWith(\"/\") ? path : `${base}/${path}`;\n const parts = raw.split(\"/\").filter(Boolean);\n const resolved: string[] = [];\n for (const part of parts) {\n if (part === \"..\") resolved.pop();\n else if (part !== \".\") resolved.push(part);\n }\n return \"/\" + resolved.join(\"/\");\n }\n\n getAllPaths(): string[] {\n return this.ws._getAllPaths();\n }\n\n async chmod(_path: string, _mode: number): Promise<void> {\n // no-op\n }\n\n async symlink(target: string, linkPath: string): Promise<void> {\n this.ws.symlink(target, linkPath);\n }\n\n async link(_existingPath: string, _newPath: string): Promise<void> {\n throw new Error(\"ENOSYS: hard links not supported in workspace filesystem\");\n }\n\n async readlink(path: string): Promise<string> {\n return this.ws.readlink(path);\n }\n\n async realpath(path: string): Promise<string> {\n const normalized = normalizePath(path);\n const s = this.ws.lstat(normalized);\n if (!s)\n throw Object.assign(new Error(`ENOENT: ${path}`), { code: \"ENOENT\" });\n if (s.type === \"symlink\") {\n const target = this.ws.readlink(normalized);\n const resolved = target.startsWith(\"/\")\n ? normalizePath(target)\n : normalizePath(getParent(normalized) + \"/\" + target);\n return this.realpath(resolved);\n }\n return normalized;\n }\n\n async utimes(_path: string, _atime: Date, mtime: Date): Promise<void> {\n this.ws._updateModifiedAt(_path, mtime);\n }\n}\n\n// ── Base64 helpers ───────────────────────────────────────────────────\n\nfunction bytesToBase64(bytes: Uint8Array): string {\n const CHUNK = 8192;\n let binary = \"\";\n for (let i = 0; i < bytes.byteLength; i += CHUNK) {\n binary += String.fromCharCode(\n ...bytes.subarray(i, Math.min(i + CHUNK, bytes.byteLength))\n );\n }\n return btoa(binary);\n}\n\nfunction base64ToBytes(b64: string): Uint8Array {\n const binary = atob(b64);\n const bytes = new Uint8Array(binary.length);\n for (let i = 0; i < binary.length; i++) {\n bytes[i] = binary.charCodeAt(i);\n }\n return bytes;\n}\n\n// ── Path helpers ─────────────────────────────────────────────────────\n\nfunction escapeLike(s: string): string {\n return s.replace(/[\\\\%_]/g, (ch) => \"\\\\\" + ch);\n}\n\nfunction normalizePath(path: string): string {\n if (!path.startsWith(\"/\")) path = \"/\" + path;\n const parts = path.split(\"/\");\n const resolved: string[] = [];\n for (const part of parts) {\n if (part === \"\" || part === \".\") continue;\n if (part === \"..\") {\n resolved.pop();\n } else {\n resolved.push(part);\n }\n }\n const result = \"/\" + resolved.join(\"/\");\n if (result.length > MAX_PATH_LENGTH) {\n throw new Error(`ENAMETOOLONG: path exceeds ${MAX_PATH_LENGTH} characters`);\n }\n return result;\n}\n\nfunction getParent(path: string): string {\n const normalized = normalizePath(path);\n if (normalized === \"/\") return \"\";\n const lastSlash = normalized.lastIndexOf(\"/\");\n return lastSlash === 0 ? \"/\" : normalized.slice(0, lastSlash);\n}\n\nfunction getBasename(path: string): string {\n const normalized = normalizePath(path);\n if (normalized === \"/\") return \"\";\n return normalized.slice(normalized.lastIndexOf(\"/\") + 1);\n}\n\nfunction toFileInfo(r: {\n path: string;\n name: string;\n type: string;\n mime_type: string;\n size: number;\n created_at: number;\n modified_at: number;\n target?: string | null;\n}): FileInfo {\n const info: FileInfo = {\n path: r.path,\n name: r.name,\n type: r.type as EntryType,\n mimeType: r.mime_type,\n size: r.size,\n createdAt: r.created_at * 1000,\n updatedAt: r.modified_at * 1000\n };\n if (r.target) info.target = r.target;\n return info;\n}\n\n// ── Glob helpers ─────────────────────────────────────────────────────\n\nfunction getGlobPrefix(pattern: string): string {\n const first = pattern.search(/[*?[{]/);\n if (first === -1) return pattern;\n const before = pattern.slice(0, first);\n const lastSlash = before.lastIndexOf(\"/\");\n return lastSlash >= 0 ? before.slice(0, lastSlash + 1) : \"/\";\n}\n\nfunction globToRegex(pattern: string): RegExp {\n let i = 0;\n let re = \"^\";\n while (i < pattern.length) {\n const ch = pattern[i];\n if (ch === \"*\") {\n if (pattern[i + 1] === \"*\") {\n // ** — match everything including /\n i += 2;\n if (pattern[i] === \"/\") {\n // **/ — zero or more directory segments\n re += \"(?:.+/)?\";\n i++;\n } else {\n re += \".*\";\n }\n } else {\n // * — match everything except /\n re += \"[^/]*\";\n i++;\n }\n } else if (ch === \"?\") {\n re += \"[^/]\";\n i++;\n } else if (ch === \"[\") {\n // character class — pass through until ]\n const close = pattern.indexOf(\"]\", i + 1);\n if (close === -1) {\n re += \"\\\\[\";\n i++;\n } else {\n re += pattern.slice(i, close + 1);\n i = close + 1;\n }\n } else if (ch === \"{\") {\n // brace expansion {a,b,c} → (?:a|b|c)\n const close = pattern.indexOf(\"}\", i + 1);\n if (close === -1) {\n re += \"\\\\{\";\n i++;\n } else {\n const inner = pattern\n .slice(i + 1, close)\n .split(\",\")\n .join(\"|\");\n re += `(?:${inner})`;\n i = close + 1;\n }\n } else {\n // escape regex special chars\n re += ch.replace(/[.+^$|\\\\()]/g, \"\\\\$&\");\n i++;\n }\n }\n re += \"$\";\n return new RegExp(re);\n}\n\n// ── Diff helpers ─────────────────────────────────────────────────────\n\nfunction unifiedDiff(\n a: string,\n b: string,\n labelA: string,\n labelB: string,\n contextLines = 3\n): string {\n if (a === b) return \"\";\n\n const linesA = a.split(\"\\n\");\n const linesB = b.split(\"\\n\");\n const edits = myersDiff(linesA, linesB);\n return formatUnified(edits, linesA, linesB, labelA, labelB, contextLines);\n}\n\ntype Edit = {\n type: \"keep\" | \"delete\" | \"insert\";\n lineA: number;\n lineB: number;\n};\n\nfunction myersDiff(a: string[], b: string[]): Edit[] {\n const n = a.length;\n const m = b.length;\n const max = n + m;\n const vSize = 2 * max + 1;\n const v = new Int32Array(vSize);\n v.fill(-1);\n const offset = max;\n v[offset + 1] = 0;\n\n const trace: Int32Array[] = [];\n\n outer: for (let d = 0; d <= max; d++) {\n trace.push(v.slice());\n for (let k = -d; k <= d; k += 2) {\n let x: number;\n if (k === -d || (k !== d && v[offset + k - 1] < v[offset + k + 1])) {\n x = v[offset + k + 1];\n } else {\n x = v[offset + k - 1] + 1;\n }\n let y = x - k;\n while (x < n && y < m && a[x] === b[y]) {\n x++;\n y++;\n }\n v[offset + k] = x;\n if (x >= n && y >= m) break outer;\n }\n }\n\n const edits: Edit[] = [];\n let x = n;\n let y = m;\n\n for (let d = trace.length - 1; d >= 0; d--) {\n const vPrev = trace[d];\n const k = x - y;\n let prevK: number;\n if (\n k === -d ||\n (k !== d && vPrev[offset + k - 1] < vPrev[offset + k + 1])\n ) {\n prevK = k + 1;\n } else {\n prevK = k - 1;\n }\n const prevX = vPrev[offset + prevK];\n const prevY = prevX - prevK;\n\n while (x > prevX && y > prevY) {\n x--;\n y--;\n edits.push({ type: \"keep\", lineA: x, lineB: y });\n }\n if (d > 0) {\n if (x === prevX) {\n edits.push({ type: \"insert\", lineA: x, lineB: y - 1 });\n y--;\n } else {\n edits.push({ type: \"delete\", lineA: x - 1, lineB: y });\n x--;\n }\n }\n }\n\n edits.reverse();\n return edits;\n}\n\nfunction formatUnified(\n edits: Edit[],\n linesA: string[],\n linesB: string[],\n labelA: string,\n labelB: string,\n ctx: number\n): string {\n const out: string[] = [];\n out.push(`--- ${labelA}`);\n out.push(`+++ ${labelB}`);\n\n const changes: number[] = [];\n for (let i = 0; i < edits.length; i++) {\n if (edits[i].type !== \"keep\") changes.push(i);\n }\n if (changes.length === 0) return \"\";\n\n let i = 0;\n while (i < changes.length) {\n let start = Math.max(0, changes[i] - ctx);\n let end = Math.min(edits.length - 1, changes[i] + ctx);\n\n let j = i + 1;\n while (j < changes.length && changes[j] - ctx <= end + 1) {\n end = Math.min(edits.length - 1, changes[j] + ctx);\n j++;\n }\n\n let startA = edits[start].lineA;\n let startB = edits[start].lineB;\n let countA = 0;\n let countB = 0;\n const hunkLines: string[] = [];\n\n for (let idx = start; idx <= end; idx++) {\n const e = edits[idx];\n if (e.type === \"keep\") {\n hunkLines.push(` ${linesA[e.lineA]}`);\n countA++;\n countB++;\n } else if (e.type === \"delete\") {\n hunkLines.push(`-${linesA[e.lineA]}`);\n countA++;\n } else {\n hunkLines.push(`+${linesB[e.lineB]}`);\n countB++;\n }\n }\n\n out.push(`@@ -${startA + 1},${countA} +${startB + 1},${countB} @@`);\n out.push(...hunkLines);\n i = j;\n }\n\n return out.join(\"\\n\");\n}\n"],"mappings":"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"}
1
+ {"version":3,"file":"workspace.js","names":["Bash"],"sources":["../../src/experimental/workspace.ts"],"sourcesContent":["import { channel } from \"node:diagnostics_channel\";\nimport { Shell as Bash, defineCommand } from \"@cloudflare/shell\";\nimport type {\n Command,\n CommandContext,\n ExecResult,\n CustomCommand\n} from \"@cloudflare/shell\";\nimport type { NetworkConfig } from \"@cloudflare/shell\";\n\nexport { defineCommand };\nexport type { Command, CommandContext, ExecResult, NetworkConfig };\n\n/**\n * Workspace — durable file storage for any Agent.\n *\n * Hybrid storage:\n * - Files < threshold: stored inline in SQLite (fast, no external calls)\n * - Files ≥ threshold: metadata in SQLite, content in R2 (avoids row limit)\n *\n * Usage:\n * ```ts\n * import { Agent } from \"agents\";\n * import { Workspace } from \"agents/experimental/workspace\";\n *\n * class MyAgent extends Agent<Env> {\n * workspace = new Workspace(this, {\n * r2: this.env.WORKSPACE_FILES,\n * // r2Prefix defaults to this.name (the Durable Object ID)\n * });\n *\n * async onMessage(conn, msg) {\n * await this.workspace.writeFile(\"/hello.txt\", \"world\");\n * const content = await this.workspace.readFile(\"/hello.txt\");\n * }\n * }\n * ```\n *\n * R2 is optional — if the configured binding isn't present, all files are\n * stored inline regardless of size (with a warning for large files).\n *\n * @module agents/workspace\n */\n\n// ── Host interface ───────────────────────────────────────────────────\n//\n// Only requires `sql` which is public on Agent (via partyserver's Server).\n// We store the host reference so that `host.sql` calls preserve the\n// correct `this` binding (sql is a method, not a standalone function).\n\nexport interface WorkspaceHost {\n sql: <T = Record<string, string | number | boolean | null>>(\n strings: TemplateStringsArray,\n ...values: (string | number | boolean | null)[]\n ) => T[];\n /** Durable Object ID / name — used as the default R2 key prefix when r2Prefix is not set. Read lazily (not at construction time). */\n name?: string;\n}\n\n// ── Options ──────────────────────────────────────────────────────────\n\nexport interface WorkspaceOptions {\n /** Namespace to isolate this workspace's tables (default: \"default\"). */\n namespace?: string;\n /** R2 bucket for large-file storage (optional). */\n r2?: R2Bucket;\n /** Prefix for R2 object keys. Defaults to `host.name` (the Durable Object ID) when omitted. */\n r2Prefix?: string;\n /** Byte threshold for spilling files to R2 (default: 1_500_000 = 1.5 MB). */\n inlineThreshold?: number;\n /** Bash execution limits (requires @cloudflare/shell). */\n bashLimits?: {\n maxCommandCount?: number;\n maxLoopIterations?: number;\n maxCallDepth?: number;\n };\n /** Custom commands available in every bash() call. */\n commands?: CustomCommand[];\n /** Environment variables available in every bash() call. */\n env?: Record<string, string>;\n /** Network configuration for curl (URL allow-list, methods, timeouts). */\n network?: NetworkConfig;\n /** Called when files/directories change. Wire to agent.broadcast() for real-time sync. */\n onChange?: (event: WorkspaceChangeEvent) => void;\n}\n\n// ── Public types ─────────────────────────────────────────────────────\n\nexport type EntryType = \"file\" | \"directory\" | \"symlink\";\n\nexport type FileInfo = {\n path: string;\n name: string;\n type: EntryType;\n mimeType: string;\n size: number;\n createdAt: number;\n updatedAt: number;\n target?: string;\n};\n\nexport type FileStat = FileInfo;\n\nexport type BashResult = {\n stdout: string;\n stderr: string;\n exitCode: number;\n};\n\nexport interface BashOptions {\n cwd?: string;\n commands?: CustomCommand[];\n env?: Record<string, string>;\n network?: NetworkConfig;\n}\n\n/** @deprecated Use {@link BashOptions} instead. */\nexport type BashSessionOptions = BashOptions;\n\nexport type WorkspaceChangeType = \"create\" | \"update\" | \"delete\";\n\nexport type WorkspaceChangeEvent = {\n type: WorkspaceChangeType;\n path: string;\n entryType: EntryType;\n};\n\n// ── Constants ────────────────────────────────────────────────────────\n\nconst DEFAULT_INLINE_THRESHOLD = 1_500_000; // 1.5 MB\nconst TEXT_ENCODER = new TextEncoder();\nconst TEXT_DECODER = new TextDecoder();\n\nconst MAX_SYMLINK_DEPTH = 40;\n\nconst DEFAULT_BASH_LIMITS = {\n maxCommandCount: 5000,\n maxLoopIterations: 2000,\n maxCallDepth: 50\n};\n\nconst VALID_NAMESPACE = /^[a-zA-Z][a-zA-Z0-9_]*$/;\n\nconst LIKE_ESCAPE = \"\\\\\";\n\nconst MAX_STREAM_SIZE = 100 * 1024 * 1024; // 100 MB\nconst MAX_DIFF_LINES = 10_000;\nconst MAX_PATH_LENGTH = 4096;\nconst MAX_SYMLINK_TARGET_LENGTH = 4096;\nconst MAX_MKDIR_DEPTH = 100;\n\nconst SESS_STATE_BEGIN = \"__BASHSESSION_STATE_BEGIN__\";\nconst SESS_STATE_END = \"__BASHSESSION_STATE_END__\";\nconst SESS_CWD_PREFIX = \"__SESS_CWD__=\";\n\n// Tracks which namespaces have been registered per host (agent) instance.\nconst workspaceRegistry = new WeakMap<WorkspaceHost, Set<string>>();\n\nconst wsChannel = channel(\"agents:workspace\");\n\n// ── Workspace class ──────────────────────────────────────────────────\n\nexport class Workspace {\n private readonly host: WorkspaceHost;\n private readonly namespace: string;\n private readonly tableName: string;\n private readonly indexName: string;\n private readonly r2: R2Bucket | null;\n private readonly r2Prefix: string | undefined;\n private readonly threshold: number;\n private readonly bashLimits: {\n maxCommandCount: number;\n maxLoopIterations: number;\n maxCallDepth: number;\n };\n private readonly commands: CustomCommand[];\n private readonly env: Record<string, string>;\n private readonly network: NetworkConfig | undefined;\n private readonly onChange:\n | ((event: WorkspaceChangeEvent) => void)\n | undefined;\n private initialized = false;\n private readonly sqlCache = new Map<\n TemplateStringsArray,\n TemplateStringsArray\n >();\n\n /**\n * @param host - Any object with a `sql` tagged-template method (typically your Agent: `this`).\n * @param options - Optional configuration (namespace, R2 bucket, thresholds, etc.).\n *\n * ```ts\n * class MyAgent extends Agent<Env> {\n * workspace = new Workspace(this, {\n * r2: this.env.WORKSPACE_FILES,\n * // r2Prefix defaults to this.name (the Durable Object ID)\n * });\n * }\n * ```\n */\n constructor(host: WorkspaceHost, options?: WorkspaceOptions) {\n const ns = options?.namespace ?? \"default\";\n if (!VALID_NAMESPACE.test(ns)) {\n throw new Error(\n `Invalid workspace namespace \"${ns}\": must start with a letter and contain only alphanumeric characters or underscores`\n );\n }\n\n // Detect duplicate registrations on the same agent\n const registered = workspaceRegistry.get(host) ?? new Set<string>();\n if (registered.has(ns)) {\n throw new Error(\n `Workspace namespace \"${ns}\" is already registered on this agent`\n );\n }\n registered.add(ns);\n workspaceRegistry.set(host, registered);\n\n this.host = host;\n this.namespace = ns;\n this.tableName = `cf_workspace_${ns}`;\n this.indexName = `cf_workspace_${ns}_parent`;\n this.r2 = options?.r2 ?? null;\n this.r2Prefix = options?.r2Prefix;\n this.threshold = options?.inlineThreshold ?? DEFAULT_INLINE_THRESHOLD;\n this.bashLimits = {\n ...DEFAULT_BASH_LIMITS,\n ...options?.bashLimits\n };\n this.commands = options?.commands ?? [];\n this.env = options?.env ?? {};\n this.network = options?.network;\n this.onChange = options?.onChange;\n }\n\n private emit(\n type: WorkspaceChangeType,\n path: string,\n entryType: EntryType\n ): void {\n if (this.onChange) this.onChange({ type, path, entryType });\n }\n\n private _observe(type: string, payload: Record<string, unknown>): void {\n wsChannel.publish({\n type,\n name: this.host.name,\n payload: { ...payload, namespace: this.namespace },\n timestamp: Date.now()\n });\n }\n\n // ── SQL helper ─────────────────────────────────────────────────\n //\n // Replaces __TABLE__ / __INDEX__ in the static template parts\n // with the namespace-scoped names. The namespace is validated\n // at construction time (alphanumeric only), so this is safe.\n\n private sql<T = Record<string, string | number | boolean | null>>(\n strings: TemplateStringsArray,\n ...values: (string | number | boolean | null)[]\n ): T[] {\n let tsa = this.sqlCache.get(strings);\n if (!tsa) {\n const replaced = strings.map((s) =>\n s\n .replace(/__TABLE__/g, this.tableName)\n .replace(/__INDEX__/g, this.indexName)\n );\n tsa = Object.assign(replaced, {\n raw: replaced\n }) as unknown as TemplateStringsArray;\n this.sqlCache.set(strings, tsa);\n }\n return this.host.sql<T>(tsa, ...values);\n }\n\n // ── Lazy table init ─────────────────────────────────────────────\n\n private ensureInit(): void {\n if (this.initialized) return;\n this.initialized = true;\n\n this.sql`\n CREATE TABLE IF NOT EXISTS __TABLE__ (\n path TEXT PRIMARY KEY,\n parent_path TEXT NOT NULL,\n name TEXT NOT NULL,\n type TEXT NOT NULL CHECK(type IN ('file','directory','symlink')),\n mime_type TEXT NOT NULL DEFAULT 'text/plain',\n size INTEGER NOT NULL DEFAULT 0,\n storage_backend TEXT NOT NULL DEFAULT 'inline' CHECK(storage_backend IN ('inline','r2')),\n r2_key TEXT,\n target TEXT,\n content_encoding TEXT NOT NULL DEFAULT 'utf8',\n content TEXT,\n created_at INTEGER NOT NULL DEFAULT (unixepoch()),\n modified_at INTEGER NOT NULL DEFAULT (unixepoch())\n )\n `;\n\n this.sql`\n CREATE INDEX IF NOT EXISTS __INDEX__\n ON __TABLE__(parent_path)\n `;\n\n // Root directory always exists\n const hasRoot =\n this.sql<{ cnt: number }>`\n SELECT COUNT(*) AS cnt FROM __TABLE__ WHERE path = '/'\n `[0]?.cnt ?? 0;\n\n if (hasRoot === 0) {\n const now = Math.floor(Date.now() / 1000);\n this.sql`\n INSERT INTO __TABLE__\n (path, parent_path, name, type, size, created_at, modified_at)\n VALUES ('/', '', '', 'directory', 0, ${now}, ${now})\n `;\n }\n }\n\n // ── R2 helpers ─────────────────────────────────────────────────\n\n private getR2(): R2Bucket | null {\n return this.r2;\n }\n\n private resolveR2Prefix(): string {\n if (this.r2Prefix !== undefined) return this.r2Prefix;\n const name = this.host.name;\n if (!name) {\n throw new Error(\n \"[Workspace] R2 is configured but no r2Prefix was provided and host.name is not available. \" +\n \"Either pass r2Prefix in WorkspaceOptions or ensure the host exposes a name property.\"\n );\n }\n return name;\n }\n\n private r2Key(filePath: string): string {\n return `${this.resolveR2Prefix()}/${this.namespace}${filePath}`;\n }\n\n // ── Symlink resolution ────────────────────────────────────────\n\n private resolveSymlink(path: string, depth = 0): string {\n if (depth > MAX_SYMLINK_DEPTH) {\n throw new Error(`ELOOP: too many levels of symbolic links: ${path}`);\n }\n const rows = this.sql<{ type: string; target: string | null }>`\n SELECT type, target FROM __TABLE__ WHERE path = ${path}\n `;\n const r = rows[0];\n if (!r || r.type !== \"symlink\" || !r.target) return path;\n const resolved = r.target.startsWith(\"/\")\n ? normalizePath(r.target)\n : normalizePath(getParent(path) + \"/\" + r.target);\n return this.resolveSymlink(resolved, depth + 1);\n }\n\n // ── Symlink API ───────────────────────────────────────────────\n\n symlink(target: string, linkPath: string): void {\n this.ensureInit();\n if (!target || target.trim().length === 0) {\n throw new Error(\"EINVAL: symlink target must not be empty\");\n }\n if (target.length > MAX_SYMLINK_TARGET_LENGTH) {\n throw new Error(\n `ENAMETOOLONG: symlink target exceeds ${MAX_SYMLINK_TARGET_LENGTH} characters`\n );\n }\n const normalized = normalizePath(linkPath);\n if (normalized === \"/\")\n throw new Error(\"EPERM: cannot create symlink at root\");\n\n const parentPath = getParent(normalized);\n const name = getBasename(normalized);\n const now = Math.floor(Date.now() / 1000);\n\n this.ensureParentDir(parentPath);\n\n const existing = this.sql<{ type: string }>`\n SELECT type FROM __TABLE__ WHERE path = ${normalized}\n `[0];\n if (existing) {\n throw new Error(`EEXIST: path already exists: ${linkPath}`);\n }\n\n this.sql`\n INSERT INTO __TABLE__\n (path, parent_path, name, type, target, size, created_at, modified_at)\n VALUES\n (${normalized}, ${parentPath}, ${name}, 'symlink', ${target}, 0, ${now}, ${now})\n `;\n this.emit(\"create\", normalized, \"symlink\");\n }\n\n readlink(path: string): string {\n this.ensureInit();\n const normalized = normalizePath(path);\n const rows = this.sql<{ type: string; target: string | null }>`\n SELECT type, target FROM __TABLE__ WHERE path = ${normalized}\n `;\n const r = rows[0];\n if (!r) throw new Error(`ENOENT: no such file or directory: ${path}`);\n if (r.type !== \"symlink\" || !r.target)\n throw new Error(`EINVAL: not a symlink: ${path}`);\n return r.target;\n }\n\n lstat(path: string): FileStat | null {\n this.ensureInit();\n const normalized = normalizePath(path);\n const rows = this.sql<{\n path: string;\n name: string;\n type: string;\n mime_type: string;\n size: number;\n created_at: number;\n modified_at: number;\n target: string | null;\n }>`\n SELECT path, name, type, mime_type, size, created_at, modified_at, target\n FROM __TABLE__ WHERE path = ${normalized}\n `;\n const r = rows[0];\n if (!r) return null;\n return toFileInfo(r);\n }\n\n // ── Metadata ───────────────────────────────────────────────────\n\n stat(path: string): FileStat | null {\n this.ensureInit();\n const normalized = normalizePath(path);\n const resolved = this.resolveSymlink(normalized);\n const rows = this.sql<{\n path: string;\n name: string;\n type: string;\n mime_type: string;\n size: number;\n created_at: number;\n modified_at: number;\n target: string | null;\n }>`\n SELECT path, name, type, mime_type, size, created_at, modified_at, target\n FROM __TABLE__ WHERE path = ${resolved}\n `;\n const r = rows[0];\n if (!r) return null;\n return toFileInfo(r);\n }\n\n // ── File I/O ───────────────────────────────────────────────────\n\n async readFile(path: string): Promise<string | null> {\n this.ensureInit();\n const normalized = normalizePath(path);\n const resolved = this.resolveSymlink(normalized);\n const rows = this.sql<{\n type: string;\n storage_backend: string;\n r2_key: string | null;\n content: string | null;\n content_encoding: string;\n }>`\n SELECT type, storage_backend, r2_key, content, content_encoding\n FROM __TABLE__ WHERE path = ${resolved}\n `;\n const r = rows[0];\n if (!r) return null;\n if (r.type !== \"file\") throw new Error(`EISDIR: ${path} is a directory`);\n this._observe(\"workspace:read\", {\n path: resolved,\n storage: r.storage_backend as \"inline\" | \"r2\"\n });\n\n if (r.storage_backend === \"r2\" && r.r2_key) {\n const r2 = this.getR2();\n if (!r2) {\n throw new Error(\n `File ${path} is stored in R2 but no R2 bucket was provided`\n );\n }\n const obj = await r2.get(r.r2_key);\n if (!obj) return \"\";\n return await obj.text();\n }\n\n if (r.content_encoding === \"base64\" && r.content) {\n const bytes = base64ToBytes(r.content);\n return TEXT_DECODER.decode(bytes);\n }\n return r.content ?? \"\";\n }\n\n async readFileBytes(path: string): Promise<Uint8Array | null> {\n this.ensureInit();\n const normalized = normalizePath(path);\n const resolved = this.resolveSymlink(normalized);\n const rows = this.sql<{\n type: string;\n storage_backend: string;\n r2_key: string | null;\n content: string | null;\n content_encoding: string;\n }>`\n SELECT type, storage_backend, r2_key, content, content_encoding\n FROM __TABLE__ WHERE path = ${resolved}\n `;\n const r = rows[0];\n if (!r) return null;\n if (r.type !== \"file\") throw new Error(`EISDIR: ${path} is a directory`);\n this._observe(\"workspace:read\", {\n path: resolved,\n storage: r.storage_backend as \"inline\" | \"r2\"\n });\n\n if (r.storage_backend === \"r2\" && r.r2_key) {\n const r2 = this.getR2();\n if (!r2) {\n throw new Error(\n `File ${path} is stored in R2 but no R2 bucket was provided`\n );\n }\n const obj = await r2.get(r.r2_key);\n if (!obj) return new Uint8Array(0);\n return new Uint8Array(await obj.arrayBuffer());\n }\n\n if (r.content_encoding === \"base64\" && r.content) {\n return base64ToBytes(r.content);\n }\n return TEXT_ENCODER.encode(r.content ?? \"\");\n }\n\n async writeFileBytes(\n path: string,\n data: Uint8Array | ArrayBuffer,\n mimeType = \"application/octet-stream\"\n ): Promise<void> {\n this.ensureInit();\n const normalized = this.resolveSymlink(normalizePath(path));\n if (normalized === \"/\")\n throw new Error(\"EISDIR: cannot write to root directory\");\n\n const bytes = data instanceof ArrayBuffer ? new Uint8Array(data) : data;\n const size = bytes.byteLength;\n const parentPath = getParent(normalized);\n const name = getBasename(normalized);\n const now = Math.floor(Date.now() / 1000);\n\n this.ensureParentDir(parentPath);\n\n const existing = this.sql<{\n storage_backend: string;\n r2_key: string | null;\n }>`\n SELECT storage_backend, r2_key FROM __TABLE__ WHERE path = ${normalized}\n `[0];\n\n const r2 = this.getR2();\n\n if (size >= this.threshold && r2) {\n const key = this.r2Key(normalized);\n if (existing?.storage_backend === \"r2\" && existing.r2_key !== key) {\n await r2.delete(existing.r2_key!);\n }\n await r2.put(key, bytes, {\n httpMetadata: { contentType: mimeType }\n });\n try {\n this.sql`\n INSERT INTO __TABLE__\n (path, parent_path, name, type, mime_type, size,\n storage_backend, r2_key, content_encoding, content, created_at, modified_at)\n VALUES\n (${normalized}, ${parentPath}, ${name}, 'file', ${mimeType}, ${size},\n 'r2', ${key}, 'base64', NULL, ${now}, ${now})\n ON CONFLICT(path) DO UPDATE SET\n mime_type = excluded.mime_type,\n size = excluded.size,\n storage_backend = 'r2',\n r2_key = excluded.r2_key,\n content_encoding = 'base64',\n content = NULL,\n modified_at = excluded.modified_at\n `;\n } catch (sqlErr) {\n try {\n await r2.delete(key);\n } catch {\n console.error(\n `[Workspace] Failed to clean up orphaned R2 object ${key} after SQL error`\n );\n }\n throw sqlErr;\n }\n this.emit(existing ? \"update\" : \"create\", normalized, \"file\");\n this._observe(\"workspace:write\", {\n path: normalized,\n size,\n storage: \"r2\" as const,\n update: !!existing\n });\n } else {\n if (size >= this.threshold && !r2) {\n console.warn(\n `[Workspace] File ${path} is ${size} bytes but no R2 bucket was provided. Storing inline.`\n );\n }\n if (existing?.storage_backend === \"r2\" && existing.r2_key && r2) {\n await r2.delete(existing.r2_key);\n }\n const b64 = bytesToBase64(bytes);\n this.sql`\n INSERT INTO __TABLE__\n (path, parent_path, name, type, mime_type, size,\n storage_backend, r2_key, content_encoding, content, created_at, modified_at)\n VALUES\n (${normalized}, ${parentPath}, ${name}, 'file', ${mimeType}, ${size},\n 'inline', NULL, 'base64', ${b64}, ${now}, ${now})\n ON CONFLICT(path) DO UPDATE SET\n mime_type = excluded.mime_type,\n size = excluded.size,\n storage_backend = 'inline',\n r2_key = NULL,\n content_encoding = 'base64',\n content = excluded.content,\n modified_at = excluded.modified_at\n `;\n this.emit(existing ? \"update\" : \"create\", normalized, \"file\");\n this._observe(\"workspace:write\", {\n path: normalized,\n size,\n storage: \"inline\" as const,\n update: !!existing\n });\n }\n }\n\n async writeFile(\n path: string,\n content: string,\n mimeType = \"text/plain\"\n ): Promise<void> {\n this.ensureInit();\n const normalized = this.resolveSymlink(normalizePath(path));\n if (normalized === \"/\")\n throw new Error(\"EISDIR: cannot write to root directory\");\n\n const parentPath = getParent(normalized);\n const name = getBasename(normalized);\n const bytes = TEXT_ENCODER.encode(content);\n const size = bytes.byteLength;\n const now = Math.floor(Date.now() / 1000);\n\n this.ensureParentDir(parentPath);\n\n // Check if there's an existing R2 file that may need cleanup\n const existing = this.sql<{\n storage_backend: string;\n r2_key: string | null;\n }>`\n SELECT storage_backend, r2_key FROM __TABLE__ WHERE path = ${normalized}\n `[0];\n\n const r2 = this.getR2();\n\n if (size >= this.threshold && r2) {\n const key = this.r2Key(normalized);\n\n if (existing?.storage_backend === \"r2\" && existing.r2_key !== key) {\n await r2.delete(existing.r2_key!);\n }\n\n // Write to R2 first. If this fails, SQL is untouched.\n await r2.put(key, bytes, {\n httpMetadata: { contentType: mimeType }\n });\n\n // Update SQL. If this fails, clean up R2.\n try {\n this.sql`\n INSERT INTO __TABLE__\n (path, parent_path, name, type, mime_type, size,\n storage_backend, r2_key, content_encoding, content, created_at, modified_at)\n VALUES\n (${normalized}, ${parentPath}, ${name}, 'file', ${mimeType}, ${size},\n 'r2', ${key}, 'utf8', NULL, ${now}, ${now})\n ON CONFLICT(path) DO UPDATE SET\n mime_type = excluded.mime_type,\n size = excluded.size,\n storage_backend = 'r2',\n r2_key = excluded.r2_key,\n content_encoding = 'utf8',\n content = NULL,\n modified_at = excluded.modified_at\n `;\n } catch (sqlErr) {\n try {\n await r2.delete(key);\n } catch {\n console.error(\n `[Workspace] Failed to clean up orphaned R2 object ${key} after SQL error`\n );\n }\n throw sqlErr;\n }\n this.emit(existing ? \"update\" : \"create\", normalized, \"file\");\n this._observe(\"workspace:write\", {\n path: normalized,\n size,\n storage: \"r2\" as const,\n update: !!existing\n });\n } else {\n if (size >= this.threshold && !r2) {\n console.warn(\n `[Workspace] File ${path} is ${size} bytes but no R2 bucket was provided. Storing inline — this may hit SQLite row limits for very large files.`\n );\n }\n\n // Going inline: delete any existing R2 object first.\n if (existing?.storage_backend === \"r2\" && existing.r2_key && r2) {\n await r2.delete(existing.r2_key);\n }\n\n this.sql`\n INSERT INTO __TABLE__\n (path, parent_path, name, type, mime_type, size,\n storage_backend, r2_key, content_encoding, content, created_at, modified_at)\n VALUES\n (${normalized}, ${parentPath}, ${name}, 'file', ${mimeType}, ${size},\n 'inline', NULL, 'utf8', ${content}, ${now}, ${now})\n ON CONFLICT(path) DO UPDATE SET\n mime_type = excluded.mime_type,\n size = excluded.size,\n storage_backend = 'inline',\n r2_key = NULL,\n content_encoding = 'utf8',\n content = excluded.content,\n modified_at = excluded.modified_at\n `;\n this.emit(existing ? \"update\" : \"create\", normalized, \"file\");\n this._observe(\"workspace:write\", {\n path: normalized,\n size,\n storage: \"inline\" as const,\n update: !!existing\n });\n }\n }\n\n async readFileStream(\n path: string\n ): Promise<ReadableStream<Uint8Array> | null> {\n this.ensureInit();\n const normalized = normalizePath(path);\n const resolved = this.resolveSymlink(normalized);\n const rows = this.sql<{\n type: string;\n storage_backend: string;\n r2_key: string | null;\n content: string | null;\n content_encoding: string;\n }>`\n SELECT type, storage_backend, r2_key, content, content_encoding\n FROM __TABLE__ WHERE path = ${resolved}\n `;\n const r = rows[0];\n if (!r) return null;\n if (r.type !== \"file\") throw new Error(`EISDIR: ${path} is a directory`);\n this._observe(\"workspace:read\", {\n path: resolved,\n storage: r.storage_backend as \"inline\" | \"r2\"\n });\n\n if (r.storage_backend === \"r2\" && r.r2_key) {\n const r2 = this.getR2();\n if (!r2) {\n throw new Error(\n `File ${path} is stored in R2 but no R2 bucket was provided`\n );\n }\n const obj = await r2.get(r.r2_key);\n if (!obj) {\n return new ReadableStream({\n start(c) {\n c.close();\n }\n });\n }\n return obj.body;\n }\n\n // Inline: wrap content in a ReadableStream\n const bytes =\n r.content_encoding === \"base64\" && r.content\n ? base64ToBytes(r.content)\n : TEXT_ENCODER.encode(r.content ?? \"\");\n return new ReadableStream({\n start(controller) {\n controller.enqueue(bytes);\n controller.close();\n }\n });\n }\n\n async writeFileStream(\n path: string,\n stream: ReadableStream<Uint8Array>,\n mimeType = \"application/octet-stream\"\n ): Promise<void> {\n // Collect stream into a single buffer (capped at MAX_STREAM_SIZE)\n const reader = stream.getReader();\n const chunks: Uint8Array[] = [];\n let totalSize = 0;\n for (;;) {\n const { done, value } = await reader.read();\n if (done) break;\n totalSize += value.byteLength;\n if (totalSize > MAX_STREAM_SIZE) {\n reader.cancel();\n throw new Error(\n `EFBIG: stream exceeds maximum size of ${MAX_STREAM_SIZE} bytes`\n );\n }\n chunks.push(value);\n }\n\n const buffer = new Uint8Array(totalSize);\n let offset = 0;\n for (const chunk of chunks) {\n buffer.set(chunk, offset);\n offset += chunk.byteLength;\n }\n\n await this.writeFileBytes(path, buffer, mimeType);\n }\n\n async appendFile(\n path: string,\n content: string,\n mimeType = \"text/plain\"\n ): Promise<void> {\n this.ensureInit();\n const normalized = this.resolveSymlink(normalizePath(path));\n\n // Check if file exists and what storage it uses\n const row = this.sql<{\n type: string;\n storage_backend: string;\n content_encoding: string;\n }>`\n SELECT type, storage_backend, content_encoding\n FROM __TABLE__ WHERE path = ${normalized}\n `[0];\n\n if (!row) {\n // File doesn't exist — create it\n await this.writeFile(path, content, mimeType);\n return;\n }\n\n if (row.type !== \"file\") {\n throw new Error(`EISDIR: ${path} is a directory`);\n }\n\n // Fast path: inline utf8 file — SQL concat avoids full read+rewrite\n if (row.storage_backend === \"inline\" && row.content_encoding === \"utf8\") {\n const appendSize = TEXT_ENCODER.encode(content).byteLength;\n const now = Math.floor(Date.now() / 1000);\n this.sql`\n UPDATE __TABLE__ SET\n content = content || ${content},\n size = size + ${appendSize},\n modified_at = ${now}\n WHERE path = ${normalized}\n `;\n this.emit(\"update\", normalized, \"file\");\n return;\n }\n\n // Slow path: R2 or base64 — full read + concat + write\n const existing = await this.readFile(path);\n await this.writeFile(path, (existing ?? \"\") + content, mimeType);\n }\n\n async deleteFile(path: string): Promise<boolean> {\n this.ensureInit();\n const normalized = normalizePath(path);\n const rows = this.sql<{\n type: string;\n storage_backend: string;\n r2_key: string | null;\n }>`\n SELECT type, storage_backend, r2_key FROM __TABLE__ WHERE path = ${normalized}\n `;\n if (!rows[0]) return false;\n if (rows[0].type === \"directory\")\n throw new Error(`EISDIR: ${path} is a directory — use rm() instead`);\n\n if (rows[0].storage_backend === \"r2\" && rows[0].r2_key) {\n const r2 = this.getR2();\n if (r2) await r2.delete(rows[0].r2_key);\n }\n\n this.sql`DELETE FROM __TABLE__ WHERE path = ${normalized}`;\n this.emit(\"delete\", normalized, rows[0].type as EntryType);\n this._observe(\"workspace:delete\", { path: normalized });\n return true;\n }\n\n fileExists(path: string): boolean {\n this.ensureInit();\n const resolved = this.resolveSymlink(normalizePath(path));\n const rows = this.sql<{ type: string }>`\n SELECT type FROM __TABLE__ WHERE path = ${resolved}\n `;\n return rows.length > 0 && rows[0].type === \"file\";\n }\n\n exists(path: string): boolean {\n this.ensureInit();\n const normalized = normalizePath(path);\n const rows = this.sql<{ cnt: number }>`\n SELECT COUNT(*) AS cnt FROM __TABLE__ WHERE path = ${normalized}\n `;\n return (rows[0]?.cnt ?? 0) > 0;\n }\n\n // ── Directory operations ───────────────────────────────────────\n\n readDir(dir = \"/\", opts?: { limit?: number; offset?: number }): FileInfo[] {\n this.ensureInit();\n const normalized = normalizePath(dir);\n const limit = opts?.limit ?? 1000;\n const offset = opts?.offset ?? 0;\n const rows = this.sql<{\n path: string;\n name: string;\n type: string;\n mime_type: string;\n size: number;\n created_at: number;\n modified_at: number;\n }>`\n SELECT path, name, type, mime_type, size, created_at, modified_at\n FROM __TABLE__\n WHERE parent_path = ${normalized}\n ORDER BY type ASC, name ASC\n LIMIT ${limit} OFFSET ${offset}\n `;\n return rows.map(toFileInfo);\n }\n\n glob(pattern: string): FileInfo[] {\n this.ensureInit();\n const normalized = normalizePath(pattern);\n const prefix = getGlobPrefix(normalized);\n const likePattern = escapeLike(prefix) + \"%\";\n const regex = globToRegex(normalized);\n\n const rows = this.sql<{\n path: string;\n name: string;\n type: string;\n mime_type: string;\n size: number;\n created_at: number;\n modified_at: number;\n target: string | null;\n }>`\n SELECT path, name, type, mime_type, size, created_at, modified_at, target\n FROM __TABLE__\n WHERE path LIKE ${likePattern} ESCAPE ${LIKE_ESCAPE}\n ORDER BY path\n `;\n\n return rows.filter((r) => regex.test(r.path)).map(toFileInfo);\n }\n\n mkdir(path: string, opts?: { recursive?: boolean }, _depth = 0): void {\n this.ensureInit();\n if (_depth > MAX_MKDIR_DEPTH) {\n throw new Error(\n `ELOOP: mkdir recursion too deep (max ${MAX_MKDIR_DEPTH} levels)`\n );\n }\n const normalized = normalizePath(path);\n if (normalized === \"/\") return;\n\n const existing = this.sql<{ type: string }>`\n SELECT type FROM __TABLE__ WHERE path = ${normalized}\n `;\n\n if (existing.length > 0) {\n if (existing[0].type === \"directory\" && opts?.recursive) return;\n throw new Error(\n existing[0].type === \"directory\"\n ? `EEXIST: directory already exists: ${path}`\n : `EEXIST: path exists as a file: ${path}`\n );\n }\n\n const parentPath = getParent(normalized);\n const parentRows = this.sql<{ type: string }>`\n SELECT type FROM __TABLE__ WHERE path = ${parentPath}\n `;\n\n if (!parentRows[0]) {\n if (opts?.recursive) {\n this.mkdir(parentPath, { recursive: true }, _depth + 1);\n } else {\n throw new Error(`ENOENT: parent directory not found: ${parentPath}`);\n }\n } else if (parentRows[0].type !== \"directory\") {\n throw new Error(`ENOTDIR: parent is not a directory: ${parentPath}`);\n }\n\n const name = getBasename(normalized);\n const now = Math.floor(Date.now() / 1000);\n this.sql`\n INSERT INTO __TABLE__\n (path, parent_path, name, type, size, created_at, modified_at)\n VALUES (${normalized}, ${parentPath}, ${name}, 'directory', 0, ${now}, ${now})\n `;\n this.emit(\"create\", normalized, \"directory\");\n this._observe(\"workspace:mkdir\", {\n path: normalized,\n recursive: !!opts?.recursive\n });\n }\n\n async rm(\n path: string,\n opts?: { recursive?: boolean; force?: boolean }\n ): Promise<void> {\n this.ensureInit();\n const normalized = normalizePath(path);\n if (normalized === \"/\")\n throw new Error(\"EPERM: cannot remove root directory\");\n\n const rows = this.sql<{ type: string }>`\n SELECT type FROM __TABLE__ WHERE path = ${normalized}\n `;\n\n if (!rows[0]) {\n if (opts?.force) return;\n throw new Error(`ENOENT: no such file or directory: ${path}`);\n }\n\n if (rows[0].type === \"directory\") {\n const children = this.sql<{ cnt: number }>`\n SELECT COUNT(*) AS cnt FROM __TABLE__ WHERE parent_path = ${normalized}\n `;\n if ((children[0]?.cnt ?? 0) > 0) {\n if (!opts?.recursive) {\n throw new Error(`ENOTEMPTY: directory not empty: ${path}`);\n }\n await this.deleteDescendants(normalized);\n }\n } else {\n const fileRow = this.sql<{\n storage_backend: string;\n r2_key: string | null;\n }>`\n SELECT storage_backend, r2_key FROM __TABLE__ WHERE path = ${normalized}\n `[0];\n if (fileRow?.storage_backend === \"r2\" && fileRow.r2_key) {\n const r2 = this.getR2();\n if (r2) await r2.delete(fileRow.r2_key);\n }\n }\n\n this.sql`DELETE FROM __TABLE__ WHERE path = ${normalized}`;\n this.emit(\"delete\", normalized, rows[0].type as EntryType);\n this._observe(\"workspace:rm\", {\n path: normalized,\n recursive: !!opts?.recursive\n });\n }\n\n // ── Copy / Move ───────────────────────────────────────────────\n\n async cp(\n src: string,\n dest: string,\n opts?: { recursive?: boolean }\n ): Promise<void> {\n this.ensureInit();\n const srcNorm = normalizePath(src);\n const destNorm = normalizePath(dest);\n const srcStat = this.lstat(srcNorm);\n if (!srcStat) throw new Error(`ENOENT: no such file or directory: ${src}`);\n\n if (srcStat.type === \"symlink\") {\n const target = this.readlink(srcNorm);\n this.symlink(target, destNorm);\n return;\n }\n\n if (srcStat.type === \"directory\") {\n if (!opts?.recursive) {\n throw new Error(\n `EISDIR: cannot copy directory without recursive: ${src}`\n );\n }\n this.mkdir(destNorm, { recursive: true });\n for (const child of this.readDir(srcNorm)) {\n await this.cp(child.path, `${destNorm}/${child.name}`, opts);\n }\n return;\n }\n\n // File: read bytes and write to dest (preserves binary/text)\n const bytes = await this.readFileBytes(srcNorm);\n if (bytes) {\n await this.writeFileBytes(destNorm, bytes, srcStat.mimeType);\n } else {\n await this.writeFile(destNorm, \"\", srcStat.mimeType);\n }\n this._observe(\"workspace:cp\", {\n src: srcNorm,\n dest: destNorm,\n recursive: !!opts?.recursive\n });\n }\n\n async mv(\n src: string,\n dest: string,\n opts?: { recursive?: boolean }\n ): Promise<void> {\n this.ensureInit();\n const srcNorm = normalizePath(src);\n const destNorm = normalizePath(dest);\n const srcStat = this.lstat(srcNorm);\n if (!srcStat) throw new Error(`ENOENT: no such file or directory: ${src}`);\n\n // Directories: fall back to cp+rm (path rewriting is complex)\n if (srcStat.type === \"directory\") {\n if (!(opts?.recursive ?? true)) {\n throw new Error(\n `EISDIR: cannot move directory without recursive: ${src}`\n );\n }\n await this.cp(src, dest, { recursive: true });\n await this.rm(src, { recursive: true, force: true });\n return;\n }\n\n // Single file or symlink: use SQL UPDATE (much faster than cp+rm)\n const destParent = getParent(destNorm);\n const destName = getBasename(destNorm);\n this.ensureParentDir(destParent);\n\n // Remove existing dest if present\n const existingDest = this.sql<{ type: string }>`\n SELECT type FROM __TABLE__ WHERE path = ${destNorm}\n `[0];\n if (existingDest) {\n if (existingDest.type === \"directory\") {\n throw new Error(`EISDIR: cannot overwrite directory: ${dest}`);\n }\n await this.deleteFile(destNorm);\n }\n\n // For R2-backed files, copy the R2 object to new key first\n if (srcStat.type === \"file\") {\n const row = this.sql<{\n storage_backend: string;\n r2_key: string | null;\n }>`\n SELECT storage_backend, r2_key FROM __TABLE__ WHERE path = ${srcNorm}\n `[0];\n if (row?.storage_backend === \"r2\" && row.r2_key) {\n const r2 = this.getR2();\n if (r2) {\n const newKey = this.r2Key(destNorm);\n const obj = await r2.get(row.r2_key);\n if (obj) {\n await r2.put(newKey, await obj.arrayBuffer(), {\n httpMetadata: obj.httpMetadata\n });\n }\n await r2.delete(row.r2_key);\n const now = Math.floor(Date.now() / 1000);\n this.sql`\n UPDATE __TABLE__ SET\n path = ${destNorm},\n parent_path = ${destParent},\n name = ${destName},\n r2_key = ${newKey},\n modified_at = ${now}\n WHERE path = ${srcNorm}\n `;\n this.emit(\"delete\", srcNorm, \"file\");\n this.emit(\"create\", destNorm, \"file\");\n this._observe(\"workspace:mv\", {\n src: srcNorm,\n dest: destNorm\n });\n return;\n }\n }\n }\n\n // Inline file or symlink: single UPDATE\n const now = Math.floor(Date.now() / 1000);\n this.sql`\n UPDATE __TABLE__ SET\n path = ${destNorm},\n parent_path = ${destParent},\n name = ${destName},\n modified_at = ${now}\n WHERE path = ${srcNorm}\n `;\n this.emit(\"delete\", srcNorm, srcStat.type);\n this.emit(\"create\", destNorm, srcStat.type);\n this._observe(\"workspace:mv\", { src: srcNorm, dest: destNorm });\n }\n\n // ── Diff ───────────────────────────────────────────────────────\n\n async diff(pathA: string, pathB: string): Promise<string> {\n const contentA = await this.readFile(pathA);\n if (contentA === null) throw new Error(`ENOENT: no such file: ${pathA}`);\n const contentB = await this.readFile(pathB);\n if (contentB === null) throw new Error(`ENOENT: no such file: ${pathB}`);\n const linesA = contentA.split(\"\\n\").length;\n const linesB = contentB.split(\"\\n\").length;\n if (linesA > MAX_DIFF_LINES || linesB > MAX_DIFF_LINES) {\n throw new Error(\n `EFBIG: files too large for diff (max ${MAX_DIFF_LINES} lines)`\n );\n }\n return unifiedDiff(\n contentA,\n contentB,\n normalizePath(pathA),\n normalizePath(pathB)\n );\n }\n\n async diffContent(path: string, newContent: string): Promise<string> {\n const existing = await this.readFile(path);\n if (existing === null) throw new Error(`ENOENT: no such file: ${path}`);\n const linesA = existing.split(\"\\n\").length;\n const linesB = newContent.split(\"\\n\").length;\n if (linesA > MAX_DIFF_LINES || linesB > MAX_DIFF_LINES) {\n throw new Error(\n `EFBIG: content too large for diff (max ${MAX_DIFF_LINES} lines)`\n );\n }\n const normalized = normalizePath(path);\n return unifiedDiff(existing, newContent, normalized, normalized);\n }\n\n // ── Bash execution ─────────────────────────────────────────────\n\n private _resolveBashConfig(options?: BashOptions): {\n commands: CustomCommand[] | undefined;\n env: Record<string, string> | undefined;\n network: NetworkConfig | undefined;\n } {\n const commands = options?.commands\n ? [...this.commands, ...options.commands]\n : this.commands.length > 0\n ? this.commands\n : undefined;\n const hasWsEnv = Object.keys(this.env).length > 0;\n const env =\n options?.env && hasWsEnv\n ? { ...this.env, ...options.env }\n : (options?.env ?? (hasWsEnv ? this.env : undefined));\n const network = options?.network ?? this.network;\n return { commands, env, network };\n }\n\n async bash(command: string, options?: BashOptions): Promise<BashResult> {\n this.ensureInit();\n const { commands, env, network } = this._resolveBashConfig(options);\n const fs = new WorkspaceFileSystem(this);\n const bashInstance = new Bash({\n fs,\n cwd: options?.cwd ?? \"/\",\n executionLimits: this.bashLimits,\n customCommands: commands,\n env,\n network\n });\n const t0 = Date.now();\n const result = await bashInstance.exec(command);\n this._observe(\"workspace:bash\", {\n command,\n exitCode: result.exitCode,\n durationMs: Date.now() - t0\n });\n return {\n stdout: result.stdout,\n stderr: result.stderr,\n exitCode: result.exitCode\n };\n }\n\n createBashSession(options?: BashOptions): BashSession {\n this.ensureInit();\n const { commands, env, network } = this._resolveBashConfig(options);\n return new BashSession({\n ws: this,\n fs: new WorkspaceFileSystem(this),\n bashLimits: this.bashLimits,\n commands,\n env: env ? { ...env } : {},\n network,\n cwd: options?.cwd ?? \"/\",\n observe: this._observe.bind(this)\n });\n }\n\n // ── Info ────────────────────────────────────────────────────────\n\n getWorkspaceInfo(): {\n fileCount: number;\n directoryCount: number;\n totalBytes: number;\n r2FileCount: number;\n } {\n this.ensureInit();\n const rows = this.sql<{\n files: number;\n dirs: number;\n total: number;\n r2files: number;\n }>`\n SELECT\n SUM(CASE WHEN type = 'file' THEN 1 ELSE 0 END) AS files,\n SUM(CASE WHEN type = 'directory' THEN 1 ELSE 0 END) AS dirs,\n COALESCE(SUM(CASE WHEN type = 'file' THEN size ELSE 0 END), 0) AS total,\n SUM(CASE WHEN type = 'file' AND storage_backend = 'r2' THEN 1 ELSE 0 END) AS r2files\n FROM __TABLE__\n `;\n return {\n fileCount: rows[0]?.files ?? 0,\n directoryCount: rows[0]?.dirs ?? 0,\n totalBytes: rows[0]?.total ?? 0,\n r2FileCount: rows[0]?.r2files ?? 0\n };\n }\n\n // ── Internal helpers (used by WorkspaceFileSystem) ─────────────\n\n /** @internal */\n _getAllPaths(): string[] {\n this.ensureInit();\n return this.sql<{ path: string }>`\n SELECT path FROM __TABLE__ ORDER BY path\n `.map((r) => r.path);\n }\n\n /** @internal */\n _updateModifiedAt(path: string, mtime: Date): void {\n this.ensureInit();\n const normalized = normalizePath(path);\n const ts = Math.floor(mtime.getTime() / 1000);\n this.sql`\n UPDATE __TABLE__ SET modified_at = ${ts} WHERE path = ${normalized}\n `;\n }\n\n // ── Private helpers ────────────────────────────────────────────\n\n private ensureParentDir(dirPath: string): void {\n if (!dirPath || dirPath === \"/\") return;\n\n // Quick check: immediate parent exists?\n const rows = this.sql<{ type: string }>`\n SELECT type FROM __TABLE__ WHERE path = ${dirPath}\n `;\n if (rows[0]) {\n if (rows[0].type !== \"directory\") {\n throw new Error(`ENOTDIR: ${dirPath} is not a directory`);\n }\n return;\n }\n\n // Walk up to find the deepest existing ancestor\n const missing: string[] = [dirPath];\n let current = getParent(dirPath);\n while (current && current !== \"/\") {\n const r = this.sql<{ type: string }>`\n SELECT type FROM __TABLE__ WHERE path = ${current}\n `;\n if (r[0]) {\n if (r[0].type !== \"directory\") {\n throw new Error(`ENOTDIR: ${current} is not a directory`);\n }\n break;\n }\n missing.push(current);\n current = getParent(current);\n }\n\n // Insert missing ancestors top-down\n const now = Math.floor(Date.now() / 1000);\n for (let i = missing.length - 1; i >= 0; i--) {\n const p = missing[i];\n const parentPath = getParent(p);\n const name = getBasename(p);\n this.sql`\n INSERT INTO __TABLE__\n (path, parent_path, name, type, size, created_at, modified_at)\n VALUES (${p}, ${parentPath}, ${name}, 'directory', 0, ${now}, ${now})\n `;\n this.emit(\"create\", p, \"directory\");\n }\n }\n\n private async deleteDescendants(dirPath: string): Promise<void> {\n const pattern = escapeLike(dirPath) + \"/%\";\n\n const r2Rows = this.sql<{ r2_key: string }>`\n SELECT r2_key FROM __TABLE__\n WHERE path LIKE ${pattern} ESCAPE ${LIKE_ESCAPE}\n AND storage_backend = 'r2'\n AND r2_key IS NOT NULL\n `;\n\n if (r2Rows.length > 0) {\n const r2 = this.getR2();\n if (r2) {\n const keys = r2Rows.map((r) => r.r2_key);\n await r2.delete(keys);\n }\n }\n\n this\n .sql`DELETE FROM __TABLE__ WHERE path LIKE ${pattern} ESCAPE ${LIKE_ESCAPE}`;\n }\n}\n\n// ── BashSession ──────────────────────────────────────────────────────\n//\n// Preserves cwd and all shell variables across multiple exec() calls.\n// Each exec() creates a fresh Bash instance seeded with the tracked state.\n// After execution, cwd and env are captured via stdout sentinels that\n// are stripped before returning the result to the caller.\n// Created via workspace.createBashSession().\n\ninterface BashSessionInit {\n ws: Workspace;\n fs: WorkspaceFileSystem;\n bashLimits: {\n maxCommandCount: number;\n maxLoopIterations: number;\n maxCallDepth: number;\n };\n commands: CustomCommand[] | undefined;\n env: Record<string, string>;\n network: NetworkConfig | undefined;\n cwd: string;\n observe: (type: string, payload: Record<string, unknown>) => void;\n}\n\nexport class BashSession {\n private readonly _ws: Workspace;\n private readonly _fs: WorkspaceFileSystem;\n private readonly _bashLimits: {\n maxCommandCount: number;\n maxLoopIterations: number;\n maxCallDepth: number;\n };\n private readonly _customCommands: CustomCommand[] | undefined;\n private readonly _networkConfig: NetworkConfig | undefined;\n private readonly _observe: (\n type: string,\n payload: Record<string, unknown>\n ) => void;\n private _currentCwd: string;\n private _currentEnv: Record<string, string>;\n private _closed = false;\n\n /** @internal — use workspace.createBashSession() instead */\n constructor(init: BashSessionInit) {\n this._ws = init.ws;\n this._fs = init.fs;\n this._bashLimits = init.bashLimits;\n this._customCommands = init.commands;\n this._networkConfig = init.network;\n this._observe = init.observe;\n this._currentCwd = init.cwd;\n this._currentEnv = init.env;\n }\n\n async exec(command: string): Promise<BashResult> {\n if (this._closed) {\n throw new Error(\"BashSession is closed\");\n }\n\n const bash = new Bash({\n fs: this._fs,\n cwd: this._currentCwd,\n env:\n Object.keys(this._currentEnv).length > 0 ? this._currentEnv : undefined,\n executionLimits: this._bashLimits,\n customCommands: this._customCommands,\n network: this._networkConfig\n });\n\n const wrapped =\n `${command}\\n__sess_rc=$?\\n` +\n `echo \"${SESS_STATE_BEGIN}\"\\n` +\n `echo \"${SESS_CWD_PREFIX}$(pwd)\"\\n` +\n `env\\n` +\n `echo \"${SESS_STATE_END}\"\\n` +\n `exit $__sess_rc`;\n\n const t0 = Date.now();\n const result = await bash.exec(wrapped);\n\n let stdout = result.stdout;\n const beginIdx = stdout.lastIndexOf(SESS_STATE_BEGIN);\n const endIdx = stdout.lastIndexOf(SESS_STATE_END);\n if (beginIdx >= 0 && endIdx > beginIdx) {\n const stateBlock = stdout.slice(\n beginIdx + SESS_STATE_BEGIN.length + 1,\n endIdx\n );\n const lines = stateBlock.split(\"\\n\");\n const newEnv: Record<string, string> = {};\n for (const line of lines) {\n if (line.startsWith(SESS_CWD_PREFIX)) {\n const cwd = line.slice(SESS_CWD_PREFIX.length).trim();\n if (cwd) this._currentCwd = cwd;\n } else if (line.includes(\"=\")) {\n const eqIdx = line.indexOf(\"=\");\n const key = line.slice(0, eqIdx);\n const value = line.slice(eqIdx + 1);\n if (key && key !== \"__sess_rc\") {\n newEnv[key] = value;\n }\n }\n }\n if (Object.keys(newEnv).length > 0) {\n this._currentEnv = newEnv;\n }\n let cutStart = beginIdx;\n if (cutStart > 0 && stdout[cutStart - 1] === \"\\n\") cutStart--;\n stdout = stdout.slice(0, cutStart);\n }\n\n this._observe(\"workspace:bash\", {\n command,\n exitCode: result.exitCode,\n durationMs: Date.now() - t0,\n session: true\n });\n\n return {\n stdout,\n stderr: result.stderr,\n exitCode: result.exitCode\n };\n }\n\n get cwd(): string {\n return this._currentCwd;\n }\n\n get env(): Record<string, string> {\n return { ...this._currentEnv };\n }\n\n get isClosed(): boolean {\n return this._closed;\n }\n\n close(): void {\n this._closed = true;\n }\n\n [Symbol.dispose](): void {\n this.close();\n }\n}\n\n// ── WorkspaceFileSystem (IFileSystem bridge for @cloudflare/shell) ──\n//\n// Bridges the workspace's async file methods into the IFileSystem\n// interface that @cloudflare/shell expects. All reads/writes go through\n// the workspace so bash commands share the same durable storage.\n//\n// We define the IFileSystem shape locally to avoid a hard dependency\n// on @cloudflare/shell types at compile time.\n\ninterface FsStat {\n isFile: boolean;\n isDirectory: boolean;\n isSymbolicLink: boolean;\n mode: number;\n size: number;\n mtime: Date;\n}\n\ninterface DirentEntry {\n name: string;\n isFile: boolean;\n isDirectory: boolean;\n isSymbolicLink: boolean;\n}\n\ntype FileContent = string | Uint8Array;\ntype BufferEncoding = \"utf-8\" | \"utf8\" | \"ascii\" | \"base64\" | \"hex\" | \"latin1\";\ntype ReadFileOptions = { encoding?: BufferEncoding | null };\ntype WriteFileOptions = { encoding?: BufferEncoding };\ntype MkdirOptions = { recursive?: boolean };\ntype RmOptions = { recursive?: boolean; force?: boolean };\ntype CpOptions = { recursive?: boolean };\n\nfunction fileContentToString(content: FileContent): string {\n return typeof content === \"string\" ? content : TEXT_DECODER.decode(content);\n}\n\nclass WorkspaceFileSystem {\n constructor(private ws: Workspace) {}\n\n async readFile(\n path: string,\n _options?: ReadFileOptions | BufferEncoding\n ): Promise<string> {\n const content = await this.ws.readFile(path);\n if (content === null)\n throw Object.assign(new Error(`ENOENT: ${path}`), { code: \"ENOENT\" });\n return content;\n }\n\n async readFileBuffer(path: string): Promise<Uint8Array> {\n const bytes = await this.ws.readFileBytes(path);\n if (bytes === null)\n throw Object.assign(new Error(`ENOENT: ${path}`), { code: \"ENOENT\" });\n return bytes;\n }\n\n async writeFile(\n path: string,\n content: FileContent,\n _options?: WriteFileOptions | BufferEncoding\n ): Promise<void> {\n if (typeof content === \"string\") {\n await this.ws.writeFile(path, content);\n } else {\n await this.ws.writeFileBytes(path, content);\n }\n }\n\n async appendFile(\n path: string,\n content: FileContent,\n _options?: WriteFileOptions | BufferEncoding\n ): Promise<void> {\n await this.ws.appendFile(path, fileContentToString(content));\n }\n\n async exists(path: string): Promise<boolean> {\n return this.ws.stat(path) !== null;\n }\n\n async stat(path: string): Promise<FsStat> {\n const s = this.ws.stat(path);\n if (!s)\n throw Object.assign(new Error(`ENOENT: ${path}`), { code: \"ENOENT\" });\n return {\n isFile: s.type === \"file\",\n isDirectory: s.type === \"directory\",\n isSymbolicLink: false,\n mode: s.type === \"directory\" ? 0o755 : 0o644,\n size: s.size,\n mtime: new Date(s.updatedAt)\n };\n }\n\n async lstat(path: string): Promise<FsStat> {\n const s = this.ws.lstat(path);\n if (!s)\n throw Object.assign(new Error(`ENOENT: ${path}`), { code: \"ENOENT\" });\n return {\n isFile: s.type === \"file\",\n isDirectory: s.type === \"directory\",\n isSymbolicLink: s.type === \"symlink\",\n mode: s.type === \"directory\" ? 0o755 : 0o644,\n size: s.size,\n mtime: new Date(s.updatedAt)\n };\n }\n\n async mkdir(path: string, options?: MkdirOptions): Promise<void> {\n this.ws.mkdir(path, options);\n }\n\n async readdir(path: string): Promise<string[]> {\n return this.ws.readDir(path).map((e) => e.name);\n }\n\n async readdirWithFileTypes(path: string): Promise<DirentEntry[]> {\n return this.ws.readDir(path).map((e) => ({\n name: e.name,\n isFile: e.type === \"file\",\n isDirectory: e.type === \"directory\",\n isSymbolicLink: e.type === \"symlink\"\n }));\n }\n\n async rm(path: string, options?: RmOptions): Promise<void> {\n await this.ws.rm(path, options);\n }\n\n async cp(src: string, dest: string, options?: CpOptions): Promise<void> {\n await this.ws.cp(src, dest, options);\n }\n\n async mv(src: string, dest: string): Promise<void> {\n await this.ws.mv(src, dest);\n }\n\n resolvePath(base: string, path: string): string {\n const raw = path.startsWith(\"/\") ? path : `${base}/${path}`;\n const parts = raw.split(\"/\").filter(Boolean);\n const resolved: string[] = [];\n for (const part of parts) {\n if (part === \"..\") resolved.pop();\n else if (part !== \".\") resolved.push(part);\n }\n return \"/\" + resolved.join(\"/\");\n }\n\n getAllPaths(): string[] {\n return this.ws._getAllPaths();\n }\n\n async chmod(_path: string, _mode: number): Promise<void> {\n // no-op\n }\n\n async symlink(target: string, linkPath: string): Promise<void> {\n this.ws.symlink(target, linkPath);\n }\n\n async link(_existingPath: string, _newPath: string): Promise<void> {\n throw new Error(\"ENOSYS: hard links not supported in workspace filesystem\");\n }\n\n async readlink(path: string): Promise<string> {\n return this.ws.readlink(path);\n }\n\n async realpath(path: string): Promise<string> {\n const normalized = normalizePath(path);\n const s = this.ws.lstat(normalized);\n if (!s)\n throw Object.assign(new Error(`ENOENT: ${path}`), { code: \"ENOENT\" });\n if (s.type === \"symlink\") {\n const target = this.ws.readlink(normalized);\n const resolved = target.startsWith(\"/\")\n ? normalizePath(target)\n : normalizePath(getParent(normalized) + \"/\" + target);\n return this.realpath(resolved);\n }\n return normalized;\n }\n\n async utimes(_path: string, _atime: Date, mtime: Date): Promise<void> {\n this.ws._updateModifiedAt(_path, mtime);\n }\n}\n\n// ── Base64 helpers ───────────────────────────────────────────────────\n\nfunction bytesToBase64(bytes: Uint8Array): string {\n const CHUNK = 8192;\n let binary = \"\";\n for (let i = 0; i < bytes.byteLength; i += CHUNK) {\n binary += String.fromCharCode(\n ...bytes.subarray(i, Math.min(i + CHUNK, bytes.byteLength))\n );\n }\n return btoa(binary);\n}\n\nfunction base64ToBytes(b64: string): Uint8Array {\n const binary = atob(b64);\n const bytes = new Uint8Array(binary.length);\n for (let i = 0; i < binary.length; i++) {\n bytes[i] = binary.charCodeAt(i);\n }\n return bytes;\n}\n\n// ── Path helpers ─────────────────────────────────────────────────────\n\nfunction escapeLike(s: string): string {\n return s.replace(/[\\\\%_]/g, (ch) => \"\\\\\" + ch);\n}\n\nfunction normalizePath(path: string): string {\n if (!path.startsWith(\"/\")) path = \"/\" + path;\n const parts = path.split(\"/\");\n const resolved: string[] = [];\n for (const part of parts) {\n if (part === \"\" || part === \".\") continue;\n if (part === \"..\") {\n resolved.pop();\n } else {\n resolved.push(part);\n }\n }\n const result = \"/\" + resolved.join(\"/\");\n if (result.length > MAX_PATH_LENGTH) {\n throw new Error(`ENAMETOOLONG: path exceeds ${MAX_PATH_LENGTH} characters`);\n }\n return result;\n}\n\nfunction getParent(path: string): string {\n const normalized = normalizePath(path);\n if (normalized === \"/\") return \"\";\n const lastSlash = normalized.lastIndexOf(\"/\");\n return lastSlash === 0 ? \"/\" : normalized.slice(0, lastSlash);\n}\n\nfunction getBasename(path: string): string {\n const normalized = normalizePath(path);\n if (normalized === \"/\") return \"\";\n return normalized.slice(normalized.lastIndexOf(\"/\") + 1);\n}\n\nfunction toFileInfo(r: {\n path: string;\n name: string;\n type: string;\n mime_type: string;\n size: number;\n created_at: number;\n modified_at: number;\n target?: string | null;\n}): FileInfo {\n const info: FileInfo = {\n path: r.path,\n name: r.name,\n type: r.type as EntryType,\n mimeType: r.mime_type,\n size: r.size,\n createdAt: r.created_at * 1000,\n updatedAt: r.modified_at * 1000\n };\n if (r.target) info.target = r.target;\n return info;\n}\n\n// ── Glob helpers ─────────────────────────────────────────────────────\n\nfunction getGlobPrefix(pattern: string): string {\n const first = pattern.search(/[*?[{]/);\n if (first === -1) return pattern;\n const before = pattern.slice(0, first);\n const lastSlash = before.lastIndexOf(\"/\");\n return lastSlash >= 0 ? before.slice(0, lastSlash + 1) : \"/\";\n}\n\nfunction globToRegex(pattern: string): RegExp {\n let i = 0;\n let re = \"^\";\n while (i < pattern.length) {\n const ch = pattern[i];\n if (ch === \"*\") {\n if (pattern[i + 1] === \"*\") {\n // ** — match everything including /\n i += 2;\n if (pattern[i] === \"/\") {\n // **/ — zero or more directory segments\n re += \"(?:.+/)?\";\n i++;\n } else {\n re += \".*\";\n }\n } else {\n // * — match everything except /\n re += \"[^/]*\";\n i++;\n }\n } else if (ch === \"?\") {\n re += \"[^/]\";\n i++;\n } else if (ch === \"[\") {\n // character class — pass through until ]\n const close = pattern.indexOf(\"]\", i + 1);\n if (close === -1) {\n re += \"\\\\[\";\n i++;\n } else {\n re += pattern.slice(i, close + 1);\n i = close + 1;\n }\n } else if (ch === \"{\") {\n // brace expansion {a,b,c} → (?:a|b|c)\n const close = pattern.indexOf(\"}\", i + 1);\n if (close === -1) {\n re += \"\\\\{\";\n i++;\n } else {\n const inner = pattern\n .slice(i + 1, close)\n .split(\",\")\n .join(\"|\");\n re += `(?:${inner})`;\n i = close + 1;\n }\n } else {\n // escape regex special chars\n re += ch.replace(/[.+^$|\\\\()]/g, \"\\\\$&\");\n i++;\n }\n }\n re += \"$\";\n return new RegExp(re);\n}\n\n// ── Diff helpers ─────────────────────────────────────────────────────\n\nfunction unifiedDiff(\n a: string,\n b: string,\n labelA: string,\n labelB: string,\n contextLines = 3\n): string {\n if (a === b) return \"\";\n\n const linesA = a.split(\"\\n\");\n const linesB = b.split(\"\\n\");\n const edits = myersDiff(linesA, linesB);\n return formatUnified(edits, linesA, linesB, labelA, labelB, contextLines);\n}\n\ntype Edit = {\n type: \"keep\" | \"delete\" | \"insert\";\n lineA: number;\n lineB: number;\n};\n\nfunction myersDiff(a: string[], b: string[]): Edit[] {\n const n = a.length;\n const m = b.length;\n const max = n + m;\n const vSize = 2 * max + 1;\n const v = new Int32Array(vSize);\n v.fill(-1);\n const offset = max;\n v[offset + 1] = 0;\n\n const trace: Int32Array[] = [];\n\n outer: for (let d = 0; d <= max; d++) {\n trace.push(v.slice());\n for (let k = -d; k <= d; k += 2) {\n let x: number;\n if (k === -d || (k !== d && v[offset + k - 1] < v[offset + k + 1])) {\n x = v[offset + k + 1];\n } else {\n x = v[offset + k - 1] + 1;\n }\n let y = x - k;\n while (x < n && y < m && a[x] === b[y]) {\n x++;\n y++;\n }\n v[offset + k] = x;\n if (x >= n && y >= m) break outer;\n }\n }\n\n const edits: Edit[] = [];\n let x = n;\n let y = m;\n\n for (let d = trace.length - 1; d >= 0; d--) {\n const vPrev = trace[d];\n const k = x - y;\n let prevK: number;\n if (\n k === -d ||\n (k !== d && vPrev[offset + k - 1] < vPrev[offset + k + 1])\n ) {\n prevK = k + 1;\n } else {\n prevK = k - 1;\n }\n const prevX = vPrev[offset + prevK];\n const prevY = prevX - prevK;\n\n while (x > prevX && y > prevY) {\n x--;\n y--;\n edits.push({ type: \"keep\", lineA: x, lineB: y });\n }\n if (d > 0) {\n if (x === prevX) {\n edits.push({ type: \"insert\", lineA: x, lineB: y - 1 });\n y--;\n } else {\n edits.push({ type: \"delete\", lineA: x - 1, lineB: y });\n x--;\n }\n }\n }\n\n edits.reverse();\n return edits;\n}\n\nfunction formatUnified(\n edits: Edit[],\n linesA: string[],\n linesB: string[],\n labelA: string,\n labelB: string,\n ctx: number\n): string {\n const out: string[] = [];\n out.push(`--- ${labelA}`);\n out.push(`+++ ${labelB}`);\n\n const changes: number[] = [];\n for (let i = 0; i < edits.length; i++) {\n if (edits[i].type !== \"keep\") changes.push(i);\n }\n if (changes.length === 0) return \"\";\n\n let i = 0;\n while (i < changes.length) {\n let start = Math.max(0, changes[i] - ctx);\n let end = Math.min(edits.length - 1, changes[i] + ctx);\n\n let j = i + 1;\n while (j < changes.length && changes[j] - ctx <= end + 1) {\n end = Math.min(edits.length - 1, changes[j] + ctx);\n j++;\n }\n\n let startA = edits[start].lineA;\n let startB = edits[start].lineB;\n let countA = 0;\n let countB = 0;\n const hunkLines: string[] = [];\n\n for (let idx = start; idx <= end; idx++) {\n const e = edits[idx];\n if (e.type === \"keep\") {\n hunkLines.push(` ${linesA[e.lineA]}`);\n countA++;\n countB++;\n } else if (e.type === \"delete\") {\n hunkLines.push(`-${linesA[e.lineA]}`);\n countA++;\n } else {\n hunkLines.push(`+${linesB[e.lineB]}`);\n countB++;\n }\n }\n\n out.push(`@@ -${startA + 1},${countA} +${startB + 1},${countB} @@`);\n out.push(...hunkLines);\n i = j;\n }\n\n return out.join(\"\\n\");\n}\n"],"mappings":"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"}
@@ -707,7 +707,7 @@ declare class MCPClientConnection {
707
707
  */
708
708
  getTransport(
709
709
  transportType: BaseTransportType
710
- ): StreamableHTTPClientTransport | SSEClientTransport | RPCClientTransport;
710
+ ): SSEClientTransport | StreamableHTTPClientTransport | RPCClientTransport;
711
711
  private tryConnect;
712
712
  private _capabilityErrorHandler;
713
713
  }
@@ -2837,4 +2837,4 @@ export {
2837
2837
  Schedule as y,
2838
2838
  MCPServerOptions as z
2839
2839
  };
2840
- //# sourceMappingURL=index-WBy5hmm3.d.ts.map
2840
+ //# sourceMappingURL=index-DBW341gU.d.ts.map
package/dist/index.d.ts CHANGED
@@ -34,7 +34,7 @@ import {
34
34
  w as SubAgentStub,
35
35
  x as StateUpdateMessage,
36
36
  y as Schedule
37
- } from "./index-WBy5hmm3.js";
37
+ } from "./index-DBW341gU.js";
38
38
  import {
39
39
  n as AgentsOAuthProvider,
40
40
  r as DurableObjectOAuthClientProvider,
package/dist/index.js CHANGED
@@ -1365,6 +1365,7 @@ var Agent = class Agent extends Server {
1365
1365
  `;
1366
1366
  if (existing.length > 0) {
1367
1367
  const row = existing[0];
1368
+ await this._scheduleNextAlarm();
1368
1369
  return {
1369
1370
  callback: row.callback,
1370
1371
  id: row.id,
@@ -1529,15 +1530,30 @@ var Agent = class Agent extends Server {
1529
1530
  */
1530
1531
  async _cf_keepAliveHeartbeat() {}
1531
1532
  async _scheduleNextAlarm() {
1532
- const result = this.sql`
1533
+ const nowMs = Date.now();
1534
+ const hungCutoffSeconds = Math.floor(nowMs / 1e3) - this._resolvedOptions.hungScheduleTimeoutSeconds;
1535
+ const readySchedules = this.sql`
1533
1536
  SELECT time FROM cf_agents_schedules
1534
- WHERE time >= ${Math.floor(Date.now() / 1e3)}
1537
+ WHERE type != 'interval'
1538
+ OR running = 0
1539
+ OR coalesce(execution_started_at, 0) <= ${hungCutoffSeconds}
1535
1540
  ORDER BY time ASC
1536
1541
  LIMIT 1
1537
1542
  `;
1538
- if (!result) return;
1543
+ const recoveringIntervals = this.sql`
1544
+ SELECT execution_started_at FROM cf_agents_schedules
1545
+ WHERE type = 'interval'
1546
+ AND running = 1
1547
+ AND coalesce(execution_started_at, 0) > ${hungCutoffSeconds}
1548
+ ORDER BY execution_started_at ASC
1549
+ LIMIT 1
1550
+ `;
1539
1551
  let nextTimeMs = null;
1540
- if (result.length > 0 && "time" in result[0]) nextTimeMs = result[0].time * 1e3;
1552
+ if (readySchedules.length > 0 && "time" in readySchedules[0]) nextTimeMs = Math.max(readySchedules[0].time * 1e3, nowMs + 1);
1553
+ if (recoveringIntervals.length > 0 && recoveringIntervals[0].execution_started_at !== null) {
1554
+ const recoveryTimeMs = (recoveringIntervals[0].execution_started_at + this._resolvedOptions.hungScheduleTimeoutSeconds) * 1e3;
1555
+ nextTimeMs = nextTimeMs === null ? recoveryTimeMs : Math.min(nextTimeMs, recoveryTimeMs);
1556
+ }
1541
1557
  if (nextTimeMs !== null) await this.ctx.storage.setAlarm(nextTimeMs);
1542
1558
  else await this.ctx.storage.deleteAlarm();
1543
1559
  }