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

@@ -13,6 +13,7 @@ import { PROTECTED_GITEA_REPOS } from './tools/security';
import { orchestratorChat, listSessions, clearSession } from './orchestrator';
import { atlasChat, listAtlasSessions, clearAtlasSession } from './atlas';
import { LLMMessage, createLLM } from './llm';
import { getTheiaContainer } from './theia-exec';
const app = express();
app.use(cors());
@@ -433,6 +434,13 @@ app.post('/agent/execute', async (req: Request, res: Response) => {
? `Original task: ${task}\n\nFollow-up instruction: ${continueTask}`
: task!;
// Derive the Theia workspace subdir from the giteaRepo slug
// e.g. "mark/sportsy" → "mark_sportsy", then append appPath
// So files land at /home/node/workspace/mark_sportsy/apps/admin inside Theia
const theiaWorkspaceSubdir = giteaRepo
? giteaRepo.replace('/', '_')
: undefined;
// Run the streaming agent loop (fire and forget)
runSessionAgent(agentConfig, effectiveTask, ctx, {
sessionId,
@@ -446,6 +454,7 @@ app.post('/agent/execute', async (req: Request, res: Response) => {
coolifyAppUuid,
coolifyApiUrl: process.env.COOLIFY_API_URL,
coolifyApiToken: process.env.COOLIFY_API_TOKEN,
theiaWorkspaceSubdir,
})
.catch(err => {
const msg = err instanceof Error ? err.message : String(err);
@@ -604,4 +613,11 @@ app.listen(PORT, () => {
if (!process.env.GOOGLE_API_KEY) {
console.warn('WARNING: GOOGLE_API_KEY is not set — agents will fail');
}
// Theia bridge status
const theiaContainer = getTheiaContainer();
if (theiaContainer) {
console.log(`Theia bridge: active (container: ${theiaContainer})`);
} else {
console.warn('Theia bridge: not available — docker socket not mounted or container not found. Commands will run locally.');
}
});