sneakoscope 7.3.0 → 7.6.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 (283) hide show
  1. package/README.md +129 -10
  2. package/crates/sks-core/Cargo.lock +1 -1
  3. package/crates/sks-core/Cargo.toml +1 -1
  4. package/dist/cli/codex-app-command.js +1 -1
  5. package/dist/cli/command-manifest-lite.js +4 -1
  6. package/dist/cli/command-registry.js +2 -0
  7. package/dist/cli/install-helpers-codex-lb-chain.js +42 -0
  8. package/dist/cli/install-helpers-codex-lb-config.js +114 -9
  9. package/dist/cli/install-helpers-install-support.js +6 -16
  10. package/dist/cli/install-helpers.js +788 -600
  11. package/dist/cli/router.js +30 -2
  12. package/dist/commands/codex-app.js +37 -1
  13. package/dist/commands/codex-lb.js +491 -300
  14. package/dist/config/skills-manifest.json +57 -71
  15. package/dist/core/align/align-route.js +127 -0
  16. package/dist/core/codex-app/codex-app-fast-ui-repair.js +8 -4
  17. package/dist/core/codex-app/codex-app-restart.js +83 -0
  18. package/dist/core/codex-app/codex-app-ui-state-snapshot.js +8 -4
  19. package/dist/core/codex-app/desktop-routing-snapshot.js +1 -1
  20. package/dist/core/codex-app/menubar/constants.js +5 -0
  21. package/dist/core/codex-app/menubar/generation-transaction-journal.js +1 -3
  22. package/dist/core/codex-app/menubar/installer.js +18 -0
  23. package/dist/core/codex-app/multi-provider-router.js +22 -10
  24. package/dist/core/codex-app/openrouter-activate.js +26 -1
  25. package/dist/core/codex-app.js +118 -26
  26. package/dist/core/codex-control/codex-app-server-runtime-env.js +86 -0
  27. package/dist/core/codex-control/codex-app-server-v2-client.js +78 -8
  28. package/dist/core/codex-control/codex-task-runner.js +2 -2
  29. package/dist/core/codex-lb/capability-runner.js +204 -0
  30. package/dist/core/codex-lb/capability-types.js +1 -0
  31. package/dist/core/codex-lb/codex-lb-env.js +9 -13
  32. package/dist/core/codex-lb/codex-lb-setup.js +45 -8
  33. package/dist/core/codex-lb/codex-lb-tool-catalog.js +52 -74
  34. package/dist/core/codex-lb/codex-lb-tool-output-recovery.js +1 -1
  35. package/dist/core/codex-lb/desktop-auth-invariant.js +185 -0
  36. package/dist/core/codex-lb/desktop-bridge/client.js +34 -0
  37. package/dist/core/codex-lb/desktop-bridge/header-policy.js +106 -0
  38. package/dist/core/codex-lb/desktop-bridge/http-forward.js +101 -0
  39. package/dist/core/codex-lb/desktop-bridge/index.js +10 -0
  40. package/dist/core/codex-lb/desktop-bridge/launchd.js +81 -0
  41. package/dist/core/codex-lb/desktop-bridge/location-rewrite.js +27 -0
  42. package/dist/core/codex-lb/desktop-bridge/security.js +274 -0
  43. package/dist/core/codex-lb/desktop-bridge/server.js +179 -0
  44. package/dist/core/codex-lb/desktop-bridge/state.js +119 -0
  45. package/dist/core/codex-lb/desktop-bridge/types.js +16 -0
  46. package/dist/core/codex-lb/desktop-bridge/websocket-forward.js +151 -0
  47. package/dist/core/codex-lb/desktop-center-credentials.js +189 -0
  48. package/dist/core/codex-lb/desktop-controller.js +1410 -0
  49. package/dist/core/codex-lb/desktop-mode.js +32 -0
  50. package/dist/core/codex-lb/desktop-real-evidence.js +168 -0
  51. package/dist/core/codex-lb/desktop-service.js +613 -0
  52. package/dist/core/codex-lb/legacy-migration.js +575 -0
  53. package/dist/core/codex-lb/migration-receipt.js +246 -0
  54. package/dist/core/codex-lb/probes/auxiliary-surfaces-probe.js +60 -0
  55. package/dist/core/codex-lb/probes/bridge-probe.js +75 -0
  56. package/dist/core/codex-lb/probes/catalog-probe.js +128 -0
  57. package/dist/core/codex-lb/probes/computer-use-probe.js +50 -0
  58. package/dist/core/codex-lb/probes/image-generation-probe.js +47 -0
  59. package/dist/core/codex-lb/probes/probe-evidence.js +39 -0
  60. package/dist/core/codex-lb/probes/voice-realtime-probe.js +44 -0
  61. package/dist/core/codex-lb/trusted-deep-evidence.js +403 -0
  62. package/dist/core/codex-native/core-skill-manifest.js +22 -6
  63. package/dist/core/codex-runtime/codex-desktop-config-policy.js +2 -1
  64. package/dist/core/commands/align-command.js +220 -0
  65. package/dist/core/commands/image-ux-review-command.js +280 -68
  66. package/dist/core/commands/naruto-command.js +257 -8
  67. package/dist/core/commands/ppt-command.js +2 -2
  68. package/dist/core/commands/telegram-command.js +402 -34
  69. package/dist/core/commands/triwiki-command.js +11 -1
  70. package/dist/core/commands/triwiki-graph-command.js +160 -0
  71. package/dist/core/commands/wiki-command.js +100 -20
  72. package/dist/core/doctor/skill-legacy-surface.js +1 -3
  73. package/dist/core/errors/message.js +3 -0
  74. package/dist/core/evidence/evidence-freshness.js +14 -0
  75. package/dist/core/feature-fixtures.js +9 -1
  76. package/dist/core/feature-registry.js +5 -3
  77. package/dist/core/fsx.js +7 -3
  78. package/dist/core/hooks-runtime/codex-commit-hooks-selftest.js +82 -0
  79. package/dist/core/hooks-runtime/context-graph-freshness-preflight.js +113 -0
  80. package/dist/core/hooks-runtime/hook-context.js +15 -2
  81. package/dist/core/hooks-runtime/managed-skill-generation-heal.js +46 -0
  82. package/dist/core/hooks-runtime/naruto-terminal-finalization.js +1 -0
  83. package/dist/core/hooks-runtime/official-subagent-lifecycle.js +1 -1
  84. package/dist/core/hooks-runtime/tool-output-quarantine.js +1 -1
  85. package/dist/core/hooks-runtime.js +33 -89
  86. package/dist/core/image-ux-review/callout-extraction.js +6 -0
  87. package/dist/core/image-ux-review/imagegen-adapter.js +64 -23
  88. package/dist/core/image-ux-review/real-callout-extractor.js +1 -0
  89. package/dist/core/image-ux-review.js +230 -12
  90. package/dist/core/imagegen/codex-lb-imagegen-target.js +21 -7
  91. package/dist/core/imagegen/imagegen-capability.js +10 -4
  92. package/dist/core/imagegen/require-imagegen.js +29 -5
  93. package/dist/core/init/skills.js +25 -13
  94. package/dist/core/init.js +1 -1
  95. package/dist/core/install/installed-package-smoke.js +157 -4
  96. package/dist/core/managed-assets/managed-assets-manifest.js +2 -1
  97. package/dist/core/managed-path-safety.js +8 -10
  98. package/dist/core/mcp-config/backup.js +2 -4
  99. package/dist/core/mcp-config/config-reader.js +2 -4
  100. package/dist/core/mcp-config/scope.js +3 -5
  101. package/dist/core/naruto/context-graph-advisor-scope.js +242 -0
  102. package/dist/core/naruto/context-graph-advisor.js +0 -0
  103. package/dist/core/perf/release-latency-slo.js +12 -6
  104. package/dist/core/pipeline-internals/runtime-core.js +78 -0
  105. package/dist/core/pipeline-internals/runtime-gates.js +5 -2
  106. package/dist/core/policy/latest-version-guidance.js +113 -0
  107. package/dist/core/ppt.js +8 -8
  108. package/dist/core/preflight/parallel-preflight-engine.js +1 -1
  109. package/dist/core/proof/auto-finalize.js +98 -6
  110. package/dist/core/proof/route-proof-gate.js +12 -1
  111. package/dist/core/proof/route-proof-policy.js +8 -8
  112. package/dist/core/release/gate-manifest.js +32 -1
  113. package/dist/core/release/npm-stage-contract.js +21 -0
  114. package/dist/core/release/package-size-budget.js +2 -2
  115. package/dist/core/release/release-gate-contract.js +5 -0
  116. package/dist/core/release/release-proof-io.js +1 -3
  117. package/dist/core/release/release-real-contract.js +5 -4
  118. package/dist/core/release/release-stamp-proof.js +1 -3
  119. package/dist/core/release/stage-publish.js +27 -0
  120. package/dist/core/remote/audit-idempotency.js +50 -18
  121. package/dist/core/remote/codex-public-activity.js +283 -0
  122. package/dist/core/remote/index.js +1 -0
  123. package/dist/core/remote/ssh-worker-client.js +4 -1
  124. package/dist/core/remote/worker.js +206 -27
  125. package/dist/core/research/research-adversarial-review.js +1 -3
  126. package/dist/core/research/research-claim-synthesizer.js +1 -3
  127. package/dist/core/research/research-falsification-runner.js +1 -3
  128. package/dist/core/research/research-source-evidence.js +1 -3
  129. package/dist/core/responses-stream.js +65 -19
  130. package/dist/core/routes/constants.js +1 -1
  131. package/dist/core/routes/design-policy.js +7 -2
  132. package/dist/core/routes/dollar-manifest-lite.js +2 -4
  133. package/dist/core/routes/evidence.js +1 -1
  134. package/dist/core/routes.js +30 -10
  135. package/dist/core/safety/command-contract/contracts.js +2 -0
  136. package/dist/core/safety/command-contract/types.js +1 -1
  137. package/dist/core/search/context-graph-seeds.js +205 -0
  138. package/dist/core/search/context.js +0 -0
  139. package/dist/core/search/provider.js +2 -2
  140. package/dist/core/secret-redaction.js +6 -0
  141. package/dist/core/subagents/naruto-help-contract.js +2 -1
  142. package/dist/core/subagents/naruto-host-credentials.js +161 -0
  143. package/dist/core/subagents/official-subagent-preparation.js +4 -1
  144. package/dist/core/subagents/official-subagent-prompt.js +44 -2
  145. package/dist/core/subagents/official-subagent-runner.js +26 -8
  146. package/dist/core/subagents/triwiki-attention.js +135 -123
  147. package/dist/core/telegram/bot-api.js +85 -10
  148. package/dist/core/telegram/center-snapshot.js +718 -0
  149. package/dist/core/telegram/config.js +158 -31
  150. package/dist/core/telegram/hub.js +288 -33
  151. package/dist/core/telegram/index.js +2 -0
  152. package/dist/core/telegram/ingress-spool.js +419 -0
  153. package/dist/core/telegram/ledgers.js +188 -29
  154. package/dist/core/telegram/messages.js +26 -6
  155. package/dist/core/telegram/owner-lock.js +10 -7
  156. package/dist/core/telegram/runtime-projection.js +38 -3
  157. package/dist/core/telegram/runtime.js +298 -63
  158. package/dist/core/telegram/service.js +137 -8
  159. package/dist/core/telegram/setup.js +291 -73
  160. package/dist/core/text/strings.js +3 -0
  161. package/dist/core/triwiki/code-pack.js +12 -120
  162. package/dist/core/triwiki/context-graph/compiler/cache-key.js +277 -0
  163. package/dist/core/triwiki/context-graph/compiler/extract.js +104 -0
  164. package/dist/core/triwiki/context-graph/compiler/freshness.js +108 -0
  165. package/dist/core/triwiki/context-graph/compiler/index.js +237 -0
  166. package/dist/core/triwiki/context-graph/compiler/merge.js +0 -0
  167. package/dist/core/triwiki/context-graph/compiler/serialize.js +115 -0
  168. package/dist/core/triwiki/context-graph/contracts.js +236 -0
  169. package/dist/core/triwiki/context-graph/extractors/code/builders.js +150 -0
  170. package/dist/core/triwiki/context-graph/extractors/code/declarations.js +161 -0
  171. package/dist/core/triwiki/context-graph/extractors/code/index.js +265 -0
  172. package/dist/core/triwiki/context-graph/extractors/code/inventory.js +237 -0
  173. package/dist/core/triwiki/context-graph/extractors/code/module-graph.js +252 -0
  174. package/dist/core/triwiki/context-graph/extractors/code/modules.js +79 -0
  175. package/dist/core/triwiki/context-graph/extractors/code/references.js +184 -0
  176. package/dist/core/triwiki/context-graph/extractors/code/selection.js +100 -0
  177. package/dist/core/triwiki/context-graph/extractors/code/ts-config.js +161 -0
  178. package/dist/core/triwiki/context-graph/extractors/code/types.js +18 -0
  179. package/dist/core/triwiki/context-graph/extractors/evidence/claims.js +289 -0
  180. package/dist/core/triwiki/context-graph/extractors/evidence/index.js +54 -0
  181. package/dist/core/triwiki/context-graph/extractors/evidence/proof-index.js +213 -0
  182. package/dist/core/triwiki/context-graph/extractors/evidence/proofs.js +266 -0
  183. package/dist/core/triwiki/context-graph/extractors/evidence/redaction.js +177 -0
  184. package/dist/core/triwiki/context-graph/extractors/evidence/shared.js +0 -0
  185. package/dist/core/triwiki/context-graph/extractors/evidence/sources.js +154 -0
  186. package/dist/core/triwiki/context-graph/extractors/index.js +7 -0
  187. package/dist/core/triwiki/context-graph/extractors/topology/commands.js +207 -0
  188. package/dist/core/triwiki/context-graph/extractors/topology/gate-edges.js +201 -0
  189. package/dist/core/triwiki/context-graph/extractors/topology/gates.js +182 -0
  190. package/dist/core/triwiki/context-graph/extractors/topology/globs.js +124 -0
  191. package/dist/core/triwiki/context-graph/extractors/topology/index.js +92 -0
  192. package/dist/core/triwiki/context-graph/extractors/topology/routes.js +135 -0
  193. package/dist/core/triwiki/context-graph/extractors/topology/shared.js +215 -0
  194. package/dist/core/triwiki/context-graph/graph-index.js +143 -0
  195. package/dist/core/triwiki/context-graph/ids.js +0 -0
  196. package/dist/core/triwiki/context-graph/lint/index.js +0 -0
  197. package/dist/core/triwiki/context-graph/lint/rules.js +232 -0
  198. package/dist/core/triwiki/context-graph/lint/warnings.js +93 -0
  199. package/dist/core/triwiki/context-graph/paths.js +116 -0
  200. package/dist/core/triwiki/context-graph/profiles.js +78 -0
  201. package/dist/core/triwiki/context-graph/projections/anchors.js +91 -0
  202. package/dist/core/triwiki/context-graph/projections/attention.js +58 -0
  203. package/dist/core/triwiki/context-graph/projections/code-pack-workspace.js +62 -0
  204. package/dist/core/triwiki/context-graph/projections/code-pack.js +144 -0
  205. package/dist/core/triwiki/context-graph/projections/index.js +7 -0
  206. package/dist/core/triwiki/context-graph/projections/module-view.js +140 -0
  207. package/dist/core/triwiki/context-graph/projections/node-summary.js +118 -0
  208. package/dist/core/triwiki/context-graph/projections/pack-contract.js +6 -0
  209. package/dist/core/triwiki/context-graph/query/explain.js +0 -0
  210. package/dist/core/triwiki/context-graph/query/index.js +178 -0
  211. package/dist/core/triwiki/context-graph/query/load.js +116 -0
  212. package/dist/core/triwiki/context-graph/query/pack.js +117 -0
  213. package/dist/core/triwiki/context-graph/query/rank.js +142 -0
  214. package/dist/core/triwiki/context-graph/query/ranking-config.js +64 -0
  215. package/dist/core/triwiki/context-graph/query/seeds.js +241 -0
  216. package/dist/core/triwiki/context-graph/query/snapshot-cache.js +72 -0
  217. package/dist/core/triwiki/context-graph/query/traverse.js +154 -0
  218. package/dist/core/triwiki/context-graph/query-types.js +29 -0
  219. package/dist/core/triwiki/context-graph/store/compile-lock.js +21 -0
  220. package/dist/core/triwiki/context-graph/store/event-log.js +48 -0
  221. package/dist/core/triwiki/context-graph/store/fragment-cache.js +85 -0
  222. package/dist/core/triwiki/context-graph/store/graph-status.js +85 -0
  223. package/dist/core/triwiki/context-graph/store/snapshot-store.js +155 -0
  224. package/dist/core/triwiki/triwiki-proof-bank-index-repair.js +115 -0
  225. package/dist/core/triwiki/triwiki-proof-bank-index-store.js +290 -0
  226. package/dist/core/triwiki/triwiki-proof-bank-index.js +126 -0
  227. package/dist/core/triwiki/triwiki-proof-bank.js +7 -1
  228. package/dist/core/verification/context-graph-affected.js +271 -0
  229. package/dist/core/version.js +1 -1
  230. package/dist/native/sks-menubar/Sources/AlertFactory.swift +11 -3
  231. package/dist/native/sks-menubar/Sources/AppDelegate.swift +9 -0
  232. package/dist/native/sks-menubar/Sources/ControlCenterWindowController.swift +25 -3
  233. package/dist/native/sks-menubar/Sources/ControlKit.swift +19 -8
  234. package/dist/native/sks-menubar/Sources/DiagnosticsViewController.swift +1 -2
  235. package/dist/native/sks-menubar/Sources/MCPServersViewController.swift +45 -17
  236. package/dist/native/sks-menubar/Sources/OverviewSummary.swift +162 -0
  237. package/dist/native/sks-menubar/Sources/OverviewViewController.swift +136 -190
  238. package/dist/native/sks-menubar/Sources/ProcessClient.swift +107 -11
  239. package/dist/native/sks-menubar/Sources/ProvidersMultiProvider.swift +5 -1
  240. package/dist/native/sks-menubar/Sources/ProvidersOpenRouter.swift +16 -4
  241. package/dist/native/sks-menubar/Sources/ProvidersRoleModels.swift +4 -1
  242. package/dist/native/sks-menubar/Sources/ProvidersRoutingTruth.swift +131 -0
  243. package/dist/native/sks-menubar/Sources/ProvidersViewController.swift +288 -341
  244. package/dist/native/sks-menubar/Sources/RemoteTelegramCenterState.swift +447 -0
  245. package/dist/native/sks-menubar/Sources/RemoteTelegramRendering.swift +484 -0
  246. package/dist/native/sks-menubar/Sources/RemoteTelegramViewController.swift +364 -115
  247. package/dist/native/sks-menubar/Sources/SettingsViewController.swift +73 -12
  248. package/dist/native/sks-menubar/Sources/SidebarItem.swift +3 -3
  249. package/dist/native/sks-menubar/Sources/StatusItemController.swift +13 -13
  250. package/dist/native/sks-menubar/Sources/TelegramHubSupervisor.swift +469 -0
  251. package/dist/native/sks-menubar/Sources/UpdatesViewController.swift +1 -6
  252. package/dist/native/sks-menubar/Tests/AppRuntimeTestSupport.swift +12 -0
  253. package/dist/native/sks-menubar/Tests/NativeTelegramRegressionRunner.swift +55 -0
  254. package/dist/native/sks-menubar/Tests/ProcessClientTests.swift +33 -0
  255. package/dist/native/sks-menubar/Tests/ProvidersViewControllerTests.swift +142 -0
  256. package/dist/native/sks-menubar/Tests/RemoteTelegramCenterStateTests.swift +56 -0
  257. package/dist/native/sks-menubar/Tests/TelegramHubSupervisorTests.swift +55 -0
  258. package/dist/scripts/codex-lb-catalog-passthrough-check.js +120 -0
  259. package/dist/scripts/codex-lb-desktop-auth-invariant-check.js +169 -0
  260. package/dist/scripts/codex-lb-desktop-bridge-check.js +394 -0
  261. package/dist/scripts/codex-lb-desktop-bridge-latency-check.js +196 -0
  262. package/dist/scripts/codex-lb-desktop-capabilities-check.js +287 -0
  263. package/dist/scripts/codex-lb-desktop-real-evidence-check.js +123 -0
  264. package/dist/scripts/codex-lb-fast-mode-truth-check.js +10 -3
  265. package/dist/scripts/codex-lb-fast-ui-preservation-check.js +81 -40
  266. package/dist/scripts/codex-lb-gpt56-fast-profile-check.js +99 -37
  267. package/dist/scripts/context-graph-check.js +191 -0
  268. package/dist/scripts/doctor-fixes-codex-app-fast-ui-check.js +1 -1
  269. package/dist/scripts/gate-policy-audit-check.js +1 -1
  270. package/dist/scripts/helper-dedup-check.js +0 -2
  271. package/dist/scripts/installed-package-smoke-check.js +4 -1
  272. package/dist/scripts/latest-version-guidance-check.js +74 -0
  273. package/dist/scripts/release-metadata-check.js +21 -4
  274. package/dist/scripts/release-real-check.js +7 -0
  275. package/dist/scripts/ux-review-imagegen-blackbox-check.js +25 -1
  276. package/dist/scripts/ux-review-run-wires-imagegen-check.js +9 -1
  277. package/package.json +8 -3
  278. package/release-gates.v2.json +176 -1
  279. package/runtime-required-scripts.json +30 -0
  280. package/schemas/triwiki/context-graph.schema.json +119 -0
  281. package/dist/cli/install-helpers-codex-lb-selftest-chain.js +0 -112
  282. package/dist/cli/install-helpers-codex-lb-selftest.js +0 -481
  283. package/dist/core/triwiki/code-index-scanner.js +0 -309
