sneakoscope 8.1.2 → 8.2.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +96 -58
- package/crates/sks-core/Cargo.lock +1 -1
- package/crates/sks-core/Cargo.toml +1 -1
- package/dist/bin/fast-inline.js +5 -51
- package/dist/cli/command-manifest-lite.js +2 -1
- package/dist/cli/command-registry.js +2 -1
- package/dist/cli/global-mode-router.js +1 -1
- package/dist/cli/install-helpers-codex-lb-config.js +112 -914
- package/dist/cli/install-helpers-codex-lb-shared.js +3 -44
- package/dist/cli/install-helpers-install-support.js +4 -20
- package/dist/cli/install-helpers.js +36 -2716
- package/dist/cli/router.js +9 -9
- package/dist/commands/bridge-command-output.js +111 -0
- package/dist/commands/bridge.js +320 -0
- package/dist/commands/codex-app.js +39 -123
- package/dist/commands/doctor-helpers.js +380 -0
- package/dist/commands/doctor-profile.js +3 -0
- package/dist/commands/doctor.js +114 -873
- package/dist/commands/mad-sks.js +0 -4
- package/dist/config/skills-manifest.json +1 -1
- package/dist/core/agents/agent-effort-policy.js +11 -21
- package/dist/core/agents/agent-recursion-guard.js +26 -0
- package/dist/core/agents/agent-runner-codex-exec.js +7 -9
- package/dist/core/architecture-hardening/contracts/contracts.js +225 -161
- package/dist/core/architecture-hardening/state/state-service.js +49 -13
- package/dist/core/auto-review.js +15 -9
- package/dist/core/codex/codex-config-guard.js +8 -0
- package/dist/core/codex-adapter.js +8 -10
- package/dist/core/codex-app/codex-app-fast-ui-repair.js +7 -29
- package/dist/core/codex-app/codex-app-launcher.js +10 -12
- package/dist/core/codex-app/codex-app-restart.js +10 -12
- package/dist/core/codex-app/menubar/constants.js +2 -5
- package/dist/core/codex-app/menubar/global-install.js +3 -2
- package/dist/core/codex-app/menubar/installer/result.js +23 -0
- package/dist/core/codex-app/menubar/installer/runtime.js +28 -0
- package/dist/core/codex-app/menubar/installer.js +5 -96
- package/dist/core/codex-app/menubar/migration.js +1 -42
- package/dist/core/codex-app/openrouter-provider.js +0 -78
- package/dist/core/codex-app.js +97 -360
- package/dist/core/codex-control/codex-app-server-runtime-env.js +8 -28
- package/dist/core/codex-control/codex-current-image-path-real-probe.js +2 -3
- package/dist/core/codex-control/codex-current-web-search-probe.js +2 -3
- package/dist/core/codex-control/codex-sdk-adapter.js +5 -48
- package/dist/core/codex-control/codex-task-runner.js +16 -60
- package/dist/core/codex-control/desktop-bridge-launch-guard.js +227 -0
- package/dist/core/codex-exec-output-schema.js +11 -13
- package/dist/core/codex-lb/bridge-contracts.js +2 -0
- package/dist/core/codex-lb/bridge-runtime-validation/capability.js +104 -0
- package/dist/core/codex-lb/bridge-runtime-validation/catalog.js +52 -0
- package/dist/core/codex-lb/bridge-runtime-validation/shared.js +109 -0
- package/dist/core/codex-lb/bridge-runtime-validation/status.js +250 -0
- package/dist/core/codex-lb/bridge-runtime-validation.js +106 -0
- package/dist/core/codex-lb/capability-runner.js +505 -201
- package/dist/core/codex-lb/codex-lb-env.js +179 -12
- package/dist/core/codex-lb/combined-catalog/builder.js +86 -0
- package/dist/core/codex-lb/combined-catalog/contracts.js +5 -0
- package/dist/core/codex-lb/combined-catalog/normalize.js +170 -0
- package/dist/core/codex-lb/combined-catalog/persistence.js +207 -0
- package/dist/core/codex-lb/combined-catalog/shared.js +12 -0
- package/dist/core/codex-lb/combined-catalog/storage.js +171 -0
- package/dist/core/codex-lb/combined-catalog.js +12 -0
- package/dist/core/codex-lb/desktop-bridge/client.js +4 -1
- package/dist/core/codex-lb/desktop-bridge/header-policy.js +48 -63
- package/dist/core/codex-lb/desktop-bridge/http-forward.js +115 -83
- package/dist/core/codex-lb/desktop-bridge/launchd.js +20 -13
- package/dist/core/codex-lb/desktop-bridge/location-rewrite.js +4 -1
- package/dist/core/codex-lb/desktop-bridge/security.js +381 -267
- package/dist/core/codex-lb/desktop-bridge/server.js +148 -19
- package/dist/core/codex-lb/desktop-bridge/state.js +56 -70
- package/dist/core/codex-lb/desktop-bridge/types.js +6 -1
- package/dist/core/codex-lb/desktop-bridge/websocket-forward.js +281 -106
- package/dist/core/codex-lb/desktop-bridge-migration/historical-config.js +245 -0
- package/dist/core/codex-lb/desktop-bridge-migration/historical-toml.js +56 -0
- package/dist/core/codex-lb/desktop-bridge-migration/metadata.js +73 -0
- package/dist/core/codex-lb/desktop-bridge-migration/receipt.js +52 -0
- package/dist/core/codex-lb/desktop-bridge-migration/retired-runtime-cleanup.js +106 -0
- package/dist/core/codex-lb/desktop-bridge-migration/types.js +1 -0
- package/dist/core/codex-lb/desktop-bridge-migration.js +238 -0
- package/dist/core/codex-lb/desktop-controller-v3/catalog.js +257 -0
- package/dist/core/codex-lb/desktop-controller-v3/diagnostics.js +62 -0
- package/dist/core/codex-lb/desktop-controller-v3/lifecycle-commands.js +203 -0
- package/dist/core/codex-lb/desktop-controller-v3/live-probes.js +293 -0
- package/dist/core/codex-lb/desktop-controller-v3/preflight-probes.js +144 -0
- package/dist/core/codex-lb/desktop-controller-v3/provider-commands.js +182 -0
- package/dist/core/codex-lb/desktop-controller-v3/shared.js +279 -0
- package/dist/core/codex-lb/desktop-controller-v3/status.js +269 -0
- package/dist/core/codex-lb/desktop-controller-v3/types.js +1 -0
- package/dist/core/codex-lb/desktop-controller-v3/verification.js +89 -0
- package/dist/core/codex-lb/desktop-controller-v3.js +67 -0
- package/dist/core/codex-lb/desktop-controller.js +2 -1730
- package/dist/core/codex-lb/desktop-service.js +462 -627
- package/dist/core/codex-lb/migration-receipt.js +560 -118
- package/dist/core/codex-lb/probes/auxiliary-surfaces-probe.js +37 -53
- package/dist/core/codex-lb/probes/bridge-probe.js +125 -64
- package/dist/core/codex-lb/probes/catalog-probe.js +36 -136
- package/dist/core/codex-lb/probes/computer-use-probe.js +63 -39
- package/dist/core/codex-lb/probes/image-generation-probe.js +98 -41
- package/dist/core/codex-lb/probes/probe-evidence.js +32 -33
- package/dist/core/codex-lb/probes/voice-realtime-probe.js +69 -43
- package/dist/core/codex-lb/provider-credentials/configuration.js +127 -0
- package/dist/core/codex-lb/provider-credentials/locks.js +11 -0
- package/dist/core/codex-lb/provider-credentials/private-snapshot.js +28 -0
- package/dist/core/codex-lb/provider-credentials/removal.js +33 -0
- package/dist/core/codex-lb/provider-credentials/resolution.js +59 -0
- package/dist/core/codex-lb/provider-credentials/runtime.js +55 -0
- package/dist/core/codex-lb/provider-credentials/types.js +1 -0
- package/dist/core/codex-lb/provider-credentials/validation-store.js +137 -0
- package/dist/core/codex-lb/provider-credentials.js +5 -0
- package/dist/core/codex-lb/provider-registry.js +323 -0
- package/dist/core/codex-lb/provider-route-policy.js +118 -0
- package/dist/core/codex-lb/request-route-resolver.js +172 -0
- package/dist/core/codex-lb/route-index.js +148 -0
- package/dist/core/codex-lb/trusted-deep-evidence.js +158 -286
- package/dist/core/commands/basic-cli.js +1 -1
- package/dist/core/commands/check-command.js +3 -10
- package/dist/core/commands/gate-result-contract.js +10 -14
- package/dist/core/commands/intent-normalization/normalizer.js +1 -1
- package/dist/core/commands/mad-sks-command.js +2 -6
- package/dist/core/commands/release-command.js +11 -1
- package/dist/core/commands/telegram-command.js +46 -6
- package/dist/core/doctor/doctor-readiness-matrix.js +9 -7
- package/dist/core/doctor/skill-legacy-surface.js +5 -5
- package/dist/core/evidence/v2/evidence-key.js +30 -3
- package/dist/core/feature-fixtures.js +8 -1
- package/dist/core/feature-registry.js +3 -2
- package/dist/core/hooks-runtime/stop-finalization.js +11 -1
- package/dist/core/hooks-runtime/subagent-context.js +15 -1
- package/dist/core/hooks-runtime/subagent-skill-availability-contract.js +1 -1
- package/dist/core/hooks-runtime/tool-output-quarantine.js +1 -1
- package/dist/core/hooks-runtime.js +73 -87
- package/dist/core/image-ux-review/imagegen-adapter.js +108 -94
- package/dist/core/image-ux-review/real-callout-extractor.js +144 -14
- package/dist/core/imagegen/desktop-bridge-imagegen-target.js +77 -0
- package/dist/core/imagegen/imagegen-capability.js +43 -151
- package/dist/core/init/skills/filesystem.js +89 -0
- package/dist/core/init/skills/inventory.js +97 -0
- package/dist/core/init/skills/manifest.js +151 -0
- package/dist/core/init/skills.js +5 -325
- package/dist/core/init.js +0 -63
- package/dist/core/install/installed-package-smoke.js +1 -1
- package/dist/core/managed-assets/managed-assets-manifest.js +0 -1
- package/dist/core/policy/latest-version-guidance.js +15 -2
- package/dist/core/preflight/parallel-preflight-engine.js +27 -51
- package/dist/core/provider/provider-badge.js +9 -4
- package/dist/core/provider/provider-context.js +57 -107
- package/dist/core/providers/openrouter/openrouter-account.js +3 -1
- package/dist/core/providers/openrouter/openrouter-secret-store.js +91 -22
- package/dist/core/release/desktop-bridge-release-evidence.js +457 -0
- package/dist/core/release/gate-manifest.js +0 -1
- package/dist/core/release/main-push-guard.js +13 -0
- package/dist/core/release/main-push-receipt.js +11 -0
- package/dist/core/release/physical-release-gates.js +664 -61
- package/dist/core/release/publish-preflight.js +3 -3
- package/dist/core/release/release-gate-batch-runner.js +19 -6
- package/dist/core/release/release-gate-dag.js +33 -6
- package/dist/core/release/release-gate-node.js +1 -3
- package/dist/core/release/release-gate-output-contract.js +55 -0
- package/dist/core/release/release-pack-contract.js +1 -1
- package/dist/core/release/release-pack-receipt.js +209 -8
- package/dist/core/release/release-real-contract.js +1 -1
- package/dist/core/release/stage-publish.js +106 -28
- package/dist/core/retention/temp-lease.js +204 -0
- package/dist/core/retention.js +18 -195
- package/dist/core/routes.js +1 -2
- package/dist/core/safety/intent-contract/intent-contract.js +3 -3
- package/dist/core/subagents/naruto-host-credentials.js +6 -1
- package/dist/core/subagents/official-subagent-config.js +27 -9
- package/dist/core/subagents/official-subagent-runner.js +14 -31
- package/dist/core/subagents/wave-lifecycle.js +36 -8
- package/dist/core/subagents/wave-parent-guidance.js +2 -1
- package/dist/core/telegram/doctor.js +2 -2
- package/dist/core/telegram/liveness.js +10 -4
- package/dist/core/triwiki/context-graph/compiler/index.js +18 -18
- package/dist/core/update/update-migration-state/fast-mode-config.js +172 -0
- package/dist/core/update/update-migration-state/session-state-split.js +247 -0
- package/dist/core/update/update-migration-state/simple-stages.js +46 -0
- package/dist/core/update/update-migration-state.js +4 -481
- package/dist/core/version.js +1 -1
- package/dist/native/sks-menubar/Sources/OperationCoordinator.swift +28 -4
- package/dist/native/sks-menubar/Sources/OperationModels.swift +112 -2
- package/dist/native/sks-menubar/Sources/ProviderRouteExplanation.swift +21 -0
- package/dist/native/sks-menubar/Sources/ProvidersBridgeCatalog.swift +140 -0
- package/dist/native/sks-menubar/Sources/ProvidersOpenRouter.swift +107 -470
- package/dist/native/sks-menubar/Sources/ProvidersReliability.swift +27 -197
- package/dist/native/sks-menubar/Sources/ProvidersRoutingTruth.swift +335 -269
- package/dist/native/sks-menubar/Sources/ProvidersViewController.swift +233 -437
- package/dist/native/sks-menubar/Sources/RemoteCodingViewController.swift +16 -7
- package/dist/native/sks-menubar/Sources/SecureProcessEnvelope.swift +39 -9
- package/dist/native/sks-menubar/Sources/TelegramSupport.swift +56 -0
- package/dist/scripts/canonical-test-runner.js +7 -1
- package/dist/scripts/check-runtime-schemas.js +7 -2
- package/dist/scripts/codex-sdk-real-smoke-check.js +3 -1
- package/dist/scripts/desktop-bridge-capabilities-check.js +123 -0
- package/dist/scripts/{codex-lb-desktop-bridge-latency-check.js → desktop-bridge-latency-check.js} +61 -16
- package/dist/scripts/desktop-bridge-real-evidence-check.js +64 -0
- package/dist/scripts/{codex-lb-desktop-bridge-check.js → desktop-bridge-transport-check.js} +92 -155
- package/dist/scripts/desktop-bridge-transport-client.js +116 -0
- package/dist/scripts/desktop-bridge-unification-check.js +276 -0
- package/dist/scripts/doctor-fixes-codex-app-fast-ui-check.js +12 -8
- package/dist/scripts/gate-policy-audit-check.js +52 -2
- package/dist/scripts/provider-badge-context-check.js +55 -12
- package/dist/scripts/publish-preflight.js +1 -2
- package/dist/scripts/release-affected-selector-check.js +1 -2
- package/dist/scripts/release-aggressive-resource-governor-check.js +1 -1
- package/dist/scripts/release-cache-glob-hashing-check.js +1 -0
- package/dist/scripts/release-cache-version-neutral-fixture-check.js +1 -0
- package/dist/scripts/release-full-parallelism-blackbox.js +1 -1
- package/dist/scripts/release-gate-batch-runner-check.js +9 -0
- package/dist/scripts/release-gate-dag-runner-check.js +6 -0
- package/dist/scripts/release-gate-dag-runner.js +4 -2
- package/dist/scripts/release-metadata-check.js +16 -3
- package/dist/scripts/release-pack-receipt.js +29 -6
- package/dist/scripts/release-physical-gates-check.js +39 -0
- package/dist/scripts/release-real-check.js +7 -5
- package/package.json +6 -8
- package/release-gates.v2.json +156 -157
- package/runtime-required-scripts.json +11 -11
- package/schemas/codex/desktop-bridge-status-v3.schema.json +286 -0
- package/schemas/codex/desktop-capabilities-v3.schema.json +198 -0
- package/schemas/release/release-gate-node.schema.json +2 -3
- package/dist/cli/codex-lb-setup-warning-output.js +0 -17
- package/dist/cli/install-helpers-codex-lb-chain.js +0 -529
- package/dist/commands/codex-lb.js +0 -1232
- package/dist/core/architecture-hardening/migration/migration.js +0 -111
- package/dist/core/codex-app/auxiliary-oauth-policy.js +0 -36
- package/dist/core/codex-app/catalog-compat/catalog-service.js +0 -104
- package/dist/core/codex-app/child-policy/child-policy.js +0 -35
- package/dist/core/codex-app/desktop-routing-snapshot.js +0 -233
- package/dist/core/codex-app/glm-model-profile.js +0 -1
- package/dist/core/codex-app/glm-profile-installer.js +0 -191
- package/dist/core/codex-app/glm-profile-schema.js +0 -42
- package/dist/core/codex-app/multi-provider-router.js +0 -391
- package/dist/core/codex-app/openrouter-activate.js +0 -405
- package/dist/core/codex-app/openrouter-model-catalog.js +0 -217
- package/dist/core/codex-app/provider-child-policy.js +0 -64
- package/dist/core/codex-app/provider-mode.js +0 -91
- package/dist/core/codex-app/provider-session-policy.js +0 -85
- package/dist/core/codex-app/session-policy/session-pinning.js +0 -68
- package/dist/core/codex-control/codex-lb-launch-recovery.js +0 -319
- package/dist/core/codex-lb/codex-lb-setup.js +0 -293
- package/dist/core/codex-lb/codex-lb-tool-catalog.js +0 -456
- package/dist/core/codex-lb/codex-lb-tool-output-recovery.js +0 -290
- package/dist/core/codex-lb/desktop-center-credentials.js +0 -1083
- package/dist/core/codex-lb/desktop-mode.js +0 -32
- package/dist/core/codex-lb/desktop-real-evidence.js +0 -168
- package/dist/core/codex-lb/legacy-migration.js +0 -576
- package/dist/core/codex-lb/native-openai-transport/transport.js +0 -68
- package/dist/core/codex-lb/provider-routing/provider-router.js +0 -58
- package/dist/core/codex-lb/routing-truth.js +0 -327
- package/dist/core/imagegen/codex-lb-imagegen-target.js +0 -92
- package/dist/native/sks-menubar/Sources/ProvidersConnectTest.swift +0 -118
- package/dist/native/sks-menubar/Sources/ProvidersFastMode.swift +0 -17
- package/dist/native/sks-menubar/Sources/ProvidersMultiProvider.swift +0 -331
- package/dist/native/sks-menubar/Sources/ProvidersRoleModels.swift +0 -260
- package/dist/scripts/codex-lb-catalog-passthrough-check.js +0 -120
- package/dist/scripts/codex-lb-desktop-auth-invariant-check.js +0 -169
- package/dist/scripts/codex-lb-desktop-capabilities-check.js +0 -287
- package/dist/scripts/codex-lb-desktop-real-evidence-check.js +0 -123
- package/dist/scripts/codex-lb-fast-mode-truth-check.js +0 -114
- package/dist/scripts/codex-lb-fast-ui-preservation-check.js +0 -152
- package/dist/scripts/codex-lb-gpt56-fast-profile-check.js +0 -231
|
@@ -0,0 +1,245 @@
|
|
|
1
|
+
import path from 'node:path';
|
|
2
|
+
import { DESKTOP_BRIDGE_MANAGED_BASE_URL_MARKER, DESKTOP_BRIDGE_MANAGED_MARKER, DESKTOP_BRIDGE_MANAGED_MODEL_CATALOG_MARKER } from '../../../cli/install-helpers-codex-lb-config.js';
|
|
3
|
+
import { escapeRegExp } from '../../text/regex.js';
|
|
4
|
+
import { CANONICAL_OPENROUTER_ENDPOINT, HISTORICAL_DESKTOP_BRIDGE_MARKER, HISTORICAL_DESKTOP_COMPAT_MARKER, HISTORICAL_MODEL_CATALOG_MARKER, HISTORICAL_OAUTH_SELECTION_MARKER, HISTORICAL_OPENAI_ROUTING_MARKER, HISTORICAL_PROVIDER_MODE_MARKER, HISTORICAL_PROVIDER_SELECTION_MARKER, hasTomlTable, hasTopLevelMarker, isHistoricalProviderMode, secretFreeProviderEndpoint, tomlTableBoolean, tomlTableContainsCustomHeader, tomlTableString, topLevelTomlString } from './historical-toml.js';
|
|
5
|
+
export function inspectHistoricalDesktopBridgeIntent(configText) {
|
|
6
|
+
const source = String(configText || '');
|
|
7
|
+
const topLevel = source.split(/\n\s*\[/)[0] || '';
|
|
8
|
+
const markerValues = topLevel
|
|
9
|
+
.split(/\r?\n/)
|
|
10
|
+
.map((line) => line.trim())
|
|
11
|
+
.filter((line) => line.startsWith(HISTORICAL_PROVIDER_MODE_MARKER))
|
|
12
|
+
.map((line) => line.slice(HISTORICAL_PROVIDER_MODE_MARKER.length).trim());
|
|
13
|
+
const providerMode = markerValues.length === 1 && isHistoricalProviderMode(markerValues[0])
|
|
14
|
+
? markerValues[0]
|
|
15
|
+
: null;
|
|
16
|
+
const selectedProvider = topLevelTomlString(source, 'model_provider') || null;
|
|
17
|
+
const nativeBridge = hasTopLevelMarker(source, HISTORICAL_DESKTOP_BRIDGE_MARKER);
|
|
18
|
+
const compatBridge = hasTopLevelMarker(source, HISTORICAL_DESKTOP_COMPAT_MARKER);
|
|
19
|
+
const managedCodexLbSelection = hasTopLevelMarker(source, HISTORICAL_PROVIDER_SELECTION_MARKER);
|
|
20
|
+
const managedOAuthSelection = hasTopLevelMarker(source, HISTORICAL_OAUTH_SELECTION_MARKER);
|
|
21
|
+
const codexLbPresent = hasTomlTable(source, 'model_providers.codex-lb');
|
|
22
|
+
const openRouterPresent = hasTomlTable(source, 'model_providers.openrouter');
|
|
23
|
+
const combinedRouterPresent = hasTomlTable(source, 'model_providers.sks-router');
|
|
24
|
+
const blockers = [];
|
|
25
|
+
if (markerValues.length > 1)
|
|
26
|
+
blockers.push('historical_provider_marker_conflict');
|
|
27
|
+
else if (markerValues.length === 1 && !providerMode)
|
|
28
|
+
blockers.push('historical_provider_marker_invalid');
|
|
29
|
+
if (nativeBridge && compatBridge)
|
|
30
|
+
blockers.push('historical_desktop_marker_conflict');
|
|
31
|
+
if (nativeBridge && selectedProvider !== 'openai')
|
|
32
|
+
blockers.push('historical_native_bridge_selection_mismatch');
|
|
33
|
+
if (compatBridge && selectedProvider !== 'codex-lb')
|
|
34
|
+
blockers.push('historical_compat_bridge_selection_mismatch');
|
|
35
|
+
if (managedCodexLbSelection && selectedProvider !== 'codex-lb') {
|
|
36
|
+
blockers.push('historical_codex_lb_selection_marker_mismatch');
|
|
37
|
+
}
|
|
38
|
+
if (managedOAuthSelection && selectedProvider !== 'openai') {
|
|
39
|
+
blockers.push('historical_oauth_selection_marker_mismatch');
|
|
40
|
+
}
|
|
41
|
+
const knownSelections = new Set(['openai', 'codex-lb', 'openrouter', 'sks-router']);
|
|
42
|
+
if (selectedProvider && !knownSelections.has(selectedProvider)) {
|
|
43
|
+
blockers.push('historical_user_owned_provider_selection_conflict');
|
|
44
|
+
}
|
|
45
|
+
else if (selectedProvider === 'codex-lb'
|
|
46
|
+
&& !compatBridge
|
|
47
|
+
&& !managedCodexLbSelection
|
|
48
|
+
&& providerMode !== 'codex-lb') {
|
|
49
|
+
blockers.push('historical_user_owned_provider_selection_conflict');
|
|
50
|
+
}
|
|
51
|
+
else if (selectedProvider === 'openrouter' && !openRouterPresent) {
|
|
52
|
+
blockers.push('historical_openrouter_selection_table_missing');
|
|
53
|
+
}
|
|
54
|
+
else if (selectedProvider === 'sks-router' && !combinedRouterPresent) {
|
|
55
|
+
blockers.push('historical_combined_router_table_missing');
|
|
56
|
+
}
|
|
57
|
+
if (providerMode === 'chatgpt-oauth' && selectedProvider !== null && selectedProvider !== 'openai') {
|
|
58
|
+
blockers.push('historical_provider_mode_selection_mismatch');
|
|
59
|
+
}
|
|
60
|
+
if (providerMode === 'codex-lb'
|
|
61
|
+
&& selectedProvider !== null
|
|
62
|
+
&& selectedProvider !== 'openai'
|
|
63
|
+
&& selectedProvider !== 'codex-lb')
|
|
64
|
+
blockers.push('historical_provider_mode_selection_mismatch');
|
|
65
|
+
if (providerMode === 'openrouter'
|
|
66
|
+
&& selectedProvider !== null
|
|
67
|
+
&& selectedProvider !== 'openai'
|
|
68
|
+
&& selectedProvider !== 'openrouter')
|
|
69
|
+
blockers.push('historical_provider_mode_selection_mismatch');
|
|
70
|
+
const rawCodexLbEndpoint = tomlTableString(source, 'model_providers.codex-lb', 'base_url');
|
|
71
|
+
const codexLbEndpoint = codexLbPresent ? secretFreeProviderEndpoint(rawCodexLbEndpoint) : null;
|
|
72
|
+
if (codexLbPresent && !codexLbEndpoint)
|
|
73
|
+
blockers.push('historical_codex_lb_endpoint_invalid');
|
|
74
|
+
const rawOpenRouterEndpoint = tomlTableString(source, 'model_providers.openrouter', 'base_url');
|
|
75
|
+
const openRouterEndpoint = rawOpenRouterEndpoint === CANONICAL_OPENROUTER_ENDPOINT
|
|
76
|
+
? CANONICAL_OPENROUTER_ENDPOINT
|
|
77
|
+
: null;
|
|
78
|
+
if (openRouterPresent && !openRouterEndpoint)
|
|
79
|
+
blockers.push('historical_openrouter_endpoint_not_canonical');
|
|
80
|
+
if ((nativeBridge || compatBridge || managedCodexLbSelection || providerMode === 'codex-lb') && !codexLbPresent) {
|
|
81
|
+
blockers.push('historical_codex_lb_table_missing');
|
|
82
|
+
}
|
|
83
|
+
if ((selectedProvider === 'openrouter' || providerMode === 'openrouter') && !openRouterPresent) {
|
|
84
|
+
blockers.push('historical_openrouter_table_missing');
|
|
85
|
+
}
|
|
86
|
+
const codexLbTransport = codexLbPresent
|
|
87
|
+
? compatBridge
|
|
88
|
+
|| tomlTableBoolean(source, 'model_providers.codex-lb', 'requires_openai_auth') === true
|
|
89
|
+
|| tomlTableContainsCustomHeader(source, 'model_providers.codex-lb')
|
|
90
|
+
? 'x-codex-lb-api-key'
|
|
91
|
+
: 'authorization-bearer'
|
|
92
|
+
: null;
|
|
93
|
+
let defaultProvider = null;
|
|
94
|
+
if (providerMode === 'codex-lb' || nativeBridge || compatBridge || selectedProvider === 'codex-lb') {
|
|
95
|
+
defaultProvider = 'codex-lb';
|
|
96
|
+
}
|
|
97
|
+
else if (providerMode === 'openrouter' || selectedProvider === 'openrouter') {
|
|
98
|
+
defaultProvider = 'openrouter';
|
|
99
|
+
}
|
|
100
|
+
const uniqueBlockers = [...new Set(blockers)];
|
|
101
|
+
const usable = uniqueBlockers.length === 0;
|
|
102
|
+
return {
|
|
103
|
+
schema: 'sks.desktop-bridge-historical-intent.v1',
|
|
104
|
+
blockers: uniqueBlockers,
|
|
105
|
+
providers: {
|
|
106
|
+
'codex-lb': {
|
|
107
|
+
present: codexLbPresent,
|
|
108
|
+
enabled: usable && codexLbPresent,
|
|
109
|
+
endpoint_url: codexLbEndpoint,
|
|
110
|
+
auth_transport: codexLbTransport
|
|
111
|
+
},
|
|
112
|
+
openrouter: {
|
|
113
|
+
present: openRouterPresent,
|
|
114
|
+
enabled: usable && openRouterPresent,
|
|
115
|
+
endpoint_url: openRouterEndpoint,
|
|
116
|
+
auth_transport: openRouterPresent ? 'openrouter-bearer' : null
|
|
117
|
+
}
|
|
118
|
+
},
|
|
119
|
+
default_provider_id: usable ? defaultProvider : null
|
|
120
|
+
};
|
|
121
|
+
}
|
|
122
|
+
export function prepareHistoricalConfigForDesktopBridgeWriter(text, state) {
|
|
123
|
+
const source = String(text || '');
|
|
124
|
+
if ([
|
|
125
|
+
DESKTOP_BRIDGE_MANAGED_MARKER,
|
|
126
|
+
DESKTOP_BRIDGE_MANAGED_BASE_URL_MARKER,
|
|
127
|
+
DESKTOP_BRIDGE_MANAGED_MODEL_CATALOG_MARKER
|
|
128
|
+
].every((marker) => hasTopLevelMarker(source, marker)))
|
|
129
|
+
return source;
|
|
130
|
+
const historicalMarkers = historicalManagedMarkers();
|
|
131
|
+
const hasHistoricalMarker = historicalMarkers.some((marker) => hasTopLevelMarker(source, marker));
|
|
132
|
+
const hasHistoricalMode = topLevelLines(source).some((line) => line.startsWith(HISTORICAL_PROVIDER_MODE_MARKER));
|
|
133
|
+
const codexLbSelectionOwned = state.model_provider === 'codex-lb'
|
|
134
|
+
&& (hasHistoricalMarker || state.provider_mode === 'codex-lb');
|
|
135
|
+
const knownThirdPartySelection = state.model_provider === 'openrouter' || state.model_provider === 'sks-router';
|
|
136
|
+
const historicalOpenAiSelection = state.model_provider === 'openai' && (hasHistoricalMarker || hasHistoricalMode);
|
|
137
|
+
let next = source;
|
|
138
|
+
if (codexLbSelectionOwned || knownThirdPartySelection || historicalOpenAiSelection) {
|
|
139
|
+
next = removeTopLevelKey(next, 'model_provider');
|
|
140
|
+
}
|
|
141
|
+
if (hasTopLevelMarker(source, HISTORICAL_DESKTOP_BRIDGE_MARKER)
|
|
142
|
+
|| hasTopLevelMarker(source, HISTORICAL_OPENAI_ROUTING_MARKER))
|
|
143
|
+
next = removeTopLevelKey(next, 'openai_base_url');
|
|
144
|
+
const historicalCatalog = state.catalog_path || '';
|
|
145
|
+
const historicalCatalogOwned = hasTopLevelMarker(source, HISTORICAL_MODEL_CATALOG_MARKER)
|
|
146
|
+
|| ['sks-codex-lb-tool-catalog.json', 'sks-openrouter-catalog.json', 'opencodex-catalog.json']
|
|
147
|
+
.includes(path.basename(historicalCatalog));
|
|
148
|
+
if (historicalCatalogOwned)
|
|
149
|
+
next = removeTopLevelKey(next, 'model_catalog_json');
|
|
150
|
+
for (const marker of historicalMarkers)
|
|
151
|
+
next = removeTopLevelExactLine(next, marker);
|
|
152
|
+
return removeTopLevelLinesWithPrefix(next, HISTORICAL_PROVIDER_MODE_MARKER);
|
|
153
|
+
}
|
|
154
|
+
export function parseHistoricalProviderConfig(text) {
|
|
155
|
+
const source = String(text || '');
|
|
156
|
+
const topLevel = source.split(/\n\s*\[/)[0] || '';
|
|
157
|
+
const markerValues = topLevel
|
|
158
|
+
.split(/\r?\n/)
|
|
159
|
+
.map((line) => line.trim())
|
|
160
|
+
.filter((line) => line.startsWith(HISTORICAL_PROVIDER_MODE_MARKER))
|
|
161
|
+
.map((line) => line.slice(HISTORICAL_PROVIDER_MODE_MARKER.length).trim());
|
|
162
|
+
const providerMode = markerValues.length === 1 && isHistoricalProviderMode(markerValues[0])
|
|
163
|
+
? markerValues[0]
|
|
164
|
+
: null;
|
|
165
|
+
const modelProvider = topLevelTomlString(source, 'model_provider') || null;
|
|
166
|
+
const catalogPath = topLevelTomlString(source, 'model_catalog_json') || null;
|
|
167
|
+
const markers = historicalManagedMarkers().filter((marker) => hasTopLevelMarker(source, marker));
|
|
168
|
+
const migratedProfiles = new Set();
|
|
169
|
+
if (providerMode === 'codex-lb'
|
|
170
|
+
|| modelProvider === 'codex-lb'
|
|
171
|
+
|| hasTomlTable(source, 'model_providers.codex-lb')
|
|
172
|
+
|| markers.includes(HISTORICAL_DESKTOP_COMPAT_MARKER))
|
|
173
|
+
migratedProfiles.add('codex-lb');
|
|
174
|
+
if (providerMode === 'openrouter'
|
|
175
|
+
|| modelProvider === 'openrouter'
|
|
176
|
+
|| hasTomlTable(source, 'model_providers.openrouter'))
|
|
177
|
+
migratedProfiles.add('openrouter');
|
|
178
|
+
if (modelProvider === 'sks-router' || hasTomlTable(source, 'model_providers.sks-router')) {
|
|
179
|
+
if (hasTomlTable(source, 'model_providers.codex-lb'))
|
|
180
|
+
migratedProfiles.add('codex-lb');
|
|
181
|
+
if (hasTomlTable(source, 'model_providers.openrouter'))
|
|
182
|
+
migratedProfiles.add('openrouter');
|
|
183
|
+
}
|
|
184
|
+
const blockers = [];
|
|
185
|
+
if (markerValues.length > 1)
|
|
186
|
+
blockers.push('historical_provider_marker_conflict');
|
|
187
|
+
else if (markerValues.length === 1 && !providerMode)
|
|
188
|
+
blockers.push('historical_provider_marker_invalid');
|
|
189
|
+
const desktopMode = markers.includes(HISTORICAL_DESKTOP_COMPAT_MARKER)
|
|
190
|
+
? 'desktop-dual-auth-compat'
|
|
191
|
+
: markers.includes(HISTORICAL_DESKTOP_BRIDGE_MARKER)
|
|
192
|
+
? 'desktop-native-bridge'
|
|
193
|
+
: modelProvider === 'codex-lb'
|
|
194
|
+
? 'cli-provider'
|
|
195
|
+
: null;
|
|
196
|
+
const gatewayAuthTransport = markers.includes(HISTORICAL_DESKTOP_COMPAT_MARKER)
|
|
197
|
+
|| tomlTableBoolean(source, 'model_providers.codex-lb', 'requires_openai_auth') === true
|
|
198
|
+
? 'x-codex-lb-api-key'
|
|
199
|
+
: hasTomlTable(source, 'model_providers.codex-lb')
|
|
200
|
+
? 'authorization-bearer'
|
|
201
|
+
: null;
|
|
202
|
+
return {
|
|
203
|
+
desktop_mode: desktopMode,
|
|
204
|
+
provider_mode: providerMode,
|
|
205
|
+
model_provider: modelProvider,
|
|
206
|
+
catalog_path: catalogPath,
|
|
207
|
+
migrated_profiles: [...migratedProfiles].sort(),
|
|
208
|
+
gateway_auth_transport: gatewayAuthTransport,
|
|
209
|
+
blockers
|
|
210
|
+
};
|
|
211
|
+
}
|
|
212
|
+
function historicalManagedMarkers() {
|
|
213
|
+
return [
|
|
214
|
+
HISTORICAL_DESKTOP_BRIDGE_MARKER,
|
|
215
|
+
HISTORICAL_DESKTOP_COMPAT_MARKER,
|
|
216
|
+
HISTORICAL_PROVIDER_SELECTION_MARKER,
|
|
217
|
+
HISTORICAL_OAUTH_SELECTION_MARKER,
|
|
218
|
+
HISTORICAL_OPENAI_ROUTING_MARKER,
|
|
219
|
+
HISTORICAL_MODEL_CATALOG_MARKER
|
|
220
|
+
];
|
|
221
|
+
}
|
|
222
|
+
function topLevelLines(text) {
|
|
223
|
+
const topLevel = String(text || '').split(/\n\s*\[/)[0] || '';
|
|
224
|
+
return topLevel.split(/\r?\n/).map((line) => line.trim());
|
|
225
|
+
}
|
|
226
|
+
function removeTopLevelKey(text, key) {
|
|
227
|
+
const pattern = new RegExp(`^\\s*${escapeRegExp(key)}\\s*=`);
|
|
228
|
+
return filterTopLevelLines(text, (line) => !pattern.test(line));
|
|
229
|
+
}
|
|
230
|
+
function removeTopLevelExactLine(text, target) {
|
|
231
|
+
return filterTopLevelLines(text, (line) => line.trim() !== target);
|
|
232
|
+
}
|
|
233
|
+
function removeTopLevelLinesWithPrefix(text, prefix) {
|
|
234
|
+
return filterTopLevelLines(text, (line) => !line.trim().startsWith(prefix));
|
|
235
|
+
}
|
|
236
|
+
function filterTopLevelLines(text, keep) {
|
|
237
|
+
const lines = String(text || '').split('\n');
|
|
238
|
+
const firstTable = lines.findIndex((line) => /^\s*\[/.test(line));
|
|
239
|
+
const end = firstTable === -1 ? lines.length : firstTable;
|
|
240
|
+
return lines
|
|
241
|
+
.filter((line, index) => index >= end || keep(line))
|
|
242
|
+
.join('\n')
|
|
243
|
+
.replace(/^\n+/, '')
|
|
244
|
+
.replace(/\n{3,}/g, '\n\n');
|
|
245
|
+
}
|
|
@@ -0,0 +1,56 @@
|
|
|
1
|
+
import { escapeRegExp } from '../../text/regex.js';
|
|
2
|
+
export const HISTORICAL_PROVIDER_MODE_MARKER = '# sks-managed-provider-mode:';
|
|
3
|
+
export const HISTORICAL_DESKTOP_BRIDGE_MARKER = '# sks-codex-lb-managed-desktop-bridge';
|
|
4
|
+
export const HISTORICAL_DESKTOP_COMPAT_MARKER = '# sks-codex-lb-managed-desktop-compat';
|
|
5
|
+
export const HISTORICAL_PROVIDER_SELECTION_MARKER = '# sks-codex-lb-managed-provider-selection';
|
|
6
|
+
export const HISTORICAL_OAUTH_SELECTION_MARKER = '# sks-codex-lb-managed-oauth-selection';
|
|
7
|
+
export const HISTORICAL_OPENAI_ROUTING_MARKER = '# sks-codex-lb-managed-openai-base-url';
|
|
8
|
+
export const HISTORICAL_MODEL_CATALOG_MARKER = '# sks-codex-lb-managed-model-catalog';
|
|
9
|
+
export const CANONICAL_OPENROUTER_ENDPOINT = 'https://openrouter.ai/api/v1';
|
|
10
|
+
export function isHistoricalProviderMode(value) {
|
|
11
|
+
return value === 'chatgpt-oauth' || value === 'codex-lb' || value === 'openrouter';
|
|
12
|
+
}
|
|
13
|
+
export function topLevelTomlString(text, key) {
|
|
14
|
+
const topLevel = String(text || '').split(/\n\s*\[/)[0] || '';
|
|
15
|
+
return topLevel.match(new RegExp(`(?:^|\\n)\\s*${escapeRegExp(key)}\\s*=\\s*"([^"]+)"\\s*(?:#.*)?(?=\\n|$)`))?.[1] || '';
|
|
16
|
+
}
|
|
17
|
+
export function hasTopLevelMarker(text, marker) {
|
|
18
|
+
const topLevel = String(text || '').split(/\n\s*\[/)[0] || '';
|
|
19
|
+
return topLevel.split(/\r?\n/).some((line) => line.trim() === marker);
|
|
20
|
+
}
|
|
21
|
+
export function hasTomlTable(text, table) {
|
|
22
|
+
return new RegExp(`(?:^|\\n)\\s*\\[${escapeRegExp(table)}\\]\\s*(?=\\n|$)`).test(text);
|
|
23
|
+
}
|
|
24
|
+
export function tomlTableString(text, table, key) {
|
|
25
|
+
const block = tomlTableBlock(text, table);
|
|
26
|
+
return block.match(new RegExp(`(?:^|\\n)\\s*${escapeRegExp(key)}\\s*=\\s*"([^"]+)"\\s*(?:#.*)?(?=\\n|$)`))?.[1] || null;
|
|
27
|
+
}
|
|
28
|
+
export function tomlTableBoolean(text, table, key) {
|
|
29
|
+
const block = tomlTableBlock(text, table);
|
|
30
|
+
const value = block.match(new RegExp(`(?:^|\\n)\\s*${escapeRegExp(key)}\\s*=\\s*(true|false)\\s*(?:#.*)?(?=\\n|$)`))?.[1];
|
|
31
|
+
return value === 'true' ? true : value === 'false' ? false : null;
|
|
32
|
+
}
|
|
33
|
+
export function tomlTableContainsCustomHeader(text, table) {
|
|
34
|
+
return /(?:^|[\s"'{,])x-codex-lb-api-key(?:[\s"'}=,]|$)/i.test(tomlTableBlock(text, table));
|
|
35
|
+
}
|
|
36
|
+
function tomlTableBlock(text, table) {
|
|
37
|
+
return String(text || '').match(new RegExp(`(?:^|\\n)\\s*\\[${escapeRegExp(table)}\\]([\\s\\S]*?)(?=\\n\\s*\\[[^\\]]+\\]|\\s*$)`))?.[1] || '';
|
|
38
|
+
}
|
|
39
|
+
export function secretFreeProviderEndpoint(value) {
|
|
40
|
+
if (!value)
|
|
41
|
+
return null;
|
|
42
|
+
try {
|
|
43
|
+
const parsed = new URL(value);
|
|
44
|
+
if ((parsed.protocol !== 'http:' && parsed.protocol !== 'https:')
|
|
45
|
+
|| !parsed.hostname
|
|
46
|
+
|| parsed.username
|
|
47
|
+
|| parsed.password
|
|
48
|
+
|| parsed.search
|
|
49
|
+
|| parsed.hash)
|
|
50
|
+
return null;
|
|
51
|
+
return value;
|
|
52
|
+
}
|
|
53
|
+
catch {
|
|
54
|
+
return null;
|
|
55
|
+
}
|
|
56
|
+
}
|
|
@@ -0,0 +1,73 @@
|
|
|
1
|
+
import { createHash } from 'node:crypto';
|
|
2
|
+
import fsp from 'node:fs/promises';
|
|
3
|
+
import path from 'node:path';
|
|
4
|
+
import { ensureDir } from '../../fsx.js';
|
|
5
|
+
export function validateMetadataUpdates(updates, protectedPaths) {
|
|
6
|
+
const seen = new Set();
|
|
7
|
+
for (const update of updates) {
|
|
8
|
+
const filePath = path.resolve(String(update.path || ''));
|
|
9
|
+
if (!update.path || !path.isAbsolute(update.path)) {
|
|
10
|
+
throw new Error('desktop_bridge_metadata_path_invalid');
|
|
11
|
+
}
|
|
12
|
+
if (filePath === path.resolve(protectedPaths.configPath)) {
|
|
13
|
+
throw new Error('desktop_bridge_metadata_config_path_forbidden');
|
|
14
|
+
}
|
|
15
|
+
if (filePath === path.resolve(protectedPaths.authPath) || metadataPathLooksSecret(filePath)) {
|
|
16
|
+
throw new Error('desktop_bridge_metadata_secret_path_forbidden');
|
|
17
|
+
}
|
|
18
|
+
const expectedPath = canonicalMetadataPath(protectedPaths.home, update.kind);
|
|
19
|
+
if (filePath !== expectedPath) {
|
|
20
|
+
throw new Error(`desktop_bridge_metadata_path_not_canonical:${update.kind}`);
|
|
21
|
+
}
|
|
22
|
+
if (seen.has(filePath))
|
|
23
|
+
throw new Error('desktop_bridge_metadata_path_duplicate');
|
|
24
|
+
seen.add(filePath);
|
|
25
|
+
if (!['bridge_settings', 'provider_registry', 'catalog_binding', 'route_policy', 'launchd_state'].includes(update.kind)) {
|
|
26
|
+
throw new Error('desktop_bridge_metadata_kind_invalid');
|
|
27
|
+
}
|
|
28
|
+
if (typeof update.text !== 'string')
|
|
29
|
+
throw new Error('desktop_bridge_metadata_text_invalid');
|
|
30
|
+
}
|
|
31
|
+
}
|
|
32
|
+
export function normalizedMetadataUpdates(updates) {
|
|
33
|
+
return updates.map((update) => ({ ...update, path: path.resolve(update.path) }));
|
|
34
|
+
}
|
|
35
|
+
export function sha256(value) {
|
|
36
|
+
return createHash('sha256').update(value).digest('hex');
|
|
37
|
+
}
|
|
38
|
+
export async function writeBufferAtomic(filePath, bytes) {
|
|
39
|
+
await ensureDir(path.dirname(filePath));
|
|
40
|
+
const tempPath = `${filePath}.${process.pid}.${Date.now().toString(36)}.tmp`;
|
|
41
|
+
try {
|
|
42
|
+
await fsp.writeFile(tempPath, bytes, { mode: 0o600, flag: 'wx' });
|
|
43
|
+
await fsp.rename(tempPath, filePath);
|
|
44
|
+
await fsp.chmod(filePath, 0o600);
|
|
45
|
+
}
|
|
46
|
+
catch (error) {
|
|
47
|
+
await fsp.rm(tempPath, { force: true }).catch(() => undefined);
|
|
48
|
+
throw error;
|
|
49
|
+
}
|
|
50
|
+
}
|
|
51
|
+
function canonicalMetadataPath(home, kind) {
|
|
52
|
+
const resolvedHome = path.resolve(home);
|
|
53
|
+
if (kind === 'bridge_settings') {
|
|
54
|
+
return path.join(resolvedHome, '.codex', 'sks', 'desktop-bridge-settings.json');
|
|
55
|
+
}
|
|
56
|
+
if (kind === 'provider_registry') {
|
|
57
|
+
return path.join(resolvedHome, '.codex', 'sks', 'sks-bridge-provider-registry.json');
|
|
58
|
+
}
|
|
59
|
+
if (kind === 'catalog_binding') {
|
|
60
|
+
return path.join(resolvedHome, '.codex', 'sks', 'sks-bridge-active-generation.json');
|
|
61
|
+
}
|
|
62
|
+
if (kind === 'route_policy') {
|
|
63
|
+
return path.join(resolvedHome, '.codex', 'sks', 'sks-bridge-route-policy.json');
|
|
64
|
+
}
|
|
65
|
+
return path.join(resolvedHome, 'Library', 'LaunchAgents', 'com.sneakoscope.desktop-bridge.plist');
|
|
66
|
+
}
|
|
67
|
+
function metadataPathLooksSecret(filePath) {
|
|
68
|
+
const basename = path.basename(filePath).toLowerCase();
|
|
69
|
+
const segments = filePath.toLowerCase().split(path.sep);
|
|
70
|
+
return segments.includes('secrets')
|
|
71
|
+
|| ['auth.json', 'sks-codex-lb.env', 'openrouter-api-key', 'openrouter-api-key.json'].includes(basename)
|
|
72
|
+
|| /(?:credential|api-key|secret)/i.test(basename);
|
|
73
|
+
}
|
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
export function authSemanticIdentityPreserved(before, after) {
|
|
2
|
+
if (before.path !== after.path || before.exists !== after.exists)
|
|
3
|
+
return false;
|
|
4
|
+
if (before.sha256 !== after.sha256)
|
|
5
|
+
return false;
|
|
6
|
+
const beforeIsOAuth = before.mode === 'chatgpt_oauth' || before.mode === 'mixed';
|
|
7
|
+
const afterIsOAuth = after.mode === 'chatgpt_oauth' || after.mode === 'mixed';
|
|
8
|
+
if (beforeIsOAuth || afterIsOAuth) {
|
|
9
|
+
return beforeIsOAuth
|
|
10
|
+
&& afterIsOAuth
|
|
11
|
+
&& before.semantic_fingerprint !== null
|
|
12
|
+
&& before.semantic_fingerprint === after.semantic_fingerprint;
|
|
13
|
+
}
|
|
14
|
+
return true;
|
|
15
|
+
}
|
|
16
|
+
export function buildDesktopBridgeMigrationReceipt(input) {
|
|
17
|
+
const common = {
|
|
18
|
+
schema: 'sks.desktop-bridge-unification-receipt.v1',
|
|
19
|
+
receipt_id: input.receiptId,
|
|
20
|
+
created_at: input.createdAt,
|
|
21
|
+
baseline_version: '8.1.2',
|
|
22
|
+
target_version: '8.1.3',
|
|
23
|
+
config_before_sha256: input.configBeforeSha,
|
|
24
|
+
config_after_sha256: input.configAfterSha,
|
|
25
|
+
auth_before_sha256: input.authBeforeSha,
|
|
26
|
+
auth_after_sha256: input.authAfterSha,
|
|
27
|
+
auth_semantic_identity_preserved: input.authSemanticIdentityPreserved ?? true,
|
|
28
|
+
historical_state: {
|
|
29
|
+
desktop_mode: input.historicalState.desktop_mode,
|
|
30
|
+
historical_provider_selection: input.historicalState.provider_mode,
|
|
31
|
+
model_provider: input.historicalState.model_provider,
|
|
32
|
+
catalog_path: input.historicalState.catalog_path
|
|
33
|
+
},
|
|
34
|
+
migrated_profiles: input.historicalState.migrated_profiles,
|
|
35
|
+
credentials_deleted: false,
|
|
36
|
+
new_runtime: 'desktop-bridge',
|
|
37
|
+
new_catalog_generation: input.newCatalogGeneration,
|
|
38
|
+
backup_paths: input.rollbackFiles
|
|
39
|
+
.map((file) => file.backup_path)
|
|
40
|
+
.filter((entry) => Boolean(entry)),
|
|
41
|
+
blockers: input.blockers || [],
|
|
42
|
+
rollback_metadata: {
|
|
43
|
+
schema: 'sks.desktop-bridge-unification-rollback-metadata.v1',
|
|
44
|
+
files: input.rollbackFiles
|
|
45
|
+
}
|
|
46
|
+
};
|
|
47
|
+
return {
|
|
48
|
+
...common,
|
|
49
|
+
rollback_supported: true,
|
|
50
|
+
migration_status: 'migrated'
|
|
51
|
+
};
|
|
52
|
+
}
|
|
@@ -0,0 +1,106 @@
|
|
|
1
|
+
import fsp from 'node:fs/promises';
|
|
2
|
+
import path from 'node:path';
|
|
3
|
+
import { runProcess } from '../../fsx.js';
|
|
4
|
+
const RETIRED_LAUNCHD_LABEL = 'com.sneakoscope.codex-lb-desktop-bridge';
|
|
5
|
+
const RETIRED_SETTINGS_SCHEMA = 'sks.codex-lb-desktop-bridge-settings.v2';
|
|
6
|
+
const RETIRED_STATE_SCHEMA = 'sks.codex-lb-desktop-bridge.v2';
|
|
7
|
+
const SETTINGS_KEYS = new Set([
|
|
8
|
+
'schema', 'listen_host', 'listen_port', 'provider_registry', 'route_policy',
|
|
9
|
+
'provider_session_pins', 'client_capability_sha256', 'allowed_origins',
|
|
10
|
+
'connect_timeout_ms', 'idle_timeout_ms',
|
|
11
|
+
]);
|
|
12
|
+
function retiredPaths(home) {
|
|
13
|
+
const resolvedHome = path.resolve(home);
|
|
14
|
+
const runtime = path.join(resolvedHome, '.codex', 'sks');
|
|
15
|
+
return {
|
|
16
|
+
settings: path.join(runtime, 'codex-lb-desktop-bridge-settings.json'),
|
|
17
|
+
state: path.join(runtime, 'codex-lb-desktop-bridge.json'),
|
|
18
|
+
plist: path.join(resolvedHome, 'Library', 'LaunchAgents', `${RETIRED_LAUNCHD_LABEL}.plist`),
|
|
19
|
+
stdout: path.join(runtime, 'logs', 'codex-lb-desktop-bridge.out.log'),
|
|
20
|
+
stderr: path.join(runtime, 'logs', 'codex-lb-desktop-bridge.err.log'),
|
|
21
|
+
};
|
|
22
|
+
}
|
|
23
|
+
async function regularFileExists(file) {
|
|
24
|
+
try {
|
|
25
|
+
const stat = await fsp.lstat(file);
|
|
26
|
+
if (stat.isSymbolicLink() || !stat.isFile())
|
|
27
|
+
throw new Error('desktop_bridge_retired_runtime_path_unsafe');
|
|
28
|
+
return true;
|
|
29
|
+
}
|
|
30
|
+
catch (error) {
|
|
31
|
+
if (error.code === 'ENOENT')
|
|
32
|
+
return false;
|
|
33
|
+
throw error;
|
|
34
|
+
}
|
|
35
|
+
}
|
|
36
|
+
async function readRetiredSettings(file) {
|
|
37
|
+
if (!(await regularFileExists(file)))
|
|
38
|
+
return null;
|
|
39
|
+
const stat = await fsp.stat(file);
|
|
40
|
+
if ((stat.mode & 0o077) !== 0 || stat.size > 256 * 1024) {
|
|
41
|
+
throw new Error('desktop_bridge_retired_settings_unsafe');
|
|
42
|
+
}
|
|
43
|
+
let value;
|
|
44
|
+
try {
|
|
45
|
+
value = JSON.parse(await fsp.readFile(file, 'utf8'));
|
|
46
|
+
}
|
|
47
|
+
catch {
|
|
48
|
+
throw new Error('desktop_bridge_retired_settings_invalid');
|
|
49
|
+
}
|
|
50
|
+
if (!value || typeof value !== 'object' || Array.isArray(value)) {
|
|
51
|
+
throw new Error('desktop_bridge_retired_settings_invalid');
|
|
52
|
+
}
|
|
53
|
+
const row = value;
|
|
54
|
+
if (row.schema !== RETIRED_SETTINGS_SCHEMA || Object.keys(row).some((key) => !SETTINGS_KEYS.has(key))) {
|
|
55
|
+
throw new Error('desktop_bridge_retired_settings_invalid');
|
|
56
|
+
}
|
|
57
|
+
if (/"(?:api_?key|secret|authorization|cookie|access_token|refresh_token)"\s*:/i.test(JSON.stringify(row))) {
|
|
58
|
+
throw new Error('desktop_bridge_retired_settings_secret_forbidden');
|
|
59
|
+
}
|
|
60
|
+
const { schema: _schema, ...settings } = row;
|
|
61
|
+
return settings;
|
|
62
|
+
}
|
|
63
|
+
function launchDomain(uid = typeof process.getuid === 'function' ? process.getuid() : 0) {
|
|
64
|
+
return `gui/${uid}`;
|
|
65
|
+
}
|
|
66
|
+
export async function prepareRetiredDesktopBridgeRuntime(options) {
|
|
67
|
+
const paths = retiredPaths(options.home);
|
|
68
|
+
const present = (await Promise.all(Object.values(paths).map(regularFileExists))).some(Boolean);
|
|
69
|
+
if (!present)
|
|
70
|
+
return { present: false, settings: null, paths };
|
|
71
|
+
const run = options.run || runProcess;
|
|
72
|
+
const launchctl = options.launchctl || '/bin/launchctl';
|
|
73
|
+
const service = `${launchDomain(options.uid)}/${RETIRED_LAUNCHD_LABEL}`;
|
|
74
|
+
const before = await run(launchctl, ['print', service], {
|
|
75
|
+
timeoutMs: 3_000, maxOutputBytes: 16 * 1024,
|
|
76
|
+
}).catch(() => null);
|
|
77
|
+
if (before?.code === 0) {
|
|
78
|
+
await run(launchctl, ['bootout', service], {
|
|
79
|
+
timeoutMs: 8_000, maxOutputBytes: 32 * 1024,
|
|
80
|
+
}).catch(() => null);
|
|
81
|
+
}
|
|
82
|
+
const after = await run(launchctl, ['print', service], {
|
|
83
|
+
timeoutMs: 3_000, maxOutputBytes: 16 * 1024,
|
|
84
|
+
}).catch(() => null);
|
|
85
|
+
if (after?.code === 0)
|
|
86
|
+
throw new Error('desktop_bridge_retired_launchd_still_loaded');
|
|
87
|
+
return { present: true, settings: await readRetiredSettings(paths.settings), paths };
|
|
88
|
+
}
|
|
89
|
+
export async function cleanupRetiredDesktopBridgeRuntime(preparation) {
|
|
90
|
+
if (!preparation.present)
|
|
91
|
+
return;
|
|
92
|
+
if (await regularFileExists(preparation.paths.settings)) {
|
|
93
|
+
const raw = JSON.parse(await fsp.readFile(preparation.paths.settings, 'utf8'));
|
|
94
|
+
if (raw.schema !== RETIRED_SETTINGS_SCHEMA)
|
|
95
|
+
throw new Error('desktop_bridge_retired_settings_changed');
|
|
96
|
+
}
|
|
97
|
+
if (await regularFileExists(preparation.paths.state)) {
|
|
98
|
+
const raw = JSON.parse(await fsp.readFile(preparation.paths.state, 'utf8'));
|
|
99
|
+
if (raw.schema !== RETIRED_STATE_SCHEMA)
|
|
100
|
+
throw new Error('desktop_bridge_retired_state_changed');
|
|
101
|
+
}
|
|
102
|
+
for (const file of Object.values(preparation.paths)) {
|
|
103
|
+
if (await regularFileExists(file))
|
|
104
|
+
await fsp.unlink(file);
|
|
105
|
+
}
|
|
106
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|