@bitkyc08/opencodex 2.12.0 → 2.13.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +1 -1
- package/gui/dist/assets/index-BHldBl6_.js +76 -0
- package/gui/dist/index.html +1 -1
- package/package.json +1 -1
- package/src/adapters/anthropic-output-schema.ts +137 -0
- package/src/adapters/anthropic.ts +15 -0
- package/src/adapters/google-antigravity-replay.ts +269 -5
- package/src/adapters/openai-chat.ts +25 -18
- package/src/adapters/openai-responses.ts +63 -17
- package/src/bridge.ts +11 -5
- package/src/claude/inbound.ts +24 -3
- package/src/cli/account-api.ts +2 -0
- package/src/cli/account-extended.ts +262 -1
- package/src/cli/account.ts +3 -1
- package/src/cli/dispatch.ts +532 -0
- package/src/cli/doctor.ts +26 -21
- package/src/cli/help.ts +9 -278
- package/src/cli/index.ts +45 -506
- package/src/cli/lab.ts +171 -65
- package/src/cli/registry.ts +384 -0
- package/src/cli/root.ts +86 -0
- package/src/cli/status.ts +9 -2
- package/src/cli/v2.ts +37 -2
- package/src/codex/account-label.ts +14 -1
- package/src/codex/account-store.ts +12 -1
- package/src/codex/admission.ts +2 -1
- package/src/codex/auth-api.ts +3 -2
- package/src/codex/catalog/metadata.ts +6 -4
- package/src/codex/catalog/parsing.ts +31 -7
- package/src/codex/catalog/provider-fetch.ts +2 -1
- package/src/codex/catalog/sync.ts +65 -11
- package/src/codex/features.ts +437 -31
- package/src/codex/history-job.ts +6 -11
- package/src/codex/history-provider.ts +10 -9
- package/src/codex/inject.ts +14 -1
- package/src/codex/native-profile-startup.ts +49 -3
- package/src/codex/native-residue.ts +14 -2
- package/src/codex/paths.ts +75 -1
- package/src/codex/reset-credit-recovery.ts +1044 -0
- package/src/codex/shim.ts +876 -16
- package/src/codex/sync.ts +27 -2
- package/src/config.ts +148 -10
- package/src/generated/compatibility-version.json +2572 -0
- package/src/images/loop.ts +1 -1
- package/src/lab/artifacts/sanitize.ts +3 -3
- package/src/lab/automation/budgets.ts +78 -0
- package/src/lab/automation/config-persistence.ts +256 -0
- package/src/lab/automation/constants.ts +39 -0
- package/src/lab/automation/cooldown.ts +103 -0
- package/src/lab/automation/dispatch.ts +211 -0
- package/src/lab/automation/index.ts +13 -0
- package/src/lab/automation/orchestrator.ts +480 -0
- package/src/lab/automation/persistence.ts +512 -0
- package/src/lab/automation/planner.ts +371 -0
- package/src/lab/automation/policy.ts +136 -0
- package/src/lab/automation/queue.ts +191 -0
- package/src/lab/automation/recovery.ts +24 -0
- package/src/lab/automation/route-context.ts +21 -0
- package/src/lab/automation/run-key.ts +44 -0
- package/src/lab/automation/runs-query.ts +34 -0
- package/src/lab/automation/types.ts +160 -0
- package/src/lab/conformance/types.ts +23 -0
- package/src/lab/events/types.ts +2 -1
- package/src/lab/events/validate.ts +2 -1
- package/src/lab/fabric/constants.ts +40 -0
- package/src/lab/fabric/executor.ts +492 -0
- package/src/lab/fabric/index.ts +80 -0
- package/src/lab/fabric/manifest.ts +222 -0
- package/src/lab/fabric/observe.ts +454 -0
- package/src/lab/fabric/patch.ts +79 -0
- package/src/lab/fabric/producer-child.ts +139 -0
- package/src/lab/fabric/producer-isolate.ts +276 -0
- package/src/lab/fabric/producer-protocol.ts +61 -0
- package/src/lab/fabric/scratch.ts +439 -0
- package/src/lab/fabric/subject.ts +106 -0
- package/src/lab/fabric/types.ts +134 -0
- package/src/lab/fabric/verifier.ts +98 -0
- package/src/lab/index.ts +2 -0
- package/src/lab/ledger/store.ts +173 -0
- package/src/lab/live/executor.ts +29 -4
- package/src/lab/live/transport.ts +3 -1
- package/src/lab/observe/from-conformance.ts +12 -57
- package/src/lab/observe/from-live.ts +9 -1
- package/src/lab/paths.ts +74 -9
- package/src/lab/projection/schema.ts +14 -1
- package/src/lab/projection/verdicts.ts +89 -53
- package/src/lab/projection/verification.ts +83 -3
- package/src/lab/query/catalog.ts +34 -5
- package/src/lab/query/freshness.ts +53 -0
- package/src/lab/query/index.ts +11 -0
- package/src/lab/query/latest-observation.ts +59 -0
- package/src/lab/query/passive-production.ts +159 -0
- package/src/lab/subject/installation-salt.ts +24 -4
- package/src/lab/subject/protocol-subject.ts +80 -0
- package/src/lab/subject/route-subject.ts +2 -1
- package/src/lib/fabric-task-execution-authority.ts +7 -0
- package/src/lib/fabric-task-host.ts +29 -0
- package/src/lib/lab-live-route-production.ts +130 -0
- package/src/lib/local-management-capability.ts +100 -0
- package/src/lib/server-resource-ownership.ts +71 -0
- package/src/lib/windows-elevation.ts +8 -1
- package/src/lib/windows-user-principal.ts +62 -2
- package/src/lib/winsw.ts +8 -2
- package/src/oauth/account-import/google-antigravity-adapter.ts +74 -0
- package/src/oauth/account-import/index.ts +15 -0
- package/src/oauth/account-import/parser.ts +83 -0
- package/src/oauth/account-import/registry.ts +18 -0
- package/src/oauth/account-import/service.ts +75 -0
- package/src/oauth/account-import/types.ts +91 -0
- package/src/oauth/anthropic.ts +12 -1
- package/src/oauth/callback-server.ts +8 -2
- package/src/oauth/chatgpt.ts +12 -1
- package/src/oauth/google-antigravity.ts +27 -0
- package/src/oauth/health.ts +12 -48
- package/src/oauth/index.ts +122 -0
- package/src/oauth/kimi.ts +16 -2
- package/src/oauth/nous.ts +749 -0
- package/src/oauth/store.ts +56 -3
- package/src/providers/codex-capacity.ts +1 -0
- package/src/providers/registry.ts +161 -16
- package/src/responses/custom-tool-compat.ts +182 -0
- package/src/responses/parser.ts +22 -0
- package/src/responses/reasoning-replay-cache.ts +168 -11
- package/src/responses/schema.ts +1 -1
- package/src/router.ts +5 -20
- package/src/routing/capability.ts +9 -3
- package/src/routing/compatibility/assemble.ts +159 -0
- package/src/routing/compatibility/behavior.ts +224 -0
- package/src/routing/compatibility/catalog.ts +99 -0
- package/src/routing/compatibility/endpoint.ts +52 -0
- package/src/routing/compatibility/policy.ts +181 -0
- package/src/routing/compatibility/reader.ts +110 -0
- package/src/routing/compatibility/subject.ts +191 -0
- package/src/routing/compatibility/types.ts +64 -0
- package/src/routing/compatibility/version.ts +104 -0
- package/src/routing/evaluator.ts +27 -32
- package/src/routing/profile.ts +118 -4
- package/src/routing/trace.ts +82 -28
- package/src/server/auth-cors.ts +7 -0
- package/src/server/background-lifecycle.ts +20 -7
- package/src/server/chat-completions.ts +2 -2
- package/src/server/claude-messages.ts +6 -3
- package/src/server/direct-local-http.ts +343 -0
- package/src/server/index.ts +80 -18
- package/src/server/lifecycle.ts +12 -4
- package/src/server/local-management-read-client.ts +90 -0
- package/src/server/management/agent-settings-routes.ts +27 -3
- package/src/server/management/lab-automation-routes.ts +206 -0
- package/src/server/management/lab-routes.ts +13 -0
- package/src/server/management/logs-usage-routes.ts +1 -0
- package/src/server/management/oauth-account-routes.ts +57 -1
- package/src/server/management/provider-routes.ts +16 -0
- package/src/server/management/routing-profile-routes.ts +12 -24
- package/src/server/management-api.ts +2 -0
- package/src/server/management-auth.ts +68 -3
- package/src/server/proxy-liveness.ts +3 -2
- package/src/server/request-decompress.ts +9 -3
- package/src/server/request-log.ts +53 -4
- package/src/server/responses/collaboration.ts +93 -17
- package/src/server/responses/compact.ts +3 -0
- package/src/server/responses/core.ts +202 -15
- package/src/server/responses/policy-fallback.ts +1 -0
- package/src/server/responses-custom-tool-repair.ts +280 -0
- package/src/server/responses-terminal-repair.ts +342 -0
- package/src/server/startup-action-control.ts +8 -1
- package/src/service.ts +278 -12
- package/src/types.ts +49 -3
- package/src/usage/expected-prices.ts +30 -0
- package/src/usage/log.ts +30 -4
- package/src/usage/summary.ts +153 -2
- package/src/web-search/loop.ts +1 -1
- package/gui/dist/assets/index-Cw1_mxO8.js +0 -70
- package/src/cli/internal-dispatch.ts +0 -20
package/src/cli/index.ts
CHANGED
|
@@ -24,7 +24,7 @@ import {
|
|
|
24
24
|
writeRuntimePort,
|
|
25
25
|
} from "../config";
|
|
26
26
|
import { collectStatus } from "./status";
|
|
27
|
-
|
|
27
|
+
|
|
28
28
|
import {
|
|
29
29
|
discoverStableProxyForRestart,
|
|
30
30
|
isProxyReplacement,
|
|
@@ -35,11 +35,12 @@ import {
|
|
|
35
35
|
} from "./tray-proxy";
|
|
36
36
|
import { requestBoundSystemRestart } from "./system-restart-client";
|
|
37
37
|
import { installCrashGuards } from "../lib/crash-guard";
|
|
38
|
-
import {
|
|
38
|
+
import { dispatchCommand } from "./dispatch";
|
|
39
39
|
import { findAvailablePort, isAddrInUse, PortUnavailableError, shouldPersistSelectedPort, waitForPortAvailable } from "../server/ports";
|
|
40
40
|
import { findLiveProxy, probeHostname, type LiveProxy } from "../server/proxy-liveness";
|
|
41
41
|
import { createReadinessGate } from "../server/readiness";
|
|
42
|
-
import {
|
|
42
|
+
import { runReady, type ReadyArgs } from "./ready";
|
|
43
|
+
import { runCli } from "./root";
|
|
43
44
|
import { ProxyOwnershipRefusedError, stopProxy } from "../lib/process-control";
|
|
44
45
|
import { loadServiceTokenFromFile } from "../lib/service-secrets";
|
|
45
46
|
import { diagnoseService, isServiceOwnershipError, serviceCommand, serviceEnvironmentOwnedHere, serviceStartableFromTray, serviceStatusSummary, stopServiceIfInstalled, uninstallServiceIfInstalled } from "../service";
|
|
@@ -50,14 +51,13 @@ import { buildDesktop3pRegistry } from "../claude/desktop-3p";
|
|
|
50
51
|
import { installShellHook, uninstallShellHook } from "../server/system-env";
|
|
51
52
|
import { startTokenGuardian } from "../oauth/token-guardian";
|
|
52
53
|
import { startHistoryMigrationGuardian } from "../codex/history-migration-guardian";
|
|
53
|
-
import { maybeAutoRestoreCodexShim } from "./codex-shim-autorestore";
|
|
54
54
|
import { maybeShowStarPrompt } from "./star-prompt";
|
|
55
55
|
import { scheduleCatalogPrewarm } from "./catalog-prewarm";
|
|
56
56
|
import { maybeShowUpdatePrompt } from "../update/notify";
|
|
57
57
|
import { syncModelsToCodex } from "../codex/sync";
|
|
58
58
|
import { setIntegrationEnabled, shouldSyncCodexOnStart, shouldSyncGrokOnStart, syncCodexOnStartIfEnabled } from "../codex/desired-state";
|
|
59
|
-
|
|
60
|
-
|
|
59
|
+
|
|
60
|
+
|
|
61
61
|
import { removeOwnedConfigState } from "../lib/config-ownership";
|
|
62
62
|
import { withProcessRuntimeProvenance } from "../lib/bun-runtime";
|
|
63
63
|
import { initializeNodeLauncherContext } from "./launcher-context";
|
|
@@ -65,43 +65,15 @@ import { createLocalAttestationSecret } from "../lib/local-management-attestatio
|
|
|
65
65
|
import { MEMORY_DRAIN_RESTART_MS, REPLACEMENT_READY_TIMEOUT_MS } from "../lib/system-restart-contract";
|
|
66
66
|
|
|
67
67
|
initializeNodeLauncherContext();
|
|
68
|
-
const args = process.argv.slice(2);
|
|
69
|
-
const command = args[0];
|
|
70
|
-
|
|
71
|
-
if (command === "--version" || command === "-v" || command === "version") {
|
|
72
|
-
printVersion();
|
|
73
|
-
process.exit(0);
|
|
74
|
-
}
|
|
75
|
-
|
|
76
|
-
if (command === undefined || command === "help" || command === "--help" || command === "-h") {
|
|
77
|
-
if (command === "help" && args[1]) printSubcommandUsage(args[1]);
|
|
78
|
-
else printUsage();
|
|
79
|
-
process.exit(0);
|
|
80
|
-
}
|
|
81
68
|
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
// only sees ready args without a help flag. Valid args are stashed so the
|
|
91
|
-
// switch dispatch can call runReady without a second parse.
|
|
92
|
-
let readyArgs: ReadyArgs | undefined;
|
|
93
|
-
if (command === "ready") {
|
|
94
|
-
const parsed = parseReadyArgs(args.slice(1));
|
|
95
|
-
if (!parsed.ok) {
|
|
96
|
-
console.error("Usage: ocx ready [--json] [--wait [--timeout <seconds>]]");
|
|
97
|
-
console.error(" --timeout requires --wait; <seconds> must be a positive integer (1..300).");
|
|
98
|
-
console.error(" Default wait timeout is 45 seconds.");
|
|
99
|
-
process.exit(parsed.code);
|
|
100
|
-
}
|
|
101
|
-
readyArgs = parsed.args;
|
|
102
|
-
}
|
|
103
|
-
|
|
104
|
-
maybeAutoRestoreCodexShim(command, args);
|
|
69
|
+
// Head: version/help early exits, `ready` pre-parse (exit 64 before any
|
|
70
|
+
// preflight), and the bounded Codex-shim auto-restore preflight live in
|
|
71
|
+
// src/cli/root.ts (Phase 1 of the CLI deepening). runCli exits for
|
|
72
|
+
// version/help and returns the dispatchable head otherwise; the switch below
|
|
73
|
+
// owns command dispatch.
|
|
74
|
+
const head = await runCli(process.argv.slice(2));
|
|
75
|
+
const args = head.args;
|
|
76
|
+
const command = head.command;
|
|
105
77
|
|
|
106
78
|
function parsePortOption(): number | undefined {
|
|
107
79
|
if (args.length === 1) return undefined;
|
|
@@ -936,470 +908,37 @@ async function handleRecoverHistory() {
|
|
|
936
908
|
* and exits with the returned code; it performs no parsing and no I/O of its
|
|
937
909
|
* own. The full behavior is unit-testable without spawning a subprocess.
|
|
938
910
|
*/
|
|
939
|
-
async function handleReady(args: ReadyArgs): Promise<
|
|
940
|
-
|
|
911
|
+
async function handleReady(args: ReadyArgs): Promise<number> {
|
|
912
|
+
return runReady(args);
|
|
941
913
|
}
|
|
942
914
|
|
|
943
|
-
|
|
944
|
-
|
|
945
|
-
|
|
946
|
-
|
|
947
|
-
|
|
948
|
-
|
|
949
|
-
|
|
950
|
-
|
|
951
|
-
|
|
952
|
-
|
|
953
|
-
|
|
954
|
-
|
|
955
|
-
|
|
956
|
-
|
|
957
|
-
|
|
958
|
-
}
|
|
959
|
-
break;
|
|
960
|
-
}
|
|
961
|
-
case "restore":
|
|
962
|
-
case "eject": {
|
|
963
|
-
const restoreJson = args[1] === "--json";
|
|
964
|
-
if (args[1] === "back") {
|
|
965
|
-
// Reverse switch: re-point plain `codex` at the RUNNING proxy without touching its
|
|
966
|
-
// lifecycle — the counterpart of `ocx restore`. Start/stop triggers are unchanged;
|
|
967
|
-
// this only re-runs the same inject (config + catalog + history) `ocx start` does.
|
|
968
|
-
const live = await findLiveProxy();
|
|
969
|
-
if (!live) {
|
|
970
|
-
console.error("No running proxy found. Run 'ocx start' — it injects opencodex automatically.");
|
|
971
|
-
process.exit(1);
|
|
972
|
-
}
|
|
973
|
-
const desired = setIntegrationEnabled("codex", true);
|
|
974
|
-
if (!desired.ok) {
|
|
975
|
-
process.exitCode = desired.reason === "conflict" ? 2 : 1;
|
|
976
|
-
console.error(`Codex desired state was not saved (${desired.reason}).`);
|
|
977
|
-
break;
|
|
978
|
-
}
|
|
979
|
-
const synced = await syncModelsToCodex(live.port);
|
|
980
|
-
if (synced.status === "skipped") {
|
|
981
|
-
process.exitCode = 2;
|
|
982
|
-
console.error("Codex integration is OFF; restore back did not change Codex. Retry after the competing integration change finishes.");
|
|
983
|
-
break;
|
|
984
|
-
}
|
|
985
|
-
if (!synced.ok) {
|
|
986
|
-
process.exitCode = 1;
|
|
987
|
-
console.error("Plain `codex` was not switched back to opencodex. Fix the reported Codex config issue and retry.");
|
|
988
|
-
break;
|
|
989
|
-
}
|
|
990
|
-
const target = collectOrcaCodexHomeDiagnostic();
|
|
991
|
-
console.log(`Plain \`codex\` now routes through opencodex in ${target.effectiveCodexHome} (undo with: ocx restore).`);
|
|
992
|
-
break;
|
|
993
|
-
}
|
|
994
|
-
const desired = setIntegrationEnabled("codex", false);
|
|
995
|
-
if (!desired.ok) {
|
|
996
|
-
process.exitCode = desired.reason === "conflict" ? 2 : 1;
|
|
997
|
-
if (restoreJson) {
|
|
998
|
-
// Machine-readable contract: every restore --json outcome emits one
|
|
999
|
-
// schema-complete envelope on stdout, including pre-machinery failures.
|
|
1000
|
-
const { skippedRestoreEnvelope } = await import("../codex/inject");
|
|
1001
|
-
console.log(JSON.stringify(skippedRestoreEnvelope(false, `Codex desired state was not saved (${desired.reason}).`)));
|
|
1002
|
-
} else {
|
|
1003
|
-
console.error(`Codex desired state was not saved (${desired.reason}).`);
|
|
1004
|
-
}
|
|
1005
|
-
break;
|
|
1006
|
-
}
|
|
1007
|
-
// A repeated OFF on an already-clean home is a policy no-op. Do not enter
|
|
1008
|
-
// restore's native-profile machinery merely to prove there is nothing to
|
|
1009
|
-
// restore: those locks live in CODEX_HOME and a skip must create nothing.
|
|
1010
|
-
if (desired.status === "unchanged") {
|
|
1011
|
-
const { classifyNativeRoutedResidue } = await import("../codex/native-residue");
|
|
1012
|
-
if (classifyNativeRoutedResidue().kind === "clean") {
|
|
1013
|
-
const alreadyOff = "Codex integration is already OFF and native; no Codex files changed.";
|
|
1014
|
-
if (restoreJson) {
|
|
1015
|
-
const { skippedRestoreEnvelope } = await import("../codex/inject");
|
|
1016
|
-
console.log(JSON.stringify(skippedRestoreEnvelope(true, alreadyOff)));
|
|
1017
|
-
} else {
|
|
1018
|
-
console.log(alreadyOff);
|
|
1019
|
-
}
|
|
1020
|
-
break;
|
|
1021
|
-
}
|
|
1022
|
-
}
|
|
1023
|
-
let r: { success: boolean; message: string };
|
|
1024
|
-
try {
|
|
1025
|
-
r = await restoreNativeCodexAsync({ revalidateDesiredState: true });
|
|
1026
|
-
} catch (err) {
|
|
1027
|
-
r = { success: false, message: err instanceof Error ? err.message : String(err) };
|
|
1028
|
-
}
|
|
1029
|
-
if (restoreJson) {
|
|
1030
|
-
// Spawned callers need the artifact-level result to distinguish a busy
|
|
1031
|
-
// history worker from a successful native restore. Keep stdout machine
|
|
1032
|
-
// readable; human framing remains the default command contract.
|
|
1033
|
-
console.log(JSON.stringify(r));
|
|
1034
|
-
if (!r.success) process.exitCode = 1;
|
|
1035
|
-
break;
|
|
1036
|
-
}
|
|
1037
|
-
if (r.success) console.log(`✅ ${r.message}`);
|
|
1038
|
-
else {
|
|
1039
|
-
console.error(`⚠️ ${r.message}`);
|
|
1040
|
-
process.exitCode = 1;
|
|
1041
|
-
}
|
|
1042
|
-
try {
|
|
1043
|
-
const g = stripGrokConfig();
|
|
1044
|
-
if (g.changed) console.log(`✅ ${g.message}`);
|
|
1045
|
-
else if (!g.ok) {
|
|
1046
|
-
console.error(`⚠️ ${g.message}`);
|
|
1047
|
-
process.exitCode = 1;
|
|
1048
|
-
}
|
|
1049
|
-
} catch { /* best-effort */ }
|
|
1050
|
-
if (r.success) {
|
|
1051
|
-
console.log("Codex integration is OFF and plain `codex` now runs natively. Switch back with: ocx restore back");
|
|
1052
|
-
} else {
|
|
1053
|
-
console.error("Plain `codex` was not fully restored. Inspect $CODEX_HOME/config.toml before using native Codex.");
|
|
1054
|
-
}
|
|
1055
|
-
break;
|
|
1056
|
-
}
|
|
1057
|
-
case "recover-history":
|
|
1058
|
-
await handleRecoverHistory();
|
|
1059
|
-
break;
|
|
1060
|
-
case "uninstall":
|
|
1061
|
-
case "remove":
|
|
1062
|
-
await handleUninstall();
|
|
1063
|
-
break;
|
|
1064
|
-
case "status":
|
|
1065
|
-
await handleStatus();
|
|
1066
|
-
break;
|
|
1067
|
-
case "doctor": {
|
|
1068
|
-
const { runDoctor } = await import("./doctor");
|
|
1069
|
-
await runDoctor(args.slice(1));
|
|
1070
|
-
break;
|
|
1071
|
-
}
|
|
1072
|
-
case "debug": {
|
|
1073
|
-
const { handleDebugCommand } = await import("./debug");
|
|
1074
|
-
await handleDebugCommand(args.slice(1));
|
|
1075
|
-
break;
|
|
1076
|
-
}
|
|
1077
|
-
case "ensure":
|
|
1078
|
-
await handleEnsure();
|
|
1079
|
-
break;
|
|
1080
|
-
case "login": {
|
|
1081
|
-
const { handleLogin } = await import("../oauth/login-cli");
|
|
1082
|
-
await handleLogin(args[1]);
|
|
1083
|
-
break;
|
|
1084
|
-
}
|
|
1085
|
-
case "logout": {
|
|
1086
|
-
const { removeCredential } = await import("../oauth/store");
|
|
1087
|
-
const name = (args[1] ?? "").trim().toLowerCase();
|
|
1088
|
-
await removeCredential(name);
|
|
1089
|
-
console.log(`Logged out of ${name || "(none)"}.`);
|
|
1090
|
-
break;
|
|
1091
|
-
}
|
|
1092
|
-
case "sync": {
|
|
1093
|
-
const restartCodex = args.slice(1).includes("--restart-codex");
|
|
1094
|
-
const synced = await syncModelsToCodex((await findLiveProxy())?.port);
|
|
1095
|
-
if (synced.status === "skipped") {
|
|
1096
|
-
console.log("Codex integration is OFF; sync skipped and no Codex files changed.");
|
|
1097
|
-
} else if (!synced.ok) {
|
|
1098
|
-
process.exitCode = 1;
|
|
1099
|
-
console.error("Codex sync did not complete. Fix the reported Codex config issue and retry.");
|
|
1100
|
-
}
|
|
1101
|
-
// Only warn/restart when a catalog or models_cache write actually happened. This is
|
|
1102
|
-
// deliberately not an `else`: refreshCodexModelCatalog runs before injectCodexConfig,
|
|
1103
|
-
// so a sync can fail (`ok: false`) after the catalog was already rewritten — which is
|
|
1104
|
-
// exactly when a long-lived app-server is holding the stale list.
|
|
1105
|
-
if (synced.catalogWritten || synced.cacheSynced) {
|
|
1106
|
-
const { afterCatalogWriteHandleAppServers } = await import("../codex/app-server-processes");
|
|
1107
|
-
afterCatalogWriteHandleAppServers({ restart: restartCodex, log: console });
|
|
1108
|
-
}
|
|
1109
|
-
break;
|
|
1110
|
-
}
|
|
1111
|
-
case "v2": {
|
|
1112
|
-
const { cmdV2 } = await import("./v2");
|
|
1113
|
-
process.exitCode = await cmdV2(args.slice(1), {}, async () => (await findLiveProxy())?.port);
|
|
1114
|
-
break;
|
|
1115
|
-
}
|
|
1116
|
-
case "sync-cache": {
|
|
1117
|
-
const restartCodex = args.slice(1).includes("--restart-codex");
|
|
1118
|
-
if (!shouldSyncCodexOnStart(loadConfig())) {
|
|
1119
|
-
console.log("Codex integration is OFF; cache sync skipped and no Codex files changed.");
|
|
1120
|
-
break;
|
|
1121
|
-
}
|
|
1122
|
-
const { withCatalogWriteSerialization } = await import("../codex/catalog-write-serialization");
|
|
1123
|
-
const { invalidateCodexModelsCacheWithPermit } = await import("../codex/catalog/sync");
|
|
1124
|
-
const { getCodexHome } = await import("../codex/paths");
|
|
1125
|
-
const owningCodexHome = getCodexHome();
|
|
1126
|
-
const invalidated = withCatalogWriteSerialization(owningCodexHome, permit =>
|
|
1127
|
-
invalidateCodexModelsCacheWithPermit(permit, owningCodexHome));
|
|
1128
|
-
// Only warn/restart when models_cache was actually rewritten from a readable catalog.
|
|
1129
|
-
if (invalidated.kind === "completed" && invalidated.value) {
|
|
1130
|
-
const { afterCatalogWriteHandleAppServers } = await import("../codex/app-server-processes");
|
|
1131
|
-
afterCatalogWriteHandleAppServers({ restart: restartCodex, log: console });
|
|
1132
|
-
}
|
|
1133
|
-
break;
|
|
1134
|
-
}
|
|
1135
|
-
case "gui": {
|
|
1136
|
-
const cfg = await import("../config");
|
|
1137
|
-
const config = cfg.loadConfig();
|
|
1138
|
-
// Identity-checked liveness (not the pid file + a fixed sleep): finds a fallback-port
|
|
1139
|
-
// proxy and waits until the spawned one actually answers before opening the browser.
|
|
1140
|
-
let live = await findLiveProxy();
|
|
1141
|
-
if (!live) {
|
|
1142
|
-
console.log("Proxy not running. Starting...");
|
|
1143
|
-
const child = spawn(process.execPath, startArgv((config.port ?? 10100) > 0 ? (config.port ?? 10100) : undefined), {
|
|
1144
|
-
detached: true,
|
|
1145
|
-
stdio: "ignore",
|
|
1146
|
-
windowsHide: true,
|
|
1147
|
-
env: withProcessRuntimeProvenance(process.env),
|
|
1148
|
-
});
|
|
1149
|
-
child.unref();
|
|
1150
|
-
live = await waitForProxy();
|
|
1151
|
-
if (!live) {
|
|
1152
|
-
console.error("❌ Proxy did not become healthy after starting. Not opening the GUI.");
|
|
1153
|
-
process.exit(1);
|
|
1154
|
-
}
|
|
1155
|
-
}
|
|
1156
|
-
// Open the host the proxy actually binds — `localhost` only answers for
|
|
1157
|
-
// loopback/wildcard binds, not a concrete LAN/IPv6 hostname.
|
|
1158
|
-
const guiHost = probeHostname(live?.hostname ?? config.hostname);
|
|
1159
|
-
const guiUrl = `http://${guiHost === "127.0.0.1" ? "localhost" : guiHost}:${live?.port ?? config.port}`;
|
|
1160
|
-
console.log(`Opening ${guiUrl}`);
|
|
1161
|
-
const { openUrl } = await import("../lib/open-url");
|
|
1162
|
-
openUrl(guiUrl);
|
|
1163
|
-
break;
|
|
1164
|
-
}
|
|
1165
|
-
case "service":
|
|
1166
|
-
await serviceCommand(...args.slice(1));
|
|
1167
|
-
break;
|
|
1168
|
-
case "tray": {
|
|
1169
|
-
const { windowsTrayCommand } = await import("../tray/windows");
|
|
1170
|
-
await windowsTrayCommand(args.slice(1));
|
|
1171
|
-
break;
|
|
1172
|
-
}
|
|
1173
|
-
case "codex-shim": {
|
|
1174
|
-
const { codexShimStatus, diagnoseCodexShim, installCodexShim, uninstallCodexShim } = await import("../codex/shim");
|
|
1175
|
-
switch (args[1]) {
|
|
1176
|
-
case "install": {
|
|
1177
|
-
const r = installCodexShim();
|
|
1178
|
-
const { collectCodexShimReadinessWarnings } = await import("./codex-shim-readiness");
|
|
1179
|
-
const warnings = diagnoseCodexShim().healthy
|
|
1180
|
-
? collectCodexShimReadinessWarnings()
|
|
1181
|
-
: [];
|
|
1182
|
-
console.log(`${r.installed && warnings.length === 0 ? "✅ " : "⚠️ "}${r.message}`);
|
|
1183
|
-
for (const warning of warnings) console.warn(` ${warning}`);
|
|
1184
|
-
break;
|
|
1185
|
-
}
|
|
1186
|
-
case "status":
|
|
1187
|
-
console.log(codexShimStatus());
|
|
1188
|
-
break;
|
|
1189
|
-
case "uninstall":
|
|
1190
|
-
case "remove": {
|
|
1191
|
-
const r = uninstallCodexShim();
|
|
1192
|
-
console.log(r.removed ? `✅ ${r.message}` : `⚠️ ${r.message}`);
|
|
1193
|
-
break;
|
|
1194
|
-
}
|
|
1195
|
-
default:
|
|
1196
|
-
console.error("Usage: ocx codex-shim <install|status|uninstall|remove>");
|
|
1197
|
-
process.exit(1);
|
|
1198
|
-
}
|
|
1199
|
-
break;
|
|
1200
|
-
}
|
|
1201
|
-
case "update": {
|
|
1202
|
-
// `ocx update --help` must print usage and exit WITHOUT side effects — running the
|
|
1203
|
-
// real self-update stops the proxy and drops in-flight routed streams (issue #168).
|
|
1204
|
-
if (hasHelpFlag(args.slice(1))) {
|
|
1205
|
-
printSubcommandUsage("update");
|
|
1206
|
-
break;
|
|
1207
|
-
}
|
|
1208
|
-
const { runUpdate } = await import("../update");
|
|
1209
|
-
await runUpdate();
|
|
1210
|
-
break;
|
|
1211
|
-
}
|
|
1212
|
-
case "__refresh-version": {
|
|
1213
|
-
// Hidden, detached helper spawned by the update prompt to refresh the
|
|
1214
|
-
// cached latest version without blocking the foreground start. Not in help.
|
|
1215
|
-
const { refreshVersionCache } = await import("../update/notify");
|
|
1216
|
-
const channel = args[1] === "preview" ? "preview" : "latest";
|
|
1217
|
-
await refreshVersionCache(channel);
|
|
1218
|
-
break;
|
|
1219
|
-
}
|
|
1220
|
-
case "__tray-start":
|
|
1221
|
-
case "__tray-restart":
|
|
1222
|
-
case "__startup-health":
|
|
1223
|
-
await dispatchInternalCliCommand(command as InternalCliCommand, {
|
|
1224
|
-
trayStart: async () => { await handleTrayProxyStart(); },
|
|
1225
|
-
trayRestart: handleTrayProxyRestart,
|
|
1226
|
-
startupHealth: async () => {
|
|
1227
|
-
const { collectStartupHealth } = await import("../codex/autostart-health");
|
|
1228
|
-
console.log(JSON.stringify(collectStartupHealth(loadConfig())));
|
|
1229
|
-
},
|
|
915
|
+
process.exit(await dispatchCommand(head, {
|
|
916
|
+
args,
|
|
917
|
+
command,
|
|
918
|
+
head,
|
|
919
|
+
loadConfig,
|
|
920
|
+
findLiveProxy,
|
|
921
|
+
probeHostname,
|
|
922
|
+
waitForProxy,
|
|
923
|
+
startArgv,
|
|
924
|
+
spawnDetached: argv => {
|
|
925
|
+
const child = spawn(process.execPath, argv, {
|
|
926
|
+
detached: true,
|
|
927
|
+
stdio: "ignore",
|
|
928
|
+
windowsHide: true,
|
|
929
|
+
env: withProcessRuntimeProvenance(process.env),
|
|
1230
930
|
});
|
|
1231
|
-
|
|
1232
|
-
|
|
1233
|
-
|
|
1234
|
-
|
|
1235
|
-
|
|
1236
|
-
|
|
1237
|
-
|
|
1238
|
-
|
|
1239
|
-
|
|
1240
|
-
|
|
1241
|
-
|
|
1242
|
-
|
|
1243
|
-
|
|
1244
|
-
|
|
1245
|
-
// The running proxy owns its drain and replacement through /api/system/restart.
|
|
1246
|
-
// If nothing is live, restart degrades to the documented `ensure` start behavior.
|
|
1247
|
-
await handleProxyRestart(handleRestartStartWhenStopped);
|
|
1248
|
-
break;
|
|
1249
|
-
}
|
|
1250
|
-
case "health": {
|
|
1251
|
-
const healthArgs = args.slice(1);
|
|
1252
|
-
const wantsHealthJson = healthArgs.includes("--json");
|
|
1253
|
-
const live = await findLiveProxy();
|
|
1254
|
-
if (wantsHealthJson) {
|
|
1255
|
-
console.log(JSON.stringify({ ok: !!live, pid: live?.pid ?? null, port: live?.port ?? null }));
|
|
1256
|
-
} else {
|
|
1257
|
-
console.log(live ? `Proxy healthy (PID ${live.pid}, port ${live.port})` : "Proxy not healthy");
|
|
1258
|
-
}
|
|
1259
|
-
process.exit(live ? 0 : 1);
|
|
1260
|
-
}
|
|
1261
|
-
case "ready":
|
|
1262
|
-
// Fail-closed impossible-state guard: readyArgs is populated by the
|
|
1263
|
-
// preparse block before maybeAutoRestoreCodexShim, so reaching here
|
|
1264
|
-
// without it means dispatch diverged. Refuse with code 64 and perform
|
|
1265
|
-
// NO I/O (no discovery/probe). process.exit is `never`, narrowing below.
|
|
1266
|
-
if (!readyArgs) process.exit(64);
|
|
1267
|
-
await handleReady(readyArgs);
|
|
1268
|
-
break;
|
|
1269
|
-
case "provider": {
|
|
1270
|
-
const { handleProviderCommand } = await import("./provider");
|
|
1271
|
-
await handleProviderCommand(args.slice(1));
|
|
1272
|
-
break;
|
|
1273
|
-
}
|
|
1274
|
-
case "account": {
|
|
1275
|
-
const { cmdAccount } = await import("./account");
|
|
1276
|
-
process.exitCode = await cmdAccount(args.slice(1));
|
|
1277
|
-
break;
|
|
1278
|
-
}
|
|
1279
|
-
case "models":
|
|
1280
|
-
case "model": {
|
|
1281
|
-
const { handleModels } = await import("./models");
|
|
1282
|
-
await handleModels(args.slice(1));
|
|
1283
|
-
break;
|
|
1284
|
-
}
|
|
1285
|
-
case "combo": {
|
|
1286
|
-
const { handleComboCommand } = await import("./combo");
|
|
1287
|
-
process.exitCode = await handleComboCommand(args.slice(1));
|
|
1288
|
-
break;
|
|
1289
|
-
}
|
|
1290
|
-
case "route": {
|
|
1291
|
-
if (args[1] !== "combo" && args[1] !== "policy") {
|
|
1292
|
-
console.error("Usage: ocx route <combo|policy> <subcommand>");
|
|
1293
|
-
process.exitCode = 2;
|
|
1294
|
-
break;
|
|
1295
|
-
}
|
|
1296
|
-
if (args[1] === "combo") {
|
|
1297
|
-
const { handleComboCommand } = await import("./combo");
|
|
1298
|
-
process.exitCode = await handleComboCommand(args.slice(2));
|
|
1299
|
-
} else {
|
|
1300
|
-
const { handleRoutePolicyCommand } = await import("./route-policy");
|
|
1301
|
-
process.exitCode = await handleRoutePolicyCommand(args.slice(2));
|
|
1302
|
-
}
|
|
1303
|
-
break;
|
|
1304
|
-
}
|
|
1305
|
-
case "agent": {
|
|
1306
|
-
const { handleAgentCommand } = await import("./agent");
|
|
1307
|
-
process.exitCode = await handleAgentCommand(args.slice(1));
|
|
1308
|
-
break;
|
|
1309
|
-
}
|
|
1310
|
-
case "observe": {
|
|
1311
|
-
const { handleObserveCommand } = await import("./observe");
|
|
1312
|
-
process.exitCode = await handleObserveCommand(args.slice(1));
|
|
1313
|
-
break;
|
|
1314
|
-
}
|
|
1315
|
-
case "logs":
|
|
1316
|
-
case "usage":
|
|
1317
|
-
case "storage":
|
|
1318
|
-
case "memory": {
|
|
1319
|
-
const { handleObserveCommand } = await import("./observe");
|
|
1320
|
-
process.exitCode = await handleObserveCommand([command, ...args.slice(1)]);
|
|
1321
|
-
break;
|
|
1322
|
-
}
|
|
1323
|
-
case "access": {
|
|
1324
|
-
const { handleAccessCommand } = await import("./access");
|
|
1325
|
-
process.exitCode = await handleAccessCommand(args.slice(1));
|
|
1326
|
-
break;
|
|
1327
|
-
}
|
|
1328
|
-
case "api-key": {
|
|
1329
|
-
const { handleAccessCommand } = await import("./access");
|
|
1330
|
-
process.exitCode = await handleAccessCommand(["key", ...args.slice(1)]);
|
|
1331
|
-
break;
|
|
1332
|
-
}
|
|
1333
|
-
case "export": {
|
|
1334
|
-
const { handleExportCommand } = await import("./export-command");
|
|
1335
|
-
process.exitCode = await handleExportCommand(args.slice(1));
|
|
1336
|
-
break;
|
|
1337
|
-
}
|
|
1338
|
-
case "grok": {
|
|
1339
|
-
const { handleGrokCommand } = await import("./integrations");
|
|
1340
|
-
process.exitCode = await handleGrokCommand(args.slice(1));
|
|
1341
|
-
break;
|
|
1342
|
-
}
|
|
1343
|
-
case "integration": {
|
|
1344
|
-
const integration = args[1];
|
|
1345
|
-
if (integration === "grok") {
|
|
1346
|
-
const { handleGrokCommand } = await import("./integrations");
|
|
1347
|
-
process.exitCode = await handleGrokCommand(args.slice(2));
|
|
1348
|
-
} else if (integration === "claude") {
|
|
1349
|
-
const { handleClaudeConfigCommand } = await import("./integrations");
|
|
1350
|
-
process.exitCode = await handleClaudeConfigCommand(args.slice(2));
|
|
1351
|
-
} else if (integration === "client") {
|
|
1352
|
-
const { handleClientIntegrationCommand } = await import("./integrations");
|
|
1353
|
-
process.exitCode = await handleClientIntegrationCommand(args.slice(2));
|
|
1354
|
-
} else {
|
|
1355
|
-
console.error("Usage: ocx integration <claude|grok|client> <subcommand>");
|
|
1356
|
-
process.exitCode = 2;
|
|
1357
|
-
}
|
|
1358
|
-
break;
|
|
1359
|
-
}
|
|
1360
|
-
case "system": {
|
|
1361
|
-
const { handleSystemCommand } = await import("./system-command");
|
|
1362
|
-
process.exitCode = await handleSystemCommand(args.slice(1));
|
|
1363
|
-
break;
|
|
1364
|
-
}
|
|
1365
|
-
case "config": {
|
|
1366
|
-
const { handleConfigCommand } = await import("./config-command");
|
|
1367
|
-
process.exitCode = await handleConfigCommand(args.slice(1));
|
|
1368
|
-
break;
|
|
1369
|
-
}
|
|
1370
|
-
case "lab": {
|
|
1371
|
-
const { handleLabCommand } = await import("./lab");
|
|
1372
|
-
process.exitCode = await handleLabCommand(args.slice(1));
|
|
1373
|
-
break;
|
|
1374
|
-
}
|
|
1375
|
-
case "claude": {
|
|
1376
|
-
const { cmdClaude } = await import("./claude");
|
|
1377
|
-
// "ocx claude desktop" → write Desktop 3P config
|
|
1378
|
-
if (args[1] === "desktop") {
|
|
1379
|
-
const { handleClaudeDesktopCommand } = await import("./claude-desktop");
|
|
1380
|
-
const exitCode = await handleClaudeDesktopCommand(args.slice(2));
|
|
1381
|
-
if (exitCode !== 0) process.exit(exitCode);
|
|
1382
|
-
break;
|
|
1383
|
-
}
|
|
1384
|
-
if (args[1] === "config") {
|
|
1385
|
-
const { handleClaudeConfigCommand } = await import("./integrations");
|
|
1386
|
-
process.exitCode = await handleClaudeConfigCommand(args.slice(2));
|
|
1387
|
-
break;
|
|
1388
|
-
}
|
|
1389
|
-
process.exit(await cmdClaude(args.slice(1)));
|
|
1390
|
-
}
|
|
1391
|
-
case "opencode": {
|
|
1392
|
-
const { cmdOpencode } = await import("./opencode");
|
|
1393
|
-
process.exit(await cmdOpencode(args.slice(1)));
|
|
1394
|
-
}
|
|
1395
|
-
case "help":
|
|
1396
|
-
case "--help":
|
|
1397
|
-
case "-h":
|
|
1398
|
-
case undefined:
|
|
1399
|
-
printUsage();
|
|
1400
|
-
break;
|
|
1401
|
-
default:
|
|
1402
|
-
console.error(`Unknown command: ${command}`);
|
|
1403
|
-
printUsage();
|
|
1404
|
-
process.exit(1);
|
|
1405
|
-
}
|
|
931
|
+
child.unref();
|
|
932
|
+
},
|
|
933
|
+
handleStart,
|
|
934
|
+
handleStop,
|
|
935
|
+
handleEnsure,
|
|
936
|
+
handleTrayProxyStart,
|
|
937
|
+
handleTrayProxyRestart,
|
|
938
|
+
handleRestartStartWhenStopped,
|
|
939
|
+
handleProxyRestart,
|
|
940
|
+
handleUninstall,
|
|
941
|
+
handleStatus,
|
|
942
|
+
handleRecoverHistory,
|
|
943
|
+
handleReady,
|
|
944
|
+
}));
|