Phase 2: single per-user box container for every thread
Every thread (agent turns + terminal + project commands) now execs into one
persistent per-user container (spoon-box-{username}) instead of ephemeral
docker run --rm — so the agent and terminal share the exact same running
environment, filesystem, and in-session installs.
- docker.ts: ensureUserContainer (persistent box) + streamExecInContainer/
runExecInContainer (docker exec, streaming) sharing a factored streamSubprocess
- user-container.ts: reference-counted box lifecycle (held while any thread
workspace is active or a terminal is connected; idle-reaped after
SPOON_AGENT_BOX_IDLE_MS, default 30m)
- worker.ts: runClaim acquires the box; codex turn + runProjectCommand exec into
it; release on stop/PR/failure
- terminal.ts: execs into the shared box (dockerode TTY) instead of a per-job
container; materializeUserHome runs the dotfiles setup in the box
- Verified: agent + terminal run in the same box, share fs, dotfiles + tmux load
This commit is contained in:
@@ -7,7 +7,7 @@ import type { Id } from '@spoon/backend/convex/_generated/dataModel.js';
|
||||
import { api } from '@spoon/backend/convex/_generated/api.js';
|
||||
|
||||
import { env } from './env';
|
||||
import { runInJobContainer } from './runtime/docker';
|
||||
import { runExecInContainer } from './runtime/docker';
|
||||
|
||||
const client = new ConvexHttpClient(env.convexUrl);
|
||||
|
||||
@@ -51,10 +51,11 @@ const safeHomeJoin = (homeDir: string, relPath: string) => {
|
||||
export const materializeUserHome = async (args: {
|
||||
homeDir: string;
|
||||
containerHome: string;
|
||||
boxName: string;
|
||||
userEnv: UserEnvironment;
|
||||
redact: (value: string) => string;
|
||||
}): Promise<void> => {
|
||||
const { homeDir, containerHome, userEnv, redact } = args;
|
||||
const { homeDir, containerHome, boxName, userEnv, redact } = args;
|
||||
await mkdir(homeDir, { recursive: true });
|
||||
|
||||
// A mounted home has no /etc/skel, so ensure login shells source ~/.bashrc.
|
||||
@@ -95,11 +96,10 @@ export const materializeUserHome = async (args: {
|
||||
]
|
||||
.filter(Boolean)
|
||||
.join('\n');
|
||||
await runInJobContainer({
|
||||
workdir: homeDir,
|
||||
containerHome,
|
||||
containerCwd: containerHome,
|
||||
await runExecInContainer({
|
||||
containerName: boxName,
|
||||
command: ['bash', '-lc', script],
|
||||
containerCwd: containerHome,
|
||||
environment: { HOME: containerHome },
|
||||
redact,
|
||||
timeoutMs: env.jobTimeoutMs,
|
||||
|
||||
Reference in New Issue
Block a user