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.
Files changed (261) hide show
  1. package/README.md +96 -58
  2. package/crates/sks-core/Cargo.lock +1 -1
  3. package/crates/sks-core/Cargo.toml +1 -1
  4. package/dist/bin/fast-inline.js +5 -51
  5. package/dist/cli/command-manifest-lite.js +2 -1
  6. package/dist/cli/command-registry.js +2 -1
  7. package/dist/cli/global-mode-router.js +1 -1
  8. package/dist/cli/install-helpers-codex-lb-config.js +112 -914
  9. package/dist/cli/install-helpers-codex-lb-shared.js +3 -44
  10. package/dist/cli/install-helpers-install-support.js +4 -20
  11. package/dist/cli/install-helpers.js +36 -2716
  12. package/dist/cli/router.js +9 -9
  13. package/dist/commands/bridge-command-output.js +111 -0
  14. package/dist/commands/bridge.js +320 -0
  15. package/dist/commands/codex-app.js +39 -123
  16. package/dist/commands/doctor-helpers.js +380 -0
  17. package/dist/commands/doctor-profile.js +3 -0
  18. package/dist/commands/doctor.js +114 -873
  19. package/dist/commands/mad-sks.js +0 -4
  20. package/dist/config/skills-manifest.json +1 -1
  21. package/dist/core/agents/agent-effort-policy.js +11 -21
  22. package/dist/core/agents/agent-recursion-guard.js +26 -0
  23. package/dist/core/agents/agent-runner-codex-exec.js +7 -9
  24. package/dist/core/architecture-hardening/contracts/contracts.js +225 -161
  25. package/dist/core/architecture-hardening/state/state-service.js +49 -13
  26. package/dist/core/auto-review.js +15 -9
  27. package/dist/core/codex/codex-config-guard.js +8 -0
  28. package/dist/core/codex-adapter.js +8 -10
  29. package/dist/core/codex-app/codex-app-fast-ui-repair.js +7 -29
  30. package/dist/core/codex-app/codex-app-launcher.js +10 -12
  31. package/dist/core/codex-app/codex-app-restart.js +10 -12
  32. package/dist/core/codex-app/menubar/constants.js +2 -5
  33. package/dist/core/codex-app/menubar/global-install.js +3 -2
  34. package/dist/core/codex-app/menubar/installer/result.js +23 -0
  35. package/dist/core/codex-app/menubar/installer/runtime.js +28 -0
  36. package/dist/core/codex-app/menubar/installer.js +5 -96
  37. package/dist/core/codex-app/menubar/migration.js +1 -42
  38. package/dist/core/codex-app/openrouter-provider.js +0 -78
  39. package/dist/core/codex-app.js +97 -360
  40. package/dist/core/codex-control/codex-app-server-runtime-env.js +8 -28
  41. package/dist/core/codex-control/codex-current-image-path-real-probe.js +2 -3
  42. package/dist/core/codex-control/codex-current-web-search-probe.js +2 -3
  43. package/dist/core/codex-control/codex-sdk-adapter.js +5 -48
  44. package/dist/core/codex-control/codex-task-runner.js +16 -60
  45. package/dist/core/codex-control/desktop-bridge-launch-guard.js +227 -0
  46. package/dist/core/codex-exec-output-schema.js +11 -13
  47. package/dist/core/codex-lb/bridge-contracts.js +2 -0
  48. package/dist/core/codex-lb/bridge-runtime-validation/capability.js +104 -0
  49. package/dist/core/codex-lb/bridge-runtime-validation/catalog.js +52 -0
  50. package/dist/core/codex-lb/bridge-runtime-validation/shared.js +109 -0
  51. package/dist/core/codex-lb/bridge-runtime-validation/status.js +250 -0
  52. package/dist/core/codex-lb/bridge-runtime-validation.js +106 -0
  53. package/dist/core/codex-lb/capability-runner.js +505 -201
  54. package/dist/core/codex-lb/codex-lb-env.js +179 -12
  55. package/dist/core/codex-lb/combined-catalog/builder.js +86 -0
  56. package/dist/core/codex-lb/combined-catalog/contracts.js +5 -0
  57. package/dist/core/codex-lb/combined-catalog/normalize.js +170 -0
  58. package/dist/core/codex-lb/combined-catalog/persistence.js +207 -0
  59. package/dist/core/codex-lb/combined-catalog/shared.js +12 -0
  60. package/dist/core/codex-lb/combined-catalog/storage.js +171 -0
  61. package/dist/core/codex-lb/combined-catalog.js +12 -0
  62. package/dist/core/codex-lb/desktop-bridge/client.js +4 -1
  63. package/dist/core/codex-lb/desktop-bridge/header-policy.js +48 -63
  64. package/dist/core/codex-lb/desktop-bridge/http-forward.js +115 -83
  65. package/dist/core/codex-lb/desktop-bridge/launchd.js +20 -13
  66. package/dist/core/codex-lb/desktop-bridge/location-rewrite.js +4 -1
  67. package/dist/core/codex-lb/desktop-bridge/security.js +381 -267
  68. package/dist/core/codex-lb/desktop-bridge/server.js +148 -19
  69. package/dist/core/codex-lb/desktop-bridge/state.js +56 -70
  70. package/dist/core/codex-lb/desktop-bridge/types.js +6 -1
  71. package/dist/core/codex-lb/desktop-bridge/websocket-forward.js +281 -106
  72. package/dist/core/codex-lb/desktop-bridge-migration/historical-config.js +245 -0
  73. package/dist/core/codex-lb/desktop-bridge-migration/historical-toml.js +56 -0
  74. package/dist/core/codex-lb/desktop-bridge-migration/metadata.js +73 -0
  75. package/dist/core/codex-lb/desktop-bridge-migration/receipt.js +52 -0
  76. package/dist/core/codex-lb/desktop-bridge-migration/retired-runtime-cleanup.js +106 -0
  77. package/dist/core/codex-lb/desktop-bridge-migration/types.js +1 -0
  78. package/dist/core/codex-lb/desktop-bridge-migration.js +238 -0
  79. package/dist/core/codex-lb/desktop-controller-v3/catalog.js +257 -0
  80. package/dist/core/codex-lb/desktop-controller-v3/diagnostics.js +62 -0
  81. package/dist/core/codex-lb/desktop-controller-v3/lifecycle-commands.js +203 -0
  82. package/dist/core/codex-lb/desktop-controller-v3/live-probes.js +293 -0
  83. package/dist/core/codex-lb/desktop-controller-v3/preflight-probes.js +144 -0
  84. package/dist/core/codex-lb/desktop-controller-v3/provider-commands.js +182 -0
  85. package/dist/core/codex-lb/desktop-controller-v3/shared.js +279 -0
  86. package/dist/core/codex-lb/desktop-controller-v3/status.js +269 -0
  87. package/dist/core/codex-lb/desktop-controller-v3/types.js +1 -0
  88. package/dist/core/codex-lb/desktop-controller-v3/verification.js +89 -0
  89. package/dist/core/codex-lb/desktop-controller-v3.js +67 -0
  90. package/dist/core/codex-lb/desktop-controller.js +2 -1730
  91. package/dist/core/codex-lb/desktop-service.js +462 -627
  92. package/dist/core/codex-lb/migration-receipt.js +560 -118
  93. package/dist/core/codex-lb/probes/auxiliary-surfaces-probe.js +37 -53
  94. package/dist/core/codex-lb/probes/bridge-probe.js +125 -64
  95. package/dist/core/codex-lb/probes/catalog-probe.js +36 -136
  96. package/dist/core/codex-lb/probes/computer-use-probe.js +63 -39
  97. package/dist/core/codex-lb/probes/image-generation-probe.js +98 -41
  98. package/dist/core/codex-lb/probes/probe-evidence.js +32 -33
  99. package/dist/core/codex-lb/probes/voice-realtime-probe.js +69 -43
  100. package/dist/core/codex-lb/provider-credentials/configuration.js +127 -0
  101. package/dist/core/codex-lb/provider-credentials/locks.js +11 -0
  102. package/dist/core/codex-lb/provider-credentials/private-snapshot.js +28 -0
  103. package/dist/core/codex-lb/provider-credentials/removal.js +33 -0
  104. package/dist/core/codex-lb/provider-credentials/resolution.js +59 -0
  105. package/dist/core/codex-lb/provider-credentials/runtime.js +55 -0
  106. package/dist/core/codex-lb/provider-credentials/types.js +1 -0
  107. package/dist/core/codex-lb/provider-credentials/validation-store.js +137 -0
  108. package/dist/core/codex-lb/provider-credentials.js +5 -0
  109. package/dist/core/codex-lb/provider-registry.js +323 -0
  110. package/dist/core/codex-lb/provider-route-policy.js +118 -0
  111. package/dist/core/codex-lb/request-route-resolver.js +172 -0
  112. package/dist/core/codex-lb/route-index.js +148 -0
  113. package/dist/core/codex-lb/trusted-deep-evidence.js +158 -286
  114. package/dist/core/commands/basic-cli.js +1 -1
  115. package/dist/core/commands/check-command.js +3 -10
  116. package/dist/core/commands/gate-result-contract.js +10 -14
  117. package/dist/core/commands/intent-normalization/normalizer.js +1 -1
  118. package/dist/core/commands/mad-sks-command.js +2 -6
  119. package/dist/core/commands/release-command.js +11 -1
  120. package/dist/core/commands/telegram-command.js +46 -6
  121. package/dist/core/doctor/doctor-readiness-matrix.js +9 -7
  122. package/dist/core/doctor/skill-legacy-surface.js +5 -5
  123. package/dist/core/evidence/v2/evidence-key.js +30 -3
  124. package/dist/core/feature-fixtures.js +8 -1
  125. package/dist/core/feature-registry.js +3 -2
  126. package/dist/core/hooks-runtime/stop-finalization.js +11 -1
  127. package/dist/core/hooks-runtime/subagent-context.js +15 -1
  128. package/dist/core/hooks-runtime/subagent-skill-availability-contract.js +1 -1
  129. package/dist/core/hooks-runtime/tool-output-quarantine.js +1 -1
  130. package/dist/core/hooks-runtime.js +73 -87
  131. package/dist/core/image-ux-review/imagegen-adapter.js +108 -94
  132. package/dist/core/image-ux-review/real-callout-extractor.js +144 -14
  133. package/dist/core/imagegen/desktop-bridge-imagegen-target.js +77 -0
  134. package/dist/core/imagegen/imagegen-capability.js +43 -151
  135. package/dist/core/init/skills/filesystem.js +89 -0
  136. package/dist/core/init/skills/inventory.js +97 -0
  137. package/dist/core/init/skills/manifest.js +151 -0
  138. package/dist/core/init/skills.js +5 -325
  139. package/dist/core/init.js +0 -63
  140. package/dist/core/install/installed-package-smoke.js +1 -1
  141. package/dist/core/managed-assets/managed-assets-manifest.js +0 -1
  142. package/dist/core/policy/latest-version-guidance.js +15 -2
  143. package/dist/core/preflight/parallel-preflight-engine.js +27 -51
  144. package/dist/core/provider/provider-badge.js +9 -4
  145. package/dist/core/provider/provider-context.js +57 -107
  146. package/dist/core/providers/openrouter/openrouter-account.js +3 -1
  147. package/dist/core/providers/openrouter/openrouter-secret-store.js +91 -22
  148. package/dist/core/release/desktop-bridge-release-evidence.js +457 -0
  149. package/dist/core/release/gate-manifest.js +0 -1
  150. package/dist/core/release/main-push-guard.js +13 -0
  151. package/dist/core/release/main-push-receipt.js +11 -0
  152. package/dist/core/release/physical-release-gates.js +664 -61
  153. package/dist/core/release/publish-preflight.js +3 -3
  154. package/dist/core/release/release-gate-batch-runner.js +19 -6
  155. package/dist/core/release/release-gate-dag.js +33 -6
  156. package/dist/core/release/release-gate-node.js +1 -3
  157. package/dist/core/release/release-gate-output-contract.js +55 -0
  158. package/dist/core/release/release-pack-contract.js +1 -1
  159. package/dist/core/release/release-pack-receipt.js +209 -8
  160. package/dist/core/release/release-real-contract.js +1 -1
  161. package/dist/core/release/stage-publish.js +106 -28
  162. package/dist/core/retention/temp-lease.js +204 -0
  163. package/dist/core/retention.js +18 -195
  164. package/dist/core/routes.js +1 -2
  165. package/dist/core/safety/intent-contract/intent-contract.js +3 -3
  166. package/dist/core/subagents/naruto-host-credentials.js +6 -1
  167. package/dist/core/subagents/official-subagent-config.js +27 -9
  168. package/dist/core/subagents/official-subagent-runner.js +14 -31
  169. package/dist/core/subagents/wave-lifecycle.js +36 -8
  170. package/dist/core/subagents/wave-parent-guidance.js +2 -1
  171. package/dist/core/telegram/doctor.js +2 -2
  172. package/dist/core/telegram/liveness.js +10 -4
  173. package/dist/core/triwiki/context-graph/compiler/index.js +18 -18
  174. package/dist/core/update/update-migration-state/fast-mode-config.js +172 -0
  175. package/dist/core/update/update-migration-state/session-state-split.js +247 -0
  176. package/dist/core/update/update-migration-state/simple-stages.js +46 -0
  177. package/dist/core/update/update-migration-state.js +4 -481
  178. package/dist/core/version.js +1 -1
  179. package/dist/native/sks-menubar/Sources/OperationCoordinator.swift +28 -4
  180. package/dist/native/sks-menubar/Sources/OperationModels.swift +112 -2
  181. package/dist/native/sks-menubar/Sources/ProviderRouteExplanation.swift +21 -0
  182. package/dist/native/sks-menubar/Sources/ProvidersBridgeCatalog.swift +140 -0
  183. package/dist/native/sks-menubar/Sources/ProvidersOpenRouter.swift +107 -470
  184. package/dist/native/sks-menubar/Sources/ProvidersReliability.swift +27 -197
  185. package/dist/native/sks-menubar/Sources/ProvidersRoutingTruth.swift +335 -269
  186. package/dist/native/sks-menubar/Sources/ProvidersViewController.swift +233 -437
  187. package/dist/native/sks-menubar/Sources/RemoteCodingViewController.swift +16 -7
  188. package/dist/native/sks-menubar/Sources/SecureProcessEnvelope.swift +39 -9
  189. package/dist/native/sks-menubar/Sources/TelegramSupport.swift +56 -0
  190. package/dist/scripts/canonical-test-runner.js +7 -1
  191. package/dist/scripts/check-runtime-schemas.js +7 -2
  192. package/dist/scripts/codex-sdk-real-smoke-check.js +3 -1
  193. package/dist/scripts/desktop-bridge-capabilities-check.js +123 -0
  194. package/dist/scripts/{codex-lb-desktop-bridge-latency-check.js → desktop-bridge-latency-check.js} +61 -16
  195. package/dist/scripts/desktop-bridge-real-evidence-check.js +64 -0
  196. package/dist/scripts/{codex-lb-desktop-bridge-check.js → desktop-bridge-transport-check.js} +92 -155
  197. package/dist/scripts/desktop-bridge-transport-client.js +116 -0
  198. package/dist/scripts/desktop-bridge-unification-check.js +276 -0
  199. package/dist/scripts/doctor-fixes-codex-app-fast-ui-check.js +12 -8
  200. package/dist/scripts/gate-policy-audit-check.js +52 -2
  201. package/dist/scripts/provider-badge-context-check.js +55 -12
  202. package/dist/scripts/publish-preflight.js +1 -2
  203. package/dist/scripts/release-affected-selector-check.js +1 -2
  204. package/dist/scripts/release-aggressive-resource-governor-check.js +1 -1
  205. package/dist/scripts/release-cache-glob-hashing-check.js +1 -0
  206. package/dist/scripts/release-cache-version-neutral-fixture-check.js +1 -0
  207. package/dist/scripts/release-full-parallelism-blackbox.js +1 -1
  208. package/dist/scripts/release-gate-batch-runner-check.js +9 -0
  209. package/dist/scripts/release-gate-dag-runner-check.js +6 -0
  210. package/dist/scripts/release-gate-dag-runner.js +4 -2
  211. package/dist/scripts/release-metadata-check.js +16 -3
  212. package/dist/scripts/release-pack-receipt.js +29 -6
  213. package/dist/scripts/release-physical-gates-check.js +39 -0
  214. package/dist/scripts/release-real-check.js +7 -5
  215. package/package.json +6 -8
  216. package/release-gates.v2.json +156 -157
  217. package/runtime-required-scripts.json +11 -11
  218. package/schemas/codex/desktop-bridge-status-v3.schema.json +286 -0
  219. package/schemas/codex/desktop-capabilities-v3.schema.json +198 -0
  220. package/schemas/release/release-gate-node.schema.json +2 -3
  221. package/dist/cli/codex-lb-setup-warning-output.js +0 -17
  222. package/dist/cli/install-helpers-codex-lb-chain.js +0 -529
  223. package/dist/commands/codex-lb.js +0 -1232
  224. package/dist/core/architecture-hardening/migration/migration.js +0 -111
  225. package/dist/core/codex-app/auxiliary-oauth-policy.js +0 -36
  226. package/dist/core/codex-app/catalog-compat/catalog-service.js +0 -104
  227. package/dist/core/codex-app/child-policy/child-policy.js +0 -35
  228. package/dist/core/codex-app/desktop-routing-snapshot.js +0 -233
  229. package/dist/core/codex-app/glm-model-profile.js +0 -1
  230. package/dist/core/codex-app/glm-profile-installer.js +0 -191
  231. package/dist/core/codex-app/glm-profile-schema.js +0 -42
  232. package/dist/core/codex-app/multi-provider-router.js +0 -391
  233. package/dist/core/codex-app/openrouter-activate.js +0 -405
  234. package/dist/core/codex-app/openrouter-model-catalog.js +0 -217
  235. package/dist/core/codex-app/provider-child-policy.js +0 -64
  236. package/dist/core/codex-app/provider-mode.js +0 -91
  237. package/dist/core/codex-app/provider-session-policy.js +0 -85
  238. package/dist/core/codex-app/session-policy/session-pinning.js +0 -68
  239. package/dist/core/codex-control/codex-lb-launch-recovery.js +0 -319
  240. package/dist/core/codex-lb/codex-lb-setup.js +0 -293
  241. package/dist/core/codex-lb/codex-lb-tool-catalog.js +0 -456
  242. package/dist/core/codex-lb/codex-lb-tool-output-recovery.js +0 -290
  243. package/dist/core/codex-lb/desktop-center-credentials.js +0 -1083
  244. package/dist/core/codex-lb/desktop-mode.js +0 -32
  245. package/dist/core/codex-lb/desktop-real-evidence.js +0 -168
  246. package/dist/core/codex-lb/legacy-migration.js +0 -576
  247. package/dist/core/codex-lb/native-openai-transport/transport.js +0 -68
  248. package/dist/core/codex-lb/provider-routing/provider-router.js +0 -58
  249. package/dist/core/codex-lb/routing-truth.js +0 -327
  250. package/dist/core/imagegen/codex-lb-imagegen-target.js +0 -92
  251. package/dist/native/sks-menubar/Sources/ProvidersConnectTest.swift +0 -118
  252. package/dist/native/sks-menubar/Sources/ProvidersFastMode.swift +0 -17
  253. package/dist/native/sks-menubar/Sources/ProvidersMultiProvider.swift +0 -331
  254. package/dist/native/sks-menubar/Sources/ProvidersRoleModels.swift +0 -260
  255. package/dist/scripts/codex-lb-catalog-passthrough-check.js +0 -120
  256. package/dist/scripts/codex-lb-desktop-auth-invariant-check.js +0 -169
  257. package/dist/scripts/codex-lb-desktop-capabilities-check.js +0 -287
  258. package/dist/scripts/codex-lb-desktop-real-evidence-check.js +0 -123
  259. package/dist/scripts/codex-lb-fast-mode-truth-check.js +0 -114
  260. package/dist/scripts/codex-lb-fast-ui-preservation-check.js +0 -152
  261. 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
+ }