feat(phase-2): Theia container bridge via docker exec

- Dockerfile: install docker-ce-cli, run as root for socket access
- theia-exec.ts: container discovery (env > label > name), theiaExec(),
  syncToTheia() via docker cp
- agent-session-runner: execute_command → docker exec into Theia (fallback to local)
- agent-session-runner: syncToTheia() before auto-commit so "Open in Theia"
  shows agent files immediately after session completes
- server.ts: compute theiaWorkspaceSubdir from giteaRepo slug, log bridge status
  at startup
- custom_docker_run_options already set to mount /var/run/docker.sock

Made-with: Cursor
This commit is contained in:
2026-03-07 13:26:07 -08:00
parent 214e8c1037
commit 7f10009b4f
4 changed files with 201 additions and 8 deletions

View File

@@ -17,6 +17,7 @@ import { createLLM, toOAITools, LLMMessage } from './llm';
import { AgentConfig } from './agents';
import { executeTool, ToolContext } from './tools';
import { resolvePrompt } from './prompts/loader';
import { isTheiaAvailable, theiaExec, syncToTheia, getTheiaContainer } from './theia-exec';
const MAX_TURNS = 60;
@@ -39,6 +40,8 @@ export interface SessionRunOptions {
coolifyAppUuid?: string;
coolifyApiUrl?: string;
coolifyApiToken?: string;
// Theia integration
theiaWorkspaceSubdir?: string; // e.g. "mark_sportsy" — subdir inside /home/node/workspace
}
// ── VIBN DB bridge ────────────────────────────────────────────────────────────
@@ -113,6 +116,17 @@ async function autoCommitAndDeploy(
const giteaToken = process.env.GITEA_API_TOKEN || '';
try {
// Sync files into Theia so "Open in Theia" shows the agent's work
if (isTheiaAvailable() && opts.theiaWorkspaceSubdir) {
await emit({ ts: now(), type: 'info', text: `Syncing files to Theia…` });
const syncResult = await syncToTheia(repoRoot, opts.theiaWorkspaceSubdir);
if (syncResult.ok) {
await emit({ ts: now(), type: 'info', text: '✓ Files available in Theia — open theia.vibnai.com to inspect.' });
} else {
console.warn('[session-runner] Theia sync failed:', syncResult.error);
}
}
try {
execSync('git config user.email "agent@vibnai.com"', gitOpts);
execSync('git config user.name "VIBN Agent"', gitOpts);
@@ -254,7 +268,22 @@ Do NOT run git commit or git push — the platform handles committing after you
let result: unknown;
try {
result = await executeTool(fnName, fnArgs, ctx);
// Route execute_command through Theia when available so npm/node
// commands run inside Theia's persistent dev environment
if (fnName === 'execute_command' && isTheiaAvailable()) {
const command = String(fnArgs.command ?? '');
const subCwd = fnArgs.working_directory
? `${opts.theiaWorkspaceSubdir ?? ''}/${fnArgs.working_directory}`.replace(/\/+/g, '/')
: opts.theiaWorkspaceSubdir ?? undefined;
result = await theiaExec(command, subCwd ? `${process.env.THEIA_WORKSPACE ?? '/home/node/workspace'}/${subCwd}` : undefined);
if ((result as any)?.error && (result as any)?.exitCode !== 0) {
// Fallback to local execution if Theia exec fails
console.warn('[session-runner] Theia exec failed, falling back to local:', (result as any).error);
result = await executeTool(fnName, fnArgs, ctx);
}
} else {
result = await executeTool(fnName, fnArgs, ctx);
}
} catch (err) {
result = { error: err instanceof Error ? err.message : String(err) };
}