docs(03): create phase plan

Phase 03: Git Integration
- 2 plans in 2 waves
- 0 parallel, 2 sequential
- Ready for execution
This commit is contained in:
Lukas May
2026-01-30 19:20:24 +01:00
parent 115866ccc6
commit e2567ded0a
2 changed files with 294 additions and 0 deletions

View File

@@ -0,0 +1,106 @@
---
phase: 03-git-integration
plan: 01
type: execute
wave: 1
depends_on: []
files_modified: [src/events/types.ts, src/git/types.ts, src/git/index.ts]
autonomous: true
---
<objective>
Create git domain events and WorktreeManager port interface.
Purpose: Establish typed foundation for git worktree operations following hexagonal architecture.
Output: Git events added to event system, WorktreeManager port interface ready for adapter implementation.
</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
# Prior phase context - established patterns
@.planning/phases/02-data-layer/02-02-SUMMARY.md
# Existing event system to extend
@src/events/types.ts
@src/events/bus.ts
@src/events/index.ts
</context>
<tasks>
<task type="auto">
<name>Task 1: Add git domain events to event types</name>
<files>src/events/types.ts, src/events/index.ts</files>
<action>
Add git worktree events following the established DomainEvent pattern:
1. In src/events/types.ts, add these typed event interfaces after the existing Log Events section:
- WorktreeCreatedEvent (type: 'worktree:created', payload: { worktreeId, branch, path })
- WorktreeRemovedEvent (type: 'worktree:removed', payload: { worktreeId, branch })
- WorktreeMergedEvent (type: 'worktree:merged', payload: { worktreeId, sourceBranch, targetBranch })
- WorktreeConflictEvent (type: 'worktree:conflict', payload: { worktreeId, sourceBranch, targetBranch, conflictingFiles })
2. Add all new events to the DomainEventMap union type
Follow the exact pattern of ProcessSpawnedEvent, ProcessStoppedEvent etc. - extends DomainEvent, specific type literal, typed payload.
</action>
<verify>npm run build passes with no TypeScript errors</verify>
<done>Four git events defined and added to DomainEventMap union</done>
</task>
<task type="auto">
<name>Task 2: Create WorktreeManager port interface</name>
<files>src/git/types.ts, src/git/index.ts</files>
<action>
Create new git module with port interface:
1. Create src/git/types.ts with:
- Worktree type: { id: string, branch: string, path: string, isMainWorktree: boolean }
- WorktreeDiff type: { files: Array<{ path: string, status: 'added' | 'modified' | 'deleted' }>, summary: string }
- MergeResult type: { success: boolean, conflicts?: string[], message: string }
- WorktreeManager interface (PORT) with methods:
* create(id: string, branch: string, baseBranch?: string): Promise<Worktree>
* remove(id: string): Promise<void>
* list(): Promise<Worktree[]>
* get(id: string): Promise<Worktree | null>
* diff(id: string): Promise<WorktreeDiff>
* merge(id: string, targetBranch: string): Promise<MergeResult>
2. Create src/git/index.ts that re-exports all types from types.ts
Follow the EventBus pattern - interface is the PORT, implementation will be the ADAPTER. Include JSDoc comments explaining the port-adapter relationship.
</action>
<verify>npm run build passes, new types are importable from src/git</verify>
<done>WorktreeManager port interface defined with all method signatures for CRUD, diff, and merge operations</done>
</task>
</tasks>
<verification>
Before declaring plan complete:
- [ ] npm run build succeeds without errors
- [ ] Git events visible in DomainEventMap type
- [ ] WorktreeManager interface importable from src/git
- [ ] All types have proper JSDoc documentation
</verification>
<success_criteria>
- All tasks completed
- All verification checks pass
- No errors or warnings introduced
- Git events follow established DomainEvent pattern exactly
- WorktreeManager interface covers all 4 requirements (GIT-01 through GIT-04)
</success_criteria>
<output>
After completion, create `.planning/phases/03-git-integration/03-01-SUMMARY.md`
</output>

View File

