-
Notifications
You must be signed in to change notification settings - Fork 0
Refactor daemon.ts — extract modules and break down monster functions #174
Copy link
Copy link
Closed
Description
Problem
daemon.ts is 1528 lines with 2 monster functions: runClaude() (324 lines) and main() (222 lines). Settings merge logic is duplicated, git operations are scattered, and there are 7 global state variables. This makes the code hard to test, debug, and extend.
What to do
Step 1: Extract src/logging.ts
Move these functions out of daemon.ts:
rotateLogs()(lines 190-199)checkRotate()(lines 200-216)out()/err()(lines 217-230)logMemory()(lines 231-260)formatEvent()(lines 804-874)- Export:
initLogging(agentName),out(),err(),logMemory(),formatEvent(),checkRotate()
Step 2: Extract src/process.ts
Move Claude subprocess management:
runClaude()(lines 969-1292) — break into sub-functions:cleanEnvironment()— env cleanup (977-995)setupClaudePermissions(globalSettingsPath, workspaceSettingsPath)— settings merge logic (1004-1040 + 1096-1118, currently DUPLICATED)spawnClaude(args, cwd, env)— process creation (1120-1124)handleClaudeTimeout(child, config, taskId)— timeout guard (1129-1163)handleClaudeCompletion(code, work, config, worktreeInfo, branchName)— post-exit merge/cleanup (1195-1243)
- The main
runClaude()should be a thin orchestrator calling these sub-functions (~50 lines max) - Export:
runClaude(config, work, phase, prompt)
Step 3: Extract src/recovery.ts
Move task recovery logic:
recoverStaleTasks()(lines 329-422)checkRuntimeStaleTasks()(lines 423-494)- These two share duplicated patterns (fetch tasks, filter by agent, post comment, update status) — extract common
performRecovery(tasks, reason, maxRetries)helper - Export:
recoverStaleTasks(config),checkRuntimeStaleTasks(config)
Step 4: Extract src/comments.ts
Move comment baseline tracking:
refreshCommentBaselines()(lines 596-606)loadCommentBaselines()(lines 607-626)saveCommentBaselines()(lines 627-660)- Export:
loadCommentBaselines(),saveCommentBaselines(),refreshCommentBaselines()
Step 5: Extract src/prompt.ts
Move prompt building:
sanitizeTaskBody()(lines 661-676)resolveBuildCmd()(lines 677-687)buildPrompt()(lines 688-803) — split into phase-specific functions:buildCommentPrompt(work, config)buildPlanPrompt(work, config)buildExecutePrompt(work, config)buildSinglePrompt(work, config)
- Export:
buildPrompt(phase, work, config)
Step 6: Simplify main() in daemon.ts
After extractions, main() should be:
- Parse args
- Init logging
- Write PID
- Recover stale tasks
- Poll loop: checkForWork → runClaude → sleep
- Shutdown cleanup
Target: main() should be ~80-100 lines, not 222.
Step 7: Remove duplicate settings merge
The settings merge logic appears twice (lines 1004-1040 and 1096-1118). Extract into a single mergeClaudeSettings(filePath, allowedTools, deniedTools) function in process.ts.
Rules
- Keep ALL existing functionality — this is a pure refactoring, no behavior changes
- Each new module should have proper TypeScript exports
- daemon.ts should import from the new modules
- Global state variables (
logStream,activeAgentName,lastSeenComments,currentProcess,busy,stopped,sleepResolve) should stay in daemon.ts or be encapsulated where they naturally belong - PID management functions can stay in daemon.ts (they're small and focused)
Files
src/daemon.ts— shrink from 1528 to ~400-500 linessrc/logging.ts— NEW (~100 lines)src/process.ts— NEW (~300 lines)src/recovery.ts— NEW (~120 lines)src/comments.ts— NEW (~70 lines)src/prompt.ts— NEW (~150 lines)
Acceptance
npm run buildpasses with zero errors- daemon.ts is under 500 lines
- No function over 100 lines
- No duplicate code
- All existing tests still pass (if any)
- Agent still completes tasks successfully after refactor
Reactions are currently unavailable