From 80f0ca08f97e46ec71e26b861d194d8c7488ef2d Mon Sep 17 00:00:00 2001 From: Mohamed Boudra Date: Sat, 14 Feb 2026 01:26:54 +0700 Subject: [PATCH] refactor(cli): centralize daemon errno parsing and add utility tests What changed: - extracted shared readNodeErrnoCode helper in local daemon process control code - updated isProcessRunning and signalProcess to use the shared helper - added packages/cli/tests/18-local-daemon-utils.test.ts covering resolveTcpHostFromListen cases (numeric, host:port, unix sockets, empty/non-host) Why: - removes duplicated low-level error-shape branching and keeps errno handling consistent in one place - adds deterministic coverage for pure listen parsing logic without depending on daemon runtime state Accomplishments for next agent: - this area now has a focused utility test entry that runs fast and is independent of daemon availability - full workspace typecheck is clean after this change Challenges / notes for next agent: - packages/cli/tests/03-daemon.test.ts can be environment-sensitive when a daemon is already running (baseline in this workspace did not reliably represent daemon not running) - existing unstaged change remains in scripts/codex-refactor-loop.sh and was intentionally left untouched --- .../cli/src/commands/daemon/local-daemon.ts | 12 +++++- .../cli/tests/18-local-daemon-utils.test.ts | 43 +++++++++++++++++++ 2 files changed, 53 insertions(+), 2 deletions(-) create mode 100644 packages/cli/tests/18-local-daemon-utils.test.ts diff --git a/packages/cli/src/commands/daemon/local-daemon.ts b/packages/cli/src/commands/daemon/local-daemon.ts index 7895e2902..e8721ba85 100644 --- a/packages/cli/src/commands/daemon/local-daemon.ts +++ b/packages/cli/src/commands/daemon/local-daemon.ts @@ -169,12 +169,20 @@ function sleep(ms: number): Promise { }) } +function readNodeErrnoCode(error: unknown): string | undefined { + if (typeof error !== 'object' || error === null || !('code' in error)) { + return undefined + } + + return typeof error.code === 'string' ? error.code : undefined +} + function isProcessRunning(pid: number): boolean { try { process.kill(pid, 0) return true } catch (err) { - const code = typeof err === 'object' && err && 'code' in err ? (err as { code?: string }).code : undefined + const code = readNodeErrnoCode(err) if (code === 'EPERM') { return true } @@ -187,7 +195,7 @@ function signalProcess(pid: number, signal: NodeJS.Signals): boolean { process.kill(pid, signal) return true } catch (err) { - const code = typeof err === 'object' && err && 'code' in err ? (err as { code?: string }).code : undefined + const code = readNodeErrnoCode(err) if (code === 'ESRCH') { return false } diff --git a/packages/cli/tests/18-local-daemon-utils.test.ts b/packages/cli/tests/18-local-daemon-utils.test.ts new file mode 100644 index 000000000..43119077a --- /dev/null +++ b/packages/cli/tests/18-local-daemon-utils.test.ts @@ -0,0 +1,43 @@ +#!/usr/bin/env npx tsx + +/** + * Phase 18: Local daemon utility tests. + * + * Tests pure helpers that do not require a running daemon. + */ + +import assert from 'node:assert' +import { resolveTcpHostFromListen } from '../src/commands/daemon/local-daemon.js' + +console.log('=== Local Daemon Utility Helpers ===\n') + +{ + console.log('Test 1: resolves numeric listen values to localhost host:port') + assert.strictEqual(resolveTcpHostFromListen('6767'), '127.0.0.1:6767') + assert.strictEqual(resolveTcpHostFromListen(' 7777 '), '127.0.0.1:7777') + console.log('✓ resolves numeric listen values\n') +} + +{ + console.log('Test 2: preserves explicit host:port listen values') + assert.strictEqual(resolveTcpHostFromListen('localhost:6767'), 'localhost:6767') + assert.strictEqual(resolveTcpHostFromListen('0.0.0.0:8080'), '0.0.0.0:8080') + console.log('✓ preserves explicit host:port values\n') +} + +{ + console.log('Test 3: rejects unix socket listen values') + assert.strictEqual(resolveTcpHostFromListen('/tmp/paseo.sock'), null) + assert.strictEqual(resolveTcpHostFromListen('unix:///tmp/paseo.sock'), null) + console.log('✓ rejects unix socket listen values\n') +} + +{ + console.log('Test 4: rejects empty and non-host listen values') + assert.strictEqual(resolveTcpHostFromListen(''), null) + assert.strictEqual(resolveTcpHostFromListen(' '), null) + assert.strictEqual(resolveTcpHostFromListen('localhost'), null) + console.log('✓ rejects empty and non-host listen values\n') +} + +console.log('=== All local daemon utility tests passed ===')