Commit Graph

30 Commits

Author SHA1 Message Date
Lukas May
43e2c8b0ba fix(agent): Eliminate race condition in completion handling
PROBLEM:
- Agents completing with questions were incorrectly marked as "crashed"
- Race condition: polling handler AND crash handler both called handleCompletion()
- Caused database corruption and lost pending questions

SOLUTION:
- Add completion mutex in OutputHandler to prevent concurrent processing
- Remove duplicate completion call from crash handler
- Only one handler executes completion logic per agent

TESTING:
- Added mutex-completion.test.ts with 4 test cases
- Verified mutex prevents concurrent access
- Verified lock cleanup on exceptions
- Verified different agents can process concurrently

FIXES: residential-cuckoo and 12+ other agents stuck in crashed state
2026-02-08 15:51:32 +01:00
Lukas May
2877484012 Add userDismissedAt field to agents schema 2026-02-07 00:33:12 +01:00
Lukas May
cbf0ed28cb 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()
2026-02-04 21:18:30 +01:00
Lukas May
26778c60f5 test(14-07): add PhaseRepository dependency tests
- Add createDependency tests (create, FK constraint, multiple deps)
- Add getDependencies tests (empty, with deps, direct only)
- Add getDependents tests (empty, with dependents, direct only)
- Add phase_dependencies table to test-helpers.ts
2026-02-02 13:46:53 +01:00
Lukas May
28622cbd04 feat(14-05): add PhaseDispatchManager to tRPC context
- Import PhaseDispatchManager type from dispatch module
- Add optional phaseDispatchManager to TRPCContext interface
- Add phaseDispatchManager to CreateContextOptions
- Wire phaseDispatchManager through createContext function

