sneakoscope 8.0.2 → 8.0.3
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 +47 -23
- package/config/skills-hash-ledger.v1.json +1 -1
- package/crates/sks-core/Cargo.lock +1 -1
- package/crates/sks-core/Cargo.toml +1 -1
- package/dist/bin/fast-inline.js +55 -13
- package/dist/bin/sks-dispatch.js +1 -1
- package/dist/cli/command-manifest-lite.js +4 -0
- package/dist/cli/command-registry.js +4 -0
- package/dist/cli/install-helpers-codex-lb-chain.js +187 -0
- package/dist/cli/install-helpers-codex-lb-config.js +74 -8
- package/dist/cli/install-helpers.js +89 -44
- package/dist/commands/codex-lb.js +117 -19
- package/dist/commands/doctor.js +697 -37
- package/dist/config/skills-manifest.json +3 -2
- package/dist/core/agents/agent-runner-codex-exec.js +5 -3
- package/dist/core/codex/codex-config-guard.js +238 -52
- package/dist/core/codex-adapter.js +5 -3
- package/dist/core/codex-app/menubar/constants.js +10 -1
- package/dist/core/codex-app/menubar/global-install.js +288 -0
- package/dist/core/codex-app/menubar/installer.js +79 -14
- package/dist/core/codex-app/menubar/launch-agent.js +267 -45
- package/dist/core/codex-app/menubar/paths.js +3 -0
- package/dist/core/codex-app/menubar/rollback.js +55 -7
- package/dist/core/codex-app/menubar/status.js +75 -4
- package/dist/core/codex-control/codex-0139-image-path-real-probe.js +3 -1
- package/dist/core/codex-control/codex-0139-web-search-probe.js +3 -1
- package/dist/core/codex-control/codex-app-server-runtime-env.js +13 -4
- package/dist/core/codex-control/codex-app-server-v2-client.js +3 -3
- package/dist/core/codex-exec-output-schema.js +4 -1
- package/dist/core/codex-lb/codex-lb-env.js +63 -72
- package/dist/core/codex-lb/codex-lb-setup.js +15 -2
- package/dist/core/codex-lb/desktop-center-credentials.js +517 -58
- package/dist/core/codex-lb/desktop-controller.js +153 -24
- package/dist/core/codex-lb/routing-truth.js +327 -0
- package/dist/core/codex-native/core-skill-manifest.js +1 -1
- package/dist/core/commands/basic-cli.js +7 -1
- package/dist/core/commands/qa-loop-command.js +3 -1
- package/dist/core/commands/telegram-command.js +241 -0
- package/dist/core/config-adopt/config-adopt-command.js +35 -0
- package/dist/core/config-adopt/config-adopt.js +346 -0
- package/dist/core/config-adopt/index.js +3 -0
- package/dist/core/doctor/command-alias-cleanup.js +4 -1
- package/dist/core/doctor/current-project-guidance-nested.js +37 -6
- package/dist/core/doctor/current-project-guidance.js +11 -6
- package/dist/core/doctor/doctor-readiness-matrix.js +14 -0
- package/dist/core/doctor/retired-managed-residue-private.js +1 -1
- package/dist/core/doctor/sks-menubar-doctor.js +4 -0
- package/dist/core/feature-fixtures.js +8 -0
- package/dist/core/hooks-runtime/hook-context.js +9 -0
- package/dist/core/hooks-runtime/managed-skill-admission.js +54 -4
- package/dist/core/hooks-runtime/official-subagent-lifecycle.js +69 -1
- package/dist/core/hooks-runtime/subagent-skill-availability-contract.js +2 -2
- package/dist/core/hooks-runtime/subagent-skill-availability-evidence.js +3 -3
- package/dist/core/hooks-runtime/subagent-skill-availability-guards.js +43 -5
- package/dist/core/hooks-runtime/subagent-skill-availability.js +64 -30
- package/dist/core/hooks-runtime/subagent-stop-hook.js +15 -2
- package/dist/core/hooks-runtime.js +148 -4
- package/dist/core/imagegen/imagegen-capability.js +46 -0
- package/dist/core/imagegen/require-imagegen.js +2 -2
- package/dist/core/init/skills.js +17 -3
- package/dist/core/install/installed-package-smoke.js +8 -2
- package/dist/core/naruto/hardware-capacity-probe.js +9 -3
- package/dist/core/naruto/naruto-concurrency-governor.js +68 -24
- package/dist/core/perf/import-graph-budget.js +0 -1
- package/dist/core/product-design-app-server.js +13 -1
- package/dist/core/release/package-size-budget.js +2 -2
- package/dist/core/release/release-pack-receipt.js +1 -2
- package/dist/core/routes/dollar-manifest-lite.js +1 -1
- package/dist/core/routes.js +1 -1
- package/dist/core/security/private-credential-file.js +209 -0
- package/dist/core/subagents/agent-catalog.js +17 -32
- package/dist/core/subagents/naruto-help-contract.js +5 -5
- package/dist/core/subagents/official-subagent-config.js +16 -6
- package/dist/core/subagents/official-subagent-preparation.js +34 -15
- package/dist/core/subagents/official-subagent-prompt.js +4 -4
- package/dist/core/subagents/official-subagent-runner.js +27 -4
- package/dist/core/subagents/thread-budget.js +19 -12
- package/dist/core/subagents/wave-lifecycle.js +18 -6
- package/dist/core/telegram/access.js +54 -0
- package/dist/core/telegram/client.js +144 -0
- package/dist/core/telegram/confirmation.js +37 -0
- package/dist/core/telegram/doctor.js +151 -0
- package/dist/core/telegram/index.js +9 -0
- package/dist/core/telegram/keychain.js +265 -0
- package/dist/core/telegram/liveness.js +109 -0
- package/dist/core/telegram/poller.js +90 -0
- package/dist/core/telegram/redaction.js +15 -0
- package/dist/core/telegram/types.js +1 -0
- package/dist/core/update/update-diagnostics.js +52 -0
- package/dist/core/update/update-migration-state.js +5 -1
- package/dist/core/update/update-operation.js +2 -1
- package/dist/core/update/update-stage-diagnostics.js +38 -0
- package/dist/core/update/update-status.js +2 -9
- package/dist/core/update-check.js +147 -31
- package/dist/core/version.js +1 -1
- package/dist/core/zellij/zellij-launcher.js +23 -4
- package/dist/native/sks-menubar/Sources/AppDelegate.swift +13 -0
- package/dist/native/sks-menubar/Sources/AppIdentity.swift +7 -0
- package/dist/native/sks-menubar/Sources/OperationCoordinator.swift +3 -2
- package/dist/native/sks-menubar/Sources/ProvidersConnectTest.swift +115 -0
- package/dist/native/sks-menubar/Sources/ProvidersFastMode.swift +17 -0
- package/dist/native/sks-menubar/Sources/ProvidersRoutingTruth.swift +190 -0
- package/dist/native/sks-menubar/Sources/ProvidersViewController.swift +100 -59
- package/dist/native/sks-menubar/Sources/SingletonInstanceGuard.swift +328 -0
- package/dist/native/sks-menubar/Sources/TelegramPrivateFileStore.swift +320 -0
- package/dist/native/sks-menubar/Sources/TelegramPrivateFileSupport.swift +303 -0
- package/dist/native/sks-menubar/Sources/TelegramProcessGateway.swift +238 -0
- package/dist/native/sks-menubar/Sources/TelegramRuntimeSupport.swift +56 -0
- package/dist/native/sks-menubar/Sources/TelegramSupport.swift +56 -0
- package/dist/native/sks-menubar/Sources/TelegramTransport.swift +474 -0
- package/dist/native/sks-menubar/Sources/main.swift +15 -1
- package/dist/native/sks-menubar/Tests/OperationCoordinatorTests.swift +4 -3
- package/dist/native/sks-menubar/Tests/ProvidersViewControllerTests.swift +129 -0
- package/dist/native/sks-menubar/Tests/SingletonInstanceGuardTests.swift +183 -0
- package/dist/native/sks-menubar/Tests/TelegramRuntimeSmokeTests.swift +267 -0
- package/dist/native/sks-menubar/Tests/TelegramRuntimeTests.swift +222 -0
- package/dist/scripts/codex-lb-fast-mode-truth-check.js +1 -1
- package/dist/scripts/codex-lb-fast-ui-preservation-check.js +1 -1
- package/dist/scripts/current-command-surface-check.js +2 -4
- package/dist/scripts/official-subagent-workflow-check.js +1 -1
- package/dist/scripts/packlist-performance-check.js +1 -2
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -22,7 +22,7 @@ Proof-first orchestration for Codex CLI, ChatGPT Desktop, AI coding agents, mult
|
|
|
22
22
|
Sneakoscope Codex (`sks`) is an open-source trust layer for Codex CLI and ChatGPT Desktop. It coordinates bounded AI coding agents, records machine-verifiable evidence, preserves project memory, and blocks release claims that are not supported by current tests or artifacts. Search visibility outcomes are measured separately; SKS does not promise rankings or traffic.
|
|
23
23
|
<!-- END SKS SEARCH VISIBILITY MARKETING -->
|
|
24
24
|
|
|
25
|
-
This README documents package **SKS 8.0.
|
|
25
|
+
This README documents package **SKS 8.0.3** — its own identity, read from `package.json` and subject to release-gate verification, not advice about what to install.
|
|
26
26
|
|
|
27
27
|
Use the official latest stable SKS and Codex CLI releases. SKS stays version-agnostic: older hosts keep working where capabilities allow, while Menu Bar / Center induce updates to the latest stable build. Run `sks update-check` for what is installed and read the capability report for what is actually supported — feature availability is decided by capability probes, not by a version number printed in a document. It resolves managed SKS skills from the authoritative global install, preserves a runnable Naruto child slot when `max_threads=2`, and keeps Menu Bar repair transactional so stamped generations remain verifiable. Naruto uses stable opt-in multi-agent V2 when the host exposes it. Local code search is mode-separated (`sks search files|text|structure|symbol|context`); `context` is answered by the compiled TriWiki Context Graph with evidence paths rather than lexical guessing — see [docs/architecture/context-graph.md](docs/architecture/context-graph.md) and [docs/architecture/search-engine-target.md](docs/architecture/search-engine-target.md). See [CHANGELOG.md](CHANGELOG.md).
|
|
28
28
|
|
|
@@ -63,11 +63,25 @@ The SKS menu bar shows the installed Codex CLI version and latest known version.
|
|
|
63
63
|
|
|
64
64
|
**Manage MCP Servers…** opens a native macOS manager for the global `~/.codex/config.toml`. It can add remote URL or local stdio servers, enable/disable existing entries, remove entries after confirmation, and refresh the current state. Mutations are lock-protected, backed up, TOML-validated, and written with mode `0600`; configured environment values and command arguments are never rendered in the list. Changes apply to new Codex sessions. The same plumbing is available through the canonical `sks mcp config list|get|add|edit|duplicate|enable|disable|remove|test|login|logout|backups|restore` surface for diagnostics and automation.
|
|
65
65
|
|
|
66
|
-
### Remote coding: Orca
|
|
67
|
-
|
|
68
|
-
SKS
|
|
69
|
-
|
|
70
|
-
|
|
66
|
+
### Remote coding: Telegram transport and Orca option
|
|
67
|
+
|
|
68
|
+
SKS 8.0.3 restores a first-party Telegram Bot API transport for the existing
|
|
69
|
+
typed remote-control contract. One bounded outbound `getUpdates` loop runs in
|
|
70
|
+
the existing Menu Bar process, so it adds no daemon, inbound port, or tunnel.
|
|
71
|
+
`sks telegram pair` enrolls an allowed chat through the existing secret store;
|
|
72
|
+
unpaired chats receive no response, free-form shell input is never accepted,
|
|
73
|
+
and destructive commands require actor-bound two-step confirmation and an audit
|
|
74
|
+
receipt. Doctor readiness requires a real `getMe` round trip plus live-poller
|
|
75
|
+
evidence. Release readiness additionally requires a real command/reply E2E from
|
|
76
|
+
a cellular network; configuration, fixtures, and local-network tests do not
|
|
77
|
+
satisfy that gate.
|
|
78
|
+
|
|
79
|
+
[Orca](https://github.com/stablyai/orca) remains an external MIT-licensed
|
|
80
|
+
option that can launch Codex in a worktree. It is not bundled with, supported
|
|
81
|
+
by, or required by SKS, and SKS adds no Orca dependency or automatic migration.
|
|
82
|
+
Orca's mobile companion and Remote Orca Servers are beta; the desktop/server
|
|
83
|
+
runtime remains the source of truth and remote access may require a private LAN
|
|
84
|
+
or Tailscale path. See [the Orca remote-coding guide](docs/orca-remote-coding.md).
|
|
71
85
|
|
|
72
86
|
## The Front Door
|
|
73
87
|
|
|
@@ -85,16 +99,25 @@ Orca's mobile companion and Remote Orca Servers are beta. Their desktop/server r
|
|
|
85
99
|
|
|
86
100
|
`$sks-naruto` and `sks naruto run "task" --agents 8 --max-threads 12` use Codex official subagents. Standalone and Codex App tasks that request project-host database, spreadsheet, or render tools require the non-persistent `--trusted-project` flag after the operator reviews the checkout; an App session ID scopes evidence but does not grant trust. The parent is GPT-5.6 Sol Max. Tiny mechanical `worker` slices use Luna Max; ordinary UI, logic, backend, and native coding uses Sol High; review, testing, debugging, architecture, integration, security, database, research, release, and other judgment-sensitive work uses Sol Max; long-context scans and direct Computer Use, Browser/Chrome, or image-generation execution uses Terra Medium. Mixed execution/judgment work is split when possible, and unsplittable judgment defaults to Sol Max.
|
|
87
101
|
|
|
88
|
-
Fresh SKS-owned project config enables Codex 0.145+ multi-agent V2 with `agents.max_concurrent_threads_per_session =
|
|
89
|
-
|
|
90
|
-
Naruto's automatic tiers are 4/6/8 children for ordinary work and 16
|
|
91
|
-
mass cheap-model work
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
102
|
+
Fresh SKS-owned project config enables Codex 0.145+ multi-agent V2 with `agents.max_concurrent_threads_per_session = 256`, `features.multi_agent_v2.max_concurrent_threads_per_session = 257`, `max_depth = 1`, and `interrupt_message = true`. Nested delegation remains forbidden. Explicit user-owned limits are preserved, while legacy SKS-owned 12/13 defaults migrate to 256/257.
|
|
103
|
+
|
|
104
|
+
Naruto's automatic starting tiers are 4/6/8 children for ordinary work and 16
|
|
105
|
+
for mass cheap-model work. After decomposition, either lane may expand to the
|
|
106
|
+
SKS-owned ceiling of 256 independent useful children. Explicit
|
|
107
|
+
`--agents N` and `--max-threads N` values from 1 through 256 remain
|
|
108
|
+
authoritative instead of being reduced to those automatic tiers. A first wave
|
|
109
|
+
may reach 256 child slots only when independent ready work, disjoint ownership,
|
|
110
|
+
verifier/tool capacity, and the external Codex/session host all permit it;
|
|
111
|
+
otherwise Naruto records the exact active limiter and reuses returned capacity
|
|
112
|
+
in later waves.
|
|
113
|
+
|
|
114
|
+
`SKS_NARUTO_REMOTE_API_PARALLEL_BUDGET` declares a lower remote provider/API
|
|
115
|
+
parallel-request budget for the governor. It cannot raise a lower external-host
|
|
116
|
+
or session limit. The official Codex lane does not impose a local CPU/RAM or
|
|
117
|
+
unmeasured API-default clamp; it follows an explicit provider budget and a
|
|
118
|
+
measured host cap. The 256 ceiling is structural, not a recommendation or proof
|
|
119
|
+
that 256 live agents were load-tested on the current host. The four GPT-5.6
|
|
120
|
+
model profiles are routing lanes, not an agent-count limit.
|
|
98
121
|
|
|
99
122
|
Gates are task-profile aware: greetings and answer-only turns create no mission gate; tiny work gets minimal verification; parallel work gets scoped ownership and verification; high-risk work keeps the full safety gates. `SubagentStart`/`SubagentStop` prove lifecycle only. Completion also requires `subagent-parent-summary.json` with one trustworthy structured outcome per thread, correlated with `subagent-events.jsonl` and `subagent-evidence.json`.
|
|
100
123
|
|
|
@@ -234,9 +257,9 @@ It shows the current quickstart flow: one-line install, `$sks-plan`, `sks review
|
|
|
234
257
|
- Project memory: `sks memory build`
|
|
235
258
|
- Codebase index/pack for LLM context: `sks wiki refresh --code`, `sks wiki validate --json` (code-pack freshness)
|
|
236
259
|
- Native capability repair: `sks doctor --fix` (imagegen/Computer Use/Browser Use), `.sneakoscope/reports/native-capability-readiness.json`
|
|
237
|
-
- codex-lb continuity: `sks codex-lb status --json` verifies the selected proxy's unauthenticated `/health` `X-App-Version`. Tool-heavy continuation requires a codex-lb deployment that reports the capability; use the official latest stable release. Older or unverified deployments block setup, doctor, and launch instead of silently falling back.
|
|
260
|
+
- codex-lb continuity: `sks codex-lb status --json` verifies the selected proxy's unauthenticated `/health` `X-App-Version`. Tool-heavy continuation requires a codex-lb deployment that reports the capability; use the official latest stable release. Older or unverified deployments block setup, doctor, and launch instead of silently falling back. A selected route is green only after one measured request records the destination host, gateway-key authentication class, measurement time, and latency; config presence alone is not routing proof.
|
|
238
261
|
- Agent bridge for any agent system: `sks mcp-server`, `sks agent-bridge setup`, `SKS_AGENT_MODE=1` — see [docs/AGENT-BRIDGE.md](docs/AGENT-BRIDGE.md)
|
|
239
|
-
- Release gates: `npm run release:check:affected` for ordinary change-aware verification and `npm run release:check:confidence` for the final local confidence pass.
|
|
262
|
+
- Release gates: `npm run release:check:affected` for ordinary change-aware verification and `npm run release:check:confidence` for the final local confidence pass. Evidence for the 8.0.3 physical checklist includes a successful 5,001-directory update scan, exactly one running Menu Bar process at the current package version, one measured real codex-lb request to the selected remote host, and one Telegram command/reply E2E over cellular.
|
|
240
263
|
- Release preparation: typecheck, one clean build, focused tests, affected/confidence gates, then `npm publish --dry-run --json --registry https://registry.npmjs.org/ --tag latest --access public`. The dry-run does not publish; authorization remains a separate maintainer workflow.
|
|
241
264
|
- Release readiness notes: [docs/release-readiness.md](docs/release-readiness.md) and [CHANGELOG.md](CHANGELOG.md)
|
|
242
265
|
- Image generation review routes require Codex App `$imagegen`/`gpt-image-2` evidence with recorded output hashes; direct API fallback and mock fixtures do not satisfy full route gates.
|
|
@@ -248,15 +271,16 @@ It shows the current quickstart flow: one-line install, `$sks-plan`, `sks review
|
|
|
248
271
|
- macOS optional: menu bar integration and `/usr/bin/open`
|
|
249
272
|
- The menubar icon shows and hides itself automatically as the Codex desktop app launches/quits; set `quit_with_codex: true` in `~/.codex/sks-menubar/config.json` to have the menubar fully quit with Codex instead of just hiding (default `false`).
|
|
250
273
|
- Native input dialogs (API keys, codex-lb setup) pass secrets to `sks` via `--api-key-stdin` instead of a visible Terminal window or process arguments.
|
|
251
|
-
- Codex Desktop
|
|
274
|
+
- Codex Desktop keeps `~/.codex/auth.json` byte-preserved. **Use codex-lb** atomically stores the provider definition and active top-level selection and resolves its separate gateway key from the owner-only `0600` env file; while selected, requests must not consume the stored ChatGPT OAuth identity. Turning codex-lb off returns to the official OAuth path. Keychain requests fail closed until a dedicated signed helper is available.
|
|
252
275
|
- Explicit codex-lb setup/reconfiguration migrates the retired generic `sks-codex-lb` Keychain item only after the replacement owner-only store is verified, deletes only the exact legacy account, and proves absence by readback. If cleanup cannot be proved, the replacement store is retained and the provider key should be rotated.
|
|
253
|
-
- Providers
|
|
276
|
+
- Providers exposes atomic **Use codex-lb** / **Use ChatGPT OAuth** selection plus shared RoutingTruth. A green codex-lb state requires one measured request to the configured remote base URL; the Menu Bar and Doctor render the same host, authentication class, measurement time, and latency.
|
|
254
277
|
- The retired dual-auth compatibility mode is detected only for safe migration. It cannot be activated or reported ready because it would require a global GUI secret.
|
|
255
|
-
- Authentication and routing modes do not toggle Codex App's native model picker, Fast, image, Browser Use, Computer Use, voice, plugins/apps, or other built-in surfaces. Capability status describes evidence for the codex-lb data path, not permission to use
|
|
278
|
+
- Authentication and routing modes do not toggle Codex App's native model picker, Fast, image, Browser Use, Computer Use, voice, plugins/apps, or other built-in surfaces. Capability status describes measured evidence for the codex-lb data path, not permission to use a native feature.
|
|
256
279
|
- `sks update`, setup, repair, and routing changes preserve OAuth, user model/reasoning/Fast settings, unknown catalog fields, and unrelated provider configuration. Legacy shared-auth routing requires explicit `sks codex-lb migrate-legacy-desktop --restart-app`; without a real restart and post-restart identity check it cannot finalize a migration receipt.
|
|
257
280
|
- The remote codex-lb service remains independently hosted and operated. SKS uses only the configured URL and gateway key; it does not deploy, restart, or change credentials on that host.
|
|
258
|
-
- Full release proof blocks with `real_required_missing` until fresh trust-anchored evidence covers the real Desktop feature/lifecycle matrix
|
|
259
|
-
- Update installs
|
|
281
|
+
- Full release proof blocks with `real_required_missing` until fresh trust-anchored evidence covers the real Desktop feature/lifecycle matrix, one measured gateway-key request to the selected separately hosted codex-lb instance, and the other-Mac runtime; fixtures and configuration cannot satisfy that boundary.
|
|
282
|
+
- Update installs stop and verify every prior Menu Bar process before replacement, rebuild the companion from the newly installed SKS package, bootstrap it, and require exactly one running process whose version probe equals the current package version.
|
|
283
|
+
- Telegram remote control uses one bounded long-poller inside that same Menu Bar process. Release evidence must include a real cellular command/reply round trip; `getMe`, a local fixture, or a configured token alone cannot satisfy the E2E gate.
|
|
260
284
|
- The menubar dropdown's `View Last Log` item opens the most recent background action's log file, so you don't need to keep a Terminal window open to see command output.
|
|
261
285
|
- `Manage MCP Servers…` provides a resizable native table and add/remove/enable/disable controls for global Codex MCP configuration. Secret environment values and command arguments are accepted through native dialogs/stdin but omitted from list output and logs.
|
|
262
286
|
- `sks menubar status --json` reports a `codex_sync` object with `bundle_id`, `codex_running`, and `icon_visible_expected` to show Codex-lifecycle detection state.
|
|
@@ -38,7 +38,7 @@
|
|
|
38
38
|
{ "canonical_name": "sks-init-deep", "trusted_sha256": ["a679fa4ba36e070de5753994f58595c4352302cc98d868ba70ff98305d15f451"] },
|
|
39
39
|
{ "canonical_name": "sks-loop", "trusted_sha256": ["e56f9c4d0f7227961779daf6806943f1926bb588ce21a965a813e8ad91cfd5c8"] },
|
|
40
40
|
{ "canonical_name": "sks-mad-sks", "trusted_sha256": ["03fb5063d19c3d48d004cd8e6e39bfe244016d7edacfe99e5dab087cbbfa6db9", "a3d0110ca97576130893311b3267621acb02c16ca9aea4b2da3e5300eea58158"] },
|
|
41
|
-
{ "canonical_name": "sks-naruto", "trusted_sha256": ["f8e808622e222b4ad7dcb2907e5f06a890db83139ae443ec6c8c33781dfa3e37", "49b5e3dcc1b537b49c2cf09e5b875cb16acb05c622b22798e265e64dacd8ac90"] },
|
|
41
|
+
{ "canonical_name": "sks-naruto", "trusted_sha256": ["34222c72e4e1ead3584907f4d905444b7de820283ee7348018f110d5e6b04461", "f8e808622e222b4ad7dcb2907e5f06a890db83139ae443ec6c8c33781dfa3e37", "49b5e3dcc1b537b49c2cf09e5b875cb16acb05c622b22798e265e64dacd8ac90"] },
|
|
42
42
|
{ "canonical_name": "sks-performance-evaluator", "trusted_sha256": ["5b8c6cea19ffda8e434700297ed060fde3cfcfc9c98635402599e84756466db4", "c0bfd5a2e6c74813cb5dac9dadd4c7543ee768a48cf3e36b86b3d9306c2712c6"] },
|
|
43
43
|
{ "canonical_name": "sks-pipeline-runner", "trusted_sha256": ["020ba4da2f96bcda23cee4596b1e790816780178f1917dee748ff4b289cba0e5", "ffcbe0ea4b585e3d2886f1d9fa7a3b88706aaf42182fb177b2371b76beb0ddcd"] },
|
|
44
44
|
{ "canonical_name": "sks-plan", "trusted_sha256": ["7795867b38a5f169924125850f137c31995cf28000f74284839530a68ace156a", "b6f3b09230e9809acf4e13df2de6af3c75a8534e8890d6560664ebfc2e4072f8"] },
|
package/dist/bin/fast-inline.js
CHANGED
|
@@ -13,11 +13,7 @@ function rootJsonFastInline(fs, cwd = process.cwd()) {
|
|
|
13
13
|
}
|
|
14
14
|
async function doctorJsonFastInline(input = {}) {
|
|
15
15
|
const startedAt = Date.now();
|
|
16
|
-
const
|
|
17
|
-
const oauthCallbackPortDiagnostic = await inspectOAuthCallbackPortConflict({
|
|
18
|
-
...(input.run ? { run: input.run } : {})
|
|
19
|
-
});
|
|
20
|
-
const oauthCallbackOperatorActions = oauthCallbackDoctorGuidance(oauthCallbackPortDiagnostic);
|
|
16
|
+
const secretResolution = await inspectCodexLbSecretResolutionFastInline(input);
|
|
21
17
|
const write = input.write || ((text) => process.stdout.write(text));
|
|
22
18
|
write(`${JSON.stringify({
|
|
23
19
|
schema: 'sks.doctor-status.v3',
|
|
@@ -59,12 +55,10 @@ async function doctorJsonFastInline(input = {}) {
|
|
|
59
55
|
},
|
|
60
56
|
doctor_fix_transaction: null,
|
|
61
57
|
blockers: [],
|
|
62
|
-
warnings: [
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
operator_actions: oauthCallbackOperatorActions,
|
|
67
|
-
oauth_callback_port_diagnostic: oauthCallbackPortDiagnostic
|
|
58
|
+
warnings: ['fast_readonly_doctor_skipped_optional_deep_diagnostics'],
|
|
59
|
+
codex_lb: {
|
|
60
|
+
secret_resolution: secretResolution
|
|
61
|
+
}
|
|
68
62
|
}, null, 2)}\n`);
|
|
69
63
|
}
|
|
70
64
|
async function narutoHelpJsonFastInline() {
|
|
@@ -125,12 +119,60 @@ function findProjectRootSync(fs, start) {
|
|
|
125
119
|
dir = parent;
|
|
126
120
|
}
|
|
127
121
|
}
|
|
122
|
+
async function inspectCodexLbSecretResolutionFastInline(input) {
|
|
123
|
+
const processEnv = input.processEnv || process.env;
|
|
124
|
+
const home = input.home || processEnv.HOME || processEnv.USERPROFILE || process.cwd();
|
|
125
|
+
const codexHome = joinPath(home, '.codex');
|
|
126
|
+
const envPath = joinPath(codexHome, 'sks-codex-lb.env');
|
|
127
|
+
const metadataPath = joinPath(codexHome, 'sks-codex-lb.json');
|
|
128
|
+
const [{ inspectConfinedPath }, { readPrivateCredentialFile }] = await Promise.all([
|
|
129
|
+
import('../core/managed-path-safety.js'),
|
|
130
|
+
import('../core/security/private-credential-file.js')
|
|
131
|
+
]);
|
|
132
|
+
let envFilePresent = false;
|
|
133
|
+
let envFilePrivate = false;
|
|
134
|
+
try {
|
|
135
|
+
const inspected = await inspectConfinedPath(codexHome, envPath);
|
|
136
|
+
envFilePresent = inspected.exists;
|
|
137
|
+
const expectedUid = typeof process.getuid === 'function' ? process.getuid() : null;
|
|
138
|
+
envFilePrivate = inspected.exists
|
|
139
|
+
&& !inspected.leafSymlink
|
|
140
|
+
&& inspected.stat?.isFile() === true
|
|
141
|
+
&& (inspected.stat.mode & 0o777) === 0o600
|
|
142
|
+
&& (expectedUid === null || inspected.stat.uid === expectedUid);
|
|
143
|
+
}
|
|
144
|
+
catch {
|
|
145
|
+
envFilePresent = false;
|
|
146
|
+
}
|
|
147
|
+
let metadataValid = false;
|
|
148
|
+
if (envFilePrivate) {
|
|
149
|
+
try {
|
|
150
|
+
const snapshot = await readPrivateCredentialFile(codexHome, metadataPath, 'codex_lb_metadata', { maxBytes: 64 * 1024 });
|
|
151
|
+
const metadata = JSON.parse(snapshot.bytes.toString('utf8'));
|
|
152
|
+
metadataValid = metadata?.schema === 'sks.codex-lb-metadata.v1'
|
|
153
|
+
&& /^[a-f0-9]{64}$/.test(String(metadata?.api_key?.sha256 || '').trim().toLowerCase())
|
|
154
|
+
&& Boolean(String(metadata?.base_url || '').trim());
|
|
155
|
+
}
|
|
156
|
+
catch {
|
|
157
|
+
metadataValid = false;
|
|
158
|
+
}
|
|
159
|
+
}
|
|
160
|
+
const processKeyPresent = Boolean(String(processEnv.CODEX_LB_API_KEY || '').trim());
|
|
161
|
+
const source = envFilePrivate && metadataValid ? 'env-file' : processKeyPresent ? 'process.env' : 'missing';
|
|
162
|
+
return {
|
|
163
|
+
source,
|
|
164
|
+
path: source === 'env-file' || envFilePresent ? envPath : null,
|
|
165
|
+
prompt_risk: (input.platform || process.platform) === 'darwin'
|
|
166
|
+
? 'unknown_keychain_not_probed'
|
|
167
|
+
: 'none'
|
|
168
|
+
};
|
|
169
|
+
}
|
|
128
170
|
function fsInline() {
|
|
129
171
|
return process.getBuiltinModule?.('node:fs') || require('node:fs');
|
|
130
172
|
}
|
|
131
|
-
function readJsonSyncInline(file) {
|
|
173
|
+
function readJsonSyncInline(file, fs = fsInline()) {
|
|
132
174
|
try {
|
|
133
|
-
return JSON.parse(
|
|
175
|
+
return JSON.parse(fs.readFileSync(file, 'utf8'));
|
|
134
176
|
}
|
|
135
177
|
catch {
|
|
136
178
|
return null;
|
package/dist/bin/sks-dispatch.js
CHANGED
|
@@ -13,7 +13,7 @@ async function runSks(args) {
|
|
|
13
13
|
const { rootJsonFastInline } = await import('./fast-inline.js');
|
|
14
14
|
rootJsonFastInline(fs);
|
|
15
15
|
}
|
|
16
|
-
else if (args[0] === 'doctor' && args.includes('--json') && !args.includes('--report-file') && !args.includes('--fix') && !args.includes('--full') && !args.includes('--capabilities') && !args.includes('--search')) {
|
|
16
|
+
else if (args[0] === 'doctor' && args.includes('--json') && !args.includes('--report-file') && !args.includes('--fix') && !args.includes('--full') && !args.includes('--capabilities') && !args.includes('--profile') && !args.includes('--search')) {
|
|
17
17
|
const { doctorJsonFastInline } = await import('./fast-inline.js');
|
|
18
18
|
await doctorJsonFastInline();
|
|
19
19
|
}
|
|
@@ -17,6 +17,7 @@ const COMMAND_MANIFEST_LITE_BASE = [
|
|
|
17
17
|
{ name: 'update', summary: 'Inspect, review, apply, or roll back the global SKS update', maturity: 'stable' },
|
|
18
18
|
{ name: 'uninstall', summary: 'Uninstall SKS global skills, hooks, config, menu bar, and optional project residue', maturity: 'stable', allowedDuringActiveRoute: true },
|
|
19
19
|
{ name: 'update-check', summary: 'Show the shared SKS, Codex CLI, and Menu Bar update status', maturity: 'stable', readonly: true, skipMigrationGate: true, allowedDuringActiveRoute: true, diagnostic: true },
|
|
20
|
+
{ name: 'config', summary: 'Adopt project Codex config into SKS management', maturity: 'stable', skipMigrationGate: true },
|
|
20
21
|
{ name: 'mcp', summary: 'Manage scoped Codex MCP configuration', maturity: 'beta', skipMigrationGate: true },
|
|
21
22
|
{ name: 'wizard', summary: 'Open setup wizard help', maturity: 'stable' },
|
|
22
23
|
{ name: 'usage', summary: 'Show focused usage topic', maturity: 'stable', readonly: true, allowedDuringActiveRoute: true, diagnostic: true },
|
|
@@ -37,6 +38,7 @@ const COMMAND_MANIFEST_LITE_BASE = [
|
|
|
37
38
|
{ name: 'codex-lb', summary: 'Inspect codex-lb status and circuit health', maturity: 'beta', skipMigrationGate: true },
|
|
38
39
|
{ name: 'menubar', summary: 'Inspect/install/restart/uninstall SKS menu bar', maturity: 'beta', skipMigrationGate: true, allowedDuringActiveRoute: true, diagnostic: true },
|
|
39
40
|
{ name: 'remote', summary: 'Inspect official Remote readiness and run the proof-aware SSH stdio worker', maturity: 'beta' },
|
|
41
|
+
{ name: 'telegram', summary: 'Pair and inspect the Telegram remote-control transport', maturity: 'beta', skipMigrationGate: true },
|
|
40
42
|
{ name: 'hooks', summary: 'Explain and inspect Codex hooks', maturity: 'beta', skipMigrationGate: true },
|
|
41
43
|
{ name: 'zellij-lane', summary: 'Render a Zellij lane frame for SKS sessions', maturity: 'beta' },
|
|
42
44
|
{ name: 'zellij-slot-pane', summary: 'Render a compact Zellij worker slot pane', maturity: 'beta' },
|
|
@@ -116,6 +118,7 @@ const COMMAND_CONTRACT_OVERRIDES_LITE = {
|
|
|
116
118
|
check: { risk: 'R1', latency: 'long' },
|
|
117
119
|
'commit-and-push': { risk: 'R3' },
|
|
118
120
|
'computer-use': { latency: 'long' },
|
|
121
|
+
config: { risk: 'R2', supportsJson: true, remoteAllowed: false, inputProfile: 'json-only' },
|
|
119
122
|
dfix: { latency: 'long' },
|
|
120
123
|
'dollar-commands': { risk: 'R2', latency: 'normal' },
|
|
121
124
|
eval: { latency: 'long' },
|
|
@@ -165,6 +168,7 @@ const COMMAND_CONTRACT_OVERRIDES_LITE = {
|
|
|
165
168
|
requiredCapabilities: ['proof.stop-gate']
|
|
166
169
|
},
|
|
167
170
|
task: { risk: 'R1', latency: 'long' },
|
|
171
|
+
telegram: { risk: 'R2', supportsJson: true, remoteAllowed: false, inputProfile: 'json-only' },
|
|
168
172
|
trust: {
|
|
169
173
|
risk: 'R0', latency: 'fast', supportsJson: true, remoteAllowed: true, inputProfile: 'trust', requiredCapabilities: ['proof.trust']
|
|
170
174
|
},
|
|
@@ -165,6 +165,7 @@ const COMMAND_DEFINITIONS = {
|
|
|
165
165
|
activeRoutePolicy: 'always'
|
|
166
166
|
}),
|
|
167
167
|
'update-check': readOnly(entry('stable', 'Show the shared SKS, Codex CLI, and Menu Bar update status', 'dist/core/commands/basic-cli.js', basicArgs('updateCheckCommand'))),
|
|
168
|
+
config: skipMigrationGate(entry('stable', 'Adopt project Codex config into SKS management', 'dist/core/config-adopt/index.js', subcommand(() => import('../core/config-adopt/index.js'), 'configCommand', 'dist/core/config-adopt/index.js', 'adopt'))),
|
|
168
169
|
mcp: skipMigrationGate(entry('beta', 'Manage scoped Codex MCP configuration', 'dist/core/commands/mcp-config-command.js', argsCommand(() => import('../core/commands/mcp-config-command.js'), 'mcpConfigCommand', 'dist/core/commands/mcp-config-command.js'))),
|
|
169
170
|
wizard: entry('stable', 'Open setup wizard help', 'dist/core/commands/basic-cli.js', basicNoArgs('quickstartCommand')),
|
|
170
171
|
usage: readOnly(entry('stable', 'Show focused usage topic', 'dist/core/commands/basic-cli.js', basicArgs('usageCommand'))),
|
|
@@ -185,6 +186,7 @@ const COMMAND_DEFINITIONS = {
|
|
|
185
186
|
'codex-lb': skipMigrationGate(entry('beta', 'Inspect codex-lb status and circuit health', 'dist/commands/codex-lb.js', directCommand(() => import('../commands/codex-lb.js'), 'dist/commands/codex-lb.js'))),
|
|
186
187
|
menubar: activeRouteDiagnostic(entry('beta', 'Inspect/install/restart/uninstall SKS menu bar', 'dist/core/commands/menubar-command.js', subcommand(() => import('../core/commands/menubar-command.js'), 'menubarCommand', 'dist/core/commands/menubar-command.js', 'status'))),
|
|
187
188
|
remote: entry('beta', 'Inspect official Remote readiness and run the proof-aware SSH stdio worker', 'dist/core/commands/remote-command.js', argsCommand(() => import('../core/commands/remote-command.js'), 'remoteCommand', 'dist/core/commands/remote-command.js')),
|
|
189
|
+
telegram: skipMigrationGate(entry('beta', 'Pair and inspect the Telegram remote-control transport', 'dist/core/commands/telegram-command.js', argsCommand(() => import('../core/commands/telegram-command.js'), 'telegramCommand', 'dist/core/commands/telegram-command.js'))),
|
|
188
190
|
hooks: skipMigrationGate(entry('beta', 'Explain and inspect Codex hooks', 'dist/commands/hooks.js', directCommand(() => import('../commands/hooks.js'), 'dist/commands/hooks.js'))),
|
|
189
191
|
'zellij-lane': entry('beta', 'Render a Zellij lane frame for SKS sessions', 'dist/commands/zellij-lane.js', directCommand(() => import('../commands/zellij-lane.js'), 'dist/commands/zellij-lane.js')),
|
|
190
192
|
'zellij-slot-pane': entry('beta', 'Render a compact Zellij worker slot pane', 'dist/commands/zellij-slot-pane.js', directCommand(() => import('../commands/zellij-slot-pane.js'), 'dist/commands/zellij-slot-pane.js')),
|
|
@@ -260,6 +262,7 @@ const COMMANDS_WITH_LEGACY_CONTRACT_OVERRIDES = applyCommandContractOverrides(CO
|
|
|
260
262
|
check: { risk: 'R1', latency: 'long' },
|
|
261
263
|
'commit-and-push': { risk: 'R3' },
|
|
262
264
|
'computer-use': { latency: 'long' },
|
|
265
|
+
config: { risk: 'R2', supportsJson: true, remoteAllowed: false, inputProfile: 'json-only' },
|
|
263
266
|
dfix: { latency: 'long' },
|
|
264
267
|
eval: { latency: 'long' },
|
|
265
268
|
gates: {
|
|
@@ -307,6 +310,7 @@ const COMMANDS_WITH_LEGACY_CONTRACT_OVERRIDES = applyCommandContractOverrides(CO
|
|
|
307
310
|
requiredCapabilities: ['proof.stop-gate']
|
|
308
311
|
},
|
|
309
312
|
task: { risk: 'R1', latency: 'long' },
|
|
313
|
+
telegram: { risk: 'R2', supportsJson: true, remoteAllowed: false, inputProfile: 'json-only' },
|
|
310
314
|
trust: {
|
|
311
315
|
risk: 'R0', latency: 'fast', supportsJson: true, remoteAllowed: true, inputProfile: 'trust', requiredCapabilities: ['proof.trust']
|
|
312
316
|
},
|
|
@@ -204,6 +204,193 @@ async function fetchCodexLbResponse(fetchImpl, endpoint, apiKey, body, timeoutMs
|
|
|
204
204
|
clearTimeout(timer);
|
|
205
205
|
}
|
|
206
206
|
}
|
|
207
|
+
const CODEX_LB_CONNECT_TEST_MAX_OUTPUT_TOKENS = 32;
|
|
208
|
+
const CODEX_LB_CONNECT_TEST_MAX_RESULT_CHARS = 256;
|
|
209
|
+
const CODEX_LB_CONNECT_TEST_MAX_ERROR_CHARS = 512;
|
|
210
|
+
const CODEX_LB_CONNECT_TEST_TIMEOUT_MS = 15_000;
|
|
211
|
+
function boundedText(value, maxChars) {
|
|
212
|
+
const text = String(value || '').trim();
|
|
213
|
+
return text.length <= maxChars ? text : text.slice(0, maxChars);
|
|
214
|
+
}
|
|
215
|
+
function codexLbCompletedResponse(json, events = []) {
|
|
216
|
+
if (json?.response && typeof json.response === 'object')
|
|
217
|
+
return json.response;
|
|
218
|
+
if (json?.data?.response && typeof json.data.response === 'object')
|
|
219
|
+
return json.data.response;
|
|
220
|
+
if (json?.data && typeof json.data === 'object')
|
|
221
|
+
return json.data;
|
|
222
|
+
if (json && typeof json === 'object')
|
|
223
|
+
return json;
|
|
224
|
+
for (let index = events.length - 1; index >= 0; index -= 1) {
|
|
225
|
+
const event = events[index];
|
|
226
|
+
if (event?.type === 'response.completed' && event?.response && typeof event.response === 'object') {
|
|
227
|
+
return event.response;
|
|
228
|
+
}
|
|
229
|
+
}
|
|
230
|
+
return null;
|
|
231
|
+
}
|
|
232
|
+
function codexLbOutputText(response, events = []) {
|
|
233
|
+
const parts = [];
|
|
234
|
+
for (const output of Array.isArray(response?.output) ? response.output : []) {
|
|
235
|
+
for (const content of Array.isArray(output?.content) ? output.content : []) {
|
|
236
|
+
if (content?.type === 'output_text' && typeof content.text === 'string' && content.text.trim()) {
|
|
237
|
+
parts.push(content.text.trim());
|
|
238
|
+
}
|
|
239
|
+
}
|
|
240
|
+
}
|
|
241
|
+
if (parts.length === 0) {
|
|
242
|
+
for (const event of events) {
|
|
243
|
+
if (event?.type === 'response.output_text.done' && typeof event.text === 'string' && event.text.trim()) {
|
|
244
|
+
parts.push(event.text.trim());
|
|
245
|
+
}
|
|
246
|
+
}
|
|
247
|
+
}
|
|
248
|
+
return parts.join('\n').trim();
|
|
249
|
+
}
|
|
250
|
+
function boundedCodexLbUsage(usage) {
|
|
251
|
+
const tokenCount = (value) => Number.isSafeInteger(value) && value >= 0 ? value : null;
|
|
252
|
+
return {
|
|
253
|
+
input_tokens: tokenCount(usage?.input_tokens),
|
|
254
|
+
output_tokens: tokenCount(usage?.output_tokens),
|
|
255
|
+
total_tokens: tokenCount(usage?.total_tokens),
|
|
256
|
+
reasoning_tokens: tokenCount(usage?.output_tokens_details?.reasoning_tokens)
|
|
257
|
+
};
|
|
258
|
+
}
|
|
259
|
+
function codexLbConnectTestFailure(status, extra = {}) {
|
|
260
|
+
return {
|
|
261
|
+
schema: 'sks.codex-lb-connect-test.v1',
|
|
262
|
+
ok: false,
|
|
263
|
+
status,
|
|
264
|
+
response_id: null,
|
|
265
|
+
model: extra.model || null,
|
|
266
|
+
latency_ms: extra.latency_ms ?? null,
|
|
267
|
+
usage: extra.usage || null,
|
|
268
|
+
result: null,
|
|
269
|
+
result_truncated: false,
|
|
270
|
+
http_status: extra.http_status ?? null,
|
|
271
|
+
blockers: Array.isArray(extra.blockers) ? extra.blockers : [status],
|
|
272
|
+
...(extra.error ? { error: extra.error } : {})
|
|
273
|
+
};
|
|
274
|
+
}
|
|
275
|
+
export async function testCodexLbConnection(status = {}, opts = {}) {
|
|
276
|
+
const providerSelected = status?.selected === true || status?.provider?.selected === true;
|
|
277
|
+
if (opts.requireSelected === true && !providerSelected) {
|
|
278
|
+
return codexLbConnectTestFailure('provider_unselected', {
|
|
279
|
+
blockers: ['codex_lb_provider_not_selected']
|
|
280
|
+
});
|
|
281
|
+
}
|
|
282
|
+
const credentialBindingBlockers = Array.isArray(opts.credentialBindingBlockers)
|
|
283
|
+
? opts.credentialBindingBlockers.map((value) => boundedText(value, 128)).filter(Boolean)
|
|
284
|
+
: [];
|
|
285
|
+
if (credentialBindingBlockers.length > 0) {
|
|
286
|
+
return codexLbConnectTestFailure('credential_binding_drift', { blockers: credentialBindingBlockers });
|
|
287
|
+
}
|
|
288
|
+
if (status.provider_base_url_matches_credential !== true) {
|
|
289
|
+
return codexLbConnectTestFailure('provider_base_url_mismatch', {
|
|
290
|
+
blockers: ['codex_lb_provider_base_url_mismatch']
|
|
291
|
+
});
|
|
292
|
+
}
|
|
293
|
+
if (status.provider_contract_ok !== true) {
|
|
294
|
+
return codexLbConnectTestFailure('provider_contract_drift', {
|
|
295
|
+
blockers: ['codex_lb_provider_contract_drift']
|
|
296
|
+
});
|
|
297
|
+
}
|
|
298
|
+
const baseUrl = opts.baseUrl || status.base_url;
|
|
299
|
+
const endpoint = codexLbResponsesEndpoint(baseUrl);
|
|
300
|
+
if (!endpoint)
|
|
301
|
+
return codexLbConnectTestFailure('missing_base_url');
|
|
302
|
+
const transportBlocker = codexLbBaseUrlSecurityBlocker(baseUrl);
|
|
303
|
+
if (transportBlocker)
|
|
304
|
+
return codexLbConnectTestFailure('transport_blocked', { blockers: [transportBlocker] });
|
|
305
|
+
const env = opts.env || process.env;
|
|
306
|
+
const home = opts.home || env.HOME || os.homedir();
|
|
307
|
+
const apiKey = opts.apiKey || parseCodexLbEnvKey(await readText(opts.envPath || status.env_path || codexLbEnvPath(home), ''));
|
|
308
|
+
if (!apiKey)
|
|
309
|
+
return codexLbConnectTestFailure('missing_env_key');
|
|
310
|
+
const model = String(opts.model || env.SKS_CODEX_MODEL || env.CODEX_MODEL || '').trim();
|
|
311
|
+
if (!model)
|
|
312
|
+
return codexLbConnectTestFailure('model_unselected');
|
|
313
|
+
if (model.length > 128)
|
|
314
|
+
return codexLbConnectTestFailure('model_invalid');
|
|
315
|
+
const fetchImpl = opts.fetch || globalThis.fetch;
|
|
316
|
+
if (typeof fetchImpl !== 'function')
|
|
317
|
+
return codexLbConnectTestFailure('fetch_unavailable', { model });
|
|
318
|
+
const timeoutMs = Number(opts.timeoutMs || env.SKS_CODEX_LB_CONNECT_TEST_TIMEOUT_MS || CODEX_LB_CONNECT_TEST_TIMEOUT_MS);
|
|
319
|
+
const body = {
|
|
320
|
+
model,
|
|
321
|
+
input: 'Reply OK.',
|
|
322
|
+
store: false,
|
|
323
|
+
reasoning: { effort: 'low' },
|
|
324
|
+
max_output_tokens: CODEX_LB_CONNECT_TEST_MAX_OUTPUT_TOKENS
|
|
325
|
+
};
|
|
326
|
+
const nowMs = typeof opts.nowMs === 'function' ? opts.nowMs : Date.now;
|
|
327
|
+
const startedAt = nowMs();
|
|
328
|
+
const fetched = await fetchCodexLbResponse(fetchImpl, endpoint, apiKey, body, timeoutMs);
|
|
329
|
+
const latencyMs = Math.max(0, Math.round(nowMs() - startedAt));
|
|
330
|
+
if (!fetched.ok) {
|
|
331
|
+
const error = redactSecretText(fetched.error_payload?.error?.message
|
|
332
|
+
|| fetched.error_payload?.response?.error?.message
|
|
333
|
+
|| fetched.text
|
|
334
|
+
|| 'codex-lb Responses request failed', [apiKey]);
|
|
335
|
+
return codexLbConnectTestFailure('request_failed', {
|
|
336
|
+
model,
|
|
337
|
+
latency_ms: latencyMs,
|
|
338
|
+
http_status: fetched.status,
|
|
339
|
+
error: boundedText(error, CODEX_LB_CONNECT_TEST_MAX_ERROR_CHARS)
|
|
340
|
+
});
|
|
341
|
+
}
|
|
342
|
+
const response = codexLbCompletedResponse(fetched.json, fetched.events);
|
|
343
|
+
const responseId = boundedText(codexLbResponseId(response), 128);
|
|
344
|
+
const responseModel = boundedText(response?.model || model, 128);
|
|
345
|
+
const usage = boundedCodexLbUsage(response?.usage);
|
|
346
|
+
if (!responseId) {
|
|
347
|
+
return codexLbConnectTestFailure('missing_response_id', {
|
|
348
|
+
model: responseModel,
|
|
349
|
+
latency_ms: latencyMs,
|
|
350
|
+
http_status: fetched.status,
|
|
351
|
+
usage
|
|
352
|
+
});
|
|
353
|
+
}
|
|
354
|
+
if (response?.error) {
|
|
355
|
+
return codexLbConnectTestFailure('response_error', {
|
|
356
|
+
model: responseModel,
|
|
357
|
+
latency_ms: latencyMs,
|
|
358
|
+
http_status: fetched.status,
|
|
359
|
+
usage,
|
|
360
|
+
error: boundedText(redactSecretText(response.error?.message || response.error, [apiKey]), CODEX_LB_CONNECT_TEST_MAX_ERROR_CHARS)
|
|
361
|
+
});
|
|
362
|
+
}
|
|
363
|
+
if (response?.status !== 'completed') {
|
|
364
|
+
return codexLbConnectTestFailure('response_not_completed', {
|
|
365
|
+
model: responseModel,
|
|
366
|
+
latency_ms: latencyMs,
|
|
367
|
+
http_status: fetched.status,
|
|
368
|
+
usage
|
|
369
|
+
});
|
|
370
|
+
}
|
|
371
|
+
const outputText = codexLbOutputText(response, fetched.events);
|
|
372
|
+
if (!outputText) {
|
|
373
|
+
return codexLbConnectTestFailure('empty_result', {
|
|
374
|
+
model: responseModel,
|
|
375
|
+
latency_ms: latencyMs,
|
|
376
|
+
http_status: fetched.status,
|
|
377
|
+
usage
|
|
378
|
+
});
|
|
379
|
+
}
|
|
380
|
+
return {
|
|
381
|
+
schema: 'sks.codex-lb-connect-test.v1',
|
|
382
|
+
ok: true,
|
|
383
|
+
status: 'connected',
|
|
384
|
+
response_id: responseId,
|
|
385
|
+
model: responseModel,
|
|
386
|
+
latency_ms: latencyMs,
|
|
387
|
+
usage,
|
|
388
|
+
result: boundedText(outputText, CODEX_LB_CONNECT_TEST_MAX_RESULT_CHARS),
|
|
389
|
+
result_truncated: outputText.length > CODEX_LB_CONNECT_TEST_MAX_RESULT_CHARS,
|
|
390
|
+
http_status: fetched.status,
|
|
391
|
+
blockers: []
|
|
392
|
+
};
|
|
393
|
+
}
|
|
207
394
|
export async function checkCodexLbResponseChain(status = {}, opts = {}) {
|
|
208
395
|
const env = opts.env || process.env;
|
|
209
396
|
if (!codexLbChainCheckEnabled(env) && !opts.force)
|