Phase 1 of v2.0. BooCoder is live at port 9502 with a health endpoint. - Database renamed: ALTER DATABASE boocode RENAME TO boochat (one-time). All services updated to connect to /boochat. Docker service name stays boocode_db (rename is internal to Postgres, not Docker). - New apps/coder/ app skeleton: Fastify server with health endpoint, postgres connection, schema apply on boot. Mirrors apps/server pattern but minimal (no inference loop yet — Phase 2). - Schema: pending_changes (operation queue before /apply), tasks (dispatch DAG with state machine), available_agents (startup-probed agent registry), human_inbox view (tasks WHERE state IN blocked/failed). All IF NOT EXISTS, idempotent on re-run. Same boochat database, different tables. - Dockerfile: Node 20 bookworm-slim (glibc for future node-pty in Phase 5). Multi-stage build matching the existing boocode image pattern. - docker-compose.yml: boocoder service on 100.114.205.53:9502, /opt:/opt:rw mount (write-capable, policy-gated at tool layer), depends on boocode_db. - BOOCODER.md: container guidance declaring write-tool capability + pending-changes discipline. All 4 services boot and pass health checks. 9 tables in the shared DB. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
46 lines
1.1 KiB
TypeScript
46 lines
1.1 KiB
TypeScript
import postgres from 'postgres';
|
|
import { readFile } from 'node:fs/promises';
|
|
import { fileURLToPath } from 'node:url';
|
|
import { dirname, resolve } from 'node:path';
|
|
import type { Config } from './config.js';
|
|
|
|
const __filename = fileURLToPath(import.meta.url);
|
|
const __dirname = dirname(__filename);
|
|
|
|
export type Sql = ReturnType<typeof postgres>;
|
|
|
|
let sqlInstance: Sql | null = null;
|
|
|
|
export function getSql(config: Config): Sql {
|
|
if (sqlInstance) return sqlInstance;
|
|
sqlInstance = postgres(config.DATABASE_URL, {
|
|
max: 10,
|
|
idle_timeout: 30,
|
|
connect_timeout: 10,
|
|
onnotice: () => {},
|
|
});
|
|
return sqlInstance;
|
|
}
|
|
|
|
export async function applySchema(sql: Sql): Promise<void> {
|
|
const schemaPath = resolve(__dirname, 'schema.sql');
|
|
const ddl = await readFile(schemaPath, 'utf8');
|
|
await sql.unsafe(ddl);
|
|
}
|
|
|
|
export async function pingDb(sql: Sql): Promise<boolean> {
|
|
try {
|
|
await sql`SELECT 1`;
|
|
return true;
|
|
} catch {
|
|
return false;
|
|
}
|
|
}
|
|
|
|
export async function closeDb(): Promise<void> {
|
|
if (sqlInstance) {
|
|
await sqlInstance.end({ timeout: 5 });
|
|
sqlInstance = null;
|
|
}
|
|
}
|