Phase 5 of v2.0. External agent dispatch via SSH to host. ACP dispatch (acp-dispatch.ts): spawns agent via SSH with JSON-RPC stdio pipe. Wraps opencode/goose in ACP mode. Captures structured events (file operations, tool calls) mapped to parts taxonomy. Falls back to PTY if ACP handshake fails. PTY dispatch (pty-dispatch.ts): raw SSH spawn for agents without ACP support (claude, pi). Captures stdout/stderr as plain text. Simpler but less structured than ACP. SSH helper (ssh.ts): shared spawn wrapper for SSH commands to samkintop@100.114.205.53 (Tailscale IP, same as booterm). Uses openssh-client installed in the runtime Dockerfile stage. Worktree management (worktrees.ts): createWorktree (git worktree add via SSH), diffWorktree (git diff HEAD...task-branch), cleanupWorktree (git worktree remove --force). One worktree per task at /tmp/booworktrees/<taskId>. Dispatcher updated: checks available_agents.supports_acp to pick transport. Path B flow: create worktree → dispatch agent → diff worktree → queue diff into pending_changes → cleanup worktree → mark task complete. Agent probe updated: probes via SSH to find host-installed agents (which opencode && opencode --version over SSH). Dockerfile: openssh-client added to runtime stage. Config: SSH_HOST env var (default 100.114.205.53). Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
46 lines
1.9 KiB
TypeScript
46 lines
1.9 KiB
TypeScript
import { z } from 'zod';
|
|
|
|
// BooCoder's config is a superset of the server's Config type so it can be
|
|
// passed directly into the inference runner's InferenceContext. Fields the
|
|
// inference loop reads: LLAMA_SWAP_URL, PROJECT_ROOT_WHITELIST. The rest
|
|
// default to values that satisfy the server's Zod schema without BooCoder
|
|
// needing to supply them in its environment.
|
|
const ConfigSchema = z.object({
|
|
NODE_ENV: z.enum(['development', 'production', 'test']).default('development'),
|
|
PORT: z.coerce.number().int().positive().default(3000),
|
|
HOST: z.string().default('0.0.0.0'),
|
|
DATABASE_URL: z.string().url(),
|
|
LLAMA_SWAP_URL: z.string().url(),
|
|
PROJECT_ROOT_WHITELIST: z.string().default('/opt'),
|
|
BOOTSTRAP_ROOT: z.string().default('/opt/projects'),
|
|
DEFAULT_MODEL: z.string().default('qwen3.6-35b-a3b-mxfp4'),
|
|
LOG_LEVEL: z.string().default('info'),
|
|
CONTAINER_GUIDANCE_FILE: z.string().optional(),
|
|
// Fields needed to satisfy the server's Config type but unused by BooCoder:
|
|
SEARXNG_URL: z.string().url().default('http://100.114.205.53:8888'),
|
|
GITEA_BASE_URL: z.string().url().default('https://git.indifferentketchup.com'),
|
|
GITEA_USER: z.string().default('indifferentketchup'),
|
|
GITEA_TOKEN: z.string().optional(),
|
|
GITEA_SSH_HOST: z.string().default('100.114.205.53:2222'),
|
|
MCP_CONFIG_PATH: z.string().optional(),
|
|
// SSH access to the host for external agent dispatch (Phase 5)
|
|
BOOCODER_SSH_HOST: z.string().default('100.114.205.53'),
|
|
BOOCODER_SSH_USER: z.string().default('samkintop'),
|
|
});
|
|
|
|
export type Config = z.infer<typeof ConfigSchema>;
|
|
|
|
let cached: Config | null = null;
|
|
|
|
export function loadConfig(): Config {
|
|
if (cached) return cached;
|
|
const parsed = ConfigSchema.safeParse(process.env);
|
|
if (!parsed.success) {
|
|
console.error('Invalid environment configuration:');
|
|
console.error(parsed.error.flatten().fieldErrors);
|
|
process.exit(1);
|
|
}
|
|
cached = parsed.data;
|
|
return cached;
|
|
}
|