@bitkyc08/opencodex 2.76.0 → 2.78.0-preview.20261005
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/bin/ocx.mjs +11 -10
- package/gui/dist/assets/App-CppMz-6w.js +54 -0
- package/gui/dist/assets/App-lCIslZ1L.css +1 -0
- package/gui/dist/assets/{Tray-DjNwwrWS.js → Tray-CJWQqtVv.js} +1 -1
- package/gui/dist/assets/index-DQt9srNi.js +94 -0
- package/gui/dist/assets/index-DmQB8D_R.css +1 -0
- package/gui/dist/assets/quota-summary-BMsyoZH2.js +1 -0
- package/gui/dist/index.html +4 -3
- package/package.json +1 -1
- package/src/adapters/anthropic/beta-allowlist.ts +19 -2
- package/src/adapters/anthropic/client-identity.ts +13 -4
- package/src/adapters/anthropic/native-client-preamble.ts +31 -0
- package/src/adapters/anthropic/passthrough.ts +103 -25
- package/src/adapters/antigravity-refusal.ts +28 -0
- package/src/adapters/cursor/protobuf-request.ts +6 -0
- package/src/adapters/cursor/request-builder.ts +3 -0
- package/src/adapters/cursor/structured-output.ts +13 -0
- package/src/adapters/cursor/types.ts +2 -0
- package/src/adapters/devin/cloud-direct/chat.ts +7 -2
- package/src/adapters/devin/trajectory.ts +49 -0
- package/src/adapters/devin.ts +13 -0
- package/src/adapters/ollama-native.ts +62 -19
- package/src/adapters/openai-responses/passthrough.ts +133 -103
- package/src/adapters/openai-responses/request-strips.ts +10 -4
- package/src/adapters/zed.ts +26 -4
- package/src/bridge/response-json.ts +14 -14
- package/src/bridge/sse.ts +15 -5
- package/src/chatgpt/app-server-shim/bundle-trust.ts +40 -10
- package/src/chatgpt/app-server-shim/gate-rewrite.ts +3 -0
- package/src/claude/agents-inject.ts +4 -43
- package/src/claude/gateway-cache.ts +16 -13
- package/src/claude/inbound-model-options.ts +9 -2
- package/src/claude/intercept/cli-catalog.ts +27 -16
- package/src/claude/intercept/client-hello.ts +103 -0
- package/src/claude/intercept/model-bindings.ts +3 -2
- package/src/claude/intercept/picker-bootstrap.ts +37 -16
- package/src/claude/intercept/picker-budget.ts +41 -0
- package/src/claude/intercept/picker-listener.ts +279 -66
- package/src/claude/outbound.ts +2 -0
- package/src/claude/subagent-force-status.ts +53 -0
- package/src/claude/subagent-model.ts +93 -0
- package/src/cli/access-audio-input.ts +84 -0
- package/src/cli/access-audio-live.ts +99 -0
- package/src/cli/access-audio.ts +123 -0
- package/src/cli/access-data-client.ts +127 -0
- package/src/cli/access-data-plane.ts +104 -0
- package/src/cli/access-data-response.ts +76 -0
- package/src/cli/access.ts +65 -2
- package/src/cli/account-api.ts +33 -6
- package/src/cli/account-auth.ts +111 -42
- package/src/cli/account-key-quota.ts +118 -0
- package/src/cli/account-main.ts +11 -4
- package/src/cli/account-next-actions.ts +63 -0
- package/src/cli/account-policy-dto.ts +68 -0
- package/src/cli/account-policy.ts +167 -0
- package/src/cli/account-target.ts +8 -0
- package/src/cli/account.ts +37 -9
- package/src/cli/agent-runtime-settings.ts +130 -0
- package/src/cli/agent-settings.ts +101 -0
- package/src/cli/agent.ts +29 -2
- package/src/cli/alias.ts +7 -2
- package/src/cli/aside-profiles.ts +2 -2
- package/src/cli/capabilities-access-remote.ts +147 -0
- package/src/cli/capabilities-accounts.ts +195 -0
- package/src/cli/capabilities-agents-routing.ts +414 -0
- package/src/cli/capabilities-base.ts +783 -0
- package/src/cli/capabilities-command.ts +1 -0
- package/src/cli/capabilities-integrations.ts +264 -0
- package/src/cli/capabilities-lab.ts +214 -0
- package/src/cli/capabilities-observe-system.ts +662 -0
- package/src/cli/capabilities-provider-models.ts +302 -0
- package/src/cli/capabilities.ts +30 -1190
- package/src/cli/capability-types.ts +54 -0
- package/src/cli/catalog-command-result.ts +57 -0
- package/src/cli/chatgpt-command.ts +35 -9
- package/src/cli/claude-agent-startup-sync.ts +17 -0
- package/src/cli/claude-desktop-profile.ts +100 -0
- package/src/cli/claude-desktop.ts +39 -6
- package/src/cli/claude.ts +22 -6
- package/src/cli/codex-shim-autorestore.ts +2 -1
- package/src/cli/codex-shim-readiness.ts +109 -0
- package/src/cli/combo-input.ts +88 -0
- package/src/cli/combo-result.ts +52 -0
- package/src/cli/combo-stats.ts +123 -0
- package/src/cli/combo.ts +37 -14
- package/src/cli/companion-timeline.ts +142 -0
- package/src/cli/companion-usage.ts +146 -0
- package/src/cli/companion.ts +12 -3
- package/src/cli/config-command.ts +24 -8
- package/src/cli/connect.ts +19 -0
- package/src/cli/dispatch.ts +55 -82
- package/src/cli/doctor.ts +22 -4
- package/src/cli/export-command.ts +20 -9
- package/src/cli/gui.ts +8 -3
- package/src/cli/help-catalog.ts +101 -0
- package/src/cli/help-models-context.ts +17 -0
- package/src/cli/help-navigation.ts +50 -0
- package/src/cli/help-recovery.ts +66 -0
- package/src/cli/help.ts +69 -11
- package/src/cli/index.ts +38 -27
- package/src/cli/injection-follow.ts +35 -0
- package/src/cli/inspect.ts +5 -0
- package/src/cli/integration-aside-sync.ts +69 -0
- package/src/cli/integration-cursor.ts +106 -0
- package/src/cli/integration-input.ts +60 -0
- package/src/cli/integration-journal.ts +49 -0
- package/src/cli/integration-plan-dto.ts +156 -0
- package/src/cli/integration-preview.ts +215 -0
- package/src/cli/integrations.ts +24 -18
- package/src/cli/json-input.ts +134 -0
- package/src/cli/link.ts +32 -4
- package/src/cli/local-sync-result.ts +41 -0
- package/src/cli/log-follow.ts +84 -0
- package/src/cli/log-view-filter.ts +146 -0
- package/src/cli/logout-command.ts +44 -0
- package/src/cli/model-picker-ordering.ts +137 -0
- package/src/cli/models-custom-input.ts +107 -0
- package/src/cli/models-custom-runtime.ts +112 -0
- package/src/cli/models-order.ts +194 -0
- package/src/cli/models-runtime-subcommands.ts +2 -0
- package/src/cli/models-runtime.ts +9 -1
- package/src/cli/models.ts +66 -81
- package/src/cli/observe-stream.ts +142 -0
- package/src/cli/observe.ts +75 -34
- package/src/cli/opencode.ts +54 -10
- package/src/cli/provider-batch.ts +77 -0
- package/src/cli/provider-lifecycle-runtime.ts +170 -0
- package/src/cli/provider-result.ts +124 -0
- package/src/cli/provider-runtime.ts +15 -12
- package/src/cli/provider-settings.ts +143 -0
- package/src/cli/provider.ts +116 -64
- package/src/cli/registry.ts +90 -24
- package/src/cli/remote-workspace-hub.ts +83 -0
- package/src/cli/remote-workspace.ts +6 -1
- package/src/cli/restart-failure.ts +27 -0
- package/src/cli/root.ts +42 -9
- package/src/cli/route-policy-write.ts +137 -0
- package/src/cli/route-policy.ts +8 -0
- package/src/cli/runtime-api.ts +57 -80
- package/src/cli/secret-args.ts +149 -0
- package/src/cli/settings-result.ts +30 -0
- package/src/cli/storage.ts +77 -7
- package/src/cli/system-command.ts +60 -2
- package/src/cli/system-restart-client.ts +20 -3
- package/src/cli/system-settings-parity.ts +83 -0
- package/src/cli/tray-proxy.ts +3 -2
- package/src/cli/update-restart-candidate.ts +21 -0
- package/src/cli/update-restart-child.ts +81 -0
- package/src/cli/update-restart-home.ts +38 -0
- package/src/cli/update-restart-transport.ts +193 -0
- package/src/cli/update-restart.ts +260 -0
- package/src/cli/usage-model-search.ts +58 -0
- package/src/cli/usage-report.ts +13 -5
- package/src/cli/v2-input.ts +66 -0
- package/src/cli/v2-local-output.ts +37 -0
- package/src/cli/v2-runtime.ts +90 -0
- package/src/cli/v2.ts +102 -144
- package/src/clients/config-export/contracts.ts +100 -0
- package/src/clients/config-export/droid.ts +54 -2
- package/src/clients/config-export/dsh.ts +21 -0
- package/src/clients/config-export/kilo.ts +12 -2
- package/src/clients/config-export/model-metadata.ts +10 -4
- package/src/clients/config-export/reasoning-metadata.ts +47 -0
- package/src/clients/config-export.ts +53 -67
- package/src/clients/omo-role-models.ts +17 -3
- package/src/codex/account-credit-use.ts +4 -2
- package/src/codex/account-runtime-state.ts +21 -0
- package/src/codex/account-store.ts +11 -47
- package/src/codex/account-usability.ts +11 -8
- package/src/codex/auth-api/account-list.ts +73 -63
- package/src/codex/auth-api/main-account-probe.ts +25 -12
- package/src/codex/auth-api/pool-mode-gate.ts +6 -9
- package/src/codex/auth-api/pool-quota-probe.ts +2 -4
- package/src/codex/auth-api/reset-credit-service.ts +3 -2
- package/src/codex/auth-context.ts +30 -11
- package/src/codex/catalog/aggregation.ts +3 -0
- package/src/codex/catalog/build-entries.ts +1 -1
- package/src/codex/catalog/bundled.ts +9 -2
- package/src/codex/catalog/heal-observation.ts +66 -0
- package/src/codex/catalog/model-hints.ts +2 -1
- package/src/codex/catalog/model-visibility.ts +6 -3
- package/src/codex/catalog/parsing.ts +2 -0
- package/src/codex/catalog/provider-models.ts +13 -4
- package/src/codex/catalog/publication-observer.ts +19 -0
- package/src/codex/catalog/remote.ts +13 -15
- package/src/codex/catalog/restore.ts +19 -6
- package/src/codex/catalog/retained-sync.ts +60 -11
- package/src/codex/catalog/routed-removal.ts +116 -0
- package/src/codex/catalog/write-audit-contract.ts +21 -0
- package/src/codex/catalog/write-audit.ts +171 -0
- package/src/codex/catalog-self-heal.ts +284 -0
- package/src/codex/catalog-write-serialization.ts +71 -7
- package/src/codex/chatgpt-refresh-failure.ts +56 -0
- package/src/codex/codex-home-owner.ts +124 -0
- package/src/codex/convergence.ts +57 -16
- package/src/codex/features.ts +8 -1
- package/src/codex/inject/restore.ts +46 -4
- package/src/codex/inject.ts +11 -1
- package/src/codex/internal/catalog-writer.ts +120 -13
- package/src/codex/journal.ts +49 -13
- package/src/codex/main-account.ts +144 -11
- package/src/codex/management-convergence.ts +3 -0
- package/src/codex/quota-refresh-outcome.ts +17 -2
- package/src/codex/quota-types.ts +36 -1
- package/src/codex/quota.ts +67 -16
- package/src/codex/refresh.ts +20 -9
- package/src/codex/routing/cooldown-math.ts +10 -4
- package/src/codex/routing/selection.ts +11 -4
- package/src/codex/routing.ts +9 -9
- package/src/codex/runtime.ts +7 -1
- package/src/codex/shim-diagnostics.ts +80 -0
- package/src/codex/shim-fingerprint.ts +7 -2
- package/src/codex/shim-migration.ts +153 -0
- package/src/codex/shim-overlay.ts +509 -0
- package/src/codex/shim-path-resolution.ts +145 -0
- package/src/codex/shim-probe.ts +4 -3
- package/src/codex/shim-state-file.ts +93 -7
- package/src/codex/shim.ts +54 -107
- package/src/codex/subagent-model-fallback.ts +2 -1
- package/src/codex/sync.ts +24 -4
- package/src/combos/failover.ts +101 -1
- package/src/combos/index.ts +1 -0
- package/src/combos/jev.ts +13 -3
- package/src/combos/resolve.ts +12 -0
- package/src/config/atomic-write.ts +13 -8
- package/src/config/diagnostics.ts +23 -1
- package/src/config/load-degrade.ts +7 -0
- package/src/config/provider-validation.ts +3 -0
- package/src/config/schema/chatgpt-desktop.ts +22 -0
- package/src/config/schema/compaction-triggers.ts +8 -0
- package/src/config/schema/config-schema.ts +43 -14
- package/src/config/schema/leaf-validators.ts +8 -3
- package/src/config/subagent-models.ts +12 -0
- package/src/generated/compatibility-version.json +645 -237
- package/src/grok/session-identity.ts +33 -0
- package/src/integrations/catalog-refresh.ts +1 -1
- package/src/integrations/merge.ts +13 -5
- package/src/integrations/mutation-plan.ts +50 -5
- package/src/integrations/omp-yaml-source.ts +181 -1
- package/src/integrations/ownership-policy.ts +66 -0
- package/src/integrations/registry.ts +50 -1
- package/src/integrations/state.ts +106 -19
- package/src/integrations/target.ts +25 -2
- package/src/integrations/writer.ts +107 -35
- package/src/lib/gui-pair-capability.ts +17 -0
- package/src/lib/package-tree-integrity.ts +42 -1
- package/src/lib/provider-client-headers.ts +62 -0
- package/src/lib/proxy-env.ts +3 -0
- package/src/lib/test-home-guard.ts +2 -1
- package/src/oauth/anthropic-account-refusal.ts +19 -8
- package/src/oauth/anthropic-continuity.ts +65 -0
- package/src/oauth/anthropic-identity.ts +75 -0
- package/src/oauth/anthropic-routing.ts +20 -15
- package/src/oauth/anthropic.ts +34 -3
- package/src/oauth/generic-account-failover.ts +21 -0
- package/src/oauth/health.ts +32 -5
- package/src/oauth/index.ts +42 -35
- package/src/oauth/local-token-detect.ts +7 -0
- package/src/oauth/pool-settings-capability.ts +9 -2
- package/src/oauth/refresh-policy.ts +2 -0
- package/src/oauth/store.ts +55 -6
- package/src/oauth/types.ts +9 -0
- package/src/protocols/encoders/messages.ts +4 -3
- package/src/protocols/plan-snapshot.ts +1 -1
- package/src/protocols/settings.ts +28 -4
- package/src/providers/antigravity-effort-families.ts +75 -0
- package/src/providers/antigravity-models.ts +54 -16
- package/src/providers/antigravity-wire-snapshot.ts +66 -0
- package/src/providers/derive.ts +2 -0
- package/src/providers/model-rename-fields.ts +3 -0
- package/src/providers/new-model-policy.ts +48 -10
- package/src/providers/registry/entries-extended.ts +3 -0
- package/src/providers/registry/model-ids.ts +2 -0
- package/src/providers/registry/model-seeds.ts +5 -0
- package/src/providers/registry/types.ts +4 -0
- package/src/responses/compaction.ts +19 -0
- package/src/router.ts +6 -0
- package/src/server/auth-cors.ts +9 -0
- package/src/server/caller-session-identity.ts +32 -0
- package/src/server/chat-completions.ts +10 -0
- package/src/server/claude-messages.ts +29 -15
- package/src/server/droid-reasoning-default.ts +50 -0
- package/src/server/github-copilot-responses-repair.ts +3 -6
- package/src/server/grok-responses-control-frame.ts +2 -2
- package/src/server/grok-responses-snapshot-repair.ts +4 -5
- package/src/server/gui-session.ts +33 -11
- package/src/server/index/claude-intercept-lifecycle.ts +4 -0
- package/src/server/index/serve-options.ts +13 -7
- package/src/server/index.ts +1 -1
- package/src/server/management/agent-settings-routes.ts +12 -134
- package/src/server/management/config-routes.ts +1 -1
- package/src/server/management/context.ts +8 -1
- package/src/server/management/cursor-integration-routes.ts +3 -3
- package/src/server/management/integration-routes.ts +69 -11
- package/src/server/management/link-routes.ts +20 -13
- package/src/server/management/model-routes.ts +3 -3
- package/src/server/management/model-row-export-metadata.ts +150 -0
- package/src/server/management/model-rows.ts +148 -9
- package/src/server/management/native-integration-routes.ts +2 -2
- package/src/server/management/oauth-account-routes.ts +96 -30
- package/src/server/management/route-registry.ts +29 -27
- package/src/server/management/shared.ts +19 -5
- package/src/server/management/subagent-model-routes.ts +214 -0
- package/src/server/messages-native-eligibility.ts +3 -6
- package/src/server/messages-native-oauth.ts +82 -35
- package/src/server/messages-native.ts +78 -16
- package/src/server/relay.ts +14 -44
- package/src/server/request-log-generation-window.ts +38 -0
- package/src/server/request-log.ts +13 -0
- package/src/server/responses/adapter-dispatch.ts +152 -28
- package/src/server/responses/codex-auth-error.ts +10 -2
- package/src/server/responses/combo-stream-preflight.ts +29 -3
- package/src/server/responses/compaction-routing.ts +10 -1
- package/src/server/responses/core-auth.ts +67 -30
- package/src/server/responses/core-codex-account.ts +6 -3
- package/src/server/responses/core-combo-failure.ts +5 -1
- package/src/server/responses/core-combo-native.ts +7 -1
- package/src/server/responses/core-combo.ts +64 -7
- package/src/server/responses/core-normalize.ts +7 -0
- package/src/server/responses/core-options.ts +5 -0
- package/src/server/responses/fetch-helpers.ts +9 -0
- package/src/server/responses/passthrough-delivery.ts +1 -1
- package/src/server/responses/policy-fallback.ts +1 -1
- package/src/server/responses/request-prepare.ts +5 -0
- package/src/server/responses/request-spend.ts +30 -30
- package/src/server/responses-custom-tool-repair.ts +2 -2
- package/src/server/responses-hosted-image-display.ts +70 -9
- package/src/server/responses-terminal-repair.ts +15 -2
- package/src/server/sse-frame-buffer.ts +38 -36
- package/src/server/sse-payload-rewrite.ts +78 -49
- package/src/server/ws-bridge.ts +1 -11
- package/src/service/cli.ts +6 -1
- package/src/service/ownership-mutation-lease.d.mts +26 -0
- package/src/service/ownership-mutation-lease.mjs +76 -1
- package/src/service/windows-taskxml.ts +1 -2
- package/src/service-manager-probe.ts +36 -2
- package/src/types/config.ts +6 -0
- package/src/types/provider.ts +28 -10
- package/src/update/index.ts +2 -1
- package/src/update/npm-invocation.mjs +35 -3
- package/src/update/proxy-liveness-probe.mjs +38 -8
- package/src/update/update-failure-guidance.d.mts +6 -0
- package/src/update/update-failure-guidance.mjs +30 -5
- package/src/usage/expected-prices.ts +9 -0
- package/src/usage/log.ts +7 -0
- package/src/usage/summary.ts +82 -1
- package/src/web-search/loop.ts +11 -8
- package/src/web-search/run-turn-loop.ts +10 -7
- package/gui/dist/assets/App-CddorHdA.js +0 -51
- package/gui/dist/assets/App-DMudtISW.css +0 -1
- package/gui/dist/assets/index-Btze1I3T.css +0 -1
- package/gui/dist/assets/index-CvnY7E6i.js +0 -86
- package/gui/dist/assets/quota-summary-B_AWpHfP.js +0 -1
package/src/cli/doctor.ts
CHANGED
|
@@ -33,6 +33,7 @@ import {
|
|
|
33
33
|
} from "../codex/subagent-model-fallback";
|
|
34
34
|
import { readCatalog, readCodexCatalogPath, readConfiguredDefaultModel } from "../codex/catalog/parsing";
|
|
35
35
|
import { diagnoseCodexShim, findCodexOnPath, isWindowsInteropDir, type CodexShimDiagnostic } from "../codex/shim";
|
|
36
|
+
import { overlayActivationHint } from "../codex/shim-overlay";
|
|
36
37
|
import { providerTableString, rootTomlString } from "../codex/injected-marker";
|
|
37
38
|
import { countPendingOpencodexHistory } from "../codex/history-provider";
|
|
38
39
|
import {
|
|
@@ -481,28 +482,41 @@ export function collectProviderApiKeyDiagnostics(
|
|
|
481
482
|
|
|
482
483
|
export type CodexEnvKeyReadinessDiagnostic = {
|
|
483
484
|
envName: string;
|
|
484
|
-
shimState: "missing" | "unhealthy";
|
|
485
|
+
shimState: "missing" | "unhealthy" | "inactive";
|
|
485
486
|
detail: string;
|
|
486
487
|
action: string;
|
|
487
488
|
};
|
|
488
489
|
|
|
490
|
+
/** Shell activation and legacy migration are independent of admission-token readiness. */
|
|
491
|
+
export function formatCodexShimDoctorLines(shim: CodexShimDiagnostic, platform = process.platform): string[] {
|
|
492
|
+
if (platform === "win32" || !shim.installed) return [];
|
|
493
|
+
const inactiveOverlay = shim.runnable === true && shim.active === false;
|
|
494
|
+
const healthyLegacy = shim.healthy && shim.runnable === undefined;
|
|
495
|
+
return inactiveOverlay || healthyLegacy ? shim.summary.split("\n").map(line => ` ${line}`) : [];
|
|
496
|
+
}
|
|
497
|
+
|
|
489
498
|
/** Warn when routed Codex cannot obtain its configured admission token at launch. */
|
|
490
499
|
export function collectCodexEnvKeyReadiness(
|
|
491
500
|
configText: string | null,
|
|
492
501
|
env: EnvMap,
|
|
493
502
|
shim: CodexShimDiagnostic,
|
|
494
503
|
serviceTokenPresent: boolean,
|
|
504
|
+
shimActivationShown = false,
|
|
495
505
|
): CodexEnvKeyReadinessDiagnostic | null {
|
|
496
506
|
if (!configText || rootTomlString(configText, "model_provider") !== "opencodex") return null;
|
|
497
507
|
const envName = providerTableString(configText, "opencodex", "env_key")?.trim();
|
|
498
508
|
const envValue = envName ? ownEnvValue(env, envName) : undefined;
|
|
499
509
|
if (!envName || envValue?.trim() || shim.healthy || !serviceTokenPresent) return null;
|
|
500
|
-
const shimState = shim.installed ? "unhealthy" : "missing";
|
|
510
|
+
const shimState = shim.runnable && shim.active === false ? "inactive" : shim.installed ? "unhealthy" : "missing";
|
|
501
511
|
return {
|
|
502
512
|
envName,
|
|
503
513
|
shimState,
|
|
504
514
|
detail: `Codex uses env_key ${envName}, but that variable is unset and the OpenCodex shim is ${shimState}; the service token file exists but plain Codex does not load it`,
|
|
505
|
-
action:
|
|
515
|
+
action: shimState === "inactive"
|
|
516
|
+
? shimActivationShown
|
|
517
|
+
? `Activate the PATH shim as shown under Codex restart safety, or export ${envName} in the process that starts Codex`
|
|
518
|
+
: `${overlayActivationHint()} Or export ${envName} in the process that starts Codex`
|
|
519
|
+
: `Run 'ocx codex-shim install' to repair launch-time token injection, or export ${envName} in the process that starts Codex`,
|
|
506
520
|
};
|
|
507
521
|
}
|
|
508
522
|
|
|
@@ -1349,11 +1363,14 @@ export async function runDoctor(args: string[] = []): Promise<void> {
|
|
|
1349
1363
|
try { return readFileSync(codexConfigPath, "utf8"); } catch { return null; }
|
|
1350
1364
|
})();
|
|
1351
1365
|
const serviceTokenPresent = Boolean(readInstalledServiceToken()?.trim());
|
|
1366
|
+
const codexShim = diagnoseCodexShim();
|
|
1367
|
+
const codexShimLines = formatCodexShimDoctorLines(codexShim);
|
|
1352
1368
|
const codexEnvKeyReadiness = collectCodexEnvKeyReadiness(
|
|
1353
1369
|
codexConfigText,
|
|
1354
1370
|
process.env,
|
|
1355
|
-
|
|
1371
|
+
codexShim,
|
|
1356
1372
|
serviceTokenPresent,
|
|
1373
|
+
codexShimLines.length > 0,
|
|
1357
1374
|
);
|
|
1358
1375
|
// Use the same attested live startup verdict as `ocx status` when the proxy is already
|
|
1359
1376
|
// identity-verified. A shell-local systemd probe can be a false negative for a system-wide
|
|
@@ -1366,6 +1383,7 @@ export async function runDoctor(args: string[] = []): Promise<void> {
|
|
|
1366
1383
|
console.log("\nCodex restart safety");
|
|
1367
1384
|
console.log(` ${startup.rebootSafe ? "ok " : "!! "} ${startupHealthSummary(startup)}`);
|
|
1368
1385
|
console.log(` ${formatStartupRoutingDetail(startup)}`);
|
|
1386
|
+
for (const line of codexShimLines) console.log(line);
|
|
1369
1387
|
|
|
1370
1388
|
console.log("\nCodex runtime selection");
|
|
1371
1389
|
{
|
|
@@ -66,12 +66,13 @@ export interface ExportCommandDeps extends RuntimeApiDeps {
|
|
|
66
66
|
* `opencodeCatalogFromProxyRows` owns the visibility rules (drop `disabled`, drop dupes,
|
|
67
67
|
* drop native under Codex Direct) — the export core does none of that, so a row filtered
|
|
68
68
|
* here is the only thing keeping a disabled model out of a client's picker. It also carries
|
|
69
|
-
* the effort ladder
|
|
70
|
-
*
|
|
71
|
-
* duplicate donate its ladder to
|
|
69
|
+
* the effort ladder and the effective custom-row projection, so every per-model field a
|
|
70
|
+
* client receives comes from the same filtered, deduped row as the model itself: a second
|
|
71
|
+
* lookup over the raw rows would let a hidden or disabled duplicate donate its ladder to
|
|
72
|
+
* the visible entry.
|
|
72
73
|
*
|
|
73
|
-
*
|
|
74
|
-
*
|
|
74
|
+
* The empty-vs-undefined ladder distinction survives the hop: a row declaring `[]` exports
|
|
75
|
+
* `[]` (explicit "no rungs"), a row declaring nothing exports nothing (unknown).
|
|
75
76
|
*/
|
|
76
77
|
export function exportModelsFromProxyRows(
|
|
77
78
|
rows: readonly OpencodeProxyModelRow[],
|
|
@@ -87,13 +88,21 @@ export function exportModelsFromProxyRows(
|
|
|
87
88
|
if (entry.fastRowAvailable !== undefined) model.fastRowAvailable = entry.fastRowAvailable;
|
|
88
89
|
if (entry.displayName) model.displayName = entry.displayName;
|
|
89
90
|
if (entry.contextWindow !== undefined) model.contextWindow = entry.contextWindow;
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
91
|
+
// The catalog row's own output limit; dropping it here is what once made every CLI
|
|
92
|
+
// export fall back to the generated-metadata guess the management path never used.
|
|
93
|
+
if (entry.maxTokens !== undefined) model.maxTokens = entry.maxTokens;
|
|
94
|
+
if (entry.maxInputTokens !== undefined) model.maxInputTokens = entry.maxInputTokens;
|
|
95
|
+
if (entry.reasoningEfforts !== undefined) model.reasoningEfforts = [...entry.reasoningEfforts];
|
|
93
96
|
if (entry.defaultReasoningEffort) model.defaultReasoningEffort = entry.defaultReasoningEffort;
|
|
94
97
|
if (entry.inputModalities && entry.inputModalities.length > 0) {
|
|
95
98
|
model.inputModalities = [...entry.inputModalities];
|
|
96
99
|
}
|
|
100
|
+
// Explicit booleans survive, false included; nothing infers a negative from absence.
|
|
101
|
+
if (entry.supportsTools !== undefined) model.supportsTools = entry.supportsTools;
|
|
102
|
+
if (entry.supportsReasoning !== undefined) model.supportsReasoning = entry.supportsReasoning;
|
|
103
|
+
if (entry.supportsReasoningSummaries !== undefined) {
|
|
104
|
+
model.supportsReasoningSummaries = entry.supportsReasoningSummaries;
|
|
105
|
+
}
|
|
97
106
|
return model;
|
|
98
107
|
});
|
|
99
108
|
}
|
|
@@ -194,7 +203,9 @@ export async function handleExportCommand(argv: string[], deps: ExportCommandDep
|
|
|
194
203
|
// `--out` is the path that writes the selected client's native format.
|
|
195
204
|
// Format metadata rides in the human lines below.
|
|
196
205
|
printData(clientConfig, wantsJson, [
|
|
197
|
-
|
|
206
|
+
// `lines` entries print one console line each and are control-escaped, so
|
|
207
|
+
// the document goes in as individual lines rather than one multi-line blob.
|
|
208
|
+
...text.trimEnd().split("\n"),
|
|
198
209
|
"",
|
|
199
210
|
...(out !== undefined ? [`Wrote ${out}`] : []),
|
|
200
211
|
`Destination: ${spec.destination(process.env)}`,
|
package/src/cli/gui.ts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import type { OcxConfig } from "../types";
|
|
2
|
-
import { canonicalGuiBrowserOrigin } from "../lib/gui-pair-capability";
|
|
2
|
+
import { canonicalGuiBrowserOrigin, standaloneGuiPairingOrigin } from "../lib/gui-pair-capability";
|
|
3
3
|
import { findLiveProxy, type LiveProxy } from "../server/proxy-liveness";
|
|
4
4
|
import {
|
|
5
5
|
requestBoundGuiPairingGrant,
|
|
@@ -23,7 +23,7 @@ export interface GuiCommandDeps extends RuntimeApiDeps {
|
|
|
23
23
|
}
|
|
24
24
|
|
|
25
25
|
function allowedPairingOrigin(origin: string, config: OcxConfig): boolean {
|
|
26
|
-
if (config.runtimeRole !== "hub") return
|
|
26
|
+
if (config.runtimeRole !== "hub") return standaloneGuiPairingOrigin(config) === origin;
|
|
27
27
|
if (canonicalGuiBrowserOrigin(config.hub?.managementPublicOrigin) === origin) return true;
|
|
28
28
|
return (config.corsAllowOrigins ?? []).some(value => canonicalGuiBrowserOrigin(value) === origin);
|
|
29
29
|
}
|
|
@@ -62,7 +62,7 @@ export async function runGuiCommand(args: string[], deps: GuiCommandDeps): Promi
|
|
|
62
62
|
}
|
|
63
63
|
const config = deps.loadConfig();
|
|
64
64
|
if (!allowedPairingOrigin(canonicalOrigin, config)) {
|
|
65
|
-
console.error("
|
|
65
|
+
console.error("Pairing requires the standalone configured literal loopback origin, or an allowed hub origin.");
|
|
66
66
|
return 1;
|
|
67
67
|
}
|
|
68
68
|
const target = await (deps.findLiveProxy ?? findLiveProxy)();
|
|
@@ -70,6 +70,11 @@ export async function runGuiCommand(args: string[], deps: GuiCommandDeps): Promi
|
|
|
70
70
|
console.error("No running attested OpenCodex proxy is available for GUI pairing.");
|
|
71
71
|
return 1;
|
|
72
72
|
}
|
|
73
|
+
if ((config.runtimeRole ?? "standalone") === "standalone"
|
|
74
|
+
&& (target.port !== config.port || (target.hostname ?? "127.0.0.1") !== (config.hostname ?? "127.0.0.1"))) {
|
|
75
|
+
console.error("Standalone pairing requires the running proxy to use its configured loopback address and port.");
|
|
76
|
+
return 1;
|
|
77
|
+
}
|
|
73
78
|
const result = await (deps.requestPairingGrant ?? requestBoundGuiPairingGrant)(target, canonicalOrigin, {
|
|
74
79
|
...(deps.fetchImpl ? { fetchImpl: deps.fetchImpl } : {}),
|
|
75
80
|
});
|
|
@@ -0,0 +1,101 @@
|
|
|
1
|
+
import { CAPABILITIES, type Capability } from "./capabilities";
|
|
2
|
+
import { CLI_COMMANDS, findCommand, type CliCommandEntry } from "./registry";
|
|
3
|
+
|
|
4
|
+
export type HelpResolution =
|
|
5
|
+
| { kind: "entry"; entry: CliCommandEntry; canonicalName: string; capability?: Capability; children: readonly Capability[] }
|
|
6
|
+
| { kind: "capability"; path: string[]; capability: Capability; children: readonly Capability[] }
|
|
7
|
+
| { kind: "prefix"; path: string[]; children: readonly Capability[] }
|
|
8
|
+
| { kind: "models-context"; path: string[] }
|
|
9
|
+
| { kind: "unavailable"; path: string[]; parent?: string[] };
|
|
10
|
+
|
|
11
|
+
function startsWithPath(command: readonly string[], prefix: readonly string[]): boolean {
|
|
12
|
+
return prefix.length <= command.length && prefix.every((token, index) => token === command[index]);
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
const DOCUMENTED_PATHS: readonly (readonly string[])[] = [
|
|
16
|
+
...CAPABILITIES.filter(capability => !findCommand(capability.command[0])?.hidden).map(capability => capability.command),
|
|
17
|
+
["models", "context"],
|
|
18
|
+
];
|
|
19
|
+
const MAX_DOCUMENTED_DEPTH = Math.max(...DOCUMENTED_PATHS.map(path => path.length));
|
|
20
|
+
|
|
21
|
+
function canonicalEntry(entry: CliCommandEntry): CliCommandEntry {
|
|
22
|
+
return CLI_COMMANDS.find(candidate => candidate.aliases?.includes(entry.name)) ?? entry;
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
/** Help-only aliases from access dispatch; never rewrite execution argv or operands. */
|
|
26
|
+
function canonicalHelpPath(requested: readonly string[], entry: CliCommandEntry): string[] {
|
|
27
|
+
const path = entry.name === "api-key"
|
|
28
|
+
? ["access", "key", ...requested.slice(1)]
|
|
29
|
+
: [canonicalEntry(entry).name, ...requested.slice(1)];
|
|
30
|
+
if (path[0] === "access") {
|
|
31
|
+
if (path[1] === "keys") path[1] = "key";
|
|
32
|
+
if (path[1] === "key" && path[2] === "delete") path[2] = "remove";
|
|
33
|
+
}
|
|
34
|
+
return path;
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
export interface HelpRecoveryCandidate {
|
|
38
|
+
names: string[];
|
|
39
|
+
path: string[];
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
/** Matching names may include aliases; destinations are always catalog-owned. */
|
|
43
|
+
export function helpRecoveryCandidates(parent: readonly string[] = []): HelpRecoveryCandidate[] {
|
|
44
|
+
const candidates = new Map<string, HelpRecoveryCandidate>();
|
|
45
|
+
if (parent.length === 0) {
|
|
46
|
+
for (const entry of CLI_COMMANDS) {
|
|
47
|
+
if (entry.hidden) continue;
|
|
48
|
+
const canonical = canonicalEntry(entry);
|
|
49
|
+
if (canonical.hidden) continue;
|
|
50
|
+
const path = canonicalHelpPath([entry.name], entry);
|
|
51
|
+
const identity = path.join(" ");
|
|
52
|
+
const candidate = candidates.get(identity) ?? { names: [], path };
|
|
53
|
+
candidate.names = [...new Set([...candidate.names, entry.name, ...(entry.aliases ?? [])])];
|
|
54
|
+
candidates.set(identity, candidate);
|
|
55
|
+
}
|
|
56
|
+
} else {
|
|
57
|
+
const entry = findCommand(parent[0]);
|
|
58
|
+
if (!entry || entry.hidden) return [];
|
|
59
|
+
const prefix = canonicalHelpPath(parent, entry);
|
|
60
|
+
if (prefix.length >= MAX_DOCUMENTED_DEPTH) return [];
|
|
61
|
+
for (const documented of DOCUMENTED_PATHS) {
|
|
62
|
+
if (documented.length <= prefix.length || !startsWithPath(documented, prefix)) continue;
|
|
63
|
+
const path = documented.slice(0, prefix.length + 1);
|
|
64
|
+
const names = [path[path.length - 1]];
|
|
65
|
+
if (path.join(" ") === "access key") names.push("keys");
|
|
66
|
+
if (path.join(" ") === "access key remove") names.push("delete");
|
|
67
|
+
candidates.set(path.join(" "), { names, path });
|
|
68
|
+
}
|
|
69
|
+
}
|
|
70
|
+
return [...candidates.values()];
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
/** Static declarations describe help coverage, never the runtime's complete grammar. */
|
|
74
|
+
export function resolveHelpPath(requested: readonly string[]): HelpResolution {
|
|
75
|
+
const entry = requested[0] ? findCommand(requested[0]) : undefined;
|
|
76
|
+
if (!entry) return { kind: "unavailable", path: [...requested] };
|
|
77
|
+
// Keep exact-name alias entries for root help; nested topics use the owner.
|
|
78
|
+
const path = canonicalHelpPath(requested, entry);
|
|
79
|
+
const declared = CAPABILITIES.filter(capability => !findCommand(capability.command[0])?.hidden);
|
|
80
|
+
if (requested.length === 1) return {
|
|
81
|
+
kind: "entry", entry, canonicalName: path.join(" "),
|
|
82
|
+
capability: entry.hidden ? undefined : declared.find(candidate => candidate.command.length === path.length && startsWithPath(candidate.command, path)),
|
|
83
|
+
children: entry.hidden ? [] : declared.filter(candidate => candidate.command.length > path.length && startsWithPath(candidate.command, path)),
|
|
84
|
+
};
|
|
85
|
+
if (path.length === 2 && path[0] === "models" && path[1] === "context") {
|
|
86
|
+
return { kind: "models-context", path };
|
|
87
|
+
}
|
|
88
|
+
const capability = declared.find(candidate => candidate.command.length === path.length && startsWithPath(candidate.command, path));
|
|
89
|
+
const children = declared.filter(candidate => candidate.command.length > path.length && startsWithPath(candidate.command, path));
|
|
90
|
+
if (capability) return { kind: "capability", path, capability, children };
|
|
91
|
+
if (children.length) return { kind: "prefix", path, children };
|
|
92
|
+
|
|
93
|
+
for (let length = Math.min(path.length - 1, MAX_DOCUMENTED_DEPTH); length > 1; length--) {
|
|
94
|
+
const parent = path.slice(0, length);
|
|
95
|
+
if ((length === 2 && parent[0] === "models" && parent[1] === "context")
|
|
96
|
+
|| declared.some(candidate => startsWithPath(candidate.command, parent))) {
|
|
97
|
+
return { kind: "unavailable", path, parent };
|
|
98
|
+
}
|
|
99
|
+
}
|
|
100
|
+
return { kind: "unavailable", path, parent: [path[0]] };
|
|
101
|
+
}
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
/** Exact runtime usage row, including its indentation. No runtime imports. */
|
|
2
|
+
export const MODELS_CONTEXT_USAGE = " ocx models context <status|value <tokens> [--set-all]|provider <name> on [--value <tokens>]|provider <name> off|all <on|off>> [--json]";
|
|
3
|
+
|
|
4
|
+
export const MODELS_CONTEXT_DETAILS = [
|
|
5
|
+
"Manage context caps for routed providers.",
|
|
6
|
+
"status: read current settings without changing them (the default action).",
|
|
7
|
+
"value <tokens>: set a positive token cap for future toggles; --set-all also applies it to every routed provider.",
|
|
8
|
+
"provider <name> on|off: enable or disable a provider cap; on accepts --value <tokens> for that provider only.",
|
|
9
|
+
"all on|off: enable or disable caps for every routed provider.",
|
|
10
|
+
"--json: print the result as JSON.",
|
|
11
|
+
"",
|
|
12
|
+
"Examples:",
|
|
13
|
+
" ocx models context status --json",
|
|
14
|
+
" ocx models context value 128000",
|
|
15
|
+
" ocx models context provider openai on --value 128000",
|
|
16
|
+
" ocx models context all off",
|
|
17
|
+
] as const;
|
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
import { findCommand } from "./registry";
|
|
2
|
+
|
|
3
|
+
// Presentation owns selection/order only; names and summaries belong to registry.
|
|
4
|
+
const ACTION_GROUPS = [
|
|
5
|
+
{ title: "Start here", commands: ["setup", "start", "status"] },
|
|
6
|
+
{ title: "Common tasks", commands: ["doctor", "logs", "usage"] },
|
|
7
|
+
] as const;
|
|
8
|
+
|
|
9
|
+
const FAMILY_GROUPS = [
|
|
10
|
+
["provider", "account", "models", "alias"],
|
|
11
|
+
["combo", "route", "agent", "effort"],
|
|
12
|
+
["observe", "inspect", "access", "api"],
|
|
13
|
+
["config", "system", "integration"],
|
|
14
|
+
] as const;
|
|
15
|
+
|
|
16
|
+
function publicCommand(name: string) {
|
|
17
|
+
const entry = findCommand(name);
|
|
18
|
+
if (!entry || entry.hidden) throw new Error(`Invalid public help group command: ${name}`);
|
|
19
|
+
return entry;
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
function actionLines(name: string): string[] {
|
|
23
|
+
const entry = publicCommand(name);
|
|
24
|
+
const prefix = ` ocx ${entry.name}`.padEnd(16);
|
|
25
|
+
const lines: string[] = [];
|
|
26
|
+
let line = prefix;
|
|
27
|
+
for (const word of entry.summary.split(/\s+/)) {
|
|
28
|
+
if (line.trim() && line.length + word.length + 1 > 80 && line !== prefix) {
|
|
29
|
+
lines.push(line);
|
|
30
|
+
line = " ".repeat(prefix.length);
|
|
31
|
+
}
|
|
32
|
+
line += `${line.endsWith(" ") ? "" : " "}${word}`;
|
|
33
|
+
}
|
|
34
|
+
lines.push(line);
|
|
35
|
+
return lines;
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
export function renderRootHelp(): string {
|
|
39
|
+
const lines = ["opencodex (ocx) — Universal provider proxy for Codex", "Usage: ocx <command> [options]"];
|
|
40
|
+
for (const group of ACTION_GROUPS) {
|
|
41
|
+
lines.push("", `${group.title}:`, ...group.commands.flatMap(actionLines));
|
|
42
|
+
}
|
|
43
|
+
lines.push("", "Explore:");
|
|
44
|
+
for (const group of FAMILY_GROUPS) lines.push(` ${group.map(name => publicCommand(name).name).join(" ")}`);
|
|
45
|
+
lines.push("", "More help:",
|
|
46
|
+
" ocx help <command> Command usage and declared topics",
|
|
47
|
+
" ocx help --all Complete command reference",
|
|
48
|
+
" ocx capabilities --json Declared capabilities for scripts");
|
|
49
|
+
return lines.join("\n");
|
|
50
|
+
}
|
|
@@ -0,0 +1,66 @@
|
|
|
1
|
+
import { helpRecoveryCandidates, resolveHelpPath } from "./help-catalog";
|
|
2
|
+
import { redactSecretString } from "../lib/redact";
|
|
3
|
+
|
|
4
|
+
const MAX_TOKEN_LENGTH = 64;
|
|
5
|
+
const MAX_PATH_DEPTH = 8;
|
|
6
|
+
const MAX_SUGGESTIONS = 3;
|
|
7
|
+
|
|
8
|
+
function safeToken(value: string | undefined): value is string {
|
|
9
|
+
return value !== undefined && value.length >= 3 && value.length <= MAX_TOKEN_LENGTH
|
|
10
|
+
&& /^[a-z][a-z0-9-]*$/i.test(value) && redactSecretString(value) === value;
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
/** Banded edit distance with adjacent transposition, over already bounded tokens. */
|
|
14
|
+
function distance(left: string, right: string, limit: number): number {
|
|
15
|
+
if (Math.abs(left.length - right.length) > limit) return limit + 1;
|
|
16
|
+
let previous = Array.from({ length: right.length + 1 }, (_, index) => index);
|
|
17
|
+
let older = previous;
|
|
18
|
+
for (let i = 1; i <= left.length; i++) {
|
|
19
|
+
const current: number[] = Array(right.length + 1).fill(limit + 1);
|
|
20
|
+
current[0] = i;
|
|
21
|
+
for (let j = Math.max(1, i - limit); j <= Math.min(right.length, i + limit); j++) {
|
|
22
|
+
current[j] = Math.min(current[j - 1] + 1, previous[j] + 1,
|
|
23
|
+
previous[j - 1] + (left[i - 1] === right[j - 1] ? 0 : 1));
|
|
24
|
+
if (i > 1 && j > 1 && left[i - 1] === right[j - 2] && left[i - 2] === right[j - 1]) {
|
|
25
|
+
current[j] = Math.min(current[j], older[j - 2] + 1);
|
|
26
|
+
}
|
|
27
|
+
}
|
|
28
|
+
older = previous;
|
|
29
|
+
previous = current;
|
|
30
|
+
}
|
|
31
|
+
return previous[right.length];
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
/** Return complete help destinations, never user-supplied trailing operands. */
|
|
35
|
+
export function suggestHelpPaths(path: readonly string[]): string[][] {
|
|
36
|
+
if (!path.length || path.length > MAX_PATH_DEPTH || !path.every(safeToken)) return [];
|
|
37
|
+
const result = resolveHelpPath(path);
|
|
38
|
+
if (result.kind !== "unavailable" || result.path.length > MAX_PATH_DEPTH) return [];
|
|
39
|
+
const parent = result.parent ?? [];
|
|
40
|
+
const token = result.path[parent.length].toLowerCase();
|
|
41
|
+
const limit = token.length < 6 ? 1 : 2;
|
|
42
|
+
return helpRecoveryCandidates(parent).map(candidate => ({
|
|
43
|
+
path: candidate.path,
|
|
44
|
+
name: candidate.path.join(" "),
|
|
45
|
+
distance: Math.min(...candidate.names.filter(safeToken).map(name => distance(token, name.toLowerCase(), limit))),
|
|
46
|
+
})).filter(candidate => candidate.distance <= limit)
|
|
47
|
+
.sort((a, b) => a.distance - b.distance || (a.name < b.name ? -1 : a.name > b.name ? 1 : 0))
|
|
48
|
+
.slice(0, MAX_SUGGESTIONS).map(candidate => candidate.path);
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
export function formatHelpRecovery(path: readonly string[]): string {
|
|
52
|
+
const result = resolveHelpPath(path);
|
|
53
|
+
const parent = result.kind === "unavailable" ? result.parent : undefined;
|
|
54
|
+
const lines = [parent ? "Detailed help unavailable for the requested topic."
|
|
55
|
+
: safeToken(path[0]) ? `Unknown command: ${path[0]}` : "Unknown command."];
|
|
56
|
+
const suggestions = suggestHelpPaths(path);
|
|
57
|
+
if (suggestions.length) {
|
|
58
|
+
lines.push("Did you mean:", ...suggestions.map(suggestion => ` ocx help ${suggestion.join(" ")}`));
|
|
59
|
+
}
|
|
60
|
+
lines.push(parent ? `See: ocx help ${parent.join(" ")}` : "See: ocx help --all");
|
|
61
|
+
return lines.join("\n");
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
export function printUnknownCommand(command: string | undefined): void {
|
|
65
|
+
console.error(formatHelpRecovery(command === undefined ? [] : [command]));
|
|
66
|
+
}
|
package/src/cli/help.ts
CHANGED
|
@@ -1,4 +1,8 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { resolveHelpPath } from "./help-catalog";
|
|
2
|
+
import type { Capability } from "./capabilities";
|
|
3
|
+
import { MODELS_CONTEXT_DETAILS, MODELS_CONTEXT_USAGE } from "./help-models-context";
|
|
4
|
+
import { renderRootHelp } from "./help-navigation";
|
|
5
|
+
import { formatHelpRecovery } from "./help-recovery";
|
|
2
6
|
import { packageVersion as readPackageVersion } from "../lib/package-version";
|
|
3
7
|
|
|
4
8
|
/**
|
|
@@ -17,6 +21,10 @@ export function printVersion(): void {
|
|
|
17
21
|
}
|
|
18
22
|
|
|
19
23
|
export function printUsage(): void {
|
|
24
|
+
console.log(renderRootHelp());
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
export function printFullUsage(): void {
|
|
20
28
|
console.log(`opencodex (ocx) — Universal provider proxy for Codex
|
|
21
29
|
|
|
22
30
|
Usage:
|
|
@@ -33,7 +41,7 @@ Usage:
|
|
|
33
41
|
ocx recover-history --ocx-compaction <thread-id> --yes
|
|
34
42
|
Back up and make one ocx1-compacted thread replayable by native Codex
|
|
35
43
|
ocx uninstall Remove service/shim/config and restore native Codex (alias: remove)
|
|
36
|
-
ocx service [sub] Run as a background service (default: install
|
|
44
|
+
ocx service [sub] Run as a background service (default: install if absent, otherwise repair)
|
|
37
45
|
ocx codex-shim <sub> Auto-start proxy when \`codex\` launches (install|status|uninstall|remove)
|
|
38
46
|
ocx tray <sub> Windows status tray (install|start|stop|status|uninstall)
|
|
39
47
|
ocx ensure Ensure the proxy is running and Codex config/cache are current
|
|
@@ -87,9 +95,9 @@ Usage:
|
|
|
87
95
|
ocx integration client <sub> Enable, disable, inspect or roll back a client integration
|
|
88
96
|
ocx grok <sub> Grok Build model selection and apply
|
|
89
97
|
ocx system <sub> Runtime settings, startup, sync, OpenCodex updates, and Codex CLI inspection
|
|
90
|
-
ocx config
|
|
98
|
+
ocx config [sub] Validated configuration show/get/set/import/export
|
|
91
99
|
ocx companion <show|set|reset> Menu-bar and widget companion usage settings
|
|
92
|
-
ocx lab <sub>
|
|
100
|
+
ocx lab <sub> Inspect Lab evidence and control local automation
|
|
93
101
|
ocx chatgpt <sub> Experimental app-server shim: launch|restore|status (macOS)
|
|
94
102
|
ocx claude [args...] Launch Claude Code wired to the proxy (model discovery on)
|
|
95
103
|
ocx claude desktop [sub] Manage and apply Claude Desktop's four-family profile
|
|
@@ -115,13 +123,63 @@ export function hasHelpFlag(values: string[]): boolean {
|
|
|
115
123
|
return values.some(value => value === "--help" || value === "-h" || value === "help");
|
|
116
124
|
}
|
|
117
125
|
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
126
|
+
function printCapabilityDetails(capability: Capability, write: (text: string) => void, shown: readonly string[] = []): void {
|
|
127
|
+
if (capability.flags.length) {
|
|
128
|
+
write("\nDeclared flags:");
|
|
129
|
+
for (const flag of capability.flags) {
|
|
130
|
+
write(` ${flag.name}${flag.value && flag.value !== "boolean" ? ` <${flag.value}>` : ""}${flag.required ? " (required)" : ""} ${flag.summary}`);
|
|
131
|
+
}
|
|
132
|
+
}
|
|
133
|
+
const details = capability.details?.filter(detail => !shown.includes(detail));
|
|
134
|
+
if (details?.length) write(`\n${details.join("\n")}`);
|
|
135
|
+
}
|
|
136
|
+
|
|
137
|
+
export function printSubcommandUsage(
|
|
138
|
+
name: string | undefined,
|
|
139
|
+
path?: readonly string[],
|
|
140
|
+
options: { fallbackToParent?: boolean; write?: (text: string) => void } = {},
|
|
141
|
+
): void {
|
|
142
|
+
const write = options.write ?? console.log;
|
|
143
|
+
const result = resolveHelpPath(path ?? (name ? [name] : []));
|
|
144
|
+
if (result.kind === "unavailable") {
|
|
145
|
+
// Appended flags may follow runtime operands. An explicit `help <path>`
|
|
146
|
+
// requests that exact detail instead, so only the CLI head enables fallback.
|
|
147
|
+
if (options.fallbackToParent && result.parent) {
|
|
148
|
+
printSubcommandUsage(result.parent[0], result.parent, { write });
|
|
149
|
+
return;
|
|
150
|
+
}
|
|
151
|
+
console.error(formatHelpRecovery(result.path));
|
|
123
152
|
process.exit(1);
|
|
124
153
|
}
|
|
125
|
-
|
|
126
|
-
|
|
154
|
+
if (result.kind === "entry") {
|
|
155
|
+
write(`Usage: ${result.entry.usage}\n\n${result.entry.summary}`);
|
|
156
|
+
if (result.entry.details?.length) write(`\n${result.entry.details.join("\n")}`);
|
|
157
|
+
if (result.capability) printCapabilityDetails(result.capability, write, result.entry.details);
|
|
158
|
+
if (result.children.length) {
|
|
159
|
+
write("\nDeclared commands (incomplete):");
|
|
160
|
+
for (const child of result.children) write(` ocx help ${child.command.join(" ")} ${child.summary}`);
|
|
161
|
+
}
|
|
162
|
+
if (result.canonicalName === "models") write("\nContext cap help: ocx help models context");
|
|
163
|
+
if (result.entry.name !== result.canonicalName) write(`\nCanonical help: ocx help ${result.canonicalName}`);
|
|
164
|
+
return;
|
|
165
|
+
}
|
|
166
|
+
if (result.kind === "models-context") {
|
|
167
|
+
write(`Usage:\n${MODELS_CONTEXT_USAGE}\n\n${MODELS_CONTEXT_DETAILS.join("\n")}`);
|
|
168
|
+
} else if (result.kind === "capability") {
|
|
169
|
+
const { capability } = result;
|
|
170
|
+
const heading = capability.usage !== undefined ? `Usage: ${capability.usage}` : `Command: ocx ${result.path.join(" ")}`;
|
|
171
|
+
write(`${heading}\n\n${capability.summary}`);
|
|
172
|
+
printCapabilityDetails(capability, write);
|
|
173
|
+
if (result.children.length) {
|
|
174
|
+
write("\nDeclared commands (incomplete):");
|
|
175
|
+
for (const child of result.children) write(` ocx help ${child.command.join(" ")} ${child.summary}`);
|
|
176
|
+
}
|
|
177
|
+
if (capability.usage === undefined) {
|
|
178
|
+
write("\nCapability metadata is incomplete; this is not the full operand grammar.");
|
|
179
|
+
}
|
|
180
|
+
} else {
|
|
181
|
+
write(`Command group: ocx ${result.path.join(" ")}\n\nDeclared commands (incomplete):`);
|
|
182
|
+
for (const child of result.children) write(` ocx ${child.command.join(" ")} ${child.summary}`);
|
|
183
|
+
}
|
|
184
|
+
write(`\nParent help: ocx help ${result.path.slice(0, -1).join(" ")}`);
|
|
127
185
|
}
|