@bitkyc08/opencodex 2.10.0 → 2.10.1
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/AGENTS_INSTALL.md +77 -0
- package/README.md +4 -10
- package/bin/ocx.mjs +71 -18
- package/gui/dist/assets/index-Cd6_PBKn.css +1 -0
- package/gui/dist/assets/index-ChZQsmBY.js +70 -0
- package/gui/dist/index.html +2 -2
- package/gui/dist/provider-icons/alibaba-color.svg +1 -1
- package/gui/dist/provider-icons/antigravity-color.svg +1 -1
- package/gui/dist/provider-icons/claude-color.svg +1 -1
- package/gui/dist/provider-icons/cline-color.svg +16 -0
- package/gui/dist/provider-icons/cloudflare-ai-gateway-color.svg +1 -1
- package/gui/dist/provider-icons/copilot-color.svg +1 -1
- package/gui/dist/provider-icons/cursor-color.svg +1 -1
- package/gui/dist/provider-icons/deepseek-color.svg +1 -1
- package/gui/dist/provider-icons/firepass-color.svg +1 -1
- package/gui/dist/provider-icons/fireworks-color.svg +1 -1
- package/gui/dist/provider-icons/gemini-color.svg +1 -1
- package/gui/dist/provider-icons/github-copilot-color.svg +1 -1
- package/gui/dist/provider-icons/gitlab-duo-color.svg +1 -1
- package/gui/dist/provider-icons/grok.svg +1 -1
- package/gui/dist/provider-icons/groq-color.svg +1 -1
- package/gui/dist/provider-icons/huggingface-color.svg +1 -1
- package/gui/dist/provider-icons/kimi-color.svg +1 -1
- package/gui/dist/provider-icons/kiro-color.svg +2 -2
- package/gui/dist/provider-icons/lm-studio-color.svg +1 -1
- package/gui/dist/provider-icons/mistral-color.svg +1 -1
- package/gui/dist/provider-icons/moonshot-color.svg +1 -1
- package/gui/dist/provider-icons/nvidia-color.svg +1 -1
- package/gui/dist/provider-icons/ollama-color.svg +1 -1
- package/gui/dist/provider-icons/openai.svg +1 -1
- package/gui/dist/provider-icons/opencode.svg +2 -1
- package/gui/dist/provider-icons/openrouter-color.svg +1 -1
- package/gui/dist/provider-icons/pi.svg +2 -2
- package/gui/dist/provider-icons/qianfan-color.svg +1 -1
- package/gui/dist/provider-icons/qwen-portal-color.svg +1 -1
- package/gui/dist/provider-icons/vercel-ai-gateway-color.svg +1 -1
- package/gui/dist/provider-icons/vllm-color.svg +1 -1
- package/gui/dist/provider-icons/xiaomi-color.svg +1 -1
- package/package.json +8 -4
- package/src/adapters/anthropic.ts +208 -14
- package/src/adapters/base.ts +16 -5
- package/src/adapters/cursor/effort-map.ts +3 -2
- package/src/adapters/cursor/framing.ts +39 -0
- package/src/adapters/cursor/live-transport.ts +105 -95
- package/src/adapters/cursor/native-exec.ts +32 -6
- package/src/adapters/cursor/protobuf-request.ts +20 -15
- package/src/adapters/cursor/request-builder.ts +21 -7
- package/src/adapters/cursor/types.ts +7 -0
- package/src/adapters/google-antigravity-replay.ts +237 -21
- package/src/adapters/google-truncation.ts +11 -0
- package/src/adapters/google.ts +50 -9
- package/src/adapters/identity.ts +39 -6
- package/src/adapters/kiro-errors.ts +11 -0
- package/src/adapters/kiro-events.ts +19 -1
- package/src/adapters/kiro-thinking.ts +10 -2
- package/src/adapters/kiro-tools.ts +10 -1
- package/src/adapters/kiro.ts +37 -11
- package/src/adapters/openai-chat.ts +284 -83
- package/src/adapters/openai-responses.ts +182 -24
- package/src/bridge.ts +177 -7
- package/src/chat/outbound.ts +78 -23
- package/src/claude/agents-inject.ts +27 -5
- package/src/claude/inbound.ts +11 -1
- package/src/claude/model-info.ts +13 -10
- package/src/claude/outbound.ts +17 -0
- package/src/cli/account-api.ts +24 -0
- package/src/cli/account-auth.ts +31 -6
- package/src/cli/account-main.ts +317 -0
- package/src/cli/account.ts +5 -0
- package/src/cli/claude.ts +2 -1
- package/src/cli/doctor.ts +93 -22
- package/src/cli/export-command.ts +26 -12
- package/src/cli/help.ts +8 -6
- package/src/cli/index.ts +56 -22
- package/src/cli/integrations.ts +84 -1
- package/src/cli/observe.ts +54 -1
- package/src/cli/opencode.ts +2 -1
- package/src/cli/provider-runtime.ts +18 -1
- package/src/cli/route-policy.ts +92 -0
- package/src/cli/runtime-api.ts +6 -3
- package/src/cli/star-prompt.ts +71 -15
- package/src/cli/status.ts +1 -1
- package/src/cli/v2.ts +36 -9
- package/src/clients/config-export.ts +687 -10
- package/src/codex/account-lifecycle.ts +30 -5
- package/src/codex/account-usability.ts +22 -2
- package/src/codex/admission.ts +255 -0
- package/src/codex/auth-api.ts +427 -140
- package/src/codex/auth-context.ts +155 -30
- package/src/codex/autostart-health.ts +8 -1
- package/src/codex/catalog/account-models.ts +62 -0
- package/src/codex/catalog/aggregation.ts +14 -1
- package/src/codex/catalog/bundled.ts +282 -32
- package/src/codex/catalog/filesystem-evidence.ts +302 -0
- package/src/codex/catalog/metadata.ts +51 -6
- package/src/codex/catalog/parsing.ts +6 -3
- package/src/codex/catalog/provider-fetch.ts +576 -41
- package/src/codex/catalog/sync.ts +505 -66
- package/src/codex/catalog-admission.ts +197 -0
- package/src/codex/catalog-write-serialization.ts +241 -0
- package/src/codex/catalog.ts +2 -1
- package/src/codex/codex-write-lock.ts +372 -0
- package/src/codex/convergence-types.ts +593 -0
- package/src/codex/convergence.ts +441 -0
- package/src/codex/desired-state.ts +177 -0
- package/src/codex/features.ts +52 -8
- package/src/codex/generation.ts +202 -0
- package/src/codex/history-job.ts +257 -0
- package/src/codex/history-lock.ts +241 -0
- package/src/codex/history-migration-guardian.ts +18 -5
- package/src/codex/history-provider.ts +9 -2
- package/src/codex/history-transition.ts +105 -0
- package/src/codex/history-worker.ts +176 -0
- package/src/codex/inject-coordination.ts +245 -0
- package/src/codex/inject.ts +605 -124
- package/src/codex/integration-record.ts +266 -0
- package/src/codex/internal/catalog-writer.ts +203 -0
- package/src/codex/internal/history-writer.ts +80 -0
- package/src/codex/journal.ts +10 -1
- package/src/codex/main-account-cache.ts +24 -0
- package/src/codex/management-convergence.ts +114 -0
- package/src/codex/native-main-admission.ts +47 -0
- package/src/codex/native-main-auth-temp.ts +187 -0
- package/src/codex/native-main-claim.ts +167 -0
- package/src/codex/native-main-lock-file.ts +158 -0
- package/src/codex/native-main-owner.ts +315 -0
- package/src/codex/native-profile-api.ts +247 -0
- package/src/codex/native-profile-manager.ts +1512 -0
- package/src/codex/native-profile-processes.ts +121 -0
- package/src/codex/native-profile-recovery.ts +99 -0
- package/src/codex/native-profile-stage-store.ts +387 -0
- package/src/codex/native-profile-startup.ts +340 -0
- package/src/codex/native-profile-store.ts +855 -0
- package/src/codex/native-profile-types.ts +120 -0
- package/src/codex/native-residue.ts +557 -0
- package/src/codex/project-config-warnings.ts +18 -4
- package/src/codex/prompt-journal.ts +311 -0
- package/src/codex/prompt-layers.ts +967 -0
- package/src/codex/prompt-lock.ts +143 -0
- package/src/codex/quota-rejection.ts +224 -0
- package/src/codex/quota.ts +86 -3
- package/src/codex/routing.ts +299 -62
- package/src/codex/runtime.ts +159 -38
- package/src/codex/shim.ts +39 -13
- package/src/codex/subagent-model-fallback.ts +73 -12
- package/src/codex/transition-state.ts +604 -0
- package/src/codex/upstream-host-health.ts +70 -0
- package/src/codex/user-identity.ts +266 -0
- package/src/codex/write-coordination.ts +114 -0
- package/src/config.ts +562 -26
- package/src/generated/jawcode-model-metadata.ts +2 -2
- package/src/grok/inject.ts +15 -4
- package/src/grok/inspect.ts +45 -0
- package/src/images/loop.ts +113 -20
- package/src/integrations/config-io.ts +151 -0
- package/src/integrations/journal.ts +315 -0
- package/src/integrations/merge.ts +135 -0
- package/src/integrations/native/ownership-preflight.ts +165 -0
- package/src/integrations/ownership.ts +111 -0
- package/src/integrations/registry.ts +101 -0
- package/src/integrations/serialize.ts +235 -0
- package/src/integrations/state.ts +290 -0
- package/src/integrations/store.ts +103 -0
- package/src/integrations/writer.ts +492 -0
- package/src/lib/bounded-body.ts +46 -8
- package/src/lib/bun-runtime.ts +110 -1
- package/src/lib/bun-stream-caps.ts +2 -1
- package/src/lib/redact.ts +407 -2
- package/src/lib/shadow-call.ts +24 -0
- package/src/lib/translator-budget.ts +10 -0
- package/src/lib/upstream-reachability.ts +91 -0
- package/src/lib/upstream-retry.ts +154 -2
- package/src/lib/windows-secret-acl.ts +212 -11
- package/src/lib/winsw.ts +9 -3
- package/src/oauth/index.ts +61 -3
- package/src/oauth/key-providers.ts +4 -0
- package/src/oauth/kiro.ts +50 -6
- package/src/oauth/store.ts +31 -6
- package/src/oauth/token-guardian.ts +9 -3
- package/src/providers/codex-capacity.ts +288 -0
- package/src/providers/derive.ts +33 -1
- package/src/providers/free-directory.ts +3 -1
- package/src/providers/key-failover.ts +71 -3
- package/src/providers/openai-sidecar.ts +64 -4
- package/src/providers/openai-virtual-models.ts +1 -0
- package/src/providers/quota.ts +334 -26
- package/src/providers/registry.ts +284 -16
- package/src/providers/xai-transport.ts +11 -4
- package/src/responses/compaction.ts +8 -1
- package/src/responses/hosted-tool-policy.ts +9 -0
- package/src/responses/parser.ts +44 -2
- package/src/responses/reasoning-envelope.ts +9 -1
- package/src/responses/reasoning-replay-cache.ts +105 -0
- package/src/responses/spill-store.ts +45 -8
- package/src/responses/state.ts +161 -17
- package/src/router.ts +302 -16
- package/src/routing/analytics.ts +377 -0
- package/src/routing/capability.ts +204 -0
- package/src/routing/cost.ts +77 -0
- package/src/routing/evaluator.ts +444 -0
- package/src/routing/health.ts +401 -0
- package/src/routing/history/cursor.ts +43 -0
- package/src/routing/history/indexer.ts +590 -0
- package/src/routing/history/schema.ts +72 -0
- package/src/routing/profile.ts +423 -0
- package/src/routing/quota.ts +124 -0
- package/src/routing/request-evidence.ts +45 -0
- package/src/routing/trace.ts +686 -0
- package/src/server/auth-cors.ts +46 -6
- package/src/server/chat-completions.ts +28 -13
- package/src/server/claude-messages.ts +23 -15
- package/src/server/gui-static.ts +39 -10
- package/src/server/images.ts +10 -1
- package/src/server/index.ts +238 -52
- package/src/server/lifecycle.ts +228 -9
- package/src/server/live.ts +14 -3
- package/src/server/management/agent-settings-routes.ts +64 -14
- package/src/server/management/combo-routes.ts +5 -5
- package/src/server/management/config-routes.ts +1 -1
- package/src/server/management/context.ts +42 -2
- package/src/server/management/integration-routes.ts +538 -0
- package/src/server/management/logs-usage-routes.ts +1 -1
- package/src/server/management/model-routes.ts +32 -113
- package/src/server/management/model-rows.ts +117 -0
- package/src/server/management/native-integration-routes.ts +587 -0
- package/src/server/management/oauth-account-routes.ts +1 -1
- package/src/server/management/provider-routes.ts +218 -117
- package/src/server/management/request-history-routes.ts +191 -0
- package/src/server/management/routing-analytics-routes.ts +74 -0
- package/src/server/management/routing-profile-routes.ts +177 -0
- package/src/server/management/shared.ts +2 -2
- package/src/server/management/sidebar-routes.ts +47 -31
- package/src/server/management/sync-response.ts +69 -0
- package/src/server/management/system-restart.ts +276 -24
- package/src/server/management/system-routes.ts +4 -0
- package/src/server/management-api.ts +84 -9
- package/src/server/management-auth.ts +43 -5
- package/src/server/relay-eager.ts +82 -42
- package/src/server/relay.ts +120 -6
- package/src/server/request-log.ts +26 -6
- package/src/server/responses/collaboration.ts +63 -8
- package/src/server/responses/compact.ts +272 -41
- package/src/server/responses/core.ts +730 -132
- package/src/server/responses/fetch-helpers.ts +15 -1
- package/src/server/responses-item-id-repair.ts +32 -3
- package/src/server/responses-json-events.ts +52 -0
- package/src/server/responses-snapshot-repair.ts +621 -0
- package/src/server/search.ts +51 -6
- package/src/server/sse-payload-rewrite.ts +89 -12
- package/src/server/startup-health-cache.ts +7 -1
- package/src/server/ws-bridge.ts +11 -17
- package/src/service-manager-probe.ts +297 -0
- package/src/service.ts +222 -32
- package/src/tray/windows-tray.ps1 +9 -0
- package/src/tray/windows.ts +15 -7
- package/src/types.ts +194 -14
- package/src/update/index.ts +13 -13
- package/src/update/job.ts +24 -21
- package/src/update/notify.ts +7 -3
- package/src/usage/cost.ts +0 -0
- package/src/usage/expected-prices.ts +129 -10
- package/src/usage/log.ts +50 -15
- package/src/usage/summary.ts +4 -4
- package/src/vision/index.ts +6 -1
- package/src/web-search/loop.ts +161 -34
- package/gui/dist/assets/index-OY43ubAq.css +0 -1
- package/gui/dist/assets/index-YwNnKZcL.js +0 -67
- package/gui/dist/provider-icons/antigravity.svg +0 -1
- package/gui/dist/provider-icons/claude.svg +0 -1
- package/gui/dist/provider-icons/copilot.svg +0 -1
- package/gui/dist/provider-icons/cursor.svg +0 -2
- package/gui/dist/provider-icons/gemini.svg +0 -1
- package/gui/dist/provider-icons/grok-color.svg +0 -1
- package/gui/dist/provider-icons/kiro.svg +0 -14
package/src/types.ts
CHANGED
|
@@ -2,6 +2,8 @@ import type { KiroOAuthMetadata } from "./oauth/types";
|
|
|
2
2
|
|
|
3
3
|
export interface OcxParsedRequest {
|
|
4
4
|
modelId: string;
|
|
5
|
+
/** Selected OpenAI API virtual-model id retained after it rewrites the upstream wire model. */
|
|
6
|
+
_openAiVirtualSelectedModelId?: string;
|
|
5
7
|
previousResponseId?: string;
|
|
6
8
|
context: OcxContext;
|
|
7
9
|
stream: boolean;
|
|
@@ -83,6 +85,12 @@ export interface OcxAssistantMessage {
|
|
|
83
85
|
phase?: OcxMessagePhase;
|
|
84
86
|
model?: string;
|
|
85
87
|
timestamp: number;
|
|
88
|
+
/**
|
|
89
|
+
* Kiro `reasoningContent.redactedContent` for THIS assistant turn — an opaque encrypted blob
|
|
90
|
+
* Kiro replays to preserve model reasoning across turns. Provider-specific and unrenderable, so
|
|
91
|
+
* it rides the message rather than a content part: any other adapter simply ignores it.
|
|
92
|
+
*/
|
|
93
|
+
kiroRedactedReasoning?: string;
|
|
86
94
|
}
|
|
87
95
|
|
|
88
96
|
export interface OcxDeveloperMessage {
|
|
@@ -252,6 +260,9 @@ export type AdapterEvent =
|
|
|
252
260
|
// opaque redacted_thinking blocks. Both must be replayed verbatim or tool-use turns 400.
|
|
253
261
|
| { type: "thinking_signature"; signature: string }
|
|
254
262
|
| { type: "redacted_thinking"; data: string }
|
|
263
|
+
// Kiro reasoning round-trip: the encrypted `redactedContent` blob for the CURRENT assistant turn.
|
|
264
|
+
// Never rendered — it only rides the reasoning item's envelope so the next request can replay it.
|
|
265
|
+
| { type: "kiro_redacted_reasoning"; data: string }
|
|
255
266
|
| { type: "reasoning_raw_delta"; text: string }
|
|
256
267
|
| { type: "tool_call_start"; id: string; name: string }
|
|
257
268
|
| { type: "tool_call_delta"; arguments: string }
|
|
@@ -528,6 +539,22 @@ export interface OcxApiKeyEntry {
|
|
|
528
539
|
createdAt: string;
|
|
529
540
|
}
|
|
530
541
|
|
|
542
|
+
/**
|
|
543
|
+
* Durable per-client intent. One key today, deliberately.
|
|
544
|
+
*
|
|
545
|
+
* A top-level `codexEnabled` would force every later client to invent an
|
|
546
|
+
* unrelated name and its own helpers; a ten-key union recreated the coupling
|
|
547
|
+
* that failed two audits, because every phase then had to touch every client's
|
|
548
|
+
* write path. A one-key object keeps the extension point without letting this
|
|
549
|
+
* phase claim ownership over a client it does not implement.
|
|
550
|
+
*/
|
|
551
|
+
export interface OcxClientIntegrationsConfig {
|
|
552
|
+
/** Durable desired state for native Codex. MISSING MEANS ON. */
|
|
553
|
+
codex?: boolean;
|
|
554
|
+
/** Durable desired state for Grok Build. MISSING MEANS ON. */
|
|
555
|
+
grok?: boolean;
|
|
556
|
+
}
|
|
557
|
+
|
|
531
558
|
export interface OcxConfig {
|
|
532
559
|
port: number;
|
|
533
560
|
/** Maximum usage-log bytes read for one management snapshot. */
|
|
@@ -541,8 +568,15 @@ export interface OcxConfig {
|
|
|
541
568
|
/** Claude Code inbound + launcher settings. */
|
|
542
569
|
claudeCode?: OcxClaudeCodeConfig;
|
|
543
570
|
/**
|
|
544
|
-
*
|
|
545
|
-
*
|
|
571
|
+
* Per-client durable intent. This phase owns only `codex`; later phases extend
|
|
572
|
+
* one key at a time rather than widening a shared union.
|
|
573
|
+
*/
|
|
574
|
+
clientIntegrations?: OcxClientIntegrationsConfig;
|
|
575
|
+
/**
|
|
576
|
+
* Up to 5 Codex-facing catalog ids to feature first. Values may be bare catalog ids,
|
|
577
|
+
* exact account-qualified "<selector>/<native-openai-model>" ids, or routed
|
|
578
|
+
* "<provider>/<model>" ids. With account selectors, one bare native choice can expand
|
|
579
|
+
* into a selector-qualified group; Codex still advertises only the first 5 visible rows.
|
|
546
580
|
*/
|
|
547
581
|
subagentModels?: string[];
|
|
548
582
|
/**
|
|
@@ -605,12 +639,17 @@ export interface OcxConfig {
|
|
|
605
639
|
*/
|
|
606
640
|
streamMode?: "auto" | "legacy-tee" | "eager-relay";
|
|
607
641
|
/**
|
|
608
|
-
* Custom override for the injected multi-agent guidance body (the text inside
|
|
609
|
-
* <multi_agent_mode> tags).
|
|
610
|
-
*
|
|
611
|
-
*
|
|
612
|
-
*
|
|
613
|
-
* the
|
|
642
|
+
* Custom override for the injected v2 multi-agent guidance body (the text inside
|
|
643
|
+
* the <multi_agent_mode> tags). After guidance is enabled and the v2 surface and
|
|
644
|
+
* catalog-state gates pass, a configured injectionModel is sufficient to render it;
|
|
645
|
+
* otherwise an eligible roster or fallback is required. Placeholders: `{{model}}` -> the
|
|
646
|
+
* effective preferred model for the request (a bare native model is account-qualified
|
|
647
|
+
* only when the request targets an explicit account selector; unresolved or ambiguous
|
|
648
|
+
* bare values become "", while unresolved explicit routed or account-qualified values
|
|
649
|
+
* remain unchanged),
|
|
650
|
+
* `{{effort}}` -> injectionEffort, `{{roster}}` -> the resolved sub-agent roster
|
|
651
|
+
* block ("" when nothing resolves), `{{fallback}}` -> the configured subagent
|
|
652
|
+
* model fallback guidance block ("" when unset).
|
|
614
653
|
*/
|
|
615
654
|
injectionPrompt?: string;
|
|
616
655
|
/**
|
|
@@ -633,10 +672,10 @@ export interface OcxConfig {
|
|
|
633
672
|
*/
|
|
634
673
|
subagentEffortCap?: string;
|
|
635
674
|
/**
|
|
636
|
-
* Models hidden from Codex
|
|
637
|
-
* from the catalog + /v1/models entirely.
|
|
638
|
-
* their
|
|
639
|
-
*
|
|
675
|
+
* Models hidden from Codex discovery without blocking direct proxy calls. Routed provider ids
|
|
676
|
+
* are excluded from the catalog + /v1/models entirely. Account-qualified native ids hide only
|
|
677
|
+
* their generated selector row and are omitted from raw /v1/models. BARE native GPT ids hide
|
|
678
|
+
* the bare row plus every generated selector row and omit that model family from raw discovery.
|
|
640
679
|
*/
|
|
641
680
|
disabledModels?: string[];
|
|
642
681
|
/** 사용자가 대시보드에서 직접 추가한 커스텀 모델 목록. */
|
|
@@ -645,7 +684,8 @@ export interface OcxConfig {
|
|
|
645
684
|
* Shadow call intercept: redirect Codex's hard-coded helper calls (title generation,
|
|
646
685
|
* commit messages, skill orchestration) to a user-chosen model. Default intercepted
|
|
647
686
|
* source models: gpt-5.4-mini (older clients) and gpt-5.6-luna (Codex 0.145.0+).
|
|
648
|
-
* Opt-in; disabled by default.
|
|
687
|
+
* Opt-in; disabled by default. Matching maintenance/helper requests are forced to low.
|
|
688
|
+
* Normal Codex turns identified by request_kind=turn are never rewritten.
|
|
649
689
|
*/
|
|
650
690
|
shadowCallIntercept?: {
|
|
651
691
|
/** When true, requests for known shadow/helper source models are rewritten to the configured model. */
|
|
@@ -754,9 +794,16 @@ export interface OcxConfig {
|
|
|
754
794
|
};
|
|
755
795
|
/** Virtual `combo/<id>` models spanning concrete provider/model targets (issue #133). */
|
|
756
796
|
combos?: Record<string, OcxComboConfig>;
|
|
797
|
+
/**
|
|
798
|
+
* Routing policy profiles (Router Intelligence, RI-04+): explicitly requested
|
|
799
|
+
* `policy/<id>` (or configured alias) models select among an explicit
|
|
800
|
+
* candidate allowlist using hard capability requirements and deterministic
|
|
801
|
+
* scoring. Existing model ids are never routed through profiles implicitly.
|
|
802
|
+
*/
|
|
803
|
+
routingProfiles?: Record<string, OcxRoutingProfileConfig>;
|
|
757
804
|
/** Background proactive token refresh ("Token Guardian"). Off by default; see OcxTokenGuardianConfig. */
|
|
758
805
|
tokenGuardian?: OcxTokenGuardianConfig;
|
|
759
|
-
/** Additional origins allowed for CORS (e.g.
|
|
806
|
+
/** Additional exact origins allowed for CORS (e.g. HTTPS or chrome-extension://<id>). Loopback origins are always allowed. */
|
|
760
807
|
corsAllowOrigins?: string[];
|
|
761
808
|
}
|
|
762
809
|
|
|
@@ -788,6 +835,65 @@ export interface OcxComboConfig {
|
|
|
788
835
|
alias?: string;
|
|
789
836
|
}
|
|
790
837
|
|
|
838
|
+
export type OcxRoutingUnknownEvidenceMode = "allow" | "penalize" | "exclude";
|
|
839
|
+
|
|
840
|
+
export interface OcxRoutingProfileCandidate {
|
|
841
|
+
provider: string;
|
|
842
|
+
model: string;
|
|
843
|
+
}
|
|
844
|
+
|
|
845
|
+
export interface OcxRoutingProfileRequirements {
|
|
846
|
+
/** Minimum model context window in tokens. */
|
|
847
|
+
minContextWindow?: number;
|
|
848
|
+
/** Minimum remaining quota headroom fraction (0..1). */
|
|
849
|
+
minQuotaHeadroom?: number;
|
|
850
|
+
tools?: boolean;
|
|
851
|
+
imageInput?: boolean;
|
|
852
|
+
structuredOutput?: boolean;
|
|
853
|
+
reasoningEffort?: string;
|
|
854
|
+
serviceTier?: string;
|
|
855
|
+
localOnly?: boolean;
|
|
856
|
+
remoteAllowed?: boolean;
|
|
857
|
+
/** Special encrypted Codex task readability (ChatGPT forward pool). */
|
|
858
|
+
encryptedCodexTasks?: boolean;
|
|
859
|
+
}
|
|
860
|
+
|
|
861
|
+
export interface OcxRoutingProfileOptimize {
|
|
862
|
+
latency?: number;
|
|
863
|
+
health?: number;
|
|
864
|
+
cost?: number;
|
|
865
|
+
quota?: number;
|
|
866
|
+
}
|
|
867
|
+
|
|
868
|
+
export interface OcxRoutingProfileLimits {
|
|
869
|
+
/** Hard per-request estimated-cost ceiling in USD. */
|
|
870
|
+
maxEstimatedCostUsd?: number;
|
|
871
|
+
}
|
|
872
|
+
|
|
873
|
+
export interface OcxRoutingProfileUnknownEvidence {
|
|
874
|
+
capability?: OcxRoutingUnknownEvidenceMode;
|
|
875
|
+
health?: OcxRoutingUnknownEvidenceMode;
|
|
876
|
+
quota?: OcxRoutingUnknownEvidenceMode;
|
|
877
|
+
cost?: OcxRoutingUnknownEvidenceMode;
|
|
878
|
+
}
|
|
879
|
+
|
|
880
|
+
export interface OcxRoutingProfileConfig {
|
|
881
|
+
/**
|
|
882
|
+
* Explicit candidate allowlist (`provider/model` refs). No implicit
|
|
883
|
+
* expansion in v1.
|
|
884
|
+
*/
|
|
885
|
+
candidates: OcxRoutingProfileCandidate[];
|
|
886
|
+
/** Optional public model name replacing the default `policy/<id>` slug. */
|
|
887
|
+
alias?: string;
|
|
888
|
+
/** Hard requirements evaluated before scoring. */
|
|
889
|
+
require?: OcxRoutingProfileRequirements;
|
|
890
|
+
/** Optimization weights; normalized deterministically. */
|
|
891
|
+
optimize?: OcxRoutingProfileOptimize;
|
|
892
|
+
limits?: OcxRoutingProfileLimits;
|
|
893
|
+
/** How unknown evidence is handled per dimension. */
|
|
894
|
+
unknownEvidence?: OcxRoutingProfileUnknownEvidence;
|
|
895
|
+
}
|
|
896
|
+
|
|
791
897
|
/**
|
|
792
898
|
* Per-provider proactive-refresh policy. The guardian only ever touches a provider whose EFFECTIVE
|
|
793
899
|
* policy is "proactive"; "lazy-only" keeps today's on-demand refresh, "disabled" forbids the
|
|
@@ -905,8 +1011,37 @@ export interface ResponsesItemIdRepairConfig {
|
|
|
905
1011
|
reasoning?: string[];
|
|
906
1012
|
/** Backfill missing `output_item.done` / terminal snapshot ids from the matching output_index. */
|
|
907
1013
|
repairMissingTerminalIds?: boolean;
|
|
1014
|
+
/**
|
|
1015
|
+
* Treat existing message/reasoning ids without the canonical `msg_`/`rs_` prefix (e.g. bare
|
|
1016
|
+
* UUIDs from DeepSeek's Responses route) as invalid and mint canonical replacements (#938).
|
|
1017
|
+
* function_call ids and call_id pairing are never rewritten.
|
|
1018
|
+
*/
|
|
1019
|
+
repairInvalidIds?: boolean;
|
|
908
1020
|
}
|
|
909
1021
|
|
|
1022
|
+
/**
|
|
1023
|
+
* Same-target 429 wait-and-retry policy (`providers.<name>.retryOn429`). When present and not
|
|
1024
|
+
* explicitly disabled, the proxy waits and replays the identical request on the same key before
|
|
1025
|
+
* any key failover. All fields optional; the runtime applies defaults (attempts=3,
|
|
1026
|
+
* intervalMs=5000, maxIntervalMs=60000, respectRetryAfter=true, enabled=true).
|
|
1027
|
+
*/
|
|
1028
|
+
export interface RateLimitRetryPolicy {
|
|
1029
|
+
/** Master switch. The presence of the object also enables the policy (default true). */
|
|
1030
|
+
enabled?: boolean;
|
|
1031
|
+
/** Extra replay attempts after the first 429 (1..20, default 3). */
|
|
1032
|
+
attempts?: number;
|
|
1033
|
+
/** Fixed wait between attempts when the upstream sends no usable Retry-After (default 5000). */
|
|
1034
|
+
intervalMs?: number;
|
|
1035
|
+
/** Cap for any single wait, including an upstream Retry-After (default 60000). */
|
|
1036
|
+
maxIntervalMs?: number;
|
|
1037
|
+
/** Prefer the upstream Retry-After header when present and parseable (default true). */
|
|
1038
|
+
respectRetryAfter?: boolean;
|
|
1039
|
+
}
|
|
1040
|
+
|
|
1041
|
+
/**
|
|
1042
|
+
* One configured provider entry. `authMode` (default `"key"`) decides whether same-target 429
|
|
1043
|
+
* retries are allowed; OAuth/forward credentials and local runtimes are never replayed.
|
|
1044
|
+
*/
|
|
910
1045
|
export interface OcxProviderConfig {
|
|
911
1046
|
adapter: string;
|
|
912
1047
|
/** Cursor MCP compatibility bounds; positive integers when configured. */
|
|
@@ -938,6 +1073,24 @@ export interface OcxProviderConfig {
|
|
|
938
1073
|
* forwarded to an upstream that cannot resolve their pair.
|
|
939
1074
|
*/
|
|
940
1075
|
statelessResponses?: boolean;
|
|
1076
|
+
/**
|
|
1077
|
+
* Whether this provider's Responses route honours the OpenAI `service_tier`
|
|
1078
|
+
* parameter. Tri-state: `true` lets fast mode inject/remove the field (an unset
|
|
1079
|
+
* fast mode preserves a caller-supplied value); `false` strips the field and
|
|
1080
|
+
* never injects, because an upstream documented as not supporting the parameter
|
|
1081
|
+
* must not receive it; absent (`undefined`) leaves the provider unclassified —
|
|
1082
|
+
* caller-supplied values are preserved untouched, and fast mode never injects.
|
|
1083
|
+
* An explicit config value always wins over the registry default.
|
|
1084
|
+
*/
|
|
1085
|
+
supportsServiceTier?: boolean;
|
|
1086
|
+
/**
|
|
1087
|
+
* Responses upstream whose native contract accepts plaintext reasoning replay
|
|
1088
|
+
* (DeepSeek documents reasoning items with plaintext content). When set, the
|
|
1089
|
+
* passthrough serializer keeps `reasoning_text` content on replayed reasoning
|
|
1090
|
+
* items instead of blanking it the way the ChatGPT backend requires; proxy-minted
|
|
1091
|
+
* `ocxr1` envelopes are still stripped because no upstream can decrypt them.
|
|
1092
|
+
*/
|
|
1093
|
+
preserveResponsesReasoningContent?: boolean;
|
|
941
1094
|
/**
|
|
942
1095
|
* Explicit opt-in for non-registry private-network destinations such as localhost, RFC1918,
|
|
943
1096
|
* link-local, or unique-local upstreams. Metadata endpoints remain blocked.
|
|
@@ -1046,10 +1199,23 @@ export interface OcxProviderConfig {
|
|
|
1046
1199
|
* Presence also advertises reasoning-summary support for that routed model.
|
|
1047
1200
|
*/
|
|
1048
1201
|
modelReasoningSummaryDelivery?: Record<string, ReasoningSummaryDelivery>;
|
|
1202
|
+
/**
|
|
1203
|
+
* Exact-model hosted tools that win collisions with Codex client tool declarations.
|
|
1204
|
+
* Use for non-forward Responses gateways that reserve a hosted tool namespace server-side.
|
|
1205
|
+
*/
|
|
1206
|
+
modelPreferHostedTools?: Record<string, string[]>;
|
|
1207
|
+
/**
|
|
1208
|
+
* Provider-local repair for Responses gateways whose lifecycle snapshots omit canonical
|
|
1209
|
+
* fields or closing events (#893). Disabled by default and applied only to client-facing
|
|
1210
|
+
* SSE/JSON; raw inspection state remains authoritative.
|
|
1211
|
+
*/
|
|
1212
|
+
responsesSnapshotRepair?: boolean;
|
|
1049
1213
|
/** Provider-wide mapping from Codex effort labels to upstream `reasoning_effort` values. */
|
|
1050
1214
|
reasoningEffortMap?: Record<string, string>;
|
|
1051
1215
|
/** Model-specific mapping from Codex effort labels to upstream `reasoning_effort` values. */
|
|
1052
1216
|
modelReasoningEffortMap?: Record<string, Record<string, string>>;
|
|
1217
|
+
/** OpenAI-compatible gateway reasoning wire shape. Default sends `reasoning_effort`. */
|
|
1218
|
+
reasoningWireFormat?: "gateway-object";
|
|
1053
1219
|
/**
|
|
1054
1220
|
* Model ids that do NOT support a reasoning/thinking parameter. The openai-chat adapter drops
|
|
1055
1221
|
* reasoning_effort for these even when Codex selects a reasoning level (e.g. xAI grok-build-0.1).
|
|
@@ -1085,6 +1251,13 @@ export interface OcxProviderConfig {
|
|
|
1085
1251
|
autoToolChoiceOnlyModels?: string[];
|
|
1086
1252
|
/** Model ids that expect prior assistant `reasoning_content` to be preserved in chat history. */
|
|
1087
1253
|
preserveReasoningContentModels?: string[];
|
|
1254
|
+
/**
|
|
1255
|
+
* Opt-in same-target 429 retry policy. Codex itself never retries 429 (it retries 5xx only,
|
|
1256
|
+
* openai/codex#30471), and single-key pools have no failover, so the proxy waits and replays
|
|
1257
|
+
* the identical request on the same key before any failover. Pre-stream only: a 429 arrives
|
|
1258
|
+
* before any response bytes are relayed, so the replay is lossless.
|
|
1259
|
+
*/
|
|
1260
|
+
retryOn429?: RateLimitRetryPolicy;
|
|
1088
1261
|
/**
|
|
1089
1262
|
* Model ids whose OpenAI-compatible chat endpoint accepts `reasoning_split: true` and returns
|
|
1090
1263
|
* thinking separately in `reasoning_content` / `reasoning_details` instead of visible content.
|
|
@@ -1104,6 +1277,13 @@ export interface OcxProviderConfig {
|
|
|
1104
1277
|
thinkingBudgetModels?: string[];
|
|
1105
1278
|
/** Anthropic-compatible gateways that need custom tool names escaped on the wire. */
|
|
1106
1279
|
escapeBuiltinToolNames?: boolean;
|
|
1280
|
+
/**
|
|
1281
|
+
* Anthropic-compatible gateways (e.g. AgentRouter) that may close the stream before
|
|
1282
|
+
* `message_stop`. With this enabled the adapter completes an otherwise-clean EOF only when
|
|
1283
|
+
* visible text was received or an open tool call has complete JSON-object arguments; all
|
|
1284
|
+
* other EOFs remain truncation errors. Absent = strict default behavior.
|
|
1285
|
+
*/
|
|
1286
|
+
anthropicEofTolerance?: boolean;
|
|
1107
1287
|
/**
|
|
1108
1288
|
* Model ids that do NOT accept image inputs. The proxy gives them "eyes" via the vision sidecar:
|
|
1109
1289
|
* attached images are described by a gpt vision model and replaced with text before the call.
|
package/src/update/index.ts
CHANGED
|
@@ -5,6 +5,7 @@ import { dirname, join } from "node:path";
|
|
|
5
5
|
import { getConfigDir, loadConfig, readPid, readRuntimePort } from "../config";
|
|
6
6
|
import { npmInvocation } from "./npm-invocation.mjs";
|
|
7
7
|
import { handoffWindowsTrayForUpdate, planWindowsTrayUpdate } from "./tray-update-plan.mjs";
|
|
8
|
+
import { withProcessRuntimeProvenance } from "../lib/bun-runtime";
|
|
8
9
|
|
|
9
10
|
/**
|
|
10
11
|
* A `codex-history-backup-*.json` surviving a stop means the native-history restore was
|
|
@@ -185,7 +186,7 @@ export async function runUpdate(): Promise<void> {
|
|
|
185
186
|
}
|
|
186
187
|
|
|
187
188
|
// Remember whether a background service manages the proxy BEFORE stopping — `ocx stop`
|
|
188
|
-
// unloads it
|
|
189
|
+
// unloads it, so a successful update must repair/restart it afterwards.
|
|
189
190
|
let serviceWasInstalled = false;
|
|
190
191
|
try {
|
|
191
192
|
const { isServiceInstalled } = await import("../service");
|
|
@@ -294,11 +295,11 @@ export async function runUpdate(): Promise<void> {
|
|
|
294
295
|
if (trayWasRunning) spawnSync(process.execPath, [process.argv[1], "tray", "start"], { stdio: "ignore", windowsHide: true });
|
|
295
296
|
}
|
|
296
297
|
}
|
|
297
|
-
// The stop above unloaded any managed service;
|
|
298
|
+
// The stop above unloaded any managed service; repair it with the NEW files
|
|
298
299
|
// (spawn the fresh cli.ts so updated code writes the baked paths) so a
|
|
299
300
|
// launchd/schtasks/systemd user isn't left with the background proxy down.
|
|
300
301
|
if (serviceWasInstalled) {
|
|
301
|
-
console.log("🔁
|
|
302
|
+
console.log("🔁 Refreshing the background service with the updated files...");
|
|
302
303
|
const { serviceReinstallArgs } = await import("../service");
|
|
303
304
|
const { reclaimListenPort } = await import("../server/port-reclaim");
|
|
304
305
|
const freed = await reclaimListenPort(capturedListen.port, capturedListen.hostname, {
|
|
@@ -309,7 +310,7 @@ export async function runUpdate(): Promise<void> {
|
|
|
309
310
|
onlyKillPids: capturedListen.oldPid != null ? [capturedListen.oldPid] : [],
|
|
310
311
|
});
|
|
311
312
|
if (!freed) {
|
|
312
|
-
console.warn(`⚠️ Port ${capturedListen.port} still busy after 30s;
|
|
313
|
+
console.warn(`⚠️ Port ${capturedListen.port} still busy after 30s; repairing service with pinned --port ${capturedListen.port} anyway (refusing to hop).`);
|
|
313
314
|
}
|
|
314
315
|
const prevBake = process.env.OCX_BAKE_PORT;
|
|
315
316
|
process.env.OCX_BAKE_PORT = String(capturedListen.port);
|
|
@@ -332,9 +333,8 @@ export async function runUpdate(): Promise<void> {
|
|
|
332
333
|
}
|
|
333
334
|
}
|
|
334
335
|
if (!serviceRefreshed || !serviceViable) {
|
|
335
|
-
//
|
|
336
|
-
//
|
|
337
|
-
// denied — or exit 0 while leaving stale/missing assets that never start
|
|
336
|
+
// A repair needs no elevation (it never calls `schtasks /create`), but it can
|
|
337
|
+
// still fail — or exit 0 while leaving stale/missing assets that never start
|
|
338
338
|
// the proxy. Fall back to a direct detached proxy start so the update
|
|
339
339
|
// never leaves the user without a running proxy — but only when the port is free.
|
|
340
340
|
if (!freed) {
|
|
@@ -344,8 +344,8 @@ export async function runUpdate(): Promise<void> {
|
|
|
344
344
|
: "⚠️ Service refresh failed and the captured port is still busy; not starting on another port.",
|
|
345
345
|
);
|
|
346
346
|
console.warn(process.platform === "win32"
|
|
347
|
-
? ` Run 'ocx service
|
|
348
|
-
: ` Run 'ocx service
|
|
347
|
+
? ` Run 'ocx service repair', then 'ocx start --port ${capturedListen.port}'.`
|
|
348
|
+
: ` Run 'ocx service repair' to see the reason, then 'ocx start --port ${capturedListen.port}'.`);
|
|
349
349
|
} else {
|
|
350
350
|
console.warn(
|
|
351
351
|
serviceRefreshed
|
|
@@ -353,18 +353,18 @@ export async function runUpdate(): Promise<void> {
|
|
|
353
353
|
: "⚠️ Service refresh failed — starting the proxy directly instead.",
|
|
354
354
|
);
|
|
355
355
|
// Elevation is a Windows-only remedy; elsewhere the refresh fails for
|
|
356
|
-
// reasons `ocx service
|
|
356
|
+
// reasons `ocx service repair` reports directly (since it now verifies
|
|
357
357
|
// the service actually serves).
|
|
358
358
|
console.warn(process.platform === "win32"
|
|
359
|
-
? " Run 'ocx service
|
|
360
|
-
: " Run 'ocx service
|
|
359
|
+
? " Run 'ocx service repair' to refresh the background service."
|
|
360
|
+
: " Run 'ocx service repair' to refresh the background service and see why it failed.");
|
|
361
361
|
const env = { ...process.env };
|
|
362
362
|
delete env.OCX_SERVICE;
|
|
363
363
|
const child = spawn(process.execPath, [process.argv[1], "start", "--port", String(capturedListen.port)], {
|
|
364
364
|
detached: true,
|
|
365
365
|
stdio: "ignore",
|
|
366
366
|
windowsHide: true,
|
|
367
|
-
env,
|
|
367
|
+
env: withProcessRuntimeProvenance(env),
|
|
368
368
|
});
|
|
369
369
|
child.unref();
|
|
370
370
|
console.log(`✅ Proxy starting on port ${capturedListen.port}.`);
|
package/src/update/job.ts
CHANGED
|
@@ -300,7 +300,9 @@ export function restartCommand(
|
|
|
300
300
|
const startArgs = pinPort
|
|
301
301
|
? [launcher, "start", "--port", String(Math.trunc(port))]
|
|
302
302
|
: [launcher, "start"];
|
|
303
|
-
|
|
303
|
+
// Default to the non-registering refresh: an update path reaching here has an already
|
|
304
|
+
// installed service, and `install` would demand elevation on Windows scheduler backends.
|
|
305
|
+
const svcArgs = serviceInstalled ? [launcher, ...(serviceArgs ?? ["service", "repair"])] : startArgs;
|
|
304
306
|
if (installer === "npm") {
|
|
305
307
|
const bin = nodeBin();
|
|
306
308
|
const args = svcArgs;
|
|
@@ -648,6 +650,8 @@ export interface RestartIo {
|
|
|
648
650
|
serviceHealthTimeoutMs?: number;
|
|
649
651
|
sleepMs?: (ms: number) => Promise<void>;
|
|
650
652
|
now?: () => number;
|
|
653
|
+
/** Test seam — defaults to process.platform so the Windows-only branch is reachable off Windows. */
|
|
654
|
+
platform?: NodeJS.Platform;
|
|
651
655
|
/** Service-mode install/reinstall command (defaults to spawnSync via runLoggedCommand). */
|
|
652
656
|
runService?: (
|
|
653
657
|
job: UpdateJobState,
|
|
@@ -782,11 +786,17 @@ async function restartAfterUpdate(
|
|
|
782
786
|
const preServiceAllow = reclaimKillAllowlist();
|
|
783
787
|
const freed = await waitFn(port, hostname, reclaimOptsFor(preServiceAllow));
|
|
784
788
|
let skipServiceInstall = false;
|
|
785
|
-
//
|
|
786
|
-
// `schtasks /create`
|
|
787
|
-
//
|
|
788
|
-
|
|
789
|
-
|
|
789
|
+
// This skip existed because the refresh ran `ocx service install`, whose Windows
|
|
790
|
+
// scheduler path always reaches `schtasks /create` — elevation the GUI update worker
|
|
791
|
+
// (OCX_SERVICE=1) never has. `service repair` rewrites the wrapper assets and
|
|
792
|
+
// restarts the EXISTING task with no `/create`, so the reason no longer applies and
|
|
793
|
+
// skipping would leave the dashboard-triggered update — the most common Windows
|
|
794
|
+
// path — with a stale service it could have refreshed.
|
|
795
|
+
//
|
|
796
|
+
// Only a caller that still passes install argv keeps the old behavior.
|
|
797
|
+
const refreshRegisters = (svcArgs ?? []).includes("install");
|
|
798
|
+
if ((io.platform ?? process.platform) === "win32" && process.env.OCX_SERVICE === "1" && refreshRegisters) {
|
|
799
|
+
updateJob(job, {}, "Skipping service re-registration from the non-elevated update worker; falling back to a direct proxy start.");
|
|
790
800
|
skipServiceInstall = true;
|
|
791
801
|
}
|
|
792
802
|
if (!freed && !skipServiceInstall) {
|
|
@@ -813,24 +823,17 @@ async function restartAfterUpdate(
|
|
|
813
823
|
const result = run(job, cmd.bin, cmd.args);
|
|
814
824
|
serviceOk = result.status === 0;
|
|
815
825
|
if (!serviceOk) {
|
|
816
|
-
//
|
|
817
|
-
//
|
|
818
|
-
//
|
|
819
|
-
//
|
|
820
|
-
//
|
|
821
|
-
//
|
|
822
|
-
//
|
|
823
|
-
// That advice is Windows-only, and on macOS/Linux it now actively misleads:
|
|
824
|
-
// `ocx service install` gained a non-zero exit for a service that registers
|
|
825
|
-
// but does not serve, so this branch fires there for a reason elevation
|
|
826
|
-
// cannot fix. Point at the command that prints the real reason instead.
|
|
826
|
+
// The refresh that just failed was `ocx service repair` (serviceReinstallArgs),
|
|
827
|
+
// which needs no elevation because it never calls `schtasks /create`. Advising
|
|
828
|
+
// `install` here would send the user to re-registration — a UAC prompt on
|
|
829
|
+
// Windows and a possible WinSW-to-scheduler backend switch — to fix a service
|
|
830
|
+
// that is already registered. Point at the same command that failed so its
|
|
831
|
+
// output explains why, on every platform.
|
|
827
832
|
updateJob(
|
|
828
833
|
job,
|
|
829
834
|
{},
|
|
830
|
-
`Service
|
|
831
|
-
+
|
|
832
|
-
? " Run 'ocx service install' as administrator to refresh the background service manager."
|
|
833
|
-
: " Run 'ocx service install' by hand to see the reason, then 'ocx service status'."),
|
|
835
|
+
`Service refresh failed (exit ${result.status ?? "?"}); falling back to a direct proxy start.`
|
|
836
|
+
+ " Run 'ocx service repair' by hand to see the reason, then 'ocx service status'.",
|
|
834
837
|
);
|
|
835
838
|
}
|
|
836
839
|
} finally {
|
package/src/update/notify.ts
CHANGED
|
@@ -83,8 +83,12 @@ function gt(a: number[], b: number[]): boolean {
|
|
|
83
83
|
|
|
84
84
|
/**
|
|
85
85
|
* Channel-aware "is latest newer than current?".
|
|
86
|
-
* - latest channel: compare maj.min.pat only;
|
|
87
|
-
* (parity with codex-rs), so stable users are not pushed onto
|
|
86
|
+
* - latest channel: compare maj.min.pat only; prerelease TARGETS are never
|
|
87
|
+
* "newer" (parity with codex-rs), so stable users are not pushed onto
|
|
88
|
+
* previews. An installed preview CURRENT compares by its maj.min.pat core,
|
|
89
|
+
* so a stable release with a strictly higher base is offered (same base is
|
|
90
|
+
* content-lateral promotion and stays not-newer, mirroring the preview
|
|
91
|
+
* channel's O3 rule).
|
|
88
92
|
* - preview channel: preview-vs-preview compares the trailing -preview.N; a
|
|
89
93
|
* stable release with a strictly higher base counts as newer (O3), while a
|
|
90
94
|
* stable release with the same base as the current preview does not.
|
|
@@ -92,7 +96,7 @@ function gt(a: number[], b: number[]): boolean {
|
|
|
92
96
|
export function isNewer(latest: string, current: string, channel: Channel): boolean {
|
|
93
97
|
if (channel === "latest") {
|
|
94
98
|
const l = parseStable(latest);
|
|
95
|
-
const c = parseStable(current);
|
|
99
|
+
const c = parseStable(current) ?? parsePreview(current)?.slice(0, 3);
|
|
96
100
|
if (!l || !c) return false;
|
|
97
101
|
return gt(l, c);
|
|
98
102
|
}
|
package/src/usage/cost.ts
CHANGED
|
Binary file
|