Upgrades the previously-stub ccsx binary entry (src/bin/codex-runtime.ts)
into an argv router: `ccsx auth <cmd>` dispatches to the Phase 2 router;
any other argv resolves the active codex-auth profile and spawns codex
with CODEX_HOME pointed at the profile dir.
- resolve-active-profile: sync, hot-path-safe (<5ms), reads YAML
registry via Phase 1 helpers; precedence is CODEX_HOME (explicit)
> CCS_CODEX_PROFILE (env) > registry default > null (legacy
~/.codex fallback); fails open on any error (silent for missing
registry, stderr warn for corrupt/missing-profile)
- codex-runtime-router: extracted main() for testability; entry
script is a thin 3-line wrapper; returns -1 sentinel for the
CCS branch so the spawn lifecycle isn't terminated
- ccsxp-runtime: H5 defensive stderr notice when CCS_CODEX_PROFILE
is set, surfacing the boundary between codex-auth (native codex)
and ccsxp (cliproxy pool) without changing functional behavior;
CLIProxyAPI does not read CODEX_HOME so no pool contamination
possible
- 14 unit tests (8 resolver + 6 router); ccsxp regression suite
(5 tests) untouched and still green
Implements the user-facing surface for ccsx auth profile management.
After `ccsx auth create work` (auto-spawns codex login with CODEX_HOME
pinned per D11), users can `eval "$(ccsx auth use work)"` in any shell
to scope all subsequent codex invocations to that profile — letting
two terminals run two different Codex accounts concurrently.
- codex-auth-router: dispatches argv to subcommand handlers
- create: idempotent, --force re-links config.toml preserving auth.json
(D9), then auto-spawns codex login with CODEX_HOME pinned (D11);
filesystem ops happen before registry write to avoid registry orphans
on EACCES/ENOSPC
- login: standalone re-auth for an existing profile
- switch: persistent default in YAML registry
- use: STDOUT-DISCIPLINED — emits only shell-evalable exports;
bash/zsh/fish/PowerShell/cmd syntaxes via shell-detect; sets
CCS_NO_PRE_DISPATCH=1 at module load to suppress recovery/migration
banners that would otherwise contaminate eval (C2)
- show: list (active(missing) row at top per D14) + detail views
- remove: default-profile guard, active-shell warn, --yes / --force
- ASCII-only output, NO_COLOR honored, all errors to stderr via
exitWithError
- pre-dispatch.ts: early-return when CCS_NO_PRE_DISPATCH=1, placed
before autoMigrate which is itself a stdout writer
57 unit tests, all green. Help text cross-references the ccsxp/ccsx
distinction since the binaries differ by one character (H5).
Adds the storage substrate for ccsx auth profile isolation.
Each Codex profile gets its own CODEX_HOME dir under
~/.ccs/codex-instances/<name>/ with isolated auth.json and
history.jsonl; config.toml is shared via symlink to ~/.codex/config.toml
so two terminals can run two Codex accounts simultaneously without
duplicating user config.
- CodexProfileRegistry (YAML, atomic write tmp.<pid>.<rand> + rename,
orphan cleanup, full CRUD + default pointer)
- decode-id-token: pure base64 JWT decoder for OpenAI id_token,
reads nested https://api.openai.com/auth claims (chatgpt_plan_type,
chatgpt_account_id) and dual-path email
- ensureSharedConfigSymlink: self-healing, idempotent, overwrites
stale entries with stderr warning
- 45 unit tests, all green
Foundation only — no CLI, no runtime injection, no dashboard.
Subsequent commits wire those in.