import { readFileSync } from "node:fs"; import { dirname, join } from "node:path"; import { fileURLToPath } from "node:url"; import { findCommand } from "./registry"; const repoRoot = dirname(fileURLToPath(new URL("../../package.json", import.meta.url))); /** * Version of the `ocx` bundle this process is running from. * * Exported so `status`/`doctor` can compare it against the version the live proxy reports, * which is how a stale `ocx` earlier on PATH becomes visible (#2701). Returns `"unknown"` * rather than throwing; callers must treat that as "cannot compare", not as a mismatch. */ export function packageVersion(): string { const raw = readFileSync(join(repoRoot, "package.json"), "utf8"); const parsed = JSON.parse(raw) as { version?: unknown }; return typeof parsed.version === "string" ? parsed.version : "unknown"; } export function printVersion(): void { console.log(`opencodex ${packageVersion()}`); } export function printUsage(): void { console.log(`opencodex (ocx) — Universal provider proxy for Codex Usage: ocx setup [--yes] Interactive setup (alias: init) ocx start [--port ] Start the proxy server (auto-syncs models to Codex) ocx stop Stop the proxy AND restore native Codex (plain codex works again) ocx restore Restore native Codex without stopping (alias: eject) ocx restore back Re-point codex at the running proxy (undo restore) ocx recover-history --legacy-openai --yes Force all user-message opencodex rows to OpenAI (legacy recovery) ocx uninstall Remove service/shim/config and restore native Codex (alias: remove) ocx service [sub] Run as a background service (default: install/update/start) ocx codex-shim Auto-start proxy when \`codex\` launches (install|status|uninstall|remove) ocx tray Windows status tray (install|start|stop|status|uninstall) ocx ensure Ensure the proxy is running and Codex config/cache are current ocx connect Connect this machine to a remote OpenCodex hub (credential via stdin) ocx disconnect Restore local state and clear the hub connection ocx sync [--restart-codex] Fetch models from providers and inject into Codex config ocx sync-cache [--restart-codex] Refresh Codex's model cache from the active catalog ocx status Check proxy server status ocx doctor Diagnose environment/network issues (WSL, proxy, ChatGPT reachability) ocx doctor --reclaim-response-temps Reclaim abandoned response-state temp files (works without a running proxy) ocx doctor --recover-zero-byte-coordinator --yes Back up a proven zero-byte Codex coordinator after stopping the proxy ocx debug provider/usage/injection/claude on|off|status|reset ocx login OAuth or API-key provider login ocx logout Remove a stored OAuth login ocx gui [pair --origin [--json]] Open the dashboard or create a single-use remote pairing grant ocx update [--tag ] Update opencodex (keeps preview installs on @preview) ocx restart Stop and restart the proxy ocx v2 multi_agent_v2 surface (status|on|off|mode|keep-native-v1|threads|mode-hint) ocx health [--json] Check proxy health (exit 0=healthy, 1=not) ocx capabilities [--json] List declared capabilities and the API routes they drive ocx ready [--json] [--wait [--timeout ]] Check post-sync readiness (exit 0 only when ready) ocx provider Providers, connectivity, quota, and selected models ocx account Accounts, login/reauth, key pools, and quota controls ocx models Live/custom models, visibility, context, and shadow calls ocx alias Short names for providers and models (list, set, rm, defaults) ocx combo Combo routing strategies and failover ocx agent Subagents, roles, injection, effort caps, and sidecars ocx effort [sub] Inspect and configure reasoning effort caps and defaults ocx observe Logs, usage, storage, memory, and debug data ocx inspect Effective config, catalog, analytics, pacing, client-config ocx route Routing features (combo, policy) ocx logs [filters] Alias of ocx observe logs ocx usage [--range ] [--provider ] [--model ] Token and estimated-cost report (alias of ocx observe usage) ocx storage Storage report, cleanup, trash, and the cleanup policy ocx memory [--json] Alias of ocx observe memory ocx api-key Alias of ocx access key ocx access External API keys and endpoint information ocx export --client Print a client config wired to the running proxy (13 clients) ocx integration client Enable, disable, inspect or roll back a client integration ocx grok Grok Build model selection and apply ocx system Runtime settings, startup, sync, OpenCodex updates, and Codex CLI inspection ocx config Validated configuration show/get/set/import/export ocx lab Read-only Compatibility Lab projection inspection ocx claude [args...] Launch Claude Code wired to the proxy (model discovery on) ocx claude desktop [sub] Manage and apply Claude Desktop's four-family profile ocx opencode [args...] Launch opencode wired to the proxy (runtime provider config) ocx mcode [args...] Launch MiniMax Code through its managed provider ocx mmx text [args] Launch MiniMax CLI text through the proxy ocx zcode [sub] Connect ZCode to the proxy (managed provider) ocx help [command] Show help ocx --version | -v Print version Examples: ocx init [--yes] Set up provider and inject into Codex (replace existing config only with --yes) ocx start Start on default port (10100) ocx start --port 8080 Start on custom port ocx help service Show service command help ocx sync Sync available models to Codex`); } export function hasHelpFlag(values: string[]): boolean { return values.some(value => value === "--help" || value === "-h" || value === "help"); } export function printSubcommandUsage(name: string | undefined): void { const entry = name ? findCommand(name) : undefined; if (!entry) { console.error(`Unknown command: ${name ?? ""}`.trim()); printUsage(); process.exit(1); } console.log(`Usage: ${entry.usage}\n\n${entry.summary}`); if (entry.details?.length) console.log(`\n${entry.details.join("\n")}`); }