refactor(worker): Remove file-based locking and improve Windows stability

This commit simplifies worker startup coordination and addresses Windows-specific issues:

**Lock Removal**:
- Removed entire file-based locking system (~100 lines)
- Replaced with health-check-first approach
- Port binding provides natural mutual exclusion - multiple spawns fail cleanly

**Windows Stability**:
- Removed all AbortSignal.timeout() calls to reduce Bun libuv assertion errors
- Added 500ms shutdown delays on Windows to prevent zombie ports
- Worker service has its own timeouts, so client-side timeouts are redundant

**Package.json Updates**:
- Updated worker scripts to use worker-service.cjs directly
- Removed references to deleted worker-cli.js and worker-wrapper.cjs

**Key Changes**:
- src/services/worker-service.ts: Lock removal, shutdown delays, simplified start logic
- src/hooks/*.ts: Removed AbortSignal.timeout from all HTTP requests
- src/shared/worker-utils.ts: Removed AbortSignal.timeout from health checks
- package.json: Updated worker:* scripts

Resolves startup hangs, reduces assertion errors, and prevents zombie port issues.

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
This commit is contained in:
Erik M Jacobs
2025-12-29 12:11:04 -05:00
parent 0330b4d37e
commit 3ea180c1ef
16 changed files with 1041 additions and 554 deletions
+3 -1
View File
@@ -29,7 +29,9 @@ async function contextHook(input?: SessionStartInput): Promise<string> {
const url = `http://127.0.0.1:${port}/api/context/inject?project=${encodeURIComponent(project)}`;
const response = await fetch(url, { signal: AbortSignal.timeout(HOOK_TIMEOUTS.DEFAULT) });
// Note: Removed AbortSignal.timeout due to Windows Bun cleanup issue (libuv assertion)
// Worker service has its own timeouts, so client-side timeout is redundant
const response = await fetch(url);
if (!response.ok) {
throw new Error(`Context generation failed: ${response.status}`);
+4 -4
View File
@@ -39,8 +39,8 @@ async function newHook(input?: UserPromptSubmitInput): Promise<void> {
contentSessionId: session_id,
project,
prompt
}),
signal: AbortSignal.timeout(5000)
})
// Note: Removed signal to avoid Windows Bun cleanup issue (libuv assertion)
});
if (!initResponse.ok) {
@@ -72,8 +72,8 @@ async function newHook(input?: UserPromptSubmitInput): Promise<void> {
const response = await fetch(`http://127.0.0.1:${port}/sessions/${sessionDbId}/init`, {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({ userPrompt: cleanedPrompt, promptNumber }),
signal: AbortSignal.timeout(5000)
body: JSON.stringify({ userPrompt: cleanedPrompt, promptNumber })
// Note: Removed signal to avoid Windows Bun cleanup issue (libuv assertion)
});
if (!response.ok) {
+2 -2
View File
@@ -56,8 +56,8 @@ async function saveHook(input?: PostToolUseInput): Promise<void> {
tool_input,
tool_response,
cwd
}),
signal: AbortSignal.timeout(HOOK_TIMEOUTS.DEFAULT)
})
// Note: Removed signal to avoid Windows Bun cleanup issue (libuv assertion)
});
if (!response.ok) {
+2 -2
View File
@@ -60,8 +60,8 @@ async function summaryHook(input?: StopInput): Promise<void> {
contentSessionId: session_id,
last_user_message: lastUserMessage,
last_assistant_message: lastAssistantMessage
}),
signal: AbortSignal.timeout(HOOK_TIMEOUTS.DEFAULT)
})
// Note: Removed signal to avoid Windows Bun cleanup issue (libuv assertion)
});
if (!response.ok) {
+2 -1
View File
@@ -18,9 +18,10 @@ const port = getWorkerPort();
const project = basename(process.cwd());
// Fetch formatted context directly from worker API
// Note: Removed AbortSignal.timeout to avoid Windows Bun cleanup issue (libuv assertion)
const response = await fetch(
`http://127.0.0.1:${port}/api/context/inject?project=${encodeURIComponent(project)}&colors=true`,
{ method: 'GET', signal: AbortSignal.timeout(5000) }
{ method: 'GET' }
);
if (!response.ok) {