feat(mosaic): claudex proxy preflight + lifecycle (P1 of #790) #793
Reference in New Issue
Block a user
Delete Branch "feat/790-mosaic-yolo-claudex"
Deleting a branch is permanent. Although the deleted branch may continue to exist for a short time before it actually gets removed, it CANNOT be undone in most cases. Continue?
PR-1 — claudex proxy preflight + lifecycle (P1 of #790)
First of two sequential PRs for
mosaic yolo claudex(GPT models in the Claude Code harness viaraine/claude-code-proxy, ChatGPT OAuth). This PR is P1 only — proxy preflight + lifecycle helpers. It ships no session launch; the isolatedCLAUDE_CONFIG_DIRcomposition, env injection, model-tier map, and EXPERIMENTAL banner are PR-2 (branches offmainafter this merges).Scope
New module
packages/mosaic/src/commands/claudex-proxy.ts(+ co-located.spec.ts). Pure / dependency-injected — every side-effecting boundary (spawn, fetch, which, fs) is an injected dep so the logic is unit-testable without touching a real proxy or the network. Nothing wired intocli.ts/launch.tsyet, so no runtime behavior change for existing commands.What it adds
checkProxyBinary— resolvesclaude-code-proxyon PATH.parseAuthStatus/checkAuthStatus— coarse auth state (valid|expired|unauthenticated|unknown) fromclaude-code-proxy codex auth status. Carries no token material by construction.runDeviceReauth— device-code re-auth viastdio: 'inherit'; the launcher never captures or logs the device code or token.probeLiveness— gotcha #1: ANY HTTP response (incl. non-2xx) means alive; nevercurl -f. Bounded by an explicitPromise.racetimeout so a hung socket can't wedge preflight.buildSystemdUnitContent/systemdUnitPath/installSystemdUnit— optional user unitclaude-code-proxy.service; unit text contains no credentials.runProxyPreflight— structured report (binary/auth/liveness/needsReauth/problems).ensureProxyRunning— systemd-preferred start with nohup fallback; re-probes before/after each start so it never spawns a duplicate proxy.Security invariants (light secrev surface, charter #4)
curl -f—probeLivenesstreats non-2xx as alive (tested: 404/500 → alive; reject/timeout → dead).runDeviceReauthusesstdio:'inherit'; test asserts inherit.ensureProxyRunningre-probes around every start.parseAuthStatusdrops token-shaped output — test assertsaccess_token/refresh_token/sk-never retained.Tests / gates
@mosaicstack/mosaicsuite: 1080 passing.pnpm typecheck,pnpm lint,pnpm format:check: green.Review asks
0e41a5c2.mosaic-100).Refs #790 (partial — issue stays open until P2–P4 land).