@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/provider.ts
CHANGED
|
@@ -8,9 +8,9 @@
|
|
|
8
8
|
* show <name> Show provider config details (secrets masked)
|
|
9
9
|
* set-default <name> Change the default provider
|
|
10
10
|
*/
|
|
11
|
-
import { hasOwnProvider, isValidProviderName, loadConfig, sanitizeModelCostsForDisplay, saveConfig } from "../config";
|
|
11
|
+
import { hasOwnProvider, isValidProviderName, loadConfig, sanitizeModelCostsForDisplay, saveConfig, validateConfigCandidate } from "../config";
|
|
12
12
|
import { apiKeyTransportConfigError, modelCapabilitiesConfigError, mergeModelCapabilities } from "../config/provider-validation";
|
|
13
|
-
import { hasHelpFlag } from "./help";
|
|
13
|
+
import { hasHelpFlag, printSubcommandUsage } from "./help";
|
|
14
14
|
import { getProviderRegistryEntry, PROVIDER_REGISTRY } from "../providers/registry";
|
|
15
15
|
import { providerConfigSeed } from "../providers/derive";
|
|
16
16
|
import { dropProviderCustomModels } from "../providers/provider-id-rewrite";
|
|
@@ -19,6 +19,16 @@ import { findLiveProxy } from "../server/proxy-liveness";
|
|
|
19
19
|
import { syncModelsToCodex } from "../codex/sync";
|
|
20
20
|
import { codexAccountNamespaceProviderCollisionError } from "../codex/account-namespace-match";
|
|
21
21
|
import { modelSelectionGuidance, modelSelectionNextSteps } from "./model-selection-guidance";
|
|
22
|
+
import { isCanonicalOpenAiForwardProvider } from "../providers/openai-tiers-destination";
|
|
23
|
+
import { providerRelativeSendPathConfigError } from "../config/provider-relative-send-path";
|
|
24
|
+
import type { RuntimeApiDeps } from "./runtime-api";
|
|
25
|
+
import { redactSecretArgs } from "./secret-args";
|
|
26
|
+
import { projectLocalSyncResult, type LocalSyncResult } from "./local-sync-result";
|
|
27
|
+
import { providerManagementConfigError } from "../server/auth-cors";
|
|
28
|
+
|
|
29
|
+
export interface ProviderCommandDeps extends RuntimeApiDeps {
|
|
30
|
+
syncModels?: typeof syncModelsToCodex;
|
|
31
|
+
}
|
|
22
32
|
|
|
23
33
|
// ---------------------------------------------------------------------------
|
|
24
34
|
// Arg helpers
|
|
@@ -42,11 +52,13 @@ function consumeFlagValue(args: string[], flag: string): string | undefined {
|
|
|
42
52
|
/** Reject any leftover args (unknown flags or trailing values). */
|
|
43
53
|
function rejectUnknownArgs(args: string[], usage: string): void {
|
|
44
54
|
if (args.length === 0) return;
|
|
45
|
-
const
|
|
55
|
+
const shown = redactSecretArgs(args);
|
|
56
|
+
// Flags plus redaction markers only: a stray positional may be a credential operand.
|
|
57
|
+
const unknown = shown.filter(a => a.startsWith("-") || a === "<redacted>");
|
|
46
58
|
if (unknown.length > 0) {
|
|
47
59
|
console.error(`Unknown flag(s): ${unknown.join(", ")}`);
|
|
48
60
|
} else {
|
|
49
|
-
console.error(`Unexpected argument(s): ${
|
|
61
|
+
console.error(`Unexpected argument(s): ${shown.join(", ")}`);
|
|
50
62
|
}
|
|
51
63
|
console.error(usage);
|
|
52
64
|
process.exit(1);
|
|
@@ -70,6 +82,16 @@ function validateAndSave(config: ReturnType<typeof loadConfig>): void {
|
|
|
70
82
|
console.error(`Error: defaultProvider "${config.defaultProvider}" does not exist in providers. Aborting.`);
|
|
71
83
|
process.exit(1);
|
|
72
84
|
}
|
|
85
|
+
const result = validateConfigCandidate(config);
|
|
86
|
+
if (!result.ok) {
|
|
87
|
+
console.error(`Error: ${result.error}`);
|
|
88
|
+
if (result.error.includes("set allowPrivateNetwork:true")) {
|
|
89
|
+
console.error("For an intentionally local provider, add --allow-private-network.");
|
|
90
|
+
} else {
|
|
91
|
+
console.error("Nothing was saved. Fix the setting named above; if this command did not set it, run ocx config validate and repair it with ocx config set/unset.");
|
|
92
|
+
}
|
|
93
|
+
process.exit(1);
|
|
94
|
+
}
|
|
73
95
|
saveConfig(config);
|
|
74
96
|
}
|
|
75
97
|
|
|
@@ -139,9 +161,9 @@ function handleList(args: string[]): void {
|
|
|
139
161
|
// provider add
|
|
140
162
|
// ---------------------------------------------------------------------------
|
|
141
163
|
|
|
142
|
-
const ADD_USAGE = "Usage: ocx provider add <name> [--adapter <adapter>] [--base-url <url>] [--api-key <key>] [--api-key-transport <x-api-key|bearer>] [--default-model <model>] [--model <id> --text-only] [--google-tool-schema-policy <compatible|reject-lossy>] [--allow-private-network] [--set-default] [--force] [--json] [--sync]";
|
|
164
|
+
const ADD_USAGE = "Usage: ocx provider add <name> [--adapter <adapter>] [--base-url <url>] [--responses-path <path>] [--auth-mode <key|forward|oauth|local>] [--api-key <key>] [--api-key-transport <x-api-key|bearer>] [--default-model <model>] [--model <id> --text-only] [--google-tool-schema-policy <compatible|reject-lossy>] [--allow-private-network] [--set-default] [--force] [--json] [--sync | --live]";
|
|
143
165
|
|
|
144
|
-
async function handleAdd(args: string[]): Promise<void> {
|
|
166
|
+
async function handleAdd(args: string[], deps: ProviderCommandDeps): Promise<void> {
|
|
145
167
|
const name = args[0];
|
|
146
168
|
if (!name || name.startsWith("-")) {
|
|
147
169
|
console.error(ADD_USAGE);
|
|
@@ -164,6 +186,8 @@ async function handleAdd(args: string[]): Promise<void> {
|
|
|
164
186
|
const adapter = consumeFlagValue(restArgs, "--adapter");
|
|
165
187
|
const baseUrl = consumeFlagValue(restArgs, "--base-url");
|
|
166
188
|
const defaultModel = consumeFlagValue(restArgs, "--default-model");
|
|
189
|
+
const responsesPath = consumeFlagValue(restArgs, "--responses-path");
|
|
190
|
+
const authMode = consumeFlagValue(restArgs, "--auth-mode");
|
|
167
191
|
const googleToolSchemaPolicy = consumeFlagValue(restArgs, "--google-tool-schema-policy");
|
|
168
192
|
const textOnly = consumeFlag(restArgs, "--text-only");
|
|
169
193
|
const capabilityModel = consumeFlagValue(restArgs, "--model");
|
|
@@ -173,6 +197,12 @@ async function handleAdd(args: string[]): Promise<void> {
|
|
|
173
197
|
process.exit(1);
|
|
174
198
|
}
|
|
175
199
|
|
|
200
|
+
const pathError = providerRelativeSendPathConfigError("responsesPath", responsesPath);
|
|
201
|
+
if (pathError || (authMode !== undefined && !["key", "forward", "oauth", "local"].includes(authMode))) {
|
|
202
|
+
console.error(pathError ? `Error: ${pathError}.` : "Error: --auth-mode must be key, forward, oauth, or local.");
|
|
203
|
+
process.exit(1);
|
|
204
|
+
}
|
|
205
|
+
|
|
176
206
|
const config = loadConfig();
|
|
177
207
|
|
|
178
208
|
const namespaceCollision = codexAccountNamespaceProviderCollisionError(config.codexAccountNamespaces, name);
|
|
@@ -192,9 +222,9 @@ async function handleAdd(args: string[]): Promise<void> {
|
|
|
192
222
|
if (registryEntry) {
|
|
193
223
|
provConfig = providerConfigSeed(registryEntry);
|
|
194
224
|
if (apiKey) {
|
|
195
|
-
if (registryEntry.authKind === "forward") {
|
|
225
|
+
if ((authMode ?? registryEntry.authKind) === "forward") {
|
|
196
226
|
console.warn(`Warning: provider "${name}" uses ChatGPT login (forward auth); --api-key is ignored.`);
|
|
197
|
-
} else if (registryEntry.authKind === "oauth") {
|
|
227
|
+
} else if ((authMode ?? registryEntry.authKind) === "oauth") {
|
|
198
228
|
console.warn(`Warning: provider "${name}" uses OAuth auth; --api-key is ignored. Run: ocx login ${name}`);
|
|
199
229
|
} else {
|
|
200
230
|
provConfig.apiKey = apiKey;
|
|
@@ -217,6 +247,15 @@ async function handleAdd(args: string[]): Promise<void> {
|
|
|
217
247
|
};
|
|
218
248
|
}
|
|
219
249
|
|
|
250
|
+
if (responsesPath !== undefined) provConfig.responsesPath = responsesPath;
|
|
251
|
+
if (authMode !== undefined) provConfig.authMode = authMode as OcxProviderConfig["authMode"];
|
|
252
|
+
if (name === "openai" && (authMode !== undefined || responsesPath !== undefined)
|
|
253
|
+
&& !isCanonicalOpenAiForwardProvider(provConfig)) {
|
|
254
|
+
console.error("Error: Canonical OpenAI must keep its built-in forward destination and authentication. Use a separate provider name for a custom endpoint.");
|
|
255
|
+
process.exitCode = 2;
|
|
256
|
+
return;
|
|
257
|
+
}
|
|
258
|
+
|
|
220
259
|
if (apiKeyTransport !== undefined) {
|
|
221
260
|
if (apiKeyTransport !== "x-api-key" && apiKeyTransport !== "bearer") {
|
|
222
261
|
console.error('Error: --api-key-transport must be "x-api-key" or "bearer".');
|
|
@@ -259,9 +298,6 @@ async function handleAdd(args: string[]): Promise<void> {
|
|
|
259
298
|
if (error) { console.error(`Error: ${error}.`); process.exit(1); }
|
|
260
299
|
provConfig.modelCapabilities = mergeModelCapabilities(provConfig.modelCapabilities, declaration);
|
|
261
300
|
}
|
|
262
|
-
const { initializeProviderModelSelection } = await import("../providers/initial-model-selection");
|
|
263
|
-
initializeProviderModelSelection(name, provConfig, existingProvider, config);
|
|
264
|
-
config.providers[name] = provConfig;
|
|
265
301
|
// A --force overwrite rotates the key/endpoint but must not drop a
|
|
266
302
|
// user-configured price overlay (same rule as the /api/providers path and
|
|
267
303
|
// the login paths); there is no explicit clear/replace flag yet.
|
|
@@ -269,10 +305,38 @@ async function handleAdd(args: string[]): Promise<void> {
|
|
|
269
305
|
provConfig.modelCosts = existingProvider.modelCosts;
|
|
270
306
|
}
|
|
271
307
|
if (allowPrivateNetwork) provConfig.allowPrivateNetwork = true;
|
|
308
|
+
// New auth/path overrides use the management owner's completed-row contract.
|
|
309
|
+
// Validate overrides before registration state changes; the full candidate is
|
|
310
|
+
// validated again by validateAndSave for every local save.
|
|
311
|
+
if ((authMode !== undefined || responsesPath !== undefined)
|
|
312
|
+
&& providerManagementConfigError(name, provConfig)) {
|
|
313
|
+
console.error("Error: Invalid provider configuration. Authentication, destination and provider options must satisfy the provider's management rules.");
|
|
314
|
+
process.exitCode = 2;
|
|
315
|
+
return;
|
|
316
|
+
}
|
|
317
|
+
const { initializeProviderModelSelection } = await import("../providers/initial-model-selection");
|
|
318
|
+
initializeProviderModelSelection(name, provConfig, existingProvider, config);
|
|
319
|
+
config.providers[name] = provConfig;
|
|
272
320
|
if (setDefault) config.defaultProvider = name;
|
|
273
321
|
|
|
274
322
|
validateAndSave(config);
|
|
275
323
|
|
|
324
|
+
let sync: LocalSyncResult | undefined;
|
|
325
|
+
if (wantsSync) {
|
|
326
|
+
try {
|
|
327
|
+
const live = await (deps.findLiveProxy ?? findLiveProxy)();
|
|
328
|
+
if (!live) sync = { status: "not-running", ok: false };
|
|
329
|
+
else {
|
|
330
|
+
const result = await (deps.syncModels ?? syncModelsToCodex)(live.port, config, null);
|
|
331
|
+
sync = projectLocalSyncResult(result);
|
|
332
|
+
}
|
|
333
|
+
} catch {
|
|
334
|
+
// Dependency errors can contain keys, paths or request details. Keep a fixed outcome.
|
|
335
|
+
sync = { status: "failed", ok: false };
|
|
336
|
+
}
|
|
337
|
+
if (!sync.ok || sync.status === "refused") process.exitCode = 1;
|
|
338
|
+
}
|
|
339
|
+
const synced = sync?.status === "applied" && sync.ok;
|
|
276
340
|
if (wantsJson) {
|
|
277
341
|
console.log(JSON.stringify({
|
|
278
342
|
action: "added",
|
|
@@ -283,26 +347,13 @@ async function handleAdd(args: string[]): Promise<void> {
|
|
|
283
347
|
defaultModel: provConfig.defaultModel ?? null,
|
|
284
348
|
isDefault: config.defaultProvider === name,
|
|
285
349
|
source: registryEntry ? "registry" : "custom",
|
|
286
|
-
needsSync:
|
|
350
|
+
needsSync: !synced,
|
|
351
|
+
...(sync ? { sync } : {}),
|
|
287
352
|
}, null, 2));
|
|
288
353
|
return;
|
|
289
354
|
}
|
|
290
355
|
|
|
291
|
-
|
|
292
|
-
if (wantsSync) {
|
|
293
|
-
const live = await findLiveProxy();
|
|
294
|
-
if (live) {
|
|
295
|
-
const synced = await syncModelsToCodex(live.port).catch(e => {
|
|
296
|
-
console.error(`Warning: sync failed: ${e instanceof Error ? e.message : String(e)}`);
|
|
297
|
-
return null;
|
|
298
|
-
});
|
|
299
|
-
if (synced?.status === "skipped") {
|
|
300
|
-
codexSyncSkipped = true;
|
|
301
|
-
console.log("Provider saved; Codex integration is OFF, so Codex sync was skipped.");
|
|
302
|
-
}
|
|
303
|
-
}
|
|
304
|
-
}
|
|
305
|
-
|
|
356
|
+
if (sync?.warning) console.log(` Warning: ${sync.warning}`);
|
|
306
357
|
const registryLabel = registryEntry ? ` (${registryEntry.label})` : "";
|
|
307
358
|
console.log(`✅ Provider "${name}"${registryLabel} added.`);
|
|
308
359
|
for (const line of modelSelectionGuidance(name)) console.log(line);
|
|
@@ -315,10 +366,15 @@ async function handleAdd(args: string[]): Promise<void> {
|
|
|
315
366
|
console.log(` Set API key with: ocx provider add ${name} --api-key <key> --force`);
|
|
316
367
|
console.log(` Or set env var: ${envKey}`);
|
|
317
368
|
}
|
|
318
|
-
if (
|
|
319
|
-
|
|
320
|
-
|
|
321
|
-
|
|
369
|
+
if (synced) console.log(" Models synced to Codex.");
|
|
370
|
+
else {
|
|
371
|
+
if (sync) {
|
|
372
|
+
console.log(sync.configApplied && !sync.ok
|
|
373
|
+
? " Provider saved; sync remains incomplete despite config injection."
|
|
374
|
+
: ` Provider saved; client sync outcome: ${sync.status}.`);
|
|
375
|
+
if (sync.catalog && !sync.catalog.converged) console.log(" Model catalog did not converge; inspect the target before retrying.");
|
|
376
|
+
}
|
|
377
|
+
console.log(" Apply to Codex: ocx sync");
|
|
322
378
|
}
|
|
323
379
|
}
|
|
324
380
|
|
|
@@ -472,49 +528,45 @@ function handleSetDefault(args: string[]): void {
|
|
|
472
528
|
// Router (F2 fix: handle help flags internally, like service/codex-shim)
|
|
473
529
|
// ---------------------------------------------------------------------------
|
|
474
530
|
|
|
475
|
-
|
|
476
|
-
|
|
477
|
-
Subcommands:
|
|
478
|
-
list List configured and available providers
|
|
479
|
-
add <name> Add a provider (registry or custom)
|
|
480
|
-
edit <name> Edit live provider fields
|
|
481
|
-
test <name> Test the provider's upstream model endpoint
|
|
482
|
-
remove <name> Remove a configured provider
|
|
483
|
-
show <name> Show provider config details
|
|
484
|
-
set-default <name> Change the default provider
|
|
485
|
-
selected <name> Show or set the provider model allowlist
|
|
486
|
-
quota Show provider quota reports
|
|
487
|
-
resets Show recently detected quota resets
|
|
488
|
-
presets List GUI provider presets
|
|
489
|
-
account-mode <mode> Set OpenAI Codex pool/direct mode
|
|
490
|
-
|
|
491
|
-
Examples:
|
|
492
|
-
ocx provider list
|
|
493
|
-
ocx provider list --jsonl
|
|
494
|
-
ocx provider add anthropic --api-key sk-ant-...
|
|
495
|
-
ocx provider add my-ollama --adapter openai-chat --base-url http://localhost:11434/v1
|
|
496
|
-
ocx provider show anthropic --json
|
|
497
|
-
ocx provider set-default anthropic
|
|
498
|
-
ocx provider edit xai --xai-chat on # opt Grok 4.5/4.6 into Chat Completions
|
|
499
|
-
ocx provider edit xai --xai-chat off # use Responses again
|
|
500
|
-
ocx provider remove my-ollama`;
|
|
501
|
-
|
|
502
|
-
export async function handleProviderCommand(args: string[]): Promise<void> {
|
|
531
|
+
|
|
532
|
+
export async function handleProviderCommand(args: string[], deps: ProviderCommandDeps = {}): Promise<void> {
|
|
503
533
|
const sub = args[0];
|
|
504
534
|
|
|
505
535
|
if (!sub || sub === "help" || hasHelpFlag(args)) {
|
|
506
|
-
|
|
536
|
+
printSubcommandUsage("provider");
|
|
507
537
|
process.exit(0);
|
|
508
538
|
}
|
|
509
539
|
|
|
510
540
|
const subArgs = args.slice(1);
|
|
541
|
+
const liveArgs = subArgs.filter(arg => arg === "--live" || arg.startsWith("--live="));
|
|
542
|
+
if (liveArgs.length) {
|
|
543
|
+
if (liveArgs.length !== 1 || liveArgs[0] !== "--live" || !["add", "remove", "set-default"].includes(sub)) {
|
|
544
|
+
console.error("Error: --live is a single boolean flag for provider add, remove, or set-default.");
|
|
545
|
+
process.exitCode = 2;
|
|
546
|
+
return;
|
|
547
|
+
}
|
|
548
|
+
subArgs.splice(subArgs.indexOf("--live"), 1);
|
|
549
|
+
const { handleProviderLifecycleRuntimeCommand } = await import("./provider-lifecycle-runtime");
|
|
550
|
+
process.exitCode = await handleProviderLifecycleRuntimeCommand(sub as "add" | "remove" | "set-default", subArgs, deps);
|
|
551
|
+
return;
|
|
552
|
+
}
|
|
553
|
+
if (sub === "snapshot" || sub === "apply") {
|
|
554
|
+
const { handleProviderBatchCommand } = await import("./provider-batch");
|
|
555
|
+
process.exitCode = await handleProviderBatchCommand(sub, subArgs, deps);
|
|
556
|
+
return;
|
|
557
|
+
}
|
|
558
|
+
if (sub === "pacing") {
|
|
559
|
+
const { handleProviderPacingCommand } = await import("./provider-settings");
|
|
560
|
+
process.exitCode = await handleProviderPacingCommand(subArgs, deps);
|
|
561
|
+
return;
|
|
562
|
+
}
|
|
511
563
|
|
|
512
564
|
switch (sub) {
|
|
513
565
|
case "list":
|
|
514
566
|
handleList(subArgs);
|
|
515
567
|
break;
|
|
516
568
|
case "add":
|
|
517
|
-
await handleAdd(subArgs);
|
|
569
|
+
await handleAdd(subArgs, deps);
|
|
518
570
|
break;
|
|
519
571
|
case "remove":
|
|
520
572
|
handleRemove(subArgs);
|
|
@@ -527,13 +579,13 @@ export async function handleProviderCommand(args: string[]): Promise<void> {
|
|
|
527
579
|
break;
|
|
528
580
|
default: {
|
|
529
581
|
const { handleProviderRuntimeCommand } = await import("./provider-runtime");
|
|
530
|
-
const code = await handleProviderRuntimeCommand(sub, subArgs);
|
|
582
|
+
const code = await handleProviderRuntimeCommand(sub, subArgs, deps);
|
|
531
583
|
if (code !== null) {
|
|
532
584
|
process.exitCode = code;
|
|
533
585
|
break;
|
|
534
586
|
}
|
|
535
|
-
console.error(`Unknown provider subcommand: ${sub}`);
|
|
536
|
-
console.error
|
|
587
|
+
console.error(`Unknown provider subcommand: ${redactSecretArgs([sub ?? ""])[0]}`);
|
|
588
|
+
printSubcommandUsage("provider", undefined, { write: console.error });
|
|
537
589
|
process.exit(1);
|
|
538
590
|
}
|
|
539
591
|
}
|
package/src/cli/registry.ts
CHANGED
|
@@ -144,18 +144,19 @@ export const CLI_COMMANDS: CliCommandEntry[] = [
|
|
|
144
144
|
"Port: ocx link port [--json]",
|
|
145
145
|
"Issue: ocx link issue --alias <alias> --tunnel-port <port> [--json]",
|
|
146
146
|
"Status: ocx link status [--json]",
|
|
147
|
-
"Revoke: ocx link revoke --link-id <id> [--json]",
|
|
147
|
+
"Revoke: ocx link revoke --link-id <id> [--force --yes] [--json]",
|
|
148
148
|
"Issue, status, and revoke use the running proxy's loopback management API and admin token.",
|
|
149
149
|
],
|
|
150
150
|
},
|
|
151
151
|
{
|
|
152
152
|
name: "remote-workspace",
|
|
153
|
-
usage: "ocx remote-workspace <pair|agent|status>",
|
|
154
|
-
summary: "
|
|
153
|
+
usage: "ocx remote-workspace <pair|agent|status|hub>",
|
|
154
|
+
summary: "Manage this workspace executor or inspect the selected Hub.",
|
|
155
155
|
details: [
|
|
156
156
|
"Pair: ocx remote-workspace pair <hub-url> --pairing-code-stdin --root <absolute-path> [--toolchain-root <absolute-directory>] [--executor-helper <absolute-file>] [--name <device-name>]",
|
|
157
157
|
"Agent: ocx remote-workspace agent",
|
|
158
158
|
"Status: ocx remote-workspace status [--json]",
|
|
159
|
+
"Hub: ocx remote-workspace hub <status|runtimes|sessions> [--json]",
|
|
159
160
|
"Codex, Claude Code, Pi, provider logins, and API keys remain on the hub; only workspace tools execute here.",
|
|
160
161
|
],
|
|
161
162
|
},
|
|
@@ -275,12 +276,42 @@ export const CLI_COMMANDS: CliCommandEntry[] = [
|
|
|
275
276
|
},
|
|
276
277
|
{
|
|
277
278
|
name: "provider",
|
|
278
|
-
usage: "ocx provider <
|
|
279
|
+
usage: "ocx provider <subcommand>",
|
|
279
280
|
summary: "Non-interactive provider management.",
|
|
280
281
|
details: [
|
|
281
|
-
"Subcommands:
|
|
282
|
+
"Subcommands:",
|
|
283
|
+
" list List configured and available providers",
|
|
284
|
+
" add <name> Add a provider (registry or custom)",
|
|
285
|
+
" edit <name> Edit live provider fields",
|
|
286
|
+
" pacing <name> Read/edit live request pacing rules",
|
|
287
|
+
" snapshot Read a non-secret provider editor baseline",
|
|
288
|
+
" apply Apply edited providers with baseline conflict checks",
|
|
289
|
+
" test <name> Test the provider's upstream model endpoint",
|
|
290
|
+
" remove <name> Remove a configured provider",
|
|
291
|
+
" show <name> Show provider config details",
|
|
292
|
+
" set-default <name> Change the default provider",
|
|
293
|
+
" add/remove/set-default support --live; live removal also requires --yes.",
|
|
294
|
+
" selected <name> Show or set the provider model allowlist",
|
|
295
|
+
" quota Show provider quota reports",
|
|
296
|
+
" resets Show recently detected quota resets",
|
|
297
|
+
" presets List GUI provider presets",
|
|
298
|
+
" account-mode <mode> Set OpenAI Codex pool/direct mode",
|
|
299
|
+
"",
|
|
300
|
+
"Examples:",
|
|
301
|
+
" ocx provider list",
|
|
302
|
+
" ocx provider list --jsonl",
|
|
303
|
+
" ocx provider presets --json",
|
|
304
|
+
" ocx provider add anthropic --api-key <key>",
|
|
305
|
+
" ocx provider add my-ollama --adapter openai-chat --base-url http://localhost:11434/v1",
|
|
306
|
+
" ocx provider show anthropic --json",
|
|
307
|
+
" ocx provider pacing anthropic --json",
|
|
308
|
+
" ocx provider snapshot --json",
|
|
309
|
+
" ocx provider set-default anthropic",
|
|
310
|
+
" ocx provider edit xai --xai-chat on # opt Grok 4.5/4.6 into Chat Completions",
|
|
311
|
+
" ocx provider edit xai --xai-chat off # use Responses again",
|
|
312
|
+
" ocx provider remove my-ollama",
|
|
313
|
+
"",
|
|
282
314
|
"Registry providers are auto-configured by name. Custom providers need --adapter and --base-url.",
|
|
283
|
-
"Run `ocx provider --help` for full usage and examples.",
|
|
284
315
|
],
|
|
285
316
|
},
|
|
286
317
|
{
|
|
@@ -296,6 +327,11 @@ export const CLI_COMMANDS: CliCommandEntry[] = [
|
|
|
296
327
|
"priority <provider> <id|main> [first|earlier|normal|later|last|-100..100|reset] Selection order; omit the value to read it.",
|
|
297
328
|
"remove <provider> <id> --yes Remove a stored account or key after an existence check.",
|
|
298
329
|
"add-key <provider> [--label <label>] Add a key read only from piped stdin.",
|
|
330
|
+
"pool <provider> Read/edit runtime-supported pool policy.",
|
|
331
|
+
"credits openai ... Explicit paid-credit-after-limit policy; separate from displaying balances.",
|
|
332
|
+
"quota-activation openai Enable/disable one account reset-window refresh policy.",
|
|
333
|
+
"anthropic-reset-grants Read grant status only; consumption remains in the dashboard.",
|
|
334
|
+
"login supports explicit browser/add-account options only for applicable flows; human verification remains required.",
|
|
299
335
|
"login/reauth/code/cancel Run browser or manual-code auth from a headless shell.",
|
|
300
336
|
"reset-credits <id|main> [--consume --yes] Inspect or consume Codex reset credits.",
|
|
301
337
|
"grok-reset-coupons [<id>] [--consume --yes] Inspect or redeem Grok reset coupons.",
|
|
@@ -316,6 +352,10 @@ export const CLI_COMMANDS: CliCommandEntry[] = [
|
|
|
316
352
|
summary: "List models and manage custom (manually registered) models.",
|
|
317
353
|
details: [
|
|
318
354
|
"List available models from static config with no subcommand (liveModels may add more at runtime).",
|
|
355
|
+
"add/remove support --live for the selected proxy; live or JSON removal requires --yes.",
|
|
356
|
+
"Local add/remove JSON reports saved state and opportunistic sync; no proxy keeps the save successful/pending.",
|
|
357
|
+
"display-name <provider/raw-model> --set <label> or --clear changes an exact upstream model label.",
|
|
358
|
+
"order status/set/reset manages routed picker order; reset native-inclusive saved order before replacement.",
|
|
319
359
|
"add: register a model the provider catalog does not advertise yet.",
|
|
320
360
|
" --display-name <name> Human label (no slashes).",
|
|
321
361
|
" --context-window <tokens> e.g. 200000.",
|
|
@@ -333,12 +373,14 @@ export const CLI_COMMANDS: CliCommandEntry[] = [
|
|
|
333
373
|
},
|
|
334
374
|
{
|
|
335
375
|
name: "companion",
|
|
336
|
-
usage: "ocx companion <show|set|reset> ...",
|
|
337
|
-
summary: "Inspect
|
|
376
|
+
usage: "ocx companion <show|set|reset|usage|timeline> ...",
|
|
377
|
+
summary: "Inspect companion settings, filtered usage and timeline, or change preferences.",
|
|
338
378
|
details: [
|
|
339
379
|
"ocx companion and ocx companion show read settings; use --json for machine-readable output.",
|
|
340
380
|
"ocx companion set accepts one or more key=value assignments; values are parsed as JSON when possible.",
|
|
341
381
|
"ocx companion reset restores the default settings.",
|
|
382
|
+
"ocx companion usage reads today and 30-day totals with saved model/provider filters; unavailable ranges return partial output and exit 1.",
|
|
383
|
+
"ocx companion timeline reads buckets; --model selects models and --hide-provider excludes providers.",
|
|
342
384
|
],
|
|
343
385
|
},
|
|
344
386
|
{
|
|
@@ -349,8 +391,8 @@ export const CLI_COMMANDS: CliCommandEntry[] = [
|
|
|
349
391
|
},
|
|
350
392
|
{
|
|
351
393
|
name: "route",
|
|
352
|
-
usage: "ocx route combo <
|
|
353
|
-
summary: "Manage
|
|
394
|
+
usage: "ocx route <combo|policy> <subcommand>",
|
|
395
|
+
summary: "Manage combo routing and routing profiles.",
|
|
354
396
|
},
|
|
355
397
|
{
|
|
356
398
|
name: "effort",
|
|
@@ -383,11 +425,11 @@ export const CLI_COMMANDS: CliCommandEntry[] = [
|
|
|
383
425
|
"`inspect star` reads the repository star status only. Starring uses your GitHub identity and is available from the dashboard alone.",
|
|
384
426
|
],
|
|
385
427
|
},
|
|
386
|
-
{ name: "logs", usage: "ocx logs [filters] [--follow] [--json|--jsonl]", summary: "
|
|
428
|
+
{ name: "logs", usage: "ocx logs [filters] [--follow] [--json|--jsonl|--events]", summary: "Read or follow request logs." },
|
|
387
429
|
{
|
|
388
430
|
name: "usage",
|
|
389
|
-
usage: "ocx usage [--range <today|1d|7d|30d|all>] [--surface <all|codex|claude|grok>] [--provider <name>] [--model <id>] [--json]",
|
|
390
|
-
summary: "
|
|
431
|
+
usage: "ocx usage [--range <today|1d|7d|30d|all>] [--surface <all|codex|claude|grok>] [--provider <name>] [--model <id>] [--api-key-id <id>] [--search <text>] [--json]",
|
|
432
|
+
summary: "Report token usage and estimated cost (alias of ocx observe usage).",
|
|
391
433
|
},
|
|
392
434
|
{
|
|
393
435
|
name: "storage",
|
|
@@ -401,14 +443,17 @@ export const CLI_COMMANDS: CliCommandEntry[] = [
|
|
|
401
443
|
{ name: "memory", usage: "ocx memory [--json]", summary: "Alias of ocx observe memory." },
|
|
402
444
|
{
|
|
403
445
|
name: "access",
|
|
404
|
-
usage: "ocx access <key|endpoints|models|test> ...",
|
|
446
|
+
usage: "ocx access <key|endpoints|models|test|audio> ...",
|
|
405
447
|
summary: "Manage OpenCodex admission API keys and inspect external endpoints.",
|
|
406
448
|
details: [
|
|
407
449
|
"Key rotation start uses POST /api/keys/rotate and returns the replacement secret once.",
|
|
408
450
|
"Commit uses POST /api/keys/rotate/commit; abort uses DELETE /api/keys/rotate with the returned rotation id.",
|
|
451
|
+
"key rename changes a masked key's name without clearing its scopes.",
|
|
452
|
+
"test --api-key-stdin uses one supplied data key; it never substitutes management or enrolled credentials.",
|
|
453
|
+
"audio transcribe/live-check use explicit piped key input and may use provider quota; authorize the operation first.",
|
|
409
454
|
],
|
|
410
455
|
},
|
|
411
|
-
{ name: "api-key", usage: "ocx api-key <list|create|rotate|remove> ...", summary: "Alias of ocx access key." },
|
|
456
|
+
{ name: "api-key", usage: "ocx api-key <list|get|create|set|rename|rotate|remove> ...", summary: "Alias of ocx access key." },
|
|
412
457
|
{
|
|
413
458
|
name: "api",
|
|
414
459
|
usage: "ocx api <protocols|explain|policy> ...",
|
|
@@ -444,14 +489,18 @@ export const CLI_COMMANDS: CliCommandEntry[] = [
|
|
|
444
489
|
summary: "Manage supported client integrations, and the native client toggles.",
|
|
445
490
|
details: [
|
|
446
491
|
"`native` shows or flips the native Claude/Claude Desktop/Codex/Grok toggles; the other subcommands manage the reversible file integrations.",
|
|
492
|
+
"client preview shows a proposed change; enable/disable/restore accept an optional --plan-fingerprint.",
|
|
493
|
+
"client history remove requires --yes; client sync --client aside refreshes managed Aside profiles.",
|
|
494
|
+
"native cursor status/local-installer are reads; installer lookup does not install anything.",
|
|
447
495
|
],
|
|
448
496
|
},
|
|
449
497
|
{
|
|
450
498
|
name: "system",
|
|
451
|
-
usage: "ocx system <status|settings|startup|diagnostics|sync|codex-app-server|codex-restart|update|codex-cli-update> ...",
|
|
499
|
+
usage: "ocx system <status|health|settings|startup|diagnostics|sync|codex-app-server|codex-restart|update|codex-cli-update> ...",
|
|
452
500
|
summary: "Manage headless runtime settings, startup, sync, diagnostics, OpenCodex updates, and read-only Codex CLI inspection.",
|
|
453
501
|
details: [
|
|
454
502
|
"system update manages OpenCodex itself.",
|
|
503
|
+
"system health reads authenticated service and spend-ledger diagnostics; root health remains liveness.",
|
|
455
504
|
"ocx system codex-cli-update check [--json]",
|
|
456
505
|
"ocx system codex-cli-update attest [--json]",
|
|
457
506
|
"ocx system codex-cli-update attest --candidate <absolute-path> --npm-prefix <absolute-path> --npm-cli <absolute-path> --node <absolute-path> [--json]",
|
|
@@ -460,9 +509,14 @@ export const CLI_COMMANDS: CliCommandEntry[] = [
|
|
|
460
509
|
},
|
|
461
510
|
{
|
|
462
511
|
name: "config",
|
|
463
|
-
usage: "ocx config
|
|
512
|
+
usage: "ocx config [show|get|set|unset|validate|export|import] ...",
|
|
464
513
|
summary: "Inspect and safely modify validated OpenCodex configuration.",
|
|
465
|
-
details: [
|
|
514
|
+
details: [
|
|
515
|
+
"show is the default: ocx config [show] [--json] [--source]. Flags alone also display the local configuration without a running proxy.",
|
|
516
|
+
"--json may precede an explicit action without changing which action runs.",
|
|
517
|
+
"--source is only supported for show and includes diagnostic source, error, and warning fields.",
|
|
518
|
+
"Secrets are masked by show/get. Import requires --yes and validates before writing.",
|
|
519
|
+
],
|
|
466
520
|
},
|
|
467
521
|
{
|
|
468
522
|
name: "claude",
|
|
@@ -487,6 +541,8 @@ export const CLI_COMMANDS: CliCommandEntry[] = [
|
|
|
487
541
|
" ocx claude desktop default <family> <route|none>",
|
|
488
542
|
" ocx claude desktop export <path|-> Export versioned JSON (`-` = stdout)",
|
|
489
543
|
" ocx claude desktop import <path> [--apply] Validate and import JSON",
|
|
544
|
+
" ocx claude desktop profile show [--json] Read the running proxy's profile",
|
|
545
|
+
" ocx claude desktop profile import <file|-> [--json] Save the running profile without applying",
|
|
490
546
|
"Families: opus, fable, sonnet, haiku. New routes start in opus.",
|
|
491
547
|
"`none` is valid only when that family is empty.",
|
|
492
548
|
"Legacy apply flags remain supported: --static, --hybrid, --discovery-only.",
|
|
@@ -503,7 +559,7 @@ export const CLI_COMMANDS: CliCommandEntry[] = [
|
|
|
503
559
|
"and `providers.opencodex` blocks injected through OpenCode's inline runtime layer",
|
|
504
560
|
"(`OPENCODE_CONFIG_CONTENT`). Any existing inline config in the environment is preserved",
|
|
505
561
|
"and only `provider.opencodex` and `providers.opencodex` are overwritten for this launch.",
|
|
506
|
-
"
|
|
562
|
+
"V1 receives reasoning-effort variant maps; V2 receives native variant arrays for the same declared choices and defaults.",
|
|
507
563
|
"Global/project opencode.json may be read to warn about an existing provider.opencodex or",
|
|
508
564
|
"providers.opencodex override; on-disk files are never modified.",
|
|
509
565
|
"Routed models appear in the model picker as opencodex/<provider>/<model>.",
|
|
@@ -536,8 +592,8 @@ export const CLI_COMMANDS: CliCommandEntry[] = [
|
|
|
536
592
|
summary: "Connect ZCode (Z.ai desktop client) to the proxy via its managed provider.",
|
|
537
593
|
details: [
|
|
538
594
|
"Alias of ocx integration client <sub> --client zcode.",
|
|
539
|
-
"enable writes the
|
|
540
|
-
"
|
|
595
|
+
"enable manages ~/.zcode/v2/provider_config.json with schemaVersion 1; if the store is absent, it writes the legacy provider.opencodex block into ~/.zcode/v2/config.json.",
|
|
596
|
+
"A surviving owned legacy block prevents switching stores. Run `ocx zcode disable` before enabling the current store. Unknown store schemas are refused.",
|
|
541
597
|
"ZCode reads its config at startup — restart ZCode after enable/disable.",
|
|
542
598
|
"Select OpenCodex Proxy/<provider>/<model> from ZCode's model picker.",
|
|
543
599
|
],
|
|
@@ -545,7 +601,13 @@ export const CLI_COMMANDS: CliCommandEntry[] = [
|
|
|
545
601
|
{
|
|
546
602
|
name: "restart",
|
|
547
603
|
usage: "ocx restart",
|
|
548
|
-
summary: "
|
|
604
|
+
summary: "Request a graceful restart of the verified running proxy, preserving routing.",
|
|
605
|
+
details: [
|
|
606
|
+
"If no proxy is running, use the normal `ocx ensure` start policy, including the Codex autostart setting.",
|
|
607
|
+
"Unverifiable running targets are refused without a stop/start fallback.",
|
|
608
|
+
"Restarting an older proxy from this newer CLI requires standalone macOS/Linux proxies; supervised, shared, foreground, or unverifiable targets are refused.",
|
|
609
|
+
"For a service-managed update, run `ocx service restart`; for a desktop-managed update, restart through the OpenCodex desktop app.",
|
|
610
|
+
],
|
|
549
611
|
},
|
|
550
612
|
{
|
|
551
613
|
name: "v2",
|
|
@@ -604,8 +666,8 @@ export const CLI_COMMANDS: CliCommandEntry[] = [
|
|
|
604
666
|
},
|
|
605
667
|
{
|
|
606
668
|
name: "lab",
|
|
607
|
-
usage: "ocx lab <status|verdicts|subjects|subject|observations|events|event|artifacts|artifact|catalog> [options] [--json]",
|
|
608
|
-
summary: "
|
|
669
|
+
usage: "ocx lab <status|verdicts|subjects|subject|observations|events|event|artifacts|artifact|catalog|production-signals|public|automation|run> [options] [--json]",
|
|
670
|
+
summary: "Inspect local Compatibility Lab evidence and explicitly control automation.",
|
|
609
671
|
details: [
|
|
610
672
|
"status Projection availability, schema versions, and row counts.",
|
|
611
673
|
"verdicts Paginated derived compatibility verdicts with filters.",
|
|
@@ -614,6 +676,10 @@ export const CLI_COMMANDS: CliCommandEntry[] = [
|
|
|
614
676
|
"events Event history; event <id> returns one safe typed event.",
|
|
615
677
|
"artifacts Artifact metadata only (no content download).",
|
|
616
678
|
"catalog Packaged protocol/live scenario catalog metadata.",
|
|
679
|
+
"production-signals Local passive routing evidence for a subject.",
|
|
680
|
+
"public Preview/export local evidence; verify/import a bundle.",
|
|
681
|
+
"automation Read status/runs or explicitly enable/disable local policy.",
|
|
682
|
+
"run Explicit manual scenario; live probes can consume quota.",
|
|
617
683
|
"Reads never rebuild the projection, trigger probes, or require the proxy.",
|
|
618
684
|
],
|
|
619
685
|
},
|
|
@@ -0,0 +1,83 @@
|
|
|
1
|
+
import { z } from "zod";
|
|
2
|
+
import { REMOTE_WORKSPACE_CAPABILITIES, isRemoteWorkspaceToolName } from "../remote-control/workspace-tools";
|
|
3
|
+
import { runCatalogAction } from "./catalog-command-result";
|
|
4
|
+
import { CliUsageError, RuntimeApiError, printData, rejectArgs, runtimeRequest, takeFlag, type RuntimeApiDeps } from "./runtime-api";
|
|
5
|
+
|
|
6
|
+
export const REMOTE_WORKSPACE_HUB_USAGE = "Usage: ocx remote-workspace hub [status|runtimes|sessions] [--json]";
|
|
7
|
+
const UNAVAILABLE = "Remote Workspace requires Hub mode and OCX_REMOTE_WORKSPACE_ENABLED=1. Run this command on the intended Hub.";
|
|
8
|
+
const identity = z.string().min(1);
|
|
9
|
+
const capabilities = z.array(z.enum(REMOTE_WORKSPACE_CAPABILITIES));
|
|
10
|
+
const root = z.object({ id: identity, label: z.string() });
|
|
11
|
+
const device = z.object({
|
|
12
|
+
id: identity, name: z.string(), platform: z.string(), capabilities, roots: z.array(root),
|
|
13
|
+
online: z.boolean(), createdAt: z.string(), lastSeenAt: z.string().nullable(),
|
|
14
|
+
});
|
|
15
|
+
const availability = z.object({ available: z.boolean(), version: z.string().optional(), reason: z.string().optional() });
|
|
16
|
+
const runtimes = z.object({ codex: availability, claude: availability, pi: availability });
|
|
17
|
+
const event = z.object({ sequence: z.number().int().nonnegative(), at: z.string(),
|
|
18
|
+
type: z.enum(["status", "assistant", "tool", "error"]), text: z.string() });
|
|
19
|
+
const session = z.object({
|
|
20
|
+
id: identity, profile: z.enum(["codex", "claude", "pi"]), accessMode: z.enum(["read-only", "workspace"]),
|
|
21
|
+
deviceId: identity, deviceName: z.string(), rootId: identity, rootLabel: z.string(), capabilities,
|
|
22
|
+
tools: z.array(z.custom<string>(isRemoteWorkspaceToolName)), threadId: z.string().nullable(),
|
|
23
|
+
resumable: z.boolean(), status: z.enum(["starting", "ready", "running", "waiting_for_executor", "failed", "stopped"]),
|
|
24
|
+
createdAt: z.string(), updatedAt: z.string(), events: z.array(event),
|
|
25
|
+
});
|
|
26
|
+
const sessions = z.array(session);
|
|
27
|
+
const status = z.object({ available: z.literal(true), devices: z.array(device), runtimes, sessions });
|
|
28
|
+
const unavailable = z.object({ available: z.literal(false), reason: z.string(),
|
|
29
|
+
devices: z.array(z.unknown()).length(0), runtimes: z.object({}).strict(), sessions: z.array(z.unknown()).length(0) });
|
|
30
|
+
|
|
31
|
+
/** Hub observations use management admission; executor pairing and session writes remain separate. */
|
|
32
|
+
export async function handleRemoteWorkspaceHubCommand(argv: string[], deps: RuntimeApiDeps = {}): Promise<number> {
|
|
33
|
+
return runCatalogAction(async () => {
|
|
34
|
+
const args = [...argv];
|
|
35
|
+
const wantsJson = takeFlag(args, "--json");
|
|
36
|
+
const action = args.shift() ?? "status";
|
|
37
|
+
rejectArgs(args, REMOTE_WORKSPACE_HUB_USAGE);
|
|
38
|
+
if (!["status", "runtimes", "sessions"].includes(action)) {
|
|
39
|
+
throw new CliUsageError("Expected Hub status, runtimes or sessions", REMOTE_WORKSPACE_HUB_USAGE);
|
|
40
|
+
}
|
|
41
|
+
const path = `/api/remote-workspace${action === "status" ? "" : `/${action}`}`;
|
|
42
|
+
let raw: unknown;
|
|
43
|
+
try {
|
|
44
|
+
raw = await runtimeRequest(path, { redirect: "error" }, deps);
|
|
45
|
+
} catch (error) {
|
|
46
|
+
// The inner owner can refuse after activation changed; the outer owner uses a 200 observation.
|
|
47
|
+
if (error instanceof RuntimeApiError && error.status === 409) {
|
|
48
|
+
console.error(`Error: ${UNAVAILABLE}`);
|
|
49
|
+
return 5;
|
|
50
|
+
}
|
|
51
|
+
throw error;
|
|
52
|
+
}
|
|
53
|
+
if (unavailable.safeParse(raw).success) {
|
|
54
|
+
printData({ available: false, reason: UNAVAILABLE, devices: [], runtimes: {}, sessions: [] }, wantsJson, [UNAVAILABLE]);
|
|
55
|
+
return 1;
|
|
56
|
+
}
|
|
57
|
+
if (action === "status") {
|
|
58
|
+
const parsed = status.safeParse(raw);
|
|
59
|
+
if (!parsed.success) throw new Error("Invalid Hub observation");
|
|
60
|
+
const data = parsed.data;
|
|
61
|
+
printData(data, wantsJson, [
|
|
62
|
+
`Remote Workspace Hub: ${data.devices.length} device(s), ${data.sessions.length} session(s).`,
|
|
63
|
+
...data.devices.map(row => `${row.id} ${row.name}: ${row.online ? "online" : "offline"} (${row.roots.length} workspace root(s))`),
|
|
64
|
+
...(data.devices.length ? [] : ["No paired devices. Pair a device from the Hub dashboard."]),
|
|
65
|
+
...Object.entries(data.runtimes).map(([name, row]) => `${name}: ${row.available ? "available" : "unavailable"}${row.version ? ` (${row.version})` : ""}`),
|
|
66
|
+
]);
|
|
67
|
+
return 0;
|
|
68
|
+
}
|
|
69
|
+
if (action === "runtimes") {
|
|
70
|
+
const parsed = z.object({ runtimes }).safeParse(raw);
|
|
71
|
+
if (!parsed.success) throw new Error("Invalid runtime observation");
|
|
72
|
+
printData(parsed.data, wantsJson, Object.entries(parsed.data.runtimes).map(([name, row]) =>
|
|
73
|
+
`${name}: ${row.available ? "available" : "unavailable"}${row.version ? ` (${row.version})` : ""}${row.reason ? ` — ${row.reason}` : ""}`));
|
|
74
|
+
return 0;
|
|
75
|
+
}
|
|
76
|
+
const parsed = z.object({ sessions }).safeParse(raw);
|
|
77
|
+
if (!parsed.success) throw new Error("Invalid session observation");
|
|
78
|
+
printData(parsed.data, wantsJson, parsed.data.sessions.length
|
|
79
|
+
? parsed.data.sessions.map(row => `${row.id} ${row.profile}: ${row.status} (${row.deviceName} / ${row.rootLabel}, ${row.accessMode})`)
|
|
80
|
+
: ["No Remote Workspace sessions. Create a session from the Hub dashboard."]);
|
|
81
|
+
return 0;
|
|
82
|
+
});
|
|
83
|
+
}
|