sneakoscope 7.1.0 → 7.3.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 +9 -1
- package/config/architecture-budgets.v1.json +1 -8
- package/crates/sks-core/Cargo.lock +225 -1
- package/crates/sks-core/Cargo.toml +8 -1
- package/crates/sks-core/src/main.rs +7 -1
- package/crates/sks-core/src/search/files.rs +114 -0
- package/crates/sks-core/src/search/mod.rs +274 -0
- package/crates/sks-core/src/search/text.rs +175 -0
- package/dist/bin/sks-dispatch.js +4 -3
- package/dist/cli/command-manifest-lite.js +177 -6
- package/dist/cli/command-registry.js +42 -8
- package/dist/cli/help.js +30 -0
- package/dist/cli/install-helpers-codex-lb-config.js +9 -6
- package/dist/cli/install-helpers-codex-lb-selftest-chain.js +1 -1
- package/dist/cli/install-helpers-install-support.js +1 -1
- package/dist/cli/install-helpers.js +19 -9
- package/dist/cli/router.js +16 -3
- package/dist/commands/codex-app.js +40 -5
- package/dist/commands/doctor-profile.js +78 -0
- package/dist/commands/doctor.js +29 -69
- package/dist/commands/search.js +4 -0
- package/dist/config/skills-manifest.json +53 -60
- package/dist/core/agent-bridge/agent-manifest.js +22 -26
- package/dist/core/agent-bridge/host-capability-policy.js +109 -8
- package/dist/core/agent-bridge/host-capability-runtime.js +178 -50
- package/dist/core/agent-guidance/directive-registry.js +123 -0
- package/dist/core/agents/agent-effort-policy.js +45 -6
- package/dist/core/agents/agent-worker-pipeline.js +1 -3
- package/dist/core/agents/native-worker-backend-router.js +43 -19
- package/dist/core/auto-review.js +1 -3
- package/dist/core/code-structure.js +282 -19
- package/dist/core/codex/codex-config-guard.js +14 -4
- package/dist/core/codex/codex-config-toml.js +1 -3
- package/dist/core/codex-app/codex-agent-role-sync.js +1 -3
- package/dist/core/codex-app/codex-app-fast-ui-repair.js +14 -1
- package/dist/core/codex-app/codex-app-types.js +2 -3
- package/dist/core/codex-app/codex-desktop-routing-ownership.js +91 -0
- package/dist/core/codex-app/codex-hook-approval-probe.js +1 -3
- package/dist/core/codex-app/codex-hook-lifecycle.js +1 -3
- package/dist/core/codex-app/codex-init-deep.js +22 -10
- package/dist/core/codex-app/codex-model-catalog.js +384 -0
- package/dist/core/codex-app/codex-models-cache.js +160 -0
- package/dist/core/codex-app/desktop-routing-snapshot.js +233 -0
- package/dist/core/codex-app/glm-profile-installer.js +1 -3
- package/dist/core/codex-app/mcp-manager.js +1 -3
- package/dist/core/codex-app/menubar/constants.js +3 -0
- package/dist/core/codex-app/menubar/installer.js +11 -1
- package/dist/core/codex-app/multi-provider-router-support.js +202 -0
- package/dist/core/codex-app/multi-provider-router.js +379 -0
- package/dist/core/codex-app/openrouter-activate.js +189 -26
- package/dist/core/codex-app/openrouter-base-instructions.js +1 -0
- package/dist/core/codex-app/openrouter-model-catalog.js +217 -0
- package/dist/core/codex-app/role-model-catalog-priority.js +61 -0
- package/dist/core/codex-app.js +30 -6
- package/dist/core/codex-compat/codex-hook-semantic-validator.js +1 -3
- package/dist/core/codex-control/codex-app-server-v2-client.js +39 -2
- package/dist/core/codex-lb/codex-lb-env.js +1 -3
- package/dist/core/codex-lb/codex-lb-tool-catalog.js +6 -1
- package/dist/core/codex-native/codex-native-feature-broker.js +2 -6
- package/dist/core/codex-native/codex-native-interop-policy.js +1 -3
- package/dist/core/codex-native/codex-native-reference-cache.js +1 -3
- package/dist/core/codex-native/codex-native-reference-source.js +1 -3
- package/dist/core/codex-native/codex-native-repair-transaction.js +1 -3
- package/dist/core/codex-native/core-skill-manifest.js +3 -2
- package/dist/core/codex-native/native-capability-repair-matrix.js +1 -3
- package/dist/core/codex-plugins/codex-plugin-repair.js +1 -3
- package/dist/core/codex-runtime/codex-desktop-config-policy.js +4 -4
- package/dist/core/commands/agent-bridge-command.js +24 -3
- package/dist/core/commands/image-ux-review-command.js +5 -11
- package/dist/core/commands/menubar-command.js +1 -1
- package/dist/core/commands/naruto-command.js +40 -13
- package/dist/core/commands/pipeline-command.js +5 -2
- package/dist/core/commands/release-command.js +63 -1
- package/dist/core/commands/remote-command.js +18 -0
- package/dist/core/commands/search-command.js +151 -0
- package/dist/core/commands/telegram-command.js +251 -108
- package/dist/core/commands/uninstall-command.js +1 -1
- package/dist/core/config/secret-preservation.js +1 -3
- package/dist/core/context7-client.js +2 -1
- package/dist/core/db-review.js +704 -0
- package/dist/core/db-safety.js +17 -23
- package/dist/core/doctor/browser-use-repair.js +1 -3
- package/dist/core/doctor/codex-startup-config-repair.js +1 -3
- package/dist/core/doctor/computer-use-repair.js +1 -3
- package/dist/core/doctor/context7-mcp-repair.js +1 -3
- package/dist/core/doctor/current-project-guidance.js +1 -3
- package/dist/core/doctor/doctor-codex-startup-repair.js +1 -3
- package/dist/core/doctor/doctor-dirty-planner.js +2 -2
- package/dist/core/doctor/doctor-native-capability-repair.js +1 -3
- package/dist/core/doctor/doctor-transaction.js +1 -3
- package/dist/core/doctor/imagegen-repair.js +1 -3
- package/dist/core/doctor/legacy-global-hook-cleanup.js +1 -3
- package/dist/core/doctor/mcp-transport-collision-repair.js +1 -3
- package/dist/core/doctor/retired-managed-residue-private.js +1 -3
- package/dist/core/doctor/supabase-mcp-repair.js +1 -3
- package/dist/core/engineering-sanity-review.js +186 -0
- package/dist/core/errors/message.js +3 -0
- package/dist/core/evidence/evidence-schema.js +1 -3
- package/dist/core/feature-fixtures.js +1 -0
- package/dist/core/feature-registry.js +1 -3
- package/dist/core/fsx.js +13 -0
- package/dist/core/git-hygiene/shared-memory-publish.js +1 -3
- package/dist/core/git-hygiene/validators.js +1 -3
- package/dist/core/harness-guard.js +21 -3
- package/dist/core/hooks-runtime/hook-context.js +2 -2
- package/dist/core/image-ux-review/imagegen-adapter.js +52 -56
- package/dist/core/image-ux-review/real-callout-extractor.js +6 -1
- package/dist/core/image-ux-review.js +3 -5
- package/dist/core/imagegen/codex-lb-imagegen-target.js +70 -0
- package/dist/core/imagegen/imagegen-capability.js +11 -11
- package/dist/core/imagegen/imagegen-evidence.js +32 -0
- package/dist/core/init/skills.js +9 -11
- package/dist/core/init.js +4 -6
- package/dist/core/json/records.js +9 -0
- package/dist/core/json-schema-validator.js +1 -3
- package/dist/core/lean-engineering-policy.js +54 -0
- package/dist/core/loops/loop-continuation-enforcer.js +1 -3
- package/dist/core/mad-sks/sql-plane/mcp-executor.js +2 -1
- package/dist/core/mad-sks/sql-plane/policy.js +2 -1
- package/dist/core/managed-assets/managed-assets-manifest.js +4 -3
- package/dist/core/mcp-config/codex-cli-adapter.js +1 -3
- package/dist/core/mcp-config/config-reader.js +2 -3
- package/dist/core/mcp-config/guarded-patch.js +1 -1
- package/dist/core/mcp-config/health-check.js +2 -1
- package/dist/core/mcp-config/mutation.js +1 -1
- package/dist/core/mcp-config/restore.js +1 -1
- package/dist/core/mcp-config/secret-policy.js +1 -3
- package/dist/core/migration/migration-transaction-journal.js +3 -3
- package/dist/core/naruto/naruto-concurrency-governor.js +2 -2
- package/dist/core/perf/import-graph-budget.js +91 -1
- package/dist/core/pipeline/pipeline-plan-writer.js +1 -1
- package/dist/core/pipeline-internals/runtime-core.js +121 -23
- package/dist/core/pipeline-internals/runtime-gates.js +193 -4
- package/dist/core/pipeline.js +1 -1
- package/dist/core/ppt-review/slide-imagegen-review.js +7 -7
- package/dist/core/ppt.js +3 -3
- package/dist/core/product-design-app-server.js +2 -1
- package/dist/core/proof/fake-real-proof-policy.js +1 -3
- package/dist/core/proof/root-cause-policy.js +1 -3
- package/dist/core/proof/validation.js +1 -3
- package/dist/core/provider/model-router.js +4 -0
- package/dist/core/provider/provider-context.js +1 -3
- package/dist/core/providers/openrouter/openrouter-account.js +1 -3
- package/dist/core/quality/helper-dedup.js +0 -0
- package/dist/core/recallpulse.js +1 -1
- package/dist/core/release/file-ownership.js +26 -17
- package/dist/core/release/macos-menubar-proof.js +59 -1
- package/dist/core/release/main-push-guard.js +288 -24
- package/dist/core/release/main-push-receipt.js +10 -45
- package/dist/core/release/package-size-budget.js +1 -1
- package/dist/core/release/release-gate-contract.js +2 -0
- package/dist/core/release/release-pack-receipt.js +1 -1
- package/dist/core/release/release-proof-io.js +33 -0
- package/dist/core/release/release-upgrade-baseline.js +9 -0
- package/dist/core/release/runtime-script-pack-closure.js +153 -4
- package/dist/core/release/stage-publish.js +194 -0
- package/dist/core/remote/index.js +2 -0
- package/dist/core/remote/local-worker-client.js +35 -0
- package/dist/core/remote/machine-registry.js +18 -13
- package/dist/core/remote/owner-proof.js +1 -3
- package/dist/core/remote/protocol.js +1 -3
- package/dist/core/remote/readiness.js +1 -3
- package/dist/core/remote/session-binding.js +153 -0
- package/dist/core/remote/session-index.js +1 -3
- package/dist/core/remote/types.js +1 -0
- package/dist/core/remote/worker.js +228 -14
- package/dist/core/responses-stream.js +151 -0
- package/dist/core/routes/dollar-manifest-lite.js +1 -1
- package/dist/core/routes.js +8 -8
- package/dist/core/rust-accelerator.js +12 -2
- package/dist/core/safety/ssot-guard.js +1 -3
- package/dist/core/search/benchmark.js +358 -0
- package/dist/core/search/cache.js +65 -0
- package/dist/core/search/context.js +144 -0
- package/dist/core/search/doctor.js +74 -0
- package/dist/core/search/files.js +192 -0
- package/dist/core/search/index.js +5 -0
- package/dist/core/search/ipc.js +64 -0
- package/dist/core/search/provider.js +142 -0
- package/dist/core/search/rust-bridge.js +24 -0
- package/dist/core/search/structure.js +230 -0
- package/dist/core/search/symbol.js +272 -0
- package/dist/core/search/text.js +146 -0
- package/dist/core/search/types.js +22 -0
- package/dist/core/search/typescript-ls.js +215 -0
- package/dist/core/search-visibility/discovery.js +1 -3
- package/dist/core/skill-forge.js +1 -1
- package/dist/core/stop-gate/gate-evaluator.js +3 -3
- package/dist/core/stop-gate/stop-gate-check.js +1 -3
- package/dist/core/structured-output-adapter.js +62 -2
- package/dist/core/subagents/agent-catalog.js +56 -43
- package/dist/core/subagents/model-policy.js +17 -7
- package/dist/core/subagents/naruto-proof-projection.js +2 -6
- package/dist/core/subagents/official-subagent-config.js +1 -3
- package/dist/core/subagents/official-subagent-preparation.js +73 -10
- package/dist/core/subagents/official-subagent-prompt.js +85 -18
- package/dist/core/subagents/official-subagent-runner.js +10 -5
- package/dist/core/subagents/role-model-preferences.js +202 -44
- package/dist/core/subagents/subagent-evidence.js +1 -3
- package/dist/core/subagents/thread-budget.js +1 -1
- package/dist/core/subagents/triwiki-attention.js +1 -5
- package/dist/core/telegram/config.js +29 -12
- package/dist/core/telegram/hub.js +8 -2
- package/dist/core/telegram/index.js +2 -0
- package/dist/core/telegram/messages.js +8 -2
- package/dist/core/telegram/runtime-projection.js +8 -5
- package/dist/core/telegram/runtime.js +19 -9
- package/dist/core/telegram/service.js +181 -0
- package/dist/core/telegram/setup.js +220 -0
- package/dist/core/text/regex.js +3 -0
- package/dist/core/text/strings.js +6 -0
- package/dist/core/triwiki-wrongness/image-wrongness.js +1 -3
- package/dist/core/triwiki-wrongness/wrongness-ledger.js +1 -3
- package/dist/core/triwiki-wrongness/wrongness-proof-linker.js +1 -3
- package/dist/core/triwiki-wrongness/wrongness-retrieval.js +1 -3
- package/dist/core/triwiki-wrongness/wrongness-schema.js +1 -3
- package/dist/core/triwiki-wrongness/wrongness-trust-policy.js +1 -3
- package/dist/core/trust-kernel/completion-contract.js +1 -3
- package/dist/core/trust-kernel/route-contract.js +1 -3
- package/dist/core/update/update-migration-state.js +1 -3
- package/dist/core/update-check.js +20 -6
- package/dist/core/verification/diff-quality.js +3 -4
- package/dist/core/verification/impact-scan.js +36 -89
- package/dist/core/verification/mistake-rule-compiler.js +17 -4
- package/dist/core/version-manager.js +3 -20
- package/dist/core/version.js +1 -1
- package/dist/native/sks-menubar/Sources/ControlCenterWindowController.swift +23 -3
- package/dist/native/sks-menubar/Sources/ControlKit.swift +102 -0
- package/dist/native/sks-menubar/Sources/DiagnosticsViewController.swift +23 -11
- package/dist/native/sks-menubar/Sources/MCPServersViewController.swift +7 -3
- package/dist/native/sks-menubar/Sources/OperationCoordinator.swift +17 -1
- package/dist/native/sks-menubar/Sources/OverviewViewController.swift +22 -15
- package/dist/native/sks-menubar/Sources/ProcessClient.swift +15 -5
- package/dist/native/sks-menubar/Sources/ProvidersMultiProvider.swift +324 -0
- package/dist/native/sks-menubar/Sources/ProvidersOpenRouter.swift +154 -214
- package/dist/native/sks-menubar/Sources/ProvidersRoleModels.swift +252 -0
- package/dist/native/sks-menubar/Sources/ProvidersViewController.swift +77 -71
- package/dist/native/sks-menubar/Sources/RemoteTelegramViewController.swift +167 -51
- package/dist/native/sks-menubar/Sources/SettingsViewController.swift +14 -5
- package/dist/native/sks-menubar/Sources/SidebarItem.swift +15 -1
- package/dist/native/sks-menubar/Sources/StatusItemController.swift +2 -2
- package/dist/native/sks-menubar/Sources/UpdatesViewController.swift +16 -12
- package/dist/scripts/agent-guidance-dedup-check.js +23 -0
- package/dist/scripts/agent-message-bus-reader-check.js +1 -1
- package/dist/scripts/all-feature-deep-completion-check.js +1 -1
- package/dist/scripts/appshots-thread-attachment-discovery-check.js +1 -1
- package/dist/scripts/architecture-guard-check.js +1 -2
- package/dist/scripts/certificate-sla-check.js +1 -1
- package/dist/scripts/cli-output-consistency-check.js +1 -1
- package/dist/scripts/codex-0-134-runner-truth-check.js +1 -1
- package/dist/scripts/codex-0138-capability-artifact-check.js +1 -1
- package/dist/scripts/codex-0138-capability-check.js +1 -1
- package/dist/scripts/codex-0138-doctor-check.js +1 -1
- package/dist/scripts/codex-0138-feature-probes-check.js +1 -1
- package/dist/scripts/codex-0144-app-server-v2-check.js +1 -1
- package/dist/scripts/codex-0144-binary-identity-check.js +1 -1
- package/dist/scripts/codex-0144-capability-check.js +1 -1
- package/dist/scripts/codex-0144-core-real-probes-check.js +1 -1
- package/dist/scripts/codex-0144-manifest-check.js +1 -1
- package/dist/scripts/codex-0144-policy-check.js +1 -1
- package/dist/scripts/codex-0144-thread-store-check.js +1 -1
- package/dist/scripts/codex-agent-role-rich-content-check.js +2 -2
- package/dist/scripts/codex-agent-role-sync-check.js +2 -2
- package/dist/scripts/codex-agent-type-routing-check.js +2 -2
- package/dist/scripts/codex-app-execution-profile-check.js +2 -2
- package/dist/scripts/codex-app-handoff-check.js +1 -1
- package/dist/scripts/codex-app-handoff-launch-check.js +1 -1
- package/dist/scripts/codex-control-tool-output-continuity-audit-check.js +1 -1
- package/dist/scripts/codex-lb-fast-ui-preservation-check.js +1 -3
- package/dist/scripts/codex-native-feature-broker-blackbox.js +2 -2
- package/dist/scripts/codex-native-feature-broker-check.js +2 -2
- package/dist/scripts/{sks-3-1-6-directive-check-lib.js → codex-native-gate-lib.js} +5 -5
- package/dist/scripts/codex-native-harness-compat-check.js +2 -2
- package/dist/scripts/codex-native-hook-lifecycle-proof-check.js +2 -2
- package/dist/scripts/codex-plugin-app-template-policy-check.js +1 -1
- package/dist/scripts/codex-sdk-backend-router-check.js +1 -1
- package/dist/scripts/codex-sdk-capability-check.js +1 -1
- package/dist/scripts/context7-evidence-dedupe-check.js +1 -1
- package/dist/scripts/core-skill-card-schema-check.js +1 -1
- package/dist/scripts/core-skill-deployment-snapshot-check.js +1 -1
- package/dist/scripts/core-skill-heldout-validation-check.js +1 -1
- package/dist/scripts/core-skill-no-inference-optimizer-check.js +1 -1
- package/dist/scripts/core-skill-patch-check.js +1 -1
- package/dist/scripts/core-skill-route-runtime-integration-check.js +1 -1
- package/dist/scripts/current-command-surface-check.js +1 -1
- package/dist/scripts/current-surface-update-e2e-check.js +4 -1
- package/dist/scripts/current-upgrade-matrix-check.js +1 -1
- package/dist/scripts/dfix-fixture-check.js +1 -1
- package/dist/scripts/dfix-patch-handoff-check.js +1 -1
- package/dist/scripts/dfix-verification-check.js +1 -1
- package/dist/scripts/dfix-verification-recommendation-check.js +1 -1
- package/dist/scripts/docs-truthfulness-check.js +16 -3
- package/dist/scripts/doctor-codex-app-harness-check.js +2 -2
- package/dist/scripts/evidence-flagship-coverage-check.js +1 -1
- package/dist/scripts/{sks-1-18-gate-lib.js → gate-lib.js} +1 -1
- package/dist/scripts/gate-policy-audit-check.js +4 -1
- package/dist/scripts/git-worktree-checkpoint-check.js +1 -1
- package/dist/scripts/git-worktree-cross-rebase-check.js +1 -1
- package/dist/scripts/git-worktree-diff-envelope-check.js +1 -1
- package/dist/scripts/git-worktree-dirty-lock-check.js +1 -1
- package/dist/scripts/git-worktree-dirty-main-detection-check.js +1 -1
- package/dist/scripts/git-worktree-integration-primary-check.js +1 -1
- package/dist/scripts/git-worktree-manifest-append-check.js +1 -1
- package/dist/scripts/git-worktree-untracked-diff-check.js +1 -1
- package/dist/scripts/harness-benchmark-check.js +1 -1
- package/dist/scripts/helper-dedup-check.js +62 -0
- package/dist/scripts/hook-latency-budget-check.js +1 -1
- package/dist/scripts/image-artifact-path-contract-check.js +1 -1
- package/dist/scripts/imagegen-real-smoke-check.js +2 -5
- package/dist/scripts/installed-package-smoke-check.js +1 -1
- package/dist/scripts/legacy-gate-inventory-check.js +1 -1
- package/dist/scripts/legacy-gate-purge-check.js +1 -1
- package/dist/scripts/legacy-strong-inventory-check.js +1 -1
- package/dist/scripts/lib/codex-sdk-gate-lib.js +1 -1
- package/dist/scripts/mad-sks-launch-sql-plane-boundary-check.js +1 -1
- package/dist/scripts/mad-sks-sql-plane-capability-check.js +1 -1
- package/dist/scripts/mad-sks-sql-plane-lifecycle-hook-decision-check.js +1 -1
- package/dist/scripts/mad-sks-sql-plane-result-lifecycle-check.js +1 -1
- package/dist/scripts/managed-config-merge-check.js +1 -1
- package/dist/scripts/mcp-plugin-inventory-check.js +1 -1
- package/dist/scripts/model-call-concurrency-check.js +1 -1
- package/dist/scripts/mutation-callsite-coverage-check.js +1 -1
- package/dist/scripts/naruto-ssot-gate-aliases-check.js +1 -1
- package/dist/scripts/naruto-ssot-pipeline-default-check.js +1 -1
- package/dist/scripts/naruto-ssot-route-normalization-check.js +1 -1
- package/dist/scripts/naruto-ssot-routing-check.js +1 -1
- package/dist/scripts/naruto-worktree-coding-blackbox.js +1 -1
- package/dist/scripts/native-capability-repair-matrix-check.js +1 -1
- package/dist/scripts/native-image-generation-repair-check.js +1 -1
- package/dist/scripts/official-subagent-workflow-check.js +3 -3
- package/dist/scripts/package-published-contract-check.js +37 -4
- package/dist/scripts/packlist-performance-check.js +17 -1
- package/dist/scripts/pipeline-codex-native-doctor-mad-routing-real-blackbox.js +1 -3
- package/dist/scripts/ppt-real-export-adapter-check.js +1 -1
- package/dist/scripts/ppt-real-imagegen-wiring-check.js +1 -1
- package/dist/scripts/ppt-reexport-rereview-check.js +1 -1
- package/dist/scripts/prepublish-fast-check.js +1 -1
- package/dist/scripts/probe-memoization-check.js +2 -2
- package/dist/scripts/prompt-placeholder-guard-check.js +1 -1
- package/dist/scripts/qa-loop-app-handoff-capability-check.js +1 -1
- package/dist/scripts/qa-loop-app-handoff-check.js +1 -1
- package/dist/scripts/qa-loop-app-handoff-cli-check.js +1 -1
- package/dist/scripts/qa-loop-app-handoff-confirmation-check.js +1 -1
- package/dist/scripts/qa-loop-app-handoff-gate-lifecycle-check.js +1 -1
- package/dist/scripts/qa-loop-app-handoff-launch-check.js +1 -1
- package/dist/scripts/qa-loop-app-handoff-status-lifecycle-check.js +1 -1
- package/dist/scripts/qa-loop-budget-policy-check.js +1 -1
- package/dist/scripts/qa-loop-effort-escalation-check.js +1 -1
- package/dist/scripts/qa-loop-execution-profile-routing-check.js +2 -2
- package/dist/scripts/qa-loop-image-path-exposure-check.js +1 -1
- package/dist/scripts/qa-loop-image-path-prompt-injection-check.js +1 -1
- package/dist/scripts/{sks-1-12-real-execution-check-lib.js → real-execution-check-lib.js} +1 -1
- package/dist/scripts/release-affected-selector-check.js +1 -1
- package/dist/scripts/release-aggressive-resource-governor-check.js +1 -1
- package/dist/scripts/release-cache-glob-hashing-check.js +1 -1
- package/dist/scripts/release-cache-input-classifier-check.js +1 -1
- package/dist/scripts/release-cache-neutralization-report-check.js +1 -1
- package/dist/scripts/release-cache-version-neutral-fixture-check.js +1 -1
- package/dist/scripts/release-dynamic-presets-check.js +2 -2
- package/dist/scripts/release-full-parallelism-blackbox.js +1 -1
- package/dist/scripts/release-gate-batch-runner-check.js +1 -1
- package/dist/scripts/release-gate-budget-check.js +1 -1
- package/dist/scripts/release-gate-dag-runner-check.js +1 -1
- package/dist/scripts/release-latency-slo-check.js +1 -1
- package/dist/scripts/release-metadata-check.js +256 -2
- package/dist/scripts/release-parallel-speed-budget-check.js +1 -1
- package/dist/scripts/release-proof-truth-check.js +1 -1
- package/dist/scripts/release-provenance-check.js +4 -2
- package/dist/scripts/release-runtime-truth-matrix-check.js +1 -1
- package/dist/scripts/research-blueprint-densifier-check.js +1 -1
- package/dist/scripts/research-claim-builder-check.js +1 -1
- package/dist/scripts/research-complete-package-fixture-check.js +1 -1
- package/dist/scripts/research-execution-profile-routing-check.js +2 -2
- package/dist/scripts/research-final-reviewer-blackbox.js +1 -1
- package/dist/scripts/{sks-3-1-4-directive-check-lib.js → runtime-domain-gate-lib.js} +2 -2
- package/dist/scripts/runtime-proof-summary-check.js +1 -1
- package/dist/scripts/runtime-script-pack-closure-check.js +7 -1
- package/dist/scripts/scheduler-batch-dispatch-check.js +1 -1
- package/dist/scripts/scheduler-parallel-proof-consistency-check.js +1 -1
- package/dist/scripts/scheduler-utilization-integral-check.js +1 -1
- package/dist/scripts/search-visibility-gate-lib.js +1 -1
- package/dist/scripts/secret-preservation-check.js +1 -1
- package/dist/scripts/seo-geo-geo-disambiguation-check.js +1 -1
- package/dist/scripts/seo-geo-skill-rich-content-check.js +1 -1
- package/dist/scripts/side-effect-runtime-report-check.js +1 -1
- package/dist/scripts/{sks-3-1-8-check-lib.js → skill-fixture-check-lib.js} +1 -1
- package/dist/scripts/skill-name-canonicalizer-check.js +1 -1
- package/dist/scripts/skills-manifest-continuity-check.js +1 -1
- package/dist/scripts/sks-uninstall-regression-check.js +1 -1
- package/dist/scripts/sksd-daemon-check.js +1 -1
- package/dist/scripts/super-search-provider-interface-check.js +1 -1
- package/dist/scripts/triwiki-cache-key-check.js +1 -1
- package/dist/scripts/triwiki-proof-bank-blackbox.js +2 -2
- package/dist/scripts/triwiki-proof-bank-check.js +1 -1
- package/dist/scripts/triwiki-proof-card-check.js +1 -1
- package/dist/scripts/type-surface-codex-app-check.js +2 -2
- package/dist/scripts/{sks-3-1-5-directive-check-lib.js → typed-routing-gate-lib.js} +2 -2
- package/dist/scripts/ultra-router-auto-router-check.js +1 -1
- package/dist/scripts/ux-review-extract-wires-real-extractor-check.js +1 -1
- package/dist/scripts/ux-review-patch-diff-recheck-check.js +1 -1
- package/dist/scripts/ux-review-run-wires-imagegen-check.js +9 -2
- package/package.json +5 -7
- package/release-gates.v2.json +66 -11
- package/runtime-required-scripts.json +138 -14
- package/config/bench-baseline.json +0 -7
- package/dist/core/codex-app/sks-menubar.js +0 -1
- package/dist/core/release/release-closure-contract.js +0 -30
- package/dist/core/release/release-closure-helpers.js +0 -293
- package/dist/core/release/release-closure-validation.js +0 -284
- package/dist/core/release/release-closure.js +0 -163
- package/dist/scripts/build-dist.js +0 -124
- package/dist/scripts/build-once-runner-check.js +0 -6
- package/dist/scripts/canonical-test-runner.js +0 -234
- package/dist/scripts/changelog-check.js +0 -45
- package/dist/scripts/check-architecture.js +0 -295
- package/dist/scripts/check-cli-entrypoint.js +0 -41
- package/dist/scripts/check-command-module-budget.js +0 -77
- package/dist/scripts/check-feature-quality.js +0 -51
- package/dist/scripts/check-legacy-free.js +0 -64
- package/dist/scripts/check-pipeline-budget.js +0 -49
- package/dist/scripts/check-pipeline-runtime.js +0 -16
- package/dist/scripts/check-publish-tag.js +0 -56
- package/dist/scripts/check-route-modularity.js +0 -72
- package/dist/scripts/codex-0140-capability-check.js +0 -14
- package/dist/scripts/codex-0140-feature-probes-check.js +0 -23
- package/dist/scripts/codex-permission-profiles-check.js +0 -34
- package/dist/scripts/codex-project-config-policy-splitter-check.js +0 -49
- package/dist/scripts/competitor-scorecard-check.js +0 -24
- package/dist/scripts/core-skill-no-drift-check.js +0 -23
- package/dist/scripts/db-route-materialization-check.js +0 -32
- package/dist/scripts/doctor-context7-mcp-repair-blackbox.js +0 -15
- package/dist/scripts/doctor-fastpath-check.js +0 -25
- package/dist/scripts/doctor-fix-production-blackbox.js +0 -35
- package/dist/scripts/doctor-idempotence-check.js +0 -6
- package/dist/scripts/doctor-ops-semantics-check.js +0 -83
- package/dist/scripts/doctor-startup-config-repair-blackbox.js +0 -18
- package/dist/scripts/doctor-supabase-mcp-repair-blackbox.js +0 -13
- package/dist/scripts/ensure-bin-executable.js +0 -16
- package/dist/scripts/fsx-hotpath-check.js +0 -9
- package/dist/scripts/high-risk-contracts-check.js +0 -183
- package/dist/scripts/hook-latency-quantum-check.js +0 -120
- package/dist/scripts/import-graph-budget-check.js +0 -9
- package/dist/scripts/mcp-tool-naming-parity-check.js +0 -14
- package/dist/scripts/naruto-codex-e2e-check.js +0 -105
- package/dist/scripts/naruto-write-e2e-check.js +0 -31
- package/dist/scripts/native-capability-postcheck-check.js +0 -16
- package/dist/scripts/ops-diagnostics-bundle-check.js +0 -11
- package/dist/scripts/parallel-production-smoke-check.js +0 -20
- package/dist/scripts/perf-budget-check.js +0 -12
- package/dist/scripts/project-skill-dedupe-blackbox.js +0 -62
- package/dist/scripts/release-dag-full-coverage-check.js +0 -98
- package/dist/scripts/release-dist-freshness-check.js +0 -6
- package/dist/scripts/release-file-ownership-check.js +0 -35
- package/dist/scripts/release-gate-script-parity-check.js +0 -148
- package/dist/scripts/release-macos-menubar-proof.js +0 -167
- package/dist/scripts/release-main-push-guard.js +0 -37
- package/dist/scripts/release-main-push-receipt.js +0 -43
- package/dist/scripts/release-metadata-1-19-check.js +0 -257
- package/dist/scripts/release-version-truth-check.js +0 -138
- package/dist/scripts/retention-apply-smoke-check.js +0 -19
- package/dist/scripts/retention-budget-check.js +0 -6
- package/dist/scripts/retention-dry-run-check.js +0 -8
- package/dist/scripts/rollback-recovery-smoke-check.js +0 -70
- package/dist/scripts/route-intent-regression-check.js +0 -42
- package/dist/scripts/runtime-current-terminal-check.js +0 -108
- package/dist/scripts/runtime-dist-parity-check.js +0 -76
- package/dist/scripts/runtime-no-src-mjs-check.js +0 -30
- package/dist/scripts/runtime-ts-rust-boundary-check.js +0 -58
- package/dist/scripts/runtime-ts-source-of-truth-check.js +0 -53
- package/dist/scripts/secret-preservation-guard-check.js +0 -36
- package/dist/scripts/seo-marketing-truthfulness-check.js +0 -98
- package/dist/scripts/seo-metadata-sync-check.js +0 -60
- package/dist/scripts/sizecheck.js +0 -148
- package/dist/scripts/sks-menubar-install-check.js +0 -333
- package/dist/scripts/supabase-secret-preservation-blackbox.js +0 -28
- package/dist/scripts/super-search-live-smoke-check.js +0 -115
- package/dist/scripts/super-search-local-http-smoke-check.js +0 -16
- package/dist/scripts/super-search-offline-contract-check.js +0 -43
- package/dist/scripts/update-fastpath-check.js +0 -28
- package/dist/scripts/update-preserves-supabase-keys-blackbox.js +0 -26
- package/dist/scripts/upgrade-migration-matrix-check.js +0 -351
- package/dist/scripts/write-build-manifest.js +0 -70
- package/dist/scripts/zellij-capability-check.js +0 -13
- package/dist/scripts/zellij-developer-controls-check.js +0 -16
- package/dist/scripts/zellij-doctor-readiness-check.js +0 -49
- package/dist/scripts/zellij-dynamic-pane-lifecycle-check.js +0 -19
- package/dist/scripts/zellij-fake-adapter-check.js +0 -31
- package/dist/scripts/zellij-first-slot-down-stack-check.js +0 -20
- package/dist/scripts/zellij-first-slot-down-stack-real-check.js +0 -348
- package/dist/scripts/zellij-homebrew-policy-check.js +0 -3
- package/dist/scripts/zellij-initial-main-only-blackbox.js +0 -21
- package/dist/scripts/zellij-lane-renderer-check.js +0 -78
- package/dist/scripts/zellij-launch-command-truth-check.js +0 -62
- package/dist/scripts/zellij-layout-valid-check.js +0 -120
- package/dist/scripts/zellij-pane-creation-lock-metrics-check.js +0 -10
- package/dist/scripts/zellij-pane-lock-concurrency-blackbox.js +0 -78
- package/dist/scripts/zellij-pane-lock-does-not-block-worker-check.js +0 -12
- package/dist/scripts/zellij-pane-lock-open-worker-integration-blackbox.js +0 -134
- package/dist/scripts/zellij-qa-app-handoff-status-check.js +0 -7
- package/dist/scripts/zellij-right-column-geometry-proof.js +0 -158
- package/dist/scripts/zellij-right-column-headless-overflow-check.js +0 -20
- package/dist/scripts/zellij-right-column-manager-check.js +0 -24
- package/dist/scripts/zellij-self-heal-check.js +0 -3
- package/dist/scripts/zellij-self-heal-dry-run-check.js +0 -3
- package/dist/scripts/zellij-self-heal-status-contract-check.js +0 -3
- package/dist/scripts/zellij-self-heal-typed-blackbox.js +0 -3
- package/dist/scripts/zellij-slot-column-anchor-check.js +0 -65
- package/dist/scripts/zellij-slot-column-anchor-telemetry-check.js +0 -8
- package/dist/scripts/zellij-slot-only-ui-check.js +0 -29
- package/dist/scripts/zellij-slot-pane-renderer-check.js +0 -149
- package/dist/scripts/zellij-slot-pane-stale-detection-check.js +0 -65
- package/dist/scripts/zellij-slot-pane-telemetry-renderer-check.js +0 -11
- package/dist/scripts/zellij-slot-renderer-proof-semantics-check.js +0 -58
- package/dist/scripts/zellij-slot-telemetry-check.js +0 -38
- package/dist/scripts/zellij-slot-telemetry-incremental-check.js +0 -46
- package/dist/scripts/zellij-slot-telemetry-live-flush-check.js +0 -55
- package/dist/scripts/zellij-slot-telemetry-performance-check.js +0 -32
- package/dist/scripts/zellij-slot-telemetry-real-blackbox.js +0 -19
- package/dist/scripts/zellij-slot-telemetry-renderer-check.js +0 -11
- package/dist/scripts/zellij-slot-telemetry-runtime-check.js +0 -23
- package/dist/scripts/zellij-spawn-on-demand-layout-check.js +0 -45
- package/dist/scripts/zellij-stacked-capability-routing-check.js +0 -9
- package/dist/scripts/zellij-stacked-fallback-integration-blackbox.js +0 -78
- package/dist/scripts/zellij-stacked-version-matrix-check.js +0 -29
- package/dist/scripts/zellij-stacked-version-parser-check.js +0 -19
- package/dist/scripts/zellij-ui-design-check.js +0 -92
- package/dist/scripts/zellij-update-missing-self-heal-check.js +0 -3
- package/dist/scripts/zellij-update-prompt-matrix-check.js +0 -16
- package/dist/scripts/zellij-update-prompt-mode-check.js +0 -18
- package/dist/scripts/zellij-update-prompt-safety-check.js +0 -8
- package/dist/scripts/zellij-worker-pane-manager-check.js +0 -108
- package/dist/scripts/zellij-worker-pane-manager-single-owner-check.js +0 -47
- package/dist/scripts/zellij-worker-pane-real-ui-blackbox.js +0 -199
- /package/dist/scripts/{sks-1-11-gate-lib.js → sks-cli-gate-lib.js} +0 -0
|
@@ -1,8 +1,9 @@
|
|
|
1
1
|
import path from 'node:path';
|
|
2
2
|
import fsp from 'node:fs/promises';
|
|
3
3
|
import { spawnSync } from 'node:child_process';
|
|
4
|
-
import { nowIso, writeJsonAtomic } from './fsx.js';
|
|
5
|
-
import { LEAN_CHANGE_EVIDENCE_SCHEMA, leanPolicyReference, parseLeanSimplificationMarkerLine } from './lean-engineering-policy.js';
|
|
4
|
+
import { nowIso, sha256, writeJsonAtomic } from './fsx.js';
|
|
5
|
+
import { LEAN_CHANGE_EVIDENCE_SCHEMA, assessTestVolume, leanPolicyReference, parseLeanSimplificationMarkerLine } from './lean-engineering-policy.js';
|
|
6
|
+
import { escapeRegExp } from './text/regex.js';
|
|
6
7
|
export const CODE_STRUCTURE_THRESHOLDS = {
|
|
7
8
|
warning: 1000,
|
|
8
9
|
review: 2000,
|
|
@@ -15,8 +16,25 @@ const SOURCE_EXT_RE = /\.(js|ts|tsx|jsx|cjs|mjs|json|md|rs|toml)$/;
|
|
|
15
16
|
const FALLBACK_RE = /\b(fallback|legacy|shim|compat|mock|catch-all|catch all|default provider)\b/i;
|
|
16
17
|
const CONFIG_FLAG_RE = /\b(process\.env|SKS_[A-Z0-9_]+|CODEX_[A-Z0-9_]+|[A-Z][A-Z0-9_]{5,})\b/;
|
|
17
18
|
const ABSTRACTION_RE = /\b(interface|abstract class|class|factory|provider|adapter|registry|orchestrator|manager)\b/;
|
|
19
|
+
const N_PLUS_ONE_RE = /(?:(?:for\s*(?:await\s*)?\([^)]*\)|for\s+(?:await\s+)?(?:const|let|var)\s+\w+\s+of\s+[^{]+|\.forEach\s*\(\s*async\b|\.map\s*\(\s*async\b))[\s\S]{0,1200}\bawait\s+[\w.$]*(?:query|execute|findMany|findUnique|findFirst|select|insert|update|delete|save)\s*\(/i;
|
|
20
|
+
const UNBOUNDED_LOOP_RE = /\bwhile\s*\(\s*true\s*\)|\bfor\s*\(\s*;\s*;\s*\)/i;
|
|
21
|
+
const RENDER_LOOP_RE = /\buseEffect\s*\(\s*\(\s*\)\s*=>\s*\{[\s\S]{0,1200}\bset[A-Z]\w*\s*\([^)]*\)[\s\S]{0,400}\}\s*\)\s*;?/i;
|
|
22
|
+
const VERIFICATION_BYPASS_RE = /\b(?:test|it|describe)\.(?:skip|only)\s*\(|\b(?:xit|xdescribe)\s*\(|@ts-ignore\b|eslint-disable(?:-next-line)?\b|\.catch\s*\(\s*\(\s*\)\s*=>\s*(?:undefined|\{\s*\})\s*\)|catch\s*\([^)]*\)\s*\{\s*\}/i;
|
|
23
|
+
const DB_POOL_CONSTRUCTOR_RE = /\bnew\s+(?:Pool|PrismaClient|DataSource|Sequelize)\s*\(|\bcreatePool\s*\(|\bknex\s*\(/i;
|
|
24
|
+
const SENSITIVE_DOMAIN_RE = /\b(payment|billing|invoice|charge|refund|ledger|balance|payout|settlement|wallet)\b|결제|청구|환불|원장|잔액|정산/i;
|
|
25
|
+
const DB_WRITE_CALL_RE = /\b(?:insert|update|delete|upsert|save|create|execute|query)\s*\(/gi;
|
|
26
|
+
const TRANSACTION_MARKER_RE = /\b(?:transaction|withTransaction|atomic|begin|commit|rollback|savepoint|\$transaction)\b/i;
|
|
27
|
+
const ENGINEERING_SANITY_TAGS = new Set([
|
|
28
|
+
'solid',
|
|
29
|
+
'n-plus-one',
|
|
30
|
+
'unbounded-loop',
|
|
31
|
+
'verification-bypass',
|
|
32
|
+
'db-pool',
|
|
33
|
+
'transaction'
|
|
34
|
+
]);
|
|
18
35
|
export async function scanCodeStructure(root, opts = {}) {
|
|
19
36
|
const changedScope = await collectChangedScope(root, opts);
|
|
37
|
+
const addedHunkScopes = await collectAddedHunkScopes(root, changedScope);
|
|
20
38
|
const files = await resolveScanFiles(root, opts, changedScope);
|
|
21
39
|
const touched = new Set((opts.touchedFiles || []).map((file) => normalizeRel(root, file)));
|
|
22
40
|
const changedSet = new Set((changedScope.source_files || []).map((file) => normalizeSlashes(file)));
|
|
@@ -30,7 +48,12 @@ export async function scanCodeStructure(root, opts = {}) {
|
|
|
30
48
|
const changedByDiff = changedSet.has(rel);
|
|
31
49
|
if (status === 'ok' && !opts.includeOk && !changedByDiff)
|
|
32
50
|
continue;
|
|
33
|
-
const
|
|
51
|
+
const addedScope = addedHunkScopes.get(rel);
|
|
52
|
+
const signals = analyzeTextSignals(rel, text, changedByDiff, addedScope || {
|
|
53
|
+
scope: changedByDiff ? 'changed_file_without_added_hunks' : 'full_file_advisory',
|
|
54
|
+
text: changedByDiff ? '' : text,
|
|
55
|
+
line_ranges: []
|
|
56
|
+
});
|
|
34
57
|
intentionalSimplifications.push(...signals.lean_markers);
|
|
35
58
|
entries.push({
|
|
36
59
|
path: rel,
|
|
@@ -115,18 +138,23 @@ async function resolveScanFiles(root, opts, changedScope) {
|
|
|
115
138
|
const changedSourceFiles = (changedScope.source_files || [])
|
|
116
139
|
.filter((file) => DEFAULT_INCLUDE.has(path.extname(file)))
|
|
117
140
|
.map((file) => path.resolve(root, file));
|
|
118
|
-
if (
|
|
141
|
+
if (opts.changed || opts.changedSince || opts.changedFiles?.length)
|
|
119
142
|
return changedSourceFiles;
|
|
120
143
|
return listSourceFiles(root);
|
|
121
144
|
}
|
|
122
145
|
async function collectChangedScope(root, opts) {
|
|
123
146
|
if (opts.changedFiles?.length) {
|
|
124
147
|
const changedFiles = Array.from(new Set(opts.changedFiles.map((file) => normalizeRel(root, file))));
|
|
148
|
+
const entries = [];
|
|
149
|
+
for (const file of changedFiles) {
|
|
150
|
+
const text = await fsp.readFile(path.join(root, file), 'utf8').catch(() => '');
|
|
151
|
+
entries.push({ path: file, status: 'M', lines_added: 0, lines_deleted: 0, source_sha256: isSourceLike(file) ? sha256(text) : null });
|
|
152
|
+
}
|
|
125
153
|
return {
|
|
126
154
|
...emptyChangedScope('explicit', opts.changedSince || 'HEAD'),
|
|
127
155
|
changed_files: changedFiles,
|
|
128
156
|
source_files: changedFiles.filter(isSourceLike),
|
|
129
|
-
entries
|
|
157
|
+
entries
|
|
130
158
|
};
|
|
131
159
|
}
|
|
132
160
|
const shouldCollect = opts.changed || opts.changedSince;
|
|
@@ -169,11 +197,18 @@ async function collectChangedScope(root, opts) {
|
|
|
169
197
|
entriesByPath.set(rel, {
|
|
170
198
|
path: rel,
|
|
171
199
|
status: 'A',
|
|
172
|
-
lines_added: text
|
|
173
|
-
lines_deleted: 0
|
|
200
|
+
lines_added: addedFileLines(text).length,
|
|
201
|
+
lines_deleted: 0,
|
|
202
|
+
source_sha256: isSourceLike(rel) ? sha256(text) : null
|
|
174
203
|
});
|
|
175
204
|
}
|
|
176
|
-
const entries = [...entriesByPath.values()].filter((entry) => entry.path);
|
|
205
|
+
const entries = [...entriesByPath.values()].filter((entry) => entry.path && isChangedScopePath(entry.path));
|
|
206
|
+
for (const entry of entries) {
|
|
207
|
+
if (!isSourceLike(entry.path) || entry.source_sha256)
|
|
208
|
+
continue;
|
|
209
|
+
const text = await fsp.readFile(path.join(root, entry.path), 'utf8').catch(() => '');
|
|
210
|
+
entry.source_sha256 = sha256(text);
|
|
211
|
+
}
|
|
177
212
|
const changedFiles = entries.map((entry) => entry.path);
|
|
178
213
|
const sourceFiles = changedFiles.filter(isSourceLike);
|
|
179
214
|
const linesAdded = entries.reduce((sum, entry) => sum + Number(entry.lines_added || 0), 0);
|
|
@@ -258,8 +293,70 @@ async function collectAddedFallbackSites(root, changedScope) {
|
|
|
258
293
|
}
|
|
259
294
|
return sites;
|
|
260
295
|
}
|
|
261
|
-
function
|
|
296
|
+
async function collectAddedHunkScopes(root, changedScope) {
|
|
297
|
+
const scopes = new Map();
|
|
298
|
+
if (!changedScope?.source_files?.length)
|
|
299
|
+
return scopes;
|
|
300
|
+
if (changedScope.mode === 'explicit') {
|
|
301
|
+
for (const rel of changedScope.source_files) {
|
|
302
|
+
const text = await fsp.readFile(path.join(root, rel), 'utf8').catch(() => '');
|
|
303
|
+
const lineCount = text ? text.split(/\r?\n/).length : 0;
|
|
304
|
+
scopes.set(normalizeSlashes(rel), {
|
|
305
|
+
scope: 'explicit_changed_file',
|
|
306
|
+
text,
|
|
307
|
+
line_ranges: lineCount ? [{ start: 1, end: lineCount }] : []
|
|
308
|
+
});
|
|
309
|
+
}
|
|
310
|
+
return scopes;
|
|
311
|
+
}
|
|
312
|
+
if (changedScope.mode !== 'git-diff')
|
|
313
|
+
return scopes;
|
|
314
|
+
const diff = gitText(root, ['diff', '--unified=0', changedScope.base || 'HEAD', '--', ...changedScope.source_files]);
|
|
315
|
+
let currentFile = '';
|
|
316
|
+
let currentLine = 0;
|
|
317
|
+
const linesByFile = new Map();
|
|
318
|
+
for (const line of diff.split(/\r?\n/)) {
|
|
319
|
+
if (line.startsWith('+++ b/')) {
|
|
320
|
+
currentFile = normalizeSlashes(line.slice('+++ b/'.length));
|
|
321
|
+
continue;
|
|
322
|
+
}
|
|
323
|
+
const hunk = /^@@ -\d+(?:,\d+)? \+(\d+)(?:,\d+)? @@/.exec(line);
|
|
324
|
+
if (hunk) {
|
|
325
|
+
currentLine = Number(hunk[1]) || 0;
|
|
326
|
+
continue;
|
|
327
|
+
}
|
|
328
|
+
if (line.startsWith('+') && !line.startsWith('+++')) {
|
|
329
|
+
if (currentFile) {
|
|
330
|
+
const rows = linesByFile.get(currentFile) || [];
|
|
331
|
+
rows.push({ line: currentLine, text: line.slice(1) });
|
|
332
|
+
linesByFile.set(currentFile, rows);
|
|
333
|
+
}
|
|
334
|
+
currentLine += 1;
|
|
335
|
+
continue;
|
|
336
|
+
}
|
|
337
|
+
if (!line.startsWith('-'))
|
|
338
|
+
currentLine += 1;
|
|
339
|
+
}
|
|
340
|
+
for (const rel of changedScope.source_files) {
|
|
341
|
+
const normalized = normalizeSlashes(rel);
|
|
342
|
+
let rows = linesByFile.get(normalized) || [];
|
|
343
|
+
const entry = changedScope.entries?.find((candidate) => normalizeSlashes(candidate.path) === normalized);
|
|
344
|
+
if (!rows.length && String(entry?.status || '').startsWith('A')) {
|
|
345
|
+
const text = await fsp.readFile(path.join(root, normalized), 'utf8').catch(() => '');
|
|
346
|
+
rows = addedFileLines(text).map((value, index) => ({ line: index + 1, text: value }));
|
|
347
|
+
}
|
|
348
|
+
scopes.set(normalized, {
|
|
349
|
+
scope: 'added_hunks',
|
|
350
|
+
text: joinAddedHunkRows(rows),
|
|
351
|
+
line_ranges: contiguousLineRanges(rows.map((row) => row.line))
|
|
352
|
+
});
|
|
353
|
+
}
|
|
354
|
+
return scopes;
|
|
355
|
+
}
|
|
356
|
+
function analyzeTextSignals(rel, text, changedByDiff, sanityScope) {
|
|
262
357
|
const lines = text.split(/\r?\n/);
|
|
358
|
+
const scopedText = String(sanityScope.text || '');
|
|
359
|
+
const scopedCode = stripNonCodeForSanity(scopedText);
|
|
263
360
|
const imports = lines.filter((line) => /^\s*import\s/.test(line));
|
|
264
361
|
const externalImports = imports
|
|
265
362
|
.map((line) => /from\s+['"]([^'"]+)['"]|import\s+['"]([^'"]+)['"]/.exec(line)?.[1] || /from\s+['"]([^'"]+)['"]|import\s+['"]([^'"]+)['"]/.exec(line)?.[2] || '')
|
|
@@ -268,21 +365,64 @@ function analyzeTextSignals(rel, text, changedByDiff) {
|
|
|
268
365
|
.map((line, index) => parseLeanSimplificationMarkerLine(line, rel, index + 1))
|
|
269
366
|
.filter((marker) => Boolean(marker));
|
|
270
367
|
const effectiveLines = lines.map((line) => line.trim()).filter(Boolean);
|
|
271
|
-
const
|
|
368
|
+
const scopeCoversWholeFile = sanityScope.line_ranges.length === 1
|
|
369
|
+
&& sanityScope.line_ranges[0]?.start === 1
|
|
370
|
+
&& sanityScope.line_ranges[0]?.end >= lines.length;
|
|
371
|
+
const forwardingOnly = scopeCoversWholeFile
|
|
372
|
+
&& effectiveLines.length > 0
|
|
272
373
|
&& effectiveLines.length <= 10
|
|
273
374
|
&& effectiveLines.every((line) => line.startsWith('import ') || line.startsWith('export ') || line.startsWith('//') || line.startsWith('/*') || line.startsWith('*'));
|
|
274
375
|
return {
|
|
275
376
|
import_count: imports.length,
|
|
276
377
|
external_dependency_imports: Array.from(new Set(externalImports)).sort(),
|
|
277
|
-
ts_nocheck: /^\s*\/\/\s*@ts-nocheck\b/m.test(
|
|
378
|
+
ts_nocheck: /^\s*\/\/\s*@ts-nocheck\b/m.test(scopedText),
|
|
278
379
|
changed_by_diff: changedByDiff,
|
|
279
380
|
forwarding_only: forwardingOnly,
|
|
280
|
-
fallback_markers: countMatches(
|
|
281
|
-
config_flag_markers: countMatches(
|
|
282
|
-
abstraction_markers: countMatches(
|
|
381
|
+
fallback_markers: countMatches(scopedCode, FALLBACK_RE),
|
|
382
|
+
config_flag_markers: countMatches(scopedCode, CONFIG_FLAG_RE),
|
|
383
|
+
abstraction_markers: countMatches(scopedCode, ABSTRACTION_RE),
|
|
384
|
+
engineering_sanity: engineeringSanitySignals(scopedText, sanityScope),
|
|
283
385
|
lean_markers: leanMarkers
|
|
284
386
|
};
|
|
285
387
|
}
|
|
388
|
+
function engineeringSanitySignals(text, scope) {
|
|
389
|
+
const code = stripNonCodeForSanity(text);
|
|
390
|
+
const writeCalls = code.match(DB_WRITE_CALL_RE)?.length || 0;
|
|
391
|
+
return {
|
|
392
|
+
source_scope: scope.scope,
|
|
393
|
+
added_hunk_line_ranges: scope.line_ranges,
|
|
394
|
+
candidate_detection_only: true,
|
|
395
|
+
n_plus_one_candidates: countMatches(code, N_PLUS_ONE_RE),
|
|
396
|
+
unbounded_loop_candidates: countMatches(code, UNBOUNDED_LOOP_RE),
|
|
397
|
+
render_loop_candidates: countMatches(code, RENDER_LOOP_RE),
|
|
398
|
+
direct_recursion_candidates: countDirectRecursionCandidates(code),
|
|
399
|
+
verification_bypass_markers: countMatches(code, VERIFICATION_BYPASS_RE),
|
|
400
|
+
db_pool_constructor_markers: countMatches(code, DB_POOL_CONSTRUCTOR_RE),
|
|
401
|
+
sensitive_transaction_candidate: SENSITIVE_DOMAIN_RE.test(code)
|
|
402
|
+
&& writeCalls >= 2
|
|
403
|
+
&& !TRANSACTION_MARKER_RE.test(code),
|
|
404
|
+
db_write_call_markers: writeCalls
|
|
405
|
+
};
|
|
406
|
+
}
|
|
407
|
+
function stripNonCodeForSanity(text) {
|
|
408
|
+
return String(text || '')
|
|
409
|
+
.replace(/^\s*const\s+[A-Z0-9_]+_RE\s*=\s*\/.*\/[dgimsuvy]*;?\s*$/gm, '')
|
|
410
|
+
.replace(/\/\*[\s\S]*?\*\//g, (value) => value.replace(/[^\n]/g, ' '))
|
|
411
|
+
.replace(/(^|[^:\\])\/\/.*$/gm, '$1')
|
|
412
|
+
.replace(/(['"`])(?:\\.|(?!\1)[\s\S])*?\1/g, (value) => value.replace(/[^\n]/g, ' '));
|
|
413
|
+
}
|
|
414
|
+
function countDirectRecursionCandidates(text) {
|
|
415
|
+
let count = 0;
|
|
416
|
+
const functions = /(?:function\s+([A-Za-z_$][\w$]*)\s*\([^)]*\)|(?:const|let)\s+([A-Za-z_$][\w$]*)\s*=\s*(?:async\s*)?\([^)]*\)\s*=>)\s*\{([\s\S]{0,3000}?)\n?\}/g;
|
|
417
|
+
let match;
|
|
418
|
+
while ((match = functions.exec(text))) {
|
|
419
|
+
const name = match[1] || match[2];
|
|
420
|
+
const body = match[3] || '';
|
|
421
|
+
if (name && new RegExp(`\\b${escapeRegExp(name)}\\s*\\(`).test(body))
|
|
422
|
+
count += 1;
|
|
423
|
+
}
|
|
424
|
+
return count;
|
|
425
|
+
}
|
|
286
426
|
function collectRunnableChecks(changedScope) {
|
|
287
427
|
return (changedScope.source_files || [])
|
|
288
428
|
.filter((file) => /\b(test|tests|fixture|fixtures|spec|check|__tests__)\b/i.test(file))
|
|
@@ -290,6 +430,14 @@ function collectRunnableChecks(changedScope) {
|
|
|
290
430
|
}
|
|
291
431
|
function buildSemanticReview(input) {
|
|
292
432
|
const findings = [];
|
|
433
|
+
const testVolume = assessTestVolume(input.changedScope?.entries || []);
|
|
434
|
+
if (testVolume.over_budget) {
|
|
435
|
+
findings.push({
|
|
436
|
+
tag: 'yagni',
|
|
437
|
+
severity: 'review',
|
|
438
|
+
summary: `change adds ${testVolume.added_test_lines} test lines for ${testVolume.added_source_lines} source lines (${testVolume.ratio?.toFixed(1)}x); keep the cases a real defect would produce and drop the rest — exhaustive cases are only owed on money-handling paths`
|
|
439
|
+
});
|
|
440
|
+
}
|
|
293
441
|
for (const dep of input.dependencyDelta.added || []) {
|
|
294
442
|
findings.push({
|
|
295
443
|
tag: 'reuse',
|
|
@@ -340,12 +488,65 @@ function buildSemanticReview(input) {
|
|
|
340
488
|
summary: 'changed file is forwarding-only; confirm it replaces an older path instead of duplicating an SSOT'
|
|
341
489
|
});
|
|
342
490
|
}
|
|
491
|
+
const sanity = entry.lean_signals.engineering_sanity || {};
|
|
343
492
|
if (entry.lean_signals.config_flag_markers > 6 || entry.lean_signals.abstraction_markers > 12) {
|
|
344
493
|
findings.push({
|
|
345
|
-
tag: '
|
|
494
|
+
tag: 'solid',
|
|
495
|
+
severity: 'review',
|
|
496
|
+
file: entry.path,
|
|
497
|
+
source_scope: sanity.source_scope,
|
|
498
|
+
added_hunk_line_ranges: sanity.added_hunk_line_ranges,
|
|
499
|
+
summary: 'changed file has dense config/abstraction markers; review single responsibility, dependency direction, and unrequested layers'
|
|
500
|
+
});
|
|
501
|
+
}
|
|
502
|
+
if (sanity.n_plus_one_candidates > 0) {
|
|
503
|
+
findings.push({
|
|
504
|
+
tag: 'n-plus-one',
|
|
505
|
+
severity: 'review',
|
|
506
|
+
file: entry.path,
|
|
507
|
+
source_scope: sanity.source_scope,
|
|
508
|
+
added_hunk_line_ranges: sanity.added_hunk_line_ranges,
|
|
509
|
+
summary: `${sanity.n_plus_one_candidates} loop-bound database or I/O call candidate(s) require batching, prefetching, or bounded-query review`
|
|
510
|
+
});
|
|
511
|
+
}
|
|
512
|
+
if (sanity.unbounded_loop_candidates > 0 || sanity.render_loop_candidates > 0 || sanity.direct_recursion_candidates > 0) {
|
|
513
|
+
findings.push({
|
|
514
|
+
tag: 'unbounded-loop',
|
|
515
|
+
severity: 'review',
|
|
516
|
+
file: entry.path,
|
|
517
|
+
source_scope: sanity.source_scope,
|
|
518
|
+
added_hunk_line_ranges: sanity.added_hunk_line_ranges,
|
|
519
|
+
summary: `control-flow review required: unbounded=${sanity.unbounded_loop_candidates || 0}, render=${sanity.render_loop_candidates || 0}, recursion=${sanity.direct_recursion_candidates || 0}`
|
|
520
|
+
});
|
|
521
|
+
}
|
|
522
|
+
if (sanity.verification_bypass_markers > 0) {
|
|
523
|
+
findings.push({
|
|
524
|
+
tag: 'verification-bypass',
|
|
346
525
|
severity: 'review',
|
|
347
526
|
file: entry.path,
|
|
348
|
-
|
|
527
|
+
source_scope: sanity.source_scope,
|
|
528
|
+
added_hunk_line_ranges: sanity.added_hunk_line_ranges,
|
|
529
|
+
summary: `${sanity.verification_bypass_markers} disabled-check or swallowed-failure marker(s) require explicit justification and equivalent verification`
|
|
530
|
+
});
|
|
531
|
+
}
|
|
532
|
+
if (sanity.db_pool_constructor_markers > 0) {
|
|
533
|
+
findings.push({
|
|
534
|
+
tag: 'db-pool',
|
|
535
|
+
severity: 'review',
|
|
536
|
+
file: entry.path,
|
|
537
|
+
source_scope: sanity.source_scope,
|
|
538
|
+
added_hunk_line_ranges: sanity.added_hunk_line_ranges,
|
|
539
|
+
summary: `${sanity.db_pool_constructor_markers} database client/pool construction marker(s) require canonical ownership, bounded acquire/release, shutdown, and exhaustion review`
|
|
540
|
+
});
|
|
541
|
+
}
|
|
542
|
+
if (sanity.sensitive_transaction_candidate) {
|
|
543
|
+
findings.push({
|
|
544
|
+
tag: 'transaction',
|
|
545
|
+
severity: 'review',
|
|
546
|
+
file: entry.path,
|
|
547
|
+
source_scope: sanity.source_scope,
|
|
548
|
+
added_hunk_line_ranges: sanity.added_hunk_line_ranges,
|
|
549
|
+
summary: 'sensitive or financial multi-write flow lacks an obvious transaction marker; verify atomic rollback, error propagation, idempotency, and post-commit invariants'
|
|
349
550
|
});
|
|
350
551
|
}
|
|
351
552
|
}
|
|
@@ -360,12 +561,16 @@ function buildSemanticReview(input) {
|
|
|
360
561
|
summary: `lean simplification marker is incomplete: ${marker.status}`
|
|
361
562
|
});
|
|
362
563
|
}
|
|
363
|
-
const
|
|
564
|
+
const finalizedFindings = findings.map((finding) => ({
|
|
565
|
+
...finding,
|
|
566
|
+
id: `eng-${sha256(`${finding.tag}:${finding.file || ''}:${finding.line || 0}:${finding.summary}`).slice(0, 16)}`
|
|
567
|
+
}));
|
|
568
|
+
const status = finalizedFindings.some((finding) => finding.severity === 'blocker')
|
|
364
569
|
? 'blocked'
|
|
365
|
-
:
|
|
570
|
+
: finalizedFindings.some((finding) => finding.severity === 'review')
|
|
366
571
|
? 'needs-review'
|
|
367
572
|
: 'pass';
|
|
368
|
-
return { status, findings };
|
|
573
|
+
return { status, findings: finalizedFindings };
|
|
369
574
|
}
|
|
370
575
|
function isLeanOwnedTypeSafetyPath(file) {
|
|
371
576
|
return [
|
|
@@ -401,6 +606,21 @@ function buildLeanChangeEvidence(input) {
|
|
|
401
606
|
fallback_sites_added: input.fallbackSites || [],
|
|
402
607
|
intentional_simplifications: input.intentionalSimplifications || [],
|
|
403
608
|
runnable_checks: input.runnableChecks || [],
|
|
609
|
+
engineering_sanity: {
|
|
610
|
+
status: (changedScope.source_files || []).length ? 'manual-review-required' : 'not-applicable',
|
|
611
|
+
automated_candidate_status: (input.semanticReview?.findings || []).some((finding) => ENGINEERING_SANITY_TAGS.has(finding.tag))
|
|
612
|
+
? 'candidates-found'
|
|
613
|
+
: 'no-candidates-found',
|
|
614
|
+
required_checks: [
|
|
615
|
+
'solid_boundaries',
|
|
616
|
+
'n_plus_one_and_repeated_io',
|
|
617
|
+
'bounded_render_recursion_event_retry_polling',
|
|
618
|
+
'verification_bypass_absent',
|
|
619
|
+
'canonical_db_pool_lifecycle_when_applicable',
|
|
620
|
+
'transaction_integrity_when_sensitive_or_multi_step'
|
|
621
|
+
],
|
|
622
|
+
findings: (input.semanticReview?.findings || []).filter((finding) => ENGINEERING_SANITY_TAGS.has(finding.tag))
|
|
623
|
+
},
|
|
404
624
|
semantic_review: input.semanticReview || { status: 'needs-review', findings: [] }
|
|
405
625
|
};
|
|
406
626
|
}
|
|
@@ -444,6 +664,13 @@ function isSourceLike(file) {
|
|
|
444
664
|
const rel = normalizeSlashes(file);
|
|
445
665
|
return SOURCE_DIR_RE.test(rel) && SOURCE_EXT_RE.test(rel) && !isGeneratedOrVendor(rel);
|
|
446
666
|
}
|
|
667
|
+
function isChangedScopePath(file) {
|
|
668
|
+
const rel = normalizeSlashes(file);
|
|
669
|
+
const first = rel.split('/')[0] || '';
|
|
670
|
+
if (first.startsWith('.') && first !== '.agents')
|
|
671
|
+
return false;
|
|
672
|
+
return !isGeneratedOrVendor(rel);
|
|
673
|
+
}
|
|
447
674
|
function parseNumstat(value) {
|
|
448
675
|
const parsed = Number(value);
|
|
449
676
|
return Number.isFinite(parsed) ? parsed : 0;
|
|
@@ -456,6 +683,18 @@ function safeJson(text) {
|
|
|
456
683
|
return {};
|
|
457
684
|
}
|
|
458
685
|
}
|
|
686
|
+
function addedFileLines(text) {
|
|
687
|
+
if (!text)
|
|
688
|
+
return [];
|
|
689
|
+
const lines = text.split(/\r?\n/);
|
|
690
|
+
if (lines[lines.length - 1] === '')
|
|
691
|
+
lines.pop();
|
|
692
|
+
return lines;
|
|
693
|
+
}
|
|
694
|
+
export function resolveChangedScopeBase(root, fallback = 'HEAD') {
|
|
695
|
+
const sha = gitText(root, ['rev-parse', 'HEAD']).trim();
|
|
696
|
+
return /^[0-9a-f]{40}$/i.test(sha) ? sha : fallback;
|
|
697
|
+
}
|
|
459
698
|
function gitLines(root, args) {
|
|
460
699
|
const result = spawnSync('git', args, { cwd: root, encoding: 'utf8' });
|
|
461
700
|
if (result.status !== 0)
|
|
@@ -488,3 +727,27 @@ function normalizeRel(root, file) {
|
|
|
488
727
|
function normalizeSlashes(file) {
|
|
489
728
|
return String(file || '').replace(/\\/g, '/');
|
|
490
729
|
}
|
|
730
|
+
function contiguousLineRanges(lines) {
|
|
731
|
+
const sorted = [...new Set(lines.filter((line) => Number.isInteger(line) && line > 0))].sort((a, b) => a - b);
|
|
732
|
+
const ranges = [];
|
|
733
|
+
for (const line of sorted) {
|
|
734
|
+
const last = ranges.at(-1);
|
|
735
|
+
if (last && line === last.end + 1)
|
|
736
|
+
last.end = line;
|
|
737
|
+
else
|
|
738
|
+
ranges.push({ start: line, end: line });
|
|
739
|
+
}
|
|
740
|
+
return ranges;
|
|
741
|
+
}
|
|
742
|
+
function joinAddedHunkRows(rows) {
|
|
743
|
+
const out = [];
|
|
744
|
+
let previousLine = 0;
|
|
745
|
+
for (const row of rows) {
|
|
746
|
+
if (previousLine > 0 && row.line > previousLine + 1) {
|
|
747
|
+
out.push(' '.repeat(1301));
|
|
748
|
+
}
|
|
749
|
+
out.push(row.text);
|
|
750
|
+
previousLine = row.line;
|
|
751
|
+
}
|
|
752
|
+
return out.join('\n');
|
|
753
|
+
}
|
|
@@ -4,7 +4,20 @@ import { randomBytes } from 'node:crypto';
|
|
|
4
4
|
import { appendJsonl, ensureDir, nowIso, readText, sha256, writeTextAtomic } from '../fsx.js';
|
|
5
5
|
import { diffCodexAppUiSnapshots, snapshotCodexAppUiState } from '../codex-app/codex-app-ui-state-snapshot.js';
|
|
6
6
|
import { cleanupCodexConfigBackups, validateCodexConfigRoundTrip } from './codex-config-toml.js';
|
|
7
|
-
|
|
7
|
+
import { escapeRegExp } from '../text/regex.js';
|
|
8
|
+
const FAST_FEATURE_KEYS = [
|
|
9
|
+
'fast_mode',
|
|
10
|
+
'hooks',
|
|
11
|
+
'apps',
|
|
12
|
+
'computer_use',
|
|
13
|
+
'browser_use',
|
|
14
|
+
'browser_use_external',
|
|
15
|
+
'image_generation',
|
|
16
|
+
'in_app_browser',
|
|
17
|
+
'guardian_approval',
|
|
18
|
+
'tool_suggest',
|
|
19
|
+
'plugins'
|
|
20
|
+
];
|
|
8
21
|
export async function writeCodexConfigGuarded(input) {
|
|
9
22
|
const configPath = path.resolve(input.configPath);
|
|
10
23
|
const root = path.resolve(input.root || process.cwd());
|
|
@@ -513,6 +526,3 @@ async function recordCodexConfigGuard(root, reportPath, record) {
|
|
|
513
526
|
}).catch(() => undefined);
|
|
514
527
|
return file;
|
|
515
528
|
}
|
|
516
|
-
function escapeRegExp(value) {
|
|
517
|
-
return String(value).replace(/[.*+?^${}()|[\]\\]/g, '\\$&');
|
|
518
|
-
}
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import fs from 'node:fs/promises';
|
|
2
2
|
import path from 'node:path';
|
|
3
3
|
import { parse } from 'smol-toml';
|
|
4
|
+
import { messageOf } from '../errors/message.js';
|
|
4
5
|
export function parseCodexConfigToml(text = '') {
|
|
5
6
|
return parse(String(text || ''));
|
|
6
7
|
}
|
|
@@ -115,6 +116,3 @@ function ownedBackupTag(base, file) {
|
|
|
115
116
|
return 'codex-app-ui-repair';
|
|
116
117
|
return null;
|
|
117
118
|
}
|
|
118
|
-
function messageOf(err) {
|
|
119
|
-
return err instanceof Error ? err.message : String(err);
|
|
120
|
-
}
|
|
@@ -4,6 +4,7 @@ import { nowIso, writeJsonAtomic } from '../fsx.js';
|
|
|
4
4
|
import { repairAgentRoleConfigs } from '../agents/agent-role-config.js';
|
|
5
5
|
import { MANAGED_OFFICIAL_SUBAGENT_ROLES } from '../managed-assets/managed-assets-manifest.js';
|
|
6
6
|
import { agentRolePayloadFor, probeCodexAgentTypeSupport } from './codex-agent-type-probe.js';
|
|
7
|
+
import { messageOf } from '../errors/message.js';
|
|
7
8
|
const OFFICIAL_ROLES = MANAGED_OFFICIAL_SUBAGENT_ROLES.map((role) => role.codex_name);
|
|
8
9
|
export async function syncCodexAgentRoles(input) {
|
|
9
10
|
const root = path.resolve(input.root);
|
|
@@ -81,6 +82,3 @@ function stringList(value, key) {
|
|
|
81
82
|
? value[key].map(String).filter(Boolean)
|
|
82
83
|
: [];
|
|
83
84
|
}
|
|
84
|
-
function messageOf(err) {
|
|
85
|
-
return err instanceof Error ? err.message : String(err);
|
|
86
|
-
}
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import fs from 'node:fs/promises';
|
|
2
2
|
import path from 'node:path';
|
|
3
|
-
import { ensureDir, nowIso, readText, sha256, writeJsonAtomic, writeTextAtomic } from '../fsx.js';
|
|
3
|
+
import { assertTestHomeWriteAllowed, ensureDir, nowIso, readText, sha256, writeJsonAtomic, writeTextAtomic } from '../fsx.js';
|
|
4
4
|
import { codexHome, isSksOwnedGlobalUiLock, scanProjectLocalForbiddenKeys, snapshotCodexAppUiState } from './codex-app-ui-state-snapshot.js';
|
|
5
5
|
import { assertCodexAppUiMutationAllowed } from './codex-app-ui-clobber-guard.js';
|
|
6
6
|
import { codexProviderModelUiStatus } from '../codex-app.js';
|
|
@@ -11,6 +11,8 @@ const FAST_UI_LEGACY_TABLES = new Set(['user.fast_mode', 'profiles.sks-fast-high
|
|
|
11
11
|
export async function repairCodexAppFastUi(root = process.cwd(), input = {}) {
|
|
12
12
|
const resolvedRoot = path.resolve(root);
|
|
13
13
|
const home = codexHome(input.codexHome === undefined ? {} : { codexHome: input.codexHome });
|
|
14
|
+
if (input.apply === true)
|
|
15
|
+
assertTestHomeWriteAllowed(path.join(home, 'config.toml'));
|
|
14
16
|
const before = await snapshotCodexAppUiState(resolvedRoot, { codexHome: home });
|
|
15
17
|
const candidates = [
|
|
16
18
|
{ scope: 'project', file: path.join(resolvedRoot, '.codex', 'config.toml'), mode: 'project_forbidden_keys' },
|
|
@@ -167,16 +169,27 @@ function stripProjectLocalForbiddenKeys(text) {
|
|
|
167
169
|
function stripSksCausedHostOwnedLines(text) {
|
|
168
170
|
const sourceLines = String(text || '').split(/\r?\n/);
|
|
169
171
|
const preserveCodexLbSelection = hasActiveCodexLbProviderSelection(text);
|
|
172
|
+
const preserveOpenRouterSelection = hasActiveOpenRouterProviderSelection(text);
|
|
170
173
|
const stripped = stripMatchingLines(text, (line, table, _previous, _next, index) => {
|
|
171
174
|
const isLegacyFastTable = table ? FAST_UI_LEGACY_TABLES.has(table) : false;
|
|
172
175
|
if (isLegacyFastTable)
|
|
173
176
|
return true;
|
|
174
177
|
if (!table && preserveCodexLbSelection && /^\s*model_provider\s*=\s*"codex-lb"\s*(?:#.*)?$/.test(line))
|
|
175
178
|
return false;
|
|
179
|
+
if (!table && preserveOpenRouterSelection && /^\s*(?:model_provider\s*=\s*"openrouter"|model\s*=)/.test(line))
|
|
180
|
+
return false;
|
|
176
181
|
return !table && FAST_UI_TOP_LEVEL_RE.test(line) && isSksOwnedGlobalUiLock(sourceLines, index);
|
|
177
182
|
});
|
|
178
183
|
return stripped;
|
|
179
184
|
}
|
|
185
|
+
function hasActiveOpenRouterProviderSelection(text) {
|
|
186
|
+
const source = String(text || '');
|
|
187
|
+
if (!/(?:^|\n)\s*model_provider\s*=\s*"openrouter"\s*(?:#.*)?(?=\n|$)/.test(source))
|
|
188
|
+
return false;
|
|
189
|
+
const body = source.match(/(?:^|\n)\[model_providers\.openrouter\]([^\n]*(?:\n(?!\s*\[)[^\n]*)*)/)?.[1] || '';
|
|
190
|
+
return /(?:^|\n)\s*base_url\s*=\s*"https:\/\/openrouter\.ai\/api\/v1"\s*(?:#.*)?(?=\n|$)/.test(body)
|
|
191
|
+
&& /(?:^|\n)\s*wire_api\s*=\s*"responses"\s*(?:#.*)?(?=\n|$)/.test(body);
|
|
192
|
+
}
|
|
180
193
|
function hasActiveCodexLbProviderSelection(text) {
|
|
181
194
|
const source = String(text || '');
|
|
182
195
|
if (!/(?:^|\n)\s*model_provider\s*=\s*"codex-lb"\s*(?:#.*)?(?=\n|$)/.test(source))
|
|
@@ -1,6 +1,5 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
}
|
|
1
|
+
import { isRecord } from '../json/records.js';
|
|
2
|
+
export { isRecord };
|
|
4
3
|
export function stringList(value) {
|
|
5
4
|
return Array.isArray(value) ? value.map((item) => String(item)).filter(Boolean) : [];
|
|
6
5
|
}
|
|
@@ -0,0 +1,91 @@
|
|
|
1
|
+
import path from 'node:path';
|
|
2
|
+
import { isLoopbackHostname, resolveCatalogPath } from './multi-provider-router-support.js';
|
|
3
|
+
import { defaultOpenCodexCatalogPath, readTopLevelTomlString } from './codex-model-catalog.js';
|
|
4
|
+
const SKS_ROUTER_PROVIDER_ID = 'sks-router';
|
|
5
|
+
const OPENROUTER_PROVIDER_ID = 'openrouter';
|
|
6
|
+
export const OPENCODEX_INJECT_MARKER = 'Auto-injected by opencodex';
|
|
7
|
+
export const OPENCODEX_DESIGN_B_FORCE_HINT = 'OpenCodex Design B currently owns openai_base_url loopback routing. Stop OpenCodex inject or re-run with --force-routing-override only if replacing that owner is intentional.';
|
|
8
|
+
export function classifyCodexDesktopRouting(configText, input = {}) {
|
|
9
|
+
const text = String(configText || '');
|
|
10
|
+
const selectedProvider = readTopLevelTomlString(text, 'model_provider');
|
|
11
|
+
const selectedModel = readTopLevelTomlString(text, 'model');
|
|
12
|
+
const openaiBaseUrl = readTopLevelTomlString(text, 'openai_base_url');
|
|
13
|
+
const catalogPathRaw = readTopLevelTomlString(text, 'model_catalog_json');
|
|
14
|
+
const catalogResolved = catalogPathRaw
|
|
15
|
+
? resolveCatalogPath(catalogPathRaw, input)
|
|
16
|
+
: null;
|
|
17
|
+
const defaultOpenCodexCatalog = path.resolve(defaultOpenCodexCatalogPath(input));
|
|
18
|
+
const catalogIsOpenCodexDefault = Boolean(catalogResolved && catalogResolved === defaultOpenCodexCatalog);
|
|
19
|
+
const markerPresent = text.includes(OPENCODEX_INJECT_MARKER);
|
|
20
|
+
const loopbackBase = openaiBaseUrl ? normalizeLoopbackOpenaiBaseUrl(openaiBaseUrl) : null;
|
|
21
|
+
const openaiBaseUrlLoopback = Boolean(loopbackBase);
|
|
22
|
+
const designB = Boolean(openaiBaseUrlLoopback
|
|
23
|
+
&& (markerPresent || catalogIsOpenCodexDefault)
|
|
24
|
+
&& (!selectedProvider || selectedProvider === 'openai'));
|
|
25
|
+
const blockers = [];
|
|
26
|
+
const warnings = [];
|
|
27
|
+
let classification = 'unconfigured';
|
|
28
|
+
if (selectedProvider === SKS_ROUTER_PROVIDER_ID)
|
|
29
|
+
classification = 'sks_router';
|
|
30
|
+
else if (selectedProvider === OPENROUTER_PROVIDER_ID)
|
|
31
|
+
classification = 'openrouter';
|
|
32
|
+
else if (selectedProvider === 'codex-lb')
|
|
33
|
+
classification = 'codex_lb';
|
|
34
|
+
else if (designB)
|
|
35
|
+
classification = 'opencodex_design_b';
|
|
36
|
+
else if (!selectedProvider || selectedProvider === 'openai')
|
|
37
|
+
classification = 'native_openai';
|
|
38
|
+
else
|
|
39
|
+
classification = 'external_conflict';
|
|
40
|
+
if (designB && selectedProvider && selectedProvider !== 'openai') {
|
|
41
|
+
classification = 'external_conflict';
|
|
42
|
+
blockers.push('opencodex_design_b_provider_conflict');
|
|
43
|
+
}
|
|
44
|
+
if (openaiBaseUrl && !openaiBaseUrlLoopback && selectedProvider === SKS_ROUTER_PROVIDER_ID) {
|
|
45
|
+
warnings.push('openai_base_url_present_with_sks_router');
|
|
46
|
+
}
|
|
47
|
+
if (designB) {
|
|
48
|
+
warnings.push('opencodex_design_b_routing_owner');
|
|
49
|
+
}
|
|
50
|
+
const sksRouterMayActivate = classification !== 'opencodex_design_b'
|
|
51
|
+
&& classification !== 'external_conflict';
|
|
52
|
+
return {
|
|
53
|
+
schema: 'sks.codex-desktop-routing-ownership.v1',
|
|
54
|
+
classification,
|
|
55
|
+
selected_provider: selectedProvider,
|
|
56
|
+
selected_model: selectedModel,
|
|
57
|
+
openai_base_url: openaiBaseUrl,
|
|
58
|
+
openai_base_url_loopback: openaiBaseUrlLoopback,
|
|
59
|
+
opencodex_design_b: designB,
|
|
60
|
+
opencodex_marker_present: markerPresent,
|
|
61
|
+
catalog_path: catalogResolved,
|
|
62
|
+
catalog_is_opencodex_default: catalogIsOpenCodexDefault,
|
|
63
|
+
sks_router_may_activate: sksRouterMayActivate,
|
|
64
|
+
blockers,
|
|
65
|
+
warnings
|
|
66
|
+
};
|
|
67
|
+
}
|
|
68
|
+
export function opencodexDesignBBlocksRouterActivation(ownership, opts = {}) {
|
|
69
|
+
if (opts.forceRoutingOverride === true)
|
|
70
|
+
return null;
|
|
71
|
+
if (ownership.classification === 'opencodex_design_b' || ownership.opencodex_design_b) {
|
|
72
|
+
return 'opencodex_design_b_routing_owner';
|
|
73
|
+
}
|
|
74
|
+
return null;
|
|
75
|
+
}
|
|
76
|
+
function normalizeLoopbackOpenaiBaseUrl(value) {
|
|
77
|
+
try {
|
|
78
|
+
const parsed = new URL(String(value || '').trim());
|
|
79
|
+
if (parsed.protocol !== 'http:' && parsed.protocol !== 'https:')
|
|
80
|
+
return null;
|
|
81
|
+
if (!isLoopbackHostname(parsed.hostname))
|
|
82
|
+
return null;
|
|
83
|
+
const normalizedPath = parsed.pathname.replace(/\/+$/, '') || '';
|
|
84
|
+
if (normalizedPath && normalizedPath !== '/v1')
|
|
85
|
+
return null;
|
|
86
|
+
return parsed.toString().replace(/\/$/, '');
|
|
87
|
+
}
|
|
88
|
+
catch {
|
|
89
|
+
return null;
|
|
90
|
+
}
|
|
91
|
+
}
|
|
@@ -3,6 +3,7 @@ import { findCodexBinary } from '../codex-adapter.js';
|
|
|
3
3
|
import { readCodexHookActualState } from '../codex-hooks/codex-hook-actual-discovery.js';
|
|
4
4
|
import { nowIso, runProcess, writeJsonAtomic } from '../fsx.js';
|
|
5
5
|
import { isRecord } from './codex-app-types.js';
|
|
6
|
+
import { messageOf } from '../errors/message.js';
|
|
6
7
|
export async function probeCodexHookApprovalState(root, input = {}) {
|
|
7
8
|
const env = input.env || process.env;
|
|
8
9
|
const sources = [];
|
|
@@ -182,6 +183,3 @@ async function persist(root, report, writeReport) {
|
|
|
182
183
|
await writeJsonAtomic(path.join(root, '.sneakoscope', 'reports', 'codex-hook-approval-probe.json'), report).catch(() => undefined);
|
|
183
184
|
return report;
|
|
184
185
|
}
|
|
185
|
-
function messageOf(err) {
|
|
186
|
-
return err instanceof Error ? err.message : String(err);
|
|
187
|
-
}
|
|
@@ -3,6 +3,7 @@ import { nowIso, writeJsonAtomic } from '../fsx.js';
|
|
|
3
3
|
import { readCodexHookActualState } from '../codex-hooks/codex-hook-actual-discovery.js';
|
|
4
4
|
import { installManagedCodexHooks } from '../codex-hooks/codex-hook-managed-install.js';
|
|
5
5
|
import { probeCodexHookApprovalState } from './codex-hook-approval-probe.js';
|
|
6
|
+
import { messageOf } from '../errors/message.js';
|
|
6
7
|
export async function buildCodexHookLifecycle(input = {}) {
|
|
7
8
|
const root = path.resolve(input.root || process.cwd());
|
|
8
9
|
const install = input.apply === true
|
|
@@ -58,6 +59,3 @@ export async function buildCodexHookLifecycle(input = {}) {
|
|
|
58
59
|
await writeJsonAtomic(path.join(root, '.sneakoscope', 'reports', 'codex-hook-lifecycle.json'), report).catch(() => undefined);
|
|
59
60
|
return report;
|
|
60
61
|
}
|
|
61
|
-
function messageOf(err) {
|
|
62
|
-
return err instanceof Error ? err.message : String(err);
|
|
63
|
-
}
|