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
@@ -20,6 +20,114 @@ enum OperationState: String, Codable {
20
20
  case queued, running, waitingForConfirmation, succeeded, failed, cancelled, terminalUncertain
21
21
  }
22
22
 
23
+ /// Diagnostic commands can complete successfully while reporting that runtime
24
+ /// readiness is not satisfied. This metadata deliberately excludes request
25
+ /// bodies, credentials, endpoint query strings, and secret fingerprints.
26
+ struct DiagnosticOperationMetadata: Codable, Equatable {
27
+ let schema: String
28
+ let executionOK: Bool
29
+ let reportGenerated: Bool
30
+ let requestedLevel: String
31
+ let levelSatisfied: Bool
32
+ let fullFeatureVerified: Bool
33
+ let reportId: String
34
+ let correlationId: String
35
+ let attemptId: Int
36
+ let catalogGeneration: String?
37
+
38
+ enum CodingKeys: String, CodingKey { case schema
39
+ case executionOK = "execution_ok", reportGenerated = "report_generated"
40
+ case requestedLevel = "requested_level", levelSatisfied = "level_satisfied"
41
+ case fullFeatureVerified = "full_feature_verified", reportId = "report_id"
42
+ case correlationId = "correlation_id", attemptId = "attempt_id"
43
+ case catalogGeneration = "catalog_generation"
44
+ }
45
+ }
46
+ struct ProviderResponseIdentity: Equatable {
47
+ let requestGeneration: Int
48
+ let reportId: String
49
+ let correlationId: String
50
+ let attemptId: Int
51
+ let checkedAt: Date
52
+ let catalogGeneration: String?
53
+ }
54
+ struct ProviderResponseGate {
55
+ private(set) var activeRequestGeneration = 0
56
+ private(set) var accepted: ProviderResponseIdentity?
57
+ mutating func begin() -> Int { activeRequestGeneration += 1; return activeRequestGeneration }
58
+ mutating func accept(_ candidate: ProviderResponseIdentity) -> Bool {
59
+ guard candidate.requestGeneration == activeRequestGeneration else { return false }
60
+ if let previous = accepted {
61
+ guard candidate.checkedAt > previous.checkedAt
62
+ || candidate.checkedAt == previous.checkedAt && candidate.attemptId >= previous.attemptId else { return false }
63
+ }
64
+ accepted = candidate
65
+ return true
66
+ }
67
+ func statusMayMerge(checkedAt: Date, catalogGeneration: String?) -> Bool {
68
+ guard let accepted = accepted else { return true }
69
+ // Ambient status can advance only the explicitly verified generation.
70
+ guard catalogGeneration == accepted.catalogGeneration else { return false }
71
+ return checkedAt >= accepted.checkedAt
72
+ }
73
+ }
74
+
75
+ enum ProviderRecoveryAction: String, CaseIterable {
76
+ case repairBridgeService = "repair_bridge_service"
77
+ case restartBridgeAndRetry = "restart_bridge_and_retry"
78
+ case inspectBridgeLogs = "inspect_bridge_logs_and_retry_transport"
79
+ case updateBridgeProtocol = "update_bridge_or_codex_protocol"
80
+ case configureCodexLb = "configure_codex_lb_credential"
81
+ case rotateCodexLb = "rotate_codex_lb_credential"
82
+ case configureOpenRouter = "configure_openrouter_credential"
83
+ case rotateOpenRouter = "rotate_openrouter_credential"
84
+ case retryCatalog = "retry_catalog_sync"
85
+ case resolveConflict = "resolve_catalog_route_conflict"
86
+ case refreshCatalog = "refresh_catalog_or_select_supported_model"
87
+ case runDeep = "run_deep_verification"
88
+ case updateMenubar = "update_sks_and_rebuild_menubar"
89
+ case reviewConfig = "review_config_manually"
90
+
91
+ var buttonTitle: String {
92
+ switch self {
93
+ case .repairBridgeService, .restartBridgeAndRetry: return "Repair Bridge"
94
+ case .inspectBridgeLogs: return "Open Diagnostics"
95
+ case .updateBridgeProtocol, .updateMenubar: return "Check for Updates"
96
+ case .configureCodexLb, .rotateCodexLb: return "Configure Codex-LB"
97
+ case .configureOpenRouter, .rotateOpenRouter: return "Configure OpenRouter"
98
+ case .retryCatalog, .resolveConflict, .refreshCatalog: return "Refresh Catalog"
99
+ case .runDeep: return "Verify Deep"
100
+ case .reviewConfig: return "Review Config"
101
+ }
102
+ }
103
+ }
104
+ enum ProviderSecretRedactor {
105
+ private static let patterns = [
106
+ (#"(?i)(authorization\s*:\s*bearer\s+)[^\s,;]+"#, "$1[REDACTED]"),
107
+ (#"(?i)(x-codex-lb-api-key\s*[:=]\s*)[^\s,;]+"#, "$1[REDACTED]"),
108
+ (#"\bsk-(?:clb|or|proj)?-[A-Za-z0-9_-]{6,}\b"#, "[REDACTED]"),
109
+ (#"(?i)(api[_-]?key\s*[:=]\s*)[^\s,;]+"#, "$1[REDACTED]")
110
+ ]
111
+
112
+ static func redact(_ value: String) -> String {
113
+ patterns.reduce(value) { output, entry in
114
+ let (pattern, replacement) = entry
115
+ guard let regex = try? NSRegularExpression(pattern: pattern) else { return output }
116
+ return regex.stringByReplacingMatches(in: output, range: NSRange(output.startIndex..., in: output), withTemplate: replacement)
117
+ }
118
+ }
119
+
120
+ static func redactEndpoint(_ value: String) -> String {
121
+ let cleaned = redact(value)
122
+ guard var components = URLComponents(string: cleaned), components.scheme != nil else { return cleaned }
123
+ components.user = nil
124
+ components.password = nil
125
+ components.query = nil
126
+ components.fragment = nil
127
+ return components.string ?? "[REDACTED ENDPOINT]"
128
+ }
129
+ }
130
+
23
131
  enum OperationProgressSignal: String, Codable, CaseIterable {
24
132
  case evidence, fileChange, testResult, modelResponse, toolResponse, none
25
133
  }
@@ -299,6 +407,7 @@ struct OperationSnapshot: Codable {
299
407
  let registry: String?
300
408
  let recovery: OperationRecoveryStatus?
301
409
  let providerApply: ProviderApplyProjection?
410
+ let diagnostic: DiagnosticOperationMetadata?
302
411
 
303
412
  init(
304
413
  schema: String,
@@ -316,7 +425,8 @@ struct OperationSnapshot: Codable {
316
425
  projectRoot: String?,
317
426
  registry: String?,
318
427
  recovery: OperationRecoveryStatus? = nil,
319
- providerApply: ProviderApplyProjection? = nil
428
+ providerApply: ProviderApplyProjection? = nil,
429
+ diagnostic: DiagnosticOperationMetadata? = nil
320
430
  ) {
321
431
  self.schema = schema
322
432
  self.id = id
@@ -334,6 +444,7 @@ struct OperationSnapshot: Codable {
334
444
  self.registry = registry
335
445
  self.recovery = recovery
336
446
  self.providerApply = providerApply
447
+ self.diagnostic = diagnostic
337
448
  }
338
449
  }
339
450
 
@@ -386,4 +497,3 @@ struct UpdateOperationReceiptSnapshot: Codable {
386
497
  case receiptPath = "receipt_path"
387
498
  }
388
499
  }
389
-
@@ -0,0 +1,21 @@
1
+ import Foundation
2
+
3
+ struct ProviderRouteExplanation: Equatable {
4
+ let providerId: String
5
+ let upstreamModel: String
6
+ let fallback: String
7
+
8
+ static func decode(from commandEnvelope: [String: Any]) -> ProviderRouteExplanation? {
9
+ guard let result = commandEnvelope["result"] as? [String: Any],
10
+ let explanation = result["explanation"] as? [String: Any],
11
+ let route = explanation["route"] as? [String: Any],
12
+ let providerId = route["provider_id"] as? String,
13
+ let upstreamModel = route["upstream_model"] as? String,
14
+ let fallback = explanation["fallback"] as? String else { return nil }
15
+ return ProviderRouteExplanation(
16
+ providerId: providerId,
17
+ upstreamModel: upstreamModel,
18
+ fallback: fallback
19
+ )
20
+ }
21
+ }
@@ -0,0 +1,140 @@
1
+ import Cocoa
2
+
3
+ extension ProvidersViewController {
4
+ func makeCombinedCatalogCard() -> NSBox {
5
+ let refresh = NativeView.button("Refresh", target: self, action: #selector(refreshCombinedCatalog))
6
+ let report = NativeView.button("Open Report", target: self, action: #selector(openCatalogReport))
7
+ registerProviderAction(refresh, id: "sks-provider-refresh-catalog")
8
+ registerProviderAction(report, id: "sks-provider-open-catalog-report")
9
+ actionButtons += [refresh, report]
10
+ let card = NativeView.card(title: "Combined Model Catalog", subtitle: "Codex-LB and OpenRouter catalogs activate atomically with one explicit route index. A failed build keeps the prior verified generation.", views: [catalogSyncStatus, ControlKit.actionRow([refresh, report])])
11
+ card.setAccessibilityIdentifier("sks-provider-card-combined-catalog")
12
+ return card
13
+ }
14
+
15
+ func makeRoutesCard() -> NSBox {
16
+ let explain = NativeView.button("Explain Route", target: self, action: #selector(explainRoute))
17
+ registerProviderAction(explain, id: "sks-provider-route-explain")
18
+ actionButtons.append(explain)
19
+ let card = NativeView.card(title: "Routes", subtitle: "Routes come only from the canonical model index or a validated session pin. Fallback is always none.", views: [routesStatus, NativeView.row([routeModelField, explain])])
20
+ card.setAccessibilityIdentifier("sks-provider-card-routes")
21
+ return card
22
+ }
23
+
24
+ func renderCombinedCatalog(_ json: [String: Any]) {
25
+ let catalog = json["catalog_sync"] as? [String: Any]
26
+ guard catalog?["schema"] as? String == "sks.combined-catalog-sync.v1",
27
+ let data = try? JSONSerialization.data(withJSONObject: catalog as Any),
28
+ let decoded = try? JSONDecoder().decode(CombinedCatalogSyncStatusV1.self, from: data),
29
+ decoded.providers["codex-lb"]?.schema == "sks.catalog-sync-state.v2",
30
+ decoded.providers["openrouter"]?.schema == "sks.catalog-sync-state.v2" else {
31
+ catalogSyncStatus.stringValue = "Capability schema invalid · catalog_sync missing · capability_schema_invalid"
32
+ catalogSyncStatus.textColor = .systemRed
33
+ return
34
+ }
35
+ renderCatalogStatus(decoded)
36
+ }
37
+
38
+ func renderCatalogStatus(_ catalog: CombinedCatalogSyncStatusV1) {
39
+ func providerText(_ id: String) -> String {
40
+ guard let state = catalog.providers[id] else { return "invalid" }
41
+ return state.modelCount.map(String.init) ?? state.state
42
+ }
43
+ let modelText = catalog.modelCount.map { " · \($0) models" } ?? ""
44
+ let routeText = catalog.routeCount.map { " · \($0) routes" } ?? ""
45
+ let conflictText = catalog.conflictCount > 0 ? " · \(catalog.conflictCount) conflicts" : ""
46
+ let cause = catalog.blockers.first.map { " · \(ProviderSecretRedactor.redact($0))" } ?? ""
47
+ let recovery = catalog.recoveryAction.flatMap(ProviderRecoveryAction.init(rawValue:)).map { " · recovery \($0.buttonTitle)" } ?? ""
48
+ catalogSyncStatus.stringValue = "Combined catalog · \(catalog.state)\(modelText)\(routeText) · Codex-LB \(providerText("codex-lb")) / OpenRouter \(providerText("openrouter"))\(conflictText)\(cause)\(recovery)"
49
+ switch catalog.state {
50
+ case "verified": catalogSyncStatus.textColor = .systemGreen
51
+ case "failed": catalogSyncStatus.textColor = .systemRed
52
+ default: catalogSyncStatus.textColor = .systemOrange
53
+ }
54
+ }
55
+
56
+ func renderRoutes(_ json: [String: Any]) {
57
+ guard let routing = json["routing"] as? [String: Any],
58
+ let policy = routing["policy"] as? [String: Any],
59
+ policy["schema"] as? String == "sks.bridge-routing-policy.v1",
60
+ policy["fallback"] as? String == "none" else {
61
+ routesStatus.stringValue = "Routes · schema invalid or fallback is not none"
62
+ routesStatus.textColor = .systemRed
63
+ return
64
+ }
65
+ let provider = policy["default_provider_id"] as? String ?? "none"
66
+ let generation = policy["policy_generation"] as? String ?? "unreported"
67
+ let catalogGeneration = policy["catalog_generation"] as? String ?? "unreported"
68
+ let pin = routing["session_pin"] as? [String: Any]
69
+ let pinText = pin.map { "\($0["provider_id"] as? String ?? "invalid") / \($0["public_model"] as? String ?? "invalid")" } ?? "none"
70
+ let selected = routing["selected_route"] as? [String: Any]
71
+ let selectedModel = routing["selected_model"] as? String ?? "unknown"
72
+ let selectedText = selected.map { "\(selectedModel) → \($0["provider_id"] as? String ?? "unknown")" } ?? "none"
73
+ routesStatus.stringValue = "Default provider: \(provider) · selected model: \(selectedText) · session pin: \(pinText) · fallback: none · policy \(generation) · catalog \(catalogGeneration)"
74
+ routesStatus.textColor = .secondaryLabelColor
75
+ }
76
+
77
+ @objc func refreshCombinedCatalog() {
78
+ runCatalogCommand(["bridge", "catalog", "sync", "--json"], title: "Refresh combined catalog", mutationGroup: "codex-config")
79
+ }
80
+
81
+ @objc func openCatalogReport() {
82
+ runCatalogCommand(["bridge", "catalog", "status", "--json"], title: "Load combined catalog report", mutationGroup: nil)
83
+ }
84
+
85
+ private func runCatalogCommand(_ args: [String], title: String, mutationGroup: String?) {
86
+ guard !catalogRefreshInFlight, let snapshot = operations.begin(kind: "bridge-catalog", mutationGroup: mutationGroup, summary: title) else { return }
87
+ catalogRefreshInFlight = true
88
+ catalogSyncStatus.stringValue = "Combined catalog · syncing"
89
+ _ = operations.update(snapshot, state: .running, stage: "catalog_sync", progress: nil, summary: title)
90
+ processClient.run(args, timeout: NativeView.mutationTimeout) { [weak self] result in
91
+ guard let self = self else { return }
92
+ self.catalogRefreshInFlight = false
93
+ guard let json = self.json(result.output) else {
94
+ _ = self.operations.update(snapshot, state: .failed, stage: "complete", progress: 1, summary: "Catalog report schema invalid")
95
+ self.catalogSyncStatus.stringValue = "Capability schema invalid · catalog_sync missing · capability_schema_invalid"
96
+ self.catalogSyncStatus.textColor = .systemRed
97
+ return
98
+ }
99
+ guard json["schema"] as? String == "sks.desktop-bridge-command-result.v1",
100
+ ["catalog.sync", "catalog.status"].contains(json["operation"] as? String ?? ""),
101
+ let statusJSON = json["status"] as? [String: Any],
102
+ let status = try? DesktopBridgeStatusV3Truth.decode(from: statusJSON) else {
103
+ _ = self.operations.update(snapshot, state: .failed, stage: "complete", progress: 1, summary: "Catalog command envelope invalid")
104
+ self.catalogSyncStatus.stringValue = "Capability schema invalid · current Desktop Bridge status missing"
105
+ self.catalogSyncStatus.textColor = .systemRed
106
+ return
107
+ }
108
+ self.renderCombinedCatalog(status.raw)
109
+ let valid = !self.catalogSyncStatus.stringValue.contains("schema invalid")
110
+ _ = self.operations.update(snapshot, state: valid ? .succeeded : .failed, stage: "complete", progress: 1, summary: valid ? "Catalog report generated" : "Catalog report schema invalid")
111
+ self.refresh()
112
+ }
113
+ }
114
+
115
+ @objc func explainRoute() {
116
+ let model = routeModelField.stringValue.trimmingCharacters(in: .whitespacesAndNewlines)
117
+ guard !model.isEmpty, let snapshot = operations.begin(kind: "bridge-route-explain", mutationGroup: nil, summary: "Explain model route") else {
118
+ routesStatus.stringValue = "Route explain blocked · choose an exact model from the combined catalog."
119
+ routesStatus.textColor = .systemOrange
120
+ return
121
+ }
122
+ routesStatus.stringValue = "Explaining \(model) through the explicit route index…"
123
+ _ = operations.update(snapshot, state: .running, stage: "model_route", progress: nil, summary: "Explain model route")
124
+ processClient.run(["bridge", "route", "explain", model, "--json"], timeout: NativeView.statusTimeout) { [weak self] result in
125
+ guard let self = self else { return }
126
+ let json = self.json(result.output)
127
+ let explanation = json.flatMap(ProviderRouteExplanation.decode(from:))
128
+ let explainedRoute = explanation.flatMap { explanation in
129
+ explanation.fallback == "none"
130
+ ? "\(model) → \(explanation.providerId) / \(explanation.upstreamModel) · fallback none"
131
+ : nil
132
+ }
133
+ let valid = explainedRoute != nil
134
+ _ = self.operations.update(snapshot, state: valid ? .succeeded : .failed, stage: "complete", progress: 1, summary: valid ? "Route explained" : "Route unavailable")
135
+ self.routesStatus.stringValue = explainedRoute
136
+ ?? "\(model) · route missing or ambiguous · no fallback · \(self.structuredPublicDetail(json, fallback: result.output, fallbackNext: "Refresh catalog or choose a supported model"))"
137
+ self.routesStatus.textColor = valid ? .systemGreen : .systemRed
138
+ }
139
+ }
140
+ }