Includes blocking fix: added 'blocked' status to phases schema enum
2026-02-02 13:39:47 +01:00
Lukas May
8e68a6e89e feat(14-01): add dependency methods to PhaseRepository
- Add createDependency(phaseId, dependsOnPhaseId) to interface and adapter
- Add getDependencies(phaseId) returning IDs of phases this phase depends on
- Add getDependents(phaseId) returning IDs of phases that depend on this phase
- Import phaseDependencies table in DrizzlePhaseRepository
- Follow exact pattern from DrizzleTaskRepository.createDependency
2026-02-02 13:33:16 +01:00
Lukas May
a55d08fffe feat(14-01): add phase_dependencies table to schema
- Add phase_dependencies table mirroring task_dependencies pattern
- Add phaseId and dependsOnPhaseId FK columns with cascade delete
- Add phasesRelations with dependsOn and dependents many relations
- Add phaseDependenciesRelations with phase and dependsOnPhase one relations
- Export PhaseDependency and NewPhaseDependency types
2026-02-02 13:32:19 +01:00
Lukas May
a61530359a test(12-07): add PlanRepository getNextNumber tests
Add tests for getNextNumber method:
- Returns 1 for phase with no plans
- Returns max + 1 for phase with existing plans
- Not affected by plans in other phases
2026-02-01 11:54:43 +01:00
Lukas May
66ad2ec6ef feat(12-04): add createTasksFromDecomposition procedure
- Add createDependency method to TaskRepository interface
- Implement createDependency in DrizzleTaskRepository
- Add createTasksFromDecomposition procedure for bulk task creation
- Procedure verifies plan exists before creating tasks
- Creates tasks in order, building number-to-ID map
- Creates task dependencies after all tasks exist
- Dependencies mapped from task numbers to IDs
2026-02-01 11:46:49 +01:00
Lukas May
8da4e71075 feat(12-01): extend AgentMode with 'decompose'
- Add 'decompose' to AgentMode union type
- Update agents table mode column enum in database schema
- Update test-helpers.ts CREATE_TABLES_SQL with CHECK constraint
- Add missing getNextNumber implementation (blocking fix)
2026-02-01 11:32:18 +01:00
Lukas May
3187e2ab01 feat(12-02): implement getNextNumber in DrizzlePlanRepository
- Import max from drizzle-orm for aggregate query
- Query MAX(number) where phase_id matches
- Return max + 1, or 1 if no plans exist
- Pattern follows DrizzlePhaseRepository.getNextNumber
2026-02-01 11:31:30 +01:00
Lukas May
0044fbfc6e feat(12-02): add getNextNumber to PlanRepository interface
- Add getNextNumber(phaseId) method signature
- Returns MAX(number) + 1, or 1 if no plans exist
- Following pattern from PhaseRepository.getNextNumber
2026-02-01 11:30:27 +01:00
Lukas May
1f4a95df4a test(db): add PhaseRepository findByNumber and getNextNumber tests
- Test findByNumber with matching/non-matching initiative and number
- Test getNextNumber returns 1 for empty initiative
- Test getNextNumber returns max + 1 with existing phases
- Test getNextNumber handles gaps in numbering
2026-01-31 19:24:09 +01:00
Lukas May
de57c15666 test(db): add InitiativeRepository findByStatus tests
- Test empty array for no matches
- Test filtering by active/completed/archived status
2026-01-31 19:23:44 +01:00
Lukas May
75f8887b53 feat(11-03): add mode field to AgentRepository
- Add AgentMode import to agent-repository.ts
- Add mode optional field to CreateAgentData interface
- Update DrizzleAgentRepository.create() to handle mode (default 'execute')
2026-01-31 19:11:12 +01:00
Lukas May
f7edac7a5c fix(11-01): add mode column to test database schema
- Add mode column to agents table in test-helpers CREATE_TABLES_SQL
- Generate drizzle migration for mode column
2026-01-31 19:07:54 +01:00
Lukas May
67cfd4d201 feat(11-02): add findByNumber and getNextNumber to PhaseRepository
- Add findByNumber method to lookup phase by initiative and number
- Add getNextNumber method to get next available phase number
- Implement both methods in DrizzlePhaseRepository adapter
- Use drizzle-orm max() and and() for query construction
2026-01-31 19:05:04 +01:00
Lukas May
91e57c66eb feat(11-01): add AgentMode type and database column
- Add AgentMode type: 'execute' | 'discuss' | 'breakdown'
- Add mode column to agents table with 'execute' default
- Update SpawnAgentOptions to accept optional mode
- Update AgentInfo interface to include mode field
- Update ClaudeAgentManager.toAgentInfo to map mode
- Fix MockAgentManager to include mode in spawn
- Fix dispatch manager tests to include mode
2026-01-31 19:03:42 +01:00
Lukas May
768c4d265e feat(11-02): add findByStatus method to InitiativeRepository
- Add findByStatus method to InitiativeRepository port interface
- Implement findByStatus in DrizzleInitiativeRepository adapter
- Filter initiatives by status (active/completed/archived)
2026-01-31 19:03:26 +01:00
Lukas May
19dc75c3f4 feat(05-01): add MessageRepository port and adapter
- Create MessageRepository port interface with CRUD and query methods
- Implement DrizzleMessageRepository adapter with nanoid generation
- Add findBySender/findByRecipient for participant-based queries
- Add findPendingForUser for unread user notifications
- Add findRequiringResponse for messages awaiting reply
- Add findReplies for message threading support
- Add 23 tests covering all operations and edge cases
- Update test-helpers with messages table schema
- Re-export from index files following AgentRepository pattern
2026-01-30 20:35:09 +01:00
Lukas May
f873a32ff4 feat(05-01): add messages table to schema
- Add messages table with sender/recipient pattern for agent-user communication
- Support message types: question, info, error, response
- Add requiresResponse flag and status tracking (pending, read, responded)
- Include parentMessageId for threading responses to original questions
- Add relations for sender/recipient agents and message threading
2026-01-30 20:32:31 +01:00
Lukas May
25f98fcbe1 feat(04-01): create DrizzleAgentRepository adapter with tests
- Implement DrizzleAgentRepository with all AgentRepository methods
- Add findByName, findByTaskId, findBySessionId lookups
- Add findByStatus for filtering including waiting_for_input
- Add updateStatus and updateSessionId for state changes
- Add agents table to test-helpers.ts SQL
- Export DrizzleAgentRepository from drizzle/index.ts
- 22 tests covering all operations and edge cases
2026-01-30 20:01:00 +01:00
Lukas May
eec5f1398e feat(04-01): create AgentRepository port interface
- Define AgentRepository interface with CRUD operations
- Add findByName, findByTaskId, findBySessionId for lookups
- Add findByStatus for filtering by agent state
- Add updateStatus and updateSessionId for state changes
- Export AgentStatus type
- Export from repositories barrel file
2026-01-30 19:59:04 +01:00
Lukas May
dfaa51076b feat(04-01): add agents table to database schema
- Define agents table with id, name (unique), taskId, sessionId, worktreeId, status
- Status enum: idle, running, waiting_for_input, stopped, crashed
- Foreign key to tasks with onDelete: 'set null' (agent may outlive task)
- Add agentsRelations linking to tasks
- Export Agent and NewAgent types
2026-01-30 19:58:35 +01:00
Lukas May
112cc231c7 feat(02-02): update exports and add cascade delete tests
- src/db/index.ts exports repository interfaces and adapters
- cascade.test.ts tests full hierarchy cascade behavior:
  - Delete initiative removes all phases, plans, tasks
  - Delete phase removes only its plans and tasks
  - Delete plan removes only its tasks
