docs(01.1): create phase plan
Phase 01.1: Hexagonal Architecture - 6 plans in 3 waves - Wave 1: Event bus + tRPC foundation (parallel) - Wave 2: Process, logging, server module refactors (parallel) - Wave 3: CLI tRPC integration - Ready for execution
This commit is contained in:
155
.planning/phases/01.1-hexagonal-architecture/01.1-01-PLAN.md
Normal file
155
.planning/phases/01.1-hexagonal-architecture/01.1-01-PLAN.md
Normal file
@@ -0,0 +1,155 @@
|
|||||||
|
---
|
||||||
|
phase: 01.1-hexagonal-architecture
|
||||||
|
plan: 01
|
||||||
|
type: execute
|
||||||
|
wave: 1
|
||||||
|
depends_on: []
|
||||||
|
files_modified: [package.json, vitest.config.ts, src/events/types.ts, src/events/bus.ts, src/events/index.ts, src/events/bus.test.ts]
|
||||||
|
autonomous: true
|
||||||
|
---
|
||||||
|
|
||||||
|
<objective>
|
||||||
|
Create the event bus foundation - the backbone of the hexagonal architecture.
|
||||||
|
|
||||||
|
Purpose: Establish extensible event infrastructure that can be swapped for external systems (RabbitMQ, WebSocket forwarding) later. All modules will communicate through this event bus.
|
||||||
|
Output: Working event bus with typed domain events and full test coverage.
|
||||||
|
</objective>
|
||||||
|
|
||||||
|
<execution_context>
|
||||||
|
@~/.claude/get-shit-done/workflows/execute-plan.md
|
||||||
|
@~/.claude/get-shit-done/templates/summary.md
|
||||||
|
</execution_context>
|
||||||
|
|
||||||
|
<context>
|
||||||
|
@.planning/PROJECT.md
|
||||||
|
@.planning/ROADMAP.md
|
||||||
|
@.planning/STATE.md
|
||||||
|
@.planning/phases/01.1-hexagonal-architecture/1.1-CONTEXT.md
|
||||||
|
|
||||||
|
@src/index.ts
|
||||||
|
@src/process/types.ts
|
||||||
|
@src/logging/types.ts
|
||||||
|
@src/server/types.ts
|
||||||
|
@package.json
|
||||||
|
</context>
|
||||||
|
|
||||||
|
<tasks>
|
||||||
|
|
||||||
|
<task type="auto">
|
||||||
|
<name>Task 1: Install and configure Vitest test framework</name>
|
||||||
|
<files>package.json, vitest.config.ts</files>
|
||||||
|
<action>
|
||||||
|
Install vitest as dev dependency: `npm install -D vitest`
|
||||||
|
|
||||||
|
Create vitest.config.ts with:
|
||||||
|
- TypeScript support (uses tsconfig.json automatically)
|
||||||
|
- Test globals enabled (describe, it, expect without imports)
|
||||||
|
- Coverage reporter (optional, for future use)
|
||||||
|
- Test file pattern: **/*.test.ts
|
||||||
|
|
||||||
|
Add npm scripts to package.json:
|
||||||
|
- "test": "vitest run"
|
||||||
|
- "test:watch": "vitest"
|
||||||
|
- "test:coverage": "vitest run --coverage"
|
||||||
|
</action>
|
||||||
|
<verify>npm test runs successfully (0 tests found is fine at this stage)</verify>
|
||||||
|
<done>Vitest configured, npm test works, test:watch works</done>
|
||||||
|
</task>
|
||||||
|
|
||||||
|
<task type="auto">
|
||||||
|
<name>Task 2: Create EventBus port interface and EventEmitter adapter</name>
|
||||||
|
<files>src/events/types.ts, src/events/bus.ts, src/events/index.ts</files>
|
||||||
|
<action>
|
||||||
|
Create src/events/types.ts:
|
||||||
|
- Define EventBus interface (the PORT):
|
||||||
|
```typescript
|
||||||
|
export interface EventBus {
|
||||||
|
emit<T extends DomainEvent>(event: T): void;
|
||||||
|
on<T extends DomainEvent>(eventType: T['type'], handler: (event: T) => void): void;
|
||||||
|
off<T extends DomainEvent>(eventType: T['type'], handler: (event: T) => void): void;
|
||||||
|
once<T extends DomainEvent>(eventType: T['type'], handler: (event: T) => void): void;
|
||||||
|
}
|
||||||
|
```
|
||||||
|
- Define base DomainEvent interface:
|
||||||
|
```typescript
|
||||||
|
export interface DomainEvent {
|
||||||
|
type: string;
|
||||||
|
timestamp: Date;
|
||||||
|
payload: unknown;
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
Create src/events/bus.ts:
|
||||||
|
- Implement EventEmitterBus class that implements EventBus interface
|
||||||
|
- Use Node.js EventEmitter internally
|
||||||
|
- Wrap EventEmitter methods to match EventBus interface
|
||||||
|
- Add type safety for event emission
|
||||||
|
|
||||||
|
Create src/events/index.ts:
|
||||||
|
- Export EventBus interface
|
||||||
|
- Export EventEmitterBus class
|
||||||
|
- Export DomainEvent type
|
||||||
|
- Export convenience function: createEventBus() that returns EventEmitterBus instance
|
||||||
|
|
||||||
|
Key design: EventBus interface is the PORT. EventEmitterBus is the ADAPTER.
|
||||||
|
This allows swapping to RabbitMQ/Kafka/WebSocket later without changing consumers.
|
||||||
|
</action>
|
||||||
|
<verify>TypeScript compiles: npm run build</verify>
|
||||||
|
<done>EventBus interface defined, EventEmitterBus implemented, exports working</done>
|
||||||
|
</task>
|
||||||
|
|
||||||
|
<task type="auto">
|
||||||
|
<name>Task 3: Define domain events with typed payloads and write tests</name>
|
||||||
|
<files>src/events/types.ts, src/events/bus.test.ts</files>
|
||||||
|
<action>
|
||||||
|
Add domain event types to src/events/types.ts:
|
||||||
|
|
||||||
|
Process events:
|
||||||
|
- ProcessSpawned: { processId: string, pid: number, command: string }
|
||||||
|
- ProcessStopped: { processId: string, pid: number, exitCode: number | null }
|
||||||
|
- ProcessCrashed: { processId: string, pid: number, signal: string | null }
|
||||||
|
|
||||||
|
Server events:
|
||||||
|
- ServerStarted: { port: number, host: string, pid: number }
|
||||||
|
- ServerStopped: { uptime: number }
|
||||||
|
|
||||||
|
Log events:
|
||||||
|
- LogEntry: { processId: string, stream: 'stdout' | 'stderr', data: string }
|
||||||
|
|
||||||
|
Create union type: DomainEventMap that maps event type strings to payload types.
|
||||||
|
This enables type-safe event handling.
|
||||||
|
|
||||||
|
Create src/events/bus.test.ts:
|
||||||
|
- Test emit/on pattern works
|
||||||
|
- Test once fires only once
|
||||||
|
- Test off removes handler
|
||||||
|
- Test multiple handlers for same event
|
||||||
|
- Test typed event payloads (TypeScript compilation = passing)
|
||||||
|
- Test events include timestamp automatically
|
||||||
|
</action>
|
||||||
|
<verify>npm test passes with all event bus tests green</verify>
|
||||||
|
<done>Domain events defined, all tests pass, type safety verified</done>
|
||||||
|
</task>
|
||||||
|
|
||||||
|
</tasks>
|
||||||
|
|
||||||
|
<verification>
|
||||||
|
Before declaring plan complete:
|
||||||
|
- [ ] npm run build succeeds
|
||||||
|
- [ ] npm test passes (event bus tests)
|
||||||
|
- [ ] EventBus interface is exported from src/events/index.ts
|
||||||
|
- [ ] EventEmitterBus implements EventBus correctly
|
||||||
|
- [ ] All domain events have typed payloads
|
||||||
|
</verification>
|
||||||
|
|
||||||
|
<success_criteria>
|
||||||
|
|
||||||
|
- All tasks completed
|
||||||
|
- All verification checks pass
|
||||||
|
- Event bus is extensible (interface-based)
|
||||||
|
- Tests prove the pattern works
|
||||||
|
</success_criteria>
|
||||||
|
|
||||||
|
<output>
|
||||||
|
After completion, create `.planning/phases/01.1-hexagonal-architecture/01.1-01-SUMMARY.md`
|
||||||
|
</output>
|
||||||
123
.planning/phases/01.1-hexagonal-architecture/01.1-02-PLAN.md
Normal file
123
.planning/phases/01.1-hexagonal-architecture/01.1-02-PLAN.md
Normal file
@@ -0,0 +1,123 @@
|
|||||||
|
---
|
||||||
|
phase: 01.1-hexagonal-architecture
|
||||||
|
plan: 02
|
||||||
|
type: execute
|
||||||
|
wave: 1
|
||||||
|
depends_on: []
|
||||||
|
files_modified: [package.json, src/trpc/router.ts, src/trpc/context.ts, src/trpc/index.ts, src/trpc/router.test.ts]
|
||||||
|
autonomous: true
|
||||||
|
---
|
||||||
|
|
||||||
|
<objective>
|
||||||
|
Create tRPC foundation for type-safe CLI-server communication.
|
||||||
|
|
||||||
|
Purpose: Establish the tRPC contract that CLI and future WebUI will use to communicate with the server. Same interface for all clients.
|
||||||
|
Output: Working tRPC router with procedures matching existing HTTP endpoints, fully tested.
|
||||||
|
</objective>
|
||||||
|
|
||||||
|
<execution_context>
|
||||||
|
@~/.claude/get-shit-done/workflows/execute-plan.md
|
||||||
|
@~/.claude/get-shit-done/templates/summary.md
|
||||||
|
</execution_context>
|
||||||
|
|
||||||
|
<context>
|
||||||
|
@.planning/PROJECT.md
|
||||||
|
@.planning/ROADMAP.md
|
||||||
|
@.planning/STATE.md
|
||||||
|
@.planning/phases/01.1-hexagonal-architecture/1.1-CONTEXT.md
|
||||||
|
|
||||||
|
@src/server/index.ts
|
||||||
|
@src/server/types.ts
|
||||||
|
@package.json
|
||||||
|
</context>
|
||||||
|
|
||||||
|
<tasks>
|
||||||
|
|
||||||
|
<task type="auto">
|
||||||
|
<name>Task 1: Install tRPC dependencies and create router foundation</name>
|
||||||
|
<files>package.json, src/trpc/router.ts, src/trpc/context.ts, src/trpc/index.ts</files>
|
||||||
|
<action>
|
||||||
|
Install dependencies:
|
||||||
|
- npm install @trpc/server zod
|
||||||
|
- npm install -D @trpc/client (for testing)
|
||||||
|
|
||||||
|
Create src/trpc/context.ts:
|
||||||
|
- Define TRPCContext type containing:
|
||||||
|
- eventBus: EventBus (from src/events - import the interface type)
|
||||||
|
- serverStartedAt: Date | null
|
||||||
|
- processCount: number
|
||||||
|
- Export createContext function that builds context
|
||||||
|
- Context will be injected into procedures
|
||||||
|
|
||||||
|
Create src/trpc/router.ts:
|
||||||
|
- Initialize tRPC with initTRPC.context<TRPCContext>().create()
|
||||||
|
- Create base router and procedure helpers
|
||||||
|
- Export router, publicProcedure
|
||||||
|
|
||||||
|
Create src/trpc/index.ts:
|
||||||
|
- Export router, context, types
|
||||||
|
- Export AppRouter type for client usage
|
||||||
|
|
||||||
|
Note: Don't import actual EventBus implementation yet - just the type.
|
||||||
|
This keeps tRPC foundation independent of event bus implementation.
|
||||||
|
</action>
|
||||||
|
<verify>npm run build succeeds, no import errors</verify>
|
||||||
|
<done>tRPC initialized, context defined, router foundation in place</done>
|
||||||
|
</task>
|
||||||
|
|
||||||
|
<task type="auto">
|
||||||
|
<name>Task 2: Define procedures matching HTTP endpoints with tests</name>
|
||||||
|
<files>src/trpc/router.ts, src/trpc/router.test.ts</files>
|
||||||
|
<action>
|
||||||
|
Add procedures to src/trpc/router.ts:
|
||||||
|
|
||||||
|
health procedure (query):
|
||||||
|
- Input: none
|
||||||
|
- Output: { status: 'ok', uptime: number, processCount: number }
|
||||||
|
- Uses context.serverStartedAt to calculate uptime
|
||||||
|
- Use Zod for output validation
|
||||||
|
|
||||||
|
status procedure (query):
|
||||||
|
- Input: none
|
||||||
|
- Output: { server: { startedAt: string, uptime: number, pid: number }, processes: Array }
|
||||||
|
- More detailed than health
|
||||||
|
- Use Zod for output validation
|
||||||
|
|
||||||
|
Create appRouter that combines procedures.
|
||||||
|
Export AppRouter type: typeof appRouter
|
||||||
|
|
||||||
|
Create src/trpc/router.test.ts:
|
||||||
|
- Use @trpc/server/adapters/standalone for testing (or direct caller)
|
||||||
|
- Test health procedure returns correct shape
|
||||||
|
- Test status procedure returns correct shape
|
||||||
|
- Test with mocked context (no real server needed)
|
||||||
|
- Verify Zod validation catches bad outputs
|
||||||
|
|
||||||
|
Testing approach: Use createCallerFactory from tRPC for direct procedure calls without HTTP.
|
||||||
|
</action>
|
||||||
|
<verify>npm test passes with tRPC router tests green</verify>
|
||||||
|
<done>Procedures defined, Zod validation in place, tests pass</done>
|
||||||
|
</task>
|
||||||
|
|
||||||
|
</tasks>
|
||||||
|
|
||||||
|
<verification>
|
||||||
|
Before declaring plan complete:
|
||||||
|
- [ ] npm run build succeeds
|
||||||
|
- [ ] npm test passes (tRPC router tests)
|
||||||
|
- [ ] AppRouter type is exported
|
||||||
|
- [ ] health and status procedures work
|
||||||
|
- [ ] Zod schemas validate outputs
|
||||||
|
</verification>
|
||||||
|
|
||||||
|
<success_criteria>
|
||||||
|
|
||||||
|
- All tasks completed
|
||||||
|
- All verification checks pass
|
||||||
|
- tRPC router ready for HTTP adapter integration
|
||||||
|
- Type-safe contract established
|
||||||
|
</success_criteria>
|
||||||
|
|
||||||
|
<output>
|
||||||
|
After completion, create `.planning/phases/01.1-hexagonal-architecture/01.1-02-SUMMARY.md`
|
||||||
|
</output>
|
||||||
126
.planning/phases/01.1-hexagonal-architecture/01.1-03-PLAN.md
Normal file
126
.planning/phases/01.1-hexagonal-architecture/01.1-03-PLAN.md
Normal file
@@ -0,0 +1,126 @@
|
|||||||
|
---
|
||||||
|
phase: 01.1-hexagonal-architecture
|
||||||
|
plan: 03
|
||||||
|
type: execute
|
||||||
|
wave: 2
|
||||||
|
depends_on: ["01.1-01"]
|
||||||
|
files_modified: [src/process/registry.test.ts, src/process/manager.test.ts, src/process/manager.ts, src/process/index.ts]
|
||||||
|
autonomous: true
|
||||||
|
---
|
||||||
|
|
||||||
|
<objective>
|
||||||
|
Add test coverage and event emission to the Process module.
|
||||||
|
|
||||||
|
Purpose: ProcessManager is core to agent lifecycle. Events like ProcessSpawned/ProcessStopped will drive coordination logic in later phases.
|
||||||
|
Output: Fully tested process module that emits domain events via the event bus.
|
||||||
|
</objective>
|
||||||
|
|
||||||
|
<execution_context>
|
||||||
|
@~/.claude/get-shit-done/workflows/execute-plan.md
|
||||||
|
@~/.claude/get-shit-done/templates/summary.md
|
||||||
|
</execution_context>
|
||||||
|
|
||||||
|
<context>
|
||||||
|
@.planning/PROJECT.md
|
||||||
|
@.planning/ROADMAP.md
|
||||||
|
@.planning/STATE.md
|
||||||
|
@.planning/phases/01.1-hexagonal-architecture/01.1-01-SUMMARY.md
|
||||||
|
|
||||||
|
@src/process/index.ts
|
||||||
|
@src/process/manager.ts
|
||||||
|
@src/process/registry.ts
|
||||||
|
@src/process/types.ts
|
||||||
|
@src/events/index.ts
|
||||||
|
</context>
|
||||||
|
|
||||||
|
<tasks>
|
||||||
|
|
||||||
|
<task type="auto">
|
||||||
|
<name>Task 1: Write unit tests for ProcessRegistry and ProcessManager</name>
|
||||||
|
<files>src/process/registry.test.ts, src/process/manager.test.ts</files>
|
||||||
|
<action>
|
||||||
|
Create src/process/registry.test.ts:
|
||||||
|
- Test register() adds process to registry
|
||||||
|
- Test get() retrieves registered process
|
||||||
|
- Test getAll() returns all processes
|
||||||
|
- Test updateStatus() changes status correctly
|
||||||
|
- Test unregister() removes process
|
||||||
|
- Test get() returns undefined for non-existent process
|
||||||
|
|
||||||
|
Create src/process/manager.test.ts:
|
||||||
|
- Test spawn() creates process and registers it
|
||||||
|
- Test spawn() throws if process ID already running
|
||||||
|
- Test stop() terminates process
|
||||||
|
- Test stop() throws if process not found
|
||||||
|
- Test stopAll() stops all running processes
|
||||||
|
- Test restart() stops and respawns process
|
||||||
|
- Test isRunning() returns correct state
|
||||||
|
|
||||||
|
Testing approach for ProcessManager:
|
||||||
|
- Mock the execa module to avoid spawning real processes
|
||||||
|
- Use vi.mock('execa') with mock subprocess that has controllable behavior
|
||||||
|
- Create mock registry for isolation
|
||||||
|
|
||||||
|
Focus on behavior, not implementation details.
|
||||||
|
</action>
|
||||||
|
<verify>npm test passes with process module tests green</verify>
|
||||||
|
<done>ProcessRegistry and ProcessManager have comprehensive test coverage</done>
|
||||||
|
</task>
|
||||||
|
|
||||||
|
<task type="auto">
|
||||||
|
<name>Task 2: Refactor ProcessManager to emit events via event bus</name>
|
||||||
|
<files>src/process/manager.ts, src/process/index.ts</files>
|
||||||
|
<action>
|
||||||
|
Modify ProcessManager constructor:
|
||||||
|
- Add optional eventBus parameter: EventBus | undefined
|
||||||
|
- Store as private readonly property
|
||||||
|
|
||||||
|
Add event emission in spawn():
|
||||||
|
- After successful spawn, emit ProcessSpawned event:
|
||||||
|
{ type: 'process.spawned', timestamp: new Date(), payload: { processId, pid, command } }
|
||||||
|
|
||||||
|
Add event emission in exit handler:
|
||||||
|
- On normal exit, emit ProcessStopped:
|
||||||
|
{ type: 'process.stopped', timestamp: new Date(), payload: { processId, pid, exitCode } }
|
||||||
|
- On crash (non-zero exit), emit ProcessCrashed:
|
||||||
|
{ type: 'process.crashed', timestamp: new Date(), payload: { processId, pid, signal } }
|
||||||
|
|
||||||
|
Add event emission in stop():
|
||||||
|
- After successful stop, ProcessStopped is already emitted by exit handler
|
||||||
|
- No additional event needed
|
||||||
|
|
||||||
|
Update src/process/index.ts exports if needed.
|
||||||
|
|
||||||
|
Update tests to verify events are emitted:
|
||||||
|
- Create mock EventBus
|
||||||
|
- Pass to ProcessManager
|
||||||
|
- Assert emit() called with correct event shape
|
||||||
|
|
||||||
|
Key: eventBus is optional for backwards compatibility. If not provided, no events emitted.
|
||||||
|
</action>
|
||||||
|
<verify>npm test passes, events emitted correctly in tests</verify>
|
||||||
|
<done>ProcessManager emits domain events, tests verify event emission</done>
|
||||||
|
</task>
|
||||||
|
|
||||||
|
</tasks>
|
||||||
|
|
||||||
|
<verification>
|
||||||
|
Before declaring plan complete:
|
||||||
|
- [ ] npm run build succeeds
|
||||||
|
- [ ] npm test passes (all process module tests)
|
||||||
|
- [ ] ProcessManager accepts optional eventBus
|
||||||
|
- [ ] ProcessSpawned event emitted on spawn
|
||||||
|
- [ ] ProcessStopped/ProcessCrashed events emitted on exit
|
||||||
|
</verification>
|
||||||
|
|
||||||
|
<success_criteria>
|
||||||
|
|
||||||
|
- All tasks completed
|
||||||
|
- All verification checks pass
|
||||||
|
- Process lifecycle events flow through event bus
|
||||||
|
- Backwards compatible (eventBus is optional)
|
||||||
|
</success_criteria>
|
||||||
|
|
||||||
|
<output>
|
||||||
|
After completion, create `.planning/phases/01.1-hexagonal-architecture/01.1-03-SUMMARY.md`
|
||||||
|
</output>
|
||||||
124
.planning/phases/01.1-hexagonal-architecture/01.1-04-PLAN.md
Normal file
124
.planning/phases/01.1-hexagonal-architecture/01.1-04-PLAN.md
Normal file
@@ -0,0 +1,124 @@
|
|||||||
|
---
|
||||||
|
phase: 01.1-hexagonal-architecture
|
||||||
|
plan: 04
|
||||||
|
type: execute
|
||||||
|
wave: 2
|
||||||
|
depends_on: ["01.1-01"]
|
||||||
|
files_modified: [src/logging/manager.test.ts, src/logging/writer.test.ts, src/logging/writer.ts, src/logging/index.ts]
|
||||||
|
autonomous: true
|
||||||
|
---
|
||||||
|
|
||||||
|
<objective>
|
||||||
|
Add test coverage and event emission to the Logging module.
|
||||||
|
|
||||||
|
Purpose: Log events will be forwarded to UI/FSUI for real-time visibility into agent output. Critical for the file system UI in Phase 7.
|
||||||
|
Output: Fully tested logging module that emits LogEntry events via the event bus.
|
||||||
|
</objective>
|
||||||
|
|
||||||
|
<execution_context>
|
||||||
|
@~/.claude/get-shit-done/workflows/execute-plan.md
|
||||||
|
@~/.claude/get-shit-done/templates/summary.md
|
||||||
|
</execution_context>
|
||||||
|
|
||||||
|
<context>
|
||||||
|
@.planning/PROJECT.md
|
||||||
|
@.planning/ROADMAP.md
|
||||||
|
@.planning/STATE.md
|
||||||
|
@.planning/phases/01.1-hexagonal-architecture/01.1-01-SUMMARY.md
|
||||||
|
|
||||||
|
@src/logging/index.ts
|
||||||
|
@src/logging/manager.ts
|
||||||
|
@src/logging/writer.ts
|
||||||
|
@src/logging/types.ts
|
||||||
|
@src/events/index.ts
|
||||||
|
</context>
|
||||||
|
|
||||||
|
<tasks>
|
||||||
|
|
||||||
|
<task type="auto">
|
||||||
|
<name>Task 1: Write unit tests for LogManager and ProcessLogWriter</name>
|
||||||
|
<files>src/logging/manager.test.ts, src/logging/writer.test.ts</files>
|
||||||
|
<action>
|
||||||
|
Create src/logging/manager.test.ts:
|
||||||
|
- Test ensureLogDir() creates directory
|
||||||
|
- Test ensureProcessDir() creates process-specific directory
|
||||||
|
- Test getProcessDir() returns correct path
|
||||||
|
- Test getLogPath() returns correct path for stdout/stderr
|
||||||
|
- Test listLogs() returns process IDs
|
||||||
|
- Test listLogs() returns empty array if dir doesn't exist
|
||||||
|
- Test cleanOldLogs() removes old directories
|
||||||
|
- Test getBaseDir() returns configured base
|
||||||
|
|
||||||
|
Use temporary directories for file system tests (use os.tmpdir()).
|
||||||
|
Clean up after each test.
|
||||||
|
|
||||||
|
Create src/logging/writer.test.ts:
|
||||||
|
- Read src/logging/writer.ts first to understand the API
|
||||||
|
- Test open() creates log files
|
||||||
|
- Test writeStdout() writes to stdout.log
|
||||||
|
- Test writeStderr() writes to stderr.log
|
||||||
|
- Test close() flushes and closes handles
|
||||||
|
- Test writing after close throws
|
||||||
|
|
||||||
|
Use temporary directories, clean up after tests.
|
||||||
|
</action>
|
||||||
|
<verify>npm test passes with logging module tests green</verify>
|
||||||
|
<done>LogManager and ProcessLogWriter have comprehensive test coverage</done>
|
||||||
|
</task>
|
||||||
|
|
||||||
|
<task type="auto">
|
||||||
|
<name>Task 2: Add event emission to ProcessLogWriter</name>
|
||||||
|
<files>src/logging/writer.ts, src/logging/index.ts</files>
|
||||||
|
<action>
|
||||||
|
Modify ProcessLogWriter constructor:
|
||||||
|
- Add optional eventBus parameter: EventBus | undefined
|
||||||
|
- Store as private readonly property
|
||||||
|
|
||||||
|
Add event emission in writeStdout():
|
||||||
|
- After writing to file, emit LogEntry event:
|
||||||
|
{ type: 'log.entry', timestamp: new Date(), payload: { processId, stream: 'stdout', data } }
|
||||||
|
|
||||||
|
Add event emission in writeStderr():
|
||||||
|
- After writing to file, emit LogEntry event:
|
||||||
|
{ type: 'log.entry', timestamp: new Date(), payload: { processId, stream: 'stderr', data } }
|
||||||
|
|
||||||
|
Update createLogger() convenience function:
|
||||||
|
- Add optional eventBus parameter
|
||||||
|
- Pass through to ProcessLogWriter
|
||||||
|
|
||||||
|
Update src/logging/index.ts exports if needed.
|
||||||
|
|
||||||
|
Update tests to verify events are emitted:
|
||||||
|
- Create mock EventBus
|
||||||
|
- Pass to ProcessLogWriter
|
||||||
|
- Assert emit() called with correct LogEntry shape
|
||||||
|
- Test that events are NOT emitted if eventBus not provided
|
||||||
|
|
||||||
|
Key: This enables real-time log streaming to UI/FSUI in later phases.
|
||||||
|
</action>
|
||||||
|
<verify>npm test passes, log events emitted correctly</verify>
|
||||||
|
<done>ProcessLogWriter emits LogEntry events, tests verify emission</done>
|
||||||
|
</task>
|
||||||
|
|
||||||
|
</tasks>
|
||||||
|
|
||||||
|
<verification>
|
||||||
|
Before declaring plan complete:
|
||||||
|
- [ ] npm run build succeeds
|
||||||
|
- [ ] npm test passes (all logging module tests)
|
||||||
|
- [ ] ProcessLogWriter accepts optional eventBus
|
||||||
|
- [ ] LogEntry events emitted on stdout/stderr writes
|
||||||
|
- [ ] Backwards compatible (eventBus is optional)
|
||||||
|
</verification>
|
||||||
|
|
||||||
|
<success_criteria>
|
||||||
|
|
||||||
|
- All tasks completed
|
||||||
|
- All verification checks pass
|
||||||
|
- Log events flow through event bus
|
||||||
|
- Ready for real-time log streaming
|
||||||
|
</success_criteria>
|
||||||
|
|
||||||
|
<output>
|
||||||
|
After completion, create `.planning/phases/01.1-hexagonal-architecture/01.1-04-SUMMARY.md`
|
||||||
|
</output>
|
||||||
133
.planning/phases/01.1-hexagonal-architecture/01.1-05-PLAN.md
Normal file
133
.planning/phases/01.1-hexagonal-architecture/01.1-05-PLAN.md
Normal file
@@ -0,0 +1,133 @@
|
|||||||
|
---
|
||||||
|
phase: 01.1-hexagonal-architecture
|
||||||
|
plan: 05
|
||||||
|
type: execute
|
||||||
|
wave: 2
|
||||||
|
depends_on: ["01.1-01"]
|
||||||
|
files_modified: [src/server/index.test.ts, src/server/shutdown.test.ts, src/server/index.ts, src/server/shutdown.ts]
|
||||||
|
autonomous: true
|
||||||
|
---
|
||||||
|
|
||||||
|
<objective>
|
||||||
|
Add test coverage and event emission to the Server module.
|
||||||
|
|
||||||
|
Purpose: Server events (started/stopped) are critical for coordination. The shutdown handler orchestrates cleanup - events enable reactive patterns.
|
||||||
|
Output: Fully tested server module with event-driven lifecycle.
|
||||||
|
</objective>
|
||||||
|
|
||||||
|
<execution_context>
|
||||||
|
@~/.claude/get-shit-done/workflows/execute-plan.md
|
||||||
|
@~/.claude/get-shit-done/templates/summary.md
|
||||||
|
</execution_context>
|
||||||
|
|
||||||
|
<context>
|
||||||
|
@.planning/PROJECT.md
|
||||||
|
@.planning/ROADMAP.md
|
||||||
|
@.planning/STATE.md
|
||||||
|
@.planning/phases/01.1-hexagonal-architecture/01.1-01-SUMMARY.md
|
||||||
|
|
||||||
|
@src/server/index.ts
|
||||||
|
@src/server/shutdown.ts
|
||||||
|
@src/server/types.ts
|
||||||
|
@src/events/index.ts
|
||||||
|
</context>
|
||||||
|
|
||||||
|
<tasks>
|
||||||
|
|
||||||
|
<task type="auto">
|
||||||
|
<name>Task 1: Write unit tests for CoordinationServer</name>
|
||||||
|
<files>src/server/index.test.ts</files>
|
||||||
|
<action>
|
||||||
|
Create src/server/index.test.ts:
|
||||||
|
|
||||||
|
Test server lifecycle:
|
||||||
|
- Test start() begins listening on configured port
|
||||||
|
- Test start() throws if already running
|
||||||
|
- Test start() throws if PID file exists (another server)
|
||||||
|
- Test stop() stops the server
|
||||||
|
- Test stop() is idempotent (no error if not running)
|
||||||
|
- Test isRunning() returns correct state
|
||||||
|
|
||||||
|
Test HTTP endpoints:
|
||||||
|
- Test GET /health returns status 'ok' with uptime
|
||||||
|
- Test GET /status returns server info
|
||||||
|
- Test GET /unknown returns 404
|
||||||
|
- Test POST /health returns 405 (method not allowed)
|
||||||
|
|
||||||
|
Test PID file:
|
||||||
|
- Test PID file created on start
|
||||||
|
- Test PID file removed on stop
|
||||||
|
- Test stale PID file is cleaned up
|
||||||
|
|
||||||
|
Testing approach:
|
||||||
|
- Create server with random high port to avoid conflicts
|
||||||
|
- Use temporary directory for PID file
|
||||||
|
- Create mock ProcessManager and LogManager (they're not used in tests)
|
||||||
|
- Use fetch() or http.request() to test endpoints
|
||||||
|
- Clean up after each test (stop server, remove temp files)
|
||||||
|
</action>
|
||||||
|
<verify>npm test passes with server tests green</verify>
|
||||||
|
<done>CoordinationServer has comprehensive test coverage</done>
|
||||||
|
</task>
|
||||||
|
|
||||||
|
<task type="auto">
|
||||||
|
<name>Task 2: Add event emission to server and shutdown handler</name>
|
||||||
|
<files>src/server/index.ts, src/server/shutdown.ts</files>
|
||||||
|
<action>
|
||||||
|
Modify CoordinationServer constructor:
|
||||||
|
- Add optional eventBus parameter: EventBus | undefined
|
||||||
|
- Store as private readonly property
|
||||||
|
|
||||||
|
Add event emission in start():
|
||||||
|
- After server starts listening, emit ServerStarted:
|
||||||
|
{ type: 'server.started', timestamp: new Date(), payload: { port, host, pid: process.pid } }
|
||||||
|
|
||||||
|
Add event emission in stop():
|
||||||
|
- Before stopping, emit ServerStopped:
|
||||||
|
{ type: 'server.stopped', timestamp: new Date(), payload: { uptime } }
|
||||||
|
|
||||||
|
Modify GracefulShutdown:
|
||||||
|
- Add optional eventBus parameter
|
||||||
|
- Emit events during shutdown sequence if event bus provided:
|
||||||
|
- Could emit ShutdownInitiated, ShutdownComplete events
|
||||||
|
- Or rely on ServerStopped from CoordinationServer (simpler)
|
||||||
|
- Keep it simple: just ensure CoordinationServer emits ServerStopped
|
||||||
|
|
||||||
|
Update tests:
|
||||||
|
- Add mock EventBus to server tests
|
||||||
|
- Verify ServerStarted emitted on start
|
||||||
|
- Verify ServerStopped emitted on stop
|
||||||
|
|
||||||
|
Create src/server/shutdown.test.ts:
|
||||||
|
- Test shutdown() calls server.stop()
|
||||||
|
- Test shutdown() calls processManager.stopAll()
|
||||||
|
- Test signal handlers are installed
|
||||||
|
- Mock dependencies (server, processManager, logManager)
|
||||||
|
</action>
|
||||||
|
<verify>npm test passes with all server module tests green</verify>
|
||||||
|
<done>Server emits lifecycle events, shutdown handler tested</done>
|
||||||
|
</task>
|
||||||
|
|
||||||
|
</tasks>
|
||||||
|
|
||||||
|
<verification>
|
||||||
|
Before declaring plan complete:
|
||||||
|
- [ ] npm run build succeeds
|
||||||
|
- [ ] npm test passes (all server module tests)
|
||||||
|
- [ ] CoordinationServer accepts optional eventBus
|
||||||
|
- [ ] ServerStarted event emitted on start
|
||||||
|
- [ ] ServerStopped event emitted on stop
|
||||||
|
- [ ] GracefulShutdown has test coverage
|
||||||
|
</verification>
|
||||||
|
|
||||||
|
<success_criteria>
|
||||||
|
|
||||||
|
- All tasks completed
|
||||||
|
- All verification checks pass
|
||||||
|
- Server lifecycle events flow through event bus
|
||||||
|
- Shutdown sequence is tested
|
||||||
|
</success_criteria>
|
||||||
|
|
||||||
|
<output>
|
||||||
|
After completion, create `.planning/phases/01.1-hexagonal-architecture/01.1-05-SUMMARY.md`
|
||||||
|
</output>
|
||||||
123
.planning/phases/01.1-hexagonal-architecture/01.1-06-PLAN.md
Normal file
123
.planning/phases/01.1-hexagonal-architecture/01.1-06-PLAN.md
Normal file
@@ -0,0 +1,123 @@
|
|||||||
|
---
|
||||||
|
phase: 01.1-hexagonal-architecture
|
||||||
|
plan: 06
|
||||||
|
type: execute
|
||||||
|
wave: 3
|
||||||
|
depends_on: ["01.1-02", "01.1-05"]
|
||||||
|
files_modified: [src/cli/trpc-client.ts, src/cli/index.ts, src/server/trpc-adapter.ts, src/server/index.ts, tests/integration/cli-server.test.ts]
|
||||||
|
autonomous: true
|
||||||
|
---
|
||||||
|
|
||||||
|
<objective>
|
||||||
|
Integrate tRPC client into CLI and add HTTP adapter to server.
|
||||||
|
|
||||||
|
Purpose: Complete the tRPC contract by connecting CLI to server. This establishes the pattern for all future client-server communication.
|
||||||
|
Output: CLI communicates with server via tRPC, with integration tests proving the full flow.
|
||||||
|
</objective>
|
||||||
|
|
||||||
|
<execution_context>
|
||||||
|
@~/.claude/get-shit-done/workflows/execute-plan.md
|
||||||
|
@~/.claude/get-shit-done/templates/summary.md
|
||||||
|
</execution_context>
|
||||||
|
|
||||||
|
<context>
|
||||||
|
@.planning/PROJECT.md
|
||||||
|
@.planning/ROADMAP.md
|
||||||
|
@.planning/STATE.md
|
||||||
|
@.planning/phases/01.1-hexagonal-architecture/01.1-02-SUMMARY.md
|
||||||
|
@.planning/phases/01.1-hexagonal-architecture/01.1-05-SUMMARY.md
|
||||||
|
|
||||||
|
@src/cli/index.ts
|
||||||
|
@src/server/index.ts
|
||||||
|
@src/trpc/index.ts
|
||||||
|
</context>
|
||||||
|
|
||||||
|
<tasks>
|
||||||
|
|
||||||
|
<task type="auto">
|
||||||
|
<name>Task 1: Add tRPC HTTP adapter to server and create CLI client</name>
|
||||||
|
<files>src/server/trpc-adapter.ts, src/server/index.ts, src/cli/trpc-client.ts, package.json</files>
|
||||||
|
<action>
|
||||||
|
Install additional dependency if needed:
|
||||||
|
- npm install @trpc/client (should already be dev dep, move to regular deps)
|
||||||
|
|
||||||
|
Create src/server/trpc-adapter.ts:
|
||||||
|
- Create function to handle tRPC requests via node:http
|
||||||
|
- Use @trpc/server/adapters/fetch or manual handling
|
||||||
|
- Route /trpc/* requests to tRPC router
|
||||||
|
- Create context with eventBus, serverStartedAt, processCount
|
||||||
|
|
||||||
|
Modify CoordinationServer:
|
||||||
|
- In handleRequest(), add routing for /trpc/* paths
|
||||||
|
- Delegate to tRPC adapter
|
||||||
|
- Keep existing /health and /status routes for backwards compatibility
|
||||||
|
- tRPC endpoints: /trpc/health, /trpc/status
|
||||||
|
|
||||||
|
Create src/cli/trpc-client.ts:
|
||||||
|
- Create tRPC client using @trpc/client
|
||||||
|
- Configure with httpBatchLink pointing to http://127.0.0.1:{port}/trpc
|
||||||
|
- Export typed client
|
||||||
|
- Export helper function: createTrpcClient(port: number)
|
||||||
|
|
||||||
|
Key: The existing HTTP endpoints (/health, /status) remain for curl/debugging.
|
||||||
|
CLI will use tRPC endpoints for type safety.
|
||||||
|
</action>
|
||||||
|
<verify>npm run build succeeds</verify>
|
||||||
|
<done>tRPC adapter integrated into server, CLI client created</done>
|
||||||
|
</task>
|
||||||
|
|
||||||
|
<task type="auto">
|
||||||
|
<name>Task 2: Update CLI status command and write integration tests</name>
|
||||||
|
<files>src/cli/index.ts, tests/integration/cli-server.test.ts</files>
|
||||||
|
<action>
|
||||||
|
Update src/cli/index.ts:
|
||||||
|
- Modify status command to use tRPC client instead of placeholder
|
||||||
|
- Create tRPC client with default port (3847) or env var
|
||||||
|
- Call health procedure and display result
|
||||||
|
- Handle connection errors gracefully (server not running)
|
||||||
|
|
||||||
|
Keep the placeholder message if tRPC call fails:
|
||||||
|
```
|
||||||
|
Server not running or unreachable. Start with: cw --server
|
||||||
|
```
|
||||||
|
|
||||||
|
Create tests/integration/cli-server.test.ts:
|
||||||
|
- Test full flow: start server, call tRPC from client, verify response
|
||||||
|
- Test health procedure returns correct data
|
||||||
|
- Test status procedure returns correct data
|
||||||
|
- Test client handles server not running
|
||||||
|
|
||||||
|
Integration test approach:
|
||||||
|
- Start CoordinationServer on random port in beforeAll
|
||||||
|
- Create tRPC client pointing to that port
|
||||||
|
- Run procedures, verify responses
|
||||||
|
- Stop server in afterAll
|
||||||
|
|
||||||
|
These are INTEGRATION tests, not unit tests - they test the full stack.
|
||||||
|
</action>
|
||||||
|
<verify>npm test passes with all tests including integration tests</verify>
|
||||||
|
<done>CLI uses tRPC for status, integration tests prove full flow works</done>
|
||||||
|
</task>
|
||||||
|
|
||||||
|
</tasks>
|
||||||
|
|
||||||
|
<verification>
|
||||||
|
Before declaring plan complete:
|
||||||
|
- [ ] npm run build succeeds
|
||||||
|
- [ ] npm test passes (all tests including integration)
|
||||||
|
- [ ] cw status connects to server via tRPC
|
||||||
|
- [ ] tRPC endpoints work alongside HTTP endpoints
|
||||||
|
- [ ] Full flow tested: server start → tRPC call → response
|
||||||
|
</verification>
|
||||||
|
|
||||||
|
<success_criteria>
|
||||||
|
|
||||||
|
- All tasks completed
|
||||||
|
- All verification checks pass
|
||||||
|
- CLI communicates with server via type-safe tRPC
|
||||||
|
- Integration tests prove the architecture works end-to-end
|
||||||
|
</success_criteria>
|
||||||
|
|
||||||
|
<output>
|
||||||
|
After completion, create `.planning/phases/01.1-hexagonal-architecture/01.1-06-SUMMARY.md`
|
||||||
|
</output>
|
||||||
Reference in New Issue
Block a user