@@ -5,12 +5,13 @@ import { projectRoot, readStdin, readText } from '../core/fsx.js';
5
5
  import { flag, readOption } from '../cli/args.js';
6
6
  import { printJson } from '../cli/output.js';
7
7
  import { codexLbMetrics, readCodexLbCircuit, recordCodexLbHealthEvent, resetCodexLbCircuit, codexLbProofEvidence } from '../core/codex-lb-circuit.js';
8
- import { checkCodexLbResponseChain, codexLbStatus, configureCodexLb, formatCodexLbStatusText, releaseCodexLbAuthHold, repairCodexLbAuth, unselectCodexLbProvider } from '../cli/install-helpers.js';
9
- import { buildCodexLbSetupPlan, codexLbPersistenceSummary, renderCodexLbSetupPlan } from '../core/codex-lb/codex-lb-setup.js';
8
+ import { checkCodexLbResponseChain, codexLbStatus, configureCodexLb, repairCodexLbAuth } from '../cli/install-helpers.js';
9
+ import { buildCodexLbSetupPlan, renderCodexLbSetupPlan } from '../core/codex-lb/codex-lb-setup.js';
10
10
  import { CODEX_LB_TOOL_OUTPUT_RECOVERY_OVERRIDE_FLAG, codexLbToolOutputRecoveryOverrideAcknowledged } from '../core/codex-lb/codex-lb-tool-output-recovery.js';
