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
@@ -1,6 +1,5 @@
1
1
  import os from 'node:os';
2
2
  import path from 'node:path';
3
- import { createHash } from 'node:crypto';
4
3
  import { projectRoot, exists, formatBytes, nowIso, readText, writeJsonAtomic } from '../core/fsx.js';
5
4
  import { flag } from '../cli/args.js';
6
5
  import { printJson } from '../cli/output.js';
@@ -8,23 +7,14 @@ import { ui as cliUi } from '../cli/cli-theme.js';
8
7
  import { getCodexInfo } from '../core/codex-adapter.js';
9
8
  import { rustInfo } from '../core/rust-accelerator.js';
10
9
  import { codexAppIntegrationStatus } from '../core/codex-app.js';
11
- import { codexLbMetrics, readCodexLbCircuit } from '../core/codex-lb-circuit.js';
12
- import { codexLbStatus } from '../cli/install-helpers.js';
13
- import { codexLbToolOutputRecoveryOverrideAcknowledged } from '../core/codex-lb/codex-lb-tool-output-recovery.js';
14
- import { codexLbEnvPath, loadCodexLbEnv } from '../core/codex-lb/codex-lb-env.js';
15
- import { codexLbLegacyKeychainMigrationStampPath, inspectDesktopCenterLaunchCredentials, inspectCodexLbLegacyKeychainMigration, repairCodexLbLegacyKeychainMigration, syncDesktopCenterLaunchCredentials } from '../core/codex-lb/desktop-center-credentials.js';
16
- import { codexLbRoutingTruthIsActive, measureAndWriteCodexLbRoutingTruth, readCodexLbRoutingTruthReceipt } from '../core/codex-lb/routing-truth.js';
17
- import { removeCodexLbOrphanManagedMarkers } from '../cli/install-helpers-codex-lb-config.js';
18
- import { safeWriteCodexConfigToml } from '../core/codex-runtime/codex-desktop-config-policy.js';
10
+ import { desktopBridgeStatusV3 } from '../core/codex-lb/desktop-controller-v3.js';
19
11
  import { probeTelegram, telegramSelfHealAction } from '../core/telegram/doctor.js';
20
12
  import { TelegramClient } from '../core/telegram/client.js';
21
13
  import { resolveTelegramBotToken } from '../core/telegram/keychain.js';
22
14
  import { telegramLivenessPath } from '../core/telegram/liveness.js';
23
- import { normalizeInstallScope } from '../core/init.js';
24
15
  import { inspectCodexConfigReadability } from '../core/codex/codex-config-readability.js';
25
16
  import { inspectOAuthCallbackPortConflict, oauthCallbackDoctorGuidance } from '../core/codex/oauth-callback-port-diagnostic.js';
26
17
  import { inventoryCodexPermissionProfiles } from '../core/codex/codex-permission-profiles.js';
27
- import { appendMigrationEvents, hashConfigText } from '../core/migration/migration-transaction-journal.js';
28
18
  import { resolveProviderContext } from '../core/provider/provider-context.js';
29
19
  import { readLocalModelConfig } from '../core/agents/ollama-worker-config.js';
30
20
  import { writeCodexCurrentAppCapabilityArtifacts } from '../core/codex-control/codex-current-app-capability.js';
@@ -42,11 +32,12 @@ import { sweepSksTempDirs } from '../core/retention.js';
42
32
  import { detectImagegenCapability } from '../core/imagegen/imagegen-capability.js';
43
33
  import { CURRENT_CODEX_RELEASE_MANIFEST } from '../core/codex-compat/codex-release-manifest.js';
44
34
  import { formatHarnessConflictReport, scanHarnessConflicts } from '../core/harness-conflicts.js';
45
- import { doctorArgWarnings as baseDoctorArgWarnings, doctorMenuBarInstallPolicy, doctorPhaseIdsForProfile, doctorProfileFromArgs } from './doctor-profile.js';
46
- export { doctorMenuBarInstallPolicy, doctorProfileFromArgs } from './doctor-profile.js';
47
- const CODEX_LB_KEYCHAIN_MIGRATION_RETRY_FLAG = '--retry-codex-lb-keychain-migration';
35
+ import { doctorArgWarnings as baseDoctorArgWarnings, doctorMenuBarInstallPolicy, doctorPhaseIdsForProfile, doctorProfileFromArgs, doctorProfileRequiresDesktopBridgeReadiness } from './doctor-profile.js';
36
+ import { buildCodexAppUiDiagnosticFailure, buildRuntimeReadiness, captureCodexConfigSnapshot, deferredNativeRepair, doctorDedupeStatus, doctorSkillStatus, fallbackCodexNativeFeatureMatrix, formatCodexDoctorConsoleStatus, installScopeFromArgs, isMigrationUserOwnedProjectConfigBlocker, mergeObservedCodexStartupWarnings, nativeCapabilityStatus, readOption, rebootstrapSksMenuBarLaunchdForDoctorFix, sksMenuBarRunningVersionConsoleLines, uniqueNativeManualActions, writeFixMigrationJournal, writeJsonReportFile } from './doctor-helpers.js';
37
+ export { doctorMenuBarInstallPolicy, doctorProfileFromArgs, doctorProfileRequiresDesktopBridgeReadiness } from './doctor-profile.js';
38
+ export { buildCodexAppUiDiagnosticFailure, buildRuntimeReadiness, formatCodexDoctorConsoleStatus, rebootstrapSksMenuBarLaunchdForDoctorFix, sksMenuBarRunningVersionConsoleLines };
48
39
  export function doctorArgWarnings(args = []) {
49
- return baseDoctorArgWarnings(args.filter((arg) => arg !== CODEX_LB_KEYCHAIN_MIGRATION_RETRY_FLAG));
40
+ return baseDoctorArgWarnings(args);
50
41
  }
51
42
  export function deferCommandAliasCleanupToMigrationReceipt(result) {
52
43
  const observedBlockers = Array.isArray(result?.blockers)
@@ -67,195 +58,50 @@ export function deferCommandAliasCleanupToMigrationReceipt(result) {
67
58
  ]
68
59
  };
69
60
  }
