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,182 @@
1
+ import { testOpenRouterConnection } from '../../providers/openrouter/openrouter-account.js';
2
+ import { openRouterSecretPaths } from '../../providers/openrouter/openrouter-secret-store.js';
3
+ import { codexLbEnvPath, codexLbMetadataPath, readCodexLbModelCatalog } from '../codex-lb-env.js';
4
+ import { configureProviderCredential, recordProviderCredentialValidation, removeProviderCredential } from '../provider-credentials.js';
5
+ import { configureBridgeProviderProfile, resolveBridgeProviderRegistry, setBridgeProviderEnabled } from '../provider-registry.js';
6
+ import { commandResult, activeProviderIds, controllerEnv, controllerPaths, nowIso, persistRuntimeSettings, providerCode, quiesceRunningBridge, resolveRawCredentials, stringArray, timeoutMs } from './shared.js';
7
+ import { desktopBridgeStatusV3, loadCore } from './status.js';
8
+ export async function configureProvider(request, options) {
9
+ const paths = controllerPaths(options);
10
+ const restartDeferred = await quiesceRunningBridge(await loadCore(options), options);
11
+ const configured = await configureProviderCredential({
12
+ provider_id: request.provider_id,
13
+ api_key: request.api_key,
14
+ ...(request.host ? { host: request.host } : {}),
15
+ home: paths.home,
16
+ processEnv: controllerEnv(options),
17
+ codexLbEnvPath: options.envPath || codexLbEnvPath(paths.home),
18
+ codexLbMetadataPath: options.metadataPath || codexLbMetadataPath(paths.home)
19
+ });
20
+ const rawCredentials = await resolveRawCredentials(options, paths);
21
+ const endpoint = request.provider_id === 'codex-lb'
22
+ ? rawCredentials['codex-lb'].endpoint_url
23
+ : 'https://openrouter.ai/api/v1';
24
+ if (!endpoint)
25
+ throw new Error(`${providerCode(request.provider_id)}_endpoint_missing`);
26
+ const registry = await configureBridgeProviderProfile({
27
+ provider_id: request.provider_id,
28
+ endpoint_url: endpoint,
29
+ enabled: true,
30
+ home: paths.home,
31
+ credentials: rawCredentials
32
+ });
33
+ const core = await loadCore(options);
34
+ if (core.activeCatalog.ok && core.policy) {
35
+ await persistRuntimeSettings({ ...core, registry }, options, { restartService: false });
36
+ }
37
+ const status = await desktopBridgeStatusV3(options);
38
+ const blockers = restartDeferred ? ['desktop_bridge_restart_deferred_until_provider_validation'] : [];
39
+ return commandResult('provider.configure', true, status, {
40
+ configuration: configured,
41
+ restart_deferred: restartDeferred,
42
+ recovery_action: restartDeferred ? `bridge provider validate ${request.provider_id}` : null,
43
+ }, blockers, options);
44
+ }
45
+ export async function validateProvider(providerId, options) {
46
+ const paths = controllerPaths(options);
47
+ const credentials = await resolveRawCredentials(options, paths);
48
+ const credential = credentials[providerId];
49
+ if (!credential.secret || !credential.fingerprint || !credential.endpoint_url) {
50
+ const status = await desktopBridgeStatusV3(options);
51
+ return commandResult('provider.validate', true, status, { provider_id: providerId, validated: false }, [`${providerCode(providerId)}_credential_missing`], options);
52
+ }
53
+ const registry = await resolveBridgeProviderRegistry({ home: paths.home, credentials });
54
+ const result = providerId === 'codex-lb'
55
+ ? await validateCodexLbCredential(credential, options, registry.profiles['codex-lb'].endpoint.auth_transport)
56
+ : await testOpenRouterConnection({
57
+ apiKey: credential.secret,
58
+ ...(options.fetchImpl ? { fetchImpl: options.fetchImpl } : {}),
59
+ timeoutMs: timeoutMs(options)
60
+ });
61
+ const ok = result.ok === true;
62
+ const blockers = stringArray(result.blockers);
63
+ if (!ok && blockers.length === 0)
64
+ blockers.push(`${providerCode(providerId)}_validation_failed`);
65
+ await recordProviderCredentialValidation({
66
+ provider_id: providerId,
67
+ credential,
68
+ state: ok ? 'ready' : validationFailureState(blockers),
69
+ checked_at: nowIso(options),
70
+ blockers,
71
+ warnings: stringArray(result.warnings),
72
+ home: paths.home,
73
+ validationPath: paths.validationPath,
74
+ resolveCurrentCredential: async () => (await resolveRawCredentials(options, paths))[providerId],
75
+ });
76
+ if (ok) {
77
+ const current = await loadCore(options);
78
+ if (current.activeCatalog.ok && current.policy) {
79
+ await persistRuntimeSettings(current, options, {
80
+ restartService: current.service.installed || current.service.running,
81
+ failClosedRestart: true,
82
+ });
83
+ }
84
+ }
85
+ const status = await desktopBridgeStatusV3(options);
86
+ return commandResult('provider.validate', true, status, { provider_id: providerId, validated: ok, validation: publicValidationResult(result) }, ok ? [] : blockers, options);
87
+ }
88
+ export async function setProviderState(providerId, enabled, operation, options) {
89
+ const paths = controllerPaths(options);
90
+ const restartService = enabled
91
+ ? null
92
+ : await quiesceRunningBridge(await loadCore(options), options);
93
+ const credentials = await resolveRawCredentials(options, paths);
94
+ await setBridgeProviderEnabled({
95
+ provider_id: providerId,
96
+ enabled,
97
+ home: paths.home,
98
+ credentials
99
+ });
100
+ const core = await loadCore(options);
101
+ if (core.activeCatalog.ok && core.policy) {
102
+ if (enabled)
103
+ await persistRuntimeSettings(core, options);
104
+ else {
105
+ await persistRuntimeSettings(core, options, {
106
+ restartService: Boolean(restartService) && activeProviderIds(core).length > 0,
107
+ failClosedRestart: true
108
+ });
109
+ }
110
+ }
111
+ const status = await desktopBridgeStatusV3(options);
112
+ return commandResult(operation, true, status, { provider_id: providerId, enabled }, [], options);
113
+ }
114
+ export async function removeCredential(providerId, options) {
115
+ const paths = controllerPaths(options);
116
+ const before = await loadCore(options);
117
+ const restartService = await quiesceRunningBridge(before, options);
118
+ const removal = await removeProviderCredential({
119
+ provider_id: providerId,
120
+ confirmed: true,
121
+ home: paths.home,
122
+ codexLbEnvPath: options.envPath || codexLbEnvPath(paths.home),
123
+ codexLbMetadataPath: options.metadataPath || codexLbMetadataPath(paths.home),
124
+ openRouterPaths: openRouterSecretPaths(controllerEnv(options))
125
+ });
126
+ if (removal.blockers.length > 0) {
127
+ const status = await desktopBridgeStatusV3(options);
128
+ return commandResult('provider.remove-credential', false, status, { removal }, removal.blockers, options);
129
+ }
130
+ const core = await loadCore(options);
131
+ if (core.activeCatalog.ok && core.policy) {
132
+ await persistRuntimeSettings(core, options, {
133
+ restartService: restartService && activeProviderIds(core).length > 0,
134
+ failClosedRestart: true
135
+ });
136
+ }
137
+ const status = await desktopBridgeStatusV3(options);
138
+ return commandResult('provider.remove-credential', removal.blockers.length === 0, status, { removal }, removal.blockers, options);
139
+ }
140
+ async function validateCodexLbCredential(credential, options, authTransport) {
141
+ if (!credential.secret || !credential.endpoint_url || !credential.fingerprint) {
142
+ throw new Error('codex_lb_credential_validation_binding_missing');
143
+ }
144
+ const loaded = {
145
+ schema: 'sks.codex-lb-env.v1', configured: true, missing: [], source: 'env-file',
146
+ source_priority: ['env-file'], base_url: credential.endpoint_url,
147
+ api_key: { present: true, usable: true, source: 'env-file', redacted: true, fingerprint: credential.fingerprint },
148
+ secret_api_key: credential.secret,
149
+ credential_binding: {
150
+ checked: true, present: true, valid: true, status: 'matched', metadata_path: '[validation-snapshot]',
151
+ api_key_matches: true, base_url_matches: true, blockers: [],
152
+ },
153
+ env_paths: [], keychain: { checked: false, available: false, status: 'not_used' },
154
+ };
155
+ const result = await readCodexLbModelCatalog({
156
+ loadedEnv: loaded,
157
+ ...(options.fetchImpl ? { fetchImpl: options.fetchImpl } : {}),
158
+ ...(options.codexLbLookup ? { lookup: options.codexLbLookup } : {}),
159
+ timeoutMs: timeoutMs(options),
160
+ gatewayAuthTransport: authTransport === 'x-codex-lb-api-key'
161
+ ? 'x-codex-lb-api-key' : 'authorization-bearer'
162
+ });
163
+ return {
164
+ schema: 'sks.codex-lb-provider-validation.v1',
165
+ ok: result.ok,
166
+ authenticated: result.ok,
167
+ model_count: result.models.length,
168
+ http_status: result.http_status,
169
+ blockers: result.blockers,
170
+ warnings: []
171
+ };
172
+ }
173
+ function publicValidationResult(value) {
174
+ if (!value || typeof value !== 'object' || Array.isArray(value))
175
+ return {};
176
+ const row = value;
177
+ return Object.fromEntries(Object.entries(row).filter(([key]) => !/(?:api.?key|secret|token|authorization|cookie|headers?|env)/i.test(key)));
178
+ }
179
+ function validationFailureState(blockers) {
180
+ return blockers.some((blocker) => /(?:401|403|auth|rejected|invalid_key|unauthorized)/i.test(blocker))
181
+ ? 'rejected' : 'unavailable';
182
+ }
@@ -0,0 +1,279 @@
1
+ import { createHash, randomUUID } from 'node:crypto';
2
+ import os from 'node:os';
3
+ import path from 'node:path';
4
+ import { codexAuthPath, codexLbConfigPath } from '../../../cli/install-helpers-codex-lb-shared.js';
5
+ import { bridgeRouteIndexPath, combinedBridgeCatalogPath, readActiveCombinedBridgeCatalog } from '../combined-catalog.js';
6
+ import { codexLbEnvPath, codexLbMetadataPath } from '../codex-lb-env.js';
7
+ import { bootstrapExistingDesktopBridgeService, desktopBridgeServicePaths, readDesktopBridgeClientCapability, resolveDesktopBridgeActivationSettings, stopDesktopBridgeService, writeDesktopBridgeServiceSettings } from '../desktop-service.js';
8
+ import { desktopBridgeClientPath } from '../desktop-bridge/index.js';
9
+ import { desktopBridgeUnificationReceiptDir } from '../migration-receipt.js';
10
+ import { providerCredentialValidationPath, resolveAllProviderCredentials, resolveAllProviderCredentialsWithValidation } from '../provider-credentials.js';
11
+ import { bridgeRoutePolicyPath } from '../provider-route-policy.js';
12
+ import { sha256Stable } from '../route-index.js';
13
+ export function controllerPaths(options) {
14
+ const env = controllerEnv(options);
15
+ const home = path.resolve(options.home || env.HOME || os.homedir());
16
+ const codexHome = path.join(home, '.codex');
17
+ return {
18
+ home,
19
+ codexHome,
20
+ configPath: path.resolve(options.configPath || codexLbConfigPath(home)),
21
+ authPath: path.resolve(options.authPath || codexAuthPath(home)),
22
+ receiptDir: path.resolve(options.receiptDir || desktopBridgeUnificationReceiptDir(home)),
23
+ catalogPath: path.resolve(options.catalogPath || combinedBridgeCatalogPath(codexHome)),
24
+ routeIndexPath: path.resolve(options.routeIndexPath || bridgeRouteIndexPath(codexHome)),
25
+ routePolicyPath: path.resolve(options.routePolicyPath || bridgeRoutePolicyPath(codexHome)),
26
+ validationPath: path.resolve(options.validationPath || providerCredentialValidationPath(home)),
27
+ diagnosticPath: path.resolve(options.diagnosticPath || path.join(codexHome, 'sks', 'sks-desktop-bridge-last-diagnostic.json'))
28
+ };
29
+ }
30
+ export async function resolveRawCredentials(options, paths) {
31
+ const env = controllerEnv(options);
32
+ return resolveAllProviderCredentials({
33
+ codexLb: {
34
+ home: paths.home,
35
+ processEnv: env,
36
+ codexLbEnvPath: options.envPath || codexLbEnvPath(paths.home),
37
+ codexLbMetadataPath: options.metadataPath || codexLbMetadataPath(paths.home)
38
+ },
39
+ openrouter: { home: paths.home, processEnv: env }
40
+ });
41
+ }
42
+ export async function resolveValidatedCredentials(options, paths) {
43
+ const env = controllerEnv(options);
44
+ return resolveAllProviderCredentialsWithValidation({
45
+ home: paths.home,
46
+ validationPath: paths.validationPath,
47
+ codexLb: {
48
+ home: paths.home,
49
+ processEnv: env,
50
+ codexLbEnvPath: options.envPath || codexLbEnvPath(paths.home),
51
+ codexLbMetadataPath: options.metadataPath || codexLbMetadataPath(paths.home)
52
+ },
53
+ openrouter: { home: paths.home, processEnv: env }
54
+ });
55
+ }
56
+ export function activeProviderIds(core) {
57
+ if (!core.policy)
58
+ return [];
59
+ return ['codex-lb', 'openrouter'].filter((providerId) => core.registry.profiles[providerId].enabled
60
+ && core.registry.profiles[providerId].state === 'ready'
61
+ && Object.values(core.policy.model_routes).some((route) => route.provider_id === providerId));
62
+ }
63
+ export function providerRegistrySnapshot(registry, routeIndex) {
64
+ const provider = (providerId) => {
65
+ const profile = registry.profiles[providerId];
66
+ const baseUrl = profile.endpoint.url
67
+ || (providerId === 'openrouter' ? 'https://openrouter.ai/api/v1' : 'https://invalid.codex-lb.local');
68
+ return {
69
+ provider_id: providerId,
70
+ enabled: profile.enabled,
71
+ base_url: baseUrl,
72
+ allowed_origins: [...profile.endpoint.allowed_origins],
73
+ auth_transport: profile.endpoint.auth_transport,
74
+ credential_state: profile.credential.state,
75
+ credential_fingerprint: profile.credential.fingerprint,
76
+ credential_generation: profile.profile_generation,
77
+ source_catalog_generation: routeIndex.providers[providerId].catalog_generation
78
+ };
79
+ };
80
+ const providers = {
81
+ 'codex-lb': provider('codex-lb'),
82
+ openrouter: provider('openrouter')
83
+ };
84
+ return {
85
+ schema: 'sks.desktop-bridge-provider-registry.v1',
86
+ generation: sha256Stable(providers),
87
+ created_at: new Date().toISOString(),
88
+ providers
89
+ };
90
+ }
91
+ export async function persistRuntimeSettings(core, options, behavior = {}) {
92
+ if (!core.activeCatalog.ok || !core.policy)
93
+ return;
94
+ const snapshot = providerRegistrySnapshot(core.registry, core.activeCatalog.route_index);
95
+ const settings = await resolveDesktopBridgeActivationSettings({
96
+ ...options,
97
+ home: core.paths.home,
98
+ providerRegistry: snapshot,
99
+ routePolicy: core.policy
100
+ });
101
+ await writeDesktopBridgeServiceSettings(options.settingsPath || desktopBridgeServicePaths(core.paths.home).settings_path, settings);
102
+ const restartService = behavior.restartService ?? (core.service.installed || core.service.running);
103
+ if (!restartService)
104
+ return;
105
+ const restartOptions = {
106
+ ...options,
107
+ home: core.paths.home,
108
+ providerRegistry: snapshot,
109
+ routePolicy: core.policy
110
+ };
111
+ let restarted;
112
+ try {
113
+ restarted = await (options.bootstrapServiceImpl || bootstrapExistingDesktopBridgeService)(restartOptions);
114
+ }
115
+ catch (error) {
116
+ await stopAfterFailedRestart(restartOptions, options);
117
+ throw error;
118
+ }
119
+ if (!restarted.ok || !restarted.running) {
120
+ await stopAfterFailedRestart(restartOptions, options);
121
+ throw new Error(restarted.blockers[0] || 'desktop_bridge_restart_failed');
122
+ }
123
+ }
124
+ export async function quiesceRunningBridge(core, options) {
125
+ if (!core.service.running)
126
+ return false;
127
+ const stopped = await (options.stopServiceImpl || stopDesktopBridgeService)({
128
+ ...options,
129
+ home: core.paths.home
130
+ });
131
+ if (stopped.running) {
132
+ throw new Error(stopped.blockers[0] || 'desktop_bridge_process_still_running');
133
+ }
134
+ return true;
135
+ }
136
+ async function stopAfterFailedRestart(restartOptions, options) {
137
+ const stopped = await (options.stopServiceImpl || stopDesktopBridgeService)(restartOptions);
138
+ if (stopped.running)
139
+ throw new Error(stopped.blockers[0] || 'desktop_bridge_process_still_running');
140
+ }
141
+ export function serializedSettings(settings) {
142
+ return `${JSON.stringify({
143
+ schema: settings.schema,
144
+ listen_host: settings.listen_host,
145
+ listen_port: settings.listen_port,
146
+ provider_registry: settings.provider_registry,
147
+ route_policy: settings.route_policy,
148
+ provider_session_pins: settings.provider_session_pins,
149
+ client_capability_sha256: settings.client_capability_sha256,
150
+ allowed_origins: settings.allowed_origins,
151
+ connect_timeout_ms: settings.connect_timeout_ms,
152
+ idle_timeout_ms: settings.idle_timeout_ms
153
+ }, null, 2)}\n`;
154
+ }
155
+ export async function bridgeBaseUrl(settings, options) {
156
+ const host = settings.listen_host === '::1' ? '[::1]' : settings.listen_host;
157
+ return bridgeClientUrl(`http://${host}:${settings.listen_port}`, '/backend-api/codex', options, settings.client_capability_sha256);
158
+ }
159
+ export async function bridgeClientUrl(loopbackOrigin, canonicalPath, options, expectedCapabilitySha256) {
160
+ const origin = validatedBridgeClientOrigin(loopbackOrigin);
161
+ const home = path.resolve(options.home || controllerEnv(options).HOME || os.homedir());
162
+ const capabilityPath = path.resolve(options.clientCapabilityPath || desktopBridgeServicePaths(home).client_capability_path);
163
+ const capability = await readDesktopBridgeClientCapability(capabilityPath);
164
+ if (expectedCapabilitySha256
165
+ && createHash('sha256').update(capability).digest('hex') !== expectedCapabilitySha256) {
166
+ throw new Error('desktop_bridge_client_capability_mismatch');
167
+ }
168
+ return `${origin}${desktopBridgeClientPath(capability, canonicalPath)}`;
169
+ }
170
+ function validatedBridgeClientOrigin(value) {
171
+ let parsed;
172
+ try {
173
+ parsed = new URL(String(value || ''));
174
+ }
175
+ catch {
176
+ throw new Error('desktop_bridge_loopback_origin_invalid');
177
+ }
178
+ const hostname = parsed.hostname.replace(/^\[|\]$/g, '').toLowerCase();
179
+ const port = Number(parsed.port);
180
+ if (!['http:', 'ws:'].includes(parsed.protocol)
181
+ || !['127.0.0.1', '::1', 'localhost'].includes(hostname)
182
+ || !Number.isInteger(port)
183
+ || port < 49_152
184
+ || port > 65_535
185
+ || parsed.username
186
+ || parsed.password
187
+ || (parsed.pathname !== '/' && parsed.pathname !== '')
188
+ || parsed.search
189
+ || parsed.hash) {
190
+ throw new Error('desktop_bridge_loopback_origin_invalid');
191
+ }
192
+ return parsed.origin;
193
+ }
194
+ export function serviceLoopbackOrigin(service) {
195
+ if (service.state?.listen_origin)
196
+ return service.state.listen_origin;
197
+ const settings = service.settings;
198
+ if (!settings)
199
+ return null;
200
+ const host = settings.listen_host === '::1' ? '[::1]' : settings.listen_host;
201
+ return `http://${host}:${settings.listen_port}`;
202
+ }
203
+ export function commandResult(operation, executionOk, status, result, blockers, options) {
204
+ const checkedAt = nowIso(options);
205
+ const readiness = status?.readiness || { ready: false, blockers: [...blockers], warnings: [] };
206
+ return {
207
+ schema: 'sks.desktop-bridge-command-result.v1',
208
+ operation,
209
+ operation_id: makeId('operation', options),
210
+ correlation_id: status?.correlation_id || makeId('correlation', options),
211
+ checked_at: checkedAt,
212
+ ok: executionOk,
213
+ execution: {
214
+ ok: executionOk,
215
+ status: executionOk ? (blockers.length > 0 ? 'partial' : 'completed') : 'failed',
216
+ blockers: unique(blockers)
217
+ },
218
+ readiness: {
219
+ ready: readiness.ready,
220
+ blockers: [...readiness.blockers],
221
+ warnings: [...readiness.warnings]
222
+ },
223
+ status,
224
+ result,
225
+ recovery_action: blockers.length > 0 ? recoveryActions(blockers)[0] || 'review_bridge_status' : null
226
+ };
227
+ }
228
+ export function emptyScope(scope, checkedAt) {
229
+ return {
230
+ schema: 'sks.scope-capability-summary.v1',
231
+ scope,
232
+ state: 'not_attempted',
233
+ checked_at: checkedAt,
234
+ capabilities: {},
235
+ blockers: [],
236
+ warnings: []
237
+ };
238
+ }
239
+ export function recoveryActions(blockers) {
240
+ return unique(blockers.map((blocker) => {
241
+ if (blocker.includes('credential') && blocker.includes('codex'))
242
+ return 'configure_codex_lb_credential';
243
+ if (blocker.includes('credential') && blocker.includes('openrouter'))
244
+ return 'configure_openrouter_credential';
245
+ if (blocker.includes('catalog') || blocker.includes('route'))
246
+ return 'retry_catalog_sync';
247
+ if (blocker.includes('oauth'))
248
+ return 'review_desktop_authentication';
249
+ if (blocker.includes('bridge'))
250
+ return 'repair_bridge_service';
251
+ return 'review_bridge_status';
252
+ }));
253
+ }
254
+ export function controllerEnv(options) {
255
+ const home = options.home || options.env?.HOME || process.env.HOME || os.homedir();
256
+ return { ...process.env, ...(options.env || {}), HOME: home };
257
+ }
258
+ export function timeoutMs(options) {
259
+ return Math.max(500, Math.min(30_000, Number(options.timeoutMs || 10_000)));
260
+ }
261
+ export function nowIso(options) {
262
+ return (options.now ? options.now() : new Date()).toISOString();
263
+ }
264
+ export function makeId(prefix, options) {
265
+ return `${prefix}-${options.id ? options.id() : randomUUID()}`;
266
+ }
267
+ export function providerCode(providerId) {
268
+ return providerId === 'codex-lb' ? 'codex_lb' : 'openrouter';
269
+ }
270
+ export function safeCode(error, fallback) {
271
+ const message = error instanceof Error ? error.message : String(error || '');
272
+ return /^[a-z0-9_:/.-]{1,240}$/i.test(message) ? message : fallback;
273
+ }
274
+ export function stringArray(value) {
275
+ return Array.isArray(value) ? value.map(String).filter(Boolean) : [];
276
+ }
277
+ export function unique(values) {
278
+ return [...new Set(values.map((value) => String(value || '').trim()).filter(Boolean))];
279
+ }