@bitkyc08/opencodex 2.81.0 → 2.82.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/bin/ocx.mjs +166 -73
- package/gui/dist/assets/App-Ds_qL7o8.js +54 -0
- package/gui/dist/assets/{Tray-EwAOsP0S.js → Tray-BqHF5Trd.js} +1 -1
- package/gui/dist/assets/{index-Brk6F3fn.css → index-BAbcj51J.css} +1 -1
- package/gui/dist/assets/{index-RsoaAxXY.js → index-D3FBCNiP.js} +13 -13
- package/gui/dist/assets/{quota-summary-D2lN8tDm.js → quota-summary-DTBC8n7-.js} +1 -1
- package/gui/dist/index.html +2 -2
- package/package.json +1 -1
- package/src/adapters/anthropic.ts +1 -1
- package/src/adapters/openai-responses/compaction-search-history.ts +109 -0
- package/src/adapters/openai-responses/passthrough.ts +9 -4
- package/src/adapters/openai-responses/tool-output-recovery.ts +20 -0
- package/src/claude/agents-inject.ts +14 -3
- package/src/claude/context-windows.ts +19 -17
- package/src/claude/desktop-3p.ts +88 -12
- package/src/claude/desktop-profile.ts +2 -1
- package/src/claude/gateway-cache.ts +18 -1
- package/src/claude/inbound.ts +77 -3
- package/src/claude/intercept/cli-catalog.ts +3 -0
- package/src/claude/intercept/picker-ca-persistence.ts +7 -6
- package/src/claude/intercept/picker-models.ts +14 -6
- package/src/claude/intercept/settings.ts +3 -0
- package/src/claude/long-context.ts +66 -0
- package/src/claude/model-info.ts +19 -16
- package/src/claude/outbound.ts +94 -9
- package/src/claude/subagent-model.ts +40 -11
- package/src/cli/agent.ts +9 -5
- package/src/cli/aside-profile-recovery.ts +33 -0
- package/src/cli/capabilities-base.ts +5 -5
- package/src/cli/capabilities-integrations.ts +2 -2
- package/src/cli/cli-path-diagnostics.ts +132 -0
- package/src/cli/desktop-runtime-guidance.ts +65 -0
- package/src/cli/dispatch.ts +5 -0
- package/src/cli/doctor.ts +16 -3
- package/src/cli/index.ts +14 -9
- package/src/cli/integration-aside-sync.ts +2 -1
- package/src/cli/integrations.ts +16 -3
- package/src/cli/resolve.ts +25 -2
- package/src/cli/root.ts +4 -2
- package/src/cli/status.ts +64 -12
- package/src/cli/update-restart-child.ts +4 -2
- package/src/cli/update-restart-home.ts +28 -10
- package/src/cli/update-restart-service-record.ts +116 -0
- package/src/cli/update-restart-supervision.ts +96 -0
- package/src/cli/update-restart.ts +59 -13
- package/src/cli/v2.ts +27 -20
- package/src/cli/version-skew-notice.ts +77 -0
- package/src/clients/lazycodex.ts +1 -1
- package/src/clients/omo-role-models.ts +32 -7
- package/src/codex/auth-api/account-selection.ts +107 -0
- package/src/codex/auth-api/routes.ts +10 -49
- package/src/codex/auth-context.ts +20 -1
- package/src/codex/autostart-health.ts +12 -3
- package/src/codex/catalog/build-entries.ts +18 -0
- package/src/codex/catalog/bundled.ts +155 -26
- package/src/codex/catalog/combo-member.ts +3 -2
- package/src/codex/catalog/effort.ts +26 -5
- package/src/codex/catalog/gather-capture.ts +5 -0
- package/src/codex/catalog/model-hints.ts +15 -8
- package/src/codex/catalog/model-visibility.ts +3 -1
- package/src/codex/catalog/operator-tiers.ts +38 -0
- package/src/codex/catalog/provider-models.ts +43 -35
- package/src/codex/catalog/retained-sync.ts +7 -5
- package/src/codex/catalog/routed-gather.ts +15 -1
- package/src/codex/catalog-auto-refresh-sources.ts +3 -4
- package/src/codex/catalog-auto-refresh.ts +19 -0
- package/src/codex/catalog.ts +1 -1
- package/src/codex/codex-home-owner.ts +3 -0
- package/src/codex/config-write-lock.ts +333 -0
- package/src/codex/convergence.ts +2 -1
- package/src/codex/features.ts +257 -200
- package/src/codex/inject/config-write-section.ts +34 -0
- package/src/codex/inject/multi-agent-v2.ts +14 -6
- package/src/codex/inject/remove.ts +36 -11
- package/src/codex/inject/restore.ts +85 -20
- package/src/codex/inject-coordination.ts +15 -6
- package/src/codex/inject.ts +62 -20
- package/src/codex/journal.ts +62 -17
- package/src/codex/main-account-cache.ts +43 -0
- package/src/codex/paths.ts +2 -0
- package/src/codex/prepared-home.ts +18 -0
- package/src/codex/prompt-journal.ts +25 -12
- package/src/codex/prompt-layers.ts +49 -26
- package/src/codex/prompt-lock-claim.ts +134 -0
- package/src/codex/prompt-lock-evidence.ts +26 -0
- package/src/codex/prompt-lock-io.ts +16 -0
- package/src/codex/prompt-lock-owner.ts +130 -0
- package/src/codex/prompt-lock.ts +84 -53
- package/src/codex/routing/failure-window.ts +146 -0
- package/src/codex/routing/selection.ts +4 -1
- package/src/codex/routing.ts +13 -17
- package/src/codex/runtime.ts +106 -18
- package/src/codex/shim.ts +45 -19
- package/src/combos/jev-service-exchange.ts +281 -0
- package/src/combos/jev.ts +34 -220
- package/src/config/atomic-write.ts +1 -1
- package/src/config/codex-ws-reuse-setting.ts +10 -0
- package/src/config/live-reconcile.ts +17 -0
- package/src/config/load-degrade.ts +8 -0
- package/src/config/rebase-provenance.ts +11 -0
- package/src/config/schema/config-schema.ts +4 -0
- package/src/generated/compatibility-version.json +303 -171
- package/src/generated/model-metadata.ts +2 -2
- package/src/grok/inject.ts +50 -4
- package/src/grok/sync.ts +2 -1
- package/src/images/loop.ts +29 -11
- package/src/integrations/aside-profiles.ts +10 -3
- package/src/integrations/catalog-refresh.ts +18 -2
- package/src/integrations/writer.ts +9 -3
- package/src/lib/bun-path-runtime.d.mts +32 -0
- package/src/lib/bun-path-runtime.mjs +95 -0
- package/src/lib/bun-runtime-preflight.ts +140 -0
- package/src/lib/desktop-cli-handoff.d.mts +20 -0
- package/src/lib/desktop-cli-handoff.mjs +92 -0
- package/src/lib/desktop-cli-record.d.mts +29 -0
- package/src/lib/desktop-cli-record.mjs +102 -0
- package/src/lib/request-execution-budget.ts +8 -0
- package/src/lib/synced-state-location.ts +46 -6
- package/src/lib/test-home-guard.ts +87 -1
- package/src/lib/translator-budget.ts +17 -4
- package/src/lib/windows-atomic-replace.ts +38 -16
- package/src/lib/windows-elevation.ts +6 -0
- package/src/lib/windows-secret-acl.ts +92 -25
- package/src/lib/winsw.ts +2 -3
- package/src/oauth/anthropic-account-refusal.ts +39 -1
- package/src/oauth/anthropic-routing.ts +1 -1
- package/src/oauth/anthropic-send-ownership.ts +3 -3
- package/src/oauth/chatgpt.ts +113 -41
- package/src/oauth/index.ts +6 -2
- package/src/oauth/store.ts +1 -1
- package/src/providers/azure-model-metadata.ts +115 -0
- package/src/providers/derive.ts +21 -0
- package/src/providers/quota/vendor-probes-key.ts +127 -17
- package/src/providers/quota.ts +1 -1
- package/src/responses/reasoning-envelope.ts +29 -1
- package/src/responses/reasoning-replay-cache.ts +17 -1
- package/src/responses/spill-store.ts +15 -2
- package/src/responses/state/metrics.ts +8 -0
- package/src/responses/state/spill-failure.ts +12 -0
- package/src/responses/state/spill-queue.ts +12 -5
- package/src/responses/state.ts +18 -10
- package/src/responses/task-input.ts +17 -0
- package/src/server/background-lifecycle.ts +27 -0
- package/src/server/chat-completions.ts +1 -0
- package/src/server/chat-native.ts +28 -12
- package/src/server/claude-messages.ts +43 -6
- package/src/server/inbound-body-admission.ts +1 -0
- package/src/server/index/claude-intercept-lifecycle.ts +3 -1
- package/src/server/index/serve-options.ts +10 -2
- package/src/server/index/spend-ledger-lifecycle.ts +2 -1
- package/src/server/index/startup-warnings.ts +19 -0
- package/src/server/index.ts +1 -0
- package/src/server/management/agent-settings-routes.ts +93 -32
- package/src/server/management/codex-agent-role-routes.ts +4 -2
- package/src/server/management/codex-prompt-routes.ts +1 -0
- package/src/server/management/codex-role-auto-assign.ts +13 -2
- package/src/server/management/config-routes.ts +59 -8
- package/src/server/management/context.ts +2 -2
- package/src/server/management/shared.ts +3 -3
- package/src/server/messages-native-oauth.ts +9 -8
- package/src/server/messages-native.ts +49 -13
- package/src/server/messages-response-headers.ts +14 -0
- package/src/server/request-log-conversation.ts +48 -5
- package/src/server/request-log.ts +31 -2
- package/src/server/responses/adapter-continuation.ts +2 -2
- package/src/server/responses/adapter-dispatch.ts +34 -13
- package/src/server/responses/codex-ws-exchange.ts +17 -2
- package/src/server/responses/codex-ws-pool.ts +100 -13
- package/src/server/responses/codex-ws-wire.ts +9 -0
- package/src/server/responses/combo-requested-effort.ts +3 -1
- package/src/server/responses/core-codex-account.ts +22 -1
- package/src/server/responses/core-combo-native.ts +20 -3
- package/src/server/responses/core-combo.ts +22 -14
- package/src/server/responses/core-lifetime.ts +3 -36
- package/src/server/responses/core-options.ts +5 -0
- package/src/server/responses/core-replay.ts +73 -0
- package/src/server/responses/core.ts +3 -3
- package/src/server/responses/fetch-helpers.ts +26 -3
- package/src/server/responses/passthrough-delivery.ts +24 -2
- package/src/server/responses/passthrough-dispatch.ts +19 -2
- package/src/server/responses/request-prepare.ts +4 -0
- package/src/server/responses/request-send-budget.ts +112 -49
- package/src/server/responses/response-effects.ts +1 -0
- package/src/server/responses/run-turn-execution.ts +2 -0
- package/src/server/responses/sidecar-execution.ts +25 -16
- package/src/server/responses/sidecar-send-budget.ts +58 -0
- package/src/server/responses/ws-upstream.ts +19 -6
- package/src/server/startup-health-cache.ts +2 -1
- package/src/server/workflow-refusal.ts +3 -0
- package/src/service/cli.ts +20 -4
- package/src/service/desktop-command-guard.ts +32 -0
- package/src/service/desktop-startup.ts +66 -40
- package/src/service/desktop-supervision.d.mts +26 -0
- package/src/service/desktop-supervision.mjs +140 -0
- package/src/service/managing-cli.ts +1 -0
- package/src/service/orchestration.ts +46 -20
- package/src/service/repair.ts +25 -9
- package/src/service/state.ts +4 -3
- package/src/service/systemd.ts +17 -8
- package/src/service/windows-ops.ts +61 -22
- package/src/storage/policy-job.ts +5 -1
- package/src/storage/policy-worker.ts +3 -1
- package/src/storage/policy.ts +9 -0
- package/src/types/config.ts +21 -0
- package/src/types/request.ts +5 -0
- package/src/types/wire.ts +1 -0
- package/src/update/index.ts +57 -9
- package/src/update/restart-ownership.ts +10 -3
- package/src/update/runtime-ownership.d.mts +6 -0
- package/src/update/runtime-ownership.mjs +23 -7
- package/src/web-search/loop.ts +5 -2
- package/gui/dist/assets/App-7yhoys8a.js +0 -54
package/src/update/index.ts
CHANGED
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import { spawn, spawnSync } from "node:child_process";
|
|
2
|
+
import { createSupervisionLatch, inspectDesktopSupervision } from "../service/desktop-supervision.mjs";
|
|
2
3
|
import { manualUpdateFailureGuidance } from "./update-failure-guidance.mjs";
|
|
3
4
|
import { STOP_HISTORY_INCOMPLETE_EXIT_CODE } from "./stop-contract.mjs";
|
|
4
5
|
import { proxyIdentityAt } from "../server/proxy-liveness";
|
|
@@ -484,14 +485,17 @@ export async function runUpdate(): Promise<void> {
|
|
|
484
485
|
} catch { /* best-effort */ }
|
|
485
486
|
// What this update may do to the runtime. A desktop takeover vetoes both the stop and the
|
|
486
487
|
// service refresh below; see `planUpdateRuntimeHandling` for why each half is wrong.
|
|
488
|
+
const supervisionLatch = createSupervisionLatch();
|
|
489
|
+
const observeSupervision = () => supervisionLatch.observe(inspectDesktopSupervision());
|
|
487
490
|
const initialOwnership = await resolvedRuntimeOwnership();
|
|
488
491
|
const runtimePlan = planUpdateRuntimeHandling({
|
|
489
492
|
...initialOwnership,
|
|
490
493
|
serviceInstalled: serviceWasInstalled,
|
|
494
|
+
supervision: observeSupervision(),
|
|
491
495
|
});
|
|
492
496
|
if (runtimePlan.notice) console.log(runtimePlan.notice);
|
|
493
497
|
if (!runtimePlan.mayReplacePackage) {
|
|
494
|
-
console.error("⚠️ Update stopped before tray handoff, runtime stop, or package replacement because runtime
|
|
498
|
+
console.error("⚠️ Update stopped before tray handoff, runtime stop, or package replacement because runtime authority does not permit it.");
|
|
495
499
|
return 1;
|
|
496
500
|
}
|
|
497
501
|
let trayWasInstalled = false;
|
|
@@ -548,6 +552,15 @@ export async function runUpdate(): Promise<void> {
|
|
|
548
552
|
&& before?.consentGeneration === after?.consentGeneration;
|
|
549
553
|
};
|
|
550
554
|
const startProxyDirectly = async (): Promise<boolean> => {
|
|
555
|
+
const ownership = await resolvedRuntimeOwnership();
|
|
556
|
+
const supervision = observeSupervision();
|
|
557
|
+
const plan = planUpdateRuntimeHandling({ ...ownership, serviceInstalled: false, supervision });
|
|
558
|
+
if (!plan.mayStopRuntime) {
|
|
559
|
+
console.warn(supervision
|
|
560
|
+
? "OpenCodex Desktop supervises the proxy; no CLI runtime was restored."
|
|
561
|
+
: plan.notice);
|
|
562
|
+
return false;
|
|
563
|
+
}
|
|
551
564
|
if (!postUpdateLauncherUsable || !existsSync(postUpdateLauncher)) return false;
|
|
552
565
|
// An ordinary owner: a stray sibling marker would otherwise mark it before any probe.
|
|
553
566
|
const env = mutation.controlEnvironment(withoutSiblingMarker(process.env));
|
|
@@ -574,7 +587,7 @@ export async function runUpdate(): Promise<void> {
|
|
|
574
587
|
const planRecovery = async () => {
|
|
575
588
|
const current = await resolvedRuntimeOwnership();
|
|
576
589
|
return planStoppedRuntimeRecovery({
|
|
577
|
-
stopAttempted, ...current, sameOwner: sameOwner(current),
|
|
590
|
+
stopAttempted, ...current, sameOwner: sameOwner(current), supervision: observeSupervision(),
|
|
578
591
|
liveness: currentPackageRuntimeLiveness(), serviceInstalled: serviceWasInstalled,
|
|
579
592
|
launcherUsable: postUpdateLauncherUsable && existsSync(postUpdateLauncher), hadRuntimeState,
|
|
580
593
|
});
|
|
@@ -588,10 +601,17 @@ export async function runUpdate(): Promise<void> {
|
|
|
588
601
|
mutation.release();
|
|
589
602
|
recovery = await planRecovery();
|
|
590
603
|
}
|
|
591
|
-
if (recovery.
|
|
604
|
+
if (recovery.reason === "desktop-supervised") {
|
|
605
|
+
console.log("OpenCodex Desktop supervises the proxy; no CLI runtime was restored.");
|
|
606
|
+
} else if (recovery.action === "manual") {
|
|
592
607
|
console.warn(`⚠️ ${reason}; runtime recovery requires manual review (${recovery.reason}).`);
|
|
593
608
|
} else if (recovery.action === "service") {
|
|
594
609
|
const { serviceReinstallArgs, isServiceViable } = await import("../service");
|
|
610
|
+
recovery = await planRecovery();
|
|
611
|
+
if (recovery.action !== "service") {
|
|
612
|
+
console.warn("Runtime authority changed before service recovery; no CLI runtime was restored.");
|
|
613
|
+
return;
|
|
614
|
+
}
|
|
595
615
|
const service = spawnSync(process.execPath, [postUpdateLauncher, ...serviceReinstallArgs()], {
|
|
596
616
|
stdio: updateChildStdio(), windowsHide: true,
|
|
597
617
|
env: mutation.controlEnvironment({ ...process.env, OCX_BAKE_PORT: String(capturedListen.port) }),
|
|
@@ -602,7 +622,7 @@ export async function runUpdate(): Promise<void> {
|
|
|
602
622
|
mutation.reacquire();
|
|
603
623
|
const nowOwned = await resolvedRuntimeOwnership();
|
|
604
624
|
const fallback = planStoppedRuntimeRecovery({
|
|
605
|
-
stopAttempted, ...nowOwned, sameOwner: sameOwner(nowOwned),
|
|
625
|
+
stopAttempted, ...nowOwned, sameOwner: sameOwner(nowOwned), supervision: observeSupervision(),
|
|
606
626
|
liveness: currentPackageRuntimeLiveness(), serviceInstalled: false,
|
|
607
627
|
launcherUsable: postUpdateLauncherUsable && existsSync(postUpdateLauncher), hadRuntimeState,
|
|
608
628
|
});
|
|
@@ -632,6 +652,15 @@ export async function runUpdate(): Promise<void> {
|
|
|
632
652
|
// Full `ocx stop` semantics (drain, service stop, restore).
|
|
633
653
|
|
|
634
654
|
if (runtimePlan.mayStopRuntime && (serviceWasInstalled || readPid() || readRuntimePort() || pendingTeardownOutstanding())) {
|
|
655
|
+
const preStopPlan = planUpdateRuntimeHandling({
|
|
656
|
+
...(await resolvedRuntimeOwnership()),
|
|
657
|
+
serviceInstalled: serviceWasInstalled,
|
|
658
|
+
supervision: supervisionLatch.observe(inspectDesktopSupervision({ targetPid: runtimeTrusted ? livePid : undefined })),
|
|
659
|
+
});
|
|
660
|
+
if (!preStopPlan.mayStopRuntime) {
|
|
661
|
+
console.error(preStopPlan.notice);
|
|
662
|
+
return 1;
|
|
663
|
+
}
|
|
635
664
|
stopAttempted = true;
|
|
636
665
|
console.log("⏹ Stopping the running proxy before updating...");
|
|
637
666
|
const stopStdio = updateChildStdio();
|
|
@@ -701,13 +730,14 @@ export async function runUpdate(): Promise<void> {
|
|
|
701
730
|
stderr?: string | Buffer | null;
|
|
702
731
|
} | null = null;
|
|
703
732
|
let replacementRefusal: string | null = null;
|
|
704
|
-
//
|
|
705
|
-
//
|
|
706
|
-
//
|
|
733
|
+
// Re-read durable ownership and live supervision before package replacement.
|
|
734
|
+
// Desktop supervision and foreign/unknown ownership veto replacement.
|
|
735
|
+
// Plain unknown supervision preserves the existing ownership/liveness decision.
|
|
707
736
|
const replacementOwnership = await resolvedRuntimeOwnership();
|
|
708
737
|
const replacementPlan = planUpdateRuntimeHandling({
|
|
709
738
|
...replacementOwnership,
|
|
710
739
|
serviceInstalled: serviceWasInstalled,
|
|
740
|
+
supervision: observeSupervision(),
|
|
711
741
|
});
|
|
712
742
|
const replacementLiveness = currentPackageRuntimeLiveness();
|
|
713
743
|
if (replacementOwnership.subjectToken !== initialOwnership.subjectToken
|
|
@@ -786,9 +816,11 @@ export async function runUpdate(): Promise<void> {
|
|
|
786
816
|
const postInstallPlan = planUpdateRuntimeHandling({
|
|
787
817
|
...(await resolvedRuntimeOwnership()),
|
|
788
818
|
serviceInstalled: serviceWasInstalled,
|
|
819
|
+
supervision: observeSupervision(),
|
|
789
820
|
});
|
|
790
821
|
if (r.status === 0) {
|
|
791
822
|
console.log(`\n✅ Updated${latest ? ` to v${latest}` : ""}.`);
|
|
823
|
+
if (!postInstallPlan.mayStopRuntime) console.warn("Runtime authority does not permit CLI recovery; no service was refreshed or proxy started.");
|
|
792
824
|
// Re-enter through the verified active package launcher. This keeps the Codex
|
|
793
825
|
// shim, tray, service and proxy recovery paths on the same package/group that
|
|
794
826
|
// pnpm selected, including when the update changed the global link target.
|
|
@@ -819,6 +851,16 @@ export async function runUpdate(): Promise<void> {
|
|
|
819
851
|
// (spawn the fresh cli.ts so updated code writes the baked paths) so a
|
|
820
852
|
// launchd/schtasks/systemd user isn't left with the background proxy down.
|
|
821
853
|
if (postInstallPlan.mayRestoreService) {
|
|
854
|
+
const mayRefresh = async () => {
|
|
855
|
+
const ownership = await resolvedRuntimeOwnership();
|
|
856
|
+
const supervision = observeSupervision();
|
|
857
|
+
const plan = planUpdateRuntimeHandling({ ...ownership, serviceInstalled: true, supervision });
|
|
858
|
+
if (!plan.mayRestoreService) console.warn(supervision
|
|
859
|
+
? "OpenCodex Desktop supervises the proxy; CLI recovery was skipped. Use the app's updater (tray → Check for Updates)."
|
|
860
|
+
: plan.notice);
|
|
861
|
+
return plan.mayRestoreService;
|
|
862
|
+
};
|
|
863
|
+
if (!await mayRefresh()) return;
|
|
822
864
|
console.log("🔁 Refreshing the background service with the updated files...");
|
|
823
865
|
const { serviceReinstallArgs } = await import("../service");
|
|
824
866
|
const { reclaimListenPort } = await import("../server/port-reclaim");
|
|
@@ -840,6 +882,7 @@ export async function runUpdate(): Promise<void> {
|
|
|
840
882
|
const prevBake = process.env.OCX_BAKE_PORT;
|
|
841
883
|
process.env.OCX_BAKE_PORT = String(capturedListen.port);
|
|
842
884
|
try {
|
|
885
|
+
if (!await mayRefresh()) return;
|
|
843
886
|
const svcStdio = updateChildStdio();
|
|
844
887
|
const svc = spawnSync(process.execPath, [postUpdateLauncher, ...serviceReinstallArgs()], {
|
|
845
888
|
env: mutation.controlEnvironment(),
|
|
@@ -889,12 +932,17 @@ export async function runUpdate(): Promise<void> {
|
|
|
889
932
|
console.warn(` Run 'ocx service repair', then 'ocx start --port ${capturedListen.port}'.`);
|
|
890
933
|
return 1;
|
|
891
934
|
}
|
|
935
|
+
const fallbackOwnership = await resolvedRuntimeOwnership();
|
|
936
|
+
const supervision = observeSupervision();
|
|
892
937
|
const nowOwned = planUpdateRuntimeHandling({
|
|
893
|
-
...
|
|
938
|
+
...fallbackOwnership,
|
|
894
939
|
serviceInstalled: true,
|
|
940
|
+
supervision,
|
|
895
941
|
});
|
|
896
942
|
if (!nowOwned.mayStopRuntime) {
|
|
897
|
-
console.warn(
|
|
943
|
+
console.warn(supervision
|
|
944
|
+
? "OpenCodex Desktop supervises the proxy; CLI recovery was skipped. Use the app's updater (tray → Check for Updates)."
|
|
945
|
+
: nowOwned.notice ?? "⚠️ The background runtime is owned elsewhere; not starting a second proxy.");
|
|
898
946
|
return;
|
|
899
947
|
}
|
|
900
948
|
console.warn(
|
|
@@ -6,6 +6,8 @@ import {
|
|
|
6
6
|
OWNERSHIP_MUTATION_LEASE_TOKEN_ENV,
|
|
7
7
|
} from "../service/ownership-mutation-lease.mjs";
|
|
8
8
|
import { planUpdateRuntimeHandling } from "./runtime-ownership.mjs";
|
|
9
|
+
import { createSupervisionLatch, inspectDesktopSupervision } from "../service/desktop-supervision.mjs";
|
|
10
|
+
type SupervisionInspector = typeof inspectDesktopSupervision;
|
|
9
11
|
|
|
10
12
|
export type { ServiceOwnershipResolution };
|
|
11
13
|
|
|
@@ -24,6 +26,8 @@ export type { ServiceOwnershipResolution };
|
|
|
24
26
|
*/
|
|
25
27
|
export function updateRestartVeto(
|
|
26
28
|
resolve: () => ServiceOwnershipResolution = resolveServiceOwnership,
|
|
29
|
+
inspect: SupervisionInspector = inspectDesktopSupervision,
|
|
30
|
+
latch = createSupervisionLatch(),
|
|
27
31
|
): string | null {
|
|
28
32
|
const owner = resolve();
|
|
29
33
|
const plan = planUpdateRuntimeHandling({
|
|
@@ -31,6 +35,7 @@ export function updateRestartVeto(
|
|
|
31
35
|
ownershipUnknown: owner.kind === "unknown",
|
|
32
36
|
// The restart decision does not refresh the service; only the stop veto is read here.
|
|
33
37
|
serviceInstalled: false,
|
|
38
|
+
supervision: latch.observe(inspect()),
|
|
34
39
|
});
|
|
35
40
|
if (plan.mayStopRuntime) return null;
|
|
36
41
|
return plan.notice ?? "The background runtime is owned elsewhere; it was left running.";
|
|
@@ -78,7 +83,9 @@ const REACQUIRE_WAIT_MS = 10_000;
|
|
|
78
83
|
export async function runUpdateRestartWithOwnershipLease<T>(
|
|
79
84
|
resolve: (() => ServiceOwnershipResolution) | undefined,
|
|
80
85
|
restart: (lease: UpdateRestartLeaseControl) => Promise<T>,
|
|
86
|
+
inspect: SupervisionInspector = inspectDesktopSupervision,
|
|
81
87
|
): Promise<{ readonly kind: "veto"; readonly notice: string } | { readonly kind: "ran"; readonly value: T }> {
|
|
88
|
+
const latch = createSupervisionLatch();
|
|
82
89
|
let lease = acquireOwnershipMutationLease(serviceStatePaths());
|
|
83
90
|
const previous = process.env[OWNERSHIP_MUTATION_LEASE_TOKEN_ENV];
|
|
84
91
|
process.env[OWNERSHIP_MUTATION_LEASE_TOKEN_ENV] = lease.token;
|
|
@@ -107,11 +114,11 @@ export async function runUpdateRestartWithOwnershipLease<T>(
|
|
|
107
114
|
heldNow = true;
|
|
108
115
|
process.env[OWNERSHIP_MUTATION_LEASE_TOKEN_ENV] = lease.token;
|
|
109
116
|
}
|
|
110
|
-
const veto = updateRestartVeto(resolve);
|
|
117
|
+
const veto = updateRestartVeto(resolve, inspect, latch);
|
|
111
118
|
return veto ? { notice: veto, failed: false } : null;
|
|
112
119
|
};
|
|
113
120
|
try {
|
|
114
|
-
const veto = updateRestartVeto(resolve);
|
|
121
|
+
const veto = updateRestartVeto(resolve, inspect, latch);
|
|
115
122
|
return veto
|
|
116
123
|
? { kind: "veto", notice: veto }
|
|
117
124
|
: {
|
|
@@ -119,7 +126,7 @@ export async function runUpdateRestartWithOwnershipLease<T>(
|
|
|
119
126
|
value: await restart({
|
|
120
127
|
releaseForServiceManager: release,
|
|
121
128
|
reacquireForDirectStart,
|
|
122
|
-
vetoAgain: () => updateRestartVeto(resolve),
|
|
129
|
+
vetoAgain: () => updateRestartVeto(resolve, inspect, latch),
|
|
123
130
|
}),
|
|
124
131
|
};
|
|
125
132
|
} finally {
|
|
@@ -1,6 +1,10 @@
|
|
|
1
|
+
import type { SupervisionEvidence } from "../service/desktop-supervision.mjs";
|
|
2
|
+
|
|
1
3
|
export declare function planUpdateRuntimeHandling(input: {
|
|
2
4
|
ownership: { owner: string; installId: string; consentGeneration: number } | null;
|
|
3
5
|
ownershipUnknown?: boolean;
|
|
6
|
+
/** Fresh evidence or the operation's supervision latch verdict. */
|
|
7
|
+
supervision?: SupervisionEvidence | boolean;
|
|
4
8
|
serviceInstalled: boolean;
|
|
5
9
|
}): {
|
|
6
10
|
mayReplacePackage: boolean;
|
|
@@ -13,6 +17,8 @@ export declare function planStoppedRuntimeRecovery(input: {
|
|
|
13
17
|
stopAttempted: boolean;
|
|
14
18
|
ownership: { owner: string; installId: string; consentGeneration: number } | null;
|
|
15
19
|
ownershipUnknown?: boolean;
|
|
20
|
+
/** Fresh evidence or the operation's supervision latch verdict. */
|
|
21
|
+
supervision?: SupervisionEvidence | boolean;
|
|
16
22
|
sameOwner: boolean;
|
|
17
23
|
liveness: "live" | "dead" | "unknown";
|
|
18
24
|
serviceInstalled: boolean;
|
|
@@ -7,6 +7,11 @@
|
|
|
7
7
|
* situation separately is how a fix ships on one side only.
|
|
8
8
|
*/
|
|
9
9
|
|
|
10
|
+
function desktopSupervisionBlocked(supervision) {
|
|
11
|
+
return supervision === true || supervision?.kind === "desktop"
|
|
12
|
+
|| (supervision?.kind === "unknown" && supervision.desktopSeen);
|
|
13
|
+
}
|
|
14
|
+
|
|
10
15
|
/**
|
|
11
16
|
* Decide how an update treats a runtime it may not own.
|
|
12
17
|
*
|
|
@@ -21,11 +26,11 @@
|
|
|
21
26
|
* The service registration itself is untouched in every case. It is kept by decision, not by
|
|
22
27
|
* accident, so a user who later runs `ocx service install` gets their npm service back.
|
|
23
28
|
*
|
|
24
|
-
*
|
|
25
|
-
*
|
|
26
|
-
*
|
|
27
|
-
*
|
|
28
|
-
*
|
|
29
|
+
* Durable ownership and live supervision are separate. Desktop supervision denies package
|
|
30
|
+
* replacement, stop and restoration even without a claim. A latch retains that veto through
|
|
31
|
+
* inconclusive probes until a positive none. Plain unknown supervision alone keeps existing
|
|
32
|
+
* behavior; unknown durable ownership still vetoes. Explicit service install recovers a stale
|
|
33
|
+
* durable claim after Desktop has quit.
|
|
29
34
|
*
|
|
30
35
|
* The three returned flags are separate authorities, not commands. In particular, leaving
|
|
31
36
|
* a runtime running is not permission to replace the package it may be executing from.
|
|
@@ -34,10 +39,19 @@
|
|
|
34
39
|
* carries installation identity, it therefore blocks package replacement as well as stop and
|
|
35
40
|
* restoration; the notice tells a stale-marker user how to take ownership back explicitly.
|
|
36
41
|
*
|
|
37
|
-
* @param {{ ownership: { owner: string, installId: string, consentGeneration: number } | null, ownershipUnknown?: boolean, serviceInstalled: boolean }} input
|
|
42
|
+
* @param {{ ownership: { owner: string, installId: string, consentGeneration: number } | null, ownershipUnknown?: boolean, serviceInstalled: boolean, supervision?: boolean | ReturnType<typeof import('../service/desktop-supervision.mjs').inspectDesktopSupervision> }} input
|
|
38
43
|
* @returns {{ mayReplacePackage: boolean, mayStopRuntime: boolean, mayRestoreService: boolean, notice: string | null }}
|
|
39
44
|
*/
|
|
40
|
-
export function planUpdateRuntimeHandling({ ownership, ownershipUnknown = false, serviceInstalled }) {
|
|
45
|
+
export function planUpdateRuntimeHandling({ ownership, ownershipUnknown = false, serviceInstalled, supervision }) {
|
|
46
|
+
if (desktopSupervisionBlocked(supervision)) {
|
|
47
|
+
return {
|
|
48
|
+
mayReplacePackage: false,
|
|
49
|
+
mayStopRuntime: false,
|
|
50
|
+
mayRestoreService: false,
|
|
51
|
+
notice: "OpenCodex Desktop runs this proxy from its own bundle; use the app's updater (tray → Check for Updates). "
|
|
52
|
+
+ "This npm/Bun install was left unchanged; quit OpenCodex first to update it.",
|
|
53
|
+
};
|
|
54
|
+
}
|
|
41
55
|
// Unreadable, malformed or contradictory is not "nobody owns it". Reading it that way is
|
|
42
56
|
// how a permissions error reactivates the npm launcher over a consented takeover.
|
|
43
57
|
if (ownershipUnknown) {
|
|
@@ -77,6 +91,7 @@ export function planUpdateRuntimeHandling({ ownership, ownershipUnknown = false,
|
|
|
77
91
|
/** Decide recovery after this updater already stopped the prior CLI-owned runtime. */
|
|
78
92
|
export function planStoppedRuntimeRecovery({
|
|
79
93
|
stopAttempted,
|
|
94
|
+
supervision,
|
|
80
95
|
ownership,
|
|
81
96
|
ownershipUnknown = false,
|
|
82
97
|
sameOwner,
|
|
@@ -86,6 +101,7 @@ export function planStoppedRuntimeRecovery({
|
|
|
86
101
|
hadRuntimeState,
|
|
87
102
|
}) {
|
|
88
103
|
if (!stopAttempted) return { action: "none", reason: "not-stopped" };
|
|
104
|
+
if (desktopSupervisionBlocked(supervision)) return { action: "none", reason: "desktop-supervised" };
|
|
89
105
|
if (ownershipUnknown) return { action: "manual", reason: "ownership-unknown" };
|
|
90
106
|
if (!sameOwner || (ownership && ownership.owner !== "cli")) {
|
|
91
107
|
return { action: "none", reason: "ownership-transferred" };
|
package/src/web-search/loop.ts
CHANGED
|
@@ -323,7 +323,7 @@ export interface WebSearchLoopDeps {
|
|
|
323
323
|
/** Observe the exact adapter request selected for each routed-model iteration. */
|
|
324
324
|
onRequestBuilt?: (request: AdapterRequest) => void;
|
|
325
325
|
/** Request-scoped executor retains the core's selection binding across loop retries. */
|
|
326
|
-
fetchForRequest?: (request: AdapterRequest, parsed: OcxParsedRequest) => typeof globalThis.fetch;
|
|
326
|
+
fetchForRequest?: (request: AdapterRequest, parsed: OcxParsedRequest, adapter: ProviderAdapter) => typeof globalThis.fetch;
|
|
327
327
|
/** Called before each routed-model dispatch in the loop, for attempt telemetry. Same-target 429 replays pass the `rate-limit-429` recovery kind. */
|
|
328
328
|
onAttemptSend?: (recovery?: AttemptRecoveryKind) => void;
|
|
329
329
|
/**
|
|
@@ -494,7 +494,7 @@ export async function runWithWebSearch(deps: WebSearchLoopDeps): Promise<Respons
|
|
|
494
494
|
cachedRequest = request;
|
|
495
495
|
cachedAdapter = requestAdapter;
|
|
496
496
|
}
|
|
497
|
-
const requestFetch = headerDeadline.pacedFetch(deps.fetchForRequest?.(request, iterParsed) ?? routedProviderFetch);
|
|
497
|
+
const requestFetch = headerDeadline.pacedFetch(deps.fetchForRequest?.(request, iterParsed, requestAdapter) ?? routedProviderFetch);
|
|
498
498
|
let response: Response;
|
|
499
499
|
try {
|
|
500
500
|
if (requestAdapter.fetchResponse) {
|
|
@@ -507,6 +507,7 @@ export async function runWithWebSearch(deps: WebSearchLoopDeps): Promise<Respons
|
|
|
507
507
|
sendBudget: deps.incomingMeta.sendBudget,
|
|
508
508
|
onPhysicalSend: deps.incomingMeta.onPhysicalSend,
|
|
509
509
|
executor: requestFetch,
|
|
510
|
+
onRecoveryWithheld: deps.incomingMeta.onRecoveryWithheld,
|
|
510
511
|
});
|
|
511
512
|
} else {
|
|
512
513
|
response = await fetchWithResetRetry(
|
|
@@ -576,6 +577,8 @@ export async function runWithWebSearch(deps: WebSearchLoopDeps): Promise<Respons
|
|
|
576
577
|
// 429 key-failover parity with the normal routed path: rotate pool keys until one responds
|
|
577
578
|
// or the pool is exhausted (deps.on429 returns null — cooldown map guarantees termination).
|
|
578
579
|
while ((prepared.response.status === 429
|
|
580
|
+
|| (prepared.response.status === 401 && isAnthropicInstanceId(deps.incomingMeta?.providerName)
|
|
581
|
+
&& !accountRefusalOutputStarted)
|
|
579
582
|
|| (prepared.response.status === 403
|
|
580
583
|
&& (isAnthropicInstanceId(deps.incomingMeta?.providerName) || deps.incomingMeta?.providerName === "google-antigravity")
|
|
581
584
|
&& !accountRefusalOutputStarted)
|