sneakoscope 8.1.2 → 8.2.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +96 -58
- package/crates/sks-core/Cargo.lock +1 -1
- package/crates/sks-core/Cargo.toml +1 -1
- package/dist/bin/fast-inline.js +5 -51
- package/dist/cli/command-manifest-lite.js +2 -1
- package/dist/cli/command-registry.js +2 -1
- package/dist/cli/global-mode-router.js +1 -1
- package/dist/cli/install-helpers-codex-lb-config.js +112 -914
- package/dist/cli/install-helpers-codex-lb-shared.js +3 -44
- package/dist/cli/install-helpers-install-support.js +4 -20
- package/dist/cli/install-helpers.js +36 -2716
- package/dist/cli/router.js +9 -9
- package/dist/commands/bridge-command-output.js +111 -0
- package/dist/commands/bridge.js +320 -0
- package/dist/commands/codex-app.js +39 -123
- package/dist/commands/doctor-helpers.js +380 -0
- package/dist/commands/doctor-profile.js +3 -0
- package/dist/commands/doctor.js +114 -873
- package/dist/commands/mad-sks.js +0 -4
- package/dist/config/skills-manifest.json +1 -1
- package/dist/core/agents/agent-effort-policy.js +11 -21
- package/dist/core/agents/agent-recursion-guard.js +26 -0
- package/dist/core/agents/agent-runner-codex-exec.js +7 -9
- package/dist/core/architecture-hardening/contracts/contracts.js +225 -161
- package/dist/core/architecture-hardening/state/state-service.js +49 -13
- package/dist/core/auto-review.js +15 -9
- package/dist/core/codex/codex-config-guard.js +8 -0
- package/dist/core/codex-adapter.js +8 -10
- package/dist/core/codex-app/codex-app-fast-ui-repair.js +7 -29
- package/dist/core/codex-app/codex-app-launcher.js +10 -12
- package/dist/core/codex-app/codex-app-restart.js +10 -12
- package/dist/core/codex-app/menubar/constants.js +2 -5
- package/dist/core/codex-app/menubar/global-install.js +3 -2
- package/dist/core/codex-app/menubar/installer/result.js +23 -0
- package/dist/core/codex-app/menubar/installer/runtime.js +28 -0
- package/dist/core/codex-app/menubar/installer.js +5 -96
- package/dist/core/codex-app/menubar/migration.js +1 -42
- package/dist/core/codex-app/openrouter-provider.js +0 -78
- package/dist/core/codex-app.js +97 -360
- package/dist/core/codex-control/codex-app-server-runtime-env.js +8 -28
- package/dist/core/codex-control/codex-current-image-path-real-probe.js +2 -3
- package/dist/core/codex-control/codex-current-web-search-probe.js +2 -3
- package/dist/core/codex-control/codex-sdk-adapter.js +5 -48
- package/dist/core/codex-control/codex-task-runner.js +16 -60
- package/dist/core/codex-control/desktop-bridge-launch-guard.js +227 -0
- package/dist/core/codex-exec-output-schema.js +11 -13
- package/dist/core/codex-lb/bridge-contracts.js +2 -0
- package/dist/core/codex-lb/bridge-runtime-validation/capability.js +104 -0
- package/dist/core/codex-lb/bridge-runtime-validation/catalog.js +52 -0
- package/dist/core/codex-lb/bridge-runtime-validation/shared.js +109 -0
- package/dist/core/codex-lb/bridge-runtime-validation/status.js +250 -0
- package/dist/core/codex-lb/bridge-runtime-validation.js +106 -0
- package/dist/core/codex-lb/capability-runner.js +505 -201
- package/dist/core/codex-lb/codex-lb-env.js +179 -12
- package/dist/core/codex-lb/combined-catalog/builder.js +86 -0
- package/dist/core/codex-lb/combined-catalog/contracts.js +5 -0
- package/dist/core/codex-lb/combined-catalog/normalize.js +170 -0
- package/dist/core/codex-lb/combined-catalog/persistence.js +207 -0
- package/dist/core/codex-lb/combined-catalog/shared.js +12 -0
- package/dist/core/codex-lb/combined-catalog/storage.js +171 -0
- package/dist/core/codex-lb/combined-catalog.js +12 -0
- package/dist/core/codex-lb/desktop-bridge/client.js +4 -1
- package/dist/core/codex-lb/desktop-bridge/header-policy.js +48 -63
- package/dist/core/codex-lb/desktop-bridge/http-forward.js +115 -83
- package/dist/core/codex-lb/desktop-bridge/launchd.js +20 -13
- package/dist/core/codex-lb/desktop-bridge/location-rewrite.js +4 -1
- package/dist/core/codex-lb/desktop-bridge/security.js +381 -267
- package/dist/core/codex-lb/desktop-bridge/server.js +148 -19
- package/dist/core/codex-lb/desktop-bridge/state.js +56 -70
- package/dist/core/codex-lb/desktop-bridge/types.js +6 -1
- package/dist/core/codex-lb/desktop-bridge/websocket-forward.js +281 -106
- package/dist/core/codex-lb/desktop-bridge-migration/historical-config.js +245 -0
- package/dist/core/codex-lb/desktop-bridge-migration/historical-toml.js +56 -0
- package/dist/core/codex-lb/desktop-bridge-migration/metadata.js +73 -0
- package/dist/core/codex-lb/desktop-bridge-migration/receipt.js +52 -0
- package/dist/core/codex-lb/desktop-bridge-migration/retired-runtime-cleanup.js +106 -0
- package/dist/core/codex-lb/desktop-bridge-migration/types.js +1 -0
- package/dist/core/codex-lb/desktop-bridge-migration.js +238 -0
- package/dist/core/codex-lb/desktop-controller-v3/catalog.js +257 -0
- package/dist/core/codex-lb/desktop-controller-v3/diagnostics.js +62 -0
- package/dist/core/codex-lb/desktop-controller-v3/lifecycle-commands.js +203 -0
- package/dist/core/codex-lb/desktop-controller-v3/live-probes.js +293 -0
- package/dist/core/codex-lb/desktop-controller-v3/preflight-probes.js +144 -0
- package/dist/core/codex-lb/desktop-controller-v3/provider-commands.js +182 -0
- package/dist/core/codex-lb/desktop-controller-v3/shared.js +279 -0
- package/dist/core/codex-lb/desktop-controller-v3/status.js +269 -0
- package/dist/core/codex-lb/desktop-controller-v3/types.js +1 -0
- package/dist/core/codex-lb/desktop-controller-v3/verification.js +89 -0
- package/dist/core/codex-lb/desktop-controller-v3.js +67 -0
- package/dist/core/codex-lb/desktop-controller.js +2 -1730
- package/dist/core/codex-lb/desktop-service.js +462 -627
- package/dist/core/codex-lb/migration-receipt.js +560 -118
- package/dist/core/codex-lb/probes/auxiliary-surfaces-probe.js +37 -53
- package/dist/core/codex-lb/probes/bridge-probe.js +125 -64
- package/dist/core/codex-lb/probes/catalog-probe.js +36 -136
- package/dist/core/codex-lb/probes/computer-use-probe.js +63 -39
- package/dist/core/codex-lb/probes/image-generation-probe.js +98 -41
- package/dist/core/codex-lb/probes/probe-evidence.js +32 -33
- package/dist/core/codex-lb/probes/voice-realtime-probe.js +69 -43
- package/dist/core/codex-lb/provider-credentials/configuration.js +127 -0
- package/dist/core/codex-lb/provider-credentials/locks.js +11 -0
- package/dist/core/codex-lb/provider-credentials/private-snapshot.js +28 -0
- package/dist/core/codex-lb/provider-credentials/removal.js +33 -0
- package/dist/core/codex-lb/provider-credentials/resolution.js +59 -0
- package/dist/core/codex-lb/provider-credentials/runtime.js +55 -0
- package/dist/core/codex-lb/provider-credentials/types.js +1 -0
- package/dist/core/codex-lb/provider-credentials/validation-store.js +137 -0
- package/dist/core/codex-lb/provider-credentials.js +5 -0
- package/dist/core/codex-lb/provider-registry.js +323 -0
- package/dist/core/codex-lb/provider-route-policy.js +118 -0
- package/dist/core/codex-lb/request-route-resolver.js +172 -0
- package/dist/core/codex-lb/route-index.js +148 -0
- package/dist/core/codex-lb/trusted-deep-evidence.js +158 -286
- package/dist/core/commands/basic-cli.js +1 -1
- package/dist/core/commands/check-command.js +3 -10
- package/dist/core/commands/gate-result-contract.js +10 -14
- package/dist/core/commands/intent-normalization/normalizer.js +1 -1
- package/dist/core/commands/mad-sks-command.js +2 -6
- package/dist/core/commands/release-command.js +11 -1
- package/dist/core/commands/telegram-command.js +46 -6
- package/dist/core/doctor/doctor-readiness-matrix.js +9 -7
- package/dist/core/doctor/skill-legacy-surface.js +5 -5
- package/dist/core/evidence/v2/evidence-key.js +30 -3
- package/dist/core/feature-fixtures.js +8 -1
- package/dist/core/feature-registry.js +3 -2
- package/dist/core/hooks-runtime/stop-finalization.js +11 -1
- package/dist/core/hooks-runtime/subagent-context.js +15 -1
- package/dist/core/hooks-runtime/subagent-skill-availability-contract.js +1 -1
- package/dist/core/hooks-runtime/tool-output-quarantine.js +1 -1
- package/dist/core/hooks-runtime.js +73 -87
- package/dist/core/image-ux-review/imagegen-adapter.js +108 -94
- package/dist/core/image-ux-review/real-callout-extractor.js +144 -14
- package/dist/core/imagegen/desktop-bridge-imagegen-target.js +77 -0
- package/dist/core/imagegen/imagegen-capability.js +43 -151
- package/dist/core/init/skills/filesystem.js +89 -0
- package/dist/core/init/skills/inventory.js +97 -0
- package/dist/core/init/skills/manifest.js +151 -0
- package/dist/core/init/skills.js +5 -325
- package/dist/core/init.js +0 -63
- package/dist/core/install/installed-package-smoke.js +1 -1
- package/dist/core/managed-assets/managed-assets-manifest.js +0 -1
- package/dist/core/policy/latest-version-guidance.js +15 -2
- package/dist/core/preflight/parallel-preflight-engine.js +27 -51
- package/dist/core/provider/provider-badge.js +9 -4
- package/dist/core/provider/provider-context.js +57 -107
- package/dist/core/providers/openrouter/openrouter-account.js +3 -1
- package/dist/core/providers/openrouter/openrouter-secret-store.js +91 -22
- package/dist/core/release/desktop-bridge-release-evidence.js +457 -0
- package/dist/core/release/gate-manifest.js +0 -1
- package/dist/core/release/main-push-guard.js +13 -0
- package/dist/core/release/main-push-receipt.js +11 -0
- package/dist/core/release/physical-release-gates.js +664 -61
- package/dist/core/release/publish-preflight.js +3 -3
- package/dist/core/release/release-gate-batch-runner.js +19 -6
- package/dist/core/release/release-gate-dag.js +33 -6
- package/dist/core/release/release-gate-node.js +1 -3
- package/dist/core/release/release-gate-output-contract.js +55 -0
- package/dist/core/release/release-pack-contract.js +1 -1
- package/dist/core/release/release-pack-receipt.js +209 -8
- package/dist/core/release/release-real-contract.js +1 -1
- package/dist/core/release/stage-publish.js +106 -28
- package/dist/core/retention/temp-lease.js +204 -0
- package/dist/core/retention.js +18 -195
- package/dist/core/routes.js +1 -2
- package/dist/core/safety/intent-contract/intent-contract.js +3 -3
- package/dist/core/subagents/naruto-host-credentials.js +6 -1
- package/dist/core/subagents/official-subagent-config.js +27 -9
- package/dist/core/subagents/official-subagent-runner.js +14 -31
- package/dist/core/subagents/wave-lifecycle.js +36 -8
- package/dist/core/subagents/wave-parent-guidance.js +2 -1
- package/dist/core/telegram/doctor.js +2 -2
- package/dist/core/telegram/liveness.js +10 -4
- package/dist/core/triwiki/context-graph/compiler/index.js +18 -18
- package/dist/core/update/update-migration-state/fast-mode-config.js +172 -0
- package/dist/core/update/update-migration-state/session-state-split.js +247 -0
- package/dist/core/update/update-migration-state/simple-stages.js +46 -0
- package/dist/core/update/update-migration-state.js +4 -481
- package/dist/core/version.js +1 -1
- package/dist/native/sks-menubar/Sources/OperationCoordinator.swift +28 -4
- package/dist/native/sks-menubar/Sources/OperationModels.swift +112 -2
- package/dist/native/sks-menubar/Sources/ProviderRouteExplanation.swift +21 -0
- package/dist/native/sks-menubar/Sources/ProvidersBridgeCatalog.swift +140 -0
- package/dist/native/sks-menubar/Sources/ProvidersOpenRouter.swift +107 -470
- package/dist/native/sks-menubar/Sources/ProvidersReliability.swift +27 -197
- package/dist/native/sks-menubar/Sources/ProvidersRoutingTruth.swift +335 -269
- package/dist/native/sks-menubar/Sources/ProvidersViewController.swift +233 -437
- package/dist/native/sks-menubar/Sources/RemoteCodingViewController.swift +16 -7
- package/dist/native/sks-menubar/Sources/SecureProcessEnvelope.swift +39 -9
- package/dist/native/sks-menubar/Sources/TelegramSupport.swift +56 -0
- package/dist/scripts/canonical-test-runner.js +7 -1
- package/dist/scripts/check-runtime-schemas.js +7 -2
- package/dist/scripts/codex-sdk-real-smoke-check.js +3 -1
- package/dist/scripts/desktop-bridge-capabilities-check.js +123 -0
- package/dist/scripts/{codex-lb-desktop-bridge-latency-check.js → desktop-bridge-latency-check.js} +61 -16
- package/dist/scripts/desktop-bridge-real-evidence-check.js +64 -0
- package/dist/scripts/{codex-lb-desktop-bridge-check.js → desktop-bridge-transport-check.js} +92 -155
- package/dist/scripts/desktop-bridge-transport-client.js +116 -0
- package/dist/scripts/desktop-bridge-unification-check.js +276 -0
- package/dist/scripts/doctor-fixes-codex-app-fast-ui-check.js +12 -8
- package/dist/scripts/gate-policy-audit-check.js +52 -2
- package/dist/scripts/provider-badge-context-check.js +55 -12
- package/dist/scripts/publish-preflight.js +1 -2
- package/dist/scripts/release-affected-selector-check.js +1 -2
- package/dist/scripts/release-aggressive-resource-governor-check.js +1 -1
- package/dist/scripts/release-cache-glob-hashing-check.js +1 -0
- package/dist/scripts/release-cache-version-neutral-fixture-check.js +1 -0
- package/dist/scripts/release-full-parallelism-blackbox.js +1 -1
- package/dist/scripts/release-gate-batch-runner-check.js +9 -0
- package/dist/scripts/release-gate-dag-runner-check.js +6 -0
- package/dist/scripts/release-gate-dag-runner.js +4 -2
- package/dist/scripts/release-metadata-check.js +16 -3
- package/dist/scripts/release-pack-receipt.js +29 -6
- package/dist/scripts/release-physical-gates-check.js +39 -0
- package/dist/scripts/release-real-check.js +7 -5
- package/package.json +6 -8
- package/release-gates.v2.json +156 -157
- package/runtime-required-scripts.json +11 -11
- package/schemas/codex/desktop-bridge-status-v3.schema.json +286 -0
- package/schemas/codex/desktop-capabilities-v3.schema.json +198 -0
- package/schemas/release/release-gate-node.schema.json +2 -3
- package/dist/cli/codex-lb-setup-warning-output.js +0 -17
- package/dist/cli/install-helpers-codex-lb-chain.js +0 -529
- package/dist/commands/codex-lb.js +0 -1232
- package/dist/core/architecture-hardening/migration/migration.js +0 -111
- package/dist/core/codex-app/auxiliary-oauth-policy.js +0 -36
- package/dist/core/codex-app/catalog-compat/catalog-service.js +0 -104
- package/dist/core/codex-app/child-policy/child-policy.js +0 -35
- package/dist/core/codex-app/desktop-routing-snapshot.js +0 -233
- package/dist/core/codex-app/glm-model-profile.js +0 -1
- package/dist/core/codex-app/glm-profile-installer.js +0 -191
- package/dist/core/codex-app/glm-profile-schema.js +0 -42
- package/dist/core/codex-app/multi-provider-router.js +0 -391
- package/dist/core/codex-app/openrouter-activate.js +0 -405
- package/dist/core/codex-app/openrouter-model-catalog.js +0 -217
- package/dist/core/codex-app/provider-child-policy.js +0 -64
- package/dist/core/codex-app/provider-mode.js +0 -91
- package/dist/core/codex-app/provider-session-policy.js +0 -85
- package/dist/core/codex-app/session-policy/session-pinning.js +0 -68
- package/dist/core/codex-control/codex-lb-launch-recovery.js +0 -319
- package/dist/core/codex-lb/codex-lb-setup.js +0 -293
- package/dist/core/codex-lb/codex-lb-tool-catalog.js +0 -456
- package/dist/core/codex-lb/codex-lb-tool-output-recovery.js +0 -290
- package/dist/core/codex-lb/desktop-center-credentials.js +0 -1083
- package/dist/core/codex-lb/desktop-mode.js +0 -32
- package/dist/core/codex-lb/desktop-real-evidence.js +0 -168
- package/dist/core/codex-lb/legacy-migration.js +0 -576
- package/dist/core/codex-lb/native-openai-transport/transport.js +0 -68
- package/dist/core/codex-lb/provider-routing/provider-router.js +0 -58
- package/dist/core/codex-lb/routing-truth.js +0 -327
- package/dist/core/imagegen/codex-lb-imagegen-target.js +0 -92
- package/dist/native/sks-menubar/Sources/ProvidersConnectTest.swift +0 -118
- package/dist/native/sks-menubar/Sources/ProvidersFastMode.swift +0 -17
- package/dist/native/sks-menubar/Sources/ProvidersMultiProvider.swift +0 -331
- package/dist/native/sks-menubar/Sources/ProvidersRoleModels.swift +0 -260
- package/dist/scripts/codex-lb-catalog-passthrough-check.js +0 -120
- package/dist/scripts/codex-lb-desktop-auth-invariant-check.js +0 -169
- package/dist/scripts/codex-lb-desktop-capabilities-check.js +0 -287
- package/dist/scripts/codex-lb-desktop-real-evidence-check.js +0 -123
- package/dist/scripts/codex-lb-fast-mode-truth-check.js +0 -114
- package/dist/scripts/codex-lb-fast-ui-preservation-check.js +0 -152
- package/dist/scripts/codex-lb-gpt56-fast-profile-check.js +0 -231
|
@@ -0,0 +1,276 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
import assert from 'node:assert/strict';
|
|
3
|
+
import fs from 'node:fs/promises';
|
|
4
|
+
import os from 'node:os';
|
|
5
|
+
import path from 'node:path';
|
|
6
|
+
import { COMMAND_ALIASES_LITE, COMMAND_MANIFEST_BY_NAME } from '../cli/command-manifest-lite.js';
|
|
7
|
+
import { normalizeCommand } from '../cli/router.js';
|
|
8
|
+
import { inspectHistoricalDesktopBridgeIntent, migrateDesktopBridgeConfig } from '../core/codex-lb/desktop-bridge-migration.js';
|
|
9
|
+
import { rollbackDesktopBridgeUnificationReceipt } from '../core/codex-lb/migration-receipt.js';
|
|
10
|
+
import { configureProviderCredential, resolveAllProviderCredentials } from '../core/codex-lb/provider-credentials.js';
|
|
11
|
+
import { buildStoredBridgeProviderRegistry, resolveBridgeProviderRegistry, serializeStoredBridgeProviderRegistry } from '../core/codex-lb/provider-registry.js';
|
|
12
|
+
import { buildBridgeRoutingPolicy, readBridgeRoutingPolicy } from '../core/codex-lb/provider-route-policy.js';
|
|
13
|
+
import { buildBridgeRouteIndex } from '../core/codex-lb/route-index.js';
|
|
14
|
+
import { openRouterSecretPaths } from '../core/providers/openrouter/openrouter-secret-store.js';
|
|
15
|
+
import { emitGate } from './gate-lib.js';
|
|
16
|
+
const clientCapability = 'A'.repeat(43);
|
|
17
|
+
const bridgeBaseUrl = `http://127.0.0.1:47821/__sks/client/${clientCapability}/backend-api/codex`;
|
|
18
|
+
const codexLbEndpoint = 'https://lb.example.test/backend-api/codex';
|
|
19
|
+
const initialCodexLbKey = 'fixture-codex-lb-key-initial-123456789';
|
|
20
|
+
const initialOpenRouterKey = 'fixture-openrouter-key-initial-987654321';
|
|
21
|
+
const rotatedCodexLbKey = 'fixture-codex-lb-key-rotated-234567891';
|
|
22
|
+
const rotatedOpenRouterKey = 'fixture-openrouter-key-rotated-876543219';
|
|
23
|
+
const initialOauthAccess = 'fixture-oauth-access-initial';
|
|
24
|
+
const initialOauthRefresh = 'fixture-oauth-refresh-initial';
|
|
25
|
+
const rotatedOauthAccess = 'fixture-oauth-access-rotated';
|
|
26
|
+
const rotatedOauthRefresh = 'fixture-oauth-refresh-rotated';
|
|
27
|
+
const allFixtureSecrets = [
|
|
28
|
+
initialCodexLbKey,
|
|
29
|
+
initialOpenRouterKey,
|
|
30
|
+
rotatedCodexLbKey,
|
|
31
|
+
rotatedOpenRouterKey,
|
|
32
|
+
initialOauthAccess,
|
|
33
|
+
initialOauthRefresh,
|
|
34
|
+
rotatedOauthAccess,
|
|
35
|
+
rotatedOauthRefresh
|
|
36
|
+
];
|
|
37
|
+
const temporaryRoot = await fs.mkdtemp(path.join(os.tmpdir(), 'sks-desktop-bridge-unification-gate-'));
|
|
38
|
+
let failed = null;
|
|
39
|
+
try {
|
|
40
|
+
const home = path.join(temporaryRoot, 'home');
|
|
41
|
+
const codexHome = path.join(home, '.codex');
|
|
42
|
+
const configPath = path.join(codexHome, 'config.toml');
|
|
43
|
+
const authPath = path.join(codexHome, 'auth.json');
|
|
44
|
+
const codexLbEnvPath = path.join(codexHome, 'sks-codex-lb.env');
|
|
45
|
+
const openRouterPaths = openRouterSecretPaths({ HOME: home });
|
|
46
|
+
const routePolicyPath = path.join(codexHome, 'sks', 'sks-bridge-route-policy.json');
|
|
47
|
+
const providerRegistryPath = path.join(codexHome, 'sks', 'sks-bridge-provider-registry.json');
|
|
48
|
+
const combinedCatalogPath = path.join(codexHome, 'sks', 'sks-bridge-catalog.json');
|
|
49
|
+
const historicalConfig = [
|
|
50
|
+
'# sks-codex-lb-managed-provider-selection',
|
|
51
|
+
'model_provider = "codex-lb"',
|
|
52
|
+
'',
|
|
53
|
+
'[model_providers.codex-lb]',
|
|
54
|
+
'name = "codex-lb"',
|
|
55
|
+
`base_url = "${codexLbEndpoint}"`,
|
|
56
|
+
'env_key = "CODEX_LB_API_KEY"',
|
|
57
|
+
'requires_openai_auth = false',
|
|
58
|
+
'',
|
|
59
|
+
'[model_providers.openrouter]',
|
|
60
|
+
'name = "OpenRouter"',
|
|
61
|
+
'base_url = "https://openrouter.ai/api/v1"',
|
|
62
|
+
'requires_openai_auth = false',
|
|
63
|
+
''
|
|
64
|
+
].join('\n');
|
|
65
|
+
const initialAuth = authJson(initialOauthAccess, initialOauthRefresh);
|
|
66
|
+
await fs.mkdir(codexHome, { recursive: true, mode: 0o700 });
|
|
67
|
+
await fs.writeFile(configPath, historicalConfig, { mode: 0o600 });
|
|
68
|
+
await fs.writeFile(authPath, initialAuth, { mode: 0o600 });
|
|
69
|
+
await configureProviderCredential({
|
|
70
|
+
provider_id: 'codex-lb',
|
|
71
|
+
api_key: initialCodexLbKey,
|
|
72
|
+
host: codexLbEndpoint,
|
|
73
|
+
home,
|
|
74
|
+
processEnv: {}
|
|
75
|
+
});
|
|
76
|
+
await configureProviderCredential({
|
|
77
|
+
provider_id: 'openrouter',
|
|
78
|
+
api_key: initialOpenRouterKey,
|
|
79
|
+
home,
|
|
80
|
+
processEnv: { HOME: home },
|
|
81
|
+
openRouterPaths
|
|
82
|
+
});
|
|
83
|
+
const initialCredentials = await resolveAllProviderCredentials({
|
|
84
|
+
codexLb: {
|
|
85
|
+
home,
|
|
86
|
+
processEnv: {},
|
|
87
|
+
validation: { state: 'ready', checked_at: '2026-08-06T00:00:00.000Z' }
|
|
88
|
+
},
|
|
89
|
+
openrouter: {
|
|
90
|
+
processEnv: { HOME: home },
|
|
91
|
+
openRouterPaths,
|
|
92
|
+
validation: { state: 'ready', checked_at: '2026-08-06T00:00:00.000Z' }
|
|
93
|
+
}
|
|
94
|
+
});
|
|
95
|
+
assert.equal(initialCredentials['codex-lb'].secret, initialCodexLbKey);
|
|
96
|
+
assert.equal(initialCredentials.openrouter.secret, initialOpenRouterKey);
|
|
97
|
+
assert.equal(initialCredentials['codex-lb'].state, 'ready');
|
|
98
|
+
assert.equal(initialCredentials.openrouter.state, 'ready');
|
|
99
|
+
const intent = inspectHistoricalDesktopBridgeIntent(historicalConfig);
|
|
100
|
+
assert.deepEqual(intent.blockers, []);
|
|
101
|
+
assert.equal(intent.default_provider_id, 'codex-lb');
|
|
102
|
+
assert.equal(intent.providers['codex-lb'].enabled, true);
|
|
103
|
+
assert.equal(intent.providers.openrouter.enabled, true);
|
|
104
|
+
const storedRegistry = buildStoredBridgeProviderRegistry({
|
|
105
|
+
credentials: initialCredentials,
|
|
106
|
+
overrides: intent.providers
|
|
107
|
+
});
|
|
108
|
+
const registryText = serializeStoredBridgeProviderRegistry(storedRegistry);
|
|
109
|
+
const registry = await resolveBridgeProviderRegistry({
|
|
110
|
+
home,
|
|
111
|
+
registryPath: providerRegistryPath,
|
|
112
|
+
credentials: initialCredentials,
|
|
113
|
+
storedRegistry
|
|
114
|
+
});
|
|
115
|
+
assert.equal(registry.profiles['codex-lb'].state, 'ready');
|
|
116
|
+
assert.equal(registry.profiles.openrouter.state, 'ready');
|
|
117
|
+
assertSecretFree(JSON.stringify({ credentials: initialCredentials, registry }), allFixtureSecrets);
|
|
118
|
+
assertSecretFree(registryText, allFixtureSecrets);
|
|
119
|
+
const routeIndex = buildBridgeRouteIndex({
|
|
120
|
+
models: [],
|
|
121
|
+
providers: {
|
|
122
|
+
'codex-lb': {
|
|
123
|
+
catalog_generation: 'fixture-codex-lb-catalog',
|
|
124
|
+
credential_fingerprint: initialCredentials['codex-lb'].fingerprint,
|
|
125
|
+
state: initialCredentials['codex-lb'].state
|
|
126
|
+
},
|
|
127
|
+
openrouter: {
|
|
128
|
+
catalog_generation: 'fixture-openrouter-catalog',
|
|
129
|
+
credential_fingerprint: initialCredentials.openrouter.fingerprint,
|
|
130
|
+
state: initialCredentials.openrouter.state
|
|
131
|
+
}
|
|
132
|
+
},
|
|
133
|
+
created_at: '2026-08-06T00:00:00.000Z'
|
|
134
|
+
}).route_index;
|
|
135
|
+
const routePolicy = buildBridgeRoutingPolicy({
|
|
136
|
+
route_index: routeIndex,
|
|
137
|
+
catalog_generation: 'fixture-combined-catalog',
|
|
138
|
+
default_provider_id: intent.default_provider_id,
|
|
139
|
+
changed_at: '2026-08-06T00:00:00.000Z'
|
|
140
|
+
});
|
|
141
|
+
const routePolicyText = `${JSON.stringify(routePolicy, null, 2)}\n`;
|
|
142
|
+
assert.equal(routePolicy.fallback, 'none');
|
|
143
|
+
assert.deepEqual(routePolicy.model_routes, {});
|
|
144
|
+
const initialCodexLbBytes = await fs.readFile(codexLbEnvPath);
|
|
145
|
+
const initialOpenRouterBytes = await fs.readFile(openRouterPaths.keyPath);
|
|
146
|
+
const first = await migrateDesktopBridgeConfig({
|
|
147
|
+
home,
|
|
148
|
+
bridgeBaseUrl,
|
|
149
|
+
combinedCatalogPath,
|
|
150
|
+
metadataUpdates: [
|
|
151
|
+
{ kind: 'provider_registry', path: providerRegistryPath, text: registryText },
|
|
152
|
+
{ kind: 'route_policy', path: routePolicyPath, text: routePolicyText }
|
|
153
|
+
],
|
|
154
|
+
now: new Date('2026-08-06T00:01:00.000Z')
|
|
155
|
+
});
|
|
156
|
+
assert.equal(first.ok, true);
|
|
157
|
+
assert.equal(first.status, 'migrated');
|
|
158
|
+
assert.ok(first.receipt_path);
|
|
159
|
+
assert.deepEqual(await fs.readFile(authPath), Buffer.from(initialAuth));
|
|
160
|
+
assert.deepEqual(await fs.readFile(codexLbEnvPath), initialCodexLbBytes);
|
|
161
|
+
assert.deepEqual(await fs.readFile(openRouterPaths.keyPath), initialOpenRouterBytes);
|
|
162
|
+
const loadedPolicy = await readBridgeRoutingPolicy(routePolicyPath);
|
|
163
|
+
assert.deepEqual(loadedPolicy.blockers, []);
|
|
164
|
+
assert.equal(loadedPolicy.policy?.default_provider_id, 'codex-lb');
|
|
165
|
+
assert.equal(loadedPolicy.policy?.fallback, 'none');
|
|
166
|
+
assert.deepEqual(loadedPolicy.policy?.model_routes, {});
|
|
167
|
+
const migratedConfig = await fs.readFile(configPath, 'utf8');
|
|
168
|
+
const receiptText = await fs.readFile(first.receipt_path, 'utf8');
|
|
169
|
+
const receiptEntries = (await fs.readdir(path.dirname(first.receipt_path))).sort();
|
|
170
|
+
assertSecretFree(migratedConfig, allFixtureSecrets);
|
|
171
|
+
assertSecretFree(await fs.readFile(routePolicyPath, 'utf8'), allFixtureSecrets);
|
|
172
|
+
assertSecretFree(await fs.readFile(providerRegistryPath, 'utf8'), allFixtureSecrets);
|
|
173
|
+
assertSecretFree(receiptText, allFixtureSecrets);
|
|
174
|
+
assert.equal(receiptText.includes(clientCapability), false);
|
|
175
|
+
const second = await migrateDesktopBridgeConfig({
|
|
176
|
+
home,
|
|
177
|
+
bridgeBaseUrl,
|
|
178
|
+
combinedCatalogPath,
|
|
179
|
+
metadataUpdates: [
|
|
180
|
+
{ kind: 'provider_registry', path: providerRegistryPath, text: registryText },
|
|
181
|
+
{ kind: 'route_policy', path: routePolicyPath, text: routePolicyText }
|
|
182
|
+
],
|
|
183
|
+
now: new Date('2026-08-06T00:02:00.000Z')
|
|
184
|
+
});
|
|
185
|
+
assert.equal(second.ok, true);
|
|
186
|
+
assert.equal(second.status, 'already_migrated');
|
|
187
|
+
assert.equal(second.receipt_path, null);
|
|
188
|
+
assert.equal(await fs.readFile(configPath, 'utf8'), migratedConfig);
|
|
189
|
+
assert.deepEqual((await fs.readdir(path.dirname(first.receipt_path))).sort(), receiptEntries);
|
|
190
|
+
const rotatedAuth = authJson(rotatedOauthAccess, rotatedOauthRefresh);
|
|
191
|
+
await fs.writeFile(authPath, rotatedAuth, { mode: 0o600 });
|
|
192
|
+
await configureProviderCredential({
|
|
193
|
+
provider_id: 'codex-lb',
|
|
194
|
+
api_key: rotatedCodexLbKey,
|
|
195
|
+
host: codexLbEndpoint,
|
|
196
|
+
home,
|
|
197
|
+
processEnv: {}
|
|
198
|
+
});
|
|
199
|
+
await configureProviderCredential({
|
|
200
|
+
provider_id: 'openrouter',
|
|
201
|
+
api_key: rotatedOpenRouterKey,
|
|
202
|
+
home,
|
|
203
|
+
processEnv: { HOME: home },
|
|
204
|
+
openRouterPaths
|
|
205
|
+
});
|
|
206
|
+
const rollback = await rollbackDesktopBridgeUnificationReceipt({ receiptPath: first.receipt_path });
|
|
207
|
+
assert.equal(rollback.ok, true);
|
|
208
|
+
assert.equal(rollback.status, 'rolled_back');
|
|
209
|
+
assert.equal(rollback.credentials_overwritten, false);
|
|
210
|
+
assert.equal(rollback.auth_overwritten, false);
|
|
211
|
+
assert.equal(await fs.readFile(configPath, 'utf8'), historicalConfig);
|
|
212
|
+
await assert.rejects(fs.access(routePolicyPath));
|
|
213
|
+
await assert.rejects(fs.access(providerRegistryPath));
|
|
214
|
+
assert.equal(await fs.readFile(authPath, 'utf8'), rotatedAuth);
|
|
215
|
+
const rotatedCredentials = await resolveAllProviderCredentials({
|
|
216
|
+
codexLb: { home, processEnv: {} },
|
|
217
|
+
openrouter: { processEnv: { HOME: home }, openRouterPaths }
|
|
218
|
+
});
|
|
219
|
+
assert.equal(rotatedCredentials['codex-lb'].secret, rotatedCodexLbKey);
|
|
220
|
+
assert.equal(rotatedCredentials.openrouter.secret, rotatedOpenRouterKey);
|
|
221
|
+
assertSecretFree(await fs.readFile(first.receipt_path, 'utf8'), allFixtureSecrets);
|
|
222
|
+
const retiredCommand = normalizeCommand(['codex-lb', 'status']);
|
|
223
|
+
assert.equal(retiredCommand.command, null);
|
|
224
|
+
assert.equal(retiredCommand.aliasTarget, null);
|
|
225
|
+
assert.equal(Object.hasOwn(COMMAND_ALIASES_LITE, 'codex-lb'), false);
|
|
226
|
+
assert.equal(Object.hasOwn(COMMAND_MANIFEST_BY_NAME, 'codex-lb'), false);
|
|
227
|
+
emitGate('desktop-bridge:unification', {
|
|
228
|
+
evidence_kind: 'hermetic_fixture',
|
|
229
|
+
fixture: true,
|
|
230
|
+
real_execution: false,
|
|
231
|
+
real_evidence_claimed: false,
|
|
232
|
+
checks: {
|
|
233
|
+
dual_credentials_coexist: true,
|
|
234
|
+
serialized_metadata_secret_free: true,
|
|
235
|
+
historical_config_migration_idempotent: true,
|
|
236
|
+
rollback_preserves_rotated_credentials_and_oauth: true,
|
|
237
|
+
retired_codex_lb_command_unknown_without_alias: true,
|
|
238
|
+
fallback_route_absent: true
|
|
239
|
+
},
|
|
240
|
+
limitations: [
|
|
241
|
+
'Temporary-home fixture evidence only; this does not prove a live Codex Desktop or provider execution.'
|
|
242
|
+
]
|
|
243
|
+
});
|
|
244
|
+
}
|
|
245
|
+
catch (error) {
|
|
246
|
+
failed = error;
|
|
247
|
+
}
|
|
248
|
+
finally {
|
|
249
|
+
await fs.rm(temporaryRoot, { recursive: true, force: true });
|
|
250
|
+
}
|
|
251
|
+
if (failed) {
|
|
252
|
+
const message = failed instanceof Error ? failed.message : String(failed);
|
|
253
|
+
console.error(JSON.stringify({
|
|
254
|
+
schema: 'sks.release-gate.v1',
|
|
255
|
+
ok: false,
|
|
256
|
+
gate: 'desktop-bridge:unification',
|
|
257
|
+
evidence_kind: 'hermetic_fixture',
|
|
258
|
+
fixture: true,
|
|
259
|
+
real_execution: false,
|
|
260
|
+
real_evidence_claimed: false,
|
|
261
|
+
blocker: message
|
|
262
|
+
}, null, 2));
|
|
263
|
+
process.exitCode = 1;
|
|
264
|
+
}
|
|
265
|
+
function authJson(accessToken, refreshToken) {
|
|
266
|
+
return `${JSON.stringify({
|
|
267
|
+
auth_mode: 'chatgpt',
|
|
268
|
+
account_id: 'fixture-desktop-account',
|
|
269
|
+
tokens: { access_token: accessToken, refresh_token: refreshToken }
|
|
270
|
+
}, null, 2)}\n`;
|
|
271
|
+
}
|
|
272
|
+
function assertSecretFree(text, secrets) {
|
|
273
|
+
assert.equal(text.includes('"secret"'), false);
|
|
274
|
+
for (const secret of secrets)
|
|
275
|
+
assert.equal(text.includes(secret), false);
|
|
276
|
+
}
|
|
@@ -30,23 +30,27 @@ const unsafePlan = await repairCodexAppFastUi(unsafeRoot, { codexHome: unsafeCod
|
|
|
30
30
|
const unsafeAfter = await fs.readFile(path.join(unsafeCodexHome, 'config.toml'), 'utf8');
|
|
31
31
|
const ok = plan.fast_selector === 'manual_action_required'
|
|
32
32
|
&& plan.provider_selector === 'manual_action_required'
|
|
33
|
-
&& plan.selected_provider_blockers.includes('
|
|
34
|
-
&& plan.selected_provider_blockers.includes('
|
|
35
|
-
&& plan.
|
|
36
|
-
&& plan.provider_actions.includes('sks
|
|
33
|
+
&& plan.selected_provider_blockers.includes('bridge_active_route_not_selected')
|
|
34
|
+
&& plan.selected_provider_blockers.includes('combined_catalog_active_generation_missing')
|
|
35
|
+
&& plan.selected_provider_blockers.includes('bridge_route_policy_missing')
|
|
36
|
+
&& plan.provider_actions.includes('sks bridge provider configure')
|
|
37
|
+
&& plan.provider_actions.includes('sks bridge provider validate')
|
|
38
|
+
&& plan.provider_actions.includes('sks bridge provider enable')
|
|
39
|
+
&& plan.provider_actions.includes('sks bridge catalog sync')
|
|
40
|
+
&& plan.provider_actions.includes('sks bridge route set-default')
|
|
37
41
|
&& plan.safe_auto_apply === true
|
|
38
42
|
&& repaired.fast_selector === 'repaired'
|
|
39
43
|
&& repaired.provider_selector === 'manual_action_required'
|
|
40
|
-
&& repaired.selected_provider_blockers.includes('
|
|
41
|
-
&& repaired.selected_provider_blockers.includes('
|
|
42
|
-
&& repaired.selected_provider_blockers.includes('
|
|
44
|
+
&& repaired.selected_provider_blockers.includes('bridge_active_route_not_selected')
|
|
45
|
+
&& repaired.selected_provider_blockers.includes('combined_catalog_active_generation_missing')
|
|
46
|
+
&& repaired.selected_provider_blockers.includes('bridge_route_policy_missing')
|
|
43
47
|
&& repaired.safe_auto_apply === true
|
|
44
48
|
&& backups.length >= 1
|
|
45
49
|
&& /^model\s*=\s*"future-codex-model"$/m.test(projectAfter.split(/\n\s*\[/)[0] || '')
|
|
46
50
|
&& /^model_reasoning_effort\s*=\s*"medium"$/m.test(projectAfter.split(/\n\s*\[/)[0] || '')
|
|
47
51
|
&& !/^model\s*=/m.test(homeTopLevel)
|
|
48
52
|
&& !/^model_reasoning_effort\s*=/m.test(homeTopLevel)
|
|
49
|
-
&&
|
|
53
|
+
&& !/^model_provider\s*=/m.test(homeTopLevel)
|
|
50
54
|
&& /model_provider\s*=\s*"codex-lb"/.test(projectAfter)
|
|
51
55
|
&& /^service_tier\s*=\s*"fast"$/m.test(homeTopLevel)
|
|
52
56
|
&& /fast_mode = false/.test(homeAfter)
|
|
@@ -18,8 +18,6 @@ const splitReviewFiles = [
|
|
|
18
18
|
'src/core/recallpulse.ts'
|
|
19
19
|
];
|
|
20
20
|
const policyCallsiteAllowlist = new Map([
|
|
21
|
-
['codex_config_write|src/cli/install-helpers-codex-lb-selftest-chain.ts|runCodexLbLaunchChainSelftest|writeTextAtomic', 'isolated launch-chain selftest config'],
|
|
22
|
-
['codex_config_write|src/cli/install-helpers-codex-lb-selftest.ts|selftestCodexLb|writeTextAtomic', 'isolated Codex LB selftest config'],
|
|
23
21
|
['mkdtemp|src/core/codex-control/codex-sdk-env-policy.ts|prepareNativeCodexAuthBridge|mkdtemp', 'identity-checked 0700 OAuth bridge root with explicit cleanup proof'],
|
|
24
22
|
['mkdtemp|src/core/mcp-config/codex-cli-adapter.ts|CodexMcpCliAdapter|mkdtemp', 'isolated official CLI transform HOME'],
|
|
25
23
|
['mkdtemp|src/core/perf/release-latency-slo.ts|runReleaseLatencySlo|mkdtemp', 'run-local latency fixture root'],
|
|
@@ -39,6 +37,7 @@ const directCodexConfigWrites = scanDirectCodexConfigWrites();
|
|
|
39
37
|
const commandGateContract = scanCommandGateContract();
|
|
40
38
|
const directMkdtempCalls = scanDirectMkdtempCalls();
|
|
41
39
|
const rustTempdirCalls = scanRustTempdirCalls();
|
|
40
|
+
const releaseEvidenceArchitecture = scanReleaseEvidenceArchitecture();
|
|
42
41
|
const unusedPolicyCallsiteAllowlist = [...policyCallsiteAllowlist.keys()].filter((key) => !policyCallsiteAllowlistHits.has(key));
|
|
43
42
|
if (releaseGates.length > 200)
|
|
44
43
|
blockers.push(`release_preset_gate_budget_exceeded:${releaseGates.length}`);
|
|
@@ -61,6 +60,8 @@ if (directMkdtempCalls.length)
|
|
|
61
60
|
blockers.push(`direct_mkdtemp_callsite:${directMkdtempCalls[0].file}:${directMkdtempCalls[0].line}`);
|
|
62
61
|
if (rustTempdirCalls.length)
|
|
63
62
|
blockers.push(`rust_tempdir_without_raii:${rustTempdirCalls[0].file}:${rustTempdirCalls[0].line}`);
|
|
63
|
+
if (!releaseEvidenceArchitecture.ok)
|
|
64
|
+
blockers.push(`release_evidence_architecture:${releaseEvidenceArchitecture.issues[0]}`);
|
|
64
65
|
if (unusedPolicyCallsiteAllowlist.length)
|
|
65
66
|
blockers.push(`unused_policy_callsite_allowlist:${unusedPolicyCallsiteAllowlist[0]}`);
|
|
66
67
|
for (const row of splitReviewLineCounts) {
|
|
@@ -82,8 +83,57 @@ const result = {
|
|
|
82
83
|
direct_mkdtemp_callsites: directMkdtempCalls.slice(0, 20),
|
|
83
84
|
policy_callsite_allowlist: { used: policyCallsiteAllowlistHits.size, unused: unusedPolicyCallsiteAllowlist },
|
|
84
85
|
rust_tempdir_raii: { ok: rustTempdirCalls.length === 0, direct_tempdir_callsites: rustTempdirCalls.slice(0, 20) },
|
|
86
|
+
release_evidence_architecture: releaseEvidenceArchitecture,
|
|
85
87
|
blockers
|
|
86
88
|
};
|
|
89
|
+
function scanReleaseEvidenceArchitecture() {
|
|
90
|
+
const issues = [];
|
|
91
|
+
const recovery = gates.find((gate) => gate.id === 'test:codex-runtime-recovery');
|
|
92
|
+
const recoveryInputs = Array.isArray(recovery?.cache?.inputs) ? recovery.cache.inputs.map(String) : [];
|
|
93
|
+
if (!recoveryInputs.includes('src/commands/bridge.ts'))
|
|
94
|
+
issues.push('recovery_cache_missing_active_bridge_command');
|
|
95
|
+
if (recoveryInputs.includes('src/commands/codex-lb.ts'))
|
|
96
|
+
issues.push('recovery_cache_references_retired_bridge_command');
|
|
97
|
+
const runtime = fs.readFileSync(path.join(root, 'runtime-required-scripts.json'), 'utf8');
|
|
98
|
+
const packageJson = fs.readFileSync(path.join(root, 'package.json'), 'utf8');
|
|
99
|
+
const manifest = fs.readFileSync(path.join(root, 'release-gates.v2.json'), 'utf8');
|
|
100
|
+
const retiredCatalogScript = 'codex-lb-catalog-passthrough-check.js';
|
|
101
|
+
if ([runtime, packageJson, manifest].some((text) => text.includes(retiredCatalogScript)))
|
|
102
|
+
issues.push('retired_catalog_passthrough_reference_present');
|
|
103
|
+
if (!runtime.includes('dist/scripts/release-physical-gates-check.js'))
|
|
104
|
+
issues.push('physical_gate_validator_missing_from_runtime_closure');
|
|
105
|
+
if (!packageJson.includes('release-physical-gates-check.js'))
|
|
106
|
+
issues.push('physical_gate_validator_missing_from_package_files');
|
|
107
|
+
const realCheck = fs.readFileSync(path.join(root, 'src', 'scripts', 'release-real-check.ts'), 'utf8');
|
|
108
|
+
if (!/nodeScript\(\s*['"]release-physical-gates-check\.js['"]/.test(realCheck)
|
|
109
|
+
|| !realCheck.includes("'sks.release-physical-gates-inspection.v2'"))
|
|
110
|
+
issues.push('release_real_check_not_bound_to_physical_inspection');
|
|
111
|
+
const workflow = fs.readFileSync(path.join(root, '.github', 'workflows', 'publish-npm.yml'), 'utf8');
|
|
112
|
+
const linux = workflow.slice(workflow.indexOf(' linux-release-proof:'), workflow.indexOf(' macos-menubar-proof:'));
|
|
113
|
+
const macos = workflow.slice(workflow.indexOf(' macos-menubar-proof:'), workflow.indexOf(' pack-and-compare:'));
|
|
114
|
+
if (linux.includes('release-physical-gates-check.js') || linux.includes('release:check:full'))
|
|
115
|
+
issues.push('linux_claims_macos_release_evidence');
|
|
116
|
+
const macosProofSequence = [
|
|
117
|
+
'npm run build:clean --silent',
|
|
118
|
+
'npm run test:release --silent',
|
|
119
|
+
'release-gate-dag-runner.js --preset release --full',
|
|
120
|
+
'release-physical-gates-check.js',
|
|
121
|
+
'release-real-check.js --skip-release-check',
|
|
122
|
+
'release-check-stamp.js write'
|
|
123
|
+
];
|
|
124
|
+
const macosProofPositions = macosProofSequence.map((required) => macos.indexOf(required));
|
|
125
|
+
for (const required of macosProofSequence) {
|
|
126
|
+
if (!macos.includes(required))
|
|
127
|
+
issues.push(`macos_release_evidence_step_missing:${required}`);
|
|
128
|
+
}
|
|
129
|
+
if (macosProofPositions.every((position) => position >= 0)
|
|
130
|
+
&& macosProofPositions.some((position, index) => index > 0 && position <= macosProofPositions[index - 1])) {
|
|
131
|
+
issues.push('macos_release_evidence_sequence_invalid');
|
|
132
|
+
}
|
|
133
|
+
if (!workflow.includes('--require-physical-proof'))
|
|
134
|
+
issues.push('main_push_guard_does_not_require_physical_proof');
|
|
135
|
+
return { ok: issues.length === 0, issues, recovery_cache_inputs: recoveryInputs };
|
|
136
|
+
}
|
|
87
137
|
console.log(JSON.stringify(result, null, 2));
|
|
88
138
|
if (!result.ok)
|
|
89
139
|
process.exit(1);
|
|
@@ -2,22 +2,65 @@
|
|
|
2
2
|
import fs from 'node:fs/promises';
|
|
3
3
|
import os from 'node:os';
|
|
4
4
|
import path from 'node:path';
|
|
5
|
-
import { providerBadgeText } from '../core/provider/provider-badge.js';
|
|
5
|
+
import { providerBadgeText, providerPaneLabel } from '../core/provider/provider-badge.js';
|
|
6
6
|
import { resolveProviderContext } from '../core/provider/provider-context.js';
|
|
7
|
-
const root = await fs.mkdtemp(path.join(os.tmpdir(), 'sks-provider-
|
|
7
|
+
const root = await fs.mkdtemp(path.join(os.tmpdir(), 'sks-provider-badge-'));
|
|
8
8
|
const codexHome = path.join(root, '.codex-home');
|
|
9
9
|
await fs.mkdir(codexHome, { recursive: true });
|
|
10
10
|
await fs.writeFile(path.join(codexHome, 'auth.json'), '{"account_id":"acct_fixture"}\n');
|
|
11
|
-
const
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
11
|
+
const bridge = await resolveProviderContext({
|
|
12
|
+
root,
|
|
13
|
+
codexHome,
|
|
14
|
+
env: { HOME: root, CODEX_LB_API_KEY: 'lb-fixture' },
|
|
15
|
+
route: '$Naruto',
|
|
16
|
+
serviceTier: 'fast',
|
|
17
|
+
desktopBridgeStatus: bridgeStatus('codex-lb')
|
|
18
|
+
});
|
|
19
|
+
const openai = await resolveProviderContext({
|
|
20
|
+
root,
|
|
21
|
+
codexHome,
|
|
22
|
+
env: { OPENAI_API_KEY: 'sk-fixture', HOME: root },
|
|
23
|
+
serviceTier: 'fast',
|
|
24
|
+
desktopBridgeStatus: unmanagedStatus()
|
|
25
|
+
});
|
|
26
|
+
const app = await resolveProviderContext({
|
|
27
|
+
root,
|
|
28
|
+
codexHome,
|
|
29
|
+
env: { HOME: root },
|
|
30
|
+
serviceTier: 'standard',
|
|
31
|
+
desktopBridgeStatus: unmanagedStatus()
|
|
32
|
+
});
|
|
33
|
+
const checks = {
|
|
34
|
+
bridge_badge: providerBadgeText(bridge) === 'Provider: Desktop Bridge → codex-lb · Fast',
|
|
35
|
+
bridge_pane: providerPaneLabel(bridge) === 'fast · desktop-bridge/codex-lb',
|
|
36
|
+
openai_badge: providerBadgeText(openai) === 'Provider: OpenAI API · Fast',
|
|
37
|
+
oauth_badge: providerBadgeText(app) === 'Provider: Codex App OAuth · Standard'
|
|
38
|
+
};
|
|
39
|
+
const ok = Object.values(checks).every(Boolean);
|
|
40
|
+
emit({ schema: 'sks.provider-badge-context-check.v2', ok, checks, bridge, openai, app, blockers: ok ? [] : ['provider_badge_context_check_failed'] });
|
|
41
|
+
function bridgeStatus(provider) {
|
|
42
|
+
return {
|
|
43
|
+
schema: 'sks.desktop-bridge-status.v3',
|
|
44
|
+
management: { managed: true, runtime: 'desktop-bridge', state: 'ready', reason: null },
|
|
45
|
+
native_identity: { configured: true },
|
|
46
|
+
providers: {
|
|
47
|
+
'codex-lb': { credential: { state: provider === 'codex-lb' ? 'ready' : 'not_configured' } },
|
|
48
|
+
openrouter: { credential: { state: provider === 'openrouter' ? 'ready' : 'not_configured' } }
|
|
49
|
+
},
|
|
50
|
+
routing: { policy: { default_provider_id: provider }, selected_route: null, session_pin: null, blockers: [] },
|
|
51
|
+
readiness: { ready: true, blockers: [] }
|
|
52
|
+
};
|
|
53
|
+
}
|
|
54
|
+
function unmanagedStatus() {
|
|
55
|
+
return {
|
|
56
|
+
schema: 'sks.desktop-bridge-status.v3',
|
|
57
|
+
management: { managed: false, runtime: null, state: 'not_installed', reason: 'never_configured' },
|
|
58
|
+
native_identity: { configured: true },
|
|
59
|
+
providers: {},
|
|
60
|
+
routing: { policy: null, selected_route: null, session_pin: null, blockers: [] },
|
|
61
|
+
readiness: { ready: false, blockers: [] }
|
|
62
|
+
};
|
|
63
|
+
}
|
|
21
64
|
function emit(report) {
|
|
22
65
|
console.log(JSON.stringify(report, null, 2));
|
|
23
66
|
if (!report.ok)
|
|
@@ -3,10 +3,9 @@ import path from 'node:path';
|
|
|
3
3
|
import { fileURLToPath } from 'node:url';
|
|
4
4
|
import { inspectPublishPreflight } from '../core/release/publish-preflight.js';
|
|
5
5
|
const root = path.resolve(path.dirname(fileURLToPath(import.meta.url)), '..', '..');
|
|
6
|
-
const dryRun = ['1', 'true'].includes(String(process.env.npm_config_dry_run || process.env.NPM_CONFIG_DRY_RUN || '').toLowerCase());
|
|
7
6
|
const report = inspectPublishPreflight({
|
|
8
7
|
root,
|
|
9
|
-
requireReleaseTag:
|
|
8
|
+
requireReleaseTag: false,
|
|
10
9
|
requirePhysicalReleaseGates: false,
|
|
11
10
|
});
|
|
12
11
|
console.log(JSON.stringify(report, null, 2));
|
|
@@ -46,12 +46,11 @@ const officialSubagentOnly = selectorMod.selectAffectedReleaseGates(root, manife
|
|
|
46
46
|
const officialSubagentIds = new Set(officialSubagentOnly.selection.selected_gate_ids.map(String));
|
|
47
47
|
assertGate(officialSubagentIds.has('naruto:canonical-stop-gate'), 'official subagent source changes must select the canonical Naruto stop gate', officialSubagentOnly.selection);
|
|
48
48
|
for (const changedFile of [
|
|
49
|
-
'src/core/codex-
|
|
49
|
+
'src/core/codex-control/desktop-bridge-launch-guard.ts',
|
|
50
50
|
'src/core/codex/codex-cli-update.ts',
|
|
51
51
|
'src/core/codex-control/codex-reliability-shield.ts',
|
|
52
52
|
'src/core/hooks-runtime.ts',
|
|
53
53
|
'src/commands/codex.ts',
|
|
54
|
-
'src/commands/codex-lb.ts',
|
|
55
54
|
'src/commands/doctor.ts',
|
|
56
55
|
'src/core/preflight/parallel-preflight-engine.ts'
|
|
57
56
|
]) {
|
|
@@ -6,7 +6,7 @@ const governor = await importDist('core/release/release-gate-resource-governor.j
|
|
|
6
6
|
const budget = governor.defaultReleaseGateBudget();
|
|
7
7
|
assertGate(budget['cpu-light'] >= 1 && budget['cpu-light'] <= 4, 'resource governor env requests must not raise the desktop-safe cpu-light cap', budget);
|
|
8
8
|
assertGate(governor.defaultReleaseGateMaxTotal() >= 1 && governor.defaultReleaseGateMaxTotal() <= 4, 'resource governor default total cap must stay desktop-safe', { max_total: governor.defaultReleaseGateMaxTotal() });
|
|
9
|
-
const gate = (id) => ({ id, resource: ['cpu-light'], deps: [], command: 'true', side_effect: 'hermetic', timeout_ms: 1000, cache: { enabled: false, inputs: [] }, isolation: { report_dir: 'per-gate' }, preset: ['release'] });
|
|
9
|
+
const gate = (id) => ({ id, resource: ['cpu-light'], deps: [], command: 'true', side_effect: 'hermetic', timeout_ms: 1000, output_contract: 'sks.gate-result.v2', cache: { enabled: false, inputs: [] }, isolation: { report_dir: 'per-gate' }, preset: ['release'] });
|
|
10
10
|
const fsGate = (id) => ({ ...gate(id), resource: ['fs-read'] });
|
|
11
11
|
const timingGate = (id) => ({ ...gate(id), resource: ['timing-sensitive'] });
|
|
12
12
|
const picked = governor.pickLaunchableReleaseGates({ ready: [gate('a'), gate('b'), gate('c')], running: [], budget });
|
|
@@ -17,6 +17,7 @@ const gate = {
|
|
|
17
17
|
resource: ['cpu-light'],
|
|
18
18
|
side_effect: 'hermetic',
|
|
19
19
|
timeout_ms: 1000,
|
|
20
|
+
output_contract: 'sks.gate-result.v2',
|
|
20
21
|
cache: { enabled: true, inputs: ['src/core/release/**'] },
|
|
21
22
|
isolation: { home: 'temp', codex_home: 'temp', report_dir: 'per-gate' },
|
|
22
23
|
preset: ['release']
|
|
@@ -11,6 +11,7 @@ const gate = {
|
|
|
11
11
|
resource: ['cpu-light'],
|
|
12
12
|
side_effect: 'hermetic',
|
|
13
13
|
timeout_ms: 1000,
|
|
14
|
+
output_contract: 'sks.gate-result.v2',
|
|
14
15
|
cache: { enabled: true, inputs: ['package.json', 'package-lock.json', 'src/**', 'dist/build-manifest.json'] },
|
|
15
16
|
isolation: { home: 'temp', codex_home: 'temp', report_dir: 'per-gate' },
|
|
16
17
|
preset: ['release']
|
|
@@ -6,7 +6,7 @@ import { performance } from 'node:perf_hooks';
|
|
|
6
6
|
import { runReleaseGateBatch } from '../core/release/release-gate-batch-runner.js';
|
|
7
7
|
import { assertGate, emitGate, root } from './gate-lib.js';
|
|
8
8
|
const reportRoot = await fs.mkdtemp(path.join(os.tmpdir(), 'sks-release-full-'));
|
|
9
|
-
const gates = Array.from({ length: 80 }, (_, i) => ({ id: `synthetic:${i + 1}`, command: `${process.execPath} -e \"setTimeout(()=>process.exit(0),1000)\"`, deps: [], resource: ['cpu-light', 'fs-read'], side_effect: 'hermetic', timeout_ms: 15000, cache: { enabled: false, inputs: [] }, isolation: { home: 'temp', codex_home: 'temp', report_dir: 'per-gate' }, preset: ['release'] }));
|
|
9
|
+
const gates = Array.from({ length: 80 }, (_, i) => ({ id: `synthetic:${i + 1}`, command: `${process.execPath} -e \"setTimeout(()=>process.exit(0),1000)\"`, deps: [], resource: ['cpu-light', 'fs-read'], side_effect: 'hermetic', timeout_ms: 15000, output_contract: 'sks.gate-result.v2', cache: { enabled: false, inputs: [] }, isolation: { home: 'temp', codex_home: 'temp', report_dir: 'per-gate' }, preset: ['release'] }));
|
|
10
10
|
const started = performance.now();
|
|
11
11
|
const result = await runReleaseGateBatch(root, gates, { concurrency: 40, reportRoot });
|
|
12
12
|
const wallMs = Math.max(1, Math.round(performance.now() - started));
|
|
@@ -13,6 +13,7 @@ const base = {
|
|
|
13
13
|
resource: ['cpu-light', 'fs-read'],
|
|
14
14
|
side_effect: 'hermetic',
|
|
15
15
|
timeout_ms: 30000,
|
|
16
|
+
output_contract: 'sks.gate-result.v2',
|
|
16
17
|
cache: { enabled: false, inputs: [] },
|
|
17
18
|
isolation: { home: 'temp', codex_home: 'temp', report_dir: 'per-gate' },
|
|
18
19
|
preset: ['release']
|
|
@@ -27,6 +28,11 @@ const envProofScript = [
|
|
|
27
28
|
].join(';');
|
|
28
29
|
const passGate = { ...base, id: 'batch:pass', command: `${process.execPath} -e ${JSON.stringify(envProofScript)}` };
|
|
29
30
|
const failGate = { ...base, id: 'batch:fail', command: `${process.execPath} -e "process.exit(7)"` };
|
|
31
|
+
const contractFailGate = {
|
|
32
|
+
...base,
|
|
33
|
+
id: 'batch:contract-fail',
|
|
34
|
+
command: `${process.execPath} -e ${JSON.stringify("console.log(JSON.stringify({schema:'sks.gate-result.v2',contract_mode:'strict',ok:false,blockers:['batch_child_blocker']}))")}`
|
|
35
|
+
};
|
|
30
36
|
const timeoutGate = { ...base, id: 'batch:timeout', timeout_ms: 50, command: `${process.execPath} -e "process.on('SIGTERM', () => {}); setInterval(() => {}, 1000)"` };
|
|
31
37
|
const browserGate = { ...base, id: 'batch:browser-real', resource: ['browser-real'], side_effect: 'real-env', command: `${process.execPath} -e "process.exit(0)"` };
|
|
32
38
|
assertGate(batch.isReleaseGateBatchable(passGate) === true, 'hermetic cpu-light fs-read gate must be batchable');
|
|
@@ -36,6 +42,9 @@ assertGate(result.ok === false && result.failed === 1, 'one failed child gate mu
|
|
|
36
42
|
assertGate(result.results.some((row) => row.id === 'batch:fail' && row.ok === false && row.exit_code === 7), 'batch result must report exact failed child id', result);
|
|
37
43
|
assertGate(fs.existsSync(path.join(reportRoot, 'batch-pass', 'result.json')) && fs.existsSync(path.join(reportRoot, 'batch-fail', 'result.json')), 'batch runner must preserve individual result JSON files');
|
|
38
44
|
assertGate(result.results.some((row) => row.id === 'batch:pass' && row.ok === true), 'batch runner must execute children with hermetic release-gate environment', result);
|
|
45
|
+
assertGate(result.results.every((row) => row.output_contract === 'sks.gate-result.v2' && row.gate_result?.contract_mode === 'strict'), 'batch children must publish the strict current gate-result contract', result);
|
|
46
|
+
const contractFailResult = await batch.runReleaseGateBatch(root, [contractFailGate], { concurrency: 1, reportRoot });
|
|
47
|
+
assertGate(contractFailResult.ok === false && contractFailResult.results[0]?.gate_result?.blockers?.includes('batch_child_blocker'), 'strict child ok:false must fail the batch even with exit zero', contractFailResult);
|
|
39
48
|
const timeoutResult = await batch.runReleaseGateBatch(root, [timeoutGate], { concurrency: 1, reportRoot });
|
|
40
49
|
assertGate(timeoutResult.results.some((row) => row.id === 'batch:timeout' && row.ok === false && row.exit_code === 124 && row.timed_out === true), 'batch runner must report timed-out child process trees explicitly', timeoutResult);
|
|
41
50
|
assertGate(timeoutResult.results.some((row) => row.id === 'batch:timeout' && row.duration_ms >= 1400), 'batch runner must wait for timed-out process tree hard-kill cleanup before resolving', timeoutResult);
|
|
@@ -10,6 +10,7 @@ const runnerCli = readText('src/scripts/release-gate-dag-runner.ts');
|
|
|
10
10
|
const hermeticEnv = readText('src/core/release/release-gate-hermetic-env.ts');
|
|
11
11
|
const scheduler = readText('src/core/release/release-gate-scheduler.ts');
|
|
12
12
|
const cache = readText('src/core/release/release-gate-cache-v2.ts');
|
|
13
|
+
const retiredContractNoteField = ['contract', 'note'].join('_');
|
|
13
14
|
const releaseCheck = String(pkg.scripts['release:check'] || '');
|
|
14
15
|
const delegatedReleaseCheck = releaseCheck.match(/^npm run ([^\s&]+)(?:\s+--silent)?$/)?.[1];
|
|
15
16
|
const effectiveReleaseCheck = delegatedReleaseCheck ? String(pkg.scripts[delegatedReleaseCheck] || '') : releaseCheck;
|
|
@@ -19,6 +20,7 @@ assertGate(!/&&\s*npm run\s+\w/.test(effectiveReleaseCheck.replace('npm run buil
|
|
|
19
20
|
assertGate(!pkg.scripts['release:check:legacy'], 'retired release:check:legacy alias must stay removed');
|
|
20
21
|
assertGate(pkg.scripts['release:real-check'] === 'node ./dist/scripts/release-real-check.js', 'release:real-check must expose the canonical environment-dependent proof runner');
|
|
21
22
|
assertGate(manifest.schema === 'sks.release-gates.v2' && manifest.gates.length >= 10, 'release-gates.v2 manifest must exist with nodes', manifest);
|
|
23
|
+
assertGate(manifest.gates.every((row) => row.output_contract === 'sks.gate-result.v2' && !Object.hasOwn(row, retiredContractNoteField)), 'every release gate must declare only the strict current output contract', manifest.gates.filter((row) => row.output_contract !== 'sks.gate-result.v2' || Object.hasOwn(row, retiredContractNoteField)).map((row) => row.id));
|
|
22
24
|
for (const gateId of [
|
|
23
25
|
'scheduler:comprehensive',
|
|
24
26
|
'doctor:fix-proves-codex-read',
|
|
@@ -33,6 +35,8 @@ assertGate(runner.includes('readReleaseGateCacheRecord') && cache.includes('dura
|
|
|
33
35
|
assertGate(runner.includes('cpu_time_saved_ms') && runner.includes('peak_running') && runner.includes('budget_snapshot'), 'DAG summary must include CPU time saved, peak running gates, and resource budget proof');
|
|
34
36
|
assertGate(runner.includes('sks.five-minute-completion-certificate.v1') && runner.includes('sks.affected-gate-graph.v1') && cache.includes('releaseGateProofBankFile'), 'DAG runner must emit completion certificates, affected graph, and proof-bank cache path');
|
|
35
37
|
assertGate(runner.includes('detached: process.platform') && runner.includes('killGateProcessTree') && runner.includes('timed_out'), 'DAG runner must kill timed-out gate process trees and record timeout evidence');
|
|
38
|
+
assertGate(runner.includes('normalizeReleaseGateOutput') && runner.includes('gate_result: normalized.gate_result'), 'DAG runner must normalize and verify every child through the strict gate-result contract');
|
|
39
|
+
assertGate(runnerCli.includes('GATE_RESULT_CONTRACT_MODE') && runnerCli.includes('contract_mode: GATE_RESULT_CONTRACT_MODE'), 'DAG CLI must emit the strict current gate-result contract');
|
|
36
40
|
assertGate(runner.includes('pruneOldReleaseGateRunDirs') && runner.includes('SKS_RELEASE_GATE_RUN_RETENTION'), 'DAG runner must prune stale release-gate run reports before they exhaust local disk');
|
|
37
41
|
assertGate(runnerCli.includes('ensureCurrentMigrationBeforeCommand') && runnerCli.includes('release-gate-runner-preflight'), 'DAG runner CLI must self-heal project migration before hermetic gates run');
|
|
38
42
|
assertGate(hermeticEnv.includes('SKS_UPDATE_MIGRATION_GATE_DISABLED'), 'hermetic release gates must not rewrite project migration receipts from temporary HOME roots');
|
|
@@ -51,6 +55,7 @@ await fsx.writeJsonAtomic(path.join(fixtureRoot, 'release-gates.v2.json'), {
|
|
|
51
55
|
resource: ['cpu-light', 'fs-read'],
|
|
52
56
|
side_effect: 'hermetic',
|
|
53
57
|
timeout_ms: 50,
|
|
58
|
+
output_contract: 'sks.gate-result.v2',
|
|
54
59
|
cache: { enabled: false, inputs: [] },
|
|
55
60
|
isolation: { home: 'temp', codex_home: 'temp', report_dir: 'per-gate' },
|
|
56
61
|
preset: ['release']
|
|
@@ -74,6 +79,7 @@ await fsx.writeJsonAtomic(path.join(cacheRoot, 'release-gates.v2.json'), {
|
|
|
74
79
|
resource: ['cpu-light', 'fs-read'],
|
|
75
80
|
side_effect: 'hermetic',
|
|
76
81
|
timeout_ms: 5000,
|
|
82
|
+
output_contract: 'sks.gate-result.v2',
|
|
77
83
|
cache: { enabled: true, inputs: [] },
|
|
78
84
|
isolation: { home: 'temp', codex_home: 'temp', report_dir: 'per-gate' },
|
|
79
85
|
preset: ['release']
|