@@ -0,0 +1,188 @@
---
phase: 03-git-integration
plan: 02
type: execute
wave: 2
depends_on: ["03-01"]
files_modified: [src/git/manager.ts, src/git/manager.test.ts, src/git/index.ts, package.json]
autonomous: true
---
<objective>
Implement WorktreeManager adapter with simple-git and comprehensive tests.
Purpose: Provide working git worktree operations that Phase 4 (Agent Lifecycle) will use to isolate agent work.
Output: Fully tested WorktreeManager implementation covering create, remove, list, diff, and merge operations.
</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
# Prior plan in this phase
@.planning/phases/03-git-integration/03-01-SUMMARY.md
# Git types we're implementing
@src/git/types.ts
# Event bus for emitting git events
@src/events/types.ts
@src/events/bus.ts
# Test pattern reference
@src/db/repositories/drizzle/test-helpers.ts
</context>
<tasks>
<task type="auto">
<name>Task 1: Install simple-git and create WorktreeManager adapter with CRUD</name>
<files>package.json, src/git/manager.ts, src/git/index.ts</files>
<action>
1. Install simple-git: npm install simple-git
2. Create src/git/manager.ts with SimpleGitWorktreeManager class:
- Constructor takes: repoPath (string), eventBus (optional EventBus)
- Private simpleGit instance initialized with repoPath
- Private worktreesDir computed as path.join(repoPath, '.cw-worktrees')
3. Implement CRUD methods:
- create(id, branch, baseBranch = 'main'):
* Compute worktree path: path.join(worktreesDir, id)
* Run: git worktree add -b {branch} {path} {baseBranch}
* Emit worktree:created event if eventBus provided
* Return Worktree object
- remove(id):
* Compute worktree path
* Run: git worktree remove {path} --force
* Emit worktree:removed event if eventBus provided
- list():
* Run: git worktree list --porcelain
* Parse output into Worktree[] (skip main worktree or mark isMainWorktree: true)
- get(id):
* Call list(), find by id (match path ending with id)
* Return null if not found
4. Update src/git/index.ts to export SimpleGitWorktreeManager
Use async/await throughout. Handle errors by throwing with descriptive messages. Follow the EventEmitterBus pattern - eventBus is optional dependency injection.
</action>
<verify>npm run build passes, SimpleGitWorktreeManager is importable</verify>
<done>WorktreeManager adapter created with create, remove, list, get methods</done>
</task>
<task type="auto">
<name>Task 2: Implement diff and merge operations</name>
<files>src/git/manager.ts</files>
<action>
Add remaining methods to SimpleGitWorktreeManager:
1. diff(id):
- Get worktree by id (throw if not found)
- cd into worktree path
- Run: git diff --name-status HEAD
- Parse output into WorktreeDiff format:
* Map each line to { path, status } based on status letter (A=added, M=modified, D=deleted)
* Generate summary: "{n} files changed"
- Also run: git diff --stat HEAD for the summary line
2. merge(id, targetBranch):
- Get worktree by id (throw if not found)
- In MAIN repo (not worktree), run:
* git checkout {targetBranch}
* git merge {worktree.branch} --no-edit
- If merge succeeds:
* Emit worktree:merged event
* Return { success: true, message: 'Merged successfully' }
- If merge fails with conflicts:
* Parse conflicting files from git status
* Emit worktree:conflict event
* Run git merge --abort to clean up
* Return { success: false, conflicts: [...], message: 'Merge conflicts detected' }
Handle edge cases:
- Worktree not found: throw Error('Worktree not found: {id}')
- No changes to diff: return empty WorktreeDiff
- Branch doesn't exist: let git error propagate with clear message
</action>
<verify>npm run build passes</verify>
<done>diff() and merge() methods implemented with proper event emission and conflict handling</done>
</task>
<task type="auto">
<name>Task 3: Write tests for WorktreeManager</name>
<files>src/git/manager.test.ts</files>
<action>
Create comprehensive tests following the repository test pattern:
1. Test setup:
- Create temp directory for each test (use Node.js fs.mkdtemp)
- Initialize git repo in temp dir: git init, git commit --allow-empty -m "Initial"
- Create SimpleGitWorktreeManager with temp repo path
- Cleanup: remove temp dir after each test
2. Test cases for CRUD:
- create() creates worktree at expected path
- create() creates branch from specified base
- create() emits worktree:created event
- remove() removes worktree directory
- remove() emits worktree:removed event
- list() returns all worktrees
- list() marks main worktree correctly
- get() returns worktree by id
- get() returns null for non-existent id
3. Test cases for diff:
- diff() returns empty for clean worktree
- diff() detects added files
- diff() detects modified files
- diff() detects deleted files
4. Test cases for merge:
- merge() succeeds with clean merge
- merge() emits worktree:merged event on success
- merge() detects conflicts and returns them
- merge() emits worktree:conflict event on conflict
- merge() aborts and cleans up after conflict
Use vitest (already in project). Create helper function createTestRepo() similar to createTestDatabase() pattern.
</action>
<verify>npm test passes with all new tests</verify>
<done>20+ tests covering all WorktreeManager operations including edge cases</done>
</task>
</tasks>
<verification>
Before declaring plan complete:
- [ ] npm run build succeeds
- [ ] npm test passes all tests (including new git tests)
- [ ] WorktreeManager can create/remove worktrees in a test repo
- [ ] Events are emitted for all git operations
- [ ] Merge conflicts are properly detected and reported
</verification>
<success_criteria>
- All tasks completed
- All verification checks pass
- No errors or warnings introduced
- WorktreeManager satisfies all 4 requirements:
- GIT-01: create() provides isolated worktree per agent
- GIT-02: diff() previews agent's changes
- GIT-03: merge() integrates changes to target branch
- GIT-04: remove() cleans up worktree
</success_criteria>
<output>
After completion, create `.planning/phases/03-git-integration/03-02-SUMMARY.md`
</output>