sneakoscope 7.3.0 → 7.6.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +129 -10
- package/crates/sks-core/Cargo.lock +1 -1
- package/crates/sks-core/Cargo.toml +1 -1
- package/dist/cli/codex-app-command.js +1 -1
- package/dist/cli/command-manifest-lite.js +4 -1
- package/dist/cli/command-registry.js +2 -0
- package/dist/cli/install-helpers-codex-lb-chain.js +42 -0
- package/dist/cli/install-helpers-codex-lb-config.js +114 -9
- package/dist/cli/install-helpers-install-support.js +6 -16
- package/dist/cli/install-helpers.js +788 -600
- package/dist/cli/router.js +30 -2
- package/dist/commands/codex-app.js +37 -1
- package/dist/commands/codex-lb.js +491 -300
- package/dist/config/skills-manifest.json +57 -71
- package/dist/core/align/align-route.js +127 -0
- package/dist/core/codex-app/codex-app-fast-ui-repair.js +8 -4
- package/dist/core/codex-app/codex-app-restart.js +83 -0
- package/dist/core/codex-app/codex-app-ui-state-snapshot.js +8 -4
- package/dist/core/codex-app/desktop-routing-snapshot.js +1 -1
- package/dist/core/codex-app/menubar/constants.js +5 -0
- package/dist/core/codex-app/menubar/generation-transaction-journal.js +1 -3
- package/dist/core/codex-app/menubar/installer.js +18 -0
- package/dist/core/codex-app/multi-provider-router.js +22 -10
- package/dist/core/codex-app/openrouter-activate.js +26 -1
- package/dist/core/codex-app.js +118 -26
- package/dist/core/codex-control/codex-app-server-runtime-env.js +86 -0
- package/dist/core/codex-control/codex-app-server-v2-client.js +78 -8
- package/dist/core/codex-control/codex-task-runner.js +2 -2
- package/dist/core/codex-lb/capability-runner.js +204 -0
- package/dist/core/codex-lb/capability-types.js +1 -0
- package/dist/core/codex-lb/codex-lb-env.js +9 -13
- package/dist/core/codex-lb/codex-lb-setup.js +45 -8
- package/dist/core/codex-lb/codex-lb-tool-catalog.js +52 -74
- package/dist/core/codex-lb/codex-lb-tool-output-recovery.js +1 -1
- package/dist/core/codex-lb/desktop-auth-invariant.js +185 -0
- package/dist/core/codex-lb/desktop-bridge/client.js +34 -0
- package/dist/core/codex-lb/desktop-bridge/header-policy.js +106 -0
- package/dist/core/codex-lb/desktop-bridge/http-forward.js +101 -0
- package/dist/core/codex-lb/desktop-bridge/index.js +10 -0
- package/dist/core/codex-lb/desktop-bridge/launchd.js +81 -0
- package/dist/core/codex-lb/desktop-bridge/location-rewrite.js +27 -0
- package/dist/core/codex-lb/desktop-bridge/security.js +274 -0
- package/dist/core/codex-lb/desktop-bridge/server.js +179 -0
- package/dist/core/codex-lb/desktop-bridge/state.js +119 -0
- package/dist/core/codex-lb/desktop-bridge/types.js +16 -0
- package/dist/core/codex-lb/desktop-bridge/websocket-forward.js +151 -0
- package/dist/core/codex-lb/desktop-center-credentials.js +189 -0
- package/dist/core/codex-lb/desktop-controller.js +1410 -0
- package/dist/core/codex-lb/desktop-mode.js +32 -0
- package/dist/core/codex-lb/desktop-real-evidence.js +168 -0
- package/dist/core/codex-lb/desktop-service.js +613 -0
- package/dist/core/codex-lb/legacy-migration.js +575 -0
- package/dist/core/codex-lb/migration-receipt.js +246 -0
- package/dist/core/codex-lb/probes/auxiliary-surfaces-probe.js +60 -0
- package/dist/core/codex-lb/probes/bridge-probe.js +75 -0
- package/dist/core/codex-lb/probes/catalog-probe.js +128 -0
- package/dist/core/codex-lb/probes/computer-use-probe.js +50 -0
- package/dist/core/codex-lb/probes/image-generation-probe.js +47 -0
- package/dist/core/codex-lb/probes/probe-evidence.js +39 -0
- package/dist/core/codex-lb/probes/voice-realtime-probe.js +44 -0
- package/dist/core/codex-lb/trusted-deep-evidence.js +403 -0
- package/dist/core/codex-native/core-skill-manifest.js +22 -6
- package/dist/core/codex-runtime/codex-desktop-config-policy.js +2 -1
- package/dist/core/commands/align-command.js +220 -0
- package/dist/core/commands/image-ux-review-command.js +280 -68
- package/dist/core/commands/naruto-command.js +257 -8
- package/dist/core/commands/ppt-command.js +2 -2
- package/dist/core/commands/telegram-command.js +402 -34
- package/dist/core/commands/triwiki-command.js +11 -1
- package/dist/core/commands/triwiki-graph-command.js +160 -0
- package/dist/core/commands/wiki-command.js +100 -20
- package/dist/core/doctor/skill-legacy-surface.js +1 -3
- package/dist/core/errors/message.js +3 -0
- package/dist/core/evidence/evidence-freshness.js +14 -0
- package/dist/core/feature-fixtures.js +9 -1
- package/dist/core/feature-registry.js +5 -3
- package/dist/core/fsx.js +7 -3
- package/dist/core/hooks-runtime/codex-commit-hooks-selftest.js +82 -0
- package/dist/core/hooks-runtime/context-graph-freshness-preflight.js +113 -0
- package/dist/core/hooks-runtime/hook-context.js +15 -2
- package/dist/core/hooks-runtime/managed-skill-generation-heal.js +46 -0
- package/dist/core/hooks-runtime/naruto-terminal-finalization.js +1 -0
- package/dist/core/hooks-runtime/official-subagent-lifecycle.js +1 -1
- package/dist/core/hooks-runtime/tool-output-quarantine.js +1 -1
- package/dist/core/hooks-runtime.js +33 -89
- package/dist/core/image-ux-review/callout-extraction.js +6 -0
- package/dist/core/image-ux-review/imagegen-adapter.js +64 -23
- package/dist/core/image-ux-review/real-callout-extractor.js +1 -0
- package/dist/core/image-ux-review.js +230 -12
- package/dist/core/imagegen/codex-lb-imagegen-target.js +21 -7
- package/dist/core/imagegen/imagegen-capability.js +10 -4
- package/dist/core/imagegen/require-imagegen.js +29 -5
- package/dist/core/init/skills.js +25 -13
- package/dist/core/init.js +1 -1
- package/dist/core/install/installed-package-smoke.js +157 -4
- package/dist/core/managed-assets/managed-assets-manifest.js +2 -1
- package/dist/core/managed-path-safety.js +8 -10
- package/dist/core/mcp-config/backup.js +2 -4
- package/dist/core/mcp-config/config-reader.js +2 -4
- package/dist/core/mcp-config/scope.js +3 -5
- package/dist/core/naruto/context-graph-advisor-scope.js +242 -0
- package/dist/core/naruto/context-graph-advisor.js +0 -0
- package/dist/core/perf/release-latency-slo.js +12 -6
- package/dist/core/pipeline-internals/runtime-core.js +78 -0
- package/dist/core/pipeline-internals/runtime-gates.js +5 -2
- package/dist/core/policy/latest-version-guidance.js +113 -0
- package/dist/core/ppt.js +8 -8
- package/dist/core/preflight/parallel-preflight-engine.js +1 -1
- package/dist/core/proof/auto-finalize.js +98 -6
- package/dist/core/proof/route-proof-gate.js +12 -1
- package/dist/core/proof/route-proof-policy.js +8 -8
- package/dist/core/release/gate-manifest.js +32 -1
- package/dist/core/release/npm-stage-contract.js +21 -0
- package/dist/core/release/package-size-budget.js +2 -2
- package/dist/core/release/release-gate-contract.js +5 -0
- package/dist/core/release/release-proof-io.js +1 -3
- package/dist/core/release/release-real-contract.js +5 -4
- package/dist/core/release/release-stamp-proof.js +1 -3
- package/dist/core/release/stage-publish.js +27 -0
- package/dist/core/remote/audit-idempotency.js +50 -18
- package/dist/core/remote/codex-public-activity.js +283 -0
- package/dist/core/remote/index.js +1 -0
- package/dist/core/remote/ssh-worker-client.js +4 -1
- package/dist/core/remote/worker.js +206 -27
- package/dist/core/research/research-adversarial-review.js +1 -3
- package/dist/core/research/research-claim-synthesizer.js +1 -3
- package/dist/core/research/research-falsification-runner.js +1 -3
- package/dist/core/research/research-source-evidence.js +1 -3
- package/dist/core/responses-stream.js +65 -19
- package/dist/core/routes/constants.js +1 -1
- package/dist/core/routes/design-policy.js +7 -2
- package/dist/core/routes/dollar-manifest-lite.js +2 -4
- package/dist/core/routes/evidence.js +1 -1
- package/dist/core/routes.js +30 -10
- package/dist/core/safety/command-contract/contracts.js +2 -0
- package/dist/core/safety/command-contract/types.js +1 -1
- package/dist/core/search/context-graph-seeds.js +205 -0
- package/dist/core/search/context.js +0 -0
- package/dist/core/search/provider.js +2 -2
- package/dist/core/secret-redaction.js +6 -0
- package/dist/core/subagents/naruto-help-contract.js +2 -1
- package/dist/core/subagents/naruto-host-credentials.js +161 -0
- package/dist/core/subagents/official-subagent-preparation.js +4 -1
- package/dist/core/subagents/official-subagent-prompt.js +44 -2
- package/dist/core/subagents/official-subagent-runner.js +26 -8
- package/dist/core/subagents/triwiki-attention.js +135 -123
- package/dist/core/telegram/bot-api.js +85 -10
- package/dist/core/telegram/center-snapshot.js +718 -0
- package/dist/core/telegram/config.js +158 -31
- package/dist/core/telegram/hub.js +288 -33
- package/dist/core/telegram/index.js +2 -0
- package/dist/core/telegram/ingress-spool.js +419 -0
- package/dist/core/telegram/ledgers.js +188 -29
- package/dist/core/telegram/messages.js +26 -6
- package/dist/core/telegram/owner-lock.js +10 -7
- package/dist/core/telegram/runtime-projection.js +38 -3
- package/dist/core/telegram/runtime.js +298 -63
- package/dist/core/telegram/service.js +137 -8
- package/dist/core/telegram/setup.js +291 -73
- package/dist/core/text/strings.js +3 -0
- package/dist/core/triwiki/code-pack.js +12 -120
- package/dist/core/triwiki/context-graph/compiler/cache-key.js +277 -0
- package/dist/core/triwiki/context-graph/compiler/extract.js +104 -0
- package/dist/core/triwiki/context-graph/compiler/freshness.js +108 -0
- package/dist/core/triwiki/context-graph/compiler/index.js +237 -0
- package/dist/core/triwiki/context-graph/compiler/merge.js +0 -0
- package/dist/core/triwiki/context-graph/compiler/serialize.js +115 -0
- package/dist/core/triwiki/context-graph/contracts.js +236 -0
- package/dist/core/triwiki/context-graph/extractors/code/builders.js +150 -0
- package/dist/core/triwiki/context-graph/extractors/code/declarations.js +161 -0
- package/dist/core/triwiki/context-graph/extractors/code/index.js +265 -0
- package/dist/core/triwiki/context-graph/extractors/code/inventory.js +237 -0
- package/dist/core/triwiki/context-graph/extractors/code/module-graph.js +252 -0
- package/dist/core/triwiki/context-graph/extractors/code/modules.js +79 -0
- package/dist/core/triwiki/context-graph/extractors/code/references.js +184 -0
- package/dist/core/triwiki/context-graph/extractors/code/selection.js +100 -0
- package/dist/core/triwiki/context-graph/extractors/code/ts-config.js +161 -0
- package/dist/core/triwiki/context-graph/extractors/code/types.js +18 -0
- package/dist/core/triwiki/context-graph/extractors/evidence/claims.js +289 -0
- package/dist/core/triwiki/context-graph/extractors/evidence/index.js +54 -0
- package/dist/core/triwiki/context-graph/extractors/evidence/proof-index.js +213 -0
- package/dist/core/triwiki/context-graph/extractors/evidence/proofs.js +266 -0
- package/dist/core/triwiki/context-graph/extractors/evidence/redaction.js +177 -0
- package/dist/core/triwiki/context-graph/extractors/evidence/shared.js +0 -0
- package/dist/core/triwiki/context-graph/extractors/evidence/sources.js +154 -0
- package/dist/core/triwiki/context-graph/extractors/index.js +7 -0
- package/dist/core/triwiki/context-graph/extractors/topology/commands.js +207 -0
- package/dist/core/triwiki/context-graph/extractors/topology/gate-edges.js +201 -0
- package/dist/core/triwiki/context-graph/extractors/topology/gates.js +182 -0
- package/dist/core/triwiki/context-graph/extractors/topology/globs.js +124 -0
- package/dist/core/triwiki/context-graph/extractors/topology/index.js +92 -0
- package/dist/core/triwiki/context-graph/extractors/topology/routes.js +135 -0
- package/dist/core/triwiki/context-graph/extractors/topology/shared.js +215 -0
- package/dist/core/triwiki/context-graph/graph-index.js +143 -0
- package/dist/core/triwiki/context-graph/ids.js +0 -0
- package/dist/core/triwiki/context-graph/lint/index.js +0 -0
- package/dist/core/triwiki/context-graph/lint/rules.js +232 -0
- package/dist/core/triwiki/context-graph/lint/warnings.js +93 -0
- package/dist/core/triwiki/context-graph/paths.js +116 -0
- package/dist/core/triwiki/context-graph/profiles.js +78 -0
- package/dist/core/triwiki/context-graph/projections/anchors.js +91 -0
- package/dist/core/triwiki/context-graph/projections/attention.js +58 -0
- package/dist/core/triwiki/context-graph/projections/code-pack-workspace.js +62 -0
- package/dist/core/triwiki/context-graph/projections/code-pack.js +144 -0
- package/dist/core/triwiki/context-graph/projections/index.js +7 -0
- package/dist/core/triwiki/context-graph/projections/module-view.js +140 -0
- package/dist/core/triwiki/context-graph/projections/node-summary.js +118 -0
- package/dist/core/triwiki/context-graph/projections/pack-contract.js +6 -0
- package/dist/core/triwiki/context-graph/query/explain.js +0 -0
- package/dist/core/triwiki/context-graph/query/index.js +178 -0
- package/dist/core/triwiki/context-graph/query/load.js +116 -0
- package/dist/core/triwiki/context-graph/query/pack.js +117 -0
- package/dist/core/triwiki/context-graph/query/rank.js +142 -0
- package/dist/core/triwiki/context-graph/query/ranking-config.js +64 -0
- package/dist/core/triwiki/context-graph/query/seeds.js +241 -0
- package/dist/core/triwiki/context-graph/query/snapshot-cache.js +72 -0
- package/dist/core/triwiki/context-graph/query/traverse.js +154 -0
- package/dist/core/triwiki/context-graph/query-types.js +29 -0
- package/dist/core/triwiki/context-graph/store/compile-lock.js +21 -0
- package/dist/core/triwiki/context-graph/store/event-log.js +48 -0
- package/dist/core/triwiki/context-graph/store/fragment-cache.js +85 -0
- package/dist/core/triwiki/context-graph/store/graph-status.js +85 -0
- package/dist/core/triwiki/context-graph/store/snapshot-store.js +155 -0
- package/dist/core/triwiki/triwiki-proof-bank-index-repair.js +115 -0
- package/dist/core/triwiki/triwiki-proof-bank-index-store.js +290 -0
- package/dist/core/triwiki/triwiki-proof-bank-index.js +126 -0
- package/dist/core/triwiki/triwiki-proof-bank.js +7 -1
- package/dist/core/verification/context-graph-affected.js +271 -0
- package/dist/core/version.js +1 -1
- package/dist/native/sks-menubar/Sources/AlertFactory.swift +11 -3
- package/dist/native/sks-menubar/Sources/AppDelegate.swift +9 -0
- package/dist/native/sks-menubar/Sources/ControlCenterWindowController.swift +25 -3
- package/dist/native/sks-menubar/Sources/ControlKit.swift +19 -8
- package/dist/native/sks-menubar/Sources/DiagnosticsViewController.swift +1 -2
- package/dist/native/sks-menubar/Sources/MCPServersViewController.swift +45 -17
- package/dist/native/sks-menubar/Sources/OverviewSummary.swift +162 -0
- package/dist/native/sks-menubar/Sources/OverviewViewController.swift +136 -190
- package/dist/native/sks-menubar/Sources/ProcessClient.swift +107 -11
- package/dist/native/sks-menubar/Sources/ProvidersMultiProvider.swift +5 -1
- package/dist/native/sks-menubar/Sources/ProvidersOpenRouter.swift +16 -4
- package/dist/native/sks-menubar/Sources/ProvidersRoleModels.swift +4 -1
- package/dist/native/sks-menubar/Sources/ProvidersRoutingTruth.swift +131 -0
- package/dist/native/sks-menubar/Sources/ProvidersViewController.swift +288 -341
- package/dist/native/sks-menubar/Sources/RemoteTelegramCenterState.swift +447 -0
- package/dist/native/sks-menubar/Sources/RemoteTelegramRendering.swift +484 -0
- package/dist/native/sks-menubar/Sources/RemoteTelegramViewController.swift +364 -115
- package/dist/native/sks-menubar/Sources/SettingsViewController.swift +73 -12
- package/dist/native/sks-menubar/Sources/SidebarItem.swift +3 -3
- package/dist/native/sks-menubar/Sources/StatusItemController.swift +13 -13
- package/dist/native/sks-menubar/Sources/TelegramHubSupervisor.swift +469 -0
- package/dist/native/sks-menubar/Sources/UpdatesViewController.swift +1 -6
- package/dist/native/sks-menubar/Tests/AppRuntimeTestSupport.swift +12 -0
- package/dist/native/sks-menubar/Tests/NativeTelegramRegressionRunner.swift +55 -0
- package/dist/native/sks-menubar/Tests/ProcessClientTests.swift +33 -0
- package/dist/native/sks-menubar/Tests/ProvidersViewControllerTests.swift +142 -0
- package/dist/native/sks-menubar/Tests/RemoteTelegramCenterStateTests.swift +56 -0
- package/dist/native/sks-menubar/Tests/TelegramHubSupervisorTests.swift +55 -0
- package/dist/scripts/codex-lb-catalog-passthrough-check.js +120 -0
- package/dist/scripts/codex-lb-desktop-auth-invariant-check.js +169 -0
- package/dist/scripts/codex-lb-desktop-bridge-check.js +394 -0
- package/dist/scripts/codex-lb-desktop-bridge-latency-check.js +196 -0
- package/dist/scripts/codex-lb-desktop-capabilities-check.js +287 -0
- package/dist/scripts/codex-lb-desktop-real-evidence-check.js +123 -0
- package/dist/scripts/codex-lb-fast-mode-truth-check.js +10 -3
- package/dist/scripts/codex-lb-fast-ui-preservation-check.js +81 -40
- package/dist/scripts/codex-lb-gpt56-fast-profile-check.js +99 -37
- package/dist/scripts/context-graph-check.js +191 -0
- package/dist/scripts/doctor-fixes-codex-app-fast-ui-check.js +1 -1
- package/dist/scripts/gate-policy-audit-check.js +1 -1
- package/dist/scripts/helper-dedup-check.js +0 -2
- package/dist/scripts/installed-package-smoke-check.js +4 -1
- package/dist/scripts/latest-version-guidance-check.js +74 -0
- package/dist/scripts/release-metadata-check.js +21 -4
- package/dist/scripts/release-real-check.js +7 -0
- package/dist/scripts/ux-review-imagegen-blackbox-check.js +25 -1
- package/dist/scripts/ux-review-run-wires-imagegen-check.js +9 -1
- package/package.json +8 -3
- package/release-gates.v2.json +176 -1
- package/runtime-required-scripts.json +30 -0
- package/schemas/triwiki/context-graph.schema.json +119 -0
- package/dist/cli/install-helpers-codex-lb-selftest-chain.js +0 -112
- package/dist/cli/install-helpers-codex-lb-selftest.js +0 -481
- package/dist/core/triwiki/code-index-scanner.js +0 -309
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
import fs from 'node:fs/promises';
|
|
3
3
|
import os from 'node:os';
|
|
4
4
|
import path from 'node:path';
|
|
5
|
-
import { codexFastModeDesktopStatus, codexLbConfigPath, configureCodexLb,
|
|
5
|
+
import { codexFastModeDesktopStatus, codexLbConfigPath, configureCodexLb, configureCodexLbDesktopRouting, ensureGlobalCodexFastModeDuringInstall, repairCodexLbAuth } from '../cli/install-helpers.js';
|
|
6
6
|
import { repairCodexConfigStructure, splitCodexProjectConfigPolicy } from '../core/codex/codex-project-config-policy.js';
|
|
7
7
|
import { parseCodexConfigToml, validateCodexConfigRoundTrip } from '../core/codex/codex-config-toml.js';
|
|
8
8
|
import { CODEX_LB_TOOL_OUTPUT_RECOVERY_MIN_VERSION } from '../core/codex-lb/codex-lb-tool-output-recovery.js';
|
|
@@ -14,30 +14,70 @@ const codexHome = path.join(home, '.codex');
|
|
|
14
14
|
const configPath = codexLbConfigPath(home);
|
|
15
15
|
const envPath = path.join(codexHome, 'sks-codex-lb.env');
|
|
16
16
|
const authPath = path.join(codexHome, 'auth.json');
|
|
17
|
-
const oauthBackupPath = path.join(codexHome, 'auth.chatgpt-backup.json');
|
|
18
17
|
const projectConfig = path.join(root, '.codex', 'config.toml');
|
|
18
|
+
const remoteBaseUrl = 'https://lb.example.test/backend-api/codex';
|
|
19
|
+
const bridgeBaseUrl = 'http://127.0.0.1:54321/backend-api/codex';
|
|
19
20
|
await fs.mkdir(path.dirname(projectConfig), { recursive: true });
|
|
20
21
|
await fs.mkdir(codexHome, { recursive: true });
|
|
21
|
-
|
|
22
|
+
const oauth = `${JSON.stringify({
|
|
23
|
+
auth_mode: 'chatgpt',
|
|
24
|
+
account_id: 'acct-fast-profile',
|
|
25
|
+
tokens: {
|
|
26
|
+
access_token: 'oauth-access',
|
|
27
|
+
refresh_token: 'oauth-refresh'
|
|
28
|
+
}
|
|
29
|
+
}, null, 2)}\n`;
|
|
30
|
+
await fs.writeFile(authPath, oauth);
|
|
22
31
|
const setup = await configureCodexLb({
|
|
23
32
|
home,
|
|
24
33
|
configPath,
|
|
25
34
|
envPath,
|
|
26
|
-
host:
|
|
35
|
+
host: remoteBaseUrl,
|
|
27
36
|
apiKey: 'fixture-codex-lb-fast-key',
|
|
28
37
|
writeEnvFile: true,
|
|
29
|
-
useDefaultProvider: true,
|
|
30
|
-
forceFastMode: true,
|
|
31
|
-
forceCodexLbApiKeyAuth: true,
|
|
32
|
-
authMode: 'codex-lb',
|
|
33
38
|
shellProfile: 'skip',
|
|
39
|
+
gatewayAuthTransport: 'x-codex-lb-api-key',
|
|
34
40
|
toolOutputRecoveryFetch
|
|
35
41
|
});
|
|
36
|
-
const
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
42
|
+
const native = await configureCodexLbDesktopRouting({
|
|
43
|
+
mode: 'desktop-native-bridge',
|
|
44
|
+
home,
|
|
45
|
+
configPath,
|
|
46
|
+
authPath,
|
|
47
|
+
bridgeBaseUrl,
|
|
48
|
+
remoteBaseUrl,
|
|
49
|
+
gatewayAuthTransport: 'x-codex-lb-api-key'
|
|
50
|
+
});
|
|
51
|
+
const fastOn = await ensureGlobalCodexFastModeDuringInstall({
|
|
52
|
+
home,
|
|
53
|
+
configPath,
|
|
54
|
+
forceFastMode: true
|
|
55
|
+
});
|
|
56
|
+
const first = assertFastProfile(await fs.readFile(configPath, 'utf8'), 'native_fast_on');
|
|
57
|
+
const disabled = await configureCodexLbDesktopRouting({
|
|
58
|
+
mode: 'disabled',
|
|
59
|
+
home,
|
|
60
|
+
configPath,
|
|
61
|
+
authPath
|
|
62
|
+
});
|
|
63
|
+
const afterDisable = assertFastProfile(await fs.readFile(configPath, 'utf8'), 'routing_disabled', false);
|
|
64
|
+
const reenabled = await configureCodexLbDesktopRouting({
|
|
65
|
+
mode: 'desktop-native-bridge',
|
|
66
|
+
home,
|
|
67
|
+
configPath,
|
|
68
|
+
authPath,
|
|
69
|
+
bridgeBaseUrl,
|
|
70
|
+
remoteBaseUrl,
|
|
71
|
+
gatewayAuthTransport: 'x-codex-lb-api-key'
|
|
72
|
+
});
|
|
73
|
+
const repair = await repairCodexLbAuth({
|
|
74
|
+
home,
|
|
75
|
+
configPath,
|
|
76
|
+
envPath,
|
|
77
|
+
forceCodexLbApiKeyAuth: true,
|
|
78
|
+
forceFastMode: true,
|
|
79
|
+
authMode: 'codex-lb'
|
|
80
|
+
});
|
|
41
81
|
await fs.writeFile(projectConfig, [
|
|
42
82
|
'# SKS managed fixture',
|
|
43
83
|
'default_profile = "sks-fast-high"',
|
|
@@ -52,37 +92,53 @@ await fs.writeFile(projectConfig, [
|
|
|
52
92
|
'service_tier = "fast"',
|
|
53
93
|
''
|
|
54
94
|
].join('\n'));
|
|
55
|
-
const split = await splitCodexProjectConfigPolicy(root, {
|
|
95
|
+
const split = await splitCodexProjectConfigPolicy(root, {
|
|
96
|
+
apply: true,
|
|
97
|
+
codexHome,
|
|
98
|
+
configPath: projectConfig,
|
|
99
|
+
writeReport: false
|
|
100
|
+
});
|
|
56
101
|
const structure = await repairCodexConfigStructure(configPath, { apply: true });
|
|
57
102
|
const final = assertFastProfile(await fs.readFile(configPath, 'utf8'), 'after_rewriters');
|
|
58
103
|
const toolCatalog = assertGpt56ToolCatalogContract();
|
|
59
|
-
const
|
|
104
|
+
const authPreserved = await fs.readFile(authPath, 'utf8') === oauth;
|
|
105
|
+
const ok = setup.ok === true
|
|
106
|
+
&& native.ok === true
|
|
107
|
+
&& disabled.ok === true
|
|
108
|
+
&& reenabled.ok === true
|
|
60
109
|
&& !['failed', 'skipped_unsafe_rewrite', 'unparseable_config_preserved'].includes(String(fastOn.status))
|
|
61
|
-
&&
|
|
62
|
-
&& repair.ok !== false
|
|
110
|
+
&& repair.ok === true
|
|
63
111
|
&& split.ok === true
|
|
64
112
|
&& structure.ok === true
|
|
113
|
+
&& authPreserved
|
|
65
114
|
&& first.ok
|
|
66
|
-
&&
|
|
115
|
+
&& afterDisable.ok
|
|
67
116
|
&& final.ok
|
|
68
117
|
&& toolCatalog.ok;
|
|
69
118
|
const report = {
|
|
70
|
-
schema: 'sks.codex-lb-gpt56-fast-profile-check.
|
|
119
|
+
schema: 'sks.codex-lb-gpt56-fast-profile-check.v2',
|
|
71
120
|
ok,
|
|
72
121
|
setup_status: setup.status,
|
|
122
|
+
native_status: native.status,
|
|
73
123
|
fast_on_status: fastOn.status,
|
|
74
|
-
|
|
124
|
+
disable_status: disabled.status,
|
|
125
|
+
reenable_status: reenabled.status,
|
|
75
126
|
repair_status: repair.status,
|
|
76
127
|
split_status: split.status || null,
|
|
77
128
|
structure_status: structure.status,
|
|
78
|
-
|
|
129
|
+
oauth_preserved: authPreserved,
|
|
130
|
+
assertions: [first, afterDisable, final],
|
|
79
131
|
tool_catalog: toolCatalog,
|
|
80
|
-
blockers: [
|
|
132
|
+
blockers: [
|
|
133
|
+
...(authPreserved ? [] : ['chatgpt_oauth_changed']),
|
|
134
|
+
...[first, afterDisable, final].flatMap((item) => item.blockers),
|
|
135
|
+
...toolCatalog.blockers
|
|
136
|
+
]
|
|
81
137
|
};
|
|
82
138
|
console.log(JSON.stringify(report, null, 2));
|
|
83
139
|
if (!report.ok)
|
|
84
140
|
process.exitCode = 1;
|
|
85
|
-
function assertFastProfile(text, label) {
|
|
141
|
+
function assertFastProfile(text, label, expectBridge = true) {
|
|
86
142
|
const validation = validateCodexConfigRoundTrip(text);
|
|
87
143
|
const parsed = validation.ok ? parseCodexConfigToml(text) : {};
|
|
88
144
|
const provider = parsed.model_providers?.['codex-lb'] || {};
|
|
@@ -93,8 +149,14 @@ function assertFastProfile(text, label) {
|
|
|
93
149
|
...(parsed.user?.fast_mode === undefined ? [] : ['user_fast_mode_legacy_table_present']),
|
|
94
150
|
...(parsed.profiles?.['sks-fast-high'] === undefined ? [] : ['sks_fast_high_legacy_profile_present']),
|
|
95
151
|
...(parsed.model === undefined ? [] : ['codex_app_model_was_injected']),
|
|
96
|
-
...(
|
|
152
|
+
...(parsed.model_provider === undefined ? [] : ['desktop_model_provider_was_selected']),
|
|
153
|
+
...(provider.name === 'codex-lb' ? [] : ['codex_lb_cli_provider_name_mismatch']),
|
|
154
|
+
...(provider.requires_openai_auth === false ? [] : ['codex_lb_cli_requires_openai_auth_not_false']),
|
|
155
|
+
...(provider.env_key === 'CODEX_LB_API_KEY' ? [] : ['codex_lb_cli_env_key_missing']),
|
|
97
156
|
...(provider.wire_api === 'responses' ? [] : ['codex_lb_wire_api_not_responses']),
|
|
157
|
+
...(expectBridge && parsed.openai_base_url === bridgeBaseUrl ? [] : expectBridge ? ['native_bridge_base_url_missing'] : []),
|
|
158
|
+
...(!expectBridge && parsed.openai_base_url !== undefined ? ['disabled_routing_still_has_openai_base_url'] : []),
|
|
159
|
+
...(parsed.model_catalog_json === undefined ? [] : ['native_local_catalog_must_not_be_bound']),
|
|
98
160
|
...(desktop.on ? [] : ['desktop_fast_status_off'])
|
|
99
161
|
];
|
|
100
162
|
return {
|
|
@@ -102,8 +164,11 @@ function assertFastProfile(text, label) {
|
|
|
102
164
|
ok: blockers.length === 0,
|
|
103
165
|
default_profile: parsed.default_profile || null,
|
|
104
166
|
model: parsed.model || null,
|
|
167
|
+
model_provider: parsed.model_provider || null,
|
|
168
|
+
openai_base_url: parsed.openai_base_url || null,
|
|
105
169
|
legacy_keys: validation.legacy_keys,
|
|
106
170
|
service_tier: parsed.service_tier || null,
|
|
171
|
+
provider_name: provider.name || null,
|
|
107
172
|
provider_wire_api: provider.wire_api || null,
|
|
108
173
|
provider_requires_openai_auth: provider.requires_openai_auth ?? null,
|
|
109
174
|
blockers
|
|
@@ -111,36 +176,32 @@ function assertFastProfile(text, label) {
|
|
|
111
176
|
}
|
|
112
177
|
function assertGpt56ToolCatalogContract() {
|
|
113
178
|
const normalized = normalizeCodexLbToolCatalog({
|
|
114
|
-
models: ['gpt-5.6-sol', 'gpt-5.6-terra', 'gpt-5.6-luna'].map(
|
|
179
|
+
models: ['gpt-5.6-sol', 'gpt-5.6-terra', 'gpt-5.6-luna'].map(codexModel)
|
|
115
180
|
});
|
|
116
181
|
const models = normalized.catalog.models.filter((model) => String(model.slug).startsWith('gpt-5.6-'));
|
|
117
182
|
const blockers = [
|
|
118
183
|
...normalized.blockers,
|
|
119
184
|
...(normalized.schema === 'sks.codex-lb-tool-catalog.v1' ? [] : ['codex_lb_gpt56_catalog_schema_mismatch']),
|
|
185
|
+
...(normalized.contract === 'codex-model-catalog-pass-through.v2' ? [] : ['codex_lb_catalog_contract_not_v2']),
|
|
120
186
|
...(normalized.tools_transport === 'full_responses' ? [] : ['codex_lb_gpt56_native_tool_transport_not_full_responses']),
|
|
121
187
|
...(normalized.patched_models.join(',') === 'gpt-5.6-luna,gpt-5.6-sol,gpt-5.6-terra' ? [] : ['codex_lb_gpt56_catalog_patch_set_incomplete']),
|
|
122
188
|
...(models.length === 3 ? [] : ['codex_lb_gpt56_catalog_model_set_incomplete']),
|
|
123
189
|
...(models.every((model) => model.use_responses_lite === false) ? [] : ['codex_lb_gpt56_responses_lite_not_disabled']),
|
|
124
|
-
...(models.every((model) => model.
|
|
125
|
-
...(models.every((model) => model.supports_parallel_tool_calls === true) ? [] : ['codex_lb_gpt56_parallel_tool_calls_not_preserved']),
|
|
126
|
-
...(models.every((model) => model.minimal_client_version === '0.144.5') ? [] : ['codex_lb_gpt56_codex_0144_contract_missing'])
|
|
190
|
+
...(models.every((model) => model.future_unknown_field === 'preserved') ? [] : ['codex_lb_unknown_catalog_field_lost'])
|
|
127
191
|
];
|
|
128
192
|
return {
|
|
129
|
-
schema: normalized.schema,
|
|
130
193
|
ok: blockers.length === 0,
|
|
131
|
-
|
|
132
|
-
models: normalized.gpt56_models,
|
|
133
|
-
patched_models: normalized.patched_models,
|
|
194
|
+
contract: normalized.contract,
|
|
134
195
|
tools_transport: normalized.tools_transport,
|
|
135
|
-
|
|
196
|
+
patched_models: normalized.patched_models,
|
|
136
197
|
blockers
|
|
137
198
|
};
|
|
138
199
|
}
|
|
139
|
-
function
|
|
200
|
+
function codexModel(slug) {
|
|
140
201
|
return {
|
|
141
202
|
slug,
|
|
142
|
-
display_name: slug
|
|
143
|
-
supported_reasoning_levels: [{ effort: '
|
|
203
|
+
display_name: slug,
|
|
204
|
+
supported_reasoning_levels: [{ effort: 'medium', description: 'Balanced' }],
|
|
144
205
|
shell_type: 'shell_command',
|
|
145
206
|
visibility: 'list',
|
|
146
207
|
supported_in_api: true,
|
|
@@ -153,7 +214,8 @@ function codex0144Model(slug) {
|
|
|
153
214
|
experimental_supported_tools: [],
|
|
154
215
|
tool_mode: 'code_mode_only',
|
|
155
216
|
use_responses_lite: true,
|
|
156
|
-
minimal_client_version: '
|
|
217
|
+
minimal_client_version: 'runtime',
|
|
218
|
+
future_unknown_field: 'preserved'
|
|
157
219
|
};
|
|
158
220
|
}
|
|
159
221
|
async function toolOutputRecoveryFetch() {
|
|
@@ -0,0 +1,191 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
import fs from 'node:fs';
|
|
3
|
+
import path from 'node:path';
|
|
4
|
+
import { spawnSync } from 'node:child_process';
|
|
5
|
+
import { assertGate, emitGate, importDist, root } from './gate-lib.js';
|
|
6
|
+
const modeIndex = process.argv.indexOf('--mode');
|
|
7
|
+
const mode = modeIndex >= 0 ? String(process.argv[modeIndex + 1] || '') : '';
|
|
8
|
+
const MODES = new Set(['contract', 'quality', 'performance', 'legacy-closure']);
|
|
9
|
+
assertGate(MODES.has(mode), 'context_graph_check_unknown_mode', { mode, modes: [...MODES] });
|
|
10
|
+
const GATE_ID = `context-graph:${mode}`;
|
|
11
|
+
function gitGrep(pattern, pathspecs) {
|
|
12
|
+
const result = spawnSync('git', ['grep', '-n', '-I', '-E', pattern, '--', ...pathspecs], {
|
|
13
|
+
cwd: root,
|
|
14
|
+
encoding: 'utf8'
|
|
15
|
+
});
|
|
16
|
+
if (result.status !== 0 && result.status !== 1) {
|
|
17
|
+
assertGate(false, 'context_graph_git_grep_failed', { pattern, stderr: (result.stderr || '').slice(0, 400) });
|
|
18
|
+
}
|
|
19
|
+
return String(result.stdout || '').split('\n').filter(Boolean);
|
|
20
|
+
}
|
|
21
|
+
async function runContract() {
|
|
22
|
+
const contracts = await importDist('core/triwiki/context-graph/contracts.js');
|
|
23
|
+
const ids = await importDist('core/triwiki/context-graph/ids.js');
|
|
24
|
+
const paths = await importDist('core/triwiki/context-graph/paths.js');
|
|
25
|
+
const profiles = await importDist('core/triwiki/context-graph/profiles.js');
|
|
26
|
+
const extractors = await importDist('core/triwiki/context-graph/extractors/index.js');
|
|
27
|
+
const schemaPath = path.join(root, 'schemas', 'triwiki', 'context-graph.schema.json');
|
|
28
|
+
assertGate(fs.existsSync(schemaPath), 'context_graph_schema_missing', { schemaPath: 'schemas/triwiki/context-graph.schema.json' });
|
|
29
|
+
const schema = JSON.parse(fs.readFileSync(schemaPath, 'utf8'));
|
|
30
|
+
assertGate(schema.title === contracts.CONTEXT_GRAPH_SCHEMA, 'context_graph_schema_title_mismatch', { title: schema.title });
|
|
31
|
+
const schemaKinds = schema.definitions.node.properties.kind.enum;
|
|
32
|
+
const schemaEdges = schema.definitions.edge.properties.type.enum;
|
|
33
|
+
assertGate(JSON.stringify(schemaKinds) === JSON.stringify([...contracts.CONTEXT_GRAPH_NODE_KINDS]), 'context_graph_node_kind_drift', { schema: schemaKinds, code: [...contracts.CONTEXT_GRAPH_NODE_KINDS] });
|
|
34
|
+
assertGate(JSON.stringify(schemaEdges) === JSON.stringify([...contracts.CONTEXT_GRAPH_EDGE_TYPES]), 'context_graph_edge_type_drift', { schema: schemaEdges, code: [...contracts.CONTEXT_GRAPH_EDGE_TYPES] });
|
|
35
|
+
const first = ids.contextGraphNodeId({ kind: 'symbol', path: 'src/a.ts', symbolKind: 'function', name: 'run', startOffset: 7 });
|
|
36
|
+
const second = ids.contextGraphNodeId({ kind: 'symbol', path: 'src/a.ts', symbolKind: 'function', name: 'run', startOffset: 7 });
|
|
37
|
+
assertGate(first === second && first === 'symbol:src/a.ts#function:run@7', 'context_graph_unstable_node_id', { first, second });
|
|
38
|
+
const edgeA = ids.contextGraphEdgeId({ from: 'file:a.ts', to: 'file:b.ts', type: 'imports' });
|
|
39
|
+
const edgeB = ids.contextGraphEdgeId({ from: 'file:a.ts', to: 'file:b.ts', type: 'imports' });
|
|
40
|
+
assertGate(edgeA === edgeB, 'context_graph_unstable_edge_id', { edgeA, edgeB });
|
|
41
|
+
const comparatorSources = gitGrep('\\.localeCompare\\(', [
|
|
42
|
+
'src/core/triwiki/context-graph/contracts.ts',
|
|
43
|
+
'src/core/triwiki/context-graph/ids.ts',
|
|
44
|
+
'src/core/triwiki/context-graph/compiler/serialize.ts'
|
|
45
|
+
]);
|
|
46
|
+
assertGate(comparatorSources.length === 0, 'context_graph_locale_sensitive_ordering', { hits: comparatorSources });
|
|
47
|
+
for (const bad of ['/etc/passwd', '../outside.ts', '']) {
|
|
48
|
+
let threw = false;
|
|
49
|
+
try {
|
|
50
|
+
paths.normalizeGraphPath(root, bad);
|
|
51
|
+
}
|
|
52
|
+
catch {
|
|
53
|
+
threw = true;
|
|
54
|
+
}
|
|
55
|
+
assertGate(threw, 'context_graph_path_escape_accepted', { candidate: bad });
|
|
56
|
+
}
|
|
57
|
+
assertGate(paths.normalizeGraphPath(root, path.join(root, 'package.json')) === 'package.json', 'context_graph_path_normalization_broken');
|
|
58
|
+
const edgeTypes = new Set(contracts.CONTEXT_GRAPH_EDGE_TYPES);
|
|
59
|
+
const reachable = new Set();
|
|
60
|
+
for (const name of profiles.CONTEXT_GRAPH_QUERY_PROFILE_NAMES) {
|
|
61
|
+
const profile = profiles.contextGraphQueryProfile(name);
|
|
62
|
+
assertGate(profile.edges.length > 0, 'context_graph_empty_profile', { profile: name });
|
|
63
|
+
for (const edge of profile.edges) {
|
|
64
|
+
assertGate(edgeTypes.has(edge), 'context_graph_profile_unknown_edge', { profile: name, edge });
|
|
65
|
+
reachable.add(edge);
|
|
66
|
+
}
|
|
67
|
+
assertGate(profile.maxDepthHighRisk >= profile.maxDepth, 'context_graph_profile_depth_inverted', { profile: name });
|
|
68
|
+
}
|
|
69
|
+
const strayWeights = gitGrep('(exact_seed_bonus|edge_profile_weight|trust_bonus|stale_penalty|redundancy_penalty|token_cost_penalty)\\s*[:=]\\s*[0-9]', [
|
|
70
|
+
'src/core/triwiki/context-graph',
|
|
71
|
+
':!src/core/triwiki/context-graph/query/ranking-config.ts',
|
|
72
|
+
':!src/core/triwiki/context-graph/**/__tests__/**'
|
|
73
|
+
]);
|
|
74
|
+
assertGate(strayWeights.length === 0, 'context_graph_ranking_constants_duplicated', { hits: strayWeights.slice(0, 10) });
|
|
75
|
+
const registered = extractors.contextGraphExtractors();
|
|
76
|
+
assertGate(registered.length >= 3, 'context_graph_extractor_registry_incomplete', { count: registered.length });
|
|
77
|
+
const registeredIds = registered.map((extractor) => extractor.id).sort();
|
|
78
|
+
assertGate(new Set(registeredIds).size === registeredIds.length, 'context_graph_extractor_id_collision', { registeredIds });
|
|
79
|
+
emitGate(GATE_ID, {
|
|
80
|
+
mode,
|
|
81
|
+
node_kinds: schemaKinds.length,
|
|
82
|
+
edge_types: schemaEdges.length,
|
|
83
|
+
profiles: profiles.CONTEXT_GRAPH_QUERY_PROFILE_NAMES.length,
|
|
84
|
+
traversable_edge_types: reachable.size,
|
|
85
|
+
extractors: registeredIds
|
|
86
|
+
});
|
|
87
|
+
}
|
|
88
|
+
async function runBenchmark() {
|
|
89
|
+
const benchmark = await importDist('core/triwiki/context-graph/benchmark/index.js');
|
|
90
|
+
const baseline = await importDist('core/triwiki/context-graph/benchmark/adapters/baseline-lexical.js');
|
|
91
|
+
const candidate = await importDist('core/triwiki/context-graph/benchmark/adapters/candidate-graph.js');
|
|
92
|
+
return benchmark.runContextGraphBenchmark([baseline.createBaselineLexicalAdapter(), candidate.createCandidateGraphAdapter()], { root, writeReport: true });
|
|
93
|
+
}
|
|
94
|
+
function summaryOf(report, kind) {
|
|
95
|
+
return report.summaries.find((entry) => entry.adapterKind === kind) || null;
|
|
96
|
+
}
|
|
97
|
+
function failedFloors(report) {
|
|
98
|
+
return report.floors.results.filter((floor) => !floor.passed).map((floor) => ({
|
|
99
|
+
id: floor.id,
|
|
100
|
+
adapter: floor.adapterId,
|
|
101
|
+
observed: floor.observed,
|
|
102
|
+
limit: floor.limit,
|
|
103
|
+
detail: floor.detail.slice(0, 6)
|
|
104
|
+
}));
|
|
105
|
+
}
|
|
106
|
+
async function runQuality() {
|
|
107
|
+
const report = await runBenchmark();
|
|
108
|
+
assertGate(report.integrity.ok, 'context_graph_benchmark_corpus_tampered', { integrity: report.integrity });
|
|
109
|
+
assertGate(report.floors.ok, 'context_graph_hard_safety_floor_failed', { failed: failedFloors(report) });
|
|
110
|
+
const candidate = summaryOf(report, 'candidate');
|
|
111
|
+
assertGate(Boolean(candidate), 'context_graph_benchmark_missing_candidate');
|
|
112
|
+
assertGate(candidate.provenanceCoverage >= 1, 'context_graph_provenance_coverage_below_floor', { observed: candidate.provenanceCoverage });
|
|
113
|
+
assertGate(candidate.protectedGateRecall >= 1, 'context_graph_protected_gate_recall_below_floor', { observed: candidate.protectedGateRecall });
|
|
114
|
+
assertGate(candidate.conflictRecall >= 1, 'context_graph_conflict_recall_below_floor', { observed: candidate.conflictRecall });
|
|
115
|
+
assertGate(candidate.recallAtK >= 0.9, 'context_graph_recall_below_floor', { observed: candidate.recallAtK });
|
|
116
|
+
assertGate(candidate.precisionAtK >= 0.5, 'context_graph_precision_below_floor', { observed: candidate.precisionAtK });
|
|
117
|
+
assertGate(report.score !== null && report.score.passed, 'context_graph_composite_below_threshold', { score: report.score });
|
|
118
|
+
emitGate(GATE_ID, {
|
|
119
|
+
mode,
|
|
120
|
+
recall_at_k: candidate.recallAtK,
|
|
121
|
+
precision_at_k: candidate.precisionAtK,
|
|
122
|
+
protected_gate_recall: candidate.protectedGateRecall,
|
|
123
|
+
conflict_recall: candidate.conflictRecall,
|
|
124
|
+
provenance_coverage: candidate.provenanceCoverage,
|
|
125
|
+
composite_improvement: report.score.improvement,
|
|
126
|
+
floors_evaluated: report.floors.evaluated
|
|
127
|
+
});
|
|
128
|
+
}
|
|
129
|
+
async function runPerformance() {
|
|
130
|
+
const report = await runBenchmark();
|
|
131
|
+
assertGate(report.integrity.ok, 'context_graph_benchmark_corpus_tampered', { integrity: report.integrity });
|
|
132
|
+
assertGate(report.floors.ok, 'context_graph_hard_safety_floor_failed', { failed: failedFloors(report) });
|
|
133
|
+
const candidate = summaryOf(report, 'candidate');
|
|
134
|
+
const baseline = summaryOf(report, 'baseline');
|
|
135
|
+
assertGate(Boolean(candidate) && Boolean(baseline), 'context_graph_benchmark_missing_adapter');
|
|
136
|
+
const warmP95 = candidate.warmLatency.p95;
|
|
137
|
+
const baselineWarmP95 = baseline.warmLatency.p95;
|
|
138
|
+
const latencyOk = warmP95 <= 75 || (baselineWarmP95 > 0 && warmP95 <= baselineWarmP95 * 0.7);
|
|
139
|
+
assertGate(latencyOk, 'context_graph_warm_latency_regression', { warmP95, baselineWarmP95 });
|
|
140
|
+
const tokenOk = baseline.meanTokenCost === 0 || candidate.meanTokenCost <= baseline.meanTokenCost * 0.7;
|
|
141
|
+
assertGate(tokenOk, 'context_graph_token_cost_regression', { candidate: candidate.meanTokenCost, baseline: baseline.meanTokenCost });
|
|
142
|
+
assertGate(candidate.warmCacheHitRate >= 0.9, 'context_graph_cache_hit_below_floor', { observed: candidate.warmCacheHitRate });
|
|
143
|
+
emitGate(GATE_ID, {
|
|
144
|
+
mode,
|
|
145
|
+
warm_p95_ms: warmP95,
|
|
146
|
+
baseline_warm_p95_ms: baselineWarmP95,
|
|
147
|
+
mean_token_cost: candidate.meanTokenCost,
|
|
148
|
+
baseline_mean_token_cost: baseline.meanTokenCost,
|
|
149
|
+
warm_cache_hit_rate: candidate.warmCacheHitRate
|
|
150
|
+
});
|
|
151
|
+
}
|
|
152
|
+
function runLegacyClosure() {
|
|
153
|
+
const excluded = [':!CHANGELOG.md', ':!docs/work-orders', ':!.sneakoscope', ':!src/scripts/context-graph-check.ts'];
|
|
154
|
+
const checks = [
|
|
155
|
+
{ id: 'triwiki_codepack_local', pattern: 'triwiki_codepack_local', pathspecs: ['.', ...excluded] },
|
|
156
|
+
{ id: 'simple_counts_comment', pattern: 'simple counts avoid needing a real dependency graph', pathspecs: ['.', ...excluded] },
|
|
157
|
+
{ id: 'scanCodebaseIndex', pattern: '\\bscanCodebaseIndex\\b', pathspecs: ['.', ...excluded] },
|
|
158
|
+
{ id: 'code_index_scanner_module', pattern: 'code-index-scanner', pathspecs: ['src', 'package.json', 'release-gates.v2.json', 'infra-harness-gates.json', 'runtime-required-scripts.json', ':!src/scripts/context-graph-check.ts'] },
|
|
159
|
+
{
|
|
160
|
+
id: 'attentionRelevance',
|
|
161
|
+
pattern: '\\battentionRelevance\\b',
|
|
162
|
+
pathspecs: ['.', ...excluded, ':!src/core/subagents/__tests__']
|
|
163
|
+
},
|
|
164
|
+
{
|
|
165
|
+
id: 'lexical_fallback_in_context_mode',
|
|
166
|
+
pattern: '\\b(searchFilesJs|searchTextJs)\\b',
|
|
167
|
+
pathspecs: ['src/core/search/context.ts']
|
|
168
|
+
}
|
|
169
|
+
];
|
|
170
|
+
const violations = [];
|
|
171
|
+
for (const check of checks) {
|
|
172
|
+
const hits = gitGrep(check.pattern, check.pathspecs);
|
|
173
|
+
if (hits.length)
|
|
174
|
+
violations.push({ id: check.id, hits: hits.slice(0, 6) });
|
|
175
|
+
}
|
|
176
|
+
assertGate(violations.length === 0, 'context_graph_legacy_path_survives', { violations });
|
|
177
|
+
for (const retired of ['src/core/triwiki/code-index-scanner.ts']) {
|
|
178
|
+
assertGate(!fs.existsSync(path.join(root, retired)), 'context_graph_retired_file_present', { path: retired });
|
|
179
|
+
}
|
|
180
|
+
const parked = gitGrep('code-index-scanner', ['src', ':!src/core/triwiki/context-graph', ':!src/scripts/context-graph-check.ts']);
|
|
181
|
+
assertGate(parked.length === 0, 'context_graph_retired_file_parked', { hits: parked.slice(0, 6) });
|
|
182
|
+
emitGate(GATE_ID, { mode, checks: checks.length, retired_modules: 1 });
|
|
183
|
+
}
|
|
184
|
+
if (mode === 'contract')
|
|
185
|
+
await runContract();
|
|
186
|
+
else if (mode === 'quality')
|
|
187
|
+
await runQuality();
|
|
188
|
+
else if (mode === 'performance')
|
|
189
|
+
await runPerformance();
|
|
190
|
+
else
|
|
191
|
+
runLegacyClosure();
|
|
@@ -12,7 +12,7 @@ const codexHome = path.join(root, 'home', '.codex');
|
|
|
12
12
|
await fs.mkdir(path.join(root, '.codex'), { recursive: true });
|
|
13
13
|
await fs.mkdir(codexHome, { recursive: true });
|
|
14
14
|
await fs.writeFile(path.join(root, '.codex', 'config.toml'), 'model = "future-codex-model"\nmodel_reasoning_effort = "medium"\nmodel_provider = "codex-lb"\n');
|
|
15
|
-
await fs.writeFile(path.join(codexHome, 'config.toml'), '# SKS forced fast UI during legacy install\nmodel = "legacy-sks-model"\nmodel_reasoning_effort = "xhigh"\nmodel_provider = "codex-lb"\nservice_tier = "fast"\n[features]\nfast_mode = false # user disabled, must remain untouched\n\n[profiles.sks-fast-high]\nmodel = "legacy-profile-model"\nservice_tier = "fast"\n\n[model_providers.codex-lb]\nname = "
|
|
15
|
+
await fs.writeFile(path.join(codexHome, 'config.toml'), '# SKS forced fast UI during legacy install\nmodel = "legacy-sks-model"\nmodel_reasoning_effort = "xhigh"\nmodel_provider = "codex-lb"\nservice_tier = "fast"\n[features]\nfast_mode = false # user disabled, must remain untouched\n\n[profiles.sks-fast-high]\nmodel = "legacy-profile-model"\nservice_tier = "fast"\n\n[model_providers.codex-lb]\nname = "codex-lb"\nbase_url = "https://lb.example.test/backend-api/codex"\nwire_api = "responses"\nenv_key = "CODEX_LB_API_KEY"\nsupports_websockets = true\nrequires_openai_auth = false\n');
|
|
16
16
|
const fixtureEnv = {};
|
|
17
17
|
const plan = await repairCodexAppFastUi(root, { codexHome, apply: false, env: fixtureEnv });
|
|
18
18
|
const repaired = await repairCodexAppFastUi(root, { codexHome, apply: true, env: fixtureEnv });
|
|
@@ -44,7 +44,7 @@ if (releaseGates.length > 200)
|
|
|
44
44
|
blockers.push(`release_preset_gate_budget_exceeded:${releaseGates.length}`);
|
|
45
45
|
if (gates.length > 200)
|
|
46
46
|
blockers.push(`release_manifest_gate_budget_exceeded:${gates.length}`);
|
|
47
|
-
if (Object.keys(pkg.scripts || {}).length >
|
|
47
|
+
if (Object.keys(pkg.scripts || {}).length > 101)
|
|
48
48
|
blockers.push(`package_script_budget_exceeded:${Object.keys(pkg.scripts || {}).length}`);
|
|
49
49
|
if (releaseGates.some((gate) => String(gate.id || '').startsWith('zellij:')))
|
|
50
50
|
blockers.push('zellij_gate_in_release_preset');
|
|
@@ -14,7 +14,10 @@ emitGate('runtime:installed-smoke', {
|
|
|
14
14
|
tarball: report.tarball,
|
|
15
15
|
tarball_sha256: report.tarball_sha256,
|
|
16
16
|
exact_match: report.tarball_binding.exact_match,
|
|
17
|
-
install_prefix: report.install_prefix
|
|
17
|
+
install_prefix: report.install_prefix,
|
|
18
|
+
postinstall_external_snapshot_match: report.postinstall_default.external_snapshot_match,
|
|
19
|
+
postinstall_launchctl_calls: report.postinstall_default.launchctl_calls.length,
|
|
20
|
+
postinstall_package_local_stamp_present: report.postinstall_default.package_local_stamp_present
|
|
18
21
|
});
|
|
19
22
|
function option(name) {
|
|
20
23
|
const index = process.argv.indexOf(name);
|
|
@@ -0,0 +1,74 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
import fs from 'node:fs';
|
|
3
|
+
import path from 'node:path';
|
|
4
|
+
import { assertGate, emitGate, importDist, root } from './gate-lib.js';
|
|
5
|
+
const { scanLatestVersionGuidance, latestVersionGuidanceReport } = await importDist('core/policy/latest-version-guidance.js');
|
|
6
|
+
const DOC_EXEMPT_RE = /(?:^|\/)(?:CHANGELOG|RECALLPULSE_[^/]*|known-gaps|release-proof-truth)\.md$|compat|codex-0|migration|legacy-upgrade|sks-4-migration|-tasks\.md$/i;
|
|
7
|
+
const SOURCE_EXEMPT = new Set([
|
|
8
|
+
'src/core/codex-compat/codex-release-manifest.ts',
|
|
9
|
+
'src/core/release/npm-stage-tarball-verifier-support.ts'
|
|
10
|
+
]);
|
|
11
|
+
const SOURCE_EXEMPT_DIR_RE = /^src\/(?:scripts|vendor|generated)\//;
|
|
12
|
+
function walk(dir, accept, out = []) {
|
|
13
|
+
let entries = [];
|
|
14
|
+
try {
|
|
15
|
+
entries = fs.readdirSync(path.join(root, dir), { withFileTypes: true });
|
|
16
|
+
}
|
|
17
|
+
catch {
|
|
18
|
+
return out;
|
|
19
|
+
}
|
|
20
|
+
for (const entry of entries.sort((a, b) => a.name.localeCompare(b.name))) {
|
|
21
|
+
const rel = `${dir}/${entry.name}`;
|
|
22
|
+
if (entry.isDirectory()) {
|
|
23
|
+
if (['node_modules', 'dist', '.git', '__tests__', 'fixtures'].includes(entry.name))
|
|
24
|
+
continue;
|
|
25
|
+
walk(rel, accept, out);
|
|
26
|
+
}
|
|
27
|
+
else if (accept(rel)) {
|
|
28
|
+
out.push(rel);
|
|
29
|
+
}
|
|
30
|
+
}
|
|
31
|
+
return out;
|
|
32
|
+
}
|
|
33
|
+
const exemptions = [];
|
|
34
|
+
const findings = [];
|
|
35
|
+
let scannedFiles = 0;
|
|
36
|
+
function scan(rel, options) {
|
|
37
|
+
const absolute = path.join(root, rel);
|
|
38
|
+
if (!fs.existsSync(absolute))
|
|
39
|
+
return;
|
|
40
|
+
scannedFiles += 1;
|
|
41
|
+
findings.push(...scanLatestVersionGuidance(rel, fs.readFileSync(absolute, 'utf8'), options));
|
|
42
|
+
}
|
|
43
|
+
scan('README.md', {});
|
|
44
|
+
for (const rel of walk('docs', (candidate) => candidate.endsWith('.md') && path.dirname(candidate) === 'docs')) {
|
|
45
|
+
if (DOC_EXEMPT_RE.test(rel)) {
|
|
46
|
+
exemptions.push(rel);
|
|
47
|
+
continue;
|
|
48
|
+
}
|
|
49
|
+
scan(rel, {});
|
|
50
|
+
}
|
|
51
|
+
for (const rel of walk('src', (candidate) => candidate.endsWith('.ts'))) {
|
|
52
|
+
if (SOURCE_EXEMPT.has(rel) || SOURCE_EXEMPT_DIR_RE.test(rel)) {
|
|
53
|
+
exemptions.push(rel);
|
|
54
|
+
continue;
|
|
55
|
+
}
|
|
56
|
+
scan(rel, { stringLiteralsOnly: true });
|
|
57
|
+
}
|
|
58
|
+
for (const rel of walk('native', (candidate) => candidate.endsWith('.swift'))) {
|
|
59
|
+
scan(rel, { stringLiteralsOnly: true });
|
|
60
|
+
}
|
|
61
|
+
const report = latestVersionGuidanceReport(findings, scannedFiles, exemptions);
|
|
62
|
+
const outDir = path.join(root, '.sneakoscope', 'reports');
|
|
63
|
+
fs.mkdirSync(outDir, { recursive: true });
|
|
64
|
+
fs.writeFileSync(path.join(outDir, 'latest-version-guidance.json'), `${JSON.stringify(report, null, 2)}\n`);
|
|
65
|
+
assertGate(report.ok, 'user_facing_pinned_version_guidance', {
|
|
66
|
+
findings: report.findings.slice(0, 40),
|
|
67
|
+
total: report.findings.length,
|
|
68
|
+
policy: 'Recommend the official latest stable release and let capability probes decide support. See docs/architecture/latest-version-guidance-policy.md.'
|
|
69
|
+
});
|
|
70
|
+
emitGate('latest-version:guidance', {
|
|
71
|
+
scanned_files: report.scannedFiles,
|
|
72
|
+
exempt_files: report.exemptions.length,
|
|
73
|
+
findings: 0
|
|
74
|
+
});
|
|
@@ -111,7 +111,7 @@ assertGate(releaseManifest?.schema === 'sks.release-gates.v2', 'release gate man
|
|
|
111
111
|
assertGate(harnessManifest?.schema === 'sks.infra-harness-gates.v1', 'infra harness manifest schema mismatch', { schema: harnessManifest?.schema || null });
|
|
112
112
|
assertGate(releaseGates.length > 0 && releaseGates.length <= 200, 'release manifest must include 1..200 release gates', { release_gates: releaseGates.length });
|
|
113
113
|
assertGate(harnessGates.length > 0, 'infra harness manifest must include harness gates', { harness_gates: harnessGates.length });
|
|
114
|
-
assertGate(Object.keys(pkg.scripts || {}).length <=
|
|
114
|
+
assertGate(Object.keys(pkg.scripts || {}).length <= 101, 'package script budget exceeded', { script_count: Object.keys(pkg.scripts || {}).length, limit: 101 });
|
|
115
115
|
for (const script of requiredPackageScripts)
|
|
116
116
|
assertGate(Boolean(pkg.scripts?.[script]), `missing package script: ${script}`);
|
|
117
117
|
const fullReleaseScript = String(pkg.scripts?.['release:check:full'] || '');
|
|
@@ -149,15 +149,23 @@ assertGate(currentDollarManifest.includes("{ command: '$Naruto'") && currentDoll
|
|
|
149
149
|
const stageWorkflow = text('.github/workflows/publish-npm.yml');
|
|
150
150
|
const stageJob = stageWorkflow.match(/^ stage-publish:\n[\s\S]*$/m)?.[0] || '';
|
|
151
151
|
const workflowPermissions = stageWorkflow.match(/^permissions:\n(?: [^\n]+\n)+/m)?.[0] || '';
|
|
152
|
+
const stageContract = text('src/core/release/npm-stage-contract.ts');
|
|
153
|
+
const stagePublishSource = text('src/core/release/stage-publish.ts');
|
|
152
154
|
const stageVerifierSource = text('src/core/release/npm-stage-tarball-verifier.ts');
|
|
153
155
|
const stageVerifierSupport = text('src/core/release/npm-stage-tarball-verifier-support.ts');
|
|
154
156
|
const stageVerifierCli = text('src/scripts/npm-stage-tarball-verifier.ts');
|
|
155
157
|
const releaseReadinessDoc = text('docs/release-readiness.md');
|
|
158
|
+
const workflowNpmStageVersion = stageWorkflow.match(/NPM_STAGE_CLI_VERSION:\s*([0-9]+\.[0-9]+\.[0-9]+)/)?.[1] || '';
|
|
159
|
+
const localNpmStageVersion = stageContract.match(/REQUIRED_NPM_STAGE_CLI_VERSION = '([0-9]+\.[0-9]+\.[0-9]+)'/)?.[1] || '';
|
|
156
160
|
for (const job of ['linux-release-proof', 'macos-menubar-proof', 'pack-and-compare', 'stage-publish']) {
|
|
157
161
|
assertGate(new RegExp(`^ ${job}:`, 'm').test(stageWorkflow), `stage workflow missing job: ${job}`);
|
|
158
162
|
}
|
|
159
163
|
assertGate(/npm install --global npm@\$\{NPM_STAGE_CLI_VERSION\}/.test(stageWorkflow), 'stage workflow must install the exact pinned npm CLI');
|
|
160
|
-
assertGate(
|
|
164
|
+
assertGate(workflowNpmStageVersion === '11.15.0', 'stage workflow must pin npm 11.15.0', { version: workflowNpmStageVersion || null });
|
|
165
|
+
assertGate(localNpmStageVersion === workflowNpmStageVersion, 'local and workflow npm stage CLI versions must match', {
|
|
166
|
+
local_version: localNpmStageVersion || null,
|
|
167
|
+
workflow_version: workflowNpmStageVersion || null
|
|
168
|
+
});
|
|
161
169
|
assertGate(/npm stage publish "\$TARBALL"/.test(stageWorkflow), 'stage workflow must stage the exact tarball path');
|
|
162
170
|
assertGate((stageWorkflow.match(/npm stage publish "\$TARBALL"/g) || []).length === 1, 'stage workflow must contain exactly one registry mutation');
|
|
163
171
|
assertGate(!/\bnpm\s+publish\b/.test(stageWorkflow), 'stage workflow must not call direct npm publish');
|
|
@@ -177,15 +185,24 @@ assertGate(/tarball_integrity: sha512Integrity/.test(stageJob), 'stage receipt m
|
|
|
177
185
|
assertGate(/stage-receipt\/stage-output\.json/.test(stageJob) && /path: stage-receipt/.test(stageJob), 'stage receipt artifact must preserve digest-bound raw stage output');
|
|
178
186
|
assertGate(/review_verifier_schema: 'sks\.npm-stage-review-receipt\.v1'/.test(stageJob), 'stage receipt must declare the maintainer verifier schema');
|
|
179
187
|
assertGate(/localPackReceiptSha256 = crypto\.createHash\('sha256'\)\.update\(localPackReceiptBytes\)/.test(stageJob), 'stage receipt must bind immutable local pack receipt bytes');
|
|
188
|
+
assertGate(/smoke\.postinstall_default\?\.scripts_enabled !== true/.test(stageJob), 'stage job must require scripts-enabled default postinstall proof');
|
|
189
|
+
assertGate(/smoke\.postinstall_default\?\.external_snapshot_match !== true/.test(stageJob), 'stage job must require zero external postinstall mutation');
|
|
190
|
+
assertGate(/smoke\.postinstall_default\.launchctl_calls\.length !== 0/.test(stageJob), 'stage job must require zero default postinstall launchctl calls');
|
|
180
191
|
assertGate(!/approve_command/.test(stageWorkflow), 'stage workflow must not serialize an approval command');
|
|
181
192
|
assertGate(!/\bnpm[ \t]+(?:ci|pack|run|publish|login|logout|whoami)\b/.test(stageJob), 'stage job must not install dependencies, repack, run lifecycle scripts, or use session credentials');
|
|
182
193
|
assertGate(!/NODE_AUTH_TOKEN|NPM_TOKEN|_authToken/.test(stageWorkflow), 'stage workflow must not inject npm tokens');
|
|
183
|
-
assertGate(/
|
|
194
|
+
assertGate(/from '\.\/npm-stage-contract\.js'/.test(stageVerifierSupport), 'maintainer stage verifier support must use the shared npm stage contract');
|
|
195
|
+
assertGate(/exactNpmStageCliInvocation\(\)/.test(stageVerifierSource), 'maintainer stage verifier must resolve the exact pinned npm CLI');
|
|
184
196
|
assertGate(/\['stage', 'view', stageId, '--json'/.test(stageVerifierSource), 'maintainer stage verifier must inspect the exact stage ID read-only');
|
|
185
197
|
assertGate(/\['stage', 'download', stageId, '--json'/.test(stageVerifierSource), 'maintainer stage verifier must download the exact stage ID read-only');
|
|
186
198
|
assertGate(/exact_bytes_match/.test(stageVerifierSource) && /sha256_match/.test(stageVerifierSource) && /sha512_match/.test(stageVerifierSource) && /integrity_match/.test(stageVerifierSource), 'maintainer stage verifier must compare bytes and digests');
|
|
187
|
-
assertGate(/oidc_environment_not_allowed/.test(
|
|
199
|
+
assertGate(/oidc_environment_not_allowed/.test(stageContract), 'maintainer stage verifier must reject OIDC and GitHub Actions environments');
|
|
200
|
+
assertGate(/local_review_verifier/.test(stagePublishSource), 'confirmed stage preflight must require the local review verifier');
|
|
201
|
+
assertGate(/localNpmStageReviewEnvironmentBlocker/.test(stagePublishSource), 'confirmed stage preflight must reject CI and OIDC review environments');
|
|
202
|
+
assertGate(/exactNpmStageCliInvocation\(\)/.test(stagePublishSource), 'confirmed stage preflight must resolve the pinned npm CLI before mutation');
|
|
203
|
+
assertGate(/if \(!preflight\.ok\) return finish\(\)/.test(stagePublishSource), 'stage preflight failures must stop before push or dispatch');
|
|
188
204
|
assertGate(!/\['stage',\s*'(?:publish|approve|reject)'/.test(`${stageVerifierSource}\n${stageVerifierSupport}\n${stageVerifierCli}`), 'maintainer stage verifier must not contain mutating stage argv');
|
|
205
|
+
assertGate(/npx --yes npm@11\.15\.0/.test(releaseReadinessDoc), 'release readiness must document pinned local npm stage resolution');
|
|
189
206
|
assertGate(/npm-stage-tarball-verifier\.js/.test(releaseReadinessDoc) && /--local-receipt/.test(releaseReadinessDoc) && /--local-tarball/.test(releaseReadinessDoc) && /--stage-receipt/.test(releaseReadinessDoc), 'release readiness must document the maintainer-local read-only verifier inputs');
|
|
190
207
|
assertGate(pkg.scripts?.prepublishOnly === 'node ./dist/scripts/prepublish-release-check-or-fast.js', 'prepublishOnly must verify release proof during official npm publish');
|
|
191
208
|
assertGate(pkg.scripts?.prepack === 'node ./dist/scripts/prepublish-release-check-or-fast.js --prepack-build', 'prepack must rebuild and reverify official npm publish output');
|
|
@@ -102,6 +102,13 @@ const tasks = [
|
|
|
102
102
|
task('zellij:real-session-cleanup', 'direct', { command: nodeScript('zellij-real-session-cleanup-check.js'), group: 'real_ui', phase: 'aggregation', args: ['--mission', zellijMissionId, '--session', zellijSessionName, '--owned-socket-dir', zellijSocketDir], env: zellijOwnedEnv, deps: ['zellij:pane-proof', 'zellij:screen-proof'], alwaysRun: true, policy: requiredPolicy(['sks.zellij-real-session-cleanup-check.v1']) }),
|
|
103
103
|
task('naruto:worktree-coding:blackbox', 'direct', { command: nodeScript('naruto-worktree-coding-blackbox.js'), group: 'real_smoke', phase: 'parallel_processing', args: ['--require-real'], env: { SKS_REQUIRE_GIT_WORKTREE: '1' }, policy: requiredPolicy(['sks.release-gate.v1']) }),
|
|
104
104
|
task('codex-sdk:real-smoke', 'direct', { command: nodeScript('codex-sdk-real-smoke-check.js'), group: 'real_smoke', phase: 'parallel_processing', args: ['--require-real'], policy: requiredPolicy(['sks.release-gate.v1'], { statusRequired: true, passStatuses: ['proven'] }) }),
|
|
105
|
+
task('codex-lb:desktop-real-evidence', 'direct', {
|
|
106
|
+
command: nodeScript('codex-lb-desktop-real-evidence-check.js'),
|
|
107
|
+
group: 'real_ui',
|
|
108
|
+
phase: 'parallel_verification',
|
|
109
|
+
deps: ['codex:actual-config-load-probe'],
|
|
110
|
+
policy: liveOptionalPolicy(['sks.codex-lb-desktop-real-evidence-check.v1'], ['passed'])
|
|
111
|
+
}),
|
|
105
112
|
task('imagegen:real-smoke', 'direct', { command: nodeScript('imagegen-real-smoke-check.js'), group: 'real_smoke', phase: 'parallel_processing', policy: liveOptionalPolicy(['sks.imagegen-real-smoke.v1'], ['passed']) }),
|
|
106
113
|
task('ux-review:real-imagegen-smoke', 'direct', { command: nodeScript('ux-review-real-imagegen-smoke-check.js'), group: 'real_smoke', phase: 'parallel_processing', deps: ['imagegen:real-smoke'], policy: liveOptionalPolicy(['sks.ux-real-imagegen-smoke.v1'], ['passed']) }),
|
|
107
114
|
task('ppt:real-imagegen-smoke', 'direct', { command: nodeScript('ppt-real-imagegen-smoke-check.js'), group: 'real_smoke', phase: 'parallel_processing', deps: ['imagegen:real-smoke'], policy: liveOptionalPolicy(['sks.ppt-real-imagegen-smoke.v1'], ['passed']) })
|