sneakoscope 7.3.0 → 7.6.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +129 -10
- package/crates/sks-core/Cargo.lock +1 -1
- package/crates/sks-core/Cargo.toml +1 -1
- package/dist/cli/codex-app-command.js +1 -1
- package/dist/cli/command-manifest-lite.js +4 -1
- package/dist/cli/command-registry.js +2 -0
- package/dist/cli/install-helpers-codex-lb-chain.js +42 -0
- package/dist/cli/install-helpers-codex-lb-config.js +114 -9
- package/dist/cli/install-helpers-install-support.js +6 -16
- package/dist/cli/install-helpers.js +788 -600
- package/dist/cli/router.js +30 -2
- package/dist/commands/codex-app.js +37 -1
- package/dist/commands/codex-lb.js +491 -300
- package/dist/config/skills-manifest.json +57 -71
- package/dist/core/align/align-route.js +127 -0
- package/dist/core/codex-app/codex-app-fast-ui-repair.js +8 -4
- package/dist/core/codex-app/codex-app-restart.js +83 -0
- package/dist/core/codex-app/codex-app-ui-state-snapshot.js +8 -4
- package/dist/core/codex-app/desktop-routing-snapshot.js +1 -1
- package/dist/core/codex-app/menubar/constants.js +5 -0
- package/dist/core/codex-app/menubar/generation-transaction-journal.js +1 -3
- package/dist/core/codex-app/menubar/installer.js +18 -0
- package/dist/core/codex-app/multi-provider-router.js +22 -10
- package/dist/core/codex-app/openrouter-activate.js +26 -1
- package/dist/core/codex-app.js +118 -26
- package/dist/core/codex-control/codex-app-server-runtime-env.js +86 -0
- package/dist/core/codex-control/codex-app-server-v2-client.js +78 -8
- package/dist/core/codex-control/codex-task-runner.js +2 -2
- package/dist/core/codex-lb/capability-runner.js +204 -0
- package/dist/core/codex-lb/capability-types.js +1 -0
- package/dist/core/codex-lb/codex-lb-env.js +9 -13
- package/dist/core/codex-lb/codex-lb-setup.js +45 -8
- package/dist/core/codex-lb/codex-lb-tool-catalog.js +52 -74
- package/dist/core/codex-lb/codex-lb-tool-output-recovery.js +1 -1
- package/dist/core/codex-lb/desktop-auth-invariant.js +185 -0
- package/dist/core/codex-lb/desktop-bridge/client.js +34 -0
- package/dist/core/codex-lb/desktop-bridge/header-policy.js +106 -0
- package/dist/core/codex-lb/desktop-bridge/http-forward.js +101 -0
- package/dist/core/codex-lb/desktop-bridge/index.js +10 -0
- package/dist/core/codex-lb/desktop-bridge/launchd.js +81 -0
- package/dist/core/codex-lb/desktop-bridge/location-rewrite.js +27 -0
- package/dist/core/codex-lb/desktop-bridge/security.js +274 -0
- package/dist/core/codex-lb/desktop-bridge/server.js +179 -0
- package/dist/core/codex-lb/desktop-bridge/state.js +119 -0
- package/dist/core/codex-lb/desktop-bridge/types.js +16 -0
- package/dist/core/codex-lb/desktop-bridge/websocket-forward.js +151 -0
- package/dist/core/codex-lb/desktop-center-credentials.js +189 -0
- package/dist/core/codex-lb/desktop-controller.js +1410 -0
- package/dist/core/codex-lb/desktop-mode.js +32 -0
- package/dist/core/codex-lb/desktop-real-evidence.js +168 -0
- package/dist/core/codex-lb/desktop-service.js +613 -0
- package/dist/core/codex-lb/legacy-migration.js +575 -0
- package/dist/core/codex-lb/migration-receipt.js +246 -0
- package/dist/core/codex-lb/probes/auxiliary-surfaces-probe.js +60 -0
- package/dist/core/codex-lb/probes/bridge-probe.js +75 -0
- package/dist/core/codex-lb/probes/catalog-probe.js +128 -0
- package/dist/core/codex-lb/probes/computer-use-probe.js +50 -0
- package/dist/core/codex-lb/probes/image-generation-probe.js +47 -0
- package/dist/core/codex-lb/probes/probe-evidence.js +39 -0
- package/dist/core/codex-lb/probes/voice-realtime-probe.js +44 -0
- package/dist/core/codex-lb/trusted-deep-evidence.js +403 -0
- package/dist/core/codex-native/core-skill-manifest.js +22 -6
- package/dist/core/codex-runtime/codex-desktop-config-policy.js +2 -1
- package/dist/core/commands/align-command.js +220 -0
- package/dist/core/commands/image-ux-review-command.js +280 -68
- package/dist/core/commands/naruto-command.js +257 -8
- package/dist/core/commands/ppt-command.js +2 -2
- package/dist/core/commands/telegram-command.js +402 -34
- package/dist/core/commands/triwiki-command.js +11 -1
- package/dist/core/commands/triwiki-graph-command.js +160 -0
- package/dist/core/commands/wiki-command.js +100 -20
- package/dist/core/doctor/skill-legacy-surface.js +1 -3
- package/dist/core/errors/message.js +3 -0
- package/dist/core/evidence/evidence-freshness.js +14 -0
- package/dist/core/feature-fixtures.js +9 -1
- package/dist/core/feature-registry.js +5 -3
- package/dist/core/fsx.js +7 -3
- package/dist/core/hooks-runtime/codex-commit-hooks-selftest.js +82 -0
- package/dist/core/hooks-runtime/context-graph-freshness-preflight.js +113 -0
- package/dist/core/hooks-runtime/hook-context.js +15 -2
- package/dist/core/hooks-runtime/managed-skill-generation-heal.js +46 -0
- package/dist/core/hooks-runtime/naruto-terminal-finalization.js +1 -0
- package/dist/core/hooks-runtime/official-subagent-lifecycle.js +1 -1
- package/dist/core/hooks-runtime/tool-output-quarantine.js +1 -1
- package/dist/core/hooks-runtime.js +33 -89
- package/dist/core/image-ux-review/callout-extraction.js +6 -0
- package/dist/core/image-ux-review/imagegen-adapter.js +64 -23
- package/dist/core/image-ux-review/real-callout-extractor.js +1 -0
- package/dist/core/image-ux-review.js +230 -12
- package/dist/core/imagegen/codex-lb-imagegen-target.js +21 -7
- package/dist/core/imagegen/imagegen-capability.js +10 -4
- package/dist/core/imagegen/require-imagegen.js +29 -5
- package/dist/core/init/skills.js +25 -13
- package/dist/core/init.js +1 -1
- package/dist/core/install/installed-package-smoke.js +157 -4
- package/dist/core/managed-assets/managed-assets-manifest.js +2 -1
- package/dist/core/managed-path-safety.js +8 -10
- package/dist/core/mcp-config/backup.js +2 -4
- package/dist/core/mcp-config/config-reader.js +2 -4
- package/dist/core/mcp-config/scope.js +3 -5
- package/dist/core/naruto/context-graph-advisor-scope.js +242 -0
- package/dist/core/naruto/context-graph-advisor.js +0 -0
- package/dist/core/perf/release-latency-slo.js +12 -6
- package/dist/core/pipeline-internals/runtime-core.js +78 -0
- package/dist/core/pipeline-internals/runtime-gates.js +5 -2
- package/dist/core/policy/latest-version-guidance.js +113 -0
- package/dist/core/ppt.js +8 -8
- package/dist/core/preflight/parallel-preflight-engine.js +1 -1
- package/dist/core/proof/auto-finalize.js +98 -6
- package/dist/core/proof/route-proof-gate.js +12 -1
- package/dist/core/proof/route-proof-policy.js +8 -8
- package/dist/core/release/gate-manifest.js +32 -1
- package/dist/core/release/npm-stage-contract.js +21 -0
- package/dist/core/release/package-size-budget.js +2 -2
- package/dist/core/release/release-gate-contract.js +5 -0
- package/dist/core/release/release-proof-io.js +1 -3
- package/dist/core/release/release-real-contract.js +5 -4
- package/dist/core/release/release-stamp-proof.js +1 -3
- package/dist/core/release/stage-publish.js +27 -0
- package/dist/core/remote/audit-idempotency.js +50 -18
- package/dist/core/remote/codex-public-activity.js +283 -0
- package/dist/core/remote/index.js +1 -0
- package/dist/core/remote/ssh-worker-client.js +4 -1
- package/dist/core/remote/worker.js +206 -27
- package/dist/core/research/research-adversarial-review.js +1 -3
- package/dist/core/research/research-claim-synthesizer.js +1 -3
- package/dist/core/research/research-falsification-runner.js +1 -3
- package/dist/core/research/research-source-evidence.js +1 -3
- package/dist/core/responses-stream.js +65 -19
- package/dist/core/routes/constants.js +1 -1
- package/dist/core/routes/design-policy.js +7 -2
- package/dist/core/routes/dollar-manifest-lite.js +2 -4
- package/dist/core/routes/evidence.js +1 -1
- package/dist/core/routes.js +30 -10
- package/dist/core/safety/command-contract/contracts.js +2 -0
- package/dist/core/safety/command-contract/types.js +1 -1
- package/dist/core/search/context-graph-seeds.js +205 -0
- package/dist/core/search/context.js +0 -0
- package/dist/core/search/provider.js +2 -2
- package/dist/core/secret-redaction.js +6 -0
- package/dist/core/subagents/naruto-help-contract.js +2 -1
- package/dist/core/subagents/naruto-host-credentials.js +161 -0
- package/dist/core/subagents/official-subagent-preparation.js +4 -1
- package/dist/core/subagents/official-subagent-prompt.js +44 -2
- package/dist/core/subagents/official-subagent-runner.js +26 -8
- package/dist/core/subagents/triwiki-attention.js +135 -123
- package/dist/core/telegram/bot-api.js +85 -10
- package/dist/core/telegram/center-snapshot.js +718 -0
- package/dist/core/telegram/config.js +158 -31
- package/dist/core/telegram/hub.js +288 -33
- package/dist/core/telegram/index.js +2 -0
- package/dist/core/telegram/ingress-spool.js +419 -0
- package/dist/core/telegram/ledgers.js +188 -29
- package/dist/core/telegram/messages.js +26 -6
- package/dist/core/telegram/owner-lock.js +10 -7
- package/dist/core/telegram/runtime-projection.js +38 -3
- package/dist/core/telegram/runtime.js +298 -63
- package/dist/core/telegram/service.js +137 -8
- package/dist/core/telegram/setup.js +291 -73
- package/dist/core/text/strings.js +3 -0
- package/dist/core/triwiki/code-pack.js +12 -120
- package/dist/core/triwiki/context-graph/compiler/cache-key.js +277 -0
- package/dist/core/triwiki/context-graph/compiler/extract.js +104 -0
- package/dist/core/triwiki/context-graph/compiler/freshness.js +108 -0
- package/dist/core/triwiki/context-graph/compiler/index.js +237 -0
- package/dist/core/triwiki/context-graph/compiler/merge.js +0 -0
- package/dist/core/triwiki/context-graph/compiler/serialize.js +115 -0
- package/dist/core/triwiki/context-graph/contracts.js +236 -0
- package/dist/core/triwiki/context-graph/extractors/code/builders.js +150 -0
- package/dist/core/triwiki/context-graph/extractors/code/declarations.js +161 -0
- package/dist/core/triwiki/context-graph/extractors/code/index.js +265 -0
- package/dist/core/triwiki/context-graph/extractors/code/inventory.js +237 -0
- package/dist/core/triwiki/context-graph/extractors/code/module-graph.js +252 -0
- package/dist/core/triwiki/context-graph/extractors/code/modules.js +79 -0
- package/dist/core/triwiki/context-graph/extractors/code/references.js +184 -0
- package/dist/core/triwiki/context-graph/extractors/code/selection.js +100 -0
- package/dist/core/triwiki/context-graph/extractors/code/ts-config.js +161 -0
- package/dist/core/triwiki/context-graph/extractors/code/types.js +18 -0
- package/dist/core/triwiki/context-graph/extractors/evidence/claims.js +289 -0
- package/dist/core/triwiki/context-graph/extractors/evidence/index.js +54 -0
- package/dist/core/triwiki/context-graph/extractors/evidence/proof-index.js +213 -0
- package/dist/core/triwiki/context-graph/extractors/evidence/proofs.js +266 -0
- package/dist/core/triwiki/context-graph/extractors/evidence/redaction.js +177 -0
- package/dist/core/triwiki/context-graph/extractors/evidence/shared.js +0 -0
- package/dist/core/triwiki/context-graph/extractors/evidence/sources.js +154 -0
- package/dist/core/triwiki/context-graph/extractors/index.js +7 -0
- package/dist/core/triwiki/context-graph/extractors/topology/commands.js +207 -0
- package/dist/core/triwiki/context-graph/extractors/topology/gate-edges.js +201 -0
- package/dist/core/triwiki/context-graph/extractors/topology/gates.js +182 -0
- package/dist/core/triwiki/context-graph/extractors/topology/globs.js +124 -0
- package/dist/core/triwiki/context-graph/extractors/topology/index.js +92 -0
- package/dist/core/triwiki/context-graph/extractors/topology/routes.js +135 -0
- package/dist/core/triwiki/context-graph/extractors/topology/shared.js +215 -0
- package/dist/core/triwiki/context-graph/graph-index.js +143 -0
- package/dist/core/triwiki/context-graph/ids.js +0 -0
- package/dist/core/triwiki/context-graph/lint/index.js +0 -0
- package/dist/core/triwiki/context-graph/lint/rules.js +232 -0
- package/dist/core/triwiki/context-graph/lint/warnings.js +93 -0
- package/dist/core/triwiki/context-graph/paths.js +116 -0
- package/dist/core/triwiki/context-graph/profiles.js +78 -0
- package/dist/core/triwiki/context-graph/projections/anchors.js +91 -0
- package/dist/core/triwiki/context-graph/projections/attention.js +58 -0
- package/dist/core/triwiki/context-graph/projections/code-pack-workspace.js +62 -0
- package/dist/core/triwiki/context-graph/projections/code-pack.js +144 -0
- package/dist/core/triwiki/context-graph/projections/index.js +7 -0
- package/dist/core/triwiki/context-graph/projections/module-view.js +140 -0
- package/dist/core/triwiki/context-graph/projections/node-summary.js +118 -0
- package/dist/core/triwiki/context-graph/projections/pack-contract.js +6 -0
- package/dist/core/triwiki/context-graph/query/explain.js +0 -0
- package/dist/core/triwiki/context-graph/query/index.js +178 -0
- package/dist/core/triwiki/context-graph/query/load.js +116 -0
- package/dist/core/triwiki/context-graph/query/pack.js +117 -0
- package/dist/core/triwiki/context-graph/query/rank.js +142 -0
- package/dist/core/triwiki/context-graph/query/ranking-config.js +64 -0
- package/dist/core/triwiki/context-graph/query/seeds.js +241 -0
- package/dist/core/triwiki/context-graph/query/snapshot-cache.js +72 -0
- package/dist/core/triwiki/context-graph/query/traverse.js +154 -0
- package/dist/core/triwiki/context-graph/query-types.js +29 -0
- package/dist/core/triwiki/context-graph/store/compile-lock.js +21 -0
- package/dist/core/triwiki/context-graph/store/event-log.js +48 -0
- package/dist/core/triwiki/context-graph/store/fragment-cache.js +85 -0
- package/dist/core/triwiki/context-graph/store/graph-status.js +85 -0
- package/dist/core/triwiki/context-graph/store/snapshot-store.js +155 -0
- package/dist/core/triwiki/triwiki-proof-bank-index-repair.js +115 -0
- package/dist/core/triwiki/triwiki-proof-bank-index-store.js +290 -0
- package/dist/core/triwiki/triwiki-proof-bank-index.js +126 -0
- package/dist/core/triwiki/triwiki-proof-bank.js +7 -1
- package/dist/core/verification/context-graph-affected.js +271 -0
- package/dist/core/version.js +1 -1
- package/dist/native/sks-menubar/Sources/AlertFactory.swift +11 -3
- package/dist/native/sks-menubar/Sources/AppDelegate.swift +9 -0
- package/dist/native/sks-menubar/Sources/ControlCenterWindowController.swift +25 -3
- package/dist/native/sks-menubar/Sources/ControlKit.swift +19 -8
- package/dist/native/sks-menubar/Sources/DiagnosticsViewController.swift +1 -2
- package/dist/native/sks-menubar/Sources/MCPServersViewController.swift +45 -17
- package/dist/native/sks-menubar/Sources/OverviewSummary.swift +162 -0
- package/dist/native/sks-menubar/Sources/OverviewViewController.swift +136 -190
- package/dist/native/sks-menubar/Sources/ProcessClient.swift +107 -11
- package/dist/native/sks-menubar/Sources/ProvidersMultiProvider.swift +5 -1
- package/dist/native/sks-menubar/Sources/ProvidersOpenRouter.swift +16 -4
- package/dist/native/sks-menubar/Sources/ProvidersRoleModels.swift +4 -1
- package/dist/native/sks-menubar/Sources/ProvidersRoutingTruth.swift +131 -0
- package/dist/native/sks-menubar/Sources/ProvidersViewController.swift +288 -341
- package/dist/native/sks-menubar/Sources/RemoteTelegramCenterState.swift +447 -0
- package/dist/native/sks-menubar/Sources/RemoteTelegramRendering.swift +484 -0
- package/dist/native/sks-menubar/Sources/RemoteTelegramViewController.swift +364 -115
- package/dist/native/sks-menubar/Sources/SettingsViewController.swift +73 -12
- package/dist/native/sks-menubar/Sources/SidebarItem.swift +3 -3
- package/dist/native/sks-menubar/Sources/StatusItemController.swift +13 -13
- package/dist/native/sks-menubar/Sources/TelegramHubSupervisor.swift +469 -0
- package/dist/native/sks-menubar/Sources/UpdatesViewController.swift +1 -6
- package/dist/native/sks-menubar/Tests/AppRuntimeTestSupport.swift +12 -0
- package/dist/native/sks-menubar/Tests/NativeTelegramRegressionRunner.swift +55 -0
- package/dist/native/sks-menubar/Tests/ProcessClientTests.swift +33 -0
- package/dist/native/sks-menubar/Tests/ProvidersViewControllerTests.swift +142 -0
- package/dist/native/sks-menubar/Tests/RemoteTelegramCenterStateTests.swift +56 -0
- package/dist/native/sks-menubar/Tests/TelegramHubSupervisorTests.swift +55 -0
- package/dist/scripts/codex-lb-catalog-passthrough-check.js +120 -0
- package/dist/scripts/codex-lb-desktop-auth-invariant-check.js +169 -0
- package/dist/scripts/codex-lb-desktop-bridge-check.js +394 -0
- package/dist/scripts/codex-lb-desktop-bridge-latency-check.js +196 -0
- package/dist/scripts/codex-lb-desktop-capabilities-check.js +287 -0
- package/dist/scripts/codex-lb-desktop-real-evidence-check.js +123 -0
- package/dist/scripts/codex-lb-fast-mode-truth-check.js +10 -3
- package/dist/scripts/codex-lb-fast-ui-preservation-check.js +81 -40
- package/dist/scripts/codex-lb-gpt56-fast-profile-check.js +99 -37
- package/dist/scripts/context-graph-check.js +191 -0
- package/dist/scripts/doctor-fixes-codex-app-fast-ui-check.js +1 -1
- package/dist/scripts/gate-policy-audit-check.js +1 -1
- package/dist/scripts/helper-dedup-check.js +0 -2
- package/dist/scripts/installed-package-smoke-check.js +4 -1
- package/dist/scripts/latest-version-guidance-check.js +74 -0
- package/dist/scripts/release-metadata-check.js +21 -4
- package/dist/scripts/release-real-check.js +7 -0
- package/dist/scripts/ux-review-imagegen-blackbox-check.js +25 -1
- package/dist/scripts/ux-review-run-wires-imagegen-check.js +9 -1
- package/package.json +8 -3
- package/release-gates.v2.json +176 -1
- package/runtime-required-scripts.json +30 -0
- package/schemas/triwiki/context-graph.schema.json +119 -0
- package/dist/cli/install-helpers-codex-lb-selftest-chain.js +0 -112
- package/dist/cli/install-helpers-codex-lb-selftest.js +0 -481
- package/dist/core/triwiki/code-index-scanner.js +0 -309
|
@@ -0,0 +1,86 @@
|
|
|
1
|
+
import fsp from 'node:fs/promises';
|
|
2
|
+
import os from 'node:os';
|
|
3
|
+
import path from 'node:path';
|
|
4
|
+
import { readTopLevelTomlString } from '../codex-app/codex-model-catalog.js';
|
|
5
|
+
import { loadCodexLbEnv } from '../codex-lb/codex-lb-env.js';
|
|
6
|
+
export const CODEX_APP_SERVER_PROVIDER_CREDENTIALS_UNAVAILABLE = 'codex_app_server_provider_credentials_unavailable';
|
|
7
|
+
export const CODEX_APP_SERVER_CONFIG_READ_FAILED = 'codex_app_server_config_read_failed';
|
|
8
|
+
export class CodexAppServerRuntimeEnvError extends Error {
|
|
9
|
+
code;
|
|
10
|
+
constructor(code) {
|
|
11
|
+
super(code);
|
|
12
|
+
this.code = code;
|
|
13
|
+
this.name = 'CodexAppServerRuntimeEnvError';
|
|
14
|
+
}
|
|
15
|
+
}
|
|
16
|
+
export function codexAppServerExecutablePath(input) {
|
|
17
|
+
const home = path.resolve(input.home || process.env.HOME || os.homedir());
|
|
18
|
+
const candidates = [
|
|
19
|
+
path.dirname(path.resolve(input.nodeBin)),
|
|
20
|
+
path.join(home, '.local', 'bin'),
|
|
21
|
+
...(input.inheritedPath || '').split(path.delimiter),
|
|
22
|
+
'/opt/homebrew/bin',
|
|
23
|
+
'/usr/local/bin',
|
|
24
|
+
'/usr/bin',
|
|
25
|
+
'/bin',
|
|
26
|
+
'/usr/sbin',
|
|
27
|
+
'/sbin'
|
|
28
|
+
];
|
|
29
|
+
return [...new Set(candidates
|
|
30
|
+
.map((entry) => String(entry || '').trim())
|
|
31
|
+
.filter((entry) => path.isAbsolute(entry)))]
|
|
32
|
+
.join(path.delimiter);
|
|
33
|
+
}
|
|
34
|
+
export async function prepareCodexAppServerRuntimeEnv(input = {}) {
|
|
35
|
+
const sourceEnv = input.env || process.env;
|
|
36
|
+
const home = path.resolve(input.home || sourceEnv.HOME || os.homedir());
|
|
37
|
+
const codexHome = path.resolve(input.codexHome || sourceEnv.CODEX_HOME || path.join(home, '.codex'));
|
|
38
|
+
let configText = input.configText;
|
|
39
|
+
if (configText === undefined) {
|
|
40
|
+
const configPath = path.join(codexHome, 'config.toml');
|
|
41
|
+
const readConfigText = input.readConfigTextImpl
|
|
42
|
+
?? ((file) => fsp.readFile(file, 'utf8'));
|
|
43
|
+
try {
|
|
44
|
+
configText = await readConfigText(configPath);
|
|
45
|
+
}
|
|
46
|
+
catch (error) {
|
|
47
|
+
if (error?.code === 'ENOENT')
|
|
48
|
+
configText = '';
|
|
49
|
+
else
|
|
50
|
+
throw new CodexAppServerRuntimeEnvError(CODEX_APP_SERVER_CONFIG_READ_FAILED);
|
|
51
|
+
}
|
|
52
|
+
}
|
|
53
|
+
const selectedProvider = readTopLevelTomlString(configText, 'model_provider');
|
|
54
|
+
const env = {
|
|
55
|
+
...sourceEnv,
|
|
56
|
+
PATH: codexAppServerExecutablePath({
|
|
57
|
+
nodeBin: input.nodeBin || process.execPath,
|
|
58
|
+
home,
|
|
59
|
+
...(sourceEnv.PATH === undefined ? {} : { inheritedPath: sourceEnv.PATH })
|
|
60
|
+
})
|
|
61
|
+
};
|
|
62
|
+
if (selectedProvider !== 'codex-lb') {
|
|
63
|
+
delete env.CODEX_LB_API_KEY;
|
|
64
|
+
delete env.CODEX_LB_BASE_URL;
|
|
65
|
+
return env;
|
|
66
|
+
}
|
|
67
|
+
const load = input.loadCodexLbEnvImpl || loadCodexLbEnv;
|
|
68
|
+
let loaded = null;
|
|
69
|
+
try {
|
|
70
|
+
loaded = await load({
|
|
71
|
+
home,
|
|
72
|
+
processEnv: {},
|
|
73
|
+
envPath: path.join(codexHome, 'sks-codex-lb.env'),
|
|
74
|
+
metadataPath: path.join(codexHome, 'sks-codex-lb.json')
|
|
75
|
+
});
|
|
76
|
+
}
|
|
77
|
+
catch {
|
|
78
|
+
throw new CodexAppServerRuntimeEnvError(CODEX_APP_SERVER_PROVIDER_CREDENTIALS_UNAVAILABLE);
|
|
79
|
+
}
|
|
80
|
+
if (!loaded?.configured || !loaded.secret_api_key || !loaded.base_url) {
|
|
81
|
+
throw new CodexAppServerRuntimeEnvError(CODEX_APP_SERVER_PROVIDER_CREDENTIALS_UNAVAILABLE);
|
|
82
|
+
}
|
|
83
|
+
env.CODEX_LB_API_KEY = loaded.secret_api_key;
|
|
84
|
+
env.CODEX_LB_BASE_URL = loaded.base_url;
|
|
85
|
+
return env;
|
|
86
|
+
}
|
|
@@ -1,18 +1,34 @@
|
|
|
1
1
|
import { spawn } from 'node:child_process';
|
|
2
2
|
import { nowIso, PACKAGE_VERSION } from '../fsx.js';
|
|
3
3
|
import { resolveCodexRuntime } from '../codex-runtime/resolve-codex-runtime.js';
|
|
4
|
+
export class CodexAppServerRequestError extends Error {
|
|
5
|
+
method;
|
|
6
|
+
kind;
|
|
7
|
+
rpcCode;
|
|
8
|
+
constructor(method, kind, message, rpcCode = null) {
|
|
9
|
+
super(message);
|
|
10
|
+
this.method = method;
|
|
11
|
+
this.kind = kind;
|
|
12
|
+
this.rpcCode = rpcCode;
|
|
13
|
+
this.name = 'CodexAppServerRequestError';
|
|
14
|
+
}
|
|
15
|
+
}
|
|
4
16
|
export class CodexAppServerV2Client {
|
|
5
17
|
command;
|
|
6
18
|
args;
|
|
7
19
|
env;
|
|
8
20
|
cwd;
|
|
9
21
|
timeoutMs;
|
|
22
|
+
maxFrameBytes;
|
|
23
|
+
maxNotifications;
|
|
24
|
+
maxNotificationBytes;
|
|
10
25
|
currentTimeProvider;
|
|
11
26
|
approvalPolicy;
|
|
12
27
|
child = null;
|
|
13
28
|
nextId = 1;
|
|
14
29
|
pending = new Map();
|
|
15
30
|
notifications = [];
|
|
31
|
+
notificationBytes = 0;
|
|
16
32
|
listeners = new Set();
|
|
17
33
|
stdoutBuffer = '';
|
|
18
34
|
stderr = '';
|
|
@@ -22,6 +38,9 @@ export class CodexAppServerV2Client {
|
|
|
22
38
|
this.env = options.env || process.env;
|
|
23
39
|
this.cwd = options.cwd || process.cwd();
|
|
24
40
|
this.timeoutMs = Number(options.timeoutMs || 20_000);
|
|
41
|
+
this.maxFrameBytes = Math.max(1_024, Math.min(32 * 1024 * 1024, options.maxFrameBytes ?? 8 * 1024 * 1024));
|
|
42
|
+
this.maxNotifications = Math.max(16, Math.min(8_192, options.maxNotifications ?? 2_048));
|
|
43
|
+
this.maxNotificationBytes = Math.max(1_024, Math.min(64 * 1024 * 1024, options.maxNotificationBytes ?? 4 * 1024 * 1024));
|
|
25
44
|
this.currentTimeProvider = options.currentTimeProvider || (() => new Date());
|
|
26
45
|
this.approvalPolicy = options.approvalPolicy || {};
|
|
27
46
|
}
|
|
@@ -57,6 +76,12 @@ export class CodexAppServerV2Client {
|
|
|
57
76
|
async readThread(threadId, includeTurns = false) {
|
|
58
77
|
return await this.request('thread/read', { threadId, includeTurns });
|
|
59
78
|
}
|
|
79
|
+
async listThreadTurns(threadId, params = {}) {
|
|
80
|
+
return await this.request('thread/turns/list', {
|
|
81
|
+
threadId,
|
|
82
|
+
...normalizeThreadListParams(params)
|
|
83
|
+
});
|
|
84
|
+
}
|
|
60
85
|
async startTurn(params = {}) {
|
|
61
86
|
return await this.request('turn/start', params);
|
|
62
87
|
}
|
|
@@ -131,9 +156,9 @@ export class CodexAppServerV2Client {
|
|
|
131
156
|
if (this.stderr.length > 64 * 1024)
|
|
132
157
|
this.stderr = this.stderr.slice(-64 * 1024);
|
|
133
158
|
});
|
|
134
|
-
this.child.on('error', (err) => this.rejectAll(err));
|
|
159
|
+
this.child.on('error', (err) => this.rejectAll(err, 'transport'));
|
|
135
160
|
this.child.on('close', (code, signal) => {
|
|
136
|
-
this.rejectAll(new Error(`Codex app-server exited before response (code ${code ?? signal ?? 'unknown'}). ${this.stderr.trim()}`.trim()));
|
|
161
|
+
this.rejectAll(new Error(`Codex app-server exited before response (code ${code ?? signal ?? 'unknown'}). ${this.stderr.trim()}`.trim()), 'process_exit');
|
|
137
162
|
});
|
|
138
163
|
}
|
|
139
164
|
request(method, params) {
|
|
@@ -143,7 +168,7 @@ export class CodexAppServerV2Client {
|
|
|
143
168
|
return new Promise((resolve, reject) => {
|
|
144
169
|
const timer = setTimeout(() => {
|
|
145
170
|
this.pending.delete(id);
|
|
146
|
-
reject(new
|
|
171
|
+
reject(new CodexAppServerRequestError(method, 'timeout', `Codex app-server request timed out: ${method}. ${this.stderr.trim()}`.trim()));
|
|
147
172
|
}, this.timeoutMs);
|
|
148
173
|
timer.unref?.();
|
|
149
174
|
this.pending.set(id, { method, resolve, reject, timer });
|
|
@@ -158,9 +183,17 @@ export class CodexAppServerV2Client {
|
|
|
158
183
|
this.stdoutBuffer += chunk.toString('utf8');
|
|
159
184
|
const lines = this.stdoutBuffer.split(/\r?\n/);
|
|
160
185
|
this.stdoutBuffer = lines.pop() || '';
|
|
186
|
+
if (Buffer.byteLength(this.stdoutBuffer, 'utf8') > this.maxFrameBytes) {
|
|
187
|
+
this.abortProtocol('codex_app_server_frame_too_large');
|
|
188
|
+
return;
|
|
189
|
+
}
|
|
161
190
|
for (const line of lines) {
|
|
162
191
|
if (!line.trim())
|
|
163
192
|
continue;
|
|
193
|
+
if (Buffer.byteLength(line, 'utf8') > this.maxFrameBytes) {
|
|
194
|
+
this.abortProtocol('codex_app_server_frame_too_large');
|
|
195
|
+
return;
|
|
196
|
+
}
|
|
164
197
|
let message;
|
|
165
198
|
try {
|
|
166
199
|
message = JSON.parse(line);
|
|
@@ -176,7 +209,18 @@ export class CodexAppServerV2Client {
|
|
|
176
209
|
}
|
|
177
210
|
else {
|
|
178
211
|
const event = { ...message, received_at: nowIso() };
|
|
179
|
-
|
|
212
|
+
const eventBytes = notificationByteLength(event);
|
|
213
|
+
if (eventBytes <= this.maxNotificationBytes) {
|
|
214
|
+
this.notifications.push(event);
|
|
215
|
+
this.notificationBytes += eventBytes;
|
|
216
|
+
while (this.notifications.length > this.maxNotifications
|
|
217
|
+
|| this.notificationBytes > this.maxNotificationBytes) {
|
|
218
|
+
const removed = this.notifications.shift();
|
|
219
|
+
if (!removed)
|
|
220
|
+
break;
|
|
221
|
+
this.notificationBytes = Math.max(0, this.notificationBytes - notificationByteLength(removed));
|
|
222
|
+
}
|
|
223
|
+
}
|
|
180
224
|
for (const listener of this.listeners) {
|
|
181
225
|
try {
|
|
182
226
|
listener(event);
|
|
@@ -247,15 +291,16 @@ export class CodexAppServerV2Client {
|
|
|
247
291
|
return;
|
|
248
292
|
this.pending.delete(id);
|
|
249
293
|
clearTimeout(pending.timer);
|
|
250
|
-
if (message.error)
|
|
251
|
-
pending.reject(new
|
|
294
|
+
if (message.error) {
|
|
295
|
+
pending.reject(new CodexAppServerRequestError(pending.method, 'rpc_rejection', jsonRpcErrorMessage(pending.method, message.error), jsonRpcErrorCode(message.error)));
|
|
296
|
+
}
|
|
252
297
|
else
|
|
253
298
|
pending.resolve(message.result);
|
|
254
299
|
}
|
|
255
|
-
rejectAll(err) {
|
|
300
|
+
rejectAll(err, kind) {
|
|
256
301
|
for (const [id, pending] of this.pending.entries()) {
|
|
257
302
|
clearTimeout(pending.timer);
|
|
258
|
-
pending.reject(err);
|
|
303
|
+
pending.reject(new CodexAppServerRequestError(pending.method, kind, err.message));
|
|
259
304
|
this.pending.delete(id);
|
|
260
305
|
}
|
|
261
306
|
}
|
|
@@ -270,6 +315,16 @@ export class CodexAppServerV2Client {
|
|
|
270
315
|
write(message) {
|
|
271
316
|
this.child?.stdin.write(`${JSON.stringify(message)}\n`);
|
|
272
317
|
}
|
|
318
|
+
abortProtocol(code) {
|
|
319
|
+
const child = this.child;
|
|
320
|
+
this.child = null;
|
|
321
|
+
this.stdoutBuffer = '';
|
|
322
|
+
this.rejectAll(new Error(code), 'protocol_overflow');
|
|
323
|
+
if (!child)
|
|
324
|
+
return;
|
|
325
|
+
child.stdin.end();
|
|
326
|
+
child.kill('SIGTERM');
|
|
327
|
+
}
|
|
273
328
|
}
|
|
274
329
|
export async function createCodexAppServerV2Client(options = {}) {
|
|
275
330
|
const runtime = await resolveCodexRuntime({
|
|
@@ -287,6 +342,12 @@ export async function createCodexAppServerV2Client(options = {}) {
|
|
|
287
342
|
clientOptions.env = options.env;
|
|
288
343
|
if (options.timeoutMs !== undefined)
|
|
289
344
|
clientOptions.timeoutMs = options.timeoutMs;
|
|
345
|
+
if (options.maxFrameBytes !== undefined)
|
|
346
|
+
clientOptions.maxFrameBytes = options.maxFrameBytes;
|
|
347
|
+
if (options.maxNotifications !== undefined)
|
|
348
|
+
clientOptions.maxNotifications = options.maxNotifications;
|
|
349
|
+
if (options.maxNotificationBytes !== undefined)
|
|
350
|
+
clientOptions.maxNotificationBytes = options.maxNotificationBytes;
|
|
290
351
|
if (options.currentTimeProvider !== undefined)
|
|
291
352
|
clientOptions.currentTimeProvider = options.currentTimeProvider;
|
|
292
353
|
if (options.approvalPolicy !== undefined)
|
|
@@ -317,6 +378,12 @@ function jsonRpcErrorMessage(method, error) {
|
|
|
317
378
|
return `${method}: ${String(error.message)}`;
|
|
318
379
|
return `${method}: ${JSON.stringify(error)}`;
|
|
319
380
|
}
|
|
381
|
+
function jsonRpcErrorCode(error) {
|
|
382
|
+
if (!error || typeof error !== 'object' || !('code' in error))
|
|
383
|
+
return null;
|
|
384
|
+
const code = Number(error.code);
|
|
385
|
+
return Number.isSafeInteger(code) ? code : null;
|
|
386
|
+
}
|
|
320
387
|
function isTurnCompletionEvent(event, threadId, turnId) {
|
|
321
388
|
if (String(event.method || '') !== 'turn/completed')
|
|
322
389
|
return false;
|
|
@@ -329,3 +396,6 @@ function isTurnCompletionEvent(event, threadId, turnId) {
|
|
|
329
396
|
return String(params.threadId || '') === threadId
|
|
330
397
|
&& (!turnId || String(completedTurn.id || params.turnId || '') === turnId);
|
|
331
398
|
}
|
|
399
|
+
function notificationByteLength(event) {
|
|
400
|
+
return Buffer.byteLength(JSON.stringify(event), 'utf8');
|
|
401
|
+
}
|
|
@@ -595,12 +595,12 @@ async function ensurePythonCodexLbConfig(env, config) {
|
|
|
595
595
|
'approval_policy = "never"',
|
|
596
596
|
'',
|
|
597
597
|
'[model_providers.codex-lb]',
|
|
598
|
-
'name = "
|
|
598
|
+
'name = "codex-lb"',
|
|
599
599
|
`base_url = ${tomlQuote(lbBaseUrl)}`,
|
|
600
600
|
'wire_api = "responses"',
|
|
601
601
|
'env_key = "CODEX_LB_API_KEY"',
|
|
602
602
|
'supports_websockets = true',
|
|
603
|
-
'requires_openai_auth =
|
|
603
|
+
'requires_openai_auth = false',
|
|
604
604
|
''
|
|
605
605
|
].join('\n');
|
|
606
606
|
const configPath = path.join(codexHome, 'config.toml');
|
|
@@ -0,0 +1,204 @@
|
|
|
1
|
+
import { runAuxiliarySurfacesProbe } from './probes/auxiliary-surfaces-probe.js';
|
|
2
|
+
import { runBridgeProbe, gatewayAuthTransportEvidence } from './probes/bridge-probe.js';
|
|
3
|
+
import { runCatalogProbe } from './probes/catalog-probe.js';
|
|
4
|
+
import { runComputerUseProbe } from './probes/computer-use-probe.js';
|
|
5
|
+
import { runImageGenerationProbe } from './probes/image-generation-probe.js';
|
|
6
|
+
import { probeEvidence } from './probes/probe-evidence.js';
|
|
7
|
+
import { runVoiceRealtimeProbe } from './probes/voice-realtime-probe.js';
|
|
8
|
+
import { CODEX_LB_DEEP_EVIDENCE_VALIDATION_SCHEMA } from './trusted-deep-evidence.js';
|
|
9
|
+
const REQUIRED_FOR_FULL = [
|
|
10
|
+
'gateway_auth_transport',
|
|
11
|
+
'provider_identity',
|
|
12
|
+
'bridge',
|
|
13
|
+
'catalog',
|
|
14
|
+
'model_picker',
|
|
15
|
+
'fast_mode',
|
|
16
|
+
'image_generation',
|
|
17
|
+
'computer_use',
|
|
18
|
+
'browser_use',
|
|
19
|
+
'voice_mode',
|
|
20
|
+
'plugins',
|
|
21
|
+
'auxiliary_surfaces'
|
|
22
|
+
];
|
|
23
|
+
export function runCodexLbDesktopCapabilityReport(input) {
|
|
24
|
+
const level = input.level || 'shallow';
|
|
25
|
+
const checkedAt = input.checkedAt || new Date().toISOString();
|
|
26
|
+
const manifest = input.manifest || null;
|
|
27
|
+
const catalog = runCatalogProbe({
|
|
28
|
+
mode: input.mode,
|
|
29
|
+
level,
|
|
30
|
+
checkedAt,
|
|
31
|
+
manifest,
|
|
32
|
+
...(input.catalog || {})
|
|
33
|
+
});
|
|
34
|
+
const providerIdentityBlockers = [
|
|
35
|
+
...(input.providerIdentity?.blockers || []),
|
|
36
|
+
...(input.providerIdentity?.requiresOauth === true && input.oauthPreserved !== true
|
|
37
|
+
? ['chatgpt_oauth_identity_not_preserved']
|
|
38
|
+
: [])
|
|
39
|
+
];
|
|
40
|
+
const providerIdentity = probeEvidence({
|
|
41
|
+
...(input.providerIdentity || {}),
|
|
42
|
+
blockers: providerIdentityBlockers,
|
|
43
|
+
evidence: {
|
|
44
|
+
...(input.providerIdentity?.evidence || {}),
|
|
45
|
+
oauth_required: input.providerIdentity?.requiresOauth === true,
|
|
46
|
+
oauth_preserved: input.oauthPreserved === true
|
|
47
|
+
}
|
|
48
|
+
}, checkedAt);
|
|
49
|
+
const bridge = runBridgeProbe({
|
|
50
|
+
mode: input.mode,
|
|
51
|
+
level,
|
|
52
|
+
checkedAt,
|
|
53
|
+
manifest,
|
|
54
|
+
...(input.bridge || {})
|
|
55
|
+
});
|
|
56
|
+
const reportWithoutOverall = {
|
|
57
|
+
schema: 'sks.codex-lb-desktop-capabilities.v2',
|
|
58
|
+
mode: input.mode,
|
|
59
|
+
configured: input.configured === true,
|
|
60
|
+
oauth_preserved: input.oauthPreserved === true,
|
|
61
|
+
gateway_auth_transport: gatewayAuthTransportEvidence({
|
|
62
|
+
checkedAt,
|
|
63
|
+
...(input.gatewayAuth || {})
|
|
64
|
+
}),
|
|
65
|
+
provider_identity: providerIdentity,
|
|
66
|
+
bridge,
|
|
67
|
+
catalog: catalog.catalog,
|
|
68
|
+
model_picker: catalog.model_picker,
|
|
69
|
+
fast_mode: catalog.fast_mode,
|
|
70
|
+
text_responses: probeEvidence(input.textResponses || {
|
|
71
|
+
skipped: true,
|
|
72
|
+
evidence: { reason: 'text_responses_probe_not_run' }
|
|
73
|
+
}, checkedAt),
|
|
74
|
+
image_generation: runImageGenerationProbe({
|
|
75
|
+
level,
|
|
76
|
+
checkedAt,
|
|
77
|
+
manifestRouteAdvertised: manifestFlag(manifest, 'routes', 'images_generations')
|
|
78
|
+
?? manifestFlag(manifest, 'routes', 'responses_http')
|
|
79
|
+
?? undefined,
|
|
80
|
+
toolAdvertised: manifestFlag(manifest, 'tools', 'image_generation') ?? undefined,
|
|
81
|
+
...(input.imageGeneration || {})
|
|
82
|
+
}),
|
|
83
|
+
computer_use: runComputerUseProbe({
|
|
84
|
+
level,
|
|
85
|
+
checkedAt,
|
|
86
|
+
toolAdvertised: manifestFlag(manifest, 'tools', 'computer_use_passthrough') ?? undefined,
|
|
87
|
+
...(input.computerUse || {})
|
|
88
|
+
}),
|
|
89
|
+
browser_use: probeEvidence(input.browserUse || {
|
|
90
|
+
source: 'config',
|
|
91
|
+
evidence: {
|
|
92
|
+
independent_from_computer_use: true,
|
|
93
|
+
independent_from_auth_mode: true,
|
|
94
|
+
reason: 'browser_use_probe_not_run'
|
|
95
|
+
}
|
|
96
|
+
}, checkedAt),
|
|
97
|
+
voice_mode: runVoiceRealtimeProbe({
|
|
98
|
+
level,
|
|
99
|
+
checkedAt,
|
|
100
|
+
routeAdvertised: manifestFlag(manifest, 'routes', 'realtime_calls') ?? undefined,
|
|
101
|
+
...(input.voiceMode || {})
|
|
102
|
+
}),
|
|
103
|
+
plugins: probeEvidence(input.plugins || {
|
|
104
|
+
source: 'config',
|
|
105
|
+
evidence: {
|
|
106
|
+
independent_from_auth_mode: true
|
|
107
|
+
}
|
|
108
|
+
}, checkedAt),
|
|
109
|
+
auxiliary_surfaces: runAuxiliarySurfacesProbe({
|
|
110
|
+
level,
|
|
111
|
+
checkedAt,
|
|
112
|
+
routesAdvertised: auxiliaryRoutesAdvertised(manifest),
|
|
113
|
+
...(input.auxiliarySurfaces || {})
|
|
114
|
+
})
|
|
115
|
+
};
|
|
116
|
+
return {
|
|
117
|
+
...reportWithoutOverall,
|
|
118
|
+
deep_evidence_validation: input.deepEvidenceValidation || {
|
|
119
|
+
schema: CODEX_LB_DEEP_EVIDENCE_VALIDATION_SCHEMA,
|
|
120
|
+
state: 'available_unverified',
|
|
121
|
+
trusted: false,
|
|
122
|
+
evidence: null,
|
|
123
|
+
producer_id: null,
|
|
124
|
+
created_at: null,
|
|
125
|
+
content_sha256: null,
|
|
126
|
+
trust_anchor_id: null,
|
|
127
|
+
blockers: ['codex_lb_deep_evidence_missing'],
|
|
128
|
+
warnings: []
|
|
129
|
+
},
|
|
130
|
+
overall: overallCapabilityState(reportWithoutOverall)
|
|
131
|
+
};
|
|
132
|
+
}
|
|
133
|
+
export function overallCapabilityState(report) {
|
|
134
|
+
if (report.mode === 'cli-provider' || report.mode === 'disabled')
|
|
135
|
+
return 'available_unverified';
|
|
136
|
+
const required = report.mode === 'desktop-native-bridge'
|
|
137
|
+
? REQUIRED_FOR_FULL
|
|
138
|
+
: REQUIRED_FOR_FULL.filter((key) => key !== 'bridge');
|
|
139
|
+
const states = required.map((key) => report[key].state);
|
|
140
|
+
if (states.some((state) => state === 'blocked'))
|
|
141
|
+
return 'blocked';
|
|
142
|
+
if (states.some((state) => state === 'unsupported'))
|
|
143
|
+
return 'unsupported';
|
|
144
|
+
if (report.configured && states.every((state) => state === 'verified'))
|
|
145
|
+
return 'verified';
|
|
146
|
+
return 'available_unverified';
|
|
147
|
+
}
|
|
148
|
+
export function shapeCodexLbDesktopCapabilityStatus(report) {
|
|
149
|
+
const entries = capabilityEntries(report);
|
|
150
|
+
return {
|
|
151
|
+
schema: 'sks.codex-lb-desktop-capability-status.v2',
|
|
152
|
+
ready: report.overall === 'verified',
|
|
153
|
+
state: report.overall,
|
|
154
|
+
configured: report.configured,
|
|
155
|
+
oauth_preserved: report.oauth_preserved,
|
|
156
|
+
gateway_auth_transport: String(report.gateway_auth_transport.evidence.configured_gateway_auth_transport || 'unknown'),
|
|
157
|
+
verified: entries.filter(([, value]) => value.state === 'verified').map(([key]) => key),
|
|
158
|
+
available_unverified: entries.filter(([, value]) => value.state === 'available_unverified').map(([key]) => key),
|
|
159
|
+
blocked: Object.fromEntries(entries
|
|
160
|
+
.filter(([, value]) => value.state === 'blocked')
|
|
161
|
+
.map(([key, value]) => [key, value.blockers])),
|
|
162
|
+
unsupported: entries.filter(([, value]) => value.state === 'unsupported').map(([key]) => key),
|
|
163
|
+
skipped: entries.filter(([, value]) => value.state === 'skipped').map(([key]) => key)
|
|
164
|
+
};
|
|
165
|
+
}
|
|
166
|
+
function capabilityEntries(report) {
|
|
167
|
+
const keys = [
|
|
168
|
+
'gateway_auth_transport',
|
|
169
|
+
'provider_identity',
|
|
170
|
+
'bridge',
|
|
171
|
+
'catalog',
|
|
172
|
+
'model_picker',
|
|
173
|
+
'fast_mode',
|
|
174
|
+
'text_responses',
|
|
175
|
+
'image_generation',
|
|
176
|
+
'computer_use',
|
|
177
|
+
'browser_use',
|
|
178
|
+
'voice_mode',
|
|
179
|
+
'plugins',
|
|
180
|
+
'auxiliary_surfaces'
|
|
181
|
+
];
|
|
182
|
+
return keys.map((key) => [key, report[key]]);
|
|
183
|
+
}
|
|
184
|
+
function manifestFlag(manifest, section, key) {
|
|
185
|
+
const row = manifest?.[section];
|
|
186
|
+
if (!row || typeof row !== 'object' || Array.isArray(row))
|
|
187
|
+
return null;
|
|
188
|
+
const value = row[key];
|
|
189
|
+
return typeof value === 'boolean' ? value : null;
|
|
190
|
+
}
|
|
191
|
+
function auxiliaryRoutesAdvertised(manifest) {
|
|
192
|
+
if (!manifest)
|
|
193
|
+
return undefined;
|
|
194
|
+
const flags = [
|
|
195
|
+
manifestFlag(manifest, 'routes', 'files'),
|
|
196
|
+
manifestFlag(manifest, 'routes', 'transcribe'),
|
|
197
|
+
manifestFlag(manifest, 'routes', 'images_edits'),
|
|
198
|
+
manifestFlag(manifest, 'routes', 'thread_goal'),
|
|
199
|
+
manifestFlag(manifest, 'routes', 'memories_trace_summarize'),
|
|
200
|
+
manifestFlag(manifest, 'routes', 'safety_arc'),
|
|
201
|
+
manifestFlag(manifest, 'routes', 'agent_identities_jwks')
|
|
202
|
+
];
|
|
203
|
+
return flags.some((flag) => flag === true);
|
|
204
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -14,9 +14,6 @@ if r != errSecSuccess{FileHandle.standardError.write(Data("keychain_status=\\(r)
|
|
|
14
14
|
export function codexLbEnvPath(home = process.env.HOME || os.homedir()) {
|
|
15
15
|
return path.join(String(home || os.homedir()), '.codex', 'sks-codex-lb.env');
|
|
16
16
|
}
|
|
17
|
-
export function legacyCodexLbEnvPath(home = process.env.HOME || os.homedir()) {
|
|
18
|
-
return path.join(String(home || os.homedir()), '.codex', 'sks.env');
|
|
19
|
-
}
|
|
20
17
|
export function codexLbMetadataPath(home = process.env.HOME || os.homedir()) {
|
|
21
18
|
return path.join(String(home || os.homedir()), '.codex', 'sks-codex-lb.json');
|
|
22
19
|
}
|
|
@@ -65,9 +62,13 @@ export async function readCodexLbModelCatalog(opts = {}) {
|
|
|
65
62
|
};
|
|
66
63
|
}
|
|
67
64
|
const fetchImpl = opts.fetchImpl || fetch;
|
|
65
|
+
const gatewayAuthTransport = opts.gatewayAuthTransport || 'x-codex-lb-api-key';
|
|
66
|
+
const gatewayHeaders = gatewayAuthTransport === 'authorization-bearer-compat'
|
|
67
|
+
? { Authorization: `Bearer ${loaded.secret_api_key}` }
|
|
68
|
+
: { 'X-Codex-LB-API-Key': loaded.secret_api_key };
|
|
68
69
|
try {
|
|
69
70
|
const response = await fetchImpl(`${loaded.base_url}/models`, {
|
|
70
|
-
headers:
|
|
71
|
+
headers: gatewayHeaders,
|
|
71
72
|
redirect: 'error',
|
|
72
73
|
signal: AbortSignal.timeout(Math.max(250, Number(opts.timeoutMs || 5000)))
|
|
73
74
|
});
|
|
@@ -159,24 +160,19 @@ export function codexLbBaseUrlSecurityBlocker(input) {
|
|
|
159
160
|
export async function loadCodexLbEnv(opts = {}) {
|
|
160
161
|
const home = opts.home || process.env.HOME || os.homedir();
|
|
161
162
|
const metadataPath = opts.metadataPath || codexLbMetadataPath(home);
|
|
162
|
-
const envPaths = [
|
|
163
|
-
|
|
164
|
-
opts.legacyEnvPath || legacyCodexLbEnvPath(home)
|
|
165
|
-
];
|
|
166
|
-
const sourcePriority = ['process.env', 'env-file', 'keychain', 'legacy-env-file'];
|
|
163
|
+
const envPaths = [opts.envPath || codexLbEnvPath(home)];
|
|
164
|
+
const sourcePriority = ['env-file', 'keychain', 'process.env'];
|
|
167
165
|
if (opts.allowProjectSecrets)
|
|
168
166
|
sourcePriority.push('project-local');
|
|
169
167
|
const processEnv = pickEnv(opts.processEnv || process.env);
|
|
170
168
|
const envFile = await readEnvFile(envPaths[0]);
|
|
171
|
-
const legacyEnv = await readEnvFile(envPaths[1]);
|
|
172
169
|
const keychain = await readMacKeychain(opts);
|
|
173
170
|
const projectLocal = opts.allowProjectSecrets ? await readEnvFile(path.join(opts.root || process.cwd(), '.env')) : {};
|
|
174
171
|
const metadata = await readCodexLbCredentialMetadata(metadataPath);
|
|
175
172
|
const apiKeyCandidates = [
|
|
176
|
-
{ source: 'process.env', apiKey: processEnv.apiKey },
|
|
177
173
|
{ source: 'env-file', apiKey: envFile.apiKey },
|
|
178
174
|
{ source: 'keychain', apiKey: keychain.apiKey },
|
|
179
|
-
{ source: '
|
|
175
|
+
{ source: 'process.env', apiKey: processEnv.apiKey },
|
|
180
176
|
...(opts.allowProjectSecrets ? [{ source: 'project-local', apiKey: String(projectLocal.apiKey || '') }] : [])
|
|
181
177
|
].filter((candidate) => Boolean(candidate.apiKey));
|
|
182
178
|
const candidateFingerprints = await Promise.all(apiKeyCandidates.map(async (candidate) => ({
|
|
@@ -188,7 +184,7 @@ export async function loadCodexLbEnv(opts = {}) {
|
|
|
188
184
|
: candidateFingerprints[0];
|
|
189
185
|
const keySource = selectedApiKey?.source || 'missing';
|
|
190
186
|
const apiKey = selectedApiKey?.apiKey || '';
|
|
191
|
-
const configuredBaseUrl = normalizeCodexLbBaseUrl(
|
|
187
|
+
const configuredBaseUrl = normalizeCodexLbBaseUrl(envFile.baseUrl || processEnv.baseUrl || projectLocal.baseUrl || '');
|
|
192
188
|
const apiKeySha256 = selectedApiKey?.sha256 || '';
|
|
193
189
|
const binding = evaluateCodexLbCredentialBinding({
|
|
194
190
|
metadata,
|
|
@@ -2,22 +2,59 @@ import os from 'node:os';
|
|
|
2
2
|
import path from 'node:path';
|
|
3
3
|
import { ensureDir, exists, readText, writeTextAtomic } from '../fsx.js';
|
|
4
4
|
import { codexLbEnvPath, codexLbMetadataPath, normalizeCodexLbBaseUrl } from './codex-lb-env.js';
|
|
5
|
+
import { DEFAULT_CODEX_LB_DESKTOP_MODE, DEFAULT_CODEX_LB_GATEWAY_AUTH_TRANSPORT } from './desktop-mode.js';
|
|
5
6
|
export function buildCodexLbSetupPlan(answers, opts = {}) {
|
|
6
7
|
const home = opts.home || process.env.HOME || os.homedir();
|
|
7
8
|
const baseUrl = normalizeCodexLbBaseUrl(answers.host_or_base_url);
|
|
8
9
|
const configPath = opts.configPath || path.join(home, '.codex', 'config.toml');
|
|
9
10
|
const envPath = opts.envPath || codexLbEnvPath(home);
|
|
10
11
|
const metadataPath = opts.metadataPath || codexLbMetadataPath(home);
|
|
12
|
+
const desktopMode = answers.desktop_mode || DEFAULT_CODEX_LB_DESKTOP_MODE;
|
|
13
|
+
const gatewayAuthTransport = answers.gateway_auth_transport || DEFAULT_CODEX_LB_GATEWAY_AUTH_TRANSPORT;
|
|
11
14
|
const blockers = [];
|
|
12
15
|
if (!baseUrl)
|
|
13
16
|
blockers.push('missing_host_or_base_url');
|
|
14
17
|
if (answers.install_shell_profile !== 'skip' && !answers.write_env_file)
|
|
15
18
|
blockers.push('shell_profile_snippet_requires_env_file');
|
|
16
|
-
const actions = [
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
19
|
+
const actions = [];
|
|
20
|
+
if (desktopMode === 'desktop-native-bridge') {
|
|
21
|
+
actions.push({
|
|
22
|
+
type: 'configure_desktop_native_bridge',
|
|
23
|
+
target: configPath,
|
|
24
|
+
effect: `keep built-in OpenAI and ChatGPT OAuth, route model traffic through a loopback bridge, and use explicit gateway auth transport ${gatewayAuthTransport}`
|
|
25
|
+
});
|
|
26
|
+
actions.push({
|
|
27
|
+
type: 'start_desktop_bridge',
|
|
28
|
+
target: 'SKS Codex Desktop bridge',
|
|
29
|
+
effect: 'start the loopback-only bridge without changing Codex Desktop auth'
|
|
30
|
+
});
|
|
31
|
+
actions.push({
|
|
32
|
+
type: 'verify_oauth_preserved',
|
|
33
|
+
target: path.join(home, '.codex', 'auth.json'),
|
|
34
|
+
effect: 'verify byte identity before App restart and semantic OAuth identity afterward'
|
|
35
|
+
});
|
|
36
|
+
}
|
|
37
|
+
else if (desktopMode === 'desktop-dual-auth-compat') {
|
|
38
|
+
if (gatewayAuthTransport !== 'x-codex-lb-api-key') {
|
|
39
|
+
blockers.push('desktop_compat_requires_x_codex_lb_api_key_transport');
|
|
40
|
+
}
|
|
41
|
+
actions.push({
|
|
42
|
+
type: 'configure_desktop_compat_provider',
|
|
43
|
+
target: configPath,
|
|
44
|
+
effect: 'configure exact provider name "OpenAI", retain ChatGPT OAuth, and send the separate LB key only with X-Codex-LB-API-Key'
|
|
45
|
+
});
|
|
46
|
+
actions.push({
|
|
47
|
+
type: 'verify_oauth_preserved',
|
|
48
|
+
target: path.join(home, '.codex', 'auth.json'),
|
|
49
|
+
effect: 'verify Desktop configuration did not change shared OAuth bytes'
|
|
50
|
+
});
|
|
51
|
+
}
|
|
52
|
+
else if (desktopMode === 'cli-provider') {
|
|
53
|
+
actions.push({
|
|
54
|
+
type: 'write_cli_provider',
|
|
55
|
+
target: configPath,
|
|
56
|
+
effect: 'write an unselected CLI-only codex-lb provider using CODEX_LB_API_KEY without changing Desktop OAuth'
|
|
57
|
+
});
|
|
21
58
|
}
|
|
22
59
|
if (answers.write_env_file) {
|
|
23
60
|
actions.push({ type: 'write_env_file', target: envPath, effect: 'write CODEX_LB_BASE_URL and redacted CODEX_LB_API_KEY env loader with chmod 0600' });
|
|
@@ -32,7 +69,7 @@ export function buildCodexLbSetupPlan(answers, opts = {}) {
|
|
|
32
69
|
actions.push({ type: 'install_shell_profile_snippet', target: profileTargets(home, answers.install_shell_profile).join(', '), effect: `install managed shell snippet for ${answers.install_shell_profile}` });
|
|
33
70
|
}
|
|
34
71
|
if (answers.run_health_check) {
|
|
35
|
-
actions.push({ type: '
|
|
72
|
+
actions.push({ type: 'run_capability_check', target: 'codex-lb response chain', effect: 'run codex-lb capability check after apply' });
|
|
36
73
|
}
|
|
37
74
|
actions.push({ type: 'write_metadata', target: metadataPath, effect: 'write redacted setup metadata and key fingerprint with chmod 0600' });
|
|
38
75
|
const selectedModes = selectedCodexLbPersistenceModes(answers);
|
|
@@ -106,8 +143,8 @@ export function codexLbPersistenceSummary({ selectedModes = [], appliedModes = [
|
|
|
106
143
|
const warnings = effective === 'process_only_ephemeral'
|
|
107
144
|
? [
|
|
108
145
|
'process_only_ephemeral',
|
|
109
|
-
'
|
|
110
|
-
'
|
|
146
|
+
'next_session_requires_center_or_setup',
|
|
147
|
+
'Save credentials in SKS Center (or sks codex-lb setup --write-env-file --keychain) so Desktop can load them automatically'
|
|
111
148
|
]
|
|
112
149
|
: [];
|
|
113
150
|
return {
|