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.
- package/README.md +96 -58
- package/crates/sks-core/Cargo.lock +1 -1
- package/crates/sks-core/Cargo.toml +1 -1
- package/dist/bin/fast-inline.js +5 -51
- package/dist/cli/command-manifest-lite.js +2 -1
- package/dist/cli/command-registry.js +2 -1
- package/dist/cli/global-mode-router.js +1 -1
- package/dist/cli/install-helpers-codex-lb-config.js +112 -914
- package/dist/cli/install-helpers-codex-lb-shared.js +3 -44
- package/dist/cli/install-helpers-install-support.js +4 -20
- package/dist/cli/install-helpers.js +36 -2716
- package/dist/cli/router.js +9 -9
- package/dist/commands/bridge-command-output.js +111 -0
- package/dist/commands/bridge.js +320 -0
- package/dist/commands/codex-app.js +39 -123
- package/dist/commands/doctor-helpers.js +380 -0
- package/dist/commands/doctor-profile.js +3 -0
- package/dist/commands/doctor.js +114 -873
- package/dist/commands/mad-sks.js +0 -4
- package/dist/config/skills-manifest.json +1 -1
- package/dist/core/agents/agent-effort-policy.js +11 -21
- package/dist/core/agents/agent-recursion-guard.js +26 -0
- package/dist/core/agents/agent-runner-codex-exec.js +7 -9
- package/dist/core/architecture-hardening/contracts/contracts.js +225 -161
- package/dist/core/architecture-hardening/state/state-service.js +49 -13
- package/dist/core/auto-review.js +15 -9
- package/dist/core/codex/codex-config-guard.js +8 -0
- package/dist/core/codex-adapter.js +8 -10
- package/dist/core/codex-app/codex-app-fast-ui-repair.js +7 -29
- package/dist/core/codex-app/codex-app-launcher.js +10 -12
- package/dist/core/codex-app/codex-app-restart.js +10 -12
- package/dist/core/codex-app/menubar/constants.js +2 -5
- package/dist/core/codex-app/menubar/global-install.js +3 -2
- package/dist/core/codex-app/menubar/installer/result.js +23 -0
- package/dist/core/codex-app/menubar/installer/runtime.js +28 -0
- package/dist/core/codex-app/menubar/installer.js +5 -96
- package/dist/core/codex-app/menubar/migration.js +1 -42
- package/dist/core/codex-app/openrouter-provider.js +0 -78
- package/dist/core/codex-app.js +97 -360
- package/dist/core/codex-control/codex-app-server-runtime-env.js +8 -28
- package/dist/core/codex-control/codex-current-image-path-real-probe.js +2 -3
- package/dist/core/codex-control/codex-current-web-search-probe.js +2 -3
- package/dist/core/codex-control/codex-sdk-adapter.js +5 -48
- package/dist/core/codex-control/codex-task-runner.js +16 -60
- package/dist/core/codex-control/desktop-bridge-launch-guard.js +227 -0
- package/dist/core/codex-exec-output-schema.js +11 -13
- package/dist/core/codex-lb/bridge-contracts.js +2 -0
- package/dist/core/codex-lb/bridge-runtime-validation/capability.js +104 -0
- package/dist/core/codex-lb/bridge-runtime-validation/catalog.js +52 -0
- package/dist/core/codex-lb/bridge-runtime-validation/shared.js +109 -0
- package/dist/core/codex-lb/bridge-runtime-validation/status.js +250 -0
- package/dist/core/codex-lb/bridge-runtime-validation.js +106 -0
- package/dist/core/codex-lb/capability-runner.js +505 -201
- package/dist/core/codex-lb/codex-lb-env.js +179 -12
- package/dist/core/codex-lb/combined-catalog/builder.js +86 -0
- package/dist/core/codex-lb/combined-catalog/contracts.js +5 -0
- package/dist/core/codex-lb/combined-catalog/normalize.js +170 -0
- package/dist/core/codex-lb/combined-catalog/persistence.js +207 -0
- package/dist/core/codex-lb/combined-catalog/shared.js +12 -0
- package/dist/core/codex-lb/combined-catalog/storage.js +171 -0
- package/dist/core/codex-lb/combined-catalog.js +12 -0
- package/dist/core/codex-lb/desktop-bridge/client.js +4 -1
- package/dist/core/codex-lb/desktop-bridge/header-policy.js +48 -63
- package/dist/core/codex-lb/desktop-bridge/http-forward.js +115 -83
- package/dist/core/codex-lb/desktop-bridge/launchd.js +20 -13
- package/dist/core/codex-lb/desktop-bridge/location-rewrite.js +4 -1
- package/dist/core/codex-lb/desktop-bridge/security.js +381 -267
- package/dist/core/codex-lb/desktop-bridge/server.js +148 -19
- package/dist/core/codex-lb/desktop-bridge/state.js +56 -70
- package/dist/core/codex-lb/desktop-bridge/types.js +6 -1
- package/dist/core/codex-lb/desktop-bridge/websocket-forward.js +281 -106
- package/dist/core/codex-lb/desktop-bridge-migration/historical-config.js +245 -0
- package/dist/core/codex-lb/desktop-bridge-migration/historical-toml.js +56 -0
- package/dist/core/codex-lb/desktop-bridge-migration/metadata.js +73 -0
- package/dist/core/codex-lb/desktop-bridge-migration/receipt.js +52 -0
- package/dist/core/codex-lb/desktop-bridge-migration/retired-runtime-cleanup.js +106 -0
- package/dist/core/codex-lb/desktop-bridge-migration/types.js +1 -0
- package/dist/core/codex-lb/desktop-bridge-migration.js +238 -0
- package/dist/core/codex-lb/desktop-controller-v3/catalog.js +257 -0
- package/dist/core/codex-lb/desktop-controller-v3/diagnostics.js +62 -0
- package/dist/core/codex-lb/desktop-controller-v3/lifecycle-commands.js +203 -0
- package/dist/core/codex-lb/desktop-controller-v3/live-probes.js +293 -0
- package/dist/core/codex-lb/desktop-controller-v3/preflight-probes.js +144 -0
- package/dist/core/codex-lb/desktop-controller-v3/provider-commands.js +182 -0
- package/dist/core/codex-lb/desktop-controller-v3/shared.js +279 -0
- package/dist/core/codex-lb/desktop-controller-v3/status.js +269 -0
- package/dist/core/codex-lb/desktop-controller-v3/types.js +1 -0
- package/dist/core/codex-lb/desktop-controller-v3/verification.js +89 -0
- package/dist/core/codex-lb/desktop-controller-v3.js +67 -0
- package/dist/core/codex-lb/desktop-controller.js +2 -1730
- package/dist/core/codex-lb/desktop-service.js +462 -627
- package/dist/core/codex-lb/migration-receipt.js +560 -118
- package/dist/core/codex-lb/probes/auxiliary-surfaces-probe.js +37 -53
- package/dist/core/codex-lb/probes/bridge-probe.js +125 -64
- package/dist/core/codex-lb/probes/catalog-probe.js +36 -136
- package/dist/core/codex-lb/probes/computer-use-probe.js +63 -39
- package/dist/core/codex-lb/probes/image-generation-probe.js +98 -41
- package/dist/core/codex-lb/probes/probe-evidence.js +32 -33
- package/dist/core/codex-lb/probes/voice-realtime-probe.js +69 -43
- package/dist/core/codex-lb/provider-credentials/configuration.js +127 -0
- package/dist/core/codex-lb/provider-credentials/locks.js +11 -0
- package/dist/core/codex-lb/provider-credentials/private-snapshot.js +28 -0
- package/dist/core/codex-lb/provider-credentials/removal.js +33 -0
- package/dist/core/codex-lb/provider-credentials/resolution.js +59 -0
- package/dist/core/codex-lb/provider-credentials/runtime.js +55 -0
- package/dist/core/codex-lb/provider-credentials/types.js +1 -0
- package/dist/core/codex-lb/provider-credentials/validation-store.js +137 -0
- package/dist/core/codex-lb/provider-credentials.js +5 -0
- package/dist/core/codex-lb/provider-registry.js +323 -0
- package/dist/core/codex-lb/provider-route-policy.js +118 -0
- package/dist/core/codex-lb/request-route-resolver.js +172 -0
- package/dist/core/codex-lb/route-index.js +148 -0
- package/dist/core/codex-lb/trusted-deep-evidence.js +158 -286
- package/dist/core/commands/basic-cli.js +1 -1
- package/dist/core/commands/check-command.js +3 -10
- package/dist/core/commands/gate-result-contract.js +10 -14
- package/dist/core/commands/intent-normalization/normalizer.js +1 -1
- package/dist/core/commands/mad-sks-command.js +2 -6
- package/dist/core/commands/release-command.js +11 -1
- package/dist/core/commands/telegram-command.js +46 -6
- package/dist/core/doctor/doctor-readiness-matrix.js +9 -7
- package/dist/core/doctor/skill-legacy-surface.js +5 -5
- package/dist/core/evidence/v2/evidence-key.js +30 -3
- package/dist/core/feature-fixtures.js +8 -1
- package/dist/core/feature-registry.js +3 -2
- package/dist/core/hooks-runtime/stop-finalization.js +11 -1
- package/dist/core/hooks-runtime/subagent-context.js +15 -1
- package/dist/core/hooks-runtime/subagent-skill-availability-contract.js +1 -1
- package/dist/core/hooks-runtime/tool-output-quarantine.js +1 -1
- package/dist/core/hooks-runtime.js +73 -87
- package/dist/core/image-ux-review/imagegen-adapter.js +108 -94
- package/dist/core/image-ux-review/real-callout-extractor.js +144 -14
- package/dist/core/imagegen/desktop-bridge-imagegen-target.js +77 -0
- package/dist/core/imagegen/imagegen-capability.js +43 -151
- package/dist/core/init/skills/filesystem.js +89 -0
- package/dist/core/init/skills/inventory.js +97 -0
- package/dist/core/init/skills/manifest.js +151 -0
- package/dist/core/init/skills.js +5 -325
- package/dist/core/init.js +0 -63
- package/dist/core/install/installed-package-smoke.js +1 -1
- package/dist/core/managed-assets/managed-assets-manifest.js +0 -1
- package/dist/core/policy/latest-version-guidance.js +15 -2
- package/dist/core/preflight/parallel-preflight-engine.js +27 -51
- package/dist/core/provider/provider-badge.js +9 -4
- package/dist/core/provider/provider-context.js +57 -107
- package/dist/core/providers/openrouter/openrouter-account.js +3 -1
- package/dist/core/providers/openrouter/openrouter-secret-store.js +91 -22
- package/dist/core/release/desktop-bridge-release-evidence.js +457 -0
- package/dist/core/release/gate-manifest.js +0 -1
- package/dist/core/release/main-push-guard.js +13 -0
- package/dist/core/release/main-push-receipt.js +11 -0
- package/dist/core/release/physical-release-gates.js +664 -61
- package/dist/core/release/publish-preflight.js +3 -3
- package/dist/core/release/release-gate-batch-runner.js +19 -6
- package/dist/core/release/release-gate-dag.js +33 -6
- package/dist/core/release/release-gate-node.js +1 -3
- package/dist/core/release/release-gate-output-contract.js +55 -0
- package/dist/core/release/release-pack-contract.js +1 -1
- package/dist/core/release/release-pack-receipt.js +209 -8
- package/dist/core/release/release-real-contract.js +1 -1
- package/dist/core/release/stage-publish.js +106 -28
- package/dist/core/retention/temp-lease.js +204 -0
- package/dist/core/retention.js +18 -195
- package/dist/core/routes.js +1 -2
- package/dist/core/safety/intent-contract/intent-contract.js +3 -3
- package/dist/core/subagents/naruto-host-credentials.js +6 -1
- package/dist/core/subagents/official-subagent-config.js +27 -9
- package/dist/core/subagents/official-subagent-runner.js +14 -31
- package/dist/core/subagents/wave-lifecycle.js +36 -8
- package/dist/core/subagents/wave-parent-guidance.js +2 -1
- package/dist/core/telegram/doctor.js +2 -2
- package/dist/core/telegram/liveness.js +10 -4
- package/dist/core/triwiki/context-graph/compiler/index.js +18 -18
- package/dist/core/update/update-migration-state/fast-mode-config.js +172 -0
- package/dist/core/update/update-migration-state/session-state-split.js +247 -0
- package/dist/core/update/update-migration-state/simple-stages.js +46 -0
- package/dist/core/update/update-migration-state.js +4 -481
- package/dist/core/version.js +1 -1
- package/dist/native/sks-menubar/Sources/OperationCoordinator.swift +28 -4
- package/dist/native/sks-menubar/Sources/OperationModels.swift +112 -2
- package/dist/native/sks-menubar/Sources/ProviderRouteExplanation.swift +21 -0
- package/dist/native/sks-menubar/Sources/ProvidersBridgeCatalog.swift +140 -0
- package/dist/native/sks-menubar/Sources/ProvidersOpenRouter.swift +107 -470
- package/dist/native/sks-menubar/Sources/ProvidersReliability.swift +27 -197
- package/dist/native/sks-menubar/Sources/ProvidersRoutingTruth.swift +335 -269
- package/dist/native/sks-menubar/Sources/ProvidersViewController.swift +233 -437
- package/dist/native/sks-menubar/Sources/RemoteCodingViewController.swift +16 -7
- package/dist/native/sks-menubar/Sources/SecureProcessEnvelope.swift +39 -9
- package/dist/native/sks-menubar/Sources/TelegramSupport.swift +56 -0
- package/dist/scripts/canonical-test-runner.js +7 -1
- package/dist/scripts/check-runtime-schemas.js +7 -2
- package/dist/scripts/codex-sdk-real-smoke-check.js +3 -1
- package/dist/scripts/desktop-bridge-capabilities-check.js +123 -0
- package/dist/scripts/{codex-lb-desktop-bridge-latency-check.js → desktop-bridge-latency-check.js} +61 -16
- package/dist/scripts/desktop-bridge-real-evidence-check.js +64 -0
- package/dist/scripts/{codex-lb-desktop-bridge-check.js → desktop-bridge-transport-check.js} +92 -155
- package/dist/scripts/desktop-bridge-transport-client.js +116 -0
- package/dist/scripts/desktop-bridge-unification-check.js +276 -0
- package/dist/scripts/doctor-fixes-codex-app-fast-ui-check.js +12 -8
- package/dist/scripts/gate-policy-audit-check.js +52 -2
- package/dist/scripts/provider-badge-context-check.js +55 -12
- package/dist/scripts/publish-preflight.js +1 -2
- package/dist/scripts/release-affected-selector-check.js +1 -2
- package/dist/scripts/release-aggressive-resource-governor-check.js +1 -1
- package/dist/scripts/release-cache-glob-hashing-check.js +1 -0
- package/dist/scripts/release-cache-version-neutral-fixture-check.js +1 -0
- package/dist/scripts/release-full-parallelism-blackbox.js +1 -1
- package/dist/scripts/release-gate-batch-runner-check.js +9 -0
- package/dist/scripts/release-gate-dag-runner-check.js +6 -0
- package/dist/scripts/release-gate-dag-runner.js +4 -2
- package/dist/scripts/release-metadata-check.js +16 -3
- package/dist/scripts/release-pack-receipt.js +29 -6
- package/dist/scripts/release-physical-gates-check.js +39 -0
- package/dist/scripts/release-real-check.js +7 -5
- package/package.json +6 -8
- package/release-gates.v2.json +156 -157
- package/runtime-required-scripts.json +11 -11
- package/schemas/codex/desktop-bridge-status-v3.schema.json +286 -0
- package/schemas/codex/desktop-capabilities-v3.schema.json +198 -0
- package/schemas/release/release-gate-node.schema.json +2 -3
- package/dist/cli/codex-lb-setup-warning-output.js +0 -17
- package/dist/cli/install-helpers-codex-lb-chain.js +0 -529
- package/dist/commands/codex-lb.js +0 -1232
- package/dist/core/architecture-hardening/migration/migration.js +0 -111
- package/dist/core/codex-app/auxiliary-oauth-policy.js +0 -36
- package/dist/core/codex-app/catalog-compat/catalog-service.js +0 -104
- package/dist/core/codex-app/child-policy/child-policy.js +0 -35
- package/dist/core/codex-app/desktop-routing-snapshot.js +0 -233
- package/dist/core/codex-app/glm-model-profile.js +0 -1
- package/dist/core/codex-app/glm-profile-installer.js +0 -191
- package/dist/core/codex-app/glm-profile-schema.js +0 -42
- package/dist/core/codex-app/multi-provider-router.js +0 -391
- package/dist/core/codex-app/openrouter-activate.js +0 -405
- package/dist/core/codex-app/openrouter-model-catalog.js +0 -217
- package/dist/core/codex-app/provider-child-policy.js +0 -64
- package/dist/core/codex-app/provider-mode.js +0 -91
- package/dist/core/codex-app/provider-session-policy.js +0 -85
- package/dist/core/codex-app/session-policy/session-pinning.js +0 -68
- package/dist/core/codex-control/codex-lb-launch-recovery.js +0 -319
- package/dist/core/codex-lb/codex-lb-setup.js +0 -293
- package/dist/core/codex-lb/codex-lb-tool-catalog.js +0 -456
- package/dist/core/codex-lb/codex-lb-tool-output-recovery.js +0 -290
- package/dist/core/codex-lb/desktop-center-credentials.js +0 -1083
- package/dist/core/codex-lb/desktop-mode.js +0 -32
- package/dist/core/codex-lb/desktop-real-evidence.js +0 -168
- package/dist/core/codex-lb/legacy-migration.js +0 -576
- package/dist/core/codex-lb/native-openai-transport/transport.js +0 -68
- package/dist/core/codex-lb/provider-routing/provider-router.js +0 -58
- package/dist/core/codex-lb/routing-truth.js +0 -327
- package/dist/core/imagegen/codex-lb-imagegen-target.js +0 -92
- package/dist/native/sks-menubar/Sources/ProvidersConnectTest.swift +0 -118
- package/dist/native/sks-menubar/Sources/ProvidersFastMode.swift +0 -17
- package/dist/native/sks-menubar/Sources/ProvidersMultiProvider.swift +0 -331
- package/dist/native/sks-menubar/Sources/ProvidersRoleModels.swift +0 -260
- package/dist/scripts/codex-lb-catalog-passthrough-check.js +0 -120
- package/dist/scripts/codex-lb-desktop-auth-invariant-check.js +0 -169
- package/dist/scripts/codex-lb-desktop-capabilities-check.js +0 -287
- package/dist/scripts/codex-lb-desktop-real-evidence-check.js +0 -123
- package/dist/scripts/codex-lb-fast-mode-truth-check.js +0 -114
- package/dist/scripts/codex-lb-fast-ui-preservation-check.js +0 -152
- 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
|
-
}
|