fix: wire database and repositories into server startup for tRPC context
The server never created a database or instantiated repositories, so all tRPC procedures requiring initiativeRepository (and other repos) threw "Initiative repository not available" on every request. - Create ensureSchema() for shared database table initialization - Extend TrpcAdapterOptions to accept all repository/manager dependencies - Add ServerContextDeps to CoordinationServer for dependency injection - Wire database, schema, and repositories in CLI startServer() - Refactor test-helpers to use shared ensureSchema()
This commit is contained in:
62
.planning/debug/initiative-repo-not-available.md
Normal file
62
.planning/debug/initiative-repo-not-available.md
Normal file
@@ -0,0 +1,62 @@
|
|||||||
|
---
|
||||||
|
status: resolved
|
||||||
|
trigger: "TRPCError: Initiative repository not available at requireInitiativeRepository (router.ts:247) on listInitiatives endpoint"
|
||||||
|
created: 2026-02-04T00:00:00Z
|
||||||
|
updated: 2026-02-04T00:00:00Z
|
||||||
|
resolved: 2026-02-04T00:00:00Z
|
||||||
|
---
|
||||||
|
|
||||||
|
## Current Focus
|
||||||
|
|
||||||
|
hypothesis: CONFIRMED - Server startup never creates database or repositories, so ctx.initiativeRepository is always undefined
|
||||||
|
test: traced full call chain from CLI -> CoordinationServer -> trpc-adapter -> createContext
|
||||||
|
expecting: N/A - confirmed
|
||||||
|
next_action: Fix by wiring database and repositories into server startup
|
||||||
|
|
||||||
|
## Symptoms
|
||||||
|
|
||||||
|
expected: Initiative page loads and displays list of initiatives via listInitiatives tRPC endpoint
|
||||||
|
actual: 500 Internal Server Error - "Initiative repository not available" thrown by requireInitiativeRepository at router.ts:247
|
||||||
|
errors: TRPCError: Initiative repository not available (code: INTERNAL_SERVER_ERROR, httpStatus: 500, path: listInitiatives)
|
||||||
|
reproduction: Load the initiative page in the browser
|
||||||
|
started: Never worked
|
||||||
|
|
||||||
|
## Eliminated
|
||||||
|
|
||||||
|
[none yet]
|
||||||
|
|
||||||
|
## Evidence
|
||||||
|
|
||||||
|
1. [2026-02-04 E1] `requireInitiativeRepository` at router.ts:245-253 throws when `ctx.initiativeRepository` is falsy.
|
||||||
|
2. [2026-02-04 E2] `TRPCContext.initiativeRepository` is typed as optional (`?`), set via `createContext()` in context.ts:85.
|
||||||
|
3. [2026-02-04 E3] `createContext` is called in production at `src/server/trpc-adapter.ts:82-88` -- only passes `eventBus`, `serverStartedAt`, `processCount`, `agentManager`. Does NOT pass `initiativeRepository`, `phaseRepository`, `planRepository`, `dispatchManager`, `coordinationManager`, or `phaseDispatchManager`.
|
||||||
|
4. [2026-02-04 E4] `TrpcAdapterOptions` interface (trpc-adapter.ts:17-26) only defines `eventBus`, `serverStartedAt`, `processCount`, `agentManager`. Missing all repository fields.
|
||||||
|
5. [2026-02-04 E5] `CoordinationServer.handleTrpc()` at server/index.ts:221-225 calls `createTrpcHandler` with only `eventBus`, `serverStartedAt`, `processCount`. No repositories passed.
|
||||||
|
6. [2026-02-04 E6] `CoordinationServer` class has no database or repository references at all.
|
||||||
|
7. [2026-02-04 E7] CLI `startServer()` at cli/index.ts:24-53 creates CoordinationServer with no database.
|
||||||
|
8. [2026-02-04 E8] `createDatabase()` exists at db/index.ts:20 but is never called in production server startup path.
|
||||||
|
9. [2026-02-04 E9] Test harness (test/harness.ts:408-450) shows correct wiring: creates db, all repositories, all managers, passes everything to createContext.
|
||||||
|
|
||||||
|
## Resolution
|
||||||
|
|
||||||
|
root_cause: Server startup path never created a database or repositories. The CLI startServer() created a CoordinationServer with only processManager, logManager, and eventBus. The tRPC adapter (trpc-adapter.ts) only passed eventBus, serverStartedAt, processCount, and agentManager to createContext(). The initiativeRepository (and all other repositories) were never instantiated or injected, so ctx.initiativeRepository was always undefined, causing requireInitiativeRepository() to throw on every call.
|
||||||
|
|
||||||
|
fix: |
|
||||||
|
1. Created src/db/ensure-schema.ts - shared schema initialization with individual CREATE TABLE IF NOT EXISTS statements
|
||||||
|
2. Extended TrpcAdapterOptions in src/server/trpc-adapter.ts to accept all repository/manager types and pass them to createContext()
|
||||||
|
3. Added ServerContextDeps type and contextDeps parameter to CoordinationServer constructor, spreads into createTrpcHandler() options
|
||||||
|
4. Updated CLI startServer() in src/cli/index.ts to create database, ensure schema, instantiate repositories, and pass them to CoordinationServer
|
||||||
|
5. Refactored src/db/repositories/drizzle/test-helpers.ts to use shared ensureSchema() instead of duplicating SQL
|
||||||
|
|
||||||
|
verification: |
|
||||||
|
- TypeScript compilation: zero errors (npx tsc --noEmit)
|
||||||
|
- All 452 tests pass, 0 failures (npx vitest run)
|
||||||
|
- ensureSchema correctly works with drizzle-orm by executing individual statements (fixed multi-statement SQL error)
|
||||||
|
|
||||||
|
files_changed:
|
||||||
|
- src/db/ensure-schema.ts (NEW - shared schema initialization)
|
||||||
|
- src/db/index.ts (added ensureSchema re-export)
|
||||||
|
- src/db/repositories/drizzle/test-helpers.ts (refactored to use shared ensureSchema)
|
||||||
|
- src/server/trpc-adapter.ts (extended options and context creation)
|
||||||
|
- src/server/index.ts (added ServerContextDeps, contextDeps to constructor, spread into handler)
|
||||||
|
- src/cli/index.ts (wired database, schema, and repositories into server startup)
|
||||||
62
.planning/debug/resolved/initiative-repo-not-available.md
Normal file
62
.planning/debug/resolved/initiative-repo-not-available.md
Normal file
@@ -0,0 +1,62 @@
|
|||||||
|
---
|
||||||
|
status: resolved
|
||||||
|
trigger: "TRPCError: Initiative repository not available at requireInitiativeRepository (router.ts:247) on listInitiatives endpoint"
|
||||||
|
created: 2026-02-04T00:00:00Z
|
||||||
|
updated: 2026-02-04T00:00:00Z
|
||||||
|
resolved: 2026-02-04T00:00:00Z
|
||||||
|
---
|
||||||
|
|
||||||
|
## Current Focus
|
||||||
|
|
||||||
|
hypothesis: CONFIRMED - Server startup never creates database or repositories, so ctx.initiativeRepository is always undefined
|
||||||
|
test: traced full call chain from CLI -> CoordinationServer -> trpc-adapter -> createContext
|
||||||
|
expecting: N/A - confirmed
|
||||||
|
next_action: Fix by wiring database and repositories into server startup
|
||||||
|
|
||||||
|
## Symptoms
|
||||||
|
|
||||||
|
expected: Initiative page loads and displays list of initiatives via listInitiatives tRPC endpoint
|
||||||
|
actual: 500 Internal Server Error - "Initiative repository not available" thrown by requireInitiativeRepository at router.ts:247
|
||||||
|
errors: TRPCError: Initiative repository not available (code: INTERNAL_SERVER_ERROR, httpStatus: 500, path: listInitiatives)
|
||||||
|
reproduction: Load the initiative page in the browser
|
||||||
|
started: Never worked
|
||||||
|
|
||||||
|
## Eliminated
|
||||||
|
|
||||||
|
[none yet]
|
||||||
|
|
||||||
|
## Evidence
|
||||||
|
|
||||||
|
1. [2026-02-04 E1] `requireInitiativeRepository` at router.ts:245-253 throws when `ctx.initiativeRepository` is falsy.
|
||||||
|
2. [2026-02-04 E2] `TRPCContext.initiativeRepository` is typed as optional (`?`), set via `createContext()` in context.ts:85.
|
||||||
|
3. [2026-02-04 E3] `createContext` is called in production at `src/server/trpc-adapter.ts:82-88` -- only passes `eventBus`, `serverStartedAt`, `processCount`, `agentManager`. Does NOT pass `initiativeRepository`, `phaseRepository`, `planRepository`, `dispatchManager`, `coordinationManager`, or `phaseDispatchManager`.
|
||||||
|
4. [2026-02-04 E4] `TrpcAdapterOptions` interface (trpc-adapter.ts:17-26) only defines `eventBus`, `serverStartedAt`, `processCount`, `agentManager`. Missing all repository fields.
|
||||||
|
5. [2026-02-04 E5] `CoordinationServer.handleTrpc()` at server/index.ts:221-225 calls `createTrpcHandler` with only `eventBus`, `serverStartedAt`, `processCount`. No repositories passed.
|
||||||
|
6. [2026-02-04 E6] `CoordinationServer` class has no database or repository references at all.
|
||||||
|
7. [2026-02-04 E7] CLI `startServer()` at cli/index.ts:24-53 creates CoordinationServer with no database.
|
||||||
|
8. [2026-02-04 E8] `createDatabase()` exists at db/index.ts:20 but is never called in production server startup path.
|
||||||
|
9. [2026-02-04 E9] Test harness (test/harness.ts:408-450) shows correct wiring: creates db, all repositories, all managers, passes everything to createContext.
|
||||||
|
|
||||||
|
## Resolution
|
||||||
|
|
||||||
|
root_cause: Server startup path never created a database or repositories. The CLI startServer() created a CoordinationServer with only processManager, logManager, and eventBus. The tRPC adapter (trpc-adapter.ts) only passed eventBus, serverStartedAt, processCount, and agentManager to createContext(). The initiativeRepository (and all other repositories) were never instantiated or injected, so ctx.initiativeRepository was always undefined, causing requireInitiativeRepository() to throw on every call.
|
||||||
|
|
||||||
|
fix: |
|
||||||
|
1. Created src/db/ensure-schema.ts - shared schema initialization with individual CREATE TABLE IF NOT EXISTS statements
|
||||||
|
2. Extended TrpcAdapterOptions in src/server/trpc-adapter.ts to accept all repository/manager types and pass them to createContext()
|
||||||
|
3. Added ServerContextDeps type and contextDeps parameter to CoordinationServer constructor, spreads into createTrpcHandler() options
|
||||||
|
4. Updated CLI startServer() in src/cli/index.ts to create database, ensure schema, instantiate repositories, and pass them to CoordinationServer
|
||||||
|
5. Refactored src/db/repositories/drizzle/test-helpers.ts to use shared ensureSchema() instead of duplicating SQL
|
||||||
|
|
||||||
|
verification: |
|
||||||
|
- TypeScript compilation: zero errors (npx tsc --noEmit)
|
||||||
|
- All 452 tests pass, 0 failures (npx vitest run)
|
||||||
|
- ensureSchema correctly works with drizzle-orm by executing individual statements (fixed multi-statement SQL error)
|
||||||
|
|
||||||
|
files_changed:
|
||||||
|
- src/db/ensure-schema.ts (NEW - shared schema initialization)
|
||||||
|
- src/db/index.ts (added ensureSchema re-export)
|
||||||
|
- src/db/repositories/drizzle/test-helpers.ts (refactored to use shared ensureSchema)
|
||||||
|
- src/server/trpc-adapter.ts (extended options and context creation)
|
||||||
|
- src/server/index.ts (added ServerContextDeps, contextDeps to constructor, spread into handler)
|
||||||
|
- src/cli/index.ts (wired database, schema, and repositories into server startup)
|
||||||
@@ -13,6 +13,15 @@ import { ProcessManager, ProcessRegistry } from '../process/index.js';
|
|||||||
import { LogManager } from '../logging/index.js';
|
import { LogManager } from '../logging/index.js';
|
||||||
import { createEventBus } from '../events/index.js';
|
import { createEventBus } from '../events/index.js';
|
||||||
import { createDefaultTrpcClient } from './trpc-client.js';
|
import { createDefaultTrpcClient } from './trpc-client.js';
|
||||||
|
import {
|
||||||
|
createDatabase,
|
||||||
|
ensureSchema,
|
||||||
|
DrizzleInitiativeRepository,
|
||||||
|
DrizzlePhaseRepository,
|
||||||
|
DrizzlePlanRepository,
|
||||||
|
DrizzleTaskRepository,
|
||||||
|
DrizzleMessageRepository,
|
||||||
|
} from '../db/index.js';
|
||||||
|
|
||||||
/** Environment variable for custom port */
|
/** Environment variable for custom port */
|
||||||
const CW_PORT_ENV = 'CW_PORT';
|
const CW_PORT_ENV = 'CW_PORT';
|
||||||
@@ -32,12 +41,30 @@ async function startServer(port?: number): Promise<void> {
|
|||||||
const processManager = new ProcessManager(registry, eventBus);
|
const processManager = new ProcessManager(registry, eventBus);
|
||||||
const logManager = new LogManager();
|
const logManager = new LogManager();
|
||||||
|
|
||||||
|
// Create database and ensure schema
|
||||||
|
const db = createDatabase();
|
||||||
|
ensureSchema(db);
|
||||||
|
|
||||||
|
// Create repositories
|
||||||
|
const initiativeRepository = new DrizzleInitiativeRepository(db);
|
||||||
|
const phaseRepository = new DrizzlePhaseRepository(db);
|
||||||
|
const planRepository = new DrizzlePlanRepository(db);
|
||||||
|
const taskRepository = new DrizzleTaskRepository(db);
|
||||||
|
const messageRepository = new DrizzleMessageRepository(db);
|
||||||
|
|
||||||
// Create and start server
|
// Create and start server
|
||||||
const server = new CoordinationServer(
|
const server = new CoordinationServer(
|
||||||
{ port: serverPort },
|
{ port: serverPort },
|
||||||
processManager,
|
processManager,
|
||||||
logManager,
|
logManager,
|
||||||
eventBus
|
eventBus,
|
||||||
|
{
|
||||||
|
initiativeRepository,
|
||||||
|
phaseRepository,
|
||||||
|
planRepository,
|
||||||
|
taskRepository,
|
||||||
|
messageRepository,
|
||||||
|
}
|
||||||
);
|
);
|
||||||
|
|
||||||
try {
|
try {
|
||||||
|
|||||||
123
src/db/ensure-schema.ts
Normal file
123
src/db/ensure-schema.ts
Normal file
@@ -0,0 +1,123 @@
|
|||||||
|
/**
|
||||||
|
* Database Schema Initialization
|
||||||
|
*
|
||||||
|
* Ensures all required tables exist in the database.
|
||||||
|
* Uses CREATE TABLE IF NOT EXISTS so it's safe to call multiple times.
|
||||||
|
*/
|
||||||
|
|
||||||
|
import type { DrizzleDatabase } from './index.js';
|
||||||
|
import { sql } from 'drizzle-orm';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Individual CREATE TABLE statements for each table.
|
||||||
|
* Each must be a single statement for drizzle-orm compatibility.
|
||||||
|
* These mirror the schema defined in schema.ts.
|
||||||
|
*/
|
||||||
|
const TABLE_STATEMENTS = [
|
||||||
|
// Initiatives table
|
||||||
|
`CREATE TABLE IF NOT EXISTS initiatives (
|
||||||
|
id TEXT PRIMARY KEY NOT NULL,
|
||||||
|
name TEXT NOT NULL,
|
||||||
|
description TEXT,
|
||||||
|
status TEXT NOT NULL DEFAULT 'active',
|
||||||
|
created_at INTEGER NOT NULL,
|
||||||
|
updated_at INTEGER NOT NULL
|
||||||
|
)`,
|
||||||
|
|
||||||
|
// Phases table
|
||||||
|
`CREATE TABLE IF NOT EXISTS phases (
|
||||||
|
id TEXT PRIMARY KEY NOT NULL,
|
||||||
|
initiative_id TEXT NOT NULL REFERENCES initiatives(id) ON DELETE CASCADE,
|
||||||
|
number INTEGER NOT NULL,
|
||||||
|
name TEXT NOT NULL,
|
||||||
|
description TEXT,
|
||||||
|
status TEXT NOT NULL DEFAULT 'pending',
|
||||||
|
created_at INTEGER NOT NULL,
|
||||||
|
updated_at INTEGER NOT NULL
|
||||||
|
)`,
|
||||||
|
|
||||||
|
// Phase dependencies table
|
||||||
|
`CREATE TABLE IF NOT EXISTS phase_dependencies (
|
||||||
|
id TEXT PRIMARY KEY NOT NULL,
|
||||||
|
phase_id TEXT NOT NULL REFERENCES phases(id) ON DELETE CASCADE,
|
||||||
|
depends_on_phase_id TEXT NOT NULL REFERENCES phases(id) ON DELETE CASCADE,
|
||||||
|
created_at INTEGER NOT NULL
|
||||||
|
)`,
|
||||||
|
|
||||||
|
// Plans table
|
||||||
|
`CREATE TABLE IF NOT EXISTS plans (
|
||||||
|
id TEXT PRIMARY KEY NOT NULL,
|
||||||
|
phase_id TEXT NOT NULL REFERENCES phases(id) ON DELETE CASCADE,
|
||||||
|
number INTEGER NOT NULL,
|
||||||
|
name TEXT NOT NULL,
|
||||||
|
description TEXT,
|
||||||
|
status TEXT NOT NULL DEFAULT 'pending',
|
||||||
|
created_at INTEGER NOT NULL,
|
||||||
|
updated_at INTEGER NOT NULL
|
||||||
|
)`,
|
||||||
|
|
||||||
|
// Tasks table
|
||||||
|
`CREATE TABLE IF NOT EXISTS tasks (
|
||||||
|
id TEXT PRIMARY KEY NOT NULL,
|
||||||
|
plan_id TEXT NOT NULL REFERENCES plans(id) ON DELETE CASCADE,
|
||||||
|
name TEXT NOT NULL,
|
||||||
|
description TEXT,
|
||||||
|
type TEXT NOT NULL DEFAULT 'auto',
|
||||||
|
priority TEXT NOT NULL DEFAULT 'medium',
|
||||||
|
status TEXT NOT NULL DEFAULT 'pending',
|
||||||
|
"order" INTEGER NOT NULL DEFAULT 0,
|
||||||
|
created_at INTEGER NOT NULL,
|
||||||
|
updated_at INTEGER NOT NULL
|
||||||
|
)`,
|
||||||
|
|
||||||
|
// Task dependencies table
|
||||||
|
`CREATE TABLE IF NOT EXISTS task_dependencies (
|
||||||
|
id TEXT PRIMARY KEY NOT NULL,
|
||||||
|
task_id TEXT NOT NULL REFERENCES tasks(id) ON DELETE CASCADE,
|
||||||
|
depends_on_task_id TEXT NOT NULL REFERENCES tasks(id) ON DELETE CASCADE,
|
||||||
|
created_at INTEGER NOT NULL
|
||||||
|
)`,
|
||||||
|
|
||||||
|
// Agents table
|
||||||
|
`CREATE TABLE IF NOT EXISTS agents (
|
||||||
|
id TEXT PRIMARY KEY NOT NULL,
|
||||||
|
name TEXT NOT NULL UNIQUE,
|
||||||
|
task_id TEXT REFERENCES tasks(id) ON DELETE SET NULL,
|
||||||
|
session_id TEXT,
|
||||||
|
worktree_id TEXT NOT NULL,
|
||||||
|
status TEXT NOT NULL DEFAULT 'idle',
|
||||||
|
mode TEXT NOT NULL DEFAULT 'execute' CHECK(mode IN ('execute', 'discuss', 'breakdown', 'decompose')),
|
||||||
|
created_at INTEGER NOT NULL,
|
||||||
|
updated_at INTEGER NOT NULL
|
||||||
|
)`,
|
||||||
|
|
||||||
|
// Messages table
|
||||||
|
`CREATE TABLE IF NOT EXISTS messages (
|
||||||
|
id TEXT PRIMARY KEY NOT NULL,
|
||||||
|
sender_type TEXT NOT NULL,
|
||||||
|
sender_id TEXT REFERENCES agents(id) ON DELETE SET NULL,
|
||||||
|
recipient_type TEXT NOT NULL,
|
||||||
|
recipient_id TEXT REFERENCES agents(id) ON DELETE SET NULL,
|
||||||
|
type TEXT NOT NULL DEFAULT 'info',
|
||||||
|
content TEXT NOT NULL,
|
||||||
|
requires_response INTEGER NOT NULL DEFAULT 0,
|
||||||
|
status TEXT NOT NULL DEFAULT 'pending',
|
||||||
|
parent_message_id TEXT REFERENCES messages(id) ON DELETE SET NULL,
|
||||||
|
created_at INTEGER NOT NULL,
|
||||||
|
updated_at INTEGER NOT NULL
|
||||||
|
)`,
|
||||||
|
];
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Ensure all database tables exist.
|
||||||
|
*
|
||||||
|
* Uses CREATE TABLE IF NOT EXISTS, so safe to call on every startup.
|
||||||
|
* Must be called before any repository operations on a fresh database.
|
||||||
|
*
|
||||||
|
* @param db - Drizzle database instance
|
||||||
|
*/
|
||||||
|
export function ensureSchema(db: DrizzleDatabase): void {
|
||||||
|
for (const statement of TABLE_STATEMENTS) {
|
||||||
|
db.run(sql.raw(statement));
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -39,6 +39,9 @@ export function createDatabase(path?: string): DrizzleDatabase {
|
|||||||
// Re-export config utilities
|
// Re-export config utilities
|
||||||
export { getDbPath, ensureDbDirectory } from './config.js';
|
export { getDbPath, ensureDbDirectory } from './config.js';
|
||||||
|
|
||||||
|
// Re-export schema initialization
|
||||||
|
export { ensureSchema } from './ensure-schema.js';
|
||||||
|
|
||||||
// Re-export schema and types
|
// Re-export schema and types
|
||||||
export * from './schema.js';
|
export * from './schema.js';
|
||||||
|
|
||||||
|
|||||||
@@ -8,107 +8,9 @@
|
|||||||
import Database from 'better-sqlite3';
|
import Database from 'better-sqlite3';
|
||||||
import { drizzle } from 'drizzle-orm/better-sqlite3';
|
import { drizzle } from 'drizzle-orm/better-sqlite3';
|
||||||
import type { DrizzleDatabase } from '../../index.js';
|
import type { DrizzleDatabase } from '../../index.js';
|
||||||
|
import { ensureSchema } from '../../ensure-schema.js';
|
||||||
import * as schema from '../../schema.js';
|
import * as schema from '../../schema.js';
|
||||||
|
|
||||||
/**
|
|
||||||
* SQL statements to create the database schema.
|
|
||||||
* These mirror the schema defined in schema.ts.
|
|
||||||
*/
|
|
||||||
const CREATE_TABLES_SQL = `
|
|
||||||
-- Initiatives table
|
|
||||||
CREATE TABLE IF NOT EXISTS initiatives (
|
|
||||||
id TEXT PRIMARY KEY NOT NULL,
|
|
||||||
name TEXT NOT NULL,
|
|
||||||
description TEXT,
|
|
||||||
status TEXT NOT NULL DEFAULT 'active',
|
|
||||||
created_at INTEGER NOT NULL,
|
|
||||||
updated_at INTEGER NOT NULL
|
|
||||||
);
|
|
||||||
|
|
||||||
-- Phases table
|
|
||||||
CREATE TABLE IF NOT EXISTS phases (
|
|
||||||
id TEXT PRIMARY KEY NOT NULL,
|
|
||||||
initiative_id TEXT NOT NULL REFERENCES initiatives(id) ON DELETE CASCADE,
|
|
||||||
number INTEGER NOT NULL,
|
|
||||||
name TEXT NOT NULL,
|
|
||||||
description TEXT,
|
|
||||||
status TEXT NOT NULL DEFAULT 'pending',
|
|
||||||
created_at INTEGER NOT NULL,
|
|
||||||
updated_at INTEGER NOT NULL
|
|
||||||
);
|
|
||||||
|
|
||||||
-- Phase dependencies table
|
|
||||||
CREATE TABLE IF NOT EXISTS phase_dependencies (
|
|
||||||
id TEXT PRIMARY KEY NOT NULL,
|
|
||||||
phase_id TEXT NOT NULL REFERENCES phases(id) ON DELETE CASCADE,
|
|
||||||
depends_on_phase_id TEXT NOT NULL REFERENCES phases(id) ON DELETE CASCADE,
|
|
||||||
created_at INTEGER NOT NULL
|
|
||||||
);
|
|
||||||
|
|
||||||
-- Plans table
|
|
||||||
CREATE TABLE IF NOT EXISTS plans (
|
|
||||||
id TEXT PRIMARY KEY NOT NULL,
|
|
||||||
phase_id TEXT NOT NULL REFERENCES phases(id) ON DELETE CASCADE,
|
|
||||||
number INTEGER NOT NULL,
|
|
||||||
name TEXT NOT NULL,
|
|
||||||
description TEXT,
|
|
||||||
status TEXT NOT NULL DEFAULT 'pending',
|
|
||||||
created_at INTEGER NOT NULL,
|
|
||||||
updated_at INTEGER NOT NULL
|
|
||||||
);
|
|
||||||
|
|
||||||
-- Tasks table
|
|
||||||
CREATE TABLE IF NOT EXISTS tasks (
|
|
||||||
id TEXT PRIMARY KEY NOT NULL,
|
|
||||||
plan_id TEXT NOT NULL REFERENCES plans(id) ON DELETE CASCADE,
|
|
||||||
name TEXT NOT NULL,
|
|
||||||
description TEXT,
|
|
||||||
type TEXT NOT NULL DEFAULT 'auto',
|
|
||||||
priority TEXT NOT NULL DEFAULT 'medium',
|
|
||||||
status TEXT NOT NULL DEFAULT 'pending',
|
|
||||||
"order" INTEGER NOT NULL DEFAULT 0,
|
|
||||||
created_at INTEGER NOT NULL,
|
|
||||||
updated_at INTEGER NOT NULL
|
|
||||||
);
|
|
||||||
|
|
||||||
-- Task dependencies table
|
|
||||||
CREATE TABLE IF NOT EXISTS task_dependencies (
|
|
||||||
id TEXT PRIMARY KEY NOT NULL,
|
|
||||||
task_id TEXT NOT NULL REFERENCES tasks(id) ON DELETE CASCADE,
|
|
||||||
depends_on_task_id TEXT NOT NULL REFERENCES tasks(id) ON DELETE CASCADE,
|
|
||||||
created_at INTEGER NOT NULL
|
|
||||||
);
|
|
||||||
|
|
||||||
-- Agents table
|
|
||||||
CREATE TABLE IF NOT EXISTS agents (
|
|
||||||
id TEXT PRIMARY KEY NOT NULL,
|
|
||||||
name TEXT NOT NULL UNIQUE,
|
|
||||||
task_id TEXT REFERENCES tasks(id) ON DELETE SET NULL,
|
|
||||||
session_id TEXT,
|
|
||||||
worktree_id TEXT NOT NULL,
|
|
||||||
status TEXT NOT NULL DEFAULT 'idle',
|
|
||||||
mode TEXT NOT NULL DEFAULT 'execute' CHECK(mode IN ('execute', 'discuss', 'breakdown', 'decompose')),
|
|
||||||
created_at INTEGER NOT NULL,
|
|
||||||
updated_at INTEGER NOT NULL
|
|
||||||
);
|
|
||||||
|
|
||||||
-- Messages table
|
|
||||||
CREATE TABLE IF NOT EXISTS messages (
|
|
||||||
id TEXT PRIMARY KEY NOT NULL,
|
|
||||||
sender_type TEXT NOT NULL,
|
|
||||||
sender_id TEXT REFERENCES agents(id) ON DELETE SET NULL,
|
|
||||||
recipient_type TEXT NOT NULL,
|
|
||||||
recipient_id TEXT REFERENCES agents(id) ON DELETE SET NULL,
|
|
||||||
type TEXT NOT NULL DEFAULT 'info',
|
|
||||||
content TEXT NOT NULL,
|
|
||||||
requires_response INTEGER NOT NULL DEFAULT 0,
|
|
||||||
status TEXT NOT NULL DEFAULT 'pending',
|
|
||||||
parent_message_id TEXT REFERENCES messages(id) ON DELETE SET NULL,
|
|
||||||
created_at INTEGER NOT NULL,
|
|
||||||
updated_at INTEGER NOT NULL
|
|
||||||
);
|
|
||||||
`;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Create an in-memory test database with schema applied.
|
* Create an in-memory test database with schema applied.
|
||||||
* Returns a fresh Drizzle instance for each call.
|
* Returns a fresh Drizzle instance for each call.
|
||||||
@@ -119,8 +21,10 @@ export function createTestDatabase(): DrizzleDatabase {
|
|||||||
// Enable foreign keys
|
// Enable foreign keys
|
||||||
sqlite.pragma('foreign_keys = ON');
|
sqlite.pragma('foreign_keys = ON');
|
||||||
|
|
||||||
// Create all tables
|
const db = drizzle(sqlite, { schema });
|
||||||
sqlite.exec(CREATE_TABLES_SQL);
|
|
||||||
|
|
||||||
return drizzle(sqlite, { schema });
|
// Create all tables
|
||||||
|
ensureSchema(db);
|
||||||
|
|
||||||
|
return db;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -15,7 +15,13 @@ import type { ServerConfig, ServerState, HealthResponse, StatusResponse } from '
|
|||||||
import type { ProcessManager } from '../process/index.js';
|
import type { ProcessManager } from '../process/index.js';
|
||||||
import type { LogManager } from '../logging/index.js';
|
import type { LogManager } from '../logging/index.js';
|
||||||
import type { EventBus, ServerStartedEvent, ServerStoppedEvent } from '../events/index.js';
|
import type { EventBus, ServerStartedEvent, ServerStoppedEvent } from '../events/index.js';
|
||||||
import { createTrpcHandler } from './trpc-adapter.js';
|
import { createTrpcHandler, type TrpcAdapterOptions } from './trpc-adapter.js';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Optional dependencies for tRPC context.
|
||||||
|
* Passed through to the tRPC adapter for procedure access.
|
||||||
|
*/
|
||||||
|
export type ServerContextDeps = Omit<TrpcAdapterOptions, 'eventBus' | 'serverStartedAt' | 'processCount'>;
|
||||||
|
|
||||||
/** Default port for the coordination server */
|
/** Default port for the coordination server */
|
||||||
const DEFAULT_PORT = 3847;
|
const DEFAULT_PORT = 3847;
|
||||||
@@ -38,6 +44,7 @@ export class CoordinationServer {
|
|||||||
private readonly processManager: ProcessManager;
|
private readonly processManager: ProcessManager;
|
||||||
private readonly logManager: LogManager;
|
private readonly logManager: LogManager;
|
||||||
private readonly eventBus: EventBus | undefined;
|
private readonly eventBus: EventBus | undefined;
|
||||||
|
private readonly contextDeps: ServerContextDeps;
|
||||||
private server: Server | null = null;
|
private server: Server | null = null;
|
||||||
private state: ServerState | null = null;
|
private state: ServerState | null = null;
|
||||||
|
|
||||||
@@ -45,7 +52,8 @@ export class CoordinationServer {
|
|||||||
config: Partial<ServerConfig>,
|
config: Partial<ServerConfig>,
|
||||||
processManager: ProcessManager,
|
processManager: ProcessManager,
|
||||||
logManager: LogManager,
|
logManager: LogManager,
|
||||||
eventBus?: EventBus
|
eventBus?: EventBus,
|
||||||
|
contextDeps?: ServerContextDeps
|
||||||
) {
|
) {
|
||||||
this.config = {
|
this.config = {
|
||||||
port: config.port ?? DEFAULT_PORT,
|
port: config.port ?? DEFAULT_PORT,
|
||||||
@@ -55,6 +63,7 @@ export class CoordinationServer {
|
|||||||
this.processManager = processManager;
|
this.processManager = processManager;
|
||||||
this.logManager = logManager;
|
this.logManager = logManager;
|
||||||
this.eventBus = eventBus;
|
this.eventBus = eventBus;
|
||||||
|
this.contextDeps = contextDeps ?? {};
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -222,6 +231,7 @@ export class CoordinationServer {
|
|||||||
eventBus: this.eventBus,
|
eventBus: this.eventBus,
|
||||||
serverStartedAt: this.state.startedAt,
|
serverStartedAt: this.state.startedAt,
|
||||||
processCount: this.state.processCount,
|
processCount: this.state.processCount,
|
||||||
|
...this.contextDeps,
|
||||||
});
|
});
|
||||||
|
|
||||||
trpcHandler(req, res).catch((error: Error) => {
|
trpcHandler(req, res).catch((error: Error) => {
|
||||||
|
|||||||
@@ -10,6 +10,13 @@ import { fetchRequestHandler } from '@trpc/server/adapters/fetch';
|
|||||||
import { appRouter, createContext } from '../trpc/index.js';
|
import { appRouter, createContext } from '../trpc/index.js';
|
||||||
import type { EventBus } from '../events/index.js';
|
import type { EventBus } from '../events/index.js';
|
||||||
import type { AgentManager } from '../agent/types.js';
|
import type { AgentManager } from '../agent/types.js';
|
||||||
|
import type { TaskRepository } from '../db/repositories/task-repository.js';
|
||||||
|
import type { MessageRepository } from '../db/repositories/message-repository.js';
|
||||||
|
import type { InitiativeRepository } from '../db/repositories/initiative-repository.js';
|
||||||
|
import type { PhaseRepository } from '../db/repositories/phase-repository.js';
|
||||||
|
import type { PlanRepository } from '../db/repositories/plan-repository.js';
|
||||||
|
import type { DispatchManager, PhaseDispatchManager } from '../dispatch/types.js';
|
||||||
|
import type { CoordinationManager } from '../coordination/types.js';
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Options for creating the tRPC request handler.
|
* Options for creating the tRPC request handler.
|
||||||
@@ -23,6 +30,22 @@ export interface TrpcAdapterOptions {
|
|||||||
processCount: number;
|
processCount: number;
|
||||||
/** Agent manager for agent lifecycle operations (optional until full wiring) */
|
/** Agent manager for agent lifecycle operations (optional until full wiring) */
|
||||||
agentManager?: AgentManager;
|
agentManager?: AgentManager;
|
||||||
|
/** Task repository for task CRUD operations */
|
||||||
|
taskRepository?: TaskRepository;
|
||||||
|
/** Message repository for agent-user communication */
|
||||||
|
messageRepository?: MessageRepository;
|
||||||
|
/** Initiative repository for initiative CRUD operations */
|
||||||
|
initiativeRepository?: InitiativeRepository;
|
||||||
|
/** Phase repository for phase CRUD operations */
|
||||||
|
phaseRepository?: PhaseRepository;
|
||||||
|
/** Plan repository for plan CRUD operations */
|
||||||
|
planRepository?: PlanRepository;
|
||||||
|
/** Dispatch manager for task queue operations */
|
||||||
|
dispatchManager?: DispatchManager;
|
||||||
|
/** Coordination manager for merge queue operations */
|
||||||
|
coordinationManager?: CoordinationManager;
|
||||||
|
/** Phase dispatch manager for phase queue operations */
|
||||||
|
phaseDispatchManager?: PhaseDispatchManager;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -85,6 +108,14 @@ export function createTrpcHandler(options: TrpcAdapterOptions) {
|
|||||||
serverStartedAt: options.serverStartedAt,
|
serverStartedAt: options.serverStartedAt,
|
||||||
processCount: options.processCount,
|
processCount: options.processCount,
|
||||||
agentManager: options.agentManager,
|
agentManager: options.agentManager,
|
||||||
|
taskRepository: options.taskRepository,
|
||||||
|
messageRepository: options.messageRepository,
|
||||||
|
initiativeRepository: options.initiativeRepository,
|
||||||
|
phaseRepository: options.phaseRepository,
|
||||||
|
planRepository: options.planRepository,
|
||||||
|
dispatchManager: options.dispatchManager,
|
||||||
|
coordinationManager: options.coordinationManager,
|
||||||
|
phaseDispatchManager: options.phaseDispatchManager,
|
||||||
}),
|
}),
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user