Files
Codewalkers/docs/git-process-logging.md
Lukas May c58e0ea77e feat: Redesign review tab with phase selection, commit navigation, and consolidated toolbar
- Add BranchManager.listCommits() and diffCommit() for commit-level navigation
- Add getPhaseReviewCommits and getCommitDiff tRPC procedures
- New ReviewHeader: consolidated toolbar with phase selector pills, branch info,
  stats, integrated preview controls, and approve/reject actions
- New CommitNav: horizontal commit strip with "All changes" + individual commits,
  each showing hash, message, and change stats
- Slim down ReviewSidebar: file list only with dimming for out-of-scope files
  when viewing a single commit
- ReviewTab orchestrates all pieces in a single bordered card layout
2026-03-05 10:20:43 +01:00

4.7 KiB

Git, Process, and Logging Modules

Three infrastructure modules supporting agent execution.

Git Module (apps/server/git/)

Manages git worktrees for isolated agent workspaces.

Architecture

  • Port: WorktreeManager interface
  • Adapter: SimpleGitWorktreeManager using simple-git library

WorktreeManager Methods

Method Purpose
create(id, branch, baseBranch?) Create worktree with new branch (default base: 'main')
remove(id) Clean up worktree directory
list() All worktrees including main
get(id) Specific worktree by ID
diff(id) Changed files vs HEAD
merge(id, targetBranch) Merge worktree branch into target

Worktree Storage

Worktrees stored in .cw-worktrees/ subdirectory of the repo. Each agent gets a worktree at .cw-worktrees/agent/<alias>/.

Merge Flow

  1. Check out target branch
  2. git merge <source> --no-edit
  3. On success: emit worktree:merged
  4. On conflict: git merge --abort, emit worktree:conflict with conflicting file list
  5. Restore original branch

BranchManager (apps/server/git/branch-manager.ts)

  • Port: BranchManager interface
  • Adapter: SimpleGitBranchManager using simple-git
Method Purpose
ensureBranch(repoPath, branch, baseBranch) Create branch from base if it doesn't exist (idempotent)
mergeBranch(repoPath, source, target) Merge via ephemeral worktree, returns conflict info
diffBranches(repoPath, base, head) Three-dot diff between branches
deleteBranch(repoPath, branch) Delete local branch (no-op if missing)
branchExists(repoPath, branch) Check local branches
remoteBranchExists(repoPath, branch) Check remote tracking branches (origin/<branch>)
listCommits(repoPath, base, head) List commits head has that base doesn't (with stats)
diffCommit(repoPath, commitHash) Get unified diff for a single commit

remoteBranchExists is used by registerProject and updateProject to validate that a project's default branch actually exists in the cloned repository before saving.

Project Clones

  • cloneProject(url, destPath) — Simple git clone wrapper
  • ensureProjectClone(project, workspaceRoot) — Idempotent: checks if clone exists, clones if not
  • getProjectCloneDir(name, id) — Canonical path: repos/<sanitized-name>-<id>/

Events Emitted

worktree:created, worktree:removed, worktree:merged, worktree:conflict


Process Module (apps/server/process/)

Spawns, tracks, and controls child processes.

Classes

ProcessRegistry — In-memory metadata store:

  • register(info), unregister(id), get(id), getAll(), getByPid(pid), updateStatus(id, status)

ProcessManager — Lifecycle management:

Method Purpose
spawn(options) Spawn detached process (survives parent exit)
stop(id) SIGTERM → wait 5s → SIGKILL
stopAll() Stop all running processes in parallel
restart(id) Stop + re-spawn with same options
isRunning(id) Check with process.kill(pid, 0)

Spawn Details

  • Uses execa with detached: true, stdio: 'ignore'
  • Calls subprocess.unref() so parent can exit
  • Exit handler updates registry and emits events

Events Emitted

process:spawned, process:stopped, process:crashed


Logger Module (apps/server/logger/)

Structured logging via pino.

Usage

import { createModuleLogger } from '../logger/index.js';
const log = createModuleLogger('my-module');
log.info({ key: 'value' }, 'message');

Configuration

Env Var Effect
CW_LOG_LEVEL Override log level
CW_LOG_PRETTY Set to '1' for human-readable output
NODE_ENV=development Default to 'debug' level

Output

  • Default: JSON to stderr (fd 2)
  • Pretty mode: pino-pretty to stdout with colors and timestamps

Logging Module (apps/server/logging/)

File-based per-process output capture (separate from pino).

Classes

LogManager — Directory management:

  • Base dir: ~/.cw/logs/
  • Structure: {processId}/stdout.log, {processId}/stderr.log
  • cleanOldLogs(retainDays) — removes old directories by mtime

ProcessLogWriter — File I/O with timestamps:

  • open() — create directories and append-mode WriteStreams
  • writeStdout(data) / writeStderr(data) — prefix each line with [YYYY-MM-DD HH:mm:ss.SSS]
  • Handles backpressure (waits for drain event)
  • Emits log:entry event via EventBus

Factory

import { createLogger } from './logging/index.js';
const writer = createLogger(processId, eventBus);
await writer.open();
await writer.writeStdout('output data');
await writer.close();