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,1232 +0,0 @@
1
- import path from 'node:path';
2
- import readline from 'node:readline/promises';
3
- import { stdin as input, stdout as output } from 'node:process';
4
- import { projectRoot, readStdin, readText } from '../core/fsx.js';
5
- import { flag, readOption } from '../cli/args.js';
6
- import { printJson } from '../cli/output.js';
7
- import { printCodexLbSetupWarnings } from '../cli/codex-lb-setup-warning-output.js';
8
- import { testCodexLbConnection } from '../cli/install-helpers-codex-lb-chain.js';
9
- import { codexLbMetrics, readCodexLbCircuit, recordCodexLbHealthEvent, resetCodexLbCircuit, codexLbProofEvidence } from '../core/codex-lb-circuit.js';
10
- import { checkCodexLbResponseChain, codexLbStatus, configureCodexLb, repairCodexLbAuth } from '../cli/install-helpers.js';
11
- import { buildCodexLbSetupPlan, renderCodexLbSetupPlan } from '../core/codex-lb/codex-lb-setup.js';
12
- import { CODEX_LB_TOOL_OUTPUT_RECOVERY_OVERRIDE_FLAG, codexLbToolOutputRecoveryOverrideAcknowledged } from '../core/codex-lb/codex-lb-tool-output-recovery.js';
13
- import { loadCodexLbEnv } from '../core/codex-lb/codex-lb-env.js';
14
- import { activateCodexLbDesktopMode, buildCodexLbDesktopCapabilities, codexLbDesktopStatusV2, configureCodexLbCliMode, disableCodexLbDesktopRouting, migrateLegacyCodexLbDesktopMode, readCodexLbDesktopDeepEvidence, readCodexLbDesktopDeepEvidenceTrustAnchors, rollbackCodexLbDesktopMode } from '../core/codex-lb/desktop-controller.js';
15
- import { serveDesktopBridge } from '../core/codex-lb/desktop-service.js';
16
- import { parseCodexLbGatewayAuthTransport } from '../core/codex-lb/desktop-mode.js';
17
- import { codexLbRoutingTruthIsActive, measureAndWriteCodexLbRoutingTruth } from '../core/codex-lb/routing-truth.js';
18
- export async function run(command, args = []) {
19
- const root = await projectRoot();
20
- const action = args[0] || 'status';
21
- if (action === 'metrics') {
22
- const result = codexLbMetrics(await readCodexLbCircuit(root));
23
- if (flag(args, '--json'))
24
- return printJson(result);
25
- console.log(`codex-lb circuit: ${result.circuit.state}`);
26
- if (!result.ok)
27
- process.exitCode = 1;
28
- return;
29
- }
30
- if (action === 'status' || action === 'check') {
31
- const options = controllerOptions(args);
32
- options.networkProbes = action === 'check'
33
- || flag(args, '--deep')
34
- || flag(args, '--fix')
35
- || flag(args, '--remeasure');
36
- const result = await codexLbDesktopStatusV2(options);
37
- if (result.ok !== true)
38
- process.exitCode = 1;
39
- if (flag(args, '--json'))
40
- return printJson(result);
41
- process.stdout.write(formatCodexLbDesktopStatusText(result));
42
- return;
43
- }
44
- if (action === 'doctor') {
45
- const status = await codexLbDesktopStatusV2(controllerOptions(args));
46
- const metrics = codexLbMetrics(await readCodexLbCircuit(root));
47
- const result = buildCodexLbDoctorResult(status, metrics, flag(args, '--deep'));
48
- if (flag(args, '--json'))
49
- return printJson(result);
50
- console.log(`codex-lb doctor: ${result.ok ? 'diagnostic_ok' : 'blocked'}; full capability: ${result.full_capability_verified ? 'verified' : 'unverified'}`);
51
- if (!result.ok)
52
- process.exitCode = 1;
53
- return;
54
- }
55
- if (action === 'connect-test') {
56
- const options = controllerOptions(args);
57
- const status = await codexLbStatus(options);
58
- const modelSelection = await resolveCodexLbHealthModel(status);
59
- const loadedEnv = await loadCodexLbEnv({
60
- home: options.home || path.dirname(path.dirname(status.env_path)),
61
- envPath: options.envPath || status.env_path,
62
- ...(options.metadataPath ? { metadataPath: options.metadataPath } : {})
63
- });
64
- const result = await testCodexLbConnection(status, {
65
- requireSelected: true,
66
- model: modelSelection.model,
67
- baseUrl: loadedEnv.base_url,
68
- apiKey: loadedEnv.secret_api_key,
69
- credentialBindingBlockers: loadedEnv.credential_binding.blockers,
70
- gatewayAuthTransport: options.gatewayAuthTransport
71
- || (directGatewayProbeTransport(status, loadedEnv) === 'x-codex-lb-api-key'
72
- ? 'x-codex-lb-api-key'
73
- : 'authorization-bearer-compat')
74
- });
75
- if (!result.ok)
76
- process.exitCode = 1;
77
- if (flag(args, '--json'))
78
- return printJson(result);
79
- console.log(result.ok
80
- ? `codex-lb connect test: ok (${result.model}, ${result.latency_ms}ms): ${result.result || ''}`
81
- : `codex-lb connect test: failed (${result.status})`);
82
- return;
83
- }
84
- if (action === 'health' || action === 'verify-chain' || action === 'chain') {
85
- const allowUnverifiedToolOutputRecovery = codexLbToolOutputRecoveryOverrideAcknowledged({ args });
86
- const status = await codexLbStatus({ probeToolOutputRecovery: true, allowUnverifiedToolOutputRecovery });
87
- const modelSelection = await resolveCodexLbHealthModel(status);
88
- const loadedEnv = await loadCodexLbEnv({ home: path.dirname(path.dirname(status.env_path)), envPath: status.env_path });
89
- const bindingBlocker = loadedEnv.credential_binding.blockers[0] || null;
90
- const providerUrlMismatch = status.provider_configured === true && status.provider_base_url_matches_credential !== true;
91
- const blocker = bindingBlocker
92
- || (providerUrlMismatch ? 'provider_base_url_mismatch' : null)
93
- || (!status.env_key_configured
94
- ? 'missing_env_key'
95
- : !status.base_url
96
- ? 'missing_base_url'
97
- : !modelSelection.model
98
- ? 'model_unselected'
99
- : 'not_configured');
100
- const chain = status.selected && status.tool_output_recovery?.ok !== true
101
- ? { ok: false, status: 'tool_output_recovery_blocked', codex_lb: status, tool_output_recovery: status.tool_output_recovery }
102
- : !bindingBlocker && !providerUrlMismatch && status.env_key_configured && loadedEnv.base_url && loadedEnv.secret_api_key && modelSelection.model
103
- ? await checkCodexLbResponseChain(status, {
104
- force: true,
105
- root,
106
- fastMode: flag(args, '--fast') || flag(args, '--priority'),
107
- model: modelSelection.model,
108
- baseUrl: loadedEnv.base_url,
109
- apiKey: loadedEnv.secret_api_key
110
- })
111
- : { ok: false, status: blocker, codex_lb: status };
112
- const routingTruth = await measureAndWriteCodexLbRoutingTruth({
113
- selected: status.selected === true,
114
- baseUrl: loadedEnv.base_url,
115
- apiKey: loadedEnv.secret_api_key,
116
- authTransport: directGatewayProbeTransport(status, loadedEnv)
117
- }, {
118
- home: path.dirname(path.dirname(status.env_path))
119
- });
120
- const result = {
121
- ...chain,
122
- ok: chain.ok === true && routingTruth.ok,
123
- codex_lb: status,
124
- model_selection: modelSelection,
125
- routing_truth: routingTruth
126
- };
127
- if (!result.ok)
128
- process.exitCode = 1;
129
- if (flag(args, '--json'))
130
- return printJson(result);
131
- console.log(`codex-lb response chain: ${result.ok ? 'ok' : `failed (${result.status})`}`);
132
- return;
133
- }
134
- if (action === 'fast-check' || action === 'fast' || action === 'verify-fast') {
135
- const allowUnverifiedToolOutputRecovery = codexLbToolOutputRecoveryOverrideAcknowledged({ args });
136
- const status = await codexLbStatus({ probeToolOutputRecovery: true, allowUnverifiedToolOutputRecovery });
137
- const loadedEnv = await loadCodexLbEnv({ home: path.dirname(path.dirname(status.env_path)), envPath: status.env_path });
138
- const bindingBlocker = loadedEnv.credential_binding.blockers[0] || null;
139
- const providerUrlMismatch = status.provider_configured === true && status.provider_base_url_matches_credential !== true;
140
- const blocker = bindingBlocker || (providerUrlMismatch ? 'provider_base_url_mismatch' : null)
141
- || (!status.env_key_configured ? 'missing_env_key' : !status.base_url ? 'missing_base_url' : !status.provider_contract_ok ? 'provider_contract_drift' : 'not_configured');
142
- const modelSelection = await resolveCodexLbFastCheckModel(status);
143
- const chain = status.selected && status.tool_output_recovery?.ok !== true
144
- ? { ok: false, status: 'tool_output_recovery_blocked', codex_lb: status, tool_output_recovery: status.tool_output_recovery }
145
- : !bindingBlocker && !providerUrlMismatch && status.env_key_configured && loadedEnv.base_url && loadedEnv.secret_api_key && modelSelection.model
146
- ? await checkCodexLbResponseChain(status, { force: true, cache: false, root, fastMode: true, model: modelSelection.model, baseUrl: loadedEnv.base_url, apiKey: loadedEnv.secret_api_key })
147
- : { ok: false, status: modelSelection.model ? blocker : 'model_unselected', codex_lb: status };
148
- const evidence = await fastEvidenceFromChain(chain, readOption(args, '--request-log', readOption(args, '--request-log-json', null)));
149
- const providerReady = status.provider_contract_ok === true;
150
- const chainVerified = isCodexLbFastChainVerified(chain);
151
- const routingTruth = await measureAndWriteCodexLbRoutingTruth({
152
- selected: status.selected === true,
153
- baseUrl: loadedEnv.base_url,
154
- apiKey: loadedEnv.secret_api_key,
155
- authTransport: directGatewayProbeTransport(status, loadedEnv)
156
- }, {
157
- home: path.dirname(path.dirname(status.env_path))
158
- });
159
- const result = {
160
- schema: 'sks.codex-lb-fast-check.v1',
161
- ok: Boolean(providerReady && chainVerified && routingTruth.ok && evidence.fast_requested && evidence.fast_actual),
162
- status: !providerReady
163
- ? 'provider_contract_drift'
164
- : chain.skipped === true
165
- ? 'fast_check_chain_skipped'
166
- : chainVerified
167
- ? evidence.fast_actual
168
- ? 'fast_verified'
169
- : evidence.fast_requested
170
- ? 'fast_requested_but_actual_unverified'
171
- : 'fast_not_requested'
172
- : chain.status,
173
- codex_lb: status,
174
- model_selection: modelSelection,
175
- chain,
176
- routing_truth: routingTruth,
177
- evidence,
178
- degraded_models: Array.isArray(chain.degraded_models) ? chain.degraded_models : [],
179
- quota_low: Boolean(chain.quota_low),
180
- blockers: [
181
- ...(providerReady ? [] : ['codex_lb_provider_contract_drift']),
182
- ...routingTruth.blockers,
183
- ...modelSelection.blockers,
184
- ...(chain.skipped === true
185
- ? ['codex_lb_fast_check_chain_skipped']
186
- : chainVerified
187
- ? evidence.fast_actual
188
- ? []
189
- : [evidence.fast_requested ? 'codex_lb_actual_fast_service_tier_unverified' : 'codex_lb_fast_service_tier_not_requested']
190
- : [chain.status || blocker])
191
- ]
192
- };
193
- if (flag(args, '--json'))
194
- return printJson(result);
195
- console.log(`codex-lb fast check: ${result.ok ? 'ok' : `blocked (${result.status})`}`);
196
- if (!result.ok) {
197
- console.log('Need codex-lb request evidence: requestedServiceTier=priority and actualServiceTier/serviceTier=priority.');
198
- process.exitCode = 1;
199
- }
200
- return;
201
- }
202
- if (action === 'repair' || action === 'resync' || action === 'login') {
203
- const result = await repairCodexLbAuth(controllerOptions(args));
204
- if (result.ok !== true)
205
- process.exitCode = 1;
206
- if (flag(args, '--json'))
207
- return printJson(result);
208
- console.log(`codex-lb repair: ${result.ok === true ? 'ok' : String(result.status || 'failed')}`);
209
- return;
210
- }
211
- if (action === 'set-key' || action === 'update-key' || action === 'rotate-key') {
212
- const current = await codexLbDesktopStatusV2(controllerOptions(args));
213
- const loaded = await loadCodexLbEnv();
214
- const host = loaded.base_url;
215
- if (!host) {
216
- const result = { schema: 'sks.codex-lb-set-key.v1', ok: false, status: 'not_configured' };
217
- if (flag(args, '--json')) {
218
- process.exitCode = 1;
219
- return printJson(result);
220
- }
221
- console.error('codex-lb is not configured yet. Run: sks codex-lb setup --host <domain> --api-key-stdin');
222
- process.exitCode = 1;
223
- return;
224
- }
225
- const newKey = await resolveNewApiKey(args);
226
- if (!newKey) {
227
- const result = { schema: 'sks.codex-lb-set-key.v1', ok: false, status: 'missing_api_key' };
228
- if (flag(args, '--json')) {
229
- process.exitCode = 1;
230
- return printJson(result);
231
- }
232
- console.error('No new API key provided. Run: sks codex-lb set-key --api-key-stdin');
233
- process.exitCode = 1;
234
- return;
235
- }
236
- const result = await configureCodexLb({
237
- host,
238
- apiKey: newKey,
239
- keychain: false,
240
- storeKeychain: false,
241
- writeEnvFile: true,
242
- syncLaunchctl: true,
243
- desktopMode: 'cli-provider',
244
- useDefaultProvider: current.mode === 'cli-provider' && current.routing_active === true,
245
- allowUnverifiedToolOutputRecovery: codexLbToolOutputRecoveryOverrideAcknowledged({ args })
246
- });
247
- let routing = null;
248
- const restartRequested = flag(args, '--restart-app') || flag(args, '--restart')
249
- || current.mode === 'desktop-native-bridge';
250
- if (result.ok && current.mode === 'desktop-native-bridge') {
251
- routing = await activateCodexLbDesktopMode({
252
- ...controllerOptions(args),
253
- mode: 'desktop-native-bridge',
254
- restartApp: restartRequested
255
- });
256
- }
257
- const ok = Boolean(result.ok && routing?.ok !== false);
258
- const output = {
259
- ...result,
260
- schema: 'sks.codex-lb-set-key.v2',
261
- ok,
262
- action: 'set-key',
263
- provider_ready: result.ok === true,
264
- routing_active: Boolean(result.ok
265
- && ((current.mode === 'desktop-native-bridge' && routing?.ok !== false)
266
- || (current.mode === 'cli-provider' && result.codex_lb?.selected === true))),
267
- activation_required: Boolean(result.ok
268
- && current.mode !== 'desktop-native-bridge'
269
- && current.mode !== 'desktop-dual-auth-compat'),
270
- desktop_auth_mutated: false,
271
- fast_mode_mutated: false,
272
- desktop_routing: routing,
273
- center_credentials: routing?.center_credentials || null
274
- };
275
- if (!ok)
276
- process.exitCode = 1;
277
- if (flag(args, '--json'))
278
- return printJson(output);
279
- console.log(result.ok ? `codex-lb API key updated (${result.base_url || host}).` : `codex-lb key update failed: ${result.status}${result.error ? `: ${result.error}` : ''}`);
280
- printCodexLbSetupWarnings(result);
281
- if (!ok)
282
- process.exitCode = 1;
283
- return;
284
- }
285
- if (action === 'use-desktop-full'
286
- || action === 'use-codex-lb'
287
- || action === 'use-lb') {
288
- if (action !== 'use-desktop-full') {
289
- printDeprecationWarning(action, 'sks codex-lb use-desktop-full');
290
- }
291
- const result = await activateCodexLbDesktopMode({
292
- ...controllerOptions(args),
293
- mode: 'desktop-native-bridge'
294
- });
295
- if (result.ok !== true)
296
- process.exitCode = 1;
297
- if (flag(args, '--json'))
298
- return printJson(result);
299
- console.log(result.ok === true
300
- ? 'Codex Desktop Full Capability routing enabled; ChatGPT OAuth remains active.'
301
- : `Desktop Full Capability activation failed: ${String(result.status || 'failed')}`);
302
- return;
303
- }
304
- if (action === 'use-cli') {
305
- const result = await configureCodexLbCliMode(controllerOptions(args));
306
- if (result.ok !== true)
307
- process.exitCode = 1;
308
- if (flag(args, '--json'))
309
- return printJson(result);
310
- console.log(result.ok === true
311
- ? `codex-lb CLI provider active (${String(result.routing_truth?.actual_host || 'verified route')}).`
312
- : `codex-lb CLI provider setup failed: ${String(result.status || 'failed')}`);
313
- return;
314
- }
315
- if (action === 'disable'
316
- || action === 'release'
317
- || action === 'unselect'
318
- || action === 'use-oauth'
319
- || action === 'use-chatgpt') {
320
- if (action !== 'disable') {
321
- printDeprecationWarning(action, 'sks codex-lb disable');
322
- }
323
- const result = await disableCodexLbDesktopRouting(controllerOptions(args));
324
- if (result.ok !== true)
325
- process.exitCode = 1;
326
- if (flag(args, '--json'))
327
- return printJson(result);
328
- console.log(result.ok === true
329
- ? 'codex-lb Desktop routing disabled; existing ChatGPT OAuth was left untouched.'
330
- : `codex-lb Desktop routing disable failed: ${String(result.status || 'failed')}`);
331
- return;
332
- }
333
- if (action === 'capabilities') {
334
- const level = normalizeCapabilityLevel(readOption(args, '--level', 'shallow'));
335
- if (!level) {
336
- const result = {
337
- schema: 'sks.codex-lb-capabilities-command.v2',
338
- ok: false,
339
- status: 'invalid_level',
340
- blockers: ['capability_level_must_be_shallow_transport_or_deep']
341
- };
342
- process.exitCode = 1;
343
- if (flag(args, '--json'))
344
- return printJson(result);
345
- console.error('Invalid capability level. Use shallow, transport, or deep.');
346
- return;
347
- }
348
- const { deepEvidence, deepEvidenceTrustAnchors } = await readDeepEvidenceOptions(args);
349
- const report = await buildCodexLbDesktopCapabilities({
350
- ...controllerOptions(args),
351
- level,
352
- deepEvidence,
353
- deepEvidenceTrustAnchors,
354
- networkProbes: !flag(args, '--no-network')
355
- });
356
- const diagnosticOk = report.overall !== 'blocked' && report.overall !== 'unsupported';
357
- const result = {
358
- ...report,
359
- ok: diagnosticOk,
360
- diagnostic_ok: diagnosticOk,
361
- level,
362
- full_capability_verified: report.overall === 'verified'
363
- };
364
- if (!diagnosticOk)
365
- process.exitCode = 1;
366
- if (flag(args, '--json'))
367
- return printJson(result);
368
- console.log(`codex-lb capabilities (${level}): ${diagnosticOk ? 'diagnostic_ok' : 'blocked'}; overall=${report.overall}`);
369
- printCapabilityRows(report);
370
- return;
371
- }
372
- if (action === 'migrate-legacy-desktop') {
373
- const { deepEvidence, deepEvidenceTrustAnchors } = await readDeepEvidenceOptions(args);
374
- const toRaw = String(readOption(args, '--to', readOption(args, '--target', 'bridge')) || 'bridge')
375
- .trim()
376
- .toLowerCase();
377
- const mode = toRaw === 'bridge'
378
- || toRaw === 'desktop-full'
379
- || toRaw === 'desktop-native-bridge'
380
- || toRaw === ''
381
- ? 'desktop-native-bridge'
382
- : null;
383
- if (!mode) {
384
- const result = {
385
- schema: 'sks.codex-lb-legacy-migration-command.v2',
386
- ok: false,
387
- status: 'invalid_migration_target',
388
- blockers: ['migration_target_must_be_bridge']
389
- };
390
- process.exitCode = 1;
391
- if (flag(args, '--json'))
392
- return printJson(result);
393
- console.error('Invalid --to value. Use bridge.');
394
- return;
395
- }
396
- const result = await migrateLegacyCodexLbDesktopMode({
397
- ...controllerOptions(args),
398
- mode,
399
- deepEvidence,
400
- deepEvidenceTrustAnchors
401
- });
402
- if (result.ok !== true)
403
- process.exitCode = 1;
404
- if (flag(args, '--json'))
405
- return printJson(result);
406
- console.log(result.ok === true
407
- ? `Legacy codex-lb Desktop state migrated (${String(result.receipt_path || '')}).`
408
- : `Legacy migration blocked: ${String(result.status || 'failed')}`);
409
- return;
410
- }
411
- if (action === 'rollback') {
412
- const receiptId = String(args[1] || readOption(args, '--receipt', '')).trim();
413
- const result = await rollbackCodexLbDesktopMode(receiptId, controllerOptions(args));
414
- if (result.ok !== true)
415
- process.exitCode = 1;
416
- if (flag(args, '--json'))
417
- return printJson(result);
418
- console.log(result.ok === true
419
- ? `codex-lb Desktop rollback completed (${receiptId}).`
420
- : `codex-lb Desktop rollback failed: ${String(result.status || 'failed')}`);
421
- return;
422
- }
423
- if ((action === 'bridge' || action === 'desktop-bridge') && args[1] === 'serve') {
424
- const result = await serveDesktopBridge(controllerOptions(args));
425
- if (!result.ok)
426
- process.exitCode = 1;
427
- if (flag(args, '--json'))
428
- return printJson(result);
429
- console.log(`codex-lb Desktop bridge: ${result.status}`);
430
- return;
431
- }
432
- if (action === 'setup' || action === 'reconfigure') {
433
- const options = await codexLbSetupOptions(args);
434
- if (options.desktopMode === 'cli-provider' && options.gatewayAuthTransport === 'x-codex-lb-api-key') {
435
- const result = {
436
- schema: 'sks.codex-lb-setup.v1',
437
- ok: false,
438
- status: 'custom_header_transport_requires_desktop_bridge',
439
- guidance: [
440
- 'The atomic CLI provider always sends Authorization: Bearer (Codex env_key).',
441
- 'For a gateway that only accepts the X-Codex-LB-API-Key header, use Desktop Bridge mode:',
442
- 'sks codex-lb setup --host <domain> --desktop-mode desktop-full --gateway-auth custom-header --api-key-stdin --yes'
443
- ]
444
- };
445
- if (flag(args, '--json')) {
446
- process.exitCode = 1;
447
- return printJson(result);
448
- }
449
- console.error('codex-lb setup rejected: --gateway-auth custom-header only applies to Desktop Bridge mode; the CLI provider always uses Authorization: Bearer.');
450
- process.exitCode = 1;
451
- return;
452
- }
453
- const plan = buildCodexLbSetupPlan({
454
- host_or_base_url: options.host || '',
455
- api_key_source: options.apiKeySource,
456
- desktop_mode: options.desktopMode,
457
- gateway_auth_transport: options.gatewayAuthTransport,
458
- write_env_file: options.writeEnvFile,
459
- store_keychain: options.keychain,
460
- sync_launchctl: options.syncLaunchctl,
461
- install_shell_profile: options.shellProfile,
462
- run_health_check: options.health,
463
- allow_insecure_localhost: options.allowInsecureLocalhost
464
- });
465
- if (!options.host || !options.apiKey) {
466
- const result = {
467
- schema: 'sks.codex-lb-setup.v1',
468
- ok: false,
469
- status: 'setup_needed',
470
- reason: !options.host ? 'missing_host_or_base_url' : 'missing_api_key',
471
- guidance: [
472
- 'Run: sks codex-lb setup',
473
- 'Or: sks codex-lb setup --host <domain> --api-key-stdin --yes'
474
- ]
475
- };
476
- if (flag(args, '--json')) {
477
- process.exitCode = 1;
478
- return printJson(result);
479
- }
480
- console.error('codex-lb API key is not configured.');
481
- console.error('Run:');
482
- console.error(' sks codex-lb setup');
483
- console.error('or:');
484
- console.error(' sks codex-lb setup --host <domain> --api-key-stdin --yes');
485
- process.exitCode = 1;
486
- return;
487
- }
488
- if (flag(args, '--plan')) {
489
- const result = { schema: 'sks.codex-lb-setup-plan-result.v1', ok: plan.blockers.length === 0, plan, writes: false, expected_actions: plan.expected_actions, persistence: plan.persistence };
490
- if (!result.ok)
491
- process.exitCode = 1;
492
- if (flag(args, '--json'))
493
- return printJson(result);
494
- process.stdout.write(renderCodexLbSetupPlan(plan));
495
- if (!result.ok)
496
- process.exitCode = 1;
497
- return;
498
- }
499
- const processOnly = plan.persistence.effective_mode === 'process_only_ephemeral';
500
- if (options.interactive && !options.yes) {
501
- process.stdout.write(renderCodexLbSetupPlan(plan));
502
- const confirm = (await ask('Apply this codex-lb setup plan? [y/N] ')).trim();
503
- if (!/^(y|yes|예|네|응)$/i.test(confirm)) {
504
- const result = { schema: 'sks.codex-lb-setup.v1', ok: false, status: 'cancelled', plan, applied_actions: [] };
505
- if (flag(args, '--json')) {
506
- process.exitCode = 1;
507
- return printJson(result);
508
- }
509
- console.log('codex-lb setup cancelled.');
510
- process.exitCode = 1;
511
- return;
512
- }
513
- if (processOnly) {
514
- const confirmProcessOnly = (await ask('This setup keeps credentials only in the current process. Type process-only to continue: ')).trim();
515
- if (confirmProcessOnly !== 'process-only') {
516
- const result = { schema: 'sks.codex-lb-setup.v1', ok: false, status: 'process_only_cancelled', plan, applied_actions: [], persistence: plan.persistence };
517
- if (flag(args, '--json')) {
518
- printJson(result);
519
- process.exitCode = 1;
520
- return;
521
- }
522
- console.log('codex-lb setup cancelled: process-only ephemeral setup was not confirmed.');
523
- process.exitCode = 1;
524
- return;
525
- }
526
- }
527
- }
528
- else if (processOnly && !options.yes) {
529
- const result = {
530
- schema: 'sks.codex-lb-setup.v1',
531
- ok: false,
532
- status: 'process_only_requires_yes',
533
- plan,
534
- applied_actions: [],
535
- persistence: plan.persistence,
536
- guidance: ['Pass --yes to acknowledge process_only_ephemeral setup, or enable --write-env-file, --launchctl, or --shell-profile.']
537
- };
538
- if (flag(args, '--json')) {
539
- printJson(result);
540
- process.exitCode = 1;
541
- return;
542
- }
543
- console.error('codex-lb setup would be process-only ephemeral. Pass --yes to acknowledge, or enable a durable persistence mode.');
544
- process.exitCode = 1;
545
- return;
546
- }
547
- const result = await configureCodexLb({
548
- host: options.host,
549
- apiKey: options.apiKey,
550
- desktopMode: 'cli-provider',
551
- useDefaultProvider: options.useDefaultProvider,
552
- gatewayAuthTransport: options.gatewayAuthTransport,
553
- keychain: options.keychain,
554
- storeKeychain: options.keychain,
555
- writeEnvFile: options.writeEnvFile,
556
- syncLaunchctl: options.syncLaunchctl,
557
- shellProfile: options.shellProfile,
558
- runHealth: false,
559
- apiKeySource: options.apiKeySource,
560
- allowInsecureHttp: options.allowInsecureLocalhost,
561
- allowUnverifiedToolOutputRecovery: codexLbToolOutputRecoveryOverrideAcknowledged({ args })
562
- });
563
- let desktopActivation = null;
564
- if (result.ok && options.desktopMode === 'desktop-native-bridge') {
565
- desktopActivation = await activateCodexLbDesktopMode({
566
- ...controllerOptions(args),
567
- mode: 'desktop-native-bridge',
568
- gatewayAuthTransport: options.gatewayAuthTransport
569
- });
570
- }
571
- const capabilities = options.health && result.ok
572
- ? await buildCodexLbDesktopCapabilities({
573
- ...controllerOptions(args),
574
- level: 'transport',
575
- networkProbes: true
576
- })
577
- : null;
578
- const capabilityDiagnosticOk = codexLbSetupCapabilityDiagnosticOk(capabilities);
579
- const setupRoutingTruth = result.ok && options.desktopMode === 'cli-provider'
580
- ? await measureAndWriteCodexLbRoutingTruth({
581
- selected: result.codex_lb?.selected === true,
582
- baseUrl: result.base_url || null,
583
- apiKey: options.apiKey,
584
- authTransport: 'authorization-bearer'
585
- }, {
586
- home: path.dirname(path.dirname(result.env_path))
587
- })
588
- : desktopActivation?.post_activation_status?.routing_truth || null;
589
- const cliRoutingActive = codexLbRoutingTruthIsActive(setupRoutingTruth);
590
- const shaped = {
591
- ...result,
592
- schema: 'sks.codex-lb-setup.v2',
593
- ok: Boolean(result.ok
594
- && desktopActivation?.ok !== false
595
- && capabilityDiagnosticOk),
596
- diagnostic_ok: capabilityDiagnosticOk,
597
- requested_desktop_mode: options.desktopMode,
598
- gateway_auth_transport: options.gatewayAuthTransport,
599
- api_key: { present: Boolean(options.apiKey), redacted: true },
600
- env_file_chmod: options.writeEnvFile ? '0600' : null,
601
- desktop_auth_mutated: false,
602
- fast_mode_mutated: false,
603
- provider_ready: result.ok === true,
604
- routing_active: Boolean(result.ok && (desktopActivation?.ok === true || cliRoutingActive)),
605
- routing_truth: setupRoutingTruth,
606
- activation_required: Boolean(result.ok
607
- && options.desktopMode === 'cli-provider'
608
- && !cliRoutingActive
609
- && desktopActivation === null),
610
- desktop_activation: desktopActivation,
611
- capabilities
612
- };
613
- if (options.health) {
614
- shaped.applied_actions = [
615
- ...(shaped.applied_actions || []),
616
- {
617
- type: 'run_capability_check',
618
- target: 'codex-lb Desktop capability matrix',
619
- ok: capabilityDiagnosticOk,
620
- overall: capabilities?.overall || null
621
- }
622
- ];
623
- }
624
- if (!shaped.ok)
625
- process.exitCode = 1;
626
- if (flag(args, '--json'))
627
- return printJson(shaped);
628
- if (!shaped.ok) {
629
- console.error(`codex-lb setup failed: ${String(result.status || 'configuration_failed')}`);
630
- const recoveryPaths = Array.isArray(result.rollback?.recovery_paths)
631
- ? result.rollback.recovery_paths.map((value) => String(value || '')).filter(Boolean)
632
- : [];
633
- if (recoveryPaths.length > 0) {
634
- console.error('Recovery files retained:');
635
- for (const recoveryPath of recoveryPaths)
636
- console.error(` ${recoveryPath}`);
637
- }
638
- const secretRecoveryPaths = Array.isArray(result.rollback?.secret_recovery_paths)
639
- ? result.rollback.secret_recovery_paths.map((value) => String(value || '')).filter(Boolean)
640
- : [];
641
- if (secretRecoveryPaths.length > 0) {
642
- console.error('Warning: the following owner-only recovery files may contain the submitted API key:');
643
- for (const recoveryPath of secretRecoveryPaths)
644
- console.error(` ${recoveryPath}`);
645
- }
646
- if (result.keychain?.keychain_state_verified === false) {
647
- console.error('Keychain state is indeterminate; do not assume the previous credential was restored.');
648
- }
649
- printCodexLbSetupWarnings(result);
650
- return;
651
- }
652
- console.log(`codex-lb configured: ${result.base_url || result.status}`);
653
- console.log(`Desktop mode: ${options.desktopMode}${desktopActivation ? ` (${String(desktopActivation.status || 'applied')})` : ' (routing unchanged)'}`);
654
- const retainedRecoveryPaths = Array.isArray(result.recovery_paths)
655
- ? result.recovery_paths.map((value) => String(value || '')).filter(Boolean)
656
- : [];
657
- const retainedSecretRecoveryPaths = Array.isArray(result.secret_recovery_paths)
658
- ? result.secret_recovery_paths.map((value) => String(value || '')).filter(Boolean)
659
- : [];
660
- const secretRecoverySet = new Set(retainedSecretRecoveryPaths);
661
- const nonSecretRecoveryPaths = retainedRecoveryPaths.filter((value) => !secretRecoverySet.has(value));
662
- if (nonSecretRecoveryPaths.length > 0) {
663
- console.log('Recovery backups retained:');
664
- for (const recoveryPath of nonSecretRecoveryPaths)
665
- console.log(` ${recoveryPath}`);
666
- }
667
- if (retainedSecretRecoveryPaths.length > 0) {
668
- console.error('Warning: owner-only recovery files may contain a previous API key and require secure review:');
669
- for (const recoveryPath of retainedSecretRecoveryPaths)
670
- console.error(` ${recoveryPath}`);
671
- }
672
- printCodexLbSetupWarnings(shaped);
673
- if (!shaped.ok)
674
- process.exitCode = 1;
675
- return;
676
- }
677
- if (action === 'circuit' && args[1] === 'reset') {
678
- const result = await resetCodexLbCircuit(root);
679
- if (flag(args, '--json'))
680
- return printJson({ ok: true, circuit: result });
681
- console.log('codex-lb circuit reset');
682
- return;
683
- }
684
- if (action === 'circuit' && args[1] === 'record-fixture') {
685
- const fixturePath = args[2] || readOption(args, '--fixture', null);
686
- if (!fixturePath) {
687
- console.error('Usage: sks codex-lb circuit record-fixture <fixture.json> [--json]');
688
- process.exitCode = 1;
689
- return;
690
- }
691
- const { readJson } = await import('../core/fsx.js');
692
- const event = await readJson(path.isAbsolute(fixturePath) ? fixturePath : path.resolve(root, fixturePath), {});
693
- const circuit = await recordCodexLbHealthEvent(root, event);
694
- const result = { schema: 'sks.codex-lb-circuit-record-fixture.v1', ok: true, fixture: fixturePath, circuit };
695
- if (flag(args, '--json'))
696
- return printJson(result);
697
- console.log(`codex-lb circuit: ${circuit.state}`);
698
- return;
699
- }
700
- if (action === 'proof-evidence') {
701
- const result = await codexLbProofEvidence(root);
702
- if (flag(args, '--json'))
703
- return printJson(result);
704
- console.log(`codex-lb proof evidence: ${result.status}`);
705
- return;
706
- }
707
- console.error('Usage: sks codex-lb status|setup|set-key|connect-test|use-desktop-full|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]');
708
- console.error(` ${CODEX_LB_TOOL_OUTPUT_RECOVERY_OVERRIDE_FLAG} explicitly acknowledge an old/unverified proxy for this command (unsafe)`);
709
- console.error(' set-key swap the codex-lb API key (reuses the stored host): sks codex-lb set-key --api-key-stdin');
710
- console.error(' --keychain fail-closed until a dedicated signed SKS Keychain helper is available; the default 0600 env file is used');
711
- console.error(' use-desktop-full keep ChatGPT OAuth/built-in OpenAI and route data through the local bridge');
712
- console.error(' use-cli verify, write, and atomically select the CLI codex-lb provider');
713
- console.error(' disable remove only SKS-managed Desktop routing; auth.json is untouched');
714
- process.exitCode = 1;
715
- }
716
- export function codexLbRestartPostcondition(restart = {}, required = false) {
717
- const performed = restart?.status === 'restarted';
718
- return {
719
- required: Boolean(required),
720
- performed,
721
- satisfied: !required || performed
722
- };
723
- }
724
- export function buildCodexLbDoctorResult(status, metrics, deep = false) {
725
- const diagnosticOk = status.ok === true;
726
- return {
727
- schema: 'sks.codex-lb-doctor.v2',
728
- ok: diagnosticOk && metrics.ok === true,
729
- diagnostic_ok: diagnosticOk,
730
- full_capability_verified: status.full_capability_verified === true,
731
- deep,
732
- status,
733
- metrics
734
- };
735
- }
736
- export function codexLbSetupCapabilityDiagnosticOk(capabilities) {
737
- return capabilities === null
738
- || (capabilities.overall !== 'blocked' && capabilities.overall !== 'unsupported');
739
- }
740
- export function isCodexLbFastChainVerified(chain = {}) {
741
- return chain.ok === true && chain.skipped !== true;
742
- }
743
- export async function resolveCodexLbFastCheckModel(status = {}, env = process.env) {
744
- return resolveCodexLbModel(status, env, { requirePriority: true, blockerPrefix: 'codex_lb_fast_check' });
745
- }
746
- export async function resolveCodexLbHealthModel(status = {}, env = process.env) {
747
- return resolveCodexLbModel(status, env, { requirePriority: false, blockerPrefix: 'codex_lb_health' });
748
- }
749
- async function resolveCodexLbModel(status = {}, env = process.env, opts = {}) {
750
- const explicit = String(env.SKS_CODEX_MODEL || env.CODEX_MODEL || '').trim();
751
- if (explicit)
752
- return { model: explicit, source: env.SKS_CODEX_MODEL ? 'SKS_CODEX_MODEL' : 'CODEX_MODEL', blockers: [] };
753
- const configPath = String(status.config_path || '').trim();
754
- const config = configPath ? await readText(configPath, '').catch(() => '') : '';
755
- const configured = topLevelTomlString(config, 'model');
756
- if (configured)
757
- return { model: configured, source: 'global_config', blockers: [] };
758
- const home = String(env.HOME || '').trim();
759
- const configuredCatalogPath = topLevelTomlString(config, 'model_catalog_json');
760
- const defaultCatalogPath = configPath
761
- ? path.join(path.dirname(configPath), 'models_cache.json')
762
- : home
763
- ? path.join(home, '.codex', 'models_cache.json')
764
- : '';
765
- const requestedCatalogPath = configuredCatalogPath || defaultCatalogPath;
766
- if (!requestedCatalogPath)
767
- return { model: null, source: null, blockers: [`${opts.blockerPrefix}_model_unselected`] };
768
- const expandedCatalogPath = requestedCatalogPath.startsWith('~/') && home
769
- ? path.join(home, requestedCatalogPath.slice(2))
770
- : requestedCatalogPath;
771
- const catalogPath = path.isAbsolute(expandedCatalogPath)
772
- ? expandedCatalogPath
773
- : path.resolve(path.dirname(configPath), expandedCatalogPath);
774
- try {
775
- const catalogText = await readText(catalogPath, '');
776
- if (!catalogText.trim()) {
777
- return { model: null, source: null, blockers: [`${opts.blockerPrefix}_model_unselected`] };
778
- }
779
- const payload = JSON.parse(catalogText);
780
- const model = selectCatalogModel(payload, opts.requirePriority === true);
781
- return model
782
- ? { model, source: configuredCatalogPath ? 'model_catalog_json' : 'codex_models_cache', blockers: [] }
783
- : { model: null, source: configuredCatalogPath ? 'model_catalog_json' : 'codex_models_cache', blockers: [`${opts.blockerPrefix}_${opts.requirePriority === true ? 'priority_' : ''}model_unavailable`] };
784
- }
785
- catch {
786
- return { model: null, source: configuredCatalogPath ? 'model_catalog_json' : 'codex_models_cache', blockers: [`${opts.blockerPrefix}_catalog_invalid`] };
787
- }
788
- }
789
- function topLevelTomlString(text, key) {
790
- const topLevel = String(text || '').split(/\n\s*\[/)[0] || '';
791
- const escaped = key.replace(/[.*+?^${}()|[\]\\]/g, '\\$&');
792
- return (topLevel.match(new RegExp(`(?:^|\\n)\\s*${escaped}\\s*=\\s*"([^"]+)"`))?.[1] || '').trim();
793
- }
794
- function selectCatalogModel(payload = {}, requirePriority = false) {
795
- const models = Array.isArray(payload?.models) ? payload.models : Array.isArray(payload?.data) ? payload.data : [];
796
- return models
797
- .filter((row) => {
798
- if (!row || typeof row !== 'object' || row.supported_in_api !== true || typeof row.slug !== 'string' || !row.slug.trim())
799
- return false;
800
- if (!requirePriority)
801
- return true;
802
- const serviceTiers = Array.isArray(row.service_tiers) ? row.service_tiers : [];
803
- const speedTiers = Array.isArray(row.additional_speed_tiers) ? row.additional_speed_tiers : [];
804
- return serviceTiers.some((tier) => normalizeTier(typeof tier === 'string' ? tier : tier?.id) === 'priority')
805
- || speedTiers.some((tier) => normalizeTier(tier) === 'priority');
806
- })
807
- .sort((left, right) => Number(left.priority ?? Number.MAX_SAFE_INTEGER) - Number(right.priority ?? Number.MAX_SAFE_INTEGER)
808
- || String(left.slug).localeCompare(String(right.slug)))[0]?.slug || null;
809
- }
810
- export async function fastEvidenceFromChain(chain = {}, requestLogPath = null) {
811
- const chainEvidence = chain.service_tier_evidence || {};
812
- const logRows = requestLogPath ? await readRequestLogRows(String(requestLogPath)) : [];
813
- const logEvidence = serviceTierEvidenceFromRows(logRows);
814
- const requested = logEvidence.requested_service_tier || chainEvidence.requested_service_tier || chain.requested_service_tier || null;
815
- const actual = logEvidence.actual_service_tier || chainEvidence.actual_service_tier || null;
816
- const effective = logEvidence.effective_service_tier || chainEvidence.effective_service_tier || null;
817
- return {
818
- requested_service_tier: requested,
819
- actual_service_tier: actual,
820
- effective_service_tier: effective,
821
- fast_requested: requested === 'priority' || chain.requested_service_tier === 'priority' || chainEvidence.fast_requested === true,
822
- fast_actual: actual === 'priority' || effective === 'priority' || logEvidence.fast_actual === true || chainEvidence.fast_actual === true,
823
- chain_evidence: chainEvidence,
824
- request_log_path: requestLogPath || null,
825
- request_log_rows: logRows.length
826
- };
827
- }
828
- async function readRequestLogRows(file) {
829
- if (!file)
830
- return [];
831
- const text = await readText(path.isAbsolute(file) ? file : path.resolve(process.cwd(), file), '').catch(() => '');
832
- const rows = [];
833
- const trimmed = text.trim();
834
- if (!trimmed)
835
- return rows;
836
- try {
837
- const parsed = JSON.parse(trimmed);
838
- if (Array.isArray(parsed))
839
- return parsed;
840
- if (Array.isArray(parsed?.rows))
841
- return parsed.rows;
842
- if (Array.isArray(parsed?.requests))
843
- return parsed.requests;
844
- return [parsed];
845
- }
846
- catch { }
847
- for (const line of text.split(/\r?\n/)) {
848
- const candidate = line.trim();
849
- if (!candidate)
850
- continue;
851
- try {
852
- rows.push(JSON.parse(candidate));
853
- }
854
- catch { }
855
- }
856
- return rows;
857
- }
858
- export function serviceTierEvidenceFromRows(rows = []) {
859
- let requested = null;
860
- let actual = null;
861
- let effective = null;
862
- for (const row of rows) {
863
- requested ||= normalizeTier(row?.requestedServiceTier || row?.requested_service_tier || row?.request?.service_tier || row?.body?.service_tier);
864
- actual ||= normalizeTier(row?.actualServiceTier || row?.actual_service_tier || row?.response?.actualServiceTier || row?.response?.actual_service_tier);
865
- effective ||= responseServiceTier(row);
866
- }
867
- return {
868
- requested_service_tier: requested,
869
- actual_service_tier: actual,
870
- effective_service_tier: effective,
871
- fast_actual: actual === 'priority' || effective === 'priority'
872
- };
873
- }
874
- function responseServiceTier(row) {
875
- const nested = normalizeTier(row?.response?.serviceTier || row?.response?.service_tier || row?.event?.response?.serviceTier || row?.event?.response?.service_tier);
876
- if (nested)
877
- return nested;
878
- const responseKind = String(row?.direction || row?.phase || row?.kind || row?.type || '').trim().toLowerCase();
879
- const responseBody = row?.object === 'response' || /^resp[_-]/i.test(String(row?.id || '')) || Array.isArray(row?.output);
880
- if (responseBody || responseKind === 'response' || responseKind === 'inbound' || responseKind.startsWith('response.')) {
881
- return normalizeTier(row?.serviceTier || row?.service_tier);
882
- }
883
- return null;
884
- }
885
- function normalizeTier(value) {
886
- const text = String(value || '').trim().toLowerCase();
887
- if (text === 'fast')
888
- return 'priority';
889
- if (text === 'priority' || text === 'default' || text === 'flex')
890
- return text;
891
- return null;
892
- }
893
- async function readDeepEvidenceOptions(args = []) {
894
- const evidencePath = readOption(args, '--evidence', null);
895
- const trustAnchorsPath = readOption(args, '--trust-anchors', readOption(args, '--evidence-trust-anchors', null));
896
- return {
897
- deepEvidence: evidencePath
898
- ? await readCodexLbDesktopDeepEvidence(String(evidencePath))
899
- : null,
900
- deepEvidenceTrustAnchors: trustAnchorsPath
901
- ? await readCodexLbDesktopDeepEvidenceTrustAnchors(String(trustAnchorsPath))
902
- : []
903
- };
904
- }
905
- export function controllerOptions(args = []) {
906
- const rawGatewayAuth = flag(args, '--compat-bearer')
907
- ? 'authorization-bearer-compat'
908
- : (() => {
909
- const explicit = readOption(args, '--gateway-auth', readOption(args, '--gateway-auth-transport', null));
910
- return explicit === null ? null : normalizeGatewayAuthChoice(explicit);
911
- })();
912
- const gatewayAuthTransport = rawGatewayAuth === null
913
- ? null
914
- : parseCodexLbGatewayAuthTransport(rawGatewayAuth);
915
- const home = readOption(args, '--home', null);
916
- const configPath = readOption(args, '--config', readOption(args, '--config-path', null));
917
- const authPath = readOption(args, '--auth', readOption(args, '--auth-path', null));
918
- const envPath = readOption(args, '--env-file', readOption(args, '--env-path', null));
919
- const metadataPath = readOption(args, '--metadata', readOption(args, '--metadata-path', null));
920
- const receiptDir = readOption(args, '--receipt-dir', null);
921
- const routingTruthReceiptPath = readOption(args, '--routing-truth-receipt', null);
922
- const listenHost = readOption(args, '--listen-host', null);
923
- const normalizedListenHost = listenHost === null
924
- ? null
925
- : listenHost === '127.0.0.1' || listenHost === '::1'
926
- ? listenHost
927
- : (() => { throw new Error(`unsupported_codex_lb_desktop_listen_host:${listenHost}`); })();
928
- const listenPortText = readOption(args, '--listen-port', null);
929
- const listenPort = listenPortText === null ? null : Number(listenPortText);
930
- const capabilityTimeoutText = readOption(args, '--capability-timeout-ms', null);
931
- const capabilityTimeoutMs = capabilityTimeoutText === null ? null : Number(capabilityTimeoutText);
932
- return {
933
- ...(gatewayAuthTransport ? { gatewayAuthTransport } : {}),
934
- restartApp: flag(args, '--restart-app') || flag(args, '--restart'),
935
- networkProbes: !flag(args, '--no-network'),
936
- ...(home ? { home: String(home) } : {}),
937
- ...(configPath ? { configPath: String(configPath) } : {}),
938
- ...(authPath ? { authPath: String(authPath) } : {}),
939
- ...(envPath ? { envPath: String(envPath) } : {}),
940
- ...(metadataPath ? { metadataPath: String(metadataPath) } : {}),
941
- ...(receiptDir ? { receiptDir: String(receiptDir) } : {}),
942
- ...(routingTruthReceiptPath ? { routingTruthReceiptPath: String(routingTruthReceiptPath) } : {}),
943
- ...(capabilityTimeoutMs !== null && Number.isFinite(capabilityTimeoutMs) && capabilityTimeoutMs > 0
944
- ? { capabilityTimeoutMs }
945
- : {}),
946
- ...(normalizedListenHost || (listenPort !== null && Number.isInteger(listenPort))
947
- ? {
948
- settings: {
949
- ...(normalizedListenHost ? { listen_host: normalizedListenHost } : {}),
950
- ...(listenPort !== null && Number.isInteger(listenPort) ? { listen_port: listenPort } : {}),
951
- ...(gatewayAuthTransport ? { gateway_auth_transport: gatewayAuthTransport } : {})
952
- }
953
- }
954
- : {})
955
- };
956
- }
957
- export function formatCodexLbDesktopStatusText(status, opts = {}) {
958
- const oauth = asRecord(status.oauth);
959
- const provider = asRecord(status.provider);
960
- const bridge = asRecord(status.bridge);
961
- const capabilities = asRecord(status.capabilities);
962
- const resolution = asRecord(status.secret_resolution);
963
- const resolutionSource = String(resolution.source || 'missing');
964
- const resolutionPath = resolution.path
965
- ? displayHomePath(String(resolution.path), opts.home || process.env.HOME || '')
966
- : '';
967
- const resolutionLabel = resolutionPath
968
- ? `${resolutionSource} (${resolutionPath})`
969
- : resolutionSource;
970
- const blockers = stringArray(status.blockers);
971
- const guidance = stringArray(status.guidance);
972
- const lines = [
973
- 'SKS codex-lb Desktop',
974
- '',
975
- `Configured: ${status.configured === true ? 'yes' : 'no'}`,
976
- `Credentials ready: ${status.credentials_ready === true ? 'yes' : 'no'}`,
977
- `Routing active: ${status.routing_active === true ? 'yes' : 'no'}`,
978
- `Mode: ${String(status.mode || 'disabled')}`,
979
- `ChatGPT OAuth: ${oauth.present === true ? 'present and preserved' : 'missing'}`,
980
- `Provider: ${String(provider.contract || 'missing')} (${provider.contract_ok === true ? 'ok' : 'blocked'})`,
981
- `Bridge: ${String(bridge.status || 'unknown')}${bridge.running === true ? ' (running)' : ''}`,
982
- `Gateway auth: ${String(status.gateway_auth_transport || 'inactive')}`,
983
- `Key source: ${resolutionLabel} · keychain: not used · prompt risk: ${String(resolution.prompt_risk || 'none')}`,
984
- `Capabilities: ${String(status.overall || capabilities.state || 'unverified')}`,
985
- `Full capability: ${status.full_capability_verified === true ? 'verified' : 'unverified'}`
986
- ];
987
- if (blockers.length) {
988
- lines.push('', 'Blockers:');
989
- for (const blocker of blockers)
990
- lines.push(`- ${blocker}`);
991
- }
992
- if (guidance.length) {
993
- lines.push('', 'Next:');
994
- for (const item of guidance)
995
- lines.push(`- ${item}`);
996
- }
997
- return `${lines.join('\n')}\n`;
998
- }
999
- function displayHomePath(file, home) {
1000
- const resolvedFile = path.resolve(file);
1001
- const resolvedHome = home ? path.resolve(home) : '';
1002
- return resolvedHome && (resolvedFile === resolvedHome || resolvedFile.startsWith(`${resolvedHome}${path.sep}`))
1003
- ? `~${resolvedFile.slice(resolvedHome.length)}`
1004
- : resolvedFile;
1005
- }
1006
- function printDeprecationWarning(oldAction, replacement) {
1007
- console.error(`warning: \`sks codex-lb ${oldAction}\` is deprecated; use \`${replacement}\`.`);
1008
- }
1009
- function normalizeCapabilityLevel(value) {
1010
- const normalized = String(value || '').trim().toLowerCase();
1011
- if (normalized === 'shallow' || normalized === 'transport' || normalized === 'deep') {
1012
- return normalized;
1013
- }
1014
- return null;
1015
- }
1016
- function printCapabilityRows(report) {
1017
- const keys = [
1018
- 'gateway_auth_transport',
1019
- 'provider_identity',
1020
- 'bridge',
1021
- 'catalog',
1022
- 'model_picker',
1023
- 'fast_mode',
1024
- 'text_responses',
1025
- 'image_generation',
1026
- 'computer_use',
1027
- 'browser_use',
1028
- 'voice_mode',
1029
- 'plugins',
1030
- 'auxiliary_surfaces'
1031
- ];
1032
- for (const key of keys) {
1033
- const capability = report[key];
1034
- const suffix = capability.blockers.length
1035
- ? ` (${capability.blockers.join(', ')})`
1036
- : '';
1037
- console.log(`- ${key}: ${capability.state}${suffix}`);
1038
- }
1039
- }
1040
- function normalizeDesktopSetupMode(value) {
1041
- const normalized = String(value || '').trim().toLowerCase();
1042
- if (normalized === 'desktop-full'
1043
- || normalized === 'full'
1044
- || normalized === 'native'
1045
- || normalized === 'desktop-native-bridge') {
1046
- return 'desktop-native-bridge';
1047
- }
1048
- if (normalized === 'desktop-compat'
1049
- || normalized === 'compat'
1050
- || normalized === 'desktop-dual-auth-compat') {
1051
- throw new Error('desktop_dual_auth_compat_unavailable');
1052
- }
1053
- if (!normalized
1054
- || normalized === 'cli'
1055
- || normalized === 'cli-only'
1056
- || normalized === 'cli-provider') {
1057
- return 'cli-provider';
1058
- }
1059
- throw new Error(`unsupported_codex_lb_desktop_mode:${normalized}`);
1060
- }
1061
- function directGatewayProbeTransport(status, loadedEnv) {
1062
- return status?.desktop_mode === 'desktop-native-bridge'
1063
- && loadedEnv?.gateway_auth_transport === 'x-codex-lb-api-key'
1064
- ? 'x-codex-lb-api-key'
1065
- : 'authorization-bearer';
1066
- }
1067
- function normalizeGatewayAuthChoice(value) {
1068
- const normalized = String(value || '').trim().toLowerCase();
1069
- if (!normalized
1070
- || normalized === 'bearer'
1071
- || normalized === 'bearer-compat'
1072
- || normalized === 'authorization-bearer'
1073
- || normalized === 'authorization-bearer-compat') {
1074
- return 'authorization-bearer-compat';
1075
- }
1076
- if (normalized === 'custom-header'
1077
- || normalized === 'header'
1078
- || normalized === 'x-codex-lb-api-key') {
1079
- return 'x-codex-lb-api-key';
1080
- }
1081
- throw new Error(`unsupported_codex_lb_gateway_auth_transport:${normalized}`);
1082
- }
1083
- function asRecord(value) {
1084
- return value && typeof value === 'object' && !Array.isArray(value)
1085
- ? value
1086
- : {};
1087
- }
1088
- function stringArray(value) {
1089
- return Array.isArray(value) ? value.map((entry) => String(entry)).filter(Boolean) : [];
1090
- }
1091
- async function resolveNewApiKey(args = []) {
1092
- if (flag(args, '--api-key-stdin'))
1093
- return String(await readStdin()).trim();
1094
- if (input.isTTY && !flag(args, '--yes')) {
1095
- const rl = readline.createInterface({ input, output });
1096
- try {
1097
- return (await rl.question('New codex-lb API key (sk-clb-...): ')).trim();
1098
- }
1099
- finally {
1100
- rl.close();
1101
- }
1102
- }
1103
- return '';
1104
- }
1105
- async function codexLbSetupOptions(args = []) {
1106
- const baseUrl = readOption(args, '--base-url', null);
1107
- let host = baseUrl || readOption(args, '--host', readOption(args, '--domain', null));
1108
- let apiKey = null;
1109
- let apiKeySource = 'hidden_prompt';
1110
- let desktopMode = normalizeDesktopSetupMode(readOption(args, '--desktop-mode', readOption(args, '--mode', 'cli-provider')));
1111
- let gatewayAuthTransport = parseCodexLbGatewayAuthTransport(normalizeGatewayAuthChoice(flag(args, '--compat-bearer')
1112
- ? 'authorization-bearer-compat'
1113
- : readOption(args, '--gateway-auth', readOption(args, '--gateway-auth-transport', 'bearer-compat'))));
1114
- let keychain = flag(args, '--keychain');
1115
- if (flag(args, '--api-key-stdin'))
1116
- apiKey = (await readStdin()).trim();
1117
- if (flag(args, '--api-key-stdin'))
1118
- apiKeySource = 'stdin';
1119
- let health = (flag(args, '--health') || flag(args, '--check')) && !flag(args, '--no-health');
1120
- let writeEnvFile = flag(args, '--no-env-file') ? false : true;
1121
- if (flag(args, '--write-env-file'))
1122
- writeEnvFile = true;
1123
- if (flag(args, '--no-keychain'))
1124
- keychain = false;
1125
- let syncLaunchctl = false;
1126
- if (flag(args, '--launchctl'))
1127
- syncLaunchctl = true;
1128
- const shellProfile = normalizeShellProfile(readOption(args, '--shell-profile', 'skip'));
1129
- const allowInsecureLocalhost = flag(args, '--allow-insecure-localhost') || flag(args, '--allow-insecure-http');
1130
- const useDefaultProvider = !flag(args, '--no-default-provider');
1131
- const interactive = (!host || !apiKey || canAskInteractive(args)) && canAskInteractive(args);
1132
- if ((!host || !apiKey) && canAskInteractive(args)) {
1133
- console.log('SKS codex-lb setup\n');
1134
- 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();
1135
- apiKey ||= (await askHidden('2. API key?\n Input hidden. Value will be stored securely and never printed.\n> ')).trim();
1136
- apiKeySource = 'hidden_prompt';
1137
- desktopMode = normalizeDesktopSetupMode((await ask('3. Configure which mode? [cli-only/desktop-full] (cli-only)\n> ')).trim()
1138
- || 'cli-only');
1139
- if (desktopMode === 'desktop-native-bridge') {
1140
- gatewayAuthTransport = parseCodexLbGatewayAuthTransport(normalizeGatewayAuthChoice((await ask('4. Gateway key transport? [bearer-compat/custom-header] (bearer-compat)\n> ')).trim()));
1141
- }
1142
- else {
1143
- gatewayAuthTransport = 'authorization-bearer-compat';
1144
- }
1145
- writeEnvFile = parseYesNo(await ask('5. Write shell env loader to ~/.codex/sks-codex-lb.env? [Y/n] '), true);
1146
- keychain = false;
1147
- console.log('6. Key storage: ~/.codex/sks-codex-lb.env (owner-only mode 0600).');
1148
- syncLaunchctl = parseYesNo(await ask('7. Sync non-secret macOS launchctl base URL only? API keys are never stored in launchd. [y/N] '), false);
1149
- const profile = (await ask('8. Install shell profile snippet? [zsh/bash/fish/all/skip] ')).trim();
1150
- const interactiveShellProfile = normalizeShellProfile(profile || 'skip');
1151
- const runHealth = (await ask('9. Run capability diagnostics now? [Y/n] ')).trim();
1152
- health = !/^(n|no|아니|아니요|ㄴ)$/i.test(runHealth || 'y');
1153
- return {
1154
- host,
1155
- apiKey,
1156
- health,
1157
- keychain,
1158
- desktopMode,
1159
- gatewayAuthTransport,
1160
- writeEnvFile,
1161
- syncLaunchctl,
1162
- shellProfile: interactiveShellProfile,
1163
- allowInsecureLocalhost,
1164
- apiKeySource,
1165
- useDefaultProvider,
1166
- interactive: true,
1167
- yes: flag(args, '--yes')
1168
- };
1169
- }
1170
- return {
1171
- host,
1172
- apiKey,
1173
- health,
1174
- keychain,
1175
- desktopMode,
1176
- gatewayAuthTransport,
1177
- writeEnvFile,
1178
- syncLaunchctl,
1179
- shellProfile,
1180
- allowInsecureLocalhost,
1181
- apiKeySource,
1182
- useDefaultProvider,
1183
- interactive,
1184
- yes: flag(args, '--yes')
1185
- };
1186
- }
1187
- function normalizeShellProfile(value) {
1188
- const raw = String(value || 'skip').toLowerCase();
1189
- return raw === 'zsh' || raw === 'bash' || raw === 'fish' || raw === 'all' ? raw : 'skip';
1190
- }
1191
- function parseYesNo(value, fallback) {
1192
- const raw = String(value || '').trim();
1193
- if (!raw)
1194
- return fallback;
1195
- if (/^(y|yes|예|네|응)$/i.test(raw))
1196
- return true;
1197
- if (/^(n|no|아니|아니요|ㄴ)$/i.test(raw))
1198
- return false;
1199
- return fallback;
1200
- }
1201
- function canAskInteractive(args = []) {
1202
- return !flag(args, '--json') && !flag(args, '--yes') && Boolean(input.isTTY && output.isTTY && process.env.CI !== 'true');
1203
- }
1204
- async function ask(question) {
1205
- const rl = readline.createInterface({ input, output });
1206
- try {
1207
- return await rl.question(question);
1208
- }
1209
- finally {
1210
- rl.close();
1211
- }
1212
- }
1213
- async function askHidden(question) {
1214
- if (!input.isTTY || !output.isTTY)
1215
- return ask(question);
1216
- const rl = readline.createInterface({ input, output, terminal: true });
1217
- rl.stdoutMuted = true;
1218
- const original = rl._writeToOutput;
1219
- rl._writeToOutput = function writeToOutput(value) {
1220
- if (rl.stdoutMuted && !/\n|\r/.test(value))
1221
- return;
1222
- return original.call(rl, value);
1223
- };
1224
- try {
1225
- const answer = await rl.question(question);
1226
- output.write('\n');
1227
- return answer;
1228
- }
1229
- finally {
1230
- rl.close();
1231
- }
1232
- }