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,104 @@
1
+ import { EVIDENCE_SOURCES, LEVELS, PROBE_STAGES, PROBE_STATES, booleanValue, enumValue, escapePath, exact, integer, iso, literal, nonEmptyString, nullableString, object, stringArray } from './shared.js';
2
+ export function validateExecution(value, path, issues) {
3
+ const row = object(value, path, issues);
4
+ if (!row)
5
+ return;
6
+ exact(row, path, ['ok', 'status', 'blockers'], issues);
7
+ booleanValue(row.ok, `${path}.ok`, issues);
8
+ enumValue(row.status, new Set(['completed', 'partial', 'failed']), `${path}.status`, issues);
9
+ stringArray(row.blockers, `${path}.blockers`, issues);
10
+ if (row.ok === true && row.status === 'failed')
11
+ issues.push(`${path}:execution_state_inconsistent`);
12
+ if (row.ok === false && row.status !== 'failed')
13
+ issues.push(`${path}:execution_state_inconsistent`);
14
+ }
15
+ export function validateScope(value, expectedScope, report, path, issues) {
16
+ const row = object(value, path, issues);
17
+ if (!row)
18
+ return;
19
+ exact(row, path, ['schema', 'scope', 'state', 'checked_at', 'capabilities', 'blockers', 'warnings'], issues);
20
+ literal(row.schema, 'sks.scope-capability-summary.v1', `${path}.schema`, issues);
21
+ literal(row.scope, expectedScope, `${path}.scope`, issues);
22
+ enumValue(row.state, PROBE_STATES, `${path}.state`, issues);
23
+ iso(row.checked_at, `${path}.checked_at`, issues);
24
+ stringArray(row.blockers, `${path}.blockers`, issues);
25
+ stringArray(row.warnings, `${path}.warnings`, issues);
26
+ const capabilities = object(row.capabilities, `${path}.capabilities`, issues);
27
+ if (!capabilities)
28
+ return;
29
+ for (const [name, probe] of Object.entries(capabilities)) {
30
+ validateProbe(probe, name, expectedScope, report, `${path}.capabilities.${escapePath(name)}`, issues);
31
+ }
32
+ }
33
+ function validateProbe(value, capability, scope, report, path, issues) {
34
+ const row = object(value, path, issues);
35
+ if (!row)
36
+ return;
37
+ exact(row, path, [
38
+ 'schema', 'capability', 'scope', 'requested_level', 'stage', 'state',
39
+ 'checked_at', 'report_id', 'correlation_id', 'session_id', 'attempt_id',
40
+ 'terminal', 'root_cause', 'blockers', 'warnings', 'retryable',
41
+ 'recovery_action', 'source', 'evidence'
42
+ ], issues);
43
+ literal(row.schema, 'sks.capability-probe.v3', `${path}.schema`, issues);
44
+ literal(row.capability, capability, `${path}.capability`, issues);
45
+ literal(row.scope, scope, `${path}.scope`, issues);
46
+ enumValue(row.requested_level, LEVELS, `${path}.requested_level`, issues);
47
+ if (report)
48
+ literal(row.requested_level, report.requested_level, `${path}.requested_level`, issues);
49
+ enumValue(row.stage, PROBE_STAGES, `${path}.stage`, issues);
50
+ enumValue(row.state, PROBE_STATES, `${path}.state`, issues);
51
+ iso(row.checked_at, `${path}.checked_at`, issues);
52
+ nonEmptyString(row.report_id, `${path}.report_id`, issues);
53
+ nonEmptyString(row.correlation_id, `${path}.correlation_id`, issues);
54
+ nonEmptyString(row.session_id, `${path}.session_id`, issues);
55
+ if (report) {
56
+ literal(row.report_id, report.report_id, `${path}.report_id`, issues);
57
+ literal(row.correlation_id, report.correlation_id, `${path}.correlation_id`, issues);
58
+ literal(row.session_id, report.session_id, `${path}.session_id`, issues);
59
+ }
60
+ integer(row.attempt_id, `${path}.attempt_id`, issues, 0);
61
+ booleanValue(row.terminal, `${path}.terminal`, issues);
62
+ nullableString(row.root_cause, `${path}.root_cause`, issues);
63
+ stringArray(row.blockers, `${path}.blockers`, issues);
64
+ stringArray(row.warnings, `${path}.warnings`, issues);
65
+ booleanValue(row.retryable, `${path}.retryable`, issues);
66
+ nullableString(row.recovery_action, `${path}.recovery_action`, issues);
67
+ enumValue(row.source, EVIDENCE_SOURCES, `${path}.source`, issues);
68
+ object(row.evidence, `${path}.evidence`, issues);
69
+ const blockers = Array.isArray(row.blockers) ? row.blockers : [];
70
+ if (row.terminal === true && typeof row.root_cause !== 'string') {
71
+ issues.push(`${path}:terminal_root_cause_missing`);
72
+ }
73
+ if (typeof row.root_cause === 'string' && !blockers.includes(row.root_cause)) {
74
+ issues.push(`${path}:root_cause_not_in_blockers`);
75
+ }
76
+ if (row.state === 'verified' && (row.root_cause !== null || blockers.length > 0)) {
77
+ issues.push(`${path}:verified_with_failure`);
78
+ }
79
+ if (row.state === 'not_attempted' && (row.root_cause !== null
80
+ || blockers.length > 0
81
+ || row.terminal !== false))
82
+ issues.push(`${path}:not_attempted_with_failure`);
83
+ }
84
+ export function validateCapabilitySummary(value, path, issues) {
85
+ const row = object(value, path, issues);
86
+ if (!row)
87
+ return;
88
+ exact(row, path, [
89
+ 'bridge_ready', 'active_routes_ready', 'level_satisfied',
90
+ 'transport_level_satisfied', 'deep_level_satisfied', 'full_feature_verified',
91
+ 'inactive_provider_failures', 'blockers', 'warnings'
92
+ ], issues);
93
+ for (const key of [
94
+ 'bridge_ready', 'active_routes_ready', 'level_satisfied',
95
+ 'transport_level_satisfied', 'deep_level_satisfied', 'full_feature_verified'
96
+ ])
97
+ booleanValue(row[key], `${path}.${key}`, issues);
98
+ stringArray(row.inactive_provider_failures, `${path}.inactive_provider_failures`, issues);
99
+ stringArray(row.blockers, `${path}.blockers`, issues);
100
+ stringArray(row.warnings, `${path}.warnings`, issues);
101
+ if (row.full_feature_verified === true && row.deep_level_satisfied !== true) {
102
+ issues.push(`${path}:full_feature_without_deep`);
103
+ }
104
+ }
@@ -0,0 +1,52 @@
1
+ import { CATALOG_STATES, PROVIDERS, enumValue, exact, integer, literal, nullableInteger, nullableIso, nullableString, object, stringArray } from './shared.js';
2
+ export function validateCombinedCatalog(value, path, issues) {
3
+ const row = object(value, path, issues);
4
+ if (!row)
5
+ return;
6
+ exact(row, path, [
7
+ 'schema', 'state', 'generation', 'digest', 'model_count', 'route_count',
8
+ 'conflict_count', 'checked_at', 'providers', 'blockers', 'warnings',
9
+ 'recovery_action'
10
+ ], issues);
11
+ literal(row.schema, 'sks.combined-catalog-sync.v1', `${path}.schema`, issues);
12
+ enumValue(row.state, CATALOG_STATES, `${path}.state`, issues);
13
+ nullableString(row.generation, `${path}.generation`, issues);
14
+ nullableString(row.digest, `${path}.digest`, issues);
15
+ nullableInteger(row.model_count, `${path}.model_count`, issues);
16
+ nullableInteger(row.route_count, `${path}.route_count`, issues);
17
+ integer(row.conflict_count, `${path}.conflict_count`, issues, 0);
18
+ nullableIso(row.checked_at, `${path}.checked_at`, issues);
19
+ const providers = object(row.providers, `${path}.providers`, issues);
20
+ if (providers) {
21
+ exact(providers, `${path}.providers`, [...PROVIDERS], issues);
22
+ validateCatalogState(providers['codex-lb'], 'codex-lb', `${path}.providers.codex-lb`, issues);
23
+ validateCatalogState(providers.openrouter, 'openrouter', `${path}.providers.openrouter`, issues);
24
+ }
25
+ stringArray(row.blockers, `${path}.blockers`, issues);
26
+ stringArray(row.warnings, `${path}.warnings`, issues);
27
+ nullableString(row.recovery_action, `${path}.recovery_action`, issues);
28
+ }
29
+ export function validateCatalogState(value, provider, path, issues) {
30
+ const row = object(value, path, issues);
31
+ if (!row)
32
+ return;
33
+ exact(row, path, [
34
+ 'schema', 'provider_id', 'state', 'source', 'generation', 'digest',
35
+ 'model_count', 'checked_at', 'expires_at', 'blockers', 'warnings',
36
+ 'recovery_action'
37
+ ], issues);
38
+ literal(row.schema, 'sks.catalog-sync-state.v2', `${path}.schema`, issues);
39
+ literal(row.provider_id, provider, `${path}.provider_id`, issues);
40
+ enumValue(row.state, CATALOG_STATES, `${path}.state`, issues);
41
+ if (row.source !== null) {
42
+ literal(row.source, provider === 'codex-lb' ? 'gateway' : 'openrouter', `${path}.source`, issues);
43
+ }
44
+ nullableString(row.generation, `${path}.generation`, issues);
45
+ nullableString(row.digest, `${path}.digest`, issues);
46
+ nullableInteger(row.model_count, `${path}.model_count`, issues);
47
+ nullableIso(row.checked_at, `${path}.checked_at`, issues);
48
+ nullableIso(row.expires_at, `${path}.expires_at`, issues);
49
+ stringArray(row.blockers, `${path}.blockers`, issues);
50
+ stringArray(row.warnings, `${path}.warnings`, issues);
51
+ nullableString(row.recovery_action, `${path}.recovery_action`, issues);
52
+ }
@@ -0,0 +1,109 @@
1
+ export const PROVIDERS = ['codex-lb', 'openrouter'];
2
+ export const LEVELS = new Set(['shallow', 'transport', 'deep']);
3
+ export const PROBE_STATES = new Set([
4
+ 'not_attempted', 'running', 'verified', 'degraded', 'blocked', 'failed',
5
+ 'unsupported', 'stale'
6
+ ]);
7
+ export const PROBE_STAGES = new Set([
8
+ 'preflight', 'process', 'tcp_connect', 'http_health', 'websocket_upgrade',
9
+ 'websocket_protocol', 'frame_round_trip', 'clean_close', 'provider_auth',
10
+ 'catalog_sync', 'model_route', 'feature_request', 'feature_response',
11
+ 'artifact_validation', 'complete'
12
+ ]);
13
+ export const EVIDENCE_SOURCES = new Set([
14
+ 'config', 'manifest', 'transport', 'desktop_ui', 'deep_probe', 'artifact'
15
+ ]);
16
+ export const CATALOG_STATES = new Set([
17
+ 'not_started', 'syncing', 'verified', 'degraded', 'failed', 'stale'
18
+ ]);
19
+ const FORBIDDEN_SECRET_KEY = /^(?:api_?key|secret|token|authorization|cookie|set_cookie|password|bearer|headers?|env)$/i;
20
+ export function object(value, path, issues) {
21
+ if (!value || typeof value !== 'object' || Array.isArray(value)) {
22
+ issues.push(`${path}:object_required`);
23
+ return null;
24
+ }
25
+ return value;
26
+ }
27
+ export function record(value) {
28
+ return value && typeof value === 'object' && !Array.isArray(value)
29
+ ? value
30
+ : null;
31
+ }
32
+ export function exact(row, path, expected, issues) {
33
+ const allowed = new Set(expected);
34
+ for (const key of expected) {
35
+ if (!Object.hasOwn(row, key))
36
+ issues.push(`${path}.${escapePath(key)}:required`);
37
+ }
38
+ for (const key of Object.keys(row)) {
39
+ if (!allowed.has(key))
40
+ issues.push(`${path}.${escapePath(key)}:unexpected`);
41
+ }
42
+ }
43
+ export function literal(value, expected, path, issues) {
44
+ if (value !== expected)
45
+ issues.push(`${path}:expected_${String(expected)}`);
46
+ }
47
+ export function enumValue(value, allowed, path, issues) {
48
+ if (typeof value !== 'string' || !allowed.has(value))
49
+ issues.push(`${path}:enum`);
50
+ }
51
+ export function nonEmptyString(value, path, issues) {
52
+ if (typeof value !== 'string' || !value.trim())
53
+ issues.push(`${path}:non_empty_string_required`);
54
+ }
55
+ export function nullableString(value, path, issues) {
56
+ if (value !== null && typeof value !== 'string')
57
+ issues.push(`${path}:nullable_string_required`);
58
+ }
59
+ export function booleanValue(value, path, issues) {
60
+ if (typeof value !== 'boolean')
61
+ issues.push(`${path}:boolean_required`);
62
+ }
63
+ export function integer(value, path, issues, minimum) {
64
+ if (!Number.isInteger(value) || (minimum !== undefined && Number(value) < minimum)) {
65
+ issues.push(`${path}:integer_required`);
66
+ }
67
+ }
68
+ export function nullableInteger(value, path, issues) {
69
+ if (value !== null && (!Number.isInteger(value) || Number(value) < 0)) {
70
+ issues.push(`${path}:nullable_integer_required`);
71
+ }
72
+ }
73
+ export function nullableNumber(value, path, issues) {
74
+ if (value !== null && (typeof value !== 'number' || !Number.isFinite(value) || value < 0)) {
75
+ issues.push(`${path}:nullable_number_required`);
76
+ }
77
+ }
78
+ export function iso(value, path, issues) {
79
+ if (typeof value !== 'string' || !Number.isFinite(Date.parse(value))) {
80
+ issues.push(`${path}:iso_timestamp_required`);
81
+ }
82
+ }
83
+ export function nullableIso(value, path, issues) {
84
+ if (value !== null)
85
+ iso(value, path, issues);
86
+ }
87
+ export function stringArray(value, path, issues) {
88
+ if (!Array.isArray(value) || value.some((entry) => typeof entry !== 'string')) {
89
+ issues.push(`${path}:string_array_required`);
90
+ }
91
+ }
92
+ export function scanForbiddenKeys(value, path, issues) {
93
+ if (Array.isArray(value)) {
94
+ value.forEach((entry, index) => scanForbiddenKeys(entry, `${path}[${index}]`, issues));
95
+ return;
96
+ }
97
+ const row = record(value);
98
+ if (!row)
99
+ return;
100
+ for (const [key, entry] of Object.entries(row)) {
101
+ const nextPath = `${path}.${escapePath(key)}`;
102
+ if (FORBIDDEN_SECRET_KEY.test(key))
103
+ issues.push(`${nextPath}:secret_field_forbidden`);
104
+ scanForbiddenKeys(entry, nextPath, issues);
105
+ }
106
+ }
107
+ export function escapePath(value) {
108
+ return /^[A-Za-z_$][\w$-]*$/.test(value) ? value : JSON.stringify(value);
109
+ }
@@ -0,0 +1,250 @@
1
+ import { validateScope } from './capability.js';
2
+ import { validateCatalogState } from './catalog.js';
3
+ import { PROBE_STATES, PROVIDERS, booleanValue, enumValue, escapePath, exact, iso, literal, nonEmptyString, nullableInteger, nullableIso, nullableNumber, nullableString, object, stringArray } from './shared.js';
4
+ export function validateManagement(value, path, issues) {
5
+ const row = object(value, path, issues);
6
+ if (!row)
7
+ return;
8
+ exact(row, path, ['managed', 'runtime', 'state', 'reason'], issues);
9
+ booleanValue(row.managed, `${path}.managed`, issues);
10
+ if (row.managed === true) {
11
+ literal(row.runtime, 'desktop-bridge', `${path}.runtime`, issues);
12
+ literal(row.reason, null, `${path}.reason`, issues);
13
+ enumValue(row.state, new Set([
14
+ 'not_installed', 'starting', 'ready', 'degraded', 'blocked', 'stopped', 'stale'
15
+ ]), `${path}.state`, issues);
16
+ }
17
+ else if (row.managed === false) {
18
+ literal(row.runtime, null, `${path}.runtime`, issues);
19
+ enumValue(row.state, new Set(['not_installed', 'stopped']), `${path}.state`, issues);
20
+ enumValue(row.reason, new Set([
21
+ 'uninstalled', 'rollback_complete', 'never_configured'
22
+ ]), `${path}.reason`, issues);
23
+ }
24
+ }
25
+ export function validateService(value, path, issues) {
26
+ const row = object(value, path, issues);
27
+ if (!row)
28
+ return;
29
+ exact(row, path, [
30
+ 'state', 'installed', 'loaded', 'running', 'loopback_origin', 'pid',
31
+ 'checked_at', 'blockers', 'warnings'
32
+ ], issues);
33
+ enumValue(row.state, new Set([
34
+ 'not_installed', 'starting', 'ready', 'degraded', 'blocked', 'stopped', 'stale'
35
+ ]), `${path}.state`, issues);
36
+ booleanValue(row.installed, `${path}.installed`, issues);
37
+ booleanValue(row.loaded, `${path}.loaded`, issues);
38
+ booleanValue(row.running, `${path}.running`, issues);
39
+ nullableString(row.loopback_origin, `${path}.loopback_origin`, issues);
40
+ nullableInteger(row.pid, `${path}.pid`, issues);
41
+ iso(row.checked_at, `${path}.checked_at`, issues);
42
+ stringArray(row.blockers, `${path}.blockers`, issues);
43
+ stringArray(row.warnings, `${path}.warnings`, issues);
44
+ }
45
+ export function validateHttpProbeResult(value, path, issues) {
46
+ const row = object(value, path, issues);
47
+ if (!row)
48
+ return;
49
+ exact(row, path, [
50
+ 'schema', 'state', 'terminal_stage', 'root_cause', 'status_code',
51
+ 'latency_ms', 'blockers', 'warnings'
52
+ ], issues);
53
+ literal(row.schema, 'sks.desktop-bridge-http-probe.v1', `${path}.schema`, issues);
54
+ enumValue(row.state, new Set(['verified', 'blocked', 'failed', 'unsupported']), `${path}.state`, issues);
55
+ enumValue(row.terminal_stage, new Set([
56
+ 'tcp_connect', 'http_health', 'complete'
57
+ ]), `${path}.terminal_stage`, issues);
58
+ nullableString(row.root_cause, `${path}.root_cause`, issues);
59
+ nullableInteger(row.status_code, `${path}.status_code`, issues);
60
+ nullableNumber(row.latency_ms, `${path}.latency_ms`, issues);
61
+ stringArray(row.blockers, `${path}.blockers`, issues);
62
+ stringArray(row.warnings, `${path}.warnings`, issues);
63
+ if (row.state === 'verified' && (row.terminal_stage !== 'complete' || row.root_cause !== null)) {
64
+ issues.push(`${path}:verified_http_incomplete`);
65
+ }
66
+ }
67
+ export function validateWebSocketProbeResult(value, path, issues) {
68
+ const row = object(value, path, issues);
69
+ if (!row)
70
+ return;
71
+ exact(row, path, [
72
+ 'schema', 'state', 'terminal_stage', 'root_cause', 'status_code',
73
+ 'negotiated_protocol', 'upgrade_verified', 'protocol_verified',
74
+ 'frame_round_trip_verified', 'clean_close_verified', 'latency_ms',
75
+ 'blockers', 'warnings'
76
+ ], issues);
77
+ literal(row.schema, 'sks.desktop-bridge-websocket-probe.v2', `${path}.schema`, issues);
78
+ enumValue(row.state, new Set([
79
+ 'not_attempted', 'verified', 'degraded', 'blocked', 'failed', 'unsupported'
80
+ ]), `${path}.state`, issues);
81
+ enumValue(row.terminal_stage, new Set([
82
+ 'tcp_connect', 'websocket_upgrade', 'websocket_protocol', 'frame_round_trip',
83
+ 'clean_close', 'complete'
84
+ ]), `${path}.terminal_stage`, issues);
85
+ nullableString(row.root_cause, `${path}.root_cause`, issues);
86
+ nullableInteger(row.status_code, `${path}.status_code`, issues);
87
+ nullableString(row.negotiated_protocol, `${path}.negotiated_protocol`, issues);
88
+ for (const key of [
89
+ 'upgrade_verified', 'protocol_verified', 'frame_round_trip_verified', 'clean_close_verified'
90
+ ])
91
+ booleanValue(row[key], `${path}.${key}`, issues);
92
+ nullableNumber(row.latency_ms, `${path}.latency_ms`, issues);
93
+ stringArray(row.blockers, `${path}.blockers`, issues);
94
+ stringArray(row.warnings, `${path}.warnings`, issues);
95
+ if (row.state === 'verified' && (row.terminal_stage !== 'complete'
96
+ || row.root_cause !== null
97
+ || row.upgrade_verified !== true
98
+ || row.protocol_verified !== true
99
+ || row.frame_round_trip_verified !== true
100
+ || row.clean_close_verified !== true))
101
+ issues.push(`${path}:verified_websocket_incomplete`);
102
+ if (row.state === 'not_attempted' && (row.root_cause !== null
103
+ || (Array.isArray(row.blockers) && row.blockers.length > 0)))
104
+ issues.push(`${path}:not_attempted_websocket_with_failure`);
105
+ }
106
+ export function validateNativeIdentity(value, path, issues) {
107
+ const row = object(value, path, issues);
108
+ if (!row)
109
+ return;
110
+ exact(row, path, [
111
+ 'state', 'configured', 'semantic_identity_preserved', 'checked_at', 'blockers', 'warnings'
112
+ ], issues);
113
+ enumValue(row.state, PROBE_STATES, `${path}.state`, issues);
114
+ booleanValue(row.configured, `${path}.configured`, issues);
115
+ if (row.semantic_identity_preserved !== null) {
116
+ booleanValue(row.semantic_identity_preserved, `${path}.semantic_identity_preserved`, issues);
117
+ }
118
+ nullableIso(row.checked_at, `${path}.checked_at`, issues);
119
+ stringArray(row.blockers, `${path}.blockers`, issues);
120
+ stringArray(row.warnings, `${path}.warnings`, issues);
121
+ }
122
+ export function validateProviderProfile(value, provider, path, issues) {
123
+ const row = object(value, path, issues);
124
+ if (!row)
125
+ return;
126
+ exact(row, path, [
127
+ 'schema', 'provider_id', 'enabled', 'credential', 'endpoint', 'catalog', 'capabilities'
128
+ ], issues);
129
+ literal(row.schema, 'sks.bridge-provider-profile-status.v1', `${path}.schema`, issues);
130
+ literal(row.provider_id, provider, `${path}.provider_id`, issues);
131
+ booleanValue(row.enabled, `${path}.enabled`, issues);
132
+ validateCredential(row.credential, `${path}.credential`, issues);
133
+ validateEndpoint(row.endpoint, `${path}.endpoint`, issues);
134
+ validateCatalogState(row.catalog, provider, `${path}.catalog`, issues);
135
+ validateScope(row.capabilities, `provider:${provider}`, null, `${path}.capabilities`, issues);
136
+ }
137
+ function validateCredential(value, path, issues) {
138
+ const row = object(value, path, issues);
139
+ if (!row)
140
+ return;
141
+ exact(row, path, ['state', 'source', 'fingerprint', 'checked_at', 'blockers', 'warnings'], issues);
142
+ enumValue(row.state, new Set([
143
+ 'not_configured', 'configured_unverified', 'validating', 'ready', 'rejected',
144
+ 'unavailable', 'stale'
145
+ ]), `${path}.state`, issues);
146
+ nullableString(row.source, `${path}.source`, issues);
147
+ nullableString(row.fingerprint, `${path}.fingerprint`, issues);
148
+ nullableIso(row.checked_at, `${path}.checked_at`, issues);
149
+ stringArray(row.blockers, `${path}.blockers`, issues);
150
+ stringArray(row.warnings, `${path}.warnings`, issues);
151
+ }
152
+ function validateEndpoint(value, path, issues) {
153
+ const row = object(value, path, issues);
154
+ if (!row)
155
+ return;
156
+ exact(row, path, ['configured', 'origin_redacted', 'auth_transport'], issues);
157
+ booleanValue(row.configured, `${path}.configured`, issues);
158
+ nullableString(row.origin_redacted, `${path}.origin_redacted`, issues);
159
+ if (row.auth_transport !== null) {
160
+ enumValue(row.auth_transport, new Set([
161
+ 'authorization-bearer', 'x-codex-lb-api-key', 'openrouter-bearer'
162
+ ]), `${path}.auth_transport`, issues);
163
+ }
164
+ }
165
+ export function validateRouting(value, path, issues) {
166
+ const row = object(value, path, issues);
167
+ if (!row)
168
+ return;
169
+ exact(row, path, [
170
+ 'policy', 'selected_model', 'selected_route', 'session_pin', 'fallback',
171
+ 'blockers', 'warnings'
172
+ ], issues);
173
+ if (row.policy !== null)
174
+ validatePolicy(row.policy, `${path}.policy`, issues);
175
+ nullableString(row.selected_model, `${path}.selected_model`, issues);
176
+ if (row.selected_route !== null) {
177
+ validateRouteTarget(row.selected_route, `${path}.selected_route`, issues);
178
+ }
179
+ if (row.session_pin !== null)
180
+ validateSessionPin(row.session_pin, `${path}.session_pin`, issues);
181
+ literal(row.fallback, 'none', `${path}.fallback`, issues);
182
+ stringArray(row.blockers, `${path}.blockers`, issues);
183
+ stringArray(row.warnings, `${path}.warnings`, issues);
184
+ }
185
+ function validateSessionPin(value, path, issues) {
186
+ const row = object(value, path, issues);
187
+ if (!row)
188
+ return;
189
+ exact(row, path, [
190
+ 'thread_id', 'provider_id', 'public_model', 'upstream_model',
191
+ 'catalog_generation', 'route_policy_generation', 'created_at'
192
+ ], issues);
193
+ for (const key of [
194
+ 'thread_id', 'public_model', 'upstream_model', 'catalog_generation', 'route_policy_generation'
195
+ ])
196
+ nonEmptyString(row[key], `${path}.${key}`, issues);
197
+ enumValue(row.provider_id, new Set(PROVIDERS), `${path}.provider_id`, issues);
198
+ iso(row.created_at, `${path}.created_at`, issues);
199
+ }
200
+ function validatePolicy(value, path, issues) {
201
+ const row = object(value, path, issues);
202
+ if (!row)
203
+ return;
204
+ exact(row, path, [
205
+ 'schema', 'default_provider_id', 'fallback', 'model_routes',
206
+ 'catalog_generation', 'policy_generation', 'changed_at'
207
+ ], issues);
208
+ literal(row.schema, 'sks.bridge-routing-policy.v1', `${path}.schema`, issues);
209
+ if (row.default_provider_id !== null) {
210
+ enumValue(row.default_provider_id, new Set(PROVIDERS), `${path}.default_provider_id`, issues);
211
+ }
212
+ literal(row.fallback, 'none', `${path}.fallback`, issues);
213
+ const routes = object(row.model_routes, `${path}.model_routes`, issues);
214
+ if (routes) {
215
+ for (const [model, target] of Object.entries(routes)) {
216
+ validateRouteTarget(target, `${path}.model_routes.${escapePath(model)}`, issues);
217
+ }
218
+ }
219
+ nonEmptyString(row.catalog_generation, `${path}.catalog_generation`, issues);
220
+ nonEmptyString(row.policy_generation, `${path}.policy_generation`, issues);
221
+ iso(row.changed_at, `${path}.changed_at`, issues);
222
+ }
223
+ function validateRouteTarget(value, path, issues) {
224
+ const row = object(value, path, issues);
225
+ if (!row)
226
+ return;
227
+ exact(row, path, ['provider_id', 'upstream_model'], issues);
228
+ enumValue(row.provider_id, new Set(PROVIDERS), `${path}.provider_id`, issues);
229
+ nonEmptyString(row.upstream_model, `${path}.upstream_model`, issues);
230
+ }
231
+ export function validateReadiness(value, path, issues) {
232
+ const row = object(value, path, issues);
233
+ if (!row)
234
+ return;
235
+ exact(row, path, [
236
+ 'ready', 'state', 'bridge_ready', 'active_routes_ready',
237
+ 'combined_catalog_ready', 'blockers', 'warnings'
238
+ ], issues);
239
+ for (const key of [
240
+ 'ready', 'bridge_ready', 'active_routes_ready', 'combined_catalog_ready'
241
+ ])
242
+ booleanValue(row[key], `${path}.${key}`, issues);
243
+ enumValue(row.state, new Set([
244
+ 'ready', 'awaiting_provider', 'degraded', 'blocked', 'unmanaged'
245
+ ]), `${path}.state`, issues);
246
+ stringArray(row.blockers, `${path}.blockers`, issues);
247
+ stringArray(row.warnings, `${path}.warnings`, issues);
248
+ if (row.ready === true && row.state !== 'ready')
249
+ issues.push(`${path}:ready_state_inconsistent`);
250
+ }
@@ -0,0 +1,106 @@
1
+ import { validateCapabilitySummary, validateExecution, validateScope } from './bridge-runtime-validation/capability.js';
2
+ import { validateCombinedCatalog } from './bridge-runtime-validation/catalog.js';
3
+ import { LEVELS, PROVIDERS, enumValue, exact, iso, literal, nonEmptyString, nullableString, object, record, scanForbiddenKeys, stringArray } from './bridge-runtime-validation/shared.js';
4
+ import { validateHttpProbeResult, validateManagement, validateNativeIdentity, validateProviderProfile, validateReadiness, validateRouting, validateService, validateWebSocketProbeResult } from './bridge-runtime-validation/status.js';
5
+ export function validateDesktopCapabilityReportV3(value) {
6
+ const issues = [];
7
+ const report = object(value, '$', issues);
8
+ if (!report)
9
+ return result(issues);
10
+ exact(report, '$', [
11
+ 'schema', 'report_id', 'correlation_id', 'session_id', 'requested_level',
12
+ 'checked_at', 'catalog_generation', 'execution', 'bridge', 'native_identity',
13
+ 'providers', 'combined_catalog', 'summary', 'catalog_sync'
14
+ ], issues);
15
+ literal(report.schema, 'sks.desktop-capabilities.v3', '$.schema', issues);
16
+ nonEmptyString(report.report_id, '$.report_id', issues);
17
+ nonEmptyString(report.correlation_id, '$.correlation_id', issues);
18
+ nonEmptyString(report.session_id, '$.session_id', issues);
19
+ enumValue(report.requested_level, LEVELS, '$.requested_level', issues);
20
+ iso(report.checked_at, '$.checked_at', issues);
21
+ nullableString(report.catalog_generation, '$.catalog_generation', issues);
22
+ validateExecution(report.execution, '$.execution', issues);
23
+ validateScope(report.bridge, 'bridge', report, '$.bridge', issues);
24
+ validateScope(report.native_identity, 'native-identity', report, '$.native_identity', issues);
25
+ const providers = object(report.providers, '$.providers', issues);
26
+ if (providers) {
27
+ exact(providers, '$.providers', [...PROVIDERS], issues);
28
+ validateScope(providers['codex-lb'], 'provider:codex-lb', report, '$.providers.codex-lb', issues);
29
+ validateScope(providers.openrouter, 'provider:openrouter', report, '$.providers.openrouter', issues);
30
+ }
31
+ validateScope(report.combined_catalog, 'catalog:combined', report, '$.combined_catalog', issues);
32
+ validateCapabilitySummary(report.summary, '$.summary', issues);
33
+ validateCombinedCatalog(report.catalog_sync, '$.catalog_sync', issues);
34
+ const catalog = record(report.catalog_sync);
35
+ if (catalog && report.catalog_generation !== catalog.generation) {
36
+ issues.push('$.catalog_generation:catalog_generation_mismatch');
37
+ }
38
+ scanForbiddenKeys(value, '$', issues);
39
+ return result(issues);
40
+ }
41
+ export function validateDesktopBridgeStatusV3(value) {
42
+ const issues = [];
43
+ const status = object(value, '$', issues);
44
+ if (!status)
45
+ return result(issues);
46
+ exact(status, '$', [
47
+ 'schema', 'checked_at', 'correlation_id', 'management', 'service', 'http_probe',
48
+ 'websocket_probe', 'native_identity', 'providers', 'routing', 'catalog_sync',
49
+ 'capabilities', 'readiness', 'recovery_actions'
50
+ ], issues);
51
+ literal(status.schema, 'sks.desktop-bridge-status.v3', '$.schema', issues);
52
+ iso(status.checked_at, '$.checked_at', issues);
53
+ nonEmptyString(status.correlation_id, '$.correlation_id', issues);
54
+ validateManagement(status.management, '$.management', issues);
55
+ validateService(status.service, '$.service', issues);
56
+ if (status.http_probe !== null) {
57
+ validateHttpProbeResult(status.http_probe, '$.http_probe', issues);
58
+ }
59
+ if (status.websocket_probe !== null) {
60
+ validateWebSocketProbeResult(status.websocket_probe, '$.websocket_probe', issues);
61
+ }
62
+ validateNativeIdentity(status.native_identity, '$.native_identity', issues);
63
+ const providers = object(status.providers, '$.providers', issues);
64
+ if (providers) {
65
+ exact(providers, '$.providers', [...PROVIDERS], issues);
66
+ validateProviderProfile(providers['codex-lb'], 'codex-lb', '$.providers.codex-lb', issues);
67
+ validateProviderProfile(providers.openrouter, 'openrouter', '$.providers.openrouter', issues);
68
+ }
69
+ validateRouting(status.routing, '$.routing', issues);
70
+ validateCombinedCatalog(status.catalog_sync, '$.catalog_sync', issues);
71
+ if (status.capabilities !== null) {
72
+ const reportValidation = validateDesktopCapabilityReportV3(status.capabilities);
73
+ issues.push(...reportValidation.issues.map((issue) => `$.capabilities${issue.slice(1)}`));
74
+ const capability = record(status.capabilities);
75
+ const catalog = record(status.catalog_sync);
76
+ if (capability && catalog && capability.catalog_generation !== catalog.generation) {
77
+ issues.push('$.capabilities.catalog_generation:status_catalog_generation_mismatch');
78
+ }
79
+ }
80
+ validateReadiness(status.readiness, '$.readiness', issues);
81
+ stringArray(status.recovery_actions, '$.recovery_actions', issues);
82
+ scanForbiddenKeys(value, '$', issues);
83
+ return result(issues);
84
+ }
85
+ export function assertDesktopCapabilityReportV3(value) {
86
+ const validation = validateDesktopCapabilityReportV3(value);
87
+ if (!validation.ok) {
88
+ throw new Error(`capability_schema_invalid:${validation.issues[0] || 'unknown'}`);
89
+ }
90
+ }
91
+ export function assertDesktopBridgeStatusV3(value) {
92
+ const validation = validateDesktopBridgeStatusV3(value);
93
+ if (!validation.ok) {
94
+ throw new Error(`desktop_bridge_status_schema_invalid:${validation.issues[0] || 'unknown'}`);
95
+ }
96
+ }
97
+ function result(issues) {
98
+ return { ok: issues.length === 0, issues: [...new Set(issues)] };
99
+ }
100
+ void {};
101
+ void {};
102
+ void {};
103
+ void {};
104
+ void {};
105
+ void {};
106
+ void {};