Files
ccs/src/errors/exit-codes.ts
T
Tam Nhu Tran 7234ef8fcf feat(errors): P4 typed-error taxonomy adoption (0->91% locked) + erasable-syntax fix
Epic P4. Migrates plain throw new Error to the typed-error classes in the four
locked subdomains, and makes the taxonomy erasable-syntax-compatible so it can
be adopted across UI-reachable code.

Migration (cliproxy/auth, web-server/routes, auth):
- 21 of 23 throws in the locked subdomains now use typed subclasses
  (ProfileError, AuthError, ConfigError, ValidationError, ProviderError).
- Typed adoption in locked subdomains: 0/23 -> 21/23 (91.3%), > 40% target.
- Overall typed adoption: 0.9% -> 8.6%.
- Messages preserved exactly (message-based tests stable). Exit codes now
  differentiate via handleError (ProfileError=7, AuthError=4, ConfigError=2,
  ProviderError=6). ccs doctor 0/1 contract untouched (outside scope).

Erasable-syntax fix (unblocks the migration in the UI build graph):
- exit-codes.ts: enum ExitCode -> const object + union type (value and type
  usage both preserved; no Object.values(ExitCode) consumers).
- error-types.ts: constructor parameter properties -> explicit readonly field
  declarations + body assignment.
- The web UI build enforces erasableSyntaxOnly (ui/tsconfig.app.json) and
  reaches src/errors via the @shared -> src/auth graph; pre-erasable
  error-types blocked the build once profile-registry adopted typed errors.

Compat audit: docs/reports/typed-error-exit-code-compat-audit.md (Q1 resolved:
migrate freely; only documented contract is ccs doctor, which is untouched).
Behavior-lock: src/errors/__tests__/typed-error-migration-exit-codes.test.ts
(taxonomy -> exit-code mapping, instanceof chains, context fields).

validate + validate:ci-parity green (incl. UI build).
2026-06-18 18:48:12 -04:00

87 lines
2.6 KiB
TypeScript

/**
* Standardized exit codes for CCS CLI
*
* Exit codes follow Unix conventions:
* - 0: Success
* - 1-125: Application errors
* - 126-127: Command execution errors (reserved by shell)
* - 128+N: Signal termination (128 + signal number)
* - 130: SIGINT (Ctrl+C) - 128 + 2
*
* Implemented as a const object + union type (not a TS `enum`) so the file is
* erasable-syntax-compatible: web UI builds (ui/tsconfig.app.json,
* erasableSyntaxOnly) can reach this module via the @shared graph without
* failing the build. Value (`ExitCode.CONFIG_ERROR`) and type (`: ExitCode`)
* usage both continue to work.
*/
export const ExitCode = {
/** Successful execution */
SUCCESS: 0,
/** General/unspecified error */
GENERAL_ERROR: 1,
/** Configuration file errors (missing, invalid, corrupt) */
CONFIG_ERROR: 2,
/** Network-related errors (connection, timeout, DNS) */
NETWORK_ERROR: 3,
/** Authentication/authorization errors (invalid token, expired, forbidden) */
AUTH_ERROR: 4,
/** Binary/executable errors (missing Claude CLI, corrupted binary) */
BINARY_ERROR: 5,
/** Provider-specific errors (API errors, rate limits, service unavailable) */
PROVIDER_ERROR: 6,
/** Profile not found or invalid */
PROFILE_ERROR: 7,
/** Proxy-related errors (startup failure, port conflict) */
PROXY_ERROR: 8,
/** Migration errors (failed to migrate config) */
MIGRATION_ERROR: 9,
/** User aborted operation (Ctrl+C, SIGINT) */
USER_ABORT: 130,
} as const;
export type ExitCode = (typeof ExitCode)[keyof typeof ExitCode];
/**
* Human-readable descriptions for exit codes
* Used in error messages and documentation
*/
export const EXIT_CODE_DESCRIPTIONS: Record<ExitCode, string> = {
[ExitCode.SUCCESS]: 'Success',
[ExitCode.GENERAL_ERROR]: 'General error',
[ExitCode.CONFIG_ERROR]: 'Configuration error',
[ExitCode.NETWORK_ERROR]: 'Network error',
[ExitCode.AUTH_ERROR]: 'Authentication error',
[ExitCode.BINARY_ERROR]: 'Binary/executable error',
[ExitCode.PROVIDER_ERROR]: 'Provider error',
[ExitCode.PROFILE_ERROR]: 'Profile error',
[ExitCode.PROXY_ERROR]: 'Proxy error',
[ExitCode.MIGRATION_ERROR]: 'Migration error',
[ExitCode.USER_ABORT]: 'User abort (Ctrl+C)',
};
/**
* Check if an exit code indicates success
*/
export function isSuccess(code: ExitCode | number): boolean {
return code === ExitCode.SUCCESS;
}
/**
* Check if an exit code indicates a recoverable error
* (errors that might succeed on retry)
*/
export function isRecoverable(code: ExitCode | number): boolean {
return code === ExitCode.NETWORK_ERROR || code === ExitCode.PROVIDER_ERROR;
}