refactor(cli): unify daemon start error message handling
What changed: - Added a shared utility `getErrorMessage(error: unknown)` in `packages/cli/src/utils/errors.ts`. - Refactored `packages/cli/src/commands/daemon/start.ts` to use `getErrorMessage` and a local `exitWithError` helper instead of repeating inline error-message extraction + exit logic in each catch block. - Added `packages/cli/tests/19-errors-utils.test.ts` to lock utility behavior for Error and non-Error throw values. Reasoning: - `runStart` had repeated branching (`err instanceof Error ? err.message : String(err)`) across multiple catch sites. - Centralizing this keeps behavior stable while reducing duplication and cognitive overhead, aligned with the refactor skill guidance to simplify structure without changing user-visible behavior. Verification: - Ran `npx tsx packages/cli/tests/18-local-daemon-utils.test.ts` (pass). - Ran `npx tsx packages/cli/tests/19-errors-utils.test.ts` (pass). - Ran `npm run -w @getpaseo/cli typecheck` (pass). Notes for next agent: - Existing `scripts/codex-refactor-loop.sh` was already modified before this change and is intentionally not included. - `packages/cli/tests/03-daemon.test.ts` currently failed in this environment because Test 3 expected daemon status failure, but command exited successfully (likely environment state dependent). This refactor does not touch that path; worth deflakifying or isolating in a follow-up.
This commit is contained in:
@@ -12,6 +12,7 @@ import {
|
||||
startLocalDaemonDetached,
|
||||
type DaemonStartOptions as StartOptions,
|
||||
} from './local-daemon.js'
|
||||
import { getErrorMessage } from '../../utils/errors.js'
|
||||
|
||||
export type { DaemonStartOptions as StartOptions } from './local-daemon.js'
|
||||
|
||||
@@ -73,9 +74,7 @@ export async function runStart(options: StartOptions): Promise<void> {
|
||||
console.log(chalk.green(`Daemon starting in background (PID ${startup.pid ?? 'unknown'}).`))
|
||||
console.log(chalk.dim(`Logs: ${startup.logPath}`))
|
||||
} catch (err) {
|
||||
const message = err instanceof Error ? err.message : String(err)
|
||||
console.error(chalk.red(message))
|
||||
process.exit(1)
|
||||
exitWithError(getErrorMessage(err))
|
||||
}
|
||||
return
|
||||
}
|
||||
@@ -94,18 +93,15 @@ export async function runStart(options: StartOptions): Promise<void> {
|
||||
logger = createRootLogger(persistedConfig)
|
||||
config = loadConfig(paseoHome, { cli: toCliOverrides(options) })
|
||||
} catch (err) {
|
||||
const message = err instanceof Error ? err.message : String(err)
|
||||
console.error(chalk.red(message))
|
||||
process.exit(1)
|
||||
exitWithError(getErrorMessage(err))
|
||||
}
|
||||
|
||||
let daemon: Awaited<ReturnType<typeof createPaseoDaemon>>
|
||||
try {
|
||||
daemon = await createPaseoDaemon(config, logger)
|
||||
} catch (err) {
|
||||
const message = err instanceof Error ? err.message : String(err)
|
||||
console.error(chalk.red(`Failed to initialize daemon: ${message}`))
|
||||
process.exit(1)
|
||||
const message = getErrorMessage(err)
|
||||
exitWithError(`Failed to initialize daemon: ${message}`)
|
||||
}
|
||||
|
||||
let shuttingDown = false
|
||||
@@ -140,8 +136,12 @@ export async function runStart(options: StartOptions): Promise<void> {
|
||||
try {
|
||||
await daemon.start()
|
||||
} catch (err) {
|
||||
const message = err instanceof Error ? err.message : String(err)
|
||||
console.error(chalk.red(`Failed to start daemon: ${message}`))
|
||||
const message = getErrorMessage(err)
|
||||
exitWithError(`Failed to start daemon: ${message}`)
|
||||
}
|
||||
}
|
||||
|
||||
function exitWithError(message: string): never {
|
||||
console.error(chalk.red(message))
|
||||
process.exit(1)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,10 @@
|
||||
/**
|
||||
* Convert unknown thrown values into a user-safe error string.
|
||||
*/
|
||||
export function getErrorMessage(error: unknown): string {
|
||||
if (error instanceof Error) {
|
||||
return error.message
|
||||
}
|
||||
|
||||
return String(error)
|
||||
}
|
||||
@@ -0,0 +1,22 @@
|
||||
#!/usr/bin/env npx tsx
|
||||
|
||||
import assert from 'node:assert'
|
||||
import { getErrorMessage } from '../src/utils/errors.js'
|
||||
|
||||
console.log('=== Error Utils ===\n')
|
||||
|
||||
{
|
||||
console.log('Test 1: returns Error.message for Error instances')
|
||||
assert.strictEqual(getErrorMessage(new Error('boom')), 'boom')
|
||||
console.log('✓ returns Error.message\n')
|
||||
}
|
||||
|
||||
{
|
||||
console.log('Test 2: stringifies non-Error values')
|
||||
assert.strictEqual(getErrorMessage('plain string'), 'plain string')
|
||||
assert.strictEqual(getErrorMessage(42), '42')
|
||||
assert.strictEqual(getErrorMessage(null), 'null')
|
||||
console.log('✓ stringifies non-Error values\n')
|
||||
}
|
||||
|
||||
console.log('=== All error utility tests passed ===')
|
||||
Reference in New Issue
Block a user