- All 45 repository tests passing
2026-01-30 19:11:31 +01:00
Lukas May
830aa4b03f test(02-02): add repository adapter tests
- createTestDatabase helper with in-memory SQLite schema
- initiative.test.ts: CRUD, defaults, not-found errors
- phase.test.ts: CRUD, FK constraint, findByInitiativeId ordering
- plan.test.ts: CRUD, FK constraint, findByPhaseId ordering
- task.test.ts: CRUD, FK constraint, findByPlanId ordering
- Fixed adapters to apply defaults and fetch inserted records
- All 42 tests passing
2026-01-30 14:53:15 +01:00
Lukas May
14e0f6f0f5 feat(02-02): create Drizzle repository adapters
- DrizzleInitiativeRepository: CRUD with nanoid ID generation
- DrizzlePhaseRepository: findByInitiativeId ordered by number
- DrizzlePlanRepository: findByPhaseId ordered by number
- DrizzleTaskRepository: findByPlanId ordered by order field
- All adapters use DI for DrizzleDatabase instance
- Timestamps set automatically on create/update
- Throws on update/delete of non-existent entities
2026-01-30 14:49:36 +01:00
Lukas May
5e5bca3d01 feat(02-02): create repository port interfaces
- InitiativeRepository: CRUD for initiative aggregate
- PhaseRepository: CRUD with findByInitiativeId ordered by number
- PlanRepository: CRUD with findByPhaseId ordered by number
- TaskRepository: CRUD with findByPlanId ordered by order field
- Re-export all interfaces from repositories/index.ts
2026-01-30 14:46:16 +01:00
Lukas May
b492f64348 feat(02-01): define task hierarchy schema
Schema defines 5 tables with proper foreign key relationships:
- initiatives: Top-level projects (active/completed/archived)
- phases: Major milestones within initiatives
- plans: Groups of related tasks within phases
- tasks: Individual work items with type, priority, status, order
- task_dependencies: Dependency relationships between tasks

All tables have cascade deletes and Unix timestamp fields.
Types exported: Initiative, Phase, Plan, Task, TaskDependency + New* variants.
Relations exported for Drizzle relational queries.
2026-01-30 14:24:41 +01:00
Lukas May
d7e4649e47 feat(02-01): create database connection factory
- src/db/config.ts: getDbPath() returns ~/.cw/data/cw.db with CW_DB_PATH override
- src/db/index.ts: createDatabase() factory with WAL mode and foreign keys
- drizzle.config.ts: Drizzle Kit configuration for migrations

Pattern: Factory function (not singleton) allows isolated test instances
2026-01-30 14:23:42 +01:00