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,104 @@
|
|
|
1
|
+
import { EVIDENCE_SOURCES, LEVELS, PROBE_STAGES, PROBE_STATES, booleanValue, enumValue, escapePath, exact, integer, iso, literal, nonEmptyString, nullableString, object, stringArray } from './shared.js';
|
|
2
|
+
export function validateExecution(value, path, issues) {
|
|
3
|
+
const row = object(value, path, issues);
|
|
4
|
+
if (!row)
|
|
5
|
+
return;
|
|
6
|
+
exact(row, path, ['ok', 'status', 'blockers'], issues);
|
|
7
|
+
booleanValue(row.ok, `${path}.ok`, issues);
|
|
8
|
+
enumValue(row.status, new Set(['completed', 'partial', 'failed']), `${path}.status`, issues);
|
|
9
|
+
stringArray(row.blockers, `${path}.blockers`, issues);
|
|
10
|
+
if (row.ok === true && row.status === 'failed')
|
|
11
|
+
issues.push(`${path}:execution_state_inconsistent`);
|
|
12
|
+
if (row.ok === false && row.status !== 'failed')
|
|
13
|
+
issues.push(`${path}:execution_state_inconsistent`);
|
|
14
|
+
}
|
|
15
|
+
export function validateScope(value, expectedScope, report, path, issues) {
|
|
16
|
+
const row = object(value, path, issues);
|
|
17
|
+
if (!row)
|
|
18
|
+
return;
|
|
19
|
+
exact(row, path, ['schema', 'scope', 'state', 'checked_at', 'capabilities', 'blockers', 'warnings'], issues);
|
|
20
|
+
literal(row.schema, 'sks.scope-capability-summary.v1', `${path}.schema`, issues);
|
|
21
|
+
literal(row.scope, expectedScope, `${path}.scope`, issues);
|
|
22
|
+
enumValue(row.state, PROBE_STATES, `${path}.state`, issues);
|
|
23
|
+
iso(row.checked_at, `${path}.checked_at`, issues);
|
|
24
|
+
stringArray(row.blockers, `${path}.blockers`, issues);
|
|
25
|
+
stringArray(row.warnings, `${path}.warnings`, issues);
|
|
26
|
+
const capabilities = object(row.capabilities, `${path}.capabilities`, issues);
|
|
27
|
+
if (!capabilities)
|
|
28
|
+
return;
|
|
29
|
+
for (const [name, probe] of Object.entries(capabilities)) {
|
|
30
|
+
validateProbe(probe, name, expectedScope, report, `${path}.capabilities.${escapePath(name)}`, issues);
|
|
31
|
+
}
|
|
32
|
+
}
|
|
33
|
+
function validateProbe(value, capability, scope, report, path, issues) {
|
|
34
|
+
const row = object(value, path, issues);
|
|
35
|
+
if (!row)
|
|
36
|
+
return;
|
|
37
|
+
exact(row, path, [
|
|
38
|
+
'schema', 'capability', 'scope', 'requested_level', 'stage', 'state',
|
|
39
|
+
'checked_at', 'report_id', 'correlation_id', 'session_id', 'attempt_id',
|
|
40
|
+
'terminal', 'root_cause', 'blockers', 'warnings', 'retryable',
|
|
41
|
+
'recovery_action', 'source', 'evidence'
|
|
42
|
+
], issues);
|
|
43
|
+
literal(row.schema, 'sks.capability-probe.v3', `${path}.schema`, issues);
|
|
44
|
+
literal(row.capability, capability, `${path}.capability`, issues);
|
|
45
|
+
literal(row.scope, scope, `${path}.scope`, issues);
|
|
46
|
+
enumValue(row.requested_level, LEVELS, `${path}.requested_level`, issues);
|
|
47
|
+
if (report)
|
|
48
|
+
literal(row.requested_level, report.requested_level, `${path}.requested_level`, issues);
|
|
49
|
+
enumValue(row.stage, PROBE_STAGES, `${path}.stage`, issues);
|
|
50
|
+
enumValue(row.state, PROBE_STATES, `${path}.state`, issues);
|
|
51
|
+
iso(row.checked_at, `${path}.checked_at`, issues);
|
|
52
|
+
nonEmptyString(row.report_id, `${path}.report_id`, issues);
|
|
53
|
+
nonEmptyString(row.correlation_id, `${path}.correlation_id`, issues);
|
|
54
|
+
nonEmptyString(row.session_id, `${path}.session_id`, issues);
|
|
55
|
+
if (report) {
|
|
56
|
+
literal(row.report_id, report.report_id, `${path}.report_id`, issues);
|
|
57
|
+
literal(row.correlation_id, report.correlation_id, `${path}.correlation_id`, issues);
|
|
58
|
+
literal(row.session_id, report.session_id, `${path}.session_id`, issues);
|
|
59
|
+
}
|
|
60
|
+
integer(row.attempt_id, `${path}.attempt_id`, issues, 0);
|
|
61
|
+
booleanValue(row.terminal, `${path}.terminal`, issues);
|
|
62
|
+
nullableString(row.root_cause, `${path}.root_cause`, issues);
|
|
63
|
+
stringArray(row.blockers, `${path}.blockers`, issues);
|
|
64
|
+
stringArray(row.warnings, `${path}.warnings`, issues);
|
|
65
|
+
booleanValue(row.retryable, `${path}.retryable`, issues);
|
|
66
|
+
nullableString(row.recovery_action, `${path}.recovery_action`, issues);
|
|
67
|
+
enumValue(row.source, EVIDENCE_SOURCES, `${path}.source`, issues);
|
|
68
|
+
object(row.evidence, `${path}.evidence`, issues);
|
|
69
|
+
const blockers = Array.isArray(row.blockers) ? row.blockers : [];
|
|
70
|
+
if (row.terminal === true && typeof row.root_cause !== 'string') {
|
|
71
|
+
issues.push(`${path}:terminal_root_cause_missing`);
|
|
72
|
+
}
|
|
73
|
+
if (typeof row.root_cause === 'string' && !blockers.includes(row.root_cause)) {
|
|
74
|
+
issues.push(`${path}:root_cause_not_in_blockers`);
|
|
75
|
+
}
|
|
76
|
+
if (row.state === 'verified' && (row.root_cause !== null || blockers.length > 0)) {
|
|
77
|
+
issues.push(`${path}:verified_with_failure`);
|
|
78
|
+
}
|
|
79
|
+
if (row.state === 'not_attempted' && (row.root_cause !== null
|
|
80
|
+
|| blockers.length > 0
|
|
81
|
+
|| row.terminal !== false))
|
|
82
|
+
issues.push(`${path}:not_attempted_with_failure`);
|
|
83
|
+
}
|
|
84
|
+
export function validateCapabilitySummary(value, path, issues) {
|
|
85
|
+
const row = object(value, path, issues);
|
|
86
|
+
if (!row)
|
|
87
|
+
return;
|
|
88
|
+
exact(row, path, [
|
|
89
|
+
'bridge_ready', 'active_routes_ready', 'level_satisfied',
|
|
90
|
+
'transport_level_satisfied', 'deep_level_satisfied', 'full_feature_verified',
|
|
91
|
+
'inactive_provider_failures', 'blockers', 'warnings'
|
|
92
|
+
], issues);
|
|
93
|
+
for (const key of [
|
|
94
|
+
'bridge_ready', 'active_routes_ready', 'level_satisfied',
|
|
95
|
+
'transport_level_satisfied', 'deep_level_satisfied', 'full_feature_verified'
|
|
96
|
+
])
|
|
97
|
+
booleanValue(row[key], `${path}.${key}`, issues);
|
|
98
|
+
stringArray(row.inactive_provider_failures, `${path}.inactive_provider_failures`, issues);
|
|
99
|
+
stringArray(row.blockers, `${path}.blockers`, issues);
|
|
100
|
+
stringArray(row.warnings, `${path}.warnings`, issues);
|
|
101
|
+
if (row.full_feature_verified === true && row.deep_level_satisfied !== true) {
|
|
102
|
+
issues.push(`${path}:full_feature_without_deep`);
|
|
103
|
+
}
|
|
104
|
+
}
|
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
import { CATALOG_STATES, PROVIDERS, enumValue, exact, integer, literal, nullableInteger, nullableIso, nullableString, object, stringArray } from './shared.js';
|
|
2
|
+
export function validateCombinedCatalog(value, path, issues) {
|
|
3
|
+
const row = object(value, path, issues);
|
|
4
|
+
if (!row)
|
|
5
|
+
return;
|
|
6
|
+
exact(row, path, [
|
|
7
|
+
'schema', 'state', 'generation', 'digest', 'model_count', 'route_count',
|
|
8
|
+
'conflict_count', 'checked_at', 'providers', 'blockers', 'warnings',
|
|
9
|
+
'recovery_action'
|
|
10
|
+
], issues);
|
|
11
|
+
literal(row.schema, 'sks.combined-catalog-sync.v1', `${path}.schema`, issues);
|
|
12
|
+
enumValue(row.state, CATALOG_STATES, `${path}.state`, issues);
|
|
13
|
+
nullableString(row.generation, `${path}.generation`, issues);
|
|
14
|
+
nullableString(row.digest, `${path}.digest`, issues);
|
|
15
|
+
nullableInteger(row.model_count, `${path}.model_count`, issues);
|
|
16
|
+
nullableInteger(row.route_count, `${path}.route_count`, issues);
|
|
17
|
+
integer(row.conflict_count, `${path}.conflict_count`, issues, 0);
|
|
18
|
+
nullableIso(row.checked_at, `${path}.checked_at`, issues);
|
|
19
|
+
const providers = object(row.providers, `${path}.providers`, issues);
|
|
20
|
+
if (providers) {
|
|
21
|
+
exact(providers, `${path}.providers`, [...PROVIDERS], issues);
|
|
22
|
+
validateCatalogState(providers['codex-lb'], 'codex-lb', `${path}.providers.codex-lb`, issues);
|
|
23
|
+
validateCatalogState(providers.openrouter, 'openrouter', `${path}.providers.openrouter`, issues);
|
|
24
|
+
}
|
|
25
|
+
stringArray(row.blockers, `${path}.blockers`, issues);
|
|
26
|
+
stringArray(row.warnings, `${path}.warnings`, issues);
|
|
27
|
+
nullableString(row.recovery_action, `${path}.recovery_action`, issues);
|
|
28
|
+
}
|
|
29
|
+
export function validateCatalogState(value, provider, path, issues) {
|
|
30
|
+
const row = object(value, path, issues);
|
|
31
|
+
if (!row)
|
|
32
|
+
return;
|
|
33
|
+
exact(row, path, [
|
|
34
|
+
'schema', 'provider_id', 'state', 'source', 'generation', 'digest',
|
|
35
|
+
'model_count', 'checked_at', 'expires_at', 'blockers', 'warnings',
|
|
36
|
+
'recovery_action'
|
|
37
|
+
], issues);
|
|
38
|
+
literal(row.schema, 'sks.catalog-sync-state.v2', `${path}.schema`, issues);
|
|
39
|
+
literal(row.provider_id, provider, `${path}.provider_id`, issues);
|
|
40
|
+
enumValue(row.state, CATALOG_STATES, `${path}.state`, issues);
|
|
41
|
+
if (row.source !== null) {
|
|
42
|
+
literal(row.source, provider === 'codex-lb' ? 'gateway' : 'openrouter', `${path}.source`, issues);
|
|
43
|
+
}
|
|
44
|
+
nullableString(row.generation, `${path}.generation`, issues);
|
|
45
|
+
nullableString(row.digest, `${path}.digest`, issues);
|
|
46
|
+
nullableInteger(row.model_count, `${path}.model_count`, issues);
|
|
47
|
+
nullableIso(row.checked_at, `${path}.checked_at`, issues);
|
|
48
|
+
nullableIso(row.expires_at, `${path}.expires_at`, issues);
|
|
49
|
+
stringArray(row.blockers, `${path}.blockers`, issues);
|
|
50
|
+
stringArray(row.warnings, `${path}.warnings`, issues);
|
|
51
|
+
nullableString(row.recovery_action, `${path}.recovery_action`, issues);
|
|
52
|
+
}
|
|
@@ -0,0 +1,109 @@
|
|
|
1
|
+
export const PROVIDERS = ['codex-lb', 'openrouter'];
|
|
2
|
+
export const LEVELS = new Set(['shallow', 'transport', 'deep']);
|
|
3
|
+
export const PROBE_STATES = new Set([
|
|
4
|
+
'not_attempted', 'running', 'verified', 'degraded', 'blocked', 'failed',
|
|
5
|
+
'unsupported', 'stale'
|
|
6
|
+
]);
|
|
7
|
+
export const PROBE_STAGES = new Set([
|
|
8
|
+
'preflight', 'process', 'tcp_connect', 'http_health', 'websocket_upgrade',
|
|
9
|
+
'websocket_protocol', 'frame_round_trip', 'clean_close', 'provider_auth',
|
|
10
|
+
'catalog_sync', 'model_route', 'feature_request', 'feature_response',
|
|
11
|
+
'artifact_validation', 'complete'
|
|
12
|
+
]);
|
|
13
|
+
export const EVIDENCE_SOURCES = new Set([
|
|
14
|
+
'config', 'manifest', 'transport', 'desktop_ui', 'deep_probe', 'artifact'
|
|
15
|
+
]);
|
|
16
|
+
export const CATALOG_STATES = new Set([
|
|
17
|
+
'not_started', 'syncing', 'verified', 'degraded', 'failed', 'stale'
|
|
18
|
+
]);
|
|
19
|
+
const FORBIDDEN_SECRET_KEY = /^(?:api_?key|secret|token|authorization|cookie|set_cookie|password|bearer|headers?|env)$/i;
|
|
20
|
+
export function object(value, path, issues) {
|
|
21
|
+
if (!value || typeof value !== 'object' || Array.isArray(value)) {
|
|
22
|
+
issues.push(`${path}:object_required`);
|
|
23
|
+
return null;
|
|
24
|
+
}
|
|
25
|
+
return value;
|
|
26
|
+
}
|
|
27
|
+
export function record(value) {
|
|
28
|
+
return value && typeof value === 'object' && !Array.isArray(value)
|
|
29
|
+
? value
|
|
30
|
+
: null;
|
|
31
|
+
}
|
|
32
|
+
export function exact(row, path, expected, issues) {
|
|
33
|
+
const allowed = new Set(expected);
|
|
34
|
+
for (const key of expected) {
|
|
35
|
+
if (!Object.hasOwn(row, key))
|
|
36
|
+
issues.push(`${path}.${escapePath(key)}:required`);
|
|
37
|
+
}
|
|
38
|
+
for (const key of Object.keys(row)) {
|
|
39
|
+
if (!allowed.has(key))
|
|
40
|
+
issues.push(`${path}.${escapePath(key)}:unexpected`);
|
|
41
|
+
}
|
|
42
|
+
}
|
|
43
|
+
export function literal(value, expected, path, issues) {
|
|
44
|
+
if (value !== expected)
|
|
45
|
+
issues.push(`${path}:expected_${String(expected)}`);
|
|
46
|
+
}
|
|
47
|
+
export function enumValue(value, allowed, path, issues) {
|
|
48
|
+
if (typeof value !== 'string' || !allowed.has(value))
|
|
49
|
+
issues.push(`${path}:enum`);
|
|
50
|
+
}
|
|
51
|
+
export function nonEmptyString(value, path, issues) {
|
|
52
|
+
if (typeof value !== 'string' || !value.trim())
|
|
53
|
+
issues.push(`${path}:non_empty_string_required`);
|
|
54
|
+
}
|
|
55
|
+
export function nullableString(value, path, issues) {
|
|
56
|
+
if (value !== null && typeof value !== 'string')
|
|
57
|
+
issues.push(`${path}:nullable_string_required`);
|
|
58
|
+
}
|
|
59
|
+
export function booleanValue(value, path, issues) {
|
|
60
|
+
if (typeof value !== 'boolean')
|
|
61
|
+
issues.push(`${path}:boolean_required`);
|
|
62
|
+
}
|
|
63
|
+
export function integer(value, path, issues, minimum) {
|
|
64
|
+
if (!Number.isInteger(value) || (minimum !== undefined && Number(value) < minimum)) {
|
|
65
|
+
issues.push(`${path}:integer_required`);
|
|
66
|
+
}
|
|
67
|
+
}
|
|
68
|
+
export function nullableInteger(value, path, issues) {
|
|
69
|
+
if (value !== null && (!Number.isInteger(value) || Number(value) < 0)) {
|
|
70
|
+
issues.push(`${path}:nullable_integer_required`);
|
|
71
|
+
}
|
|
72
|
+
}
|
|
73
|
+
export function nullableNumber(value, path, issues) {
|
|
74
|
+
if (value !== null && (typeof value !== 'number' || !Number.isFinite(value) || value < 0)) {
|
|
75
|
+
issues.push(`${path}:nullable_number_required`);
|
|
76
|
+
}
|
|
77
|
+
}
|
|
78
|
+
export function iso(value, path, issues) {
|
|
79
|
+
if (typeof value !== 'string' || !Number.isFinite(Date.parse(value))) {
|
|
80
|
+
issues.push(`${path}:iso_timestamp_required`);
|
|
81
|
+
}
|
|
82
|
+
}
|
|
83
|
+
export function nullableIso(value, path, issues) {
|
|
84
|
+
if (value !== null)
|
|
85
|
+
iso(value, path, issues);
|
|
86
|
+
}
|
|
87
|
+
export function stringArray(value, path, issues) {
|
|
88
|
+
if (!Array.isArray(value) || value.some((entry) => typeof entry !== 'string')) {
|
|
89
|
+
issues.push(`${path}:string_array_required`);
|
|
90
|
+
}
|
|
91
|
+
}
|
|
92
|
+
export function scanForbiddenKeys(value, path, issues) {
|
|
93
|
+
if (Array.isArray(value)) {
|
|
94
|
+
value.forEach((entry, index) => scanForbiddenKeys(entry, `${path}[${index}]`, issues));
|
|
95
|
+
return;
|
|
96
|
+
}
|
|
97
|
+
const row = record(value);
|
|
98
|
+
if (!row)
|
|
99
|
+
return;
|
|
100
|
+
for (const [key, entry] of Object.entries(row)) {
|
|
101
|
+
const nextPath = `${path}.${escapePath(key)}`;
|
|
102
|
+
if (FORBIDDEN_SECRET_KEY.test(key))
|
|
103
|
+
issues.push(`${nextPath}:secret_field_forbidden`);
|
|
104
|
+
scanForbiddenKeys(entry, nextPath, issues);
|
|
105
|
+
}
|
|
106
|
+
}
|
|
107
|
+
export function escapePath(value) {
|
|
108
|
+
return /^[A-Za-z_$][\w$-]*$/.test(value) ? value : JSON.stringify(value);
|
|
109
|
+
}
|
|
@@ -0,0 +1,250 @@
|
|
|
1
|
+
import { validateScope } from './capability.js';
|
|
2
|
+
import { validateCatalogState } from './catalog.js';
|
|
3
|
+
import { PROBE_STATES, PROVIDERS, booleanValue, enumValue, escapePath, exact, iso, literal, nonEmptyString, nullableInteger, nullableIso, nullableNumber, nullableString, object, stringArray } from './shared.js';
|
|
4
|
+
export function validateManagement(value, path, issues) {
|
|
5
|
+
const row = object(value, path, issues);
|
|
6
|
+
if (!row)
|
|
7
|
+
return;
|
|
8
|
+
exact(row, path, ['managed', 'runtime', 'state', 'reason'], issues);
|
|
9
|
+
booleanValue(row.managed, `${path}.managed`, issues);
|
|
10
|
+
if (row.managed === true) {
|
|
11
|
+
literal(row.runtime, 'desktop-bridge', `${path}.runtime`, issues);
|
|
12
|
+
literal(row.reason, null, `${path}.reason`, issues);
|
|
13
|
+
enumValue(row.state, new Set([
|
|
14
|
+
'not_installed', 'starting', 'ready', 'degraded', 'blocked', 'stopped', 'stale'
|
|
15
|
+
]), `${path}.state`, issues);
|
|
16
|
+
}
|
|
17
|
+
else if (row.managed === false) {
|
|
18
|
+
literal(row.runtime, null, `${path}.runtime`, issues);
|
|
19
|
+
enumValue(row.state, new Set(['not_installed', 'stopped']), `${path}.state`, issues);
|
|
20
|
+
enumValue(row.reason, new Set([
|
|
21
|
+
'uninstalled', 'rollback_complete', 'never_configured'
|
|
22
|
+
]), `${path}.reason`, issues);
|
|
23
|
+
}
|
|
24
|
+
}
|
|
25
|
+
export function validateService(value, path, issues) {
|
|
26
|
+
const row = object(value, path, issues);
|
|
27
|
+
if (!row)
|
|
28
|
+
return;
|
|
29
|
+
exact(row, path, [
|
|
30
|
+
'state', 'installed', 'loaded', 'running', 'loopback_origin', 'pid',
|
|
31
|
+
'checked_at', 'blockers', 'warnings'
|
|
32
|
+
], issues);
|
|
33
|
+
enumValue(row.state, new Set([
|
|
34
|
+
'not_installed', 'starting', 'ready', 'degraded', 'blocked', 'stopped', 'stale'
|
|
35
|
+
]), `${path}.state`, issues);
|
|
36
|
+
booleanValue(row.installed, `${path}.installed`, issues);
|
|
37
|
+
booleanValue(row.loaded, `${path}.loaded`, issues);
|
|
38
|
+
booleanValue(row.running, `${path}.running`, issues);
|
|
39
|
+
nullableString(row.loopback_origin, `${path}.loopback_origin`, issues);
|
|
40
|
+
nullableInteger(row.pid, `${path}.pid`, issues);
|
|
41
|
+
iso(row.checked_at, `${path}.checked_at`, issues);
|
|
42
|
+
stringArray(row.blockers, `${path}.blockers`, issues);
|
|
43
|
+
stringArray(row.warnings, `${path}.warnings`, issues);
|
|
44
|
+
}
|
|
45
|
+
export function validateHttpProbeResult(value, path, issues) {
|
|
46
|
+
const row = object(value, path, issues);
|
|
47
|
+
if (!row)
|
|
48
|
+
return;
|
|
49
|
+
exact(row, path, [
|
|
50
|
+
'schema', 'state', 'terminal_stage', 'root_cause', 'status_code',
|
|
51
|
+
'latency_ms', 'blockers', 'warnings'
|
|
52
|
+
], issues);
|
|
53
|
+
literal(row.schema, 'sks.desktop-bridge-http-probe.v1', `${path}.schema`, issues);
|
|
54
|
+
enumValue(row.state, new Set(['verified', 'blocked', 'failed', 'unsupported']), `${path}.state`, issues);
|
|
55
|
+
enumValue(row.terminal_stage, new Set([
|
|
56
|
+
'tcp_connect', 'http_health', 'complete'
|
|
57
|
+
]), `${path}.terminal_stage`, issues);
|
|
58
|
+
nullableString(row.root_cause, `${path}.root_cause`, issues);
|
|
59
|
+
nullableInteger(row.status_code, `${path}.status_code`, issues);
|
|
60
|
+
nullableNumber(row.latency_ms, `${path}.latency_ms`, issues);
|
|
61
|
+
stringArray(row.blockers, `${path}.blockers`, issues);
|
|
62
|
+
stringArray(row.warnings, `${path}.warnings`, issues);
|
|
63
|
+
if (row.state === 'verified' && (row.terminal_stage !== 'complete' || row.root_cause !== null)) {
|
|
64
|
+
issues.push(`${path}:verified_http_incomplete`);
|
|
65
|
+
}
|
|
66
|
+
}
|
|
67
|
+
export function validateWebSocketProbeResult(value, path, issues) {
|
|
68
|
+
const row = object(value, path, issues);
|
|
69
|
+
if (!row)
|
|
70
|
+
return;
|
|
71
|
+
exact(row, path, [
|
|
72
|
+
'schema', 'state', 'terminal_stage', 'root_cause', 'status_code',
|
|
73
|
+
'negotiated_protocol', 'upgrade_verified', 'protocol_verified',
|
|
74
|
+
'frame_round_trip_verified', 'clean_close_verified', 'latency_ms',
|
|
75
|
+
'blockers', 'warnings'
|
|
76
|
+
], issues);
|
|
77
|
+
literal(row.schema, 'sks.desktop-bridge-websocket-probe.v2', `${path}.schema`, issues);
|
|
78
|
+
enumValue(row.state, new Set([
|
|
79
|
+
'not_attempted', 'verified', 'degraded', 'blocked', 'failed', 'unsupported'
|
|
80
|
+
]), `${path}.state`, issues);
|
|
81
|
+
enumValue(row.terminal_stage, new Set([
|
|
82
|
+
'tcp_connect', 'websocket_upgrade', 'websocket_protocol', 'frame_round_trip',
|
|
83
|
+
'clean_close', 'complete'
|
|
84
|
+
]), `${path}.terminal_stage`, issues);
|
|
85
|
+
nullableString(row.root_cause, `${path}.root_cause`, issues);
|
|
86
|
+
nullableInteger(row.status_code, `${path}.status_code`, issues);
|
|
87
|
+
nullableString(row.negotiated_protocol, `${path}.negotiated_protocol`, issues);
|
|
88
|
+
for (const key of [
|
|
89
|
+
'upgrade_verified', 'protocol_verified', 'frame_round_trip_verified', 'clean_close_verified'
|
|
90
|
+
])
|
|
91
|
+
booleanValue(row[key], `${path}.${key}`, issues);
|
|
92
|
+
nullableNumber(row.latency_ms, `${path}.latency_ms`, issues);
|
|
93
|
+
stringArray(row.blockers, `${path}.blockers`, issues);
|
|
94
|
+
stringArray(row.warnings, `${path}.warnings`, issues);
|
|
95
|
+
if (row.state === 'verified' && (row.terminal_stage !== 'complete'
|
|
96
|
+
|| row.root_cause !== null
|
|
97
|
+
|| row.upgrade_verified !== true
|
|
98
|
+
|| row.protocol_verified !== true
|
|
99
|
+
|| row.frame_round_trip_verified !== true
|
|
100
|
+
|| row.clean_close_verified !== true))
|
|
101
|
+
issues.push(`${path}:verified_websocket_incomplete`);
|
|
102
|
+
if (row.state === 'not_attempted' && (row.root_cause !== null
|
|
103
|
+
|| (Array.isArray(row.blockers) && row.blockers.length > 0)))
|
|
104
|
+
issues.push(`${path}:not_attempted_websocket_with_failure`);
|
|
105
|
+
}
|
|
106
|
+
export function validateNativeIdentity(value, path, issues) {
|
|
107
|
+
const row = object(value, path, issues);
|
|
108
|
+
if (!row)
|
|
109
|
+
return;
|
|
110
|
+
exact(row, path, [
|
|
111
|
+
'state', 'configured', 'semantic_identity_preserved', 'checked_at', 'blockers', 'warnings'
|
|
112
|
+
], issues);
|
|
113
|
+
enumValue(row.state, PROBE_STATES, `${path}.state`, issues);
|
|
114
|
+
booleanValue(row.configured, `${path}.configured`, issues);
|
|
115
|
+
if (row.semantic_identity_preserved !== null) {
|
|
116
|
+
booleanValue(row.semantic_identity_preserved, `${path}.semantic_identity_preserved`, issues);
|
|
117
|
+
}
|
|
118
|
+
nullableIso(row.checked_at, `${path}.checked_at`, issues);
|
|
119
|
+
stringArray(row.blockers, `${path}.blockers`, issues);
|
|
120
|
+
stringArray(row.warnings, `${path}.warnings`, issues);
|
|
121
|
+
}
|
|
122
|
+
export function validateProviderProfile(value, provider, path, issues) {
|
|
123
|
+
const row = object(value, path, issues);
|
|
124
|
+
if (!row)
|
|
125
|
+
return;
|
|
126
|
+
exact(row, path, [
|
|
127
|
+
'schema', 'provider_id', 'enabled', 'credential', 'endpoint', 'catalog', 'capabilities'
|
|
128
|
+
], issues);
|
|
129
|
+
literal(row.schema, 'sks.bridge-provider-profile-status.v1', `${path}.schema`, issues);
|
|
130
|
+
literal(row.provider_id, provider, `${path}.provider_id`, issues);
|
|
131
|
+
booleanValue(row.enabled, `${path}.enabled`, issues);
|
|
132
|
+
validateCredential(row.credential, `${path}.credential`, issues);
|
|
133
|
+
validateEndpoint(row.endpoint, `${path}.endpoint`, issues);
|
|
134
|
+
validateCatalogState(row.catalog, provider, `${path}.catalog`, issues);
|
|
135
|
+
validateScope(row.capabilities, `provider:${provider}`, null, `${path}.capabilities`, issues);
|
|
136
|
+
}
|
|
137
|
+
function validateCredential(value, path, issues) {
|
|
138
|
+
const row = object(value, path, issues);
|
|
139
|
+
if (!row)
|
|
140
|
+
return;
|
|
141
|
+
exact(row, path, ['state', 'source', 'fingerprint', 'checked_at', 'blockers', 'warnings'], issues);
|
|
142
|
+
enumValue(row.state, new Set([
|
|
143
|
+
'not_configured', 'configured_unverified', 'validating', 'ready', 'rejected',
|
|
144
|
+
'unavailable', 'stale'
|
|
145
|
+
]), `${path}.state`, issues);
|
|
146
|
+
nullableString(row.source, `${path}.source`, issues);
|
|
147
|
+
nullableString(row.fingerprint, `${path}.fingerprint`, issues);
|
|
148
|
+
nullableIso(row.checked_at, `${path}.checked_at`, issues);
|
|
149
|
+
stringArray(row.blockers, `${path}.blockers`, issues);
|
|
150
|
+
stringArray(row.warnings, `${path}.warnings`, issues);
|
|
151
|
+
}
|
|
152
|
+
function validateEndpoint(value, path, issues) {
|
|
153
|
+
const row = object(value, path, issues);
|
|
154
|
+
if (!row)
|
|
155
|
+
return;
|
|
156
|
+
exact(row, path, ['configured', 'origin_redacted', 'auth_transport'], issues);
|
|
157
|
+
booleanValue(row.configured, `${path}.configured`, issues);
|
|
158
|
+
nullableString(row.origin_redacted, `${path}.origin_redacted`, issues);
|
|
159
|
+
if (row.auth_transport !== null) {
|
|
160
|
+
enumValue(row.auth_transport, new Set([
|
|
161
|
+
'authorization-bearer', 'x-codex-lb-api-key', 'openrouter-bearer'
|
|
162
|
+
]), `${path}.auth_transport`, issues);
|
|
163
|
+
}
|
|
164
|
+
}
|
|
165
|
+
export function validateRouting(value, path, issues) {
|
|
166
|
+
const row = object(value, path, issues);
|
|
167
|
+
if (!row)
|
|
168
|
+
return;
|
|
169
|
+
exact(row, path, [
|
|
170
|
+
'policy', 'selected_model', 'selected_route', 'session_pin', 'fallback',
|
|
171
|
+
'blockers', 'warnings'
|
|
172
|
+
], issues);
|
|
173
|
+
if (row.policy !== null)
|
|
174
|
+
validatePolicy(row.policy, `${path}.policy`, issues);
|
|
175
|
+
nullableString(row.selected_model, `${path}.selected_model`, issues);
|
|
176
|
+
if (row.selected_route !== null) {
|
|
177
|
+
validateRouteTarget(row.selected_route, `${path}.selected_route`, issues);
|
|
178
|
+
}
|
|
179
|
+
if (row.session_pin !== null)
|
|
180
|
+
validateSessionPin(row.session_pin, `${path}.session_pin`, issues);
|
|
181
|
+
literal(row.fallback, 'none', `${path}.fallback`, issues);
|
|
182
|
+
stringArray(row.blockers, `${path}.blockers`, issues);
|
|
183
|
+
stringArray(row.warnings, `${path}.warnings`, issues);
|
|
184
|
+
}
|
|
185
|
+
function validateSessionPin(value, path, issues) {
|
|
186
|
+
const row = object(value, path, issues);
|
|
187
|
+
if (!row)
|
|
188
|
+
return;
|
|
189
|
+
exact(row, path, [
|
|
190
|
+
'thread_id', 'provider_id', 'public_model', 'upstream_model',
|
|
191
|
+
'catalog_generation', 'route_policy_generation', 'created_at'
|
|
192
|
+
], issues);
|
|
193
|
+
for (const key of [
|
|
194
|
+
'thread_id', 'public_model', 'upstream_model', 'catalog_generation', 'route_policy_generation'
|
|
195
|
+
])
|
|
196
|
+
nonEmptyString(row[key], `${path}.${key}`, issues);
|
|
197
|
+
enumValue(row.provider_id, new Set(PROVIDERS), `${path}.provider_id`, issues);
|
|
198
|
+
iso(row.created_at, `${path}.created_at`, issues);
|
|
199
|
+
}
|
|
200
|
+
function validatePolicy(value, path, issues) {
|
|
201
|
+
const row = object(value, path, issues);
|
|
202
|
+
if (!row)
|
|
203
|
+
return;
|
|
204
|
+
exact(row, path, [
|
|
205
|
+
'schema', 'default_provider_id', 'fallback', 'model_routes',
|
|
206
|
+
'catalog_generation', 'policy_generation', 'changed_at'
|
|
207
|
+
], issues);
|
|
208
|
+
literal(row.schema, 'sks.bridge-routing-policy.v1', `${path}.schema`, issues);
|
|
209
|
+
if (row.default_provider_id !== null) {
|
|
210
|
+
enumValue(row.default_provider_id, new Set(PROVIDERS), `${path}.default_provider_id`, issues);
|
|
211
|
+
}
|
|
212
|
+
literal(row.fallback, 'none', `${path}.fallback`, issues);
|
|
213
|
+
const routes = object(row.model_routes, `${path}.model_routes`, issues);
|
|
214
|
+
if (routes) {
|
|
215
|
+
for (const [model, target] of Object.entries(routes)) {
|
|
216
|
+
validateRouteTarget(target, `${path}.model_routes.${escapePath(model)}`, issues);
|
|
217
|
+
}
|
|
218
|
+
}
|
|
219
|
+
nonEmptyString(row.catalog_generation, `${path}.catalog_generation`, issues);
|
|
220
|
+
nonEmptyString(row.policy_generation, `${path}.policy_generation`, issues);
|
|
221
|
+
iso(row.changed_at, `${path}.changed_at`, issues);
|
|
222
|
+
}
|
|
223
|
+
function validateRouteTarget(value, path, issues) {
|
|
224
|
+
const row = object(value, path, issues);
|
|
225
|
+
if (!row)
|
|
226
|
+
return;
|
|
227
|
+
exact(row, path, ['provider_id', 'upstream_model'], issues);
|
|
228
|
+
enumValue(row.provider_id, new Set(PROVIDERS), `${path}.provider_id`, issues);
|
|
229
|
+
nonEmptyString(row.upstream_model, `${path}.upstream_model`, issues);
|
|
230
|
+
}
|
|
231
|
+
export function validateReadiness(value, path, issues) {
|
|
232
|
+
const row = object(value, path, issues);
|
|
233
|
+
if (!row)
|
|
234
|
+
return;
|
|
235
|
+
exact(row, path, [
|
|
236
|
+
'ready', 'state', 'bridge_ready', 'active_routes_ready',
|
|
237
|
+
'combined_catalog_ready', 'blockers', 'warnings'
|
|
238
|
+
], issues);
|
|
239
|
+
for (const key of [
|
|
240
|
+
'ready', 'bridge_ready', 'active_routes_ready', 'combined_catalog_ready'
|
|
241
|
+
])
|
|
242
|
+
booleanValue(row[key], `${path}.${key}`, issues);
|
|
243
|
+
enumValue(row.state, new Set([
|
|
244
|
+
'ready', 'awaiting_provider', 'degraded', 'blocked', 'unmanaged'
|
|
245
|
+
]), `${path}.state`, issues);
|
|
246
|
+
stringArray(row.blockers, `${path}.blockers`, issues);
|
|
247
|
+
stringArray(row.warnings, `${path}.warnings`, issues);
|
|
248
|
+
if (row.ready === true && row.state !== 'ready')
|
|
249
|
+
issues.push(`${path}:ready_state_inconsistent`);
|
|
250
|
+
}
|
|
@@ -0,0 +1,106 @@
|
|
|
1
|
+
import { validateCapabilitySummary, validateExecution, validateScope } from './bridge-runtime-validation/capability.js';
|
|
2
|
+
import { validateCombinedCatalog } from './bridge-runtime-validation/catalog.js';
|
|
3
|
+
import { LEVELS, PROVIDERS, enumValue, exact, iso, literal, nonEmptyString, nullableString, object, record, scanForbiddenKeys, stringArray } from './bridge-runtime-validation/shared.js';
|
|
4
|
+
import { validateHttpProbeResult, validateManagement, validateNativeIdentity, validateProviderProfile, validateReadiness, validateRouting, validateService, validateWebSocketProbeResult } from './bridge-runtime-validation/status.js';
|
|
5
|
+
export function validateDesktopCapabilityReportV3(value) {
|
|
6
|
+
const issues = [];
|
|
7
|
+
const report = object(value, '$', issues);
|
|
8
|
+
if (!report)
|
|
9
|
+
return result(issues);
|
|
10
|
+
exact(report, '$', [
|
|
11
|
+
'schema', 'report_id', 'correlation_id', 'session_id', 'requested_level',
|
|
12
|
+
'checked_at', 'catalog_generation', 'execution', 'bridge', 'native_identity',
|
|
13
|
+
'providers', 'combined_catalog', 'summary', 'catalog_sync'
|
|
14
|
+
], issues);
|
|
15
|
+
literal(report.schema, 'sks.desktop-capabilities.v3', '$.schema', issues);
|
|
16
|
+
nonEmptyString(report.report_id, '$.report_id', issues);
|
|
17
|
+
nonEmptyString(report.correlation_id, '$.correlation_id', issues);
|
|
18
|
+
nonEmptyString(report.session_id, '$.session_id', issues);
|
|
19
|
+
enumValue(report.requested_level, LEVELS, '$.requested_level', issues);
|
|
20
|
+
iso(report.checked_at, '$.checked_at', issues);
|
|
21
|
+
nullableString(report.catalog_generation, '$.catalog_generation', issues);
|
|
22
|
+
validateExecution(report.execution, '$.execution', issues);
|
|
23
|
+
validateScope(report.bridge, 'bridge', report, '$.bridge', issues);
|
|
24
|
+
validateScope(report.native_identity, 'native-identity', report, '$.native_identity', issues);
|
|
25
|
+
const providers = object(report.providers, '$.providers', issues);
|
|
26
|
+
if (providers) {
|
|
27
|
+
exact(providers, '$.providers', [...PROVIDERS], issues);
|
|
28
|
+
validateScope(providers['codex-lb'], 'provider:codex-lb', report, '$.providers.codex-lb', issues);
|
|
29
|
+
validateScope(providers.openrouter, 'provider:openrouter', report, '$.providers.openrouter', issues);
|
|
30
|
+
}
|
|
31
|
+
validateScope(report.combined_catalog, 'catalog:combined', report, '$.combined_catalog', issues);
|
|
32
|
+
validateCapabilitySummary(report.summary, '$.summary', issues);
|
|
33
|
+
validateCombinedCatalog(report.catalog_sync, '$.catalog_sync', issues);
|
|
34
|
+
const catalog = record(report.catalog_sync);
|
|
35
|
+
if (catalog && report.catalog_generation !== catalog.generation) {
|
|
36
|
+
issues.push('$.catalog_generation:catalog_generation_mismatch');
|
|
37
|
+
}
|
|
38
|
+
scanForbiddenKeys(value, '$', issues);
|
|
39
|
+
return result(issues);
|
|
40
|
+
}
|
|
41
|
+
export function validateDesktopBridgeStatusV3(value) {
|
|
42
|
+
const issues = [];
|
|
43
|
+
const status = object(value, '$', issues);
|
|
44
|
+
if (!status)
|
|
45
|
+
return result(issues);
|
|
46
|
+
exact(status, '$', [
|
|
47
|
+
'schema', 'checked_at', 'correlation_id', 'management', 'service', 'http_probe',
|
|
48
|
+
'websocket_probe', 'native_identity', 'providers', 'routing', 'catalog_sync',
|
|
49
|
+
'capabilities', 'readiness', 'recovery_actions'
|
|
50
|
+
], issues);
|
|
51
|
+
literal(status.schema, 'sks.desktop-bridge-status.v3', '$.schema', issues);
|
|
52
|
+
iso(status.checked_at, '$.checked_at', issues);
|
|
53
|
+
nonEmptyString(status.correlation_id, '$.correlation_id', issues);
|
|
54
|
+
validateManagement(status.management, '$.management', issues);
|
|
55
|
+
validateService(status.service, '$.service', issues);
|
|
56
|
+
if (status.http_probe !== null) {
|
|
57
|
+
validateHttpProbeResult(status.http_probe, '$.http_probe', issues);
|
|
58
|
+
}
|
|
59
|
+
if (status.websocket_probe !== null) {
|
|
60
|
+
validateWebSocketProbeResult(status.websocket_probe, '$.websocket_probe', issues);
|
|
61
|
+
}
|
|
62
|
+
validateNativeIdentity(status.native_identity, '$.native_identity', issues);
|
|
63
|
+
const providers = object(status.providers, '$.providers', issues);
|
|
64
|
+
if (providers) {
|
|
65
|
+
exact(providers, '$.providers', [...PROVIDERS], issues);
|
|
66
|
+
validateProviderProfile(providers['codex-lb'], 'codex-lb', '$.providers.codex-lb', issues);
|
|
67
|
+
validateProviderProfile(providers.openrouter, 'openrouter', '$.providers.openrouter', issues);
|
|
68
|
+
}
|
|
69
|
+
validateRouting(status.routing, '$.routing', issues);
|
|
70
|
+
validateCombinedCatalog(status.catalog_sync, '$.catalog_sync', issues);
|
|
71
|
+
if (status.capabilities !== null) {
|
|
72
|
+
const reportValidation = validateDesktopCapabilityReportV3(status.capabilities);
|
|
73
|
+
issues.push(...reportValidation.issues.map((issue) => `$.capabilities${issue.slice(1)}`));
|
|
74
|
+
const capability = record(status.capabilities);
|
|
75
|
+
const catalog = record(status.catalog_sync);
|
|
76
|
+
if (capability && catalog && capability.catalog_generation !== catalog.generation) {
|
|
77
|
+
issues.push('$.capabilities.catalog_generation:status_catalog_generation_mismatch');
|
|
78
|
+
}
|
|
79
|
+
}
|
|
80
|
+
validateReadiness(status.readiness, '$.readiness', issues);
|
|
81
|
+
stringArray(status.recovery_actions, '$.recovery_actions', issues);
|
|
82
|
+
scanForbiddenKeys(value, '$', issues);
|
|
83
|
+
return result(issues);
|
|
84
|
+
}
|
|
85
|
+
export function assertDesktopCapabilityReportV3(value) {
|
|
86
|
+
const validation = validateDesktopCapabilityReportV3(value);
|
|
87
|
+
if (!validation.ok) {
|
|
88
|
+
throw new Error(`capability_schema_invalid:${validation.issues[0] || 'unknown'}`);
|
|
89
|
+
}
|
|
90
|
+
}
|
|
91
|
+
export function assertDesktopBridgeStatusV3(value) {
|
|
92
|
+
const validation = validateDesktopBridgeStatusV3(value);
|
|
93
|
+
if (!validation.ok) {
|
|
94
|
+
throw new Error(`desktop_bridge_status_schema_invalid:${validation.issues[0] || 'unknown'}`);
|
|
95
|
+
}
|
|
96
|
+
}
|
|
97
|
+
function result(issues) {
|
|
98
|
+
return { ok: issues.length === 0, issues: [...new Set(issues)] };
|
|
99
|
+
}
|
|
100
|
+
void {};
|
|
101
|
+
void {};
|
|
102
|
+
void {};
|
|
103
|
+
void {};
|
|
104
|
+
void {};
|
|
105
|
+
void {};
|
|
106
|
+
void {};
|