70
- export async function inspectDoctorCodexLbSecretResolution(input = {}, deps = {}) {
61
+ export async function inspectDoctorDesktopBridgeStatus(input = {}, deps = {}) {
71
62
  const processEnv = input.processEnv || process.env;
72
63
  const home = path.resolve(input.home || processEnv.HOME || os.homedir());
73
- const suppliedMigrationOptions = input.migrationOptions || {};
74
- const migrationOptions = {
75
- ...suppliedMigrationOptions,
76
- home,
77
- env: suppliedMigrationOptions.env || processEnv,
78
- processEnv: suppliedMigrationOptions.processEnv || processEnv,
79
- ...(input.baseUrl ? { baseUrl: input.baseUrl } : {}),
80
- ...(input.forceRetry === true ? { forceRetry: true } : {})
81
- };
82
- if (processEnv.SKS_TEST_FORBID_REAL_HOME === '1' && suppliedMigrationOptions.platform === undefined) {
83
- migrationOptions.platform = 'linux';
84
- }
85
- const mode = input.fix === true ? 'repair' : 'inspect';
86
- const reconcile = mode === 'repair'
87
- ? deps.repairImpl || repairCodexLbLegacyKeychainMigration
88
- : deps.inspectImpl || inspectCodexLbLegacyKeychainMigration;
89
- let migration;
90
- try {
91
- migration = await reconcile(migrationOptions);
92
- }
93
- catch (error) {
94
- migration = {
95
- schema: 'sks.codex-lb-legacy-keychain-reconciliation.v1',
96
- ok: false,
97
- status: `${mode}_failed`,
98
- mode,
99
- env_key_valid: false,
100
- keychain_item_present: null,
101
- prompt_risk: 'none',
102
- attempted: false,
103
- stamp_path: codexLbLegacyKeychainMigrationStampPath(home),
104
- stamp_outcome: null,
105
- keychain_deleted: false,
106
- keychain_cleared: [],
107
- blockers: [`codex_lb_legacy_keychain_${mode}_failed:${error instanceof Error ? error.message : String(error)}`]
108
- };
109
- }
110
- const envPath = String(suppliedMigrationOptions.envPath || codexLbEnvPath(home));
111
- let loaded = null;
112
- let resolutionError = null;
113
64
  try {
114
- loaded = await (deps.loadEnvImpl || loadCodexLbEnv)({
65
+ const status = await (deps.desktopBridgeStatusImpl || desktopBridgeStatusV3)({
115
66
  home,
116
- processEnv,
117
- envPath,
118
- ...(suppliedMigrationOptions.metadataPath ? { metadataPath: suppliedMigrationOptions.metadataPath } : {})
67
+ env: processEnv
119
68
  });
69
+ if (!status || typeof status !== 'object' || !status.providers || !status.readiness) {
70
+ throw new Error('invalid Desktop Bridge status response');
71
+ }
72
+ const enabledProviders = Object.values(status.providers)
73
+ .filter((provider) => provider?.enabled === true);
74
+ const expected = enabledProviders.length > 0;
75
+ const blockers = expected && status.readiness.ready !== true
76
+ ? (status.readiness.blockers || []).map(String).filter(Boolean)
77
+ : [];
78
+ return {
79
+ schema: 'sks.doctor-desktop-bridge.v1',
80
+ ok: blockers.length === 0,
81
+ read_only: true,
82
+ credentials_mutated: false,
83
+ managed: status.management?.managed === true,
84
+ status,
85
+ providers: status.providers,
86
+ blockers,
87
+ warnings: (status.readiness.warnings || []).map(String).filter(Boolean),
88
+ recovery_actions: (status.recovery_actions || []).map(String).filter(Boolean)
89
+ };
120
90
  }
121
91
  catch (error) {
122
- resolutionError = error instanceof Error ? error.message : String(error);
123
- }
124
- const source = String(loaded?.source || 'missing');
125
- const unsafeEnvFile = Array.isArray(loaded?.blockers)
126
- && loaded.blockers.some((blocker) => String(blocker).startsWith('codex_lb_env_file_'));
127
- const resolutionPath = source === 'env-file' || unsafeEnvFile
128
- ? String(loaded?.env_paths?.[0] || envPath)
129
- : null;
130
- const operatorActions = [];
131
- if (mode === 'inspect' && migration.prompt_risk === 'one_time_on_repair') {
132
- operatorActions.push('Run `sks doctor --fix` to perform the one-time legacy Keychain transfer.');
133
- }
134
- if (mode === 'repair'
135
- && migration.ok === false
136
- && (migration.attempted === true || migration.status === 'already_attempted')) {
137
- operatorActions.push(`Run \`sks doctor --fix ${CODEX_LB_KEYCHAIN_MIGRATION_RETRY_FLAG}\` to explicitly retry the one-time Keychain transfer.`);
138
- }
139
- return {
140
- ok: migration.ok !== false && resolutionError === null,
141
- secret_resolution: {
142
- source,
143
- path: resolutionPath,
144
- prompt_risk: migration.prompt_risk || 'none'
145
- },
146
- legacy_keychain_migration: {
147
- ...migration,
148
- operator_actions: operatorActions,
149
- ...(resolutionError ? { resolution_error: resolutionError } : {})
150
- }
151
- };
152
- }
153
- export async function inspectDoctorCodexLbDivergence(input = {}, deps = {}) {
154
- const processEnv = input.processEnv || process.env;
155
- const home = path.resolve(input.home || processEnv.HOME || os.homedir());
156
- const status = input.providerStatus || {};
157
- const configPath = String(status.config_path || path.join(home, '.codex', 'config.toml'));
158
- const configText = await (deps.readTextImpl || readText)(configPath, '');
159
- const orphan = removeCodexLbOrphanManagedMarkers(configText);
160
- let orphanRepair = {
161
- schema: 'sks.codex-lb-orphan-managed-marker-repair.v1',
162
- attempted: false,
163
- changed: false,
164
- markers: orphan.orphan_markers,
165
- receipt: null
166
- };
167
- if (input.fix === true && orphan.changed) {
168
- const write = deps.writeConfigImpl || safeWriteCodexConfigToml;
169
- const receipt = await write(configPath, configText, orphan.text, 'doctor-codex-lb-orphan-marker');
170
- orphanRepair = {
171
- ...orphanRepair,
172
- attempted: true,
173
- changed: receipt?.ok !== false,
174
- receipt
92
+ return {
93
+ schema: 'sks.doctor-desktop-bridge.v1',
94
+ ok: false,
95
+ read_only: true,
96
+ credentials_mutated: false,
97
+ managed: null,
98
+ status: null,
99
+ providers: null,
100
+ blockers: [`desktop_bridge_status_unavailable:${error instanceof Error ? error.message : String(error)}`],
101
+ warnings: [],
102
+ recovery_actions: ['Run `sks bridge status --json` to inspect Desktop Bridge provider readiness.']
175
103
  };
176
104
  }
177
- const load = deps.loadEnvImpl || loadCodexLbEnv;
178
- const canonical = await load({
179
- home,
180
- processEnv: {},
181
- envPath: String(status.env_path || codexLbEnvPath(home))
182
- }).catch(() => null);
183
- const ambientKey = String(processEnv.CODEX_LB_API_KEY || '').trim();
184
- const canonicalKey = String(canonical?.secret_api_key || '').trim();
185
- const sha256 = (value) => value
186
- ? createHash('sha256').update(value).digest('hex')
187
- : null;
188
- const ambientHash = sha256(ambientKey);
189
- const canonicalHash = sha256(canonicalKey);
190
- const staleAmbient = Boolean(ambientHash && canonicalHash && ambientHash !== canonicalHash);
191
- const bridgeActive = status.desktop_mode === 'desktop-native-bridge';
192
- const definedButNotSelected = status.provider_configured === true
193
- && status.selected !== true
194
- && !bridgeActive
195
- && status.desktop_mode !== 'desktop-dual-auth-compat';
196
- const mode = status.selected === true
197
- ? 'cli-provider'
198
- : bridgeActive
199
- ? 'desktop-native-bridge'
200
- : 'disabled';
201
- const inspectLaunch = deps.inspectLaunchImpl || inspectDesktopCenterLaunchCredentials;
202
- const syncLaunch = deps.syncLaunchImpl || syncDesktopCenterLaunchCredentials;
203
- const launchOptions = {
204
- mode,
205
- home,
206
- ...(input.launchctlBin ? { launchctlBin: input.launchctlBin } : {}),
207
- ...(input.platform ? { platform: input.platform } : {}),
208
- ...(input.forceLaunchctl ? { force: true } : {}),
209
- ...(input.runProcessImpl ? { runProcessImpl: input.runProcessImpl } : {})
210
- };
211
- const launchBefore = await inspectLaunch(launchOptions);
212
- const launchRepair = input.fix === true && launchBefore.ok === false
213
- ? await syncLaunch({ ...launchOptions, skipPurge: true })
214
- : null;
215
- const launchAfter = launchRepair ? await inspectLaunch(launchOptions) : launchBefore;
216
- const warnings = [
217
- ...(definedButNotSelected
218
- ? ['codex_lb_defined_but_not_selected']
219
- : []),
220
- ...(staleAmbient ? ['codex_lb_stale_ambient_key'] : []),
221
- ...(orphan.orphan_markers.length > 0
222
- ? [`codex_lb_orphan_managed_markers:${orphan.orphan_markers.join(',')}`]
223
- : [])
224
- ];
225
- const blockers = [
226
- ...(launchAfter.ok === false ? launchAfter.blockers || ['codex_lb_launchd_selection_state_mismatch'] : []),
227
- ...(input.fix === true && orphan.changed && orphanRepair.changed !== true
228
- ? ['codex_lb_orphan_marker_repair_failed']
229
- : [])
230
- ];
231
- return {
232
- schema: 'sks.doctor-codex-lb-divergence.v1',
233
- ok: blockers.length === 0,
234
- warnings,
235
- blockers,
236
- operator_actions: [
237
- ...(definedButNotSelected
238
- ? ['Run `sks codex-lb use-cli` to select the stored provider.']
239
- : []),
240
- ...(staleAmbient
241
- ? ['Remove or update the stale shell export: `unset CODEX_LB_API_KEY`; the canonical key remains in ~/.codex/sks-codex-lb.env.']
242
- : []),
243
- ...(launchAfter.operator_actions || [])
244
- ],
245
- ambient_key: {
246
- present: Boolean(ambientKey),
247
- sha256: ambientHash,
248
- matches_canonical: ambientHash && canonicalHash ? ambientHash === canonicalHash : null
249
- },
250
- canonical_key: {
251
- present: Boolean(canonicalKey),
252
- sha256: canonicalHash,
253
- path: String(status.env_path || codexLbEnvPath(home))
254
- },
255
- orphan_markers: orphan.orphan_markers,
256
- orphan_marker_repair: orphanRepair,
257
- launchd: { before: launchBefore, repair: launchRepair, after: launchAfter }
258
- };
259
105
  }
260
106
  export async function run(_command, args = [], deps = {}) {
261
107
  const root = await projectRoot();
@@ -319,50 +165,10 @@ export async function executeDoctorGlobalOnlyFix(args = [], root, deps = {}) {
319
165
  || (await import('../core/doctor/command-alias-cleanup.js')).runDoctorCommandAliasCleanup;
320
166
  const ensureGlobalFastModeImpl = deps.ensureGlobalCodexFastModeDuringInstallImpl
321
167
  || (await import('../cli/install-helpers.js')).ensureGlobalCodexFastModeDuringInstall;
322
- const ensureStoredOpenRouterProviderImpl = deps.ensureStoredOpenRouterProviderDuringInstallImpl
323
- || (await import('../cli/install-helpers.js')).ensureStoredOpenRouterProviderDuringInstall;
324
168
  const installMenuBarImpl = deps.installSksMenuBarImpl || installSksMenuBar;
325
- const codexLbStatusImpl = deps.codexLbStatusImpl || codexLbStatus;
326
169
  const doctorEnv = deps.env || (deps.home
327
170
  ? { ...process.env, HOME: home }
328
171
  : process.env);
329
- const statusOptions = {
330
- home,
331
- env: doctorEnv,
332
- processEnv: doctorEnv
333
- };
334
- const preRepairProviderStatus = await codexLbStatusImpl({
335
- ...statusOptions,
336
- probeToolOutputRecovery: false
337
- }).catch(() => null);
338
- const codexLbSecretProbeImpl = deps.codexLbSecretProbeImpl || inspectDoctorCodexLbSecretResolution;
339
- const codexLbSecretProbe = await codexLbSecretProbeImpl({
340
- home,
341
- processEnv: doctorEnv,
342
- fix: true,
343
- forceRetry: flag(args, CODEX_LB_KEYCHAIN_MIGRATION_RETRY_FLAG),
344
- baseUrl: preRepairProviderStatus?.base_url || preRepairProviderStatus?.provider_base_url || null,
345
- migrationOptions: {
346
- ...(deps.codexLbMigrationOptions || {}),
347
- ...(!deps.codexLbMigrationOptions && deps.codexLbStatusImpl ? { platform: 'linux' } : {})
348
- }
349
- });
350
- const providerStatus = await codexLbStatusImpl({
351
- ...statusOptions,
352
- probeToolOutputRecovery: true,
353
- allowUnverifiedToolOutputRecovery: codexLbToolOutputRecoveryOverrideAcknowledged({ args })
354
- }).catch((err) => ({
355
- selected: null,
356
- provider_ready: false,
357
- recovery_probe_failed: true,
358
- tool_output_recovery: {
359
- ok: false,
360
- status: 'probe_failed',
361
- blockers: ['codex_lb_tool_output_recovery_status_probe_failed'],
362
- operator_actions: []
363
- },
364
- error: err?.message || String(err)
365
- }));
366
172
  const globalSkills = await reconcileSkillsImpl({
367
173
  targetDir: path.join(home, '.agents', 'skills'),
368
174
  scope: 'global',
@@ -388,18 +194,6 @@ export async function executeDoctorGlobalOnlyFix(args = [], root, deps = {}) {
388
194
  status: 'failed',
389
195
  error: err?.message || String(err)
390
196
  }));
391
- const openRouterEnv = {
392
- ...doctorEnv,
393
- HOME: home,
394
- SKS_HOME: path.join(home, '.sneakoscope')
395
- };
396
- const openRouterProvider = await ensureStoredOpenRouterProviderImpl({ home, env: openRouterEnv }).catch((err) => ({
397
- schema: 'sks.openrouter-provider-upgrade-repair.v1',
398
- ok: false,
399
- status: 'failed',
400
- blockers: ['openrouter_provider_repair_failed'],
401
- error: err?.message || String(err)
402
- }));
403
197
  const menuBar = await installMenuBarImpl({
404
198
  home,
405
199
  root: home,
@@ -414,18 +208,10 @@ export async function executeDoctorGlobalOnlyFix(args = [], root, deps = {}) {
414
208
  blockers: [err?.message || String(err)],
415
209
  warnings: []
416
210
  }));
417
- const codexLbRoutingTruth = await codexLbRoutingTruthForStatus(providerStatus, { home, remeasure: true });
418
- const codexLbRoutingReady = !doctorCodexLbRouteExpected(providerStatus)
419
- || codexLbRoutingTruthIsActive(codexLbRoutingTruth);
420
- const codexLbDivergence = await inspectDoctorCodexLbDivergence({
211
+ const desktopBridge = await inspectDoctorDesktopBridgeStatus({
421
212
  home,
422
- processEnv: doctorEnv,
423
- providerStatus,
424
- fix: true,
425
- ...(deps.codexLbLaunchctlBin ? { launchctlBin: deps.codexLbLaunchctlBin } : {}),
426
- ...(deps.codexLbLaunchPlatform ? { platform: deps.codexLbLaunchPlatform } : {}),
427
- ...(deps.codexLbLaunchRunProcessImpl ? { runProcessImpl: deps.codexLbLaunchRunProcessImpl } : {})
428
- }, deps.codexLbDivergenceDeps || {});
213
+ processEnv: doctorEnv
214
+ }, { desktopBridgeStatusImpl: deps.desktopBridgeStatusImpl });
429
215
  const telegramRemote = await inspectTelegramRemote({
430
216
  live: true,
431
217
  fix: true,
@@ -433,26 +219,20 @@ export async function executeDoctorGlobalOnlyFix(args = [], root, deps = {}) {
433
219
  home,
434
220
  env: doctorEnv
435
221
  }, deps);
436
- const recoveryReady = codexLbRecoveryStatusReady(providerStatus, true);
437
222
  const globalSkillsReady = !globalSkills?.error
438
223
  && globalSkills?.ok !== false
439
224
  && globalSkills?.core_skill_integrity?.ok !== false;
440
225
  const globalFastModeReady = globalFastMode?.status !== 'failed'
441
226
  && globalFastMode?.ok !== false;
442
227
  const menuBarReady = menuBar?.ok !== false;
443
- const openRouterProviderReady = openRouterProvider?.ok !== false;
444
228
  const blockers = [...new Set([
445
229
  ...(!globalSkillsReady ? [`global_skills_reconcile_failed:${globalSkills?.error || 'core_skill_integrity'}`] : []),
446
230
  ...(currentSurface?.ok !== true ? (currentSurface?.blockers || ['global_current_surface_reconcile_failed']) : []),
447
231
  ...(!globalFastModeReady ? [`global_fast_mode_repair_failed:${globalFastMode?.error || globalFastMode?.status || 'unknown'}`] : []),
448
- ...(!openRouterProviderReady ? (openRouterProvider?.blockers || ['openrouter_provider_repair_failed']) : []),
449
232
  ...(!menuBarReady ? (menuBar?.blockers || ['sks_menubar_repair_failed']) : []),
450
- ...(codexLbSecretProbe.ok === false
451
- ? (codexLbSecretProbe.legacy_keychain_migration?.blockers || ['codex_lb_secret_resolution_failed'])
452
- : []),
453
- ...(!recoveryReady ? (providerStatus?.tool_output_recovery?.blockers || ['codex_lb_tool_output_recovery_unverified']) : []),
454
- ...(!codexLbRoutingReady ? (codexLbRoutingTruth?.blockers || ['codex_lb_routing_truth_unverified']) : []),
455
- ...(codexLbDivergence.blockers || [])
233
+ ...(desktopBridge.ok === false
234
+ ? (desktopBridge.blockers || ['desktop_bridge_unavailable'])
235
+ : [])
456
236
  ].map(String).filter(Boolean))];
457
237
  const ok = blockers.length === 0;
458
238
  return {
@@ -479,26 +259,14 @@ export async function executeDoctorGlobalOnlyFix(args = [], root, deps = {}) {
479
259
  skills: { global: globalSkills, project: { skipped: true, reason: 'global_only_doctor' } },
480
260
  current_public_surface: currentSurface,
481
261
  codex_app_fast_mode: globalFastMode,
482
- openrouter_provider: openRouterProvider,
262
+ openrouter_provider: desktopBridge.providers?.openrouter || null,
483
263
  sks_menubar: menuBar,
484
264
  telegram_remote: telegramRemote,
485
- codex_lb: {
486
- provider_status: providerStatus,
487
- tool_output_recovery: providerStatus?.tool_output_recovery || null,
488
- recovery_ok: recoveryReady,
489
- routing_truth: codexLbRoutingTruth,
490
- routing_ok: codexLbRoutingReady,
491
- secret_resolution: codexLbSecretProbe.secret_resolution,
492
- legacy_keychain_migration: codexLbSecretProbe.legacy_keychain_migration,
493
- divergence: codexLbDivergence
494
- },
265
+ desktop_bridge: desktopBridge,
495
266
  blockers,
496
267
  next_actions: [
497
- ...(recoveryReady ? [] : (providerStatus?.tool_output_recovery?.operator_actions || [])),
498
- ...(codexLbSecretProbe.legacy_keychain_migration?.operator_actions || []),
499
- ...(codexLbDivergence.operator_actions || []),
268
+ ...(desktopBridge.ok === false ? desktopBridge.recovery_actions || [] : []),
500
269
  ...telegramDoctorOperatorActions(telegramRemote),
501
- ...(!openRouterProviderReady ? ['Run `sks codex-app set-openrouter-key` to repair the stored-key provider configuration without switching models.'] : []),
502
270
  'Run `sks doctor --fix --json` from a specific project directory when project-scoped repair is required.'
503
271
  ]
504
272
  };
@@ -528,7 +296,7 @@ async function runDoctorGlobalOnlyFix(args = [], root, deps = {}) {
528
296
  const telegramCheckedLine = telegramDoctorCheckedLine(result.telegram_remote);
529
297
  if (telegramCheckedLine)
530
298
  console.log(telegramCheckedLine);
531
- console.log(`codex-lb key: ${result.codex_lb.secret_resolution.source} (prompt risk ${result.codex_lb.secret_resolution.prompt_risk})`);
299
+ console.log(`Desktop Bridge: ${result.desktop_bridge.ok ? 'ready' : 'blocked'} (${result.desktop_bridge.status?.readiness?.state || 'unavailable'})`);
532
300
  for (const blocker of result.blockers)
533
301
  console.log(`- blocker: ${blocker}`);
534
302
  for (const action of result.next_actions)
@@ -538,107 +306,6 @@ async function runDoctorGlobalOnlyFix(args = [], root, deps = {}) {
538
306
  process.exitCode = 1;
539
307
  return result;
540
308
  }
541
- function codexLbRecoveryStatusReady(status, probeRequired = false) {
542
- if (status == null)
543
- return !probeRequired;
544
- if (status.recovery_probe_failed === true || status.error)
545
- return false;
546
- if (status.selected === false)
547
- return true;
548
- if (!probeRequired)
549
- return true;
550
- return status.selected === true && status.tool_output_recovery?.ok === true;
551
- }
552
- export async function codexLbRoutingTruthForStatus(status, deps = {}) {
553
- if (!status)
554
- return null;
555
- const statusEnvPath = typeof status.env_path === 'string' && status.env_path
556
- ? status.env_path
557
- : null;
558
- const resolvedHome = deps.home
559
- ? path.resolve(deps.home)
560
- : statusEnvPath
561
- ? path.dirname(path.dirname(statusEnvPath))
562
- : undefined;
563
- const envOptions = {
564
- ...(resolvedHome ? { home: resolvedHome } : {}),
565
- ...(statusEnvPath ? { envPath: statusEnvPath } : {})
566
- };
567
- const routeSelected = doctorCodexLbRouteExpected(status);
568
- const mode = status.desktop_mode === 'desktop-native-bridge' ? 'bridge' : 'cli-provider';
569
- const receiptOptions = {
570
- ...(resolvedHome ? { home: resolvedHome } : {}),
571
- ...(deps.receiptPath ? { receiptPath: deps.receiptPath } : {}),
572
- expectedMode: mode,
573
- expectedSelected: routeSelected
574
- };
575
- const receipt = await readCodexLbRoutingTruthReceipt(receiptOptions).catch(() => null);
576
- if (deps.remeasure !== true && receipt?.fresh === true)
577
- return receipt;
578
- try {
579
- const loaded = await loadCodexLbEnv({ ...envOptions, processEnv: {} });
580
- const baseUrl = loaded.base_url || status.base_url || null;
581
- const configuredHost = publicUrlHost(baseUrl);
582
- const authTransport = mode === 'cli-provider'
583
- ? 'authorization-bearer'
584
- : doctorBridgeRoutingTransport(status, receipt);
585
- const contextReceipt = await readCodexLbRoutingTruthReceipt({
586
- ...receiptOptions,
587
- expectedConfiguredHost: configuredHost,
588
- expectedAuthTransport: authTransport
589
- }).catch(() => null);
590
- if (deps.remeasure !== true && contextReceipt?.fresh === true)
591
- return contextReceipt;
592
- return measureAndWriteCodexLbRoutingTruth({
593
- mode,
594
- selected: routeSelected,
595
- baseUrl,
596
- apiKey: loaded.secret_api_key,
597
- authTransport,
598
- measure: routeSelected,
599
- ...(deps.fetchImpl ? { fetchImpl: deps.fetchImpl } : {})
600
- }, {
601
- ...envOptions,
602
- ...(deps.receiptPath ? { receiptPath: deps.receiptPath } : {})
603
- });
604
- }
605
- catch {
606
- return measureAndWriteCodexLbRoutingTruth({
607
- mode,
608
- selected: routeSelected,
609
- baseUrl: status.base_url || null,
610
- apiKey: null,
611
- authTransport: mode === 'cli-provider'
612
- ? 'authorization-bearer'
613
- : doctorBridgeRoutingTransport(status, receipt),
614
- measure: false
615
- }, {
616
- ...envOptions,
617
- ...(deps.receiptPath ? { receiptPath: deps.receiptPath } : {})
618
- });
619
- }
620
- }
621
- function doctorCodexLbRouteExpected(status) {
622
- return status?.selected === true || status?.desktop_mode === 'desktop-native-bridge';
623
- }
624
- function doctorBridgeRoutingTransport(status, receipt) {
625
- if (receipt?.mode === 'bridge'
626
- && (receipt.auth_transport === 'authorization-bearer'
627
- || receipt.auth_transport === 'x-codex-lb-api-key')) {
628
- return receipt.auth_transport;
629
- }
630
- return status?.gateway_auth_transport === 'x-codex-lb-api-key'
631
- ? 'x-codex-lb-api-key'
632
- : 'authorization-bearer';
633
- }
634
- function publicUrlHost(value) {
635
- try {
636
- return value ? new URL(String(value)).host : null;
637
- }
638
- catch {
639
- return null;
640
- }
641
- }
642
309
  export async function inspectTelegramRemote(input = {}, deps = {}) {
643
310
  const env = input.env || process.env;
644
311
  const home = path.resolve(input.home || env.HOME || os.homedir());
@@ -752,7 +419,7 @@ async function runDoctorJsonFastPath(args = [], root) {
752
419
  requireActualCodex: false,
753
420
  codexBin: codexBin || undefined
754
421
  };
755
- const [codex, rust, codexConfig, sneakoscopeExists, oauthCallbackPortDiagnostic, codexLbSecretProbe] = await Promise.all([
422
+ const [codex, rust, codexConfig, sneakoscopeExists, oauthCallbackPortDiagnostic, desktopBridge] = await Promise.all([
756
423
  codexBin
757
424
  ? Promise.resolve({ bin: codexBin, version: 'fixture-or-explicit', available: true })
758
425
  : getCodexInfo().catch(() => ({ bin: null, version: null, available: false })),
@@ -765,7 +432,7 @@ async function runDoctorJsonFastPath(args = [], root) {
765
432
  })),
766
433
  exists(`${root}/.sneakoscope`),
767
434
  inspectOAuthCallbackPortConflict(),
768
- inspectDoctorCodexLbSecretResolution({ processEnv: process.env, fix: false })
435
+ inspectDoctorDesktopBridgeStatus({ processEnv: process.env })
769
436
  ]);
770
437
  const oauthCallbackOperatorActions = oauthCallbackDoctorGuidance(oauthCallbackPortDiagnostic);
771
438
  const telegramRemote = await inspectTelegramRemote();
@@ -794,18 +461,19 @@ async function runDoctorJsonFastPath(args = [], root) {
794
461
  const deferredBrowserUse = deferredNativeRepair('sks.doctor-browser-use-repair.v1', false, [
795
462
  'Chrome/web review route needs the Codex Chrome Extension enabled before use.'
796
463
  ]);
464
+ const desktopBridgeReady = desktopBridge.ok !== false;
797
465
  const result = {
798
466
  schema: 'sks.doctor-status.v3',
799
467
  elapsed_ms: Date.now() - startedAtMs,
800
- ok: true,
801
- status: 'fast_readonly_ok',
468
+ ok: desktopBridgeReady,
469
+ status: desktopBridgeReady ? 'fast_readonly_ok' : 'blocked',
802
470
  diagnostic_depth: 'fast',
803
471
  deep_diagnostics_skipped: true,
804
472
  deep_ok: null,
805
473
  not_counted_as_full_doctor: true,
806
474
  next_actions: [
807
475
  'Run sks doctor --full --json for deep diagnostics.',
808
- ...(codexLbSecretProbe.legacy_keychain_migration?.operator_actions || []),
476
+ ...(desktopBridge.ok === false ? desktopBridge.recovery_actions || [] : []),
809
477
  ...telegramDoctorOperatorActions(telegramRemote)
810
478
  ],
811
479
  root,
@@ -815,7 +483,7 @@ async function runDoctorJsonFastPath(args = [], root) {
815
483
  warnings: [...oauthCallbackPortDiagnostic.warnings],
816
484
  operator_actions: [
817
485
  ...oauthCallbackOperatorActions,
818
- ...(codexLbSecretProbe.legacy_keychain_migration?.operator_actions || [])
486
+ ...(desktopBridge.ok === false ? desktopBridge.recovery_actions || [] : [])
819
487
  ],
820
488
  node: { ok: Number(process.versions.node.split('.')[0]) >= 20, version: process.version },
821
489
  codex,
@@ -843,25 +511,28 @@ async function runDoctorJsonFastPath(args = [], root) {
843
511
  },
844
512
  telegram_remote: telegramRemote,
845
513
  provider_context: {
846
- schema: 'sks.provider-context.v1',
514
+ schema: 'sks.provider-context.v2',
847
515
  generated_at: nowIso(),
848
516
  provider: 'unknown',
849
517
  auth_mode: 'unknown',
850
518
  route: '$Doctor',
851
519
  service_tier: process.env.SKS_SERVICE_TIER || 'fast',
852
- source: 'skipped',
520
+ source: 'unknown',
853
521
  confidence: 'low',
854
522
  conflict: false,
855
523
  warnings: ['provider_context_optional_diagnostic_skipped'],
856
- signals: {}
857
- },
858
- codex_lb: {
859
- ...codexLbMetrics(await readCodexLbCircuit(root).catch(() => ({}))),
860
- routing_truth: null,
861
- routing_measurement_deferred: true,
862
- secret_resolution: codexLbSecretProbe.secret_resolution,
863
- legacy_keychain_migration: codexLbSecretProbe.legacy_keychain_migration
524
+ signals: {
525
+ openai_api_key_present: false,
526
+ codex_app_auth_present: false,
527
+ desktop_bridge_status_available: false,
528
+ desktop_bridge_managed: false,
529
+ desktop_bridge_ready: false,
530
+ desktop_bridge_provider: null,
531
+ desktop_bridge_native_identity_configured: false,
532
+ desktop_bridge_credential_state: null
533
+ }
864
534
  },
535
+ desktop_bridge: desktopBridge,
865
536
  codex_doctor: null,
866
537
  pre_repair_codex_doctor: null,
867
538
  post_repair_codex_doctor: null,
@@ -960,20 +631,15 @@ async function runDoctor(args = [], root, doctorFix, deps = {}) {
960
631
  const doctorDirtyPlan = doctorFix ? (await import('../core/doctor/doctor-dirty-planner.js')).planDoctorDirtyRepair(root, doctorPhaseIds) : null;
961
632
  let setupRepair = null;
962
633
  let sksUpdate = null;
963
- let openRouterProviderRepair = { ok: true, status: 'skipped', reason: 'doctor_without_fix' };
634
+ const openRouterProviderRepair = {
635
+ ok: true,
636
+ status: 'read_only',
637
+ reason: 'Desktop Bridge owns provider credentials; Doctor does not migrate them.'
638
+ };
964
639
  let migrationPreFix = null;
965
640
  if (doctorFix) {
966
641
  migrationPreFix = await captureCodexConfigSnapshot();
967
642
  const installScope = installScopeFromArgs(args);
968
- openRouterProviderRepair = flag(args, '--local-only')
969
- ? { ok: true, status: 'skipped', reason: 'local-only repair' }
970
- : await (await import('../cli/install-helpers.js')).ensureStoredOpenRouterProviderDuringInstall().catch((err) => ({
971
- schema: 'sks.openrouter-provider-upgrade-repair.v1',
972
- ok: false,
973
- status: 'failed',
974
- blockers: ['openrouter_provider_repair_failed'],
975
- error: err?.message || String(err)
976
- }));
977
643
  setupRepair = {
978
644
  schema: 'sks.doctor-setup-phase.v2',
979
645
  ok: true,
@@ -1105,59 +771,12 @@ async function runDoctor(args = [], root, doctorFix, deps = {}) {
1105
771
  const codexApp = deepDiagnostics
1106
772
  ? await codexAppIntegrationStatus({ codex }).catch((err) => ({ ok: false, error: err.message }))
1107
773
  : { ok: false, skipped: true, warnings: ['codex_app_optional_diagnostic_skipped'] };
1108
- const codexLbCircuit = codexLbMetrics(await readCodexLbCircuit(root).catch(() => ({})));
1109
- const codexLbPreRepairStatus = doctorFix
1110
- ? await codexLbStatus({ probeToolOutputRecovery: false }).catch(() => null)
1111
- : null;
1112
- const codexLbSecretProbe = await inspectDoctorCodexLbSecretResolution({
1113
- processEnv: process.env,
1114
- fix: doctorFix,
1115
- forceRetry: flag(args, CODEX_LB_KEYCHAIN_MIGRATION_RETRY_FLAG),
1116
- baseUrl: codexLbPreRepairStatus?.base_url || codexLbPreRepairStatus?.provider_base_url || null
1117
- });
1118
- const codexLbProviderStatus = await codexLbStatus({
1119
- probeToolOutputRecovery: deepDiagnostics || doctorFix,
1120
- allowUnverifiedToolOutputRecovery: codexLbToolOutputRecoveryOverrideAcknowledged({ args })
1121
- }).catch((err) => ({
1122
- selected: null,
1123
- provider_ready: false,
1124
- recovery_probe_failed: deepDiagnostics || doctorFix,
1125
- tool_output_recovery: {
1126
- ok: false,
1127
- status: deepDiagnostics || doctorFix ? 'probe_failed' : 'not_checked',
1128
- blockers: deepDiagnostics || doctorFix ? ['codex_lb_tool_output_recovery_status_probe_failed'] : [],
1129
- operator_actions: []
1130
- },
1131
- error: err?.message || String(err)
1132
- }));
1133
- const codexLbRecoveryReady = codexLbRecoveryStatusReady(codexLbProviderStatus, deepDiagnostics || doctorFix);
1134
- const codexLbRoutingTruth = await codexLbRoutingTruthForStatus(codexLbProviderStatus, {
1135
- remeasure: deepDiagnostics || doctorFix
1136
- });
1137
- const codexLbRoutingReady = !doctorCodexLbRouteExpected(codexLbProviderStatus)
1138
- || codexLbRoutingTruthIsActive(codexLbRoutingTruth);
1139
- const codexLbDivergence = await inspectDoctorCodexLbDivergence({
1140
- processEnv: process.env,
1141
- providerStatus: codexLbProviderStatus,
1142
- fix: doctorFix,
1143
- ...(deps.codexLbLaunchctlBin ? { launchctlBin: deps.codexLbLaunchctlBin } : {}),
1144
- ...(deps.codexLbLaunchPlatform ? { platform: deps.codexLbLaunchPlatform } : {}),
1145
- ...(deps.codexLbLaunchRunProcessImpl ? { runProcessImpl: deps.codexLbLaunchRunProcessImpl } : {})
1146
- }, deps.codexLbDivergenceDeps || {});
1147
- const codexLb = {
1148
- ...codexLbCircuit,
1149
- provider_status: codexLbProviderStatus,
1150
- tool_output_recovery: codexLbProviderStatus?.tool_output_recovery || null,
1151
- recovery_ok: codexLbRecoveryReady,
1152
- routing_truth: codexLbRoutingTruth,
1153
- routing_ok: codexLbRoutingReady,
1154
- secret_resolution: codexLbSecretProbe.secret_resolution,
1155
- legacy_keychain_migration: codexLbSecretProbe.legacy_keychain_migration,
1156
- divergence: codexLbDivergence
1157
- };
774
+ const desktopBridge = await inspectDoctorDesktopBridgeStatus({
775
+ processEnv: process.env
776
+ }, { desktopBridgeStatusImpl: deps.desktopBridgeStatusImpl });
1158
777
  const providerContext = deepDiagnostics
1159
778
  ? await resolveProviderContext({ root, route: '$Doctor', serviceTier: process.env.SKS_SERVICE_TIER || 'fast' }).catch((err) => ({
1160
- schema: 'sks.provider-context.v1',
779
+ schema: 'sks.provider-context.v2',
1161
780
  generated_at: new Date().toISOString(),
1162
781
  provider: 'unknown',
1163
782
  auth_mode: 'unknown',
@@ -1169,29 +788,35 @@ async function runDoctor(args = [], root, doctorFix, deps = {}) {
1169
788
  warnings: [err?.message || String(err)],
1170
789
  signals: {
1171
790
  openai_api_key_present: false,
1172
- codex_lb_key_present: false,
1173
- codex_lb_explicit: false,
1174
791
  codex_app_auth_present: false,
1175
- model_provider: null
792
+ desktop_bridge_status_available: false,
793
+ desktop_bridge_managed: false,
794
+ desktop_bridge_ready: false,
795
+ desktop_bridge_provider: null,
796
+ desktop_bridge_native_identity_configured: false,
797
+ desktop_bridge_credential_state: null
1176
798
  }
1177
799
  }))
1178
800
  : {
1179
- schema: 'sks.provider-context.v1',
801
+ schema: 'sks.provider-context.v2',
1180
802
  generated_at: new Date().toISOString(),
1181
803
  provider: 'unknown',
1182
804
  auth_mode: 'unknown',
1183
805
  route: '$Doctor',
1184
806
  service_tier: process.env.SKS_SERVICE_TIER || 'fast',
1185
- source: 'skipped',
807
+ source: 'unknown',
1186
808
  confidence: 'low',
1187
809
  conflict: false,
1188
810
  warnings: ['provider_context_optional_diagnostic_skipped'],
1189
811
  signals: {
1190
812
  openai_api_key_present: false,
1191
- codex_lb_key_present: false,
1192
- codex_lb_explicit: false,
1193
813
  codex_app_auth_present: false,
1194
- model_provider: null
814
+ desktop_bridge_status_available: false,
815
+ desktop_bridge_managed: false,
816
+ desktop_bridge_ready: false,
817
+ desktop_bridge_provider: null,
818
+ desktop_bridge_native_identity_configured: false,
819
+ desktop_bridge_credential_state: null
1195
820
  }
1196
821
  };
1197
822
  const explicitCodexAppUiRepair = flag(args, '--repair-codex-app-ui');
@@ -1252,7 +877,6 @@ async function runDoctor(args = [], root, doctorFix, deps = {}) {
1252
877
  'Run: sks menubar status',
1253
878
  'Run: sks menubar install',
1254
879
  'Run: sks menubar restart',
1255
- 'Rotate CODEX_LB_API_KEY and OPENROUTER_API_KEY if they were previously exposed in launchd.'
1256
880
  ],
1257
881
  blockers: [err?.message || String(err)],
1258
882
  warnings: []
@@ -1750,7 +1374,7 @@ async function runDoctor(args = [], root, doctorFix, deps = {}) {
1750
1374
  codex,
1751
1375
  codex_config: codexConfig,
1752
1376
  codex_app: codexApp,
1753
- codex_lb: codexLb,
1377
+ desktop_bridge: desktopBridge,
1754
1378
  codex_doctor: authoritativeCodexDoctor,
1755
1379
  pre_repair_codex_doctor: preRepairCodexDoctor,
1756
1380
  post_repair_codex_doctor: postRepairCodexDoctor,
@@ -1786,7 +1410,7 @@ async function runDoctor(args = [], root, doctorFix, deps = {}) {
1786
1410
  ...(codexStartupRepair.manual_actions || []),
1787
1411
  ...(codexConfigSyntaxRepair?.manual_actions || []),
1788
1412
  ...(pluginPolicy?.doctor_warnings || []),
1789
- ...(codexLbSecretProbe.legacy_keychain_migration?.operator_actions || []),
1413
+ ...(desktopBridge.ok === false ? desktopBridge.recovery_actions || [] : []),
1790
1414
  ...telegramDoctorOperatorActions(telegramRemote)
1791
1415
  ]
1792
1416
  };
@@ -1874,10 +1498,7 @@ async function runDoctor(args = [], root, doctorFix, deps = {}) {
1874
1498
  && agentRoleConfigRepair.ok !== false
1875
1499
  && openRouterProviderRepair.ok !== false
1876
1500
  && (officialSubagentConfig.blockers || []).length === 0
1877
- && codexLbSecretProbe.ok !== false
1878
- && codexLbDivergence.ok !== false
1879
- && codexLbRecoveryReady
1880
- && codexLbRoutingReady;
1501
+ && (!doctorProfileRequiresDesktopBridgeReadiness(doctorProfile) || desktopBridge.ok !== false);
1881
1502
  const result = {
1882
1503
  schema: 'sks.doctor-status.v3',
1883
1504
  elapsed_ms: Date.now() - startedAtMs,
@@ -1892,11 +1513,10 @@ async function runDoctor(args = [], root, doctorFix, deps = {}) {
1892
1513
  not_counted_as_full_doctor: !deepDiagnostics,
1893
1514
  root,
1894
1515
  arg_warnings: argWarnings,
1895
- warnings: [...oauthCallbackPortDiagnostic.warnings, ...(codexLbDivergence.warnings || [])],
1516
+ warnings: [...oauthCallbackPortDiagnostic.warnings, ...(desktopBridge.warnings || [])],
1896
1517
  operator_actions: [
1897
1518
  ...oauthCallbackOperatorActions,
1898
- ...(codexLbSecretProbe.legacy_keychain_migration?.operator_actions || []),
1899
- ...(codexLbDivergence.operator_actions || [])
1519
+ ...(desktopBridge.ok === false ? desktopBridge.recovery_actions || [] : [])
1900
1520
  ],
1901
1521
  node: { ok: Number(process.versions.node.split('.')[0]) >= 20, version: process.version },
1902
1522
  codex,
@@ -1905,11 +1525,11 @@ async function runDoctor(args = [], root, doctorFix, deps = {}) {
1905
1525
  rust,
1906
1526
  codex_app: codexApp,
1907
1527
  codex_app_ui: codexAppUi,
1908
- openrouter_provider: openRouterProviderRepair,
1528
+ openrouter_provider: desktopBridge.providers?.openrouter || null,
1909
1529
  sks_menubar: sksMenuBar,
1910
1530
  telegram_remote: telegramRemote,
1911
1531
  provider_context: providerContext,
1912
- codex_lb: codexLb,
1532
+ desktop_bridge: desktopBridge,
1913
1533
  codex_doctor: authoritativeCodexDoctor,
1914
1534
  pre_repair_codex_doctor: preRepairCodexDoctor,
1915
1535
  post_repair_codex_doctor: postRepairCodexDoctor,
@@ -2188,25 +1808,20 @@ async function runDoctor(args = [], root, doctorFix, deps = {}) {
2188
1808
  console.log(` warning: ${warning}`);
2189
1809
  if (codexCurrentAppDoctor?.fixed?.length)
2190
1810
  console.log(` doctor --fix repaired: ${codexCurrentAppDoctor.fixed.join(', ')}`);
2191
- console.log(`codex-lb: ${codexLb.ok ? 'ok' : `warning ${codexLb.circuit?.state || 'unknown'}`}`);
2192
- console.log(` key source: ${codexLb.secret_resolution.source}${codexLb.secret_resolution.path ? ` (${codexLb.secret_resolution.path})` : ''}; prompt risk: ${codexLb.secret_resolution.prompt_risk}`);
2193
- for (const action of codexLb.legacy_keychain_migration?.operator_actions || [])
2194
- console.log(` action: ${action}`);
2195
- for (const warning of codexLb.divergence?.warnings || [])
1811
+ console.log(`Desktop Bridge: ${desktopBridge.ok ? 'ready' : 'blocked'} (${desktopBridge.status?.readiness?.state || 'unavailable'})`);
1812
+ for (const providerId of ['codex-lb', 'openrouter']) {
1813
+ const provider = desktopBridge.providers?.[providerId];
1814
+ if (!provider)
1815
+ continue;
1816
+ console.log(` ${providerId}: ${provider.enabled ? 'enabled' : 'disabled'}; credential ${provider.credential?.state || 'unknown'} (${provider.credential?.source || 'none'}); endpoint ${provider.endpoint?.configured ? 'configured' : 'missing'}`);
1817
+ }
1818
+ for (const warning of desktopBridge.warnings || [])
2196
1819
  console.log(` warning: ${warning}`);
2197
- for (const action of codexLb.divergence?.operator_actions || [])
2198
- console.log(` action: ${action}`);
2199
- if (codexLb.routing_truth) {
2200
- const routingTruth = codexLb.routing_truth;
2201
- console.log(` routing truth: ${codexLb.routing_ok ? 'verified' : 'blocked'} (${routingTruth.actual_host || routingTruth.configured_host || 'host unavailable'}, ${routingTruth.auth_outcome}, ${routingTruth.latency_ms ?? 'unmeasured'} ms at ${routingTruth.checked_at})`);
2202
- }
2203
- if (codexLb.tool_output_recovery) {
2204
- const recovery = codexLb.tool_output_recovery;
2205
- console.log(` interrupted tool-output recovery: ${recovery.ok ? 'ready' : 'blocked'} (${recovery.observed_version || recovery.status}; minimum ${recovery.minimum_version})`);
2206
- if (!recovery.ok)
2207
- for (const action of recovery.operator_actions || [])
2208
- console.log(` action: ${action}`);
2209
- }
1820
+ for (const blocker of desktopBridge.blockers || [])
1821
+ console.log(` blocker: ${blocker}`);
1822
+ if (!desktopBridge.ok)
1823
+ for (const action of desktopBridge.recovery_actions || [])
1824
+ console.log(` action: ${action}`);
2210
1825
  if (localModel) {
2211
1826
  console.log('Local LLM:');
2212
1827
  console.log(` enabled: ${localModel.enabled ? 'yes' : 'no'}`);
@@ -2253,377 +1868,3 @@ async function runDoctor(args = [], root, doctorFix, deps = {}) {
2253
1868
  if (!result.ok)
2254
1869
  process.exitCode = 1;
2255
1870
  }
2256
- export function buildRuntimeReadiness(matrix) {
2257
- const defaults = matrix?.invocation_defaults || {};
2258
- const hookPolicy = defaults.hook_evidence_policy || 'unknown-do-not-count';
2259
- const agentStrategy = defaults.loop_worker_role_strategy || 'message-role';
2260
- const multiAgentMode = defaults.multi_agent_mode || 'none';
2261
- const rolloutBudget = defaults.rollout_budget_strategy || 'sks-local-only';
2262
- const researchSource = defaults.research_source_strategy || 'local-files';
2263
- const codexNative = matrix?.ok === true ? 'ok' : matrix?.codex_cli?.available ? 'degraded' : 'blocked';
2264
- const repairActions = [];
2265
- if (codexNative !== 'ok') {
2266
- repairActions.push([
2267
- 'Codex Native managed assets: sks doctor',
2268
- '--fix',
2269
- '--repair-codex-native',
2270
- '--yes'
2271
- ].join(' '));
2272
- }
2273
- if (matrix?.features?.project_memory?.ok !== true)
2274
- repairActions.push('Project memory: sks codex-native init-deep --apply --directory-local');
2275
- return {
2276
- schema: 'sks.runtime-readiness-story.v1',
2277
- codex_native: codexNative,
2278
- loop_mesh: agentStrategy === 'agent_type' ? 'ok' : 'fallback',
2279
- qa_visual: defaults.qa_visual_review_strategy || 'blocked',
2280
- research_sources: researchSource,
2281
- image_followup: defaults.image_followup_strategy || 'blocked',
2282
- hook_evidence_policy: hookPolicy,
2283
- agent_role_strategy: agentStrategy,
2284
- multi_agent_mode: multiAgentMode,
2285
- rollout_budget_strategy: rolloutBudget,
2286
- current_time_source: defaults.current_time_source || 'external-clock',
2287
- overload_retry_policy: defaults.overload_retry_policy || 'generic',
2288
- notes: [
2289
- ...(hookPolicy !== 'approved-only' ? ['hook-derived evidence will not count'] : []),
2290
- ...(agentStrategy !== 'agent_type' ? ['message-role fallback active'] : []),
2291
- ...(multiAgentMode === 'proactive' ? ['Proactive multi-agent mode is available for Naruto-style routes'] : []),
2292
- ...(rolloutBudget === 'codex-current-shared' ? ['Shared rollout budgeting is available for route proof'] : []),
2293
- ...(researchSource === 'indexed-web-search' ? ['Indexed web search is selected for source-intelligence routes'] : [])
2294
- ],
2295
- repair_actions: [...new Set(repairActions)]
2296
- };
2297
- }
2298
- function deferredNativeRepair(schema, doctorFix, nextActions) {
2299
- return {
2300
- schema,
2301
- generated_at: nowIso(),
2302
- ok: true,
2303
- skipped: true,
2304
- status: 'deferred_to_explicit_native_capability_probe',
2305
- attempted: false,
2306
- apply: doctorFix,
2307
- recovered: false,
2308
- blockers: [],
2309
- next_actions: nextActions,
2310
- manual_actions: nextActions
2311
- };
2312
- }
2313
- function fallbackCodexNativeFeatureMatrix(codex, blockers = [], warnings = []) {
2314
- return {
2315
- schema: 'sks.codex-native-feature-matrix.v1',
2316
- ok: blockers.length === 0,
2317
- skipped: blockers.length === 0,
2318
- codex_cli: { available: Boolean(codex?.bin || codex?.available), version: codex?.version || null, bin: codex?.bin || null },
2319
- features: {},
2320
- invocation_defaults: {
2321
- loop_worker_role_strategy: 'message-role',
2322
- multi_agent_mode: 'none',
2323
- rollout_budget_strategy: 'sks-local-only',
2324
- qa_visual_review_strategy: 'route-gated',
2325
- research_source_strategy: 'local-files',
2326
- image_followup_strategy: 'artifact-path',
2327
- hook_evidence_policy: 'unknown-do-not-count',
2328
- skill_bridge_strategy: 'cli-only',
2329
- current_time_source: 'external-clock',
2330
- overload_retry_policy: 'generic'
2331
- },
2332
- blockers,
2333
- warnings
2334
- };
2335
- }
2336
- async function writeJsonReportFile(file, value) {
2337
- const fsp = await import('node:fs/promises');
2338
- const path = await import('node:path');
2339
- await fsp.mkdir(path.dirname(file), { recursive: true });
2340
- await fsp.writeFile(file, `${JSON.stringify(value, null, 2)}\n`, 'utf8');
2341
- }
2342
- function nativeCapabilityStatus(rows, id, fallback) {
2343
- const row = rows.find((entry) => entry?.id === id);
2344
- if (!row)
2345
- return fallback;
2346
- if (row.after === 'verified' || row.before === 'verified')
2347
- return 'verified';
2348
- if (id === 'image_path_exposure') {
2349
- if (row.before === 'degraded' || row.after === 'degraded' || row.repairability === 'doctor-fix')
2350
- return 'fallback';
2351
- return fallback;
2352
- }
2353
- if (id === 'app_handoff')
2354
- return 'unavailable';
2355
- if (row.repairability === 'manual-required')
2356
- return 'manual_required';
2357
- if (row.before === 'degraded' || row.after === 'degraded')
2358
- return 'degraded';
2359
- if (row.repairability === 'doctor-fix')
2360
- return row.after === 'blocked' ? 'blocked' : 'repair_required';
2361
- if (row.repairability === 'unavailable')
2362
- return 'unavailable';
2363
- return fallback;
2364
- }
2365
- function uniqueNativeManualActions(rows) {
2366
- return [...new Set(rows
2367
- .filter((row) => row?.repairability === 'manual-required' && row?.after !== 'verified')
2368
- .flatMap((row) => Array.isArray(row.repair_actions) ? row.repair_actions : [])
2369
- .filter((action) => typeof action === 'string' && action.trim()))];
2370
- }
2371
- function doctorSkillStatus(coreSkills) {
2372
- if (!coreSkills)
2373
- return 'drift_detected';
2374
- if (Array.isArray(coreSkills.restored) && coreSkills.restored.length)
2375
- return 'repaired';
2376
- if (Array.isArray(coreSkills.blockers) && coreSkills.blockers.length)
2377
- return 'drift_detected';
2378
- return 'current';
2379
- }
2380
- function doctorDedupeStatus(skillDedupe) {
2381
- if (!skillDedupe)
2382
- return 'manual_required';
2383
- if (Array.isArray(skillDedupe.actions) && skillDedupe.actions.some((action) => action.action === 'quarantined'))
2384
- return 'repaired';
2385
- if (Array.isArray(skillDedupe.blockers) && skillDedupe.blockers.length)
2386
- return 'manual_required';
2387
- return 'none';
2388
- }
2389
- async function codexHomeConfigPath() {
2390
- const path = await import('node:path');
2391
- const os = await import('node:os');
2392
- const home = process.env.CODEX_HOME || path.join(process.env.HOME || os.homedir(), '.codex');
2393
- return path.join(home, 'config.toml');
2394
- }
2395
- async function captureCodexConfigSnapshot() {
2396
- const fsp = await import('node:fs/promises');
2397
- const path = await import('node:path');
2398
- const read = async (p) => {
2399
- if (!p)
2400
- return null;
2401
- try {
2402
- return await fsp.readFile(p, 'utf8');
2403
- }
2404
- catch {
2405
- return null;
2406
- }
2407
- };
2408
- const root = await projectRoot();
2409
- const projectPath = root ? path.join(root, '.codex', 'config.toml') : null;
2410
- const homePath = await codexHomeConfigPath();
2411
- return {
2412
- project_path: projectPath,
2413
- project_text: await read(projectPath),
2414
- home_path: homePath,
2415
- home_text: await read(homePath)
2416
- };
2417
- }
2418
- async function writeFixMigrationJournal(root, preFix, configRepair, setupRepair) {
2419
- if (!preFix)
2420
- return null;
2421
- const fsp = await import('node:fs/promises');
2422
- const read = async (p) => {
2423
- if (!p)
2424
- return null;
2425
- try {
2426
- return await fsp.readFile(p, 'utf8');
2427
- }
2428
- catch {
2429
- return null;
2430
- }
2431
- };
2432
- const projectAfter = await read(preFix.project_path);
2433
- const homeAfter = await read(preFix.home_path);
2434
- const structureRepairs = Array.isArray(configRepair?.structure_repairs) ? configRepair.structure_repairs : [];
2435
- const projectStructure = structureRepairs.find((repair) => repair.scope === 'project');
2436
- const homeStructure = structureRepairs.find((repair) => repair.scope === 'codex_home');
2437
- const events = [
2438
- {
2439
- step: 'doctor_fix_project_config',
2440
- target: preFix.project_path || '.codex/config.toml',
2441
- beforeHash: preFix.project_text != null ? hashConfigText(preFix.project_text) : null,
2442
- afterHash: projectAfter != null ? hashConfigText(projectAfter) : null,
2443
- backupPath: setupRepair?.config_backup_path || projectStructure?.backup_path || configRepair?.policy?.backup_path || null
2444
- },
2445
- {
2446
- step: 'doctor_fix_codex_home_config',
2447
- target: preFix.home_path || '~/.codex/config.toml',
2448
- beforeHash: preFix.home_text != null ? hashConfigText(preFix.home_text) : null,
2449
- afterHash: homeAfter != null ? hashConfigText(homeAfter) : null,
2450
- backupPath: homeStructure?.backup_path || null
2451
- }
2452
- ].filter((event) => event.beforeHash != null || event.afterHash != null);
2453
- if (!events.length)
2454
- return null;
2455
- return appendMigrationEvents(root, events);
2456
- }
2457
- async function backupProjectConfigBeforeFix() {
2458
- try {
2459
- const fsp = await import('node:fs/promises');
2460
- const path = await import('node:path');
2461
- const root = await projectRoot();
2462
- if (!root)
2463
- return null;
2464
- const configPath = path.join(root, '.codex', 'config.toml');
2465
- if (!(await exists(configPath)))
2466
- return null;
2467
- const text = await fsp.readFile(configPath, 'utf8');
2468
- const backupPath = `${configPath}.doctor-pre-fix-${Date.now().toString(36)}.bak`;
2469
- await fsp.writeFile(backupPath, text);
2470
- return backupPath;
2471
- }
2472
- catch {
2473
- return null;
2474
- }
2475
- }
2476
- function installScopeFromArgs(args = []) {
2477
- if (flag(args, '--project'))
2478
- return 'project';
2479
- if (flag(args, '--global'))
2480
- return 'global';
2481
- const index = args.indexOf('--install-scope');
2482
- return normalizeInstallScope(index >= 0 && args[index + 1] ? args[index + 1] : 'global');
2483
- }
2484
- function isMigrationUserOwnedProjectConfigBlocker(blocker) {
2485
- const value = String(blocker || '').trim();
2486
- return value === 'user_owned_file_without_sks_marker'
2487
- || value.endsWith(':user_owned_file_without_sks_marker')
2488
- || value === 'config_write_guard:blocked_unmanaged_project_config'
2489
- || value.endsWith(':config_write_guard:blocked_unmanaged_project_config');
2490
- }
2491
- function readOption(args = [], name, fallback = null) {
2492
- const index = args.indexOf(name);
2493
- return index >= 0 && args[index + 1] ? args[index + 1] : fallback;
2494
- }
2495
- export function buildCodexAppUiDiagnosticFailure(apply, error) {
2496
- return {
2497
- schema: 'sks.codex-app-fast-ui-repair.v1',
2498
- ok: false,
2499
- apply,
2500
- safe_auto_apply: false,
2501
- requires_confirmation: true,
2502
- fast_selector: 'manual_action_required',
2503
- provider_selector: 'manual_action_required',
2504
- host_owned_config: 'diagnostic_failed',
2505
- next_action: 'Review Codex App UI config manually.',
2506
- actions: [],
2507
- blockers: [error instanceof Error ? error.message : String(error)]
2508
- };
2509
- }
2510
- export function formatCodexDoctorConsoleStatus(report) {
2511
- if (!report || report.available !== true)
2512
- return 'unavailable';
2513
- return report.disposition || (report.exit_code === 0 ? 'pass' : 'warn');
2514
- }
2515
- export function sksMenuBarRunningVersionConsoleLines(status) {
2516
- const runningVersion = status?.running_process?.package_version
2517
- || status?.menubar_version_probe?.running_version
2518
- || null;
2519
- const runningPid = status?.running_process?.pid ?? status?.menubar_version_probe?.pid ?? null;
2520
- if (typeof runningVersion !== 'string' || !runningVersion || !Number.isInteger(runningPid) || runningPid <= 0) {
2521
- return [];
2522
- }
2523
- const expectedVersion = status?.menubar_version_probe?.expected_version
2524
- || status?.action_target?.expected_version
2525
- || status?.package_version
2526
- || null;
2527
- const installedVersion = status?.installed_version || status?.build_stamp?.package_version || null;
2528
- return [
2529
- ` RUNNING: version ${runningVersion} (PID ${runningPid})`,
2530
- ...(typeof expectedVersion === 'string' && expectedVersion && expectedVersion !== runningVersion
2531
- ? [` expected: version ${expectedVersion}`]
2532
- : []),
2533
- ...(typeof installedVersion === 'string' && installedVersion && installedVersion !== runningVersion
2534
- ? [` installed: version ${installedVersion}`]
2535
- : [])
2536
- ];
2537
- }
2538
- export async function rebootstrapSksMenuBarLaunchdForDoctorFix(input, deps = {}) {
2539
- const env = input.env || process.env;
2540
- const status = input.status;
2541
- const expectedVersion = status?.menubar_version_probe?.expected_version
2542
- || status?.action_target?.expected_version
2543
- || status?.installed_version
2544
- || null;
2545
- const warningOnlyVerifiedProcess = input.fix
2546
- && !sksMenuBarRestartDeferred(env)
2547
- && status?.launchd?.checked === true
2548
- && status?.launchd?.ok === false
2549
- && Array.isArray(status?.warnings)
2550
- && status.warnings.includes('launchd_not_running_process_active')
2551
- && !(Array.isArray(status?.blockers) && status.blockers.includes('launchd_not_running'))
2552
- && status?.running_process?.ok === true
2553
- && typeof expectedVersion === 'string'
2554
- && status.running_process.package_version === expectedVersion;
2555
- if (!warningOnlyVerifiedProcess) {
2556
- return { attempted: false, ok: true, status, restart: null };
2557
- }
2558
- const paths = sksMenuBarPaths(input.home || env.HOME, input.root);
2559
- const restartImpl = deps.restartLaunchAgentImpl || restartLaunchAgent;
2560
- const inspectImpl = deps.inspectSksMenuBarStatusImpl || inspectSksMenuBarStatus;
2561
- const restart = await restartImpl(paths, env).catch((error) => ({
2562
- ok: false,
2563
- error: error instanceof Error ? error.message : String(error)
2564
- }));
2565
- if (restart?.ok !== true) {
2566
- const detail = restart?.error ? `:${restart.error}` : '';
2567
- return {
2568
- attempted: true,
2569
- ok: false,
2570
- restart,
2571
- status: {
2572
- ...status,
2573
- ok: false,
2574
- blockers: [...new Set([...(status?.blockers || []), `launchd_rebootstrap_failed${detail}`])]
2575
- }
2576
- };
2577
- }
2578
- const refreshed = await inspectImpl({
2579
- root: input.root,
2580
- ...(input.home ? { home: input.home } : {}),
2581
- ...(input.env ? { env: input.env } : {})
2582
- }).catch((error) => ({
2583
- ...status,
2584
- ok: false,
2585
- blockers: [...new Set([
2586
- ...(status?.blockers || []),
2587
- `launchd_rebootstrap_status_failed:${error instanceof Error ? error.message : String(error)}`
2588
- ])]
2589
- }));
2590
- if (refreshed?.launchd?.checked !== true || refreshed?.launchd?.ok !== true) {
2591
- return {
2592
- attempted: true,
2593
- ok: false,
2594
- restart,
2595
- status: {
2596
- ...refreshed,
2597
- ok: false,
2598
- blockers: [...new Set([...(refreshed?.blockers || []), 'launchd_rebootstrap_not_confirmed'])]
2599
- }
2600
- };
2601
- }
2602
- return { attempted: true, ok: true, status: refreshed, restart };
2603
- }
2604
- function mergeObservedCodexStartupWarnings(startupRepair, codexDoctor) {
2605
- const text = `${codexDoctor?.stdout_tail || ''}\n${codexDoctor?.stderr_tail || ''}`;
2606
- const manual = new Set(Array.isArray(startupRepair?.manual_actions) ? startupRepair.manual_actions : []);
2607
- const warnings = new Set(Array.isArray(startupRepair?.warnings) ? startupRepair.warnings : []);
2608
- const blockers = new Set(Array.isArray(startupRepair?.blockers) ? startupRepair.blockers : []);
2609
- if (/codex_apps[\s\S]{0,500}token_expired|token_expired[\s\S]{0,500}codex_apps/i.test(text)) {
2610
- manual.add('Codex Apps MCP token is expired; sign in to Codex App/CLI again so the connector can mint a fresh token.');
2611
- warnings.add('codex_apps_token_expired_observed');
2612
- blockers.add('codex_apps_token_expired_manual_reauth_required');
2613
- }
2614
- if (/SUPABASE_ACCESS_TOKEN[\s\S]{0,500}mcp server ['"`]?supabase['"`]?|mcp server ['"`]?supabase['"`]?[\s\S]{0,500}SUPABASE_ACCESS_TOKEN/i.test(text)) {
2615
- manual.add('Supabase MCP uses SUPABASE_ACCESS_TOKEN but the variable is unset; export the token or migrate that server to a read-only remote URL.');
2616
- warnings.add('supabase_access_token_missing_observed');
2617
- blockers.add('supabase_access_token_missing_manual_auth_required');
2618
- }
2619
- if (/node_repl[\s\S]{0,500}No such file or directory|No such file or directory[\s\S]{0,500}node_repl/i.test(text)) {
2620
- warnings.add('node_repl_missing_command_observed');
2621
- }
2622
- return {
2623
- ...startupRepair,
2624
- ok: blockers.size === 0 && startupRepair?.ok !== false,
2625
- manual_actions: [...manual],
2626
- warnings: [...warnings],
2627
- blockers: [...blockers]
2628
- };
2629
- }