diff --git a/apps/agent-worker/README.md b/apps/agent-worker/README.md index 2f7d433d..ba209ff7 100644 --- a/apps/agent-worker/README.md +++ b/apps/agent-worker/README.md @@ -133,10 +133,6 @@ manifest avoids rewriting unchanged packages and limits cleanup to files previou managed by that package, preserving local dependencies and generated output. Curated default skills are immutable snapshot files under `/home/node/.cheatcode/default-skills/`. -ProjectSandbox also writes `/workspace/.cheatcode/runtime.json` as a generated projection of -managed app-preview processes through Daytona's filesystem API. The Durable Object process records -remain authoritative; the file is only an inspectable runtime manifest. - Managed processes use required stable IDs and a maximum of 32 live metadata slots per user sandbox. Reusing an ID atomically replaces that slot. At capacity, ProjectSandbox reconciles the bounded record set against Daytona, removes missing or completed sessions and their port state, diff --git a/apps/agent-worker/src/durable-objects/project-sandbox-lifecycle.ts b/apps/agent-worker/src/durable-objects/project-sandbox-lifecycle.ts index e445e7d5..d4cf97cd 100644 --- a/apps/agent-worker/src/durable-objects/project-sandbox-lifecycle.ts +++ b/apps/agent-worker/src/durable-objects/project-sandbox-lifecycle.ts @@ -47,7 +47,6 @@ import { } from "./project-sandbox-workspace-state"; const ClearWorkspaceEvidenceSchema = z.object({ cleared: z.literal(true) }).strict(); -const RUNTIME_MANIFEST_PATH = "/workspace/.cheatcode/runtime.json"; const RUNTIME_RESET_PENDING_KEY = "sandbox_runtime_reset_pending"; const SKILL_RUNTIME_DIRECTORY = "/workspace/.cheatcode/runtime"; @@ -682,7 +681,6 @@ export abstract class ProjectSandboxLifecycle extends DurableObject { const result = await this.runCode({ code: "print('ready')", language: "python" }); - const id = await this.existingSandboxId(); - if (id) await this.syncRuntimeManifestBestEffort(id); return { healthy: result.success, ping: result.stdout.trim(), @@ -198,12 +195,10 @@ export abstract class ProjectSandboxProcesses extends ProjectSandboxLifecycle { ); } catch (error) { await this.cleanupLaunchedProcess(id, sessionId, name); - await this.syncRuntimeManifestBestEffort(id); throw error; } const record = { ...provisionalRecord, cmdId: exec.cmdId ?? sessionId }; await this.persistStartedProcess(id, name, record, parsed.waitForPort); - await this.syncRuntimeManifestBestEffort(id); await recordSandboxUsageBestEffort(await this.meteringContext()); return { command: record.command, id: name, status: "running" }; } @@ -299,7 +294,6 @@ export abstract class ProjectSandboxProcesses extends ProjectSandboxLifecycle { await this.client().deleteFilePath(id, ENV_FILE_DIR, true); } await this.ctx.storage.delete(PROCESS_PORT_ALLOC_KEY); - if (id) await this.syncRuntimeManifestBestEffort(id); return killed; } @@ -317,7 +311,6 @@ export abstract class ProjectSandboxProcesses extends ProjectSandboxLifecycle { await this.ctx.storage.delete(`${PROC_PREFIX}${processId}`); await this.releaseProcessPort(processId); } - if (id) await this.syncRuntimeManifestBestEffort(id); return { processId, status: "killed", success: true }; } @@ -335,7 +328,6 @@ export abstract class ProjectSandboxProcesses extends ProjectSandboxLifecycle { if (isMissingDaytonaProcessError(error)) { await this.ctx.storage.delete(`${PROC_PREFIX}${process.name}`); await this.releaseProcessPort(process.name); - await this.syncRuntimeManifestBestEffort(id); return null; } throw this.toUpstreamError(error, "Sandbox console read failed."); @@ -379,10 +371,8 @@ export abstract class ProjectSandboxProcesses extends ProjectSandboxLifecycle { cmdId: exec.cmdId ?? sessionId, startedAtMs: Date.now(), } satisfies ProcessRecord); - await this.syncRuntimeManifestBestEffort(id); } catch (error) { await this.cleanupLaunchedProcess(id, sessionId, name); - await this.syncRuntimeManifestBestEffort(id); throw error; } } @@ -687,16 +677,6 @@ cd ${shellQuote(cwd)} && ${rawCommand}`; await this.ctx.storage.delete(`${PROC_PREFIX}${name}`); } - private async syncRuntimeManifestBestEffort(id: string): Promise { - const records = await this.ctx.storage.list({ prefix: PROC_PREFIX }); - await writeSandboxRuntimeManifest(this.client(), id, records).catch((error: unknown) => { - createLogger().warn("sandbox_runtime_manifest_sync_failed", { - error, - sandboxId: this.sandboxName(), - }); - }); - } - private async deleteSessionEnvironment(id: string, sessionId: string): Promise { await this.client().deleteFilePath(id, `${ENV_FILE_DIR}/${sessionId}.env`, false); } diff --git a/apps/agent-worker/src/durable-objects/project-sandbox-runtime-manifest.ts b/apps/agent-worker/src/durable-objects/project-sandbox-runtime-manifest.ts deleted file mode 100644 index f42647e8..00000000 --- a/apps/agent-worker/src/durable-objects/project-sandbox-runtime-manifest.ts +++ /dev/null @@ -1,74 +0,0 @@ -import type { DaytonaClient } from "@cheatcode/tools-code"; -import { z } from "zod"; -import { - APP_PREVIEW_SLOT_PREFIX, - PROC_PREFIX, - ProcessRecordSchema, -} from "./project-sandbox-process-support"; - -const RUNTIME_DIRECTORY = "/workspace/.cheatcode"; -const SANDBOX_RUNTIME_MANIFEST_PATH = `${RUNTIME_DIRECTORY}/runtime.json`; - -const RuntimeProjectSchema = z - .object({ - cwd: z.string().min(1), - isMobile: z.boolean(), - port: z.number().int().positive().max(65_535).nullable(), - processId: z.string().min(1), - startupCommands: z.array(z.string().min(1)).max(4), - }) - .strict(); - -const SandboxRuntimeManifestSchema = z - .object({ - generatedAt: z.string().datetime(), - projects: z.record(z.string(), RuntimeProjectSchema), - source: z.literal("durable-object-process-state"), - version: z.literal(1), - }) - .strict(); - -export async function writeSandboxRuntimeManifest( - client: DaytonaClient, - sandboxId: string, - records: Map, -): Promise { - const manifest = buildSandboxRuntimeManifest(records); - await client.createFolder(sandboxId, RUNTIME_DIRECTORY, "0700"); - await client.uploadFile( - sandboxId, - SANDBOX_RUNTIME_MANIFEST_PATH, - new TextEncoder().encode(`${JSON.stringify(manifest, null, 2)}\n`), - ); -} - -function buildSandboxRuntimeManifest( - records: Map, -): z.infer { - const projects: Record> = {}; - for (const [key, value] of [...records.entries()].sort(([left], [right]) => - left.localeCompare(right), - )) { - const processId = key.slice(PROC_PREFIX.length); - if (!key.startsWith(PROC_PREFIX) || !processId.startsWith(APP_PREVIEW_SLOT_PREFIX)) { - continue; - } - const parsed = ProcessRecordSchema.safeParse(value); - if (!parsed.success) continue; - const workspaceSlug = processId.slice(APP_PREVIEW_SLOT_PREFIX.length); - if (!/^[a-z0-9][a-z0-9-]{0,119}$/u.test(workspaceSlug)) continue; - projects[workspaceSlug] = { - cwd: parsed.data.cwd, - isMobile: parsed.data.isMobile ?? false, - port: parsed.data.port ?? null, - processId, - startupCommands: [parsed.data.command], - }; - } - return SandboxRuntimeManifestSchema.parse({ - generatedAt: new Date().toISOString(), - projects, - source: "durable-object-process-state", - version: 1, - }); -} diff --git a/infra/containers/sandbox/README.md b/infra/containers/sandbox/README.md index 7c6b22e2..e6a9cdac 100644 --- a/infra/containers/sandbox/README.md +++ b/infra/containers/sandbox/README.md @@ -154,10 +154,6 @@ is canonical in R2 and mirrored completely to source, schemas, references, templates, and common binary assets; dependency folders, virtual environments, caches, locks, and build output remain sandbox-local. -`/workspace/.cheatcode/runtime.json` is generated from Durable Object-managed -preview process state. It is a human-readable projection only; sandbox code -must never treat it as the lifecycle authority. - Cheatcode does not deploy or synchronize generated user apps. The curated catalog therefore has no deploy skill, deploy runtime, or app-side Composio bridge. Connected-app skills invoke the existing request-scoped Composio tools