refactor: Restructure monorepo to apps/server/ and apps/web/ layout

Move src/ → apps/server/ and packages/web/ → apps/web/ to adopt
standard monorepo conventions (apps/ for runnable apps, packages/
for reusable libraries). Update all config files, shared package
imports, test fixtures, and documentation to reflect new paths.

Key fixes:
- Update workspace config to ["apps/*", "packages/*"]
- Update tsconfig.json rootDir/include for apps/server/
- Add apps/web/** to vitest exclude list
- Update drizzle.config.ts schema path
- Fix ensure-schema.ts migration path detection (3 levels up in dev,
  2 levels up in dist)
- Fix tests/integration/cli-server.test.ts import paths
- Update packages/shared imports to apps/server/ paths
- Update all docs/ files with new paths
This commit is contained in:
Lukas May
2026-03-03 11:22:53 +01:00
parent 8c38d958ce
commit 34578d39c6
535 changed files with 75452 additions and 687 deletions

View File

@@ -1,6 +1,6 @@
# Agent Module
`src/agent/` — Agent lifecycle management, output parsing, multi-provider support, and account failover.
`apps/server/agent/` — Agent lifecycle management, output parsing, multi-provider support, and account failover.
## File Inventory
@@ -169,7 +169,7 @@ Agents can communicate with each other via the `conversations` table, coordinate
## Prompt Architecture
Mode-specific prompts in `prompts/` use XML tags as top-level structural delimiters, with markdown formatting inside tags. This separates first-order instructions from second-order content (task descriptions, examples, templates) per Anthropic best practices. The old `src/agent/prompts.ts` (flat markdown) has been deleted.
Mode-specific prompts in `prompts/` use XML tags as top-level structural delimiters, with markdown formatting inside tags. This separates first-order instructions from second-order content (task descriptions, examples, templates) per Anthropic best practices. The old `apps/server/agent/prompts.ts` (flat markdown) has been deleted.
### XML Tag Structure
@@ -217,4 +217,4 @@ Examples within mode-specific tags use `<examples>` > `<example label="good">` /
### Execute Prompt Dispatch
`buildExecutePrompt(taskDescription?)` accepts an optional task description wrapped in a `<task>` tag. The dispatch manager (`src/dispatch/manager.ts`) wraps `task.description || task.name` in `buildExecutePrompt()` so execute agents receive full system context alongside their task. The `<workspace>` and `<inter_agent_communication>` blocks are appended by the agent manager at spawn time.
`buildExecutePrompt(taskDescription?)` accepts an optional task description wrapped in a `<task>` tag. The dispatch manager (`apps/server/dispatch/manager.ts`) wraps `task.description || task.name` in `buildExecutePrompt()` so execute agents receive full system context alongside their task. The `<workspace>` and `<inter_agent_communication>` blocks are appended by the agent manager at spawn time.

View File

@@ -23,7 +23,7 @@ CLI (cw)
├── CoordinationManager (merge queue, conflict resolution)
└── PreviewManager (Docker-based preview deployments)
Web UI (packages/web/)
Web UI (apps/web/)
└── React 19 + TanStack Router + tRPC React Query
├── Initiative management (CRUD, projects)
├── Page editor (Tiptap rich text)
@@ -36,9 +36,9 @@ Web UI (packages/web/)
### Hexagonal Architecture (Ports & Adapters)
Every data-access layer follows this pattern:
- **Port** (interface): `src/db/repositories/<entity>-repository.ts`
- **Adapter** (implementation): `src/db/repositories/drizzle/<entity>-repository.ts`
- Re-exported from barrel files so consumers import from `src/db/`
- **Port** (interface): `apps/server/db/repositories/<entity>-repository.ts`
- **Adapter** (implementation): `apps/server/db/repositories/drizzle/<entity>-repository.ts`
- Re-exported from barrel files so consumers import from `apps/server/db/`
### Event-Driven Communication
All inter-module communication flows through a typed `EventBus`:
@@ -55,20 +55,20 @@ Agent providers (Claude, Codex, etc.) are defined as configuration objects, not
| Module | Path | Purpose | Docs |
|--------|------|---------|------|
| Agent | `src/agent/` | Agent lifecycle, output parsing, accounts | [agent.md](agent.md) |
| Database | `src/db/` | Schema, repositories, migrations | [database.md](database.md) |
| Server & API | `src/server/`, `src/trpc/` | HTTP server, tRPC procedures | [server-api.md](server-api.md) |
| Frontend | `packages/web/` | React UI, components, hooks | [frontend.md](frontend.md) |
| CLI & Config | `src/cli/`, `src/config/` | CLI commands, workspace config | [cli-config.md](cli-config.md) |
| Dispatch | `src/dispatch/` | Task/phase queue and dispatch | [dispatch-events.md](dispatch-events.md) |
| Coordination | `src/coordination/` | Merge queue, conflict resolution | [server-api.md](server-api.md#coordination) |
| Git | `src/git/` | Worktree management, project clones | [git-process-logging.md](git-process-logging.md) |
| Process | `src/process/` | Child process spawn/track/stop | [git-process-logging.md](git-process-logging.md) |
| Logging | `src/logger/`, `src/logging/` | Structured logging, file capture | [git-process-logging.md](git-process-logging.md) |
| Events | `src/events/` | EventBus, typed event system | [dispatch-events.md](dispatch-events.md) |
| Agent | `apps/server/agent/` | Agent lifecycle, output parsing, accounts | [agent.md](agent.md) |
| Database | `apps/server/db/` | Schema, repositories, migrations | [database.md](database.md) |
| Server & API | `apps/server/server/`, `apps/server/trpc/` | HTTP server, tRPC procedures | [server-api.md](server-api.md) |
| Frontend | `apps/web/` | React UI, components, hooks | [frontend.md](frontend.md) |
| CLI & Config | `apps/server/cli/`, `apps/server/config/` | CLI commands, workspace config | [cli-config.md](cli-config.md) |
| Dispatch | `apps/server/dispatch/` | Task/phase queue and dispatch | [dispatch-events.md](dispatch-events.md) |
| Coordination | `apps/server/coordination/` | Merge queue, conflict resolution | [server-api.md](server-api.md#coordination) |
| Git | `apps/server/git/` | Worktree management, project clones | [git-process-logging.md](git-process-logging.md) |
| Process | `apps/server/process/` | Child process spawn/track/stop | [git-process-logging.md](git-process-logging.md) |
| Logging | `apps/server/logger/`, `apps/server/logging/` | Structured logging, file capture | [git-process-logging.md](git-process-logging.md) |
| Events | `apps/server/events/` | EventBus, typed event system | [dispatch-events.md](dispatch-events.md) |
| Shared | `packages/shared/` | Types shared between frontend/backend | [frontend.md](frontend.md) |
| Preview | `src/preview/` | Docker-based preview deployments | [preview.md](preview.md) |
| Tests | `src/test/` | E2E, integration, fixtures | [testing.md](testing.md) |
| Preview | `apps/server/preview/` | Docker-based preview deployments | [preview.md](preview.md) |
| Tests | `apps/server/test/` | E2E, integration, fixtures | [testing.md](testing.md) |
## Entity Relationships

View File

@@ -1,10 +1,10 @@
# CLI & Configuration
`src/cli/` — CLI commands, `src/config/` — workspace configuration, `src/bin/` — entry point.
`apps/server/cli/` — CLI commands, `apps/server/config/` — workspace configuration, `apps/server/bin/` — entry point.
## Entry Point
`src/bin/cw.ts` — hashbang entry that imports and runs the CLI.
`apps/server/bin/cw.ts` — hashbang entry that imports and runs the CLI.
## CLI Framework
@@ -136,7 +136,7 @@ This includes all repositories, managers, and the credential manager. The server
## Workspace Configuration
`src/config/` module:
`apps/server/config/` module:
### .cwrc File
JSON file at workspace root that marks a `cw` workspace:

View File

@@ -4,10 +4,10 @@ This project uses [drizzle-kit](https://orm.drizzle.team/kit-docs/overview) for
## Overview
- **Schema definition:** `src/db/schema.ts` (drizzle-orm table definitions)
- **Schema definition:** `apps/server/db/schema.ts` (drizzle-orm table definitions)
- **Migration output:** `drizzle/` directory (SQL files + meta journal)
- **Config:** `drizzle.config.ts`
- **Runtime migrator:** `src/db/ensure-schema.ts` (calls `drizzle-orm/better-sqlite3/migrator`)
- **Runtime migrator:** `apps/server/db/ensure-schema.ts` (calls `drizzle-orm/better-sqlite3/migrator`)
## How It Works
@@ -17,7 +17,7 @@ On every server startup, `ensureSchema(db)` runs all pending migrations from the
### Making schema changes
1. Edit `src/db/schema.ts` with your table/column changes
1. Edit `apps/server/db/schema.ts` with your table/column changes
2. Generate a migration:
```bash
npx drizzle-kit generate
@@ -29,7 +29,7 @@ On every server startup, `ensureSchema(db)` runs all pending migrations from the
Migrations are applied automatically on server startup. No manual step needed.
For tests, the same `ensureSchema()` function is called on in-memory SQLite databases in `src/db/repositories/drizzle/test-helpers.ts`.
For tests, the same `ensureSchema()` function is called on in-memory SQLite databases in `apps/server/db/repositories/drizzle/test-helpers.ts`.
### Checking migration status

View File

@@ -1,13 +1,13 @@
# Database Module
`src/db/` — SQLite database via better-sqlite3 + Drizzle ORM with hexagonal architecture.
`apps/server/db/` — SQLite database via better-sqlite3 + Drizzle ORM with hexagonal architecture.
## Architecture
- **Schema**: `src/db/schema.ts` — all tables, columns, relations
- **Ports** (interfaces): `src/db/repositories/*.ts` — 10 repository interfaces
- **Adapters** (implementations): `src/db/repositories/drizzle/*.ts` — 10 Drizzle adapters
- **Barrel exports**: `src/db/index.ts` re-exports everything
- **Schema**: `apps/server/db/schema.ts` — all tables, columns, relations
- **Ports** (interfaces): `apps/server/db/repositories/*.ts` — 10 repository interfaces
- **Adapters** (implementations): `apps/server/db/repositories/drizzle/*.ts` — 10 Drizzle adapters
- **Barrel exports**: `apps/server/db/index.ts` re-exports everything
All adapters use nanoid() for IDs, auto-manage timestamps, and use Drizzle's `.returning()` for atomic reads after writes.

View File

@@ -1,10 +1,10 @@
# Dispatch & Events
`src/dispatch/` — Task and phase dispatch queues. `src/events/` — Typed event bus.
`apps/server/dispatch/` — Task and phase dispatch queues. `apps/server/events/` — Typed event bus.
## Event Bus
`src/events/` — Typed pub/sub system for inter-module communication.
`apps/server/events/` — Typed pub/sub system for inter-module communication.
### Architecture
- **Port**: `EventBus` interface with `emit(event)` and `on(type, handler)`
@@ -46,7 +46,7 @@ AccountCredentialsRefreshedEvent { accountId, expiresAt, previousExpiresAt? }
## Task Dispatch
`src/dispatch/` — In-memory queue with dependency-ordered dispatch.
`apps/server/dispatch/` — In-memory queue with dependency-ordered dispatch.
### Architecture
- **Port**: `DispatchManager` interface

View File

@@ -1,6 +1,6 @@
# Frontend
`packages/web/` — React web UI for managing initiatives, agents, and content.
`apps/web/` — React web UI for managing initiatives, agents, and content.
## Tech Stack
@@ -134,4 +134,4 @@ Configured in `src/lib/trpc.ts`. Uses `@trpc/react-query` with TanStack Query fo
`packages/shared/` exports:
- `sortByPriorityAndQueueTime()` — priority-based task sorting
- `topologicalSort()` / `groupByPipelineColumn()` — phase DAG layout
- Shared type re-exports from `packages/shared/src/types.ts`
- Shared type re-exports from `packages/shared/src/types.ts` (which re-exports from `apps/server/`)

View File

@@ -2,7 +2,7 @@
Three infrastructure modules supporting agent execution.
## Git Module (`src/git/`)
## Git Module (`apps/server/git/`)
Manages git worktrees for isolated agent workspaces.
@@ -31,7 +31,7 @@ Worktrees stored in `.cw-worktrees/` subdirectory of the repo. Each agent gets a
4. On conflict: `git merge --abort`, emit `worktree:conflict` with conflicting file list
5. Restore original branch
### BranchManager (`src/git/branch-manager.ts`)
### BranchManager (`apps/server/git/branch-manager.ts`)
- **Port**: `BranchManager` interface
- **Adapter**: `SimpleGitBranchManager` using simple-git
@@ -56,7 +56,7 @@ Worktrees stored in `.cw-worktrees/` subdirectory of the repo. Each agent gets a
---
## Process Module (`src/process/`)
## Process Module (`apps/server/process/`)
Spawns, tracks, and controls child processes.
@@ -85,13 +85,13 @@ Spawns, tracks, and controls child processes.
---
## Logger Module (`src/logger/`)
## Logger Module (`apps/server/logger/`)
Structured logging via **pino**.
### Usage
```typescript
import { createModuleLogger } from './logger/index.js';
import { createModuleLogger } from '../logger/index.js';
const log = createModuleLogger('my-module');
log.info({ key: 'value' }, 'message');
```
@@ -109,7 +109,7 @@ log.info({ key: 'value' }, 'message');
---
## Logging Module (`src/logging/`)
## Logging Module (`apps/server/logging/`)
File-based per-process output capture (separate from pino).

View File

@@ -6,7 +6,7 @@ Codewalk District uses [pino](https://getpino.io/) for structured JSON logging o
- **pino** writes structured JSON to **stderr** so CLI user output on stdout stays clean
- **console.log** remains for CLI command handlers (user-facing output on stdout)
- The `src/logging/` module (ProcessLogWriter/LogManager) is a separate concern — it captures per-agent process stdout/stderr to files
- The `apps/server/logging/` module (ProcessLogWriter/LogManager) is a separate concern — it captures per-agent process stdout/stderr to files
## Environment Variables
@@ -42,12 +42,12 @@ log.debug({ path, count }, 'processing items');
| Module | Used in |
|--------|---------|
| `agent-manager` | `src/agent/manager.ts` |
| `dispatch` | `src/dispatch/manager.ts` |
| `http` | `src/server/index.ts` |
| `server` | `src/cli/index.ts` (startup) |
| `git` | `src/git/manager.ts`, `src/git/clone.ts`, `src/git/project-clones.ts` |
| `db` | `src/db/ensure-schema.ts` |
| `agent-manager` | `apps/server/agent/manager.ts` |
| `dispatch` | `apps/server/dispatch/manager.ts` |
| `http` | `apps/server/server/index.ts` |
| `server` | `apps/server/cli/index.ts` (startup) |
| `git` | `apps/server/git/manager.ts`, `apps/server/git/clone.ts`, `apps/server/git/project-clones.ts` |
| `db` | `apps/server/db/ensure-schema.ts` |
## Testing

View File

@@ -1,6 +1,6 @@
# Preview Deployments
`src/preview/` — Docker-based preview deployments for reviewing changes in a running application.
`apps/server/preview/` — Docker-based preview deployments for reviewing changes in a running application.
## Overview
@@ -56,7 +56,7 @@ services:
frontend:
build:
context: .
dockerfile: packages/web/Dockerfile
dockerfile: apps/web/Dockerfile
port: 3000
route: /
healthcheck:
@@ -160,10 +160,10 @@ Polls `getPreviewStatus` with `refetchInterval: 3000` while active.
## Container Wiring
- `PreviewManager` instantiated in `src/container.ts` with `(projectRepository, eventBus, workspaceRoot)`
- `PreviewManager` instantiated in `apps/server/container.ts` with `(projectRepository, eventBus, workspaceRoot)`
- Added to `Container` interface and `toContextDeps()`
- `GracefulShutdown` calls `previewManager.stopAll()` during shutdown
- `requirePreviewManager(ctx)` helper in `src/trpc/routers/_helpers.ts`
- `requirePreviewManager(ctx)` helper in `apps/server/trpc/routers/_helpers.ts`
## Dependencies

View File

@@ -1,6 +1,6 @@
# Server & API Module
`src/server/` — HTTP server, `src/trpc/` — tRPC procedures, `src/coordination/` — merge queue.
`apps/server/server/` — HTTP server, `apps/server/trpc/` — tRPC procedures, `apps/server/coordination/` — merge queue.
## HTTP Server
@@ -194,7 +194,7 @@ Subscriptions use `eventBusIterable()` — queue-based async generator, max 1000
## Coordination Module
`src/coordination/` manages merge queue:
`apps/server/coordination/` manages merge queue:
- **CoordinationManager** port: `queueMerge`, `getNextMergeable`, `processMerges`, `handleConflict`, `getQueueState`
- **DefaultCoordinationManager** adapter: in-memory queue, dependency-ordered processing

View File

@@ -1,6 +1,6 @@
# Testing
`src/test/` — Test infrastructure, fixtures, and test suites.
`apps/server/test/` — Test infrastructure, fixtures, and test suites.
## Framework
@@ -10,15 +10,15 @@
### Unit Tests
Located alongside source files (`*.test.ts`):
- `src/agent/*.test.ts` — Manager, output handler, completion detection, file I/O, process manager
- `src/db/repositories/drizzle/*.test.ts` — Repository adapters
- `src/dispatch/*.test.ts` — Dispatch manager
- `src/git/manager.test.ts` — Worktree operations
- `src/process/*.test.ts` — Process registry and manager
- `src/logging/*.test.ts` — Log manager and writer
- `apps/server/agent/*.test.ts` — Manager, output handler, completion detection, file I/O, process manager
- `apps/server/db/repositories/drizzle/*.test.ts` — Repository adapters
- `apps/server/dispatch/*.test.ts` — Dispatch manager
- `apps/server/git/manager.test.ts` — Worktree operations
- `apps/server/process/*.test.ts` — Process registry and manager
- `apps/server/logging/*.test.ts` — Log manager and writer
### E2E Tests (Mocked Agents)
`src/test/e2e/`:
`apps/server/test/e2e/`:
| File | Scenarios |
|------|-----------|
| `happy-path.test.ts` | Single task, parallel, complex flows |
@@ -32,14 +32,14 @@ Located alongside source files (`*.test.ts`):
These use `MockAgentManager` which bypasses the real subprocess pipeline. They test dispatch/coordination logic only.
### Cassette Tests (Pipeline Integration, Zero API Cost)
`src/test/cassette/` — Tests the full agent execution pipeline using pre-recorded cassettes.
`apps/server/test/cassette/` — Tests the full agent execution pipeline using pre-recorded cassettes.
Unlike E2E tests, cassette tests exercise the real `ProcessManager → FileTailer → OutputHandler → SignalManager` path. Unlike real provider tests, they cost nothing to run in CI.
See **[Cassette System](#cassette-system)** below for full documentation.
### Integration Tests (Real Providers)
`src/test/integration/real-providers/`**skipped by default** (cost real money):
`apps/server/test/integration/real-providers/`**skipped by default** (cost real money):
| File | Provider | Cost |
|------|----------|------|
| `claude-manager.test.ts` | Claude CLI | ~$0.10 |
@@ -51,7 +51,7 @@ Enable with env vars: `REAL_CLAUDE_TESTS=1`, `REAL_CODEX_TESTS=1`
## Test Infrastructure
### TestHarness (`src/test/harness.ts`)
### TestHarness (`apps/server/test/harness.ts`)
Central test utility providing:
- In-memory SQLite database with schema applied
- All 10 repository instances
@@ -61,7 +61,7 @@ Central test utility providing:
- `DefaultDispatchManager` and `DefaultPhaseDispatchManager`
- 25+ helper methods for test scenarios
### Fixtures (`src/test/fixtures.ts`)
### Fixtures (`apps/server/test/fixtures.ts`)
Pre-built task hierarchies for testing:
| Fixture | Structure |
|---------|-----------|
@@ -69,7 +69,7 @@ Pre-built task hierarchies for testing:
| `PARALLEL_FIXTURE` | 1 initiative → 1 phase → 2 groups → 4 independent tasks |
| `COMPLEX_FIXTURE` | 1 initiative → 2 phases → 4 groups → cross-phase dependencies |
### Real Provider Harness (`src/test/integration/real-providers/harness.ts`)
### Real Provider Harness (`apps/server/test/integration/real-providers/harness.ts`)
- Creates real database, real agent manager with real CLI tools
- Provides `describeRealClaude()` / `describeRealCodex()` that skip when env var not set
- `MINIMAL_PROMPTS` — cheap prompts for testing output parsing
@@ -85,23 +85,23 @@ See **[test-inventory.md](test-inventory.md)** for a complete catalog of every t
npm test
# Specific test file
npm test -- src/agent/manager.test.ts
npm test -- apps/server/agent/manager.test.ts
# Cassette tests — replay pre-recorded cassettes (no API cost)
npm test -- src/test/cassette/
npm test -- apps/server/test/cassette/
# Record new cassettes locally (requires real Claude CLI)
CW_CASSETTE_RECORD=1 npm test -- src/test/integration/real-providers/claude-manager.test.ts
CW_CASSETTE_RECORD=1 npm test -- apps/server/test/integration/real-providers/claude-manager.test.ts
# Real provider tests (costs money!)
REAL_CLAUDE_TESTS=1 npm test -- src/test/integration/real-providers/ --test-timeout=300000
REAL_CLAUDE_TESTS=1 npm test -- apps/server/test/integration/real-providers/ --test-timeout=300000
```
---
## Cassette System
`src/test/cassette/` — VCR-style recording and replay for the agent subprocess pipeline.
`apps/server/test/cassette/` — VCR-style recording and replay for the agent subprocess pipeline.
### Why it exists
@@ -223,7 +223,7 @@ describe('agent pipeline (cassette)', () => {
### Cassette directory
```
src/test/cassettes/
apps/server/test/cassettes/
<hash>.json ← committed to git; one file per recorded scenario
.gitkeep
```