11
- import { restartCodexApp } from '../core/codex-app/codex-app-restart.js';
12
- import { repairCodexAppFastUi } from '../core/codex-app/codex-app-fast-ui-repair.js';
13
11
  import { loadCodexLbEnv } from '../core/codex-lb/codex-lb-env.js';
12
+ import { activateCodexLbDesktopMode, buildCodexLbDesktopCapabilities, codexLbDesktopStatusV2, configureCodexLbCliMode, disableCodexLbDesktopRouting, migrateLegacyCodexLbDesktopMode, readCodexLbDesktopDeepEvidence, readCodexLbDesktopDeepEvidenceTrustAnchors, rollbackCodexLbDesktopMode } from '../core/codex-lb/desktop-controller.js';
13
+ import { serveDesktopBridge } from '../core/codex-lb/desktop-service.js';
14
+ import { parseCodexLbGatewayAuthTransport } from '../core/codex-lb/desktop-mode.js';
14
15
  export async function run(command, args = []) {
15
16
  const root = await projectRoot();
16
17
  const action = args[0] || 'status';
@@ -24,26 +25,23 @@ export async function run(command, args = []) {
24
25
  return;
25
26
  }
26
27
  if (action === 'status' || action === 'check') {
27
- const allowUnverifiedToolOutputRecovery = codexLbToolOutputRecoveryOverrideAcknowledged({ args });
28
- const result = await codexLbStatus({ probeToolOutputRecovery: true, allowUnverifiedToolOutputRecovery });
29
- const shaped = shapeCodexLbStatus(result);
30
- if (result.selected && result.tool_output_recovery?.ok !== true)
28
+ const result = await codexLbDesktopStatusV2(controllerOptions(args));
29
+ if (result.ok !== true)
31
30
  process.exitCode = 1;
32
31
  if (flag(args, '--json'))
33
- return printJson(shaped);
34
- process.stdout.write(formatCodexLbStatusText(result));
32
+ return printJson(result);
33
+ process.stdout.write(formatCodexLbDesktopStatusText(result));
35
34
  return;
36
35
  }
37
36
  if (action === 'doctor') {
38
- const allowUnverifiedToolOutputRecovery = codexLbToolOutputRecoveryOverrideAcknowledged({ args });
39
- const status = shapeCodexLbStatus(await codexLbStatus({ probeToolOutputRecovery: true, allowUnverifiedToolOutputRecovery }));
37
+ const status = await codexLbDesktopStatusV2(controllerOptions(args));
40
38
  const metrics = codexLbMetrics(await readCodexLbCircuit(root));
41
- const result = { schema: 'sks.codex-lb-doctor.v1', ok: Boolean(status.ok && metrics.ok), deep: flag(args, '--deep'), status, metrics };
39
+ const result = buildCodexLbDoctorResult(status, metrics, flag(args, '--deep'));
42
40
  if (flag(args, '--json'))
43
41
  return printJson(result);
44
- console.log(`codex-lb doctor: ${result.ok ? 'ok' : status.setup_needed ? 'setup_needed' : 'blocked'}`);
42
+ console.log(`codex-lb doctor: ${result.ok ? 'diagnostic_ok' : 'blocked'}; full capability: ${result.full_capability_verified ? 'verified' : 'unverified'}`);
45
43
  if (!result.ok)
46
- process.exitCode = status.setup_needed ? 0 : 1;
44
+ process.exitCode = 1;
47
45
  return;
48
46
  }
49
47
  if (action === 'health' || action === 'verify-chain' || action === 'chain') {
@@ -141,39 +139,18 @@ export async function run(command, args = []) {
141
139
  return;
142
140
  }
143
141
  if (action === 'repair' || action === 'resync' || action === 'login') {
144
- const result = await repairCodexLbAuth({
145
- allowUnverifiedToolOutputRecovery: codexLbToolOutputRecoveryOverrideAcknowledged({ args })
146
- });
147
- const fastUi = await repairCodexAppFastUiAfterMutation(root, Boolean(result.ok));
148
- const shaped = { ...result, ok: Boolean(result.ok && fastUi.ok), codex_app_fast_ui: fastUi };
149
- if (!shaped.ok)
142
+ const result = await repairCodexLbAuth(controllerOptions(args));
143
+ if (result.ok !== true)
150
144
  process.exitCode = 1;
151
- if (flag(args, '--json'))
152
- return printJson(shaped);
153
- console.log(`codex-lb repair: ${shaped.ok ? 'ok' : result.ok ? 'fast_ui_repair_failed' : result.status}`);
154
- return;
155
- }
156
- if (action === 'release') {
157
- const result = await releaseCodexLbAuthHold({ keepProvider: flag(args, '--keep-provider'), deleteBackup: flag(args, '--delete-backup'), force: flag(args, '--force') });
158
145
  if (flag(args, '--json'))
159
146
  return printJson(result);
160
- console.log(`codex-lb release: ${result.status}`);
161
- if (['no_backup', 'auth_in_use', 'failed'].includes(result.status))
162
- process.exitCode = 1;
163
- return;
164
- }
165
- if (action === 'unselect') {
166
- const result = await unselectCodexLbProvider();
167
- if (flag(args, '--json'))
168
- return printJson(result);
169
- console.log(`codex-lb unselect: ${result.status}`);
170
- if (result.status === 'failed')
171
- process.exitCode = 1;
147
+ console.log(`codex-lb repair: ${result.ok === true ? 'ok' : String(result.status || 'failed')}`);
172
148
  return;
173
149
  }
174
150
  if (action === 'set-key' || action === 'update-key' || action === 'rotate-key') {
175
- const status = await codexLbStatus();
176
- const host = status.base_url;
151
+ const current = await codexLbDesktopStatusV2(controllerOptions(args));
152
+ const loaded = await loadCodexLbEnv();
153
+ const host = loaded.base_url;
177
154
  if (!host) {
178
155
  const result = { schema: 'sks.codex-lb-set-key.v1', ok: false, status: 'not_configured' };
179
156
  if (flag(args, '--json')) {
@@ -195,111 +172,218 @@ export async function run(command, args = []) {
195
172
  process.exitCode = 1;
196
173
  return;
197
174
  }
198
- const keychainPresent = status.env_loader?.api_key?.source === 'keychain'
199
- || ['found', 'present'].includes(status.env_loader?.keychain?.status)
200
- || flag(args, '--keychain');
201
175
  const result = await configureCodexLb({
202
176
  host,
203
177
  apiKey: newKey,
204
- keychain: keychainPresent,
205
- storeKeychain: keychainPresent,
206
- useDefaultProvider: flag(args, '--preserve-auth') ? status.selected === true : true,
207
- authMode: flag(args, '--preserve-auth') ? 'preserve' : 'codex-lb',
208
- forceCodexLbApiKeyAuth: !flag(args, '--preserve-auth'),
178
+ keychain: true,
179
+ storeKeychain: true,
180
+ writeEnvFile: true,
181
+ syncLaunchctl: true,
182
+ desktopMode: 'cli-provider',
209
183
  allowUnverifiedToolOutputRecovery: codexLbToolOutputRecoveryOverrideAcknowledged({ args })
210
184
  });
211
- const fastUi = await repairCodexAppFastUiAfterMutation(root, Boolean(result.ok));
212
- const restart = await maybeRestartCodexAppForAuthSwitch(args, Boolean(result.ok && fastUi.ok));
213
- const ok = Boolean(result.ok && fastUi.ok && restart?.ok !== false);
214
- const output = { ...result, ok, action: 'set-key', codex_app_fast_ui: fastUi, restart_app: restart };
185
+ let routing = null;
186
+ const restartRequested = flag(args, '--restart-app') || flag(args, '--restart')
187
+ || current.mode === 'desktop-dual-auth-compat'
188
+ || current.mode === 'desktop-native-bridge';
189
+ if (result.ok && current.mode === 'desktop-native-bridge') {
190
+ routing = await activateCodexLbDesktopMode({
191
+ ...controllerOptions(args),
192
+ mode: 'desktop-native-bridge',
193
+ restartApp: restartRequested
194
+ });
195
+ }
196
+ else if (result.ok && current.mode === 'desktop-dual-auth-compat') {
197
+ routing = await activateCodexLbDesktopMode({
198
+ ...controllerOptions(args),
199
+ mode: 'desktop-dual-auth-compat',
200
+ restartApp: restartRequested
201
+ });
202
+ }
203
+ const ok = Boolean(result.ok && routing?.ok !== false);
204
+ const output = {
205
+ ...result,
206
+ schema: 'sks.codex-lb-set-key.v2',
207
+ ok,
208
+ action: 'set-key',
209
+ desktop_auth_mutated: false,
210
+ fast_mode_mutated: false,
211
+ desktop_routing: routing,
212
+ center_credentials: routing?.center_credentials || null
213
+ };
215
214
  if (!ok)
216
215
  process.exitCode = 1;
217
216
  if (flag(args, '--json'))
218
217
  return printJson(output);
219
218
  console.log(result.ok ? `codex-lb API key updated (${result.base_url || host}).` : `codex-lb key update failed: ${result.status}${result.error ? `: ${result.error}` : ''}`);
220
- if (restart?.status === 'restarted')
221
- console.log('Codex App restarted for the new codex-lb auth mode.');
222
219
  if (!ok)
223
220
  process.exitCode = 1;
224
221
  return;
225
222
  }
226
- if (action === 'use-codex-lb' || action === 'use-lb') {
227
- const restartRequired = flag(args, '--restart-app') || flag(args, '--restart');
228
- const repairOptions = {
229
- forceCodexLbApiKeyAuth: true,
230
- authMode: 'codex-lb',
231
- forceFastMode: !flag(args, '--no-fast'),
232
- allowUnverifiedToolOutputRecovery: codexLbToolOutputRecoveryOverrideAcknowledged({ args })
233
- };
234
- const result = await repairCodexLbAuth(repairOptions);
235
- const fastUi = await repairCodexAppFastUiAfterMutation(root, Boolean(result.ok));
236
- const restart = await maybeRestartCodexAppForAuthSwitch(args, Boolean(result.ok && fastUi.ok));
237
- const postRestart = await reconcileCodexLbAfterRestart(restart, repairOptions, Boolean(result.ok && fastUi.ok), restartRequired);
238
- const finalStatus = postRestart.attempted ? postRestart.stable_status : result.codex_lb;
239
- const readiness = codexLbActivationReadiness(finalStatus);
240
- const restartRequirement = codexLbRestartPostcondition(restart, restartRequired);
241
- const restartPerformed = restartRequirement.performed;
242
- const restartSatisfied = restartRequirement.satisfied;
243
- const ok = Boolean(result.ok && fastUi.ok && restart?.ok !== false && restartSatisfied && postRestart.ok && readiness.ok);
244
- const shaped = {
245
- ...result,
246
- ok,
247
- mode: 'codex-lb',
248
- codex_lb: finalStatus,
249
- readiness,
250
- restart_required: restartRequired,
251
- restart_performed: restartPerformed,
252
- codex_app_fast_ui: fastUi,
253
- restart_app: restart,
254
- post_restart: postRestart
255
- };
256
- if (!ok)
223
+ if (action === 'use-desktop-full'
224
+ || action === 'use-codex-lb'
225
+ || action === 'use-lb') {
226
+ if (action !== 'use-desktop-full') {
227
+ printDeprecationWarning(action, 'sks codex-lb use-desktop-full');
228
+ }
229
+ const result = await activateCodexLbDesktopMode({
230
+ ...controllerOptions(args),
231
+ mode: 'desktop-native-bridge'
232
+ });
233
+ if (result.ok !== true)
257
234
  process.exitCode = 1;
258
235
  if (flag(args, '--json'))
259
- return printJson(shaped);
260
- const failureStatus = !restartSatisfied ? 'restart_not_performed' : postRestart.status || result.status;
261
- console.log(ok ? 'Auth mode: codex-lb selected (API key).' : `Switch to codex-lb failed: ${failureStatus}${result.error ? `: ${result.error}` : ''}`);
262
- if (restart?.status === 'restarted')
263
- console.log('Codex App restarted for codex-lb auth.');
264
- if (!ok)
236
+ return printJson(result);
237
+ console.log(result.ok === true
238
+ ? 'Codex Desktop Full Capability routing enabled; ChatGPT OAuth remains active.'
239
+ : `Desktop Full Capability activation failed: ${String(result.status || 'failed')}`);
240
+ return;
241
+ }
242
+ if (action === 'use-desktop-compat') {
243
+ const result = await activateCodexLbDesktopMode({
244
+ ...controllerOptions(args),
245
+ mode: 'desktop-dual-auth-compat',
246
+ gatewayAuthTransport: 'x-codex-lb-api-key'
247
+ });
248
+ if (result.ok !== true)
265
249
  process.exitCode = 1;
250
+ if (flag(args, '--json'))
251
+ return printJson(result);
252
+ console.log(result.ok === true
253
+ ? 'Codex Desktop compatibility routing enabled; ChatGPT OAuth remains active.'
254
+ : `Desktop compatibility activation failed: ${String(result.status || 'failed')}`);
266
255
  return;
267
256
  }
268
- if (action === 'use-oauth' || action === 'use-chatgpt') {
269
- const restartRequired = flag(args, '--restart-app') || flag(args, '--restart');
270
- const result = await releaseCodexLbAuthHold({ force: flag(args, '--force') });
271
- const authOk = !['no_backup', 'auth_in_use', 'failed'].includes(result.status);
272
- const fastUi = await repairCodexAppFastUiAfterMutation(root, authOk);
273
- const restart = await maybeRestartCodexAppForAuthSwitch(args, Boolean(authOk && fastUi.ok));
274
- const restartRequirement = codexLbRestartPostcondition(restart, restartRequired);
275
- const ok = Boolean(authOk && fastUi.ok && restart?.ok !== false && restartRequirement.satisfied);
276
- const shaped = {
277
- ...result,
278
- ok,
279
- mode: 'oauth',
280
- restart_required: restartRequired,
281
- restart_performed: restartRequirement.performed,
282
- codex_app_fast_ui: fastUi,
283
- restart_app: restart
257
+ if (action === 'use-cli') {
258
+ const result = await configureCodexLbCliMode(controllerOptions(args));
259
+ if (result.ok !== true)
260
+ process.exitCode = 1;
261
+ if (flag(args, '--json'))
262
+ return printJson(result);
263
+ console.log(result.ok === true
264
+ ? `codex-lb CLI provider ready. Run: ${String(result.command)}`
265
+ : `codex-lb CLI provider setup failed: ${String(result.status || 'failed')}`);
266
+ return;
267
+ }
268
+ if (action === 'disable'
269
+ || action === 'release'
270
+ || action === 'unselect'
271
+ || action === 'use-oauth'
272
+ || action === 'use-chatgpt') {
273
+ if (action !== 'disable') {
274
+ printDeprecationWarning(action, 'sks codex-lb disable');
275
+ }
276
+ const result = await disableCodexLbDesktopRouting(controllerOptions(args));
277
+ if (result.ok !== true)
278
+ process.exitCode = 1;
279
+ if (flag(args, '--json'))
280
+ return printJson(result);
281
+ console.log(result.ok === true
282
+ ? 'codex-lb Desktop routing disabled; existing ChatGPT OAuth was left untouched.'
283
+ : `codex-lb Desktop routing disable failed: ${String(result.status || 'failed')}`);
284
+ return;
285
+ }
286
+ if (action === 'capabilities') {
287
+ const level = normalizeCapabilityLevel(readOption(args, '--level', 'shallow'));
288
+ if (!level) {
289
+ const result = {
290
+ schema: 'sks.codex-lb-capabilities-command.v2',
291
+ ok: false,
292
+ status: 'invalid_level',
293
+ blockers: ['capability_level_must_be_shallow_transport_or_deep']
294
+ };
295
+ process.exitCode = 1;
296
+ if (flag(args, '--json'))
297
+ return printJson(result);
298
+ console.error('Invalid capability level. Use shallow, transport, or deep.');
299
+ return;
300
+ }
301
+ const { deepEvidence, deepEvidenceTrustAnchors } = await readDeepEvidenceOptions(args);
302
+ const report = await buildCodexLbDesktopCapabilities({
303
+ ...controllerOptions(args),
304
+ level,
305
+ deepEvidence,
306
+ deepEvidenceTrustAnchors,
307
+ networkProbes: !flag(args, '--no-network')
308
+ });
309
+ const diagnosticOk = report.overall !== 'blocked' && report.overall !== 'unsupported';
310
+ const result = {
311
+ ...report,
312
+ ok: diagnosticOk,
313
+ diagnostic_ok: diagnosticOk,
314
+ level,
315
+ full_capability_verified: report.overall === 'verified'
284
316
  };
285
- if (!ok)
317
+ if (!diagnosticOk)
286
318
  process.exitCode = 1;
287
319
  if (flag(args, '--json'))
288
- return printJson(shaped);
289
- if (result.status === 'no_backup') {
290
- console.log('No saved ChatGPT OAuth credentials to restore. Switch to OAuth by logging in:');
291
- console.log(' codex login');
292
- console.log('Then, if codex-lb is still the selected provider: sks codex-lb unselect');
320
+ return printJson(result);
321
+ console.log(`codex-lb capabilities (${level}): ${diagnosticOk ? 'diagnostic_ok' : 'blocked'}; overall=${report.overall}`);
322
+ printCapabilityRows(report);
323
+ return;
324
+ }
325
+ if (action === 'migrate-legacy-desktop') {
326
+ const { deepEvidence, deepEvidenceTrustAnchors } = await readDeepEvidenceOptions(args);
327
+ const toRaw = String(readOption(args, '--to', readOption(args, '--target', 'bridge')) || 'bridge')
328
+ .trim()
329
+ .toLowerCase();
330
+ const mode = toRaw === 'compat'
331
+ || toRaw === 'desktop-compat'
332
+ || toRaw === 'desktop-dual-auth-compat'
333
+ ? 'desktop-dual-auth-compat'
334
+ : toRaw === 'bridge'
335
+ || toRaw === 'desktop-full'
336
+ || toRaw === 'desktop-native-bridge'
337
+ || toRaw === ''
338
+ ? 'desktop-native-bridge'
339
+ : null;
340
+ if (!mode) {
341
+ const result = {
342
+ schema: 'sks.codex-lb-legacy-migration-command.v2',
343
+ ok: false,
344
+ status: 'invalid_migration_target',
345
+ blockers: ['migration_target_must_be_bridge_or_compat']
346
+ };
293
347
  process.exitCode = 1;
348
+ if (flag(args, '--json'))
349
+ return printJson(result);
350
+ console.error('Invalid --to value. Use bridge or compat.');
294
351
  return;
295
352
  }
296
- console.log(ok
297
- ? `Auth mode: ${['released', 'oauth_restored'].includes(result.status) ? 'ChatGPT OAuth restored' : result.status}.`
298
- : `Switch to ChatGPT OAuth failed: ${restartRequirement.satisfied ? result.status : 'restart_not_performed'}.`);
299
- if (restart?.status === 'restarted')
300
- console.log('Codex App restarted for ChatGPT OAuth.');
301
- if (['auth_in_use', 'failed'].includes(result.status))
353
+ const result = await migrateLegacyCodexLbDesktopMode({
354
+ ...controllerOptions(args),
355
+ mode,
356
+ deepEvidence,
357
+ deepEvidenceTrustAnchors
358
+ });
359
+ if (result.ok !== true)
302
360
  process.exitCode = 1;
361
+ if (flag(args, '--json'))
362
+ return printJson(result);
363
+ console.log(result.ok === true
364
+ ? `Legacy codex-lb Desktop state migrated (${String(result.receipt_path || '')}).`
365
+ : `Legacy migration blocked: ${String(result.status || 'failed')}`);
366
+ return;
367
+ }
368
+ if (action === 'rollback') {
369
+ const receiptId = String(args[1] || readOption(args, '--receipt', '')).trim();
370
+ const result = await rollbackCodexLbDesktopMode(receiptId, controllerOptions(args));
371
+ if (result.ok !== true)
372
+ process.exitCode = 1;
373
+ if (flag(args, '--json'))
374
+ return printJson(result);
375
+ console.log(result.ok === true
376
+ ? `codex-lb Desktop rollback completed (${receiptId}).`
377
+ : `codex-lb Desktop rollback failed: ${String(result.status || 'failed')}`);
378
+ return;
379
+ }
380
+ if ((action === 'bridge' || action === 'desktop-bridge') && args[1] === 'serve') {
381
+ const result = await serveDesktopBridge(controllerOptions(args));
382
+ if (!result.ok)
383
+ process.exitCode = 1;
384
+ if (flag(args, '--json'))
385
+ return printJson(result);
386
+ console.log(`codex-lb Desktop bridge: ${result.status}`);
303
387
  return;
304
388
  }
305
389
  if (action === 'setup' || action === 'reconfigure') {
@@ -307,7 +391,8 @@ export async function run(command, args = []) {
307
391
  const plan = buildCodexLbSetupPlan({
308
392
  host_or_base_url: options.host || '',
309
393
  api_key_source: options.apiKeySource,
310
- use_as_default_provider: options.useDefaultProvider,
394
+ desktop_mode: options.desktopMode,
395
+ gateway_auth_transport: options.gatewayAuthTransport,
311
396
  write_env_file: options.writeEnvFile,
312
397
  store_keychain: options.keychain,
313
398
  sync_launchctl: options.syncLaunchctl,
@@ -400,34 +485,74 @@ export async function run(command, args = []) {
400
485
  const result = await configureCodexLb({
401
486
  host: options.host,
402
487
  apiKey: options.apiKey,
403
- authMode: flag(args, '--preserve-auth') ? 'preserve' : 'codex-lb',
404
- forceCodexLbApiKeyAuth: !flag(args, '--preserve-auth'),
405
- forceFastMode: !flag(args, '--no-fast'),
488
+ desktopMode: 'cli-provider',
489
+ gatewayAuthTransport: options.gatewayAuthTransport,
406
490
  keychain: options.keychain,
407
491
  storeKeychain: options.keychain,
408
- useDefaultProvider: options.useDefaultProvider,
409
492
  writeEnvFile: options.writeEnvFile,
410
493
  syncLaunchctl: options.syncLaunchctl,
411
494
  shellProfile: options.shellProfile,
412
- runHealth: options.health,
495
+ runHealth: false,
413
496
  apiKeySource: options.apiKeySource,
414
497
  allowInsecureHttp: options.allowInsecureLocalhost,
415
498
  allowUnverifiedToolOutputRecovery: codexLbToolOutputRecoveryOverrideAcknowledged({ args })
416
499
  });
417
- const fastUi = await repairCodexAppFastUiAfterMutation(root, Boolean(result.ok));
418
- const restart = await maybeRestartCodexAppForAuthSwitch(args, Boolean(result.ok && fastUi.ok) && !flag(args, '--preserve-auth'));
419
- const shaped = { schema: 'sks.codex-lb-setup.v1', ...result, api_key: { present: Boolean(options.apiKey), redacted: true }, env_file_chmod: '0600', codex_app_fast_ui: fastUi };
420
- shaped.restart_app = restart;
421
- if (options.health)
422
- shaped.applied_actions = [...(shaped.applied_actions || []), { type: 'run_health_check', target: 'codex-lb response chain', ok: true }];
423
- if (options.health)
424
- shaped.chain_health = result.ok ? await checkCodexLbResponseChain(result, { force: true, root }) : null;
425
- shaped.ok = Boolean(result.ok && fastUi.ok && restart?.ok !== false);
500
+ let desktopActivation = null;
501
+ if (result.ok && options.desktopMode === 'desktop-native-bridge') {
502
+ desktopActivation = await activateCodexLbDesktopMode({
503
+ ...controllerOptions(args),
504
+ mode: 'desktop-native-bridge',
505
+ gatewayAuthTransport: options.gatewayAuthTransport
506
+ });
507
+ }
508
+ else if (result.ok && options.desktopMode === 'desktop-dual-auth-compat') {
509
+ desktopActivation = await activateCodexLbDesktopMode({
510
+ ...controllerOptions(args),
511
+ mode: 'desktop-dual-auth-compat',
512
+ gatewayAuthTransport: 'x-codex-lb-api-key'
513
+ });
514
+ }
515
+ const capabilities = options.health && result.ok
516
+ ? await buildCodexLbDesktopCapabilities({
517
+ ...controllerOptions(args),
518
+ level: 'transport',
519
+ networkProbes: true
520
+ })
521
+ : null;
522
+ const capabilityDiagnosticOk = codexLbSetupCapabilityDiagnosticOk(capabilities);
523
+ const shaped = {
524
+ ...result,
525
+ schema: 'sks.codex-lb-setup.v2',
526
+ ok: Boolean(result.ok
527
+ && desktopActivation?.ok !== false
528
+ && capabilityDiagnosticOk),
529
+ diagnostic_ok: capabilityDiagnosticOk,
530
+ requested_desktop_mode: options.desktopMode,
531
+ gateway_auth_transport: options.gatewayAuthTransport,
532
+ api_key: { present: Boolean(options.apiKey), redacted: true },
533
+ env_file_chmod: options.writeEnvFile ? '0600' : null,
534
+ desktop_auth_mutated: false,
535
+ fast_mode_mutated: false,
536
+ desktop_activation: desktopActivation,
537
+ capabilities
538
+ };
539
+ if (options.health) {
540
+ shaped.applied_actions = [
541
+ ...(shaped.applied_actions || []),
542
+ {
543
+ type: 'run_capability_check',
544
+ target: 'codex-lb Desktop capability matrix',
545
+ ok: capabilityDiagnosticOk,
546
+ overall: capabilities?.overall || null
547
+ }
548
+ ];
549
+ }
426
550
  if (!shaped.ok)
427
551
  process.exitCode = 1;
428
552
  if (flag(args, '--json'))
429
553
  return printJson(shaped);
430
554
  console.log(`codex-lb configured: ${result.base_url || result.status}`);
555
+ console.log(`Desktop mode: ${options.desktopMode}${desktopActivation ? ` (${String(desktopActivation.status || 'applied')})` : ' (routing unchanged)'}`);
431
556
  if (shaped.persistence?.warning)
432
557
  console.log(`warning: ${shaped.persistence.warning}`);
433
558
  if (!shaped.ok)
@@ -464,20 +589,15 @@ export async function run(command, args = []) {
464
589
  console.log(`codex-lb proof evidence: ${result.status}`);
465
590
  return;
466
591
  }
467
- console.error('Usage: sks codex-lb status|metrics|doctor --deep|health|setup|set-key|use-codex-lb|use-oauth|repair|release|unselect|circuit reset|circuit record-fixture|proof-evidence [--json]');
592
+ console.error('Usage: sks codex-lb status|setup|set-key|use-desktop-full|use-desktop-compat|use-cli|disable|capabilities [--level shallow|transport|deep] [--evidence <file> --trust-anchors <file>]|migrate-legacy-desktop|rollback <receipt-id>|health|metrics|doctor|repair|circuit reset|circuit record-fixture|proof-evidence [--json]');
468
593
  console.error(` ${CODEX_LB_TOOL_OUTPUT_RECOVERY_OVERRIDE_FLAG} explicitly acknowledge an old/unverified proxy for this command (unsafe)`);
469
594
  console.error(' set-key swap the codex-lb API key (reuses the stored host): sks codex-lb set-key --api-key-stdin');
470
- console.error(' use-codex-lb switch auth mode to codex-lb (API key)');
471
- console.error(' use-oauth switch auth mode to ChatGPT OAuth (restores saved login, else: codex login)');
595
+ console.error(' use-desktop-full keep ChatGPT OAuth/built-in OpenAI and route data through the local bridge');
596
+ console.error(' use-desktop-compat keep ChatGPT OAuth and use the explicit dual-auth custom provider');
597
+ console.error(' use-cli configure an unselected CLI-only provider');
598
+ console.error(' disable remove only SKS-managed Desktop routing; auth.json is untouched');
472
599
  process.exitCode = 1;
473
600
  }
474
- async function maybeRestartCodexAppForAuthSwitch(args = [], enabled) {
475
- if (!enabled)
476
- return { schema: 'sks.codex-app-restart.v1', ok: true, status: 'skipped', skipped: true, reason: 'previous_step_failed', app_name: 'ChatGPT', bundle_id: 'com.openai.codex', blockers: [] };
477
- const requested = flag(args, '--restart-app') || flag(args, '--restart');
478
- const shouldRestart = requested || (!flag(args, '--json') && !flag(args, '--no-restart-app') && !flag(args, '--no-restart'));
479
- return restartCodexApp({ enabled: shouldRestart });
480
- }
481
601
  export function codexLbRestartPostcondition(restart = {}, required = false) {
482
602
  const performed = restart?.status === 'restarted';
483
603
  return {
@@ -486,112 +606,21 @@ export function codexLbRestartPostcondition(restart = {}, required = false) {
486
606
  satisfied: !required || performed
487
607
  };
488
608
  }
489
- async function reconcileCodexLbAfterRestart(restart, repairOptions, enabled, restartRequired = false) {
490
- if (!enabled || restart?.status !== 'restarted') {
491
- const restartRequirement = codexLbRestartPostcondition(restart, restartRequired);
492
- return {
493
- schema: 'sks.codex-lb-post-restart.v1',
494
- ok: Boolean(enabled && restart?.ok !== false && restartRequirement.satisfied),
495
- attempted: false,
496
- status: restartRequired && !restartRequirement.performed ? 'restart_not_performed' : 'skipped',
497
- reason: !enabled ? 'previous_step_failed' : restart?.reason || restart?.status || 'restart_not_performed',
498
- attempts: 0,
499
- observations: [],
500
- selected: null,
501
- provider_ready: null,
502
- auth_routing_coherent: null,
503
- shared_openai_routing_safe: null,
504
- reconcile: null,
505
- codex_lb: null,
506
- repair: null,
507
- stable_status: null,
508
- readiness: null
509
- };
510
- }
511
- await codexLbRestartSettle(750);
512
- const repair = await repairCodexLbAuth(repairOptions);
513
- const observations = [];
514
- let stableStatus = null;
515
- for (let attempt = 1; attempt <= 3; attempt += 1) {
516
- if (attempt > 1)
517
- await codexLbRestartSettle(750);
518
- stableStatus = await codexLbStatus({
519
- probeToolOutputRecovery: false
520
- });
521
- observations.push({ attempt, readiness: codexLbActivationReadiness(stableStatus) });
522
- }
523
- const readiness = codexLbActivationReadiness(stableStatus);
524
- const finalTwoReady = observations.slice(-2).every((observation) => observation.readiness.ok === true);
525
- const regressed = observations.some((observation, index) => index > 0
526
- && observations[index - 1].readiness.ok === true
527
- && observation.readiness.ok !== true);
528
- const stable = finalTwoReady && !regressed;
529
- return {
530
- schema: 'sks.codex-lb-post-restart.v1',
531
- ok: Boolean(repair.ok && readiness.ok && stable),
532
- attempted: true,
533
- status: repair.ok && readiness.ok && stable ? 'reconciled_stable' : 'reconcile_failed',
534
- attempts: observations.length,
535
- stable,
536
- observations,
537
- selected: readiness.selected,
538
- provider_ready: readiness.provider_ready,
539
- auth_routing_coherent: readiness.auth_routing_coherent,
540
- shared_openai_routing_safe: readiness.shared_openai_routing_safe,
541
- reconcile: repair,
542
- codex_lb: stableStatus,
543
- repair,
544
- stable_status: stableStatus,
545
- readiness
546
- };
547
- }
548
- function codexLbRestartSettle(ms) {
549
- return new Promise((resolve) => setTimeout(resolve, Math.max(0, ms)));
550
- }
551
- function codexLbActivationReadiness(status = {}) {
552
- const selected = status?.selected === true;
553
- const providerReady = status?.provider_ready === true;
554
- const authRoutingCoherent = status?.auth_routing_coherent === true;
555
- const sharedOpenAiRoutingSafe = status?.shared_openai_routing?.safe === true;
609
+ export function buildCodexLbDoctorResult(status, metrics, deep = false) {
610
+ const diagnosticOk = status.ok === true;
556
611
  return {
557
- ok: selected && providerReady && authRoutingCoherent && sharedOpenAiRoutingSafe,
558
- selected,
559
- provider_ready: providerReady,
560
- auth_routing_coherent: authRoutingCoherent,
561
- shared_openai_routing_safe: sharedOpenAiRoutingSafe,
562
- blockers: [
563
- ...(selected ? [] : ['codex_lb_not_selected']),
564
- ...(providerReady ? [] : ['codex_lb_provider_not_ready']),
565
- ...(authRoutingCoherent ? [] : ['codex_lb_auth_routing_incoherent']),
566
- ...(sharedOpenAiRoutingSafe ? [] : ['codex_lb_shared_openai_routing_unsafe'])
567
- ]
612
+ schema: 'sks.codex-lb-doctor.v2',
613
+ ok: diagnosticOk && metrics.ok === true,
614
+ diagnostic_ok: diagnosticOk,
615
+ full_capability_verified: status.full_capability_verified === true,
616
+ deep,
617
+ status,
618
+ metrics
568
619
  };
569
620
  }
570
- async function repairCodexAppFastUiAfterMutation(root, enabled) {
571
- if (!enabled) {
572
- return {
573
- schema: 'sks.codex-app-fast-ui-repair.v1',
574
- ok: true,
575
- status: 'skipped',
576
- skipped: true,
577
- reason: 'previous_step_failed',
578
- actions: [],
579
- blockers: []
580
- };
581
- }
582
- try {
583
- return await repairCodexAppFastUi(root, { apply: true });
584
- }
585
- catch (err) {
586
- return {
587
- schema: 'sks.codex-app-fast-ui-repair.v1',
588
- ok: false,
589
- status: 'failed',
590
- actions: [],
591
- blockers: ['codex_app_fast_ui_repair_failed'],
592
- error: String(err?.message || err)
593
- };
594
- }
621
+ export function codexLbSetupCapabilityDiagnosticOk(capabilities) {
622
+ return capabilities === null
623
+ || (capabilities.overall !== 'blocked' && capabilities.overall !== 'unsupported');
595
624
  }
596
625
  export function isCodexLbFastChainVerified(chain = {}) {
597
626
  return chain.ok === true && chain.skipped !== true;
@@ -736,6 +765,172 @@ function normalizeTier(value) {
736
765
  return text;
737
766
  return null;
738
767
  }
768
+ async function readDeepEvidenceOptions(args = []) {
769
+ const evidencePath = readOption(args, '--evidence', null);
770
+ const trustAnchorsPath = readOption(args, '--trust-anchors', readOption(args, '--evidence-trust-anchors', null));
771
+ return {
772
+ deepEvidence: evidencePath
773
+ ? await readCodexLbDesktopDeepEvidence(String(evidencePath))
774
+ : null,
775
+ deepEvidenceTrustAnchors: trustAnchorsPath
776
+ ? await readCodexLbDesktopDeepEvidenceTrustAnchors(String(trustAnchorsPath))
777
+ : []
778
+ };
779
+ }
780
+ function controllerOptions(args = []) {
781
+ const rawGatewayAuth = flag(args, '--compat-bearer')
782
+ ? 'authorization-bearer-compat'
783
+ : normalizeGatewayAuthChoice(readOption(args, '--gateway-auth', readOption(args, '--gateway-auth-transport', 'x-codex-lb-api-key')));
784
+ const gatewayAuthTransport = parseCodexLbGatewayAuthTransport(rawGatewayAuth);
785
+ const home = readOption(args, '--home', null);
786
+ const configPath = readOption(args, '--config', readOption(args, '--config-path', null));
787
+ const authPath = readOption(args, '--auth', readOption(args, '--auth-path', null));
788
+ const envPath = readOption(args, '--env-file', readOption(args, '--env-path', null));
789
+ const metadataPath = readOption(args, '--metadata', readOption(args, '--metadata-path', null));
790
+ const receiptDir = readOption(args, '--receipt-dir', null);
791
+ const listenHost = readOption(args, '--listen-host', null);
792
+ const normalizedListenHost = listenHost === null
793
+ ? null
794
+ : listenHost === '127.0.0.1' || listenHost === '::1'
795
+ ? listenHost
796
+ : (() => { throw new Error(`unsupported_codex_lb_desktop_listen_host:${listenHost}`); })();
797
+ const listenPortText = readOption(args, '--listen-port', null);
798
+ const listenPort = listenPortText === null ? null : Number(listenPortText);
799
+ const capabilityTimeoutText = readOption(args, '--capability-timeout-ms', null);
800
+ const capabilityTimeoutMs = capabilityTimeoutText === null ? null : Number(capabilityTimeoutText);
801
+ return {
802
+ gatewayAuthTransport,
803
+ restartApp: flag(args, '--restart-app') || flag(args, '--restart'),
804
+ networkProbes: !flag(args, '--no-network'),
805
+ ...(home ? { home: String(home) } : {}),
806
+ ...(configPath ? { configPath: String(configPath) } : {}),
807
+ ...(authPath ? { authPath: String(authPath) } : {}),
808
+ ...(envPath ? { envPath: String(envPath) } : {}),
809
+ ...(metadataPath ? { metadataPath: String(metadataPath) } : {}),
810
+ ...(receiptDir ? { receiptDir: String(receiptDir) } : {}),
811
+ ...(capabilityTimeoutMs !== null && Number.isFinite(capabilityTimeoutMs) && capabilityTimeoutMs > 0
812
+ ? { capabilityTimeoutMs }
813
+ : {}),
814
+ ...(normalizedListenHost || (listenPort !== null && Number.isInteger(listenPort))
815
+ ? {
816
+ settings: {
817
+ ...(normalizedListenHost ? { listen_host: normalizedListenHost } : {}),
818
+ ...(listenPort !== null && Number.isInteger(listenPort) ? { listen_port: listenPort } : {}),
819
+ gateway_auth_transport: gatewayAuthTransport
820
+ }
821
+ }
822
+ : {})
823
+ };
824
+ }
825
+ function formatCodexLbDesktopStatusText(status) {
826
+ const oauth = asRecord(status.oauth);
827
+ const provider = asRecord(status.provider);
828
+ const bridge = asRecord(status.bridge);
829
+ const capabilities = asRecord(status.capabilities);
830
+ const blockers = stringArray(status.blockers);
831
+ const guidance = stringArray(status.guidance);
832
+ const lines = [
833
+ 'SKS codex-lb Desktop',
834
+ '',
835
+ `Configured: ${status.configured === true ? 'yes' : 'no'}`,
836
+ `Mode: ${String(status.mode || 'disabled')}`,
837
+ `ChatGPT OAuth: ${oauth.present === true ? 'present and preserved' : 'missing'}`,
838
+ `Provider: ${String(provider.contract || 'missing')} (${provider.contract_ok === true ? 'ok' : 'blocked'})`,
839
+ `Bridge: ${String(bridge.status || 'unknown')}${bridge.running === true ? ' (running)' : ''}`,
840
+ `Gateway auth: ${String(bridge.gateway_auth_transport || 'unknown')}`,
841
+ `Capabilities: ${String(status.overall || capabilities.state || 'unverified')}`,
842
+ `Full capability: ${status.full_capability_verified === true ? 'verified' : 'unverified'}`
843
+ ];
844
+ if (blockers.length) {
845
+ lines.push('', 'Blockers:');
846
+ for (const blocker of blockers)
847
+ lines.push(`- ${blocker}`);
848
+ }
849
+ if (guidance.length) {
850
+ lines.push('', 'Next:');
851
+ for (const item of guidance)
852
+ lines.push(`- ${item}`);
853
+ }
854
+ return `${lines.join('\n')}\n`;
855
+ }
856
+ function printDeprecationWarning(oldAction, replacement) {
857
+ console.error(`warning: \`sks codex-lb ${oldAction}\` is deprecated; use \`${replacement}\`.`);
858
+ }
859
+ function normalizeCapabilityLevel(value) {
860
+ const normalized = String(value || '').trim().toLowerCase();
861
+ if (normalized === 'shallow' || normalized === 'transport' || normalized === 'deep') {
862
+ return normalized;
863
+ }
864
+ return null;
865
+ }
866
+ function printCapabilityRows(report) {
867
+ const keys = [
868
+ 'gateway_auth_transport',
869
+ 'provider_identity',
870
+ 'bridge',
871
+ 'catalog',
872
+ 'model_picker',
873
+ 'fast_mode',
874
+ 'text_responses',
875
+ 'image_generation',
876
+ 'computer_use',
877
+ 'browser_use',
878
+ 'voice_mode',
879
+ 'plugins',
880
+ 'auxiliary_surfaces'
881
+ ];
882
+ for (const key of keys) {
883
+ const capability = report[key];
884
+ const suffix = capability.blockers.length
885
+ ? ` (${capability.blockers.join(', ')})`
886
+ : '';
887
+ console.log(`- ${key}: ${capability.state}${suffix}`);
888
+ }
889
+ }
890
+ function normalizeDesktopSetupMode(value) {
891
+ const normalized = String(value || '').trim().toLowerCase();
892
+ if (normalized === 'desktop-full'
893
+ || normalized === 'full'
894
+ || normalized === 'native'
895
+ || normalized === 'desktop-native-bridge') {
896
+ return 'desktop-native-bridge';
897
+ }
898
+ if (normalized === 'desktop-compat'
899
+ || normalized === 'compat'
900
+ || normalized === 'desktop-dual-auth-compat') {
901
+ return 'desktop-dual-auth-compat';
902
+ }
903
+ if (!normalized
904
+ || normalized === 'cli'
905
+ || normalized === 'cli-only'
906
+ || normalized === 'cli-provider') {
907
+ return 'cli-provider';
908
+ }
909
+ throw new Error(`unsupported_codex_lb_desktop_mode:${normalized}`);
910
+ }
911
+ function normalizeGatewayAuthChoice(value) {
912
+ const normalized = String(value || '').trim().toLowerCase();
913
+ if (!normalized
914
+ || normalized === 'custom-header'
915
+ || normalized === 'header'
916
+ || normalized === 'x-codex-lb-api-key') {
917
+ return 'x-codex-lb-api-key';
918
+ }
919
+ if (normalized === 'bearer'
920
+ || normalized === 'bearer-compat'
921
+ || normalized === 'authorization-bearer-compat') {
922
+ return 'authorization-bearer-compat';
923
+ }
924
+ throw new Error(`unsupported_codex_lb_gateway_auth_transport:${normalized}`);
925
+ }
926
+ function asRecord(value) {
927
+ return value && typeof value === 'object' && !Array.isArray(value)
928
+ ? value
929
+ : {};
930
+ }
931
+ function stringArray(value) {
932
+ return Array.isArray(value) ? value.map((entry) => String(entry)).filter(Boolean) : [];
933
+ }
739
934
  async function resolveNewApiKey(args = []) {
740
935
  if (flag(args, '--api-key-stdin'))
741
936
  return String(await readStdin()).trim();
@@ -750,60 +945,21 @@ async function resolveNewApiKey(args = []) {
750
945
  }
751
946
  return '';
752
947
  }
753
- function shapeCodexLbStatus(status = {}) {
754
- const modes = [];
755
- if (status.env_file && status.env_key_configured)
756
- modes.push('durable_env_file');
757
- if (status.env_loader?.api_key?.source === 'keychain' || status.env_loader?.keychain?.status === 'present')
758
- modes.push('durable_keychain');
759
- if (status.launch_environment?.status === 'secret_env_present')
760
- modes.push('process_only_ephemeral');
761
- if (!modes.length && status.env_loader?.api_key?.source === 'process.env')
762
- modes.push('process_only_ephemeral');
763
- const mode = modes[0] || 'none';
764
- const persistence = codexLbPersistenceSummary({
765
- selectedModes: modes.length ? modes : [],
766
- appliedModes: modes.length ? modes : mode === 'none' ? ['none'] : [mode],
767
- processOnly: mode === 'process_only_ephemeral'
768
- });
769
- return {
770
- schema: 'sks.codex-lb-status.v1',
771
- ...status,
772
- configured: Boolean(status.provider_ready ?? status.ok),
773
- setup_needed: !Boolean(status.provider_ready ?? status.ok),
774
- upgrade_needed: Boolean(status.selected && status.tool_output_recovery?.ok !== true),
775
- repair_available: !Boolean(status.provider_ready ?? status.ok),
776
- api_key: {
777
- present: Boolean(status.env_key_configured),
778
- source: status.env_loader?.api_key?.source || null,
779
- redacted: true
780
- },
781
- persistence,
782
- env_loader: status.env_loader || null,
783
- env_auto_load: Boolean(status.env_file && status.env_key_configured),
784
- guidance: status.selected && status.tool_output_recovery?.ok !== true
785
- ? status.tool_output_recovery.operator_actions || []
786
- : status.ok ? [] : [
787
- 'codex-lb API key is not configured.',
788
- 'Run: sks codex-lb setup',
789
- 'Or: sks codex-lb setup --host <domain> --api-key-stdin --yes'
790
- ]
791
- };
792
- }
793
948
  async function codexLbSetupOptions(args = []) {
794
949
  const baseUrl = readOption(args, '--base-url', null);
795
950
  let host = baseUrl || readOption(args, '--host', readOption(args, '--domain', null));
796
951
  let apiKey = null;
797
952
  let apiKeySource = 'hidden_prompt';
953
+ let desktopMode = normalizeDesktopSetupMode(readOption(args, '--desktop-mode', readOption(args, '--mode', 'cli-provider')));
954
+ let gatewayAuthTransport = parseCodexLbGatewayAuthTransport(normalizeGatewayAuthChoice(flag(args, '--compat-bearer')
955
+ ? 'authorization-bearer-compat'
956
+ : readOption(args, '--gateway-auth', readOption(args, '--gateway-auth-transport', 'x-codex-lb-api-key'))));
798
957
  let keychain = flag(args, '--keychain');
799
958
  if (flag(args, '--api-key-stdin'))
800
959
  apiKey = (await readStdin()).trim();
801
960
  if (flag(args, '--api-key-stdin'))
802
961
  apiKeySource = 'stdin';
803
962
  let health = (flag(args, '--health') || flag(args, '--check')) && !flag(args, '--no-health');
804
- let useDefaultProvider = flag(args, '--no-default-provider') ? false : true;
805
- if (flag(args, '--use-default-provider'))
806
- useDefaultProvider = true;
807
963
  let writeEnvFile = flag(args, '--no-env-file') ? false : true;
808
964
  if (flag(args, '--write-env-file'))
809
965
  writeEnvFile = true;
@@ -820,18 +976,53 @@ async function codexLbSetupOptions(args = []) {
820
976
  host ||= (await ask('1. codex-lb domain or base URL?\n Example: lb.example.com or https://lb.example.com/backend-api/codex\n> ')).trim();
821
977
  apiKey ||= (await askHidden('2. API key?\n Input hidden. Value will be stored securely and never printed.\n> ')).trim();
822
978
  apiKeySource = 'hidden_prompt';
823
- useDefaultProvider = parseYesNo(await ask('3. Use this codex-lb as default for Codex launches? [Y/n] '), true);
824
- writeEnvFile = parseYesNo(await ask('4. Write shell env loader to ~/.codex/sks-codex-lb.env? [Y/n] '), true);
825
- const storeKeychain = (await ask('5. Store the key in macOS Keychain when available? [Y/n] ')).trim();
979
+ desktopMode = normalizeDesktopSetupMode((await ask('3. Configure which mode? [desktop-full/desktop-compat/cli-only] (desktop-full)\n> ')).trim()
980
+ || 'desktop-full');
981
+ if (desktopMode === 'desktop-native-bridge') {
982
+ gatewayAuthTransport = parseCodexLbGatewayAuthTransport(normalizeGatewayAuthChoice((await ask('4. Gateway key transport? [custom-header/bearer-compat] (custom-header)\n> ')).trim()));
983
+ }
984
+ else {
985
+ gatewayAuthTransport = 'x-codex-lb-api-key';
986
+ }
987
+ writeEnvFile = parseYesNo(await ask('5. Write shell env loader to ~/.codex/sks-codex-lb.env? [Y/n] '), true);
988
+ const storeKeychain = (await ask('6. Store the key in macOS Keychain when available? [Y/n] ')).trim();
826
989
  keychain = !/^(n|no|아니|아니요|ㄴ)$/i.test(storeKeychain || 'y');
827
- syncLaunchctl = parseYesNo(await ask('6. Sync non-secret macOS launchctl base URL only? API keys are never stored in launchd. [y/N] '), false);
828
- const profile = (await ask('7. Install shell profile snippet? [zsh/bash/fish/all/skip] ')).trim();
990
+ syncLaunchctl = parseYesNo(await ask('7. Sync non-secret macOS launchctl base URL only? API keys are never stored in launchd. [y/N] '), false);
991
+ const profile = (await ask('8. Install shell profile snippet? [zsh/bash/fish/all/skip] ')).trim();
829
992
  const interactiveShellProfile = normalizeShellProfile(profile || 'skip');
830
- const runHealth = (await ask('8. Run health check now? [Y/n] ')).trim();
993
+ const runHealth = (await ask('9. Run capability diagnostics now? [Y/n] ')).trim();
831
994
  health = !/^(n|no|아니|아니요|ㄴ)$/i.test(runHealth || 'y');
832
- return { host, apiKey, health, keychain, useDefaultProvider, writeEnvFile, syncLaunchctl, shellProfile: interactiveShellProfile, allowInsecureLocalhost, apiKeySource, interactive: true, yes: flag(args, '--yes') };
995
+ return {
996
+ host,
997
+ apiKey,
998
+ health,
999
+ keychain,
1000
+ desktopMode,
1001
+ gatewayAuthTransport,
1002
+ writeEnvFile,
1003
+ syncLaunchctl,
1004
+ shellProfile: interactiveShellProfile,
1005
+ allowInsecureLocalhost,
1006
+ apiKeySource,
1007
+ interactive: true,
1008
+ yes: flag(args, '--yes')
1009
+ };
833
1010
  }
834
- return { host, apiKey, health, keychain, useDefaultProvider, writeEnvFile, syncLaunchctl, shellProfile, allowInsecureLocalhost, apiKeySource, interactive, yes: flag(args, '--yes') };
1011
+ return {
1012
+ host,
1013
+ apiKey,
1014
+ health,
1015
+ keychain,
1016
+ desktopMode,
1017
+ gatewayAuthTransport,
1018
+ writeEnvFile,
1019
+ syncLaunchctl,
1020
+ shellProfile,
1021
+ allowInsecureLocalhost,
1022
+ apiKeySource,
1023
+ interactive,
1024
+ yes: flag(args, '--yes')
1025
+ };
835
1026
  }
836
1027
  function normalizeShellProfile(value) {
837
1028
  const raw = String(value || 'skip').toLowerCase();