sneakoscope 5.12.0 → 6.0.1
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 +1 -1
- package/config/bench-baseline.json +3 -3
- package/config/perf-budgets.v1.json +11 -6
- package/crates/sks-core/Cargo.lock +1 -1
- package/crates/sks-core/Cargo.toml +1 -1
- package/crates/sks-core/src/main.rs +1 -1
- package/dist/bin/fast-inline.js +55 -0
- package/dist/bin/sks-dispatch.js +29 -0
- package/dist/bin/sks.js +2 -2
- package/dist/cli/codex-app-command.js +2 -2
- package/dist/cli/install-helpers.js +88 -73
- package/dist/cli/router.js +43 -26
- package/dist/commands/doctor.js +3 -4
- package/dist/config/skills-manifest.json +57 -57
- package/dist/core/agents/agent-effort-policy.js +9 -9
- package/dist/core/agents/native-cli-session-swarm.js +0 -1
- package/dist/core/agents/native-cli-worker.js +0 -6
- package/dist/core/auto-review.js +7 -7
- package/dist/core/codex/agent-config-file-repair.js +1 -4
- package/dist/core/codex/codex-config-guard.js +18 -12
- package/dist/core/codex/codex-config-toml.js +17 -35
- package/dist/core/codex/codex-project-config-policy.js +8 -4
- package/dist/core/codex-adapter.js +2 -2
- package/dist/core/codex-app/codex-agent-type-probe.js +29 -9
- package/dist/core/codex-app/codex-app-fast-ui-repair.js +42 -4
- package/dist/core/codex-app.js +5 -7
- package/dist/core/codex-control/codex-model-capabilities.js +2 -1
- package/dist/core/codex-control/codex-model-metadata.js +3 -2
- package/dist/core/codex-control/codex-sdk-config-policy.js +2 -1
- package/dist/core/codex-control/codex-task-runner.js +7 -2
- package/dist/core/codex-control/codex-thread-registry.js +8 -26
- package/dist/core/codex-model-guard.js +50 -6
- package/dist/core/commands/fast-mode-command.js +1 -1
- package/dist/core/commands/mad-sks-command.js +36 -1
- package/dist/core/commands/naruto-command.js +127 -37
- package/dist/core/commands/profile-command.js +7 -6
- package/dist/core/commands/run-command.js +29 -8
- package/dist/core/commands/ui-command.js +42 -4
- package/dist/core/daemon/sksd-hook-daemon-entrypoint.js +12 -0
- package/dist/core/daemon/sksd-hook-daemon.js +178 -0
- package/dist/core/daemon/sksd-hook-dispatch.js +36 -0
- package/dist/core/doctor/doctor-codex-startup-repair.js +2 -2
- package/dist/core/fsx.js +11 -2
- package/dist/core/hooks-runtime/hook-io.js +132 -0
- package/dist/core/hooks-runtime.js +5 -126
- package/dist/core/image-ux-review/imagegen-adapter.js +2 -1
- package/dist/core/init/skills.js +8 -7
- package/dist/core/init.js +40 -25
- package/dist/core/locks/file-lock.js +96 -16
- package/dist/core/mad-db/mad-db-coordinator.js +11 -3
- package/dist/core/mad-db/mad-db-executor.js +17 -1
- package/dist/core/mad-db/mad-db-ledger.js +7 -1
- package/dist/core/mad-db/mad-db-lock.js +8 -30
- package/dist/core/mad-db/mad-db-policy-resolver.js +2 -0
- package/dist/core/mad-db/mad-db-postconditions.js +19 -4
- package/dist/core/mad-db/mad-db-recovery.js +2 -0
- package/dist/core/mad-db/mad-db-runtime-profile.js +8 -0
- package/dist/core/mad-sks/executors/db-write-executor.js +11 -7
- package/dist/core/mad-sks/executors/executor-base.js +15 -2
- package/dist/core/mad-sks/executors/file-write-executor.js +3 -1
- package/dist/core/mad-sks/executors/package-install-executor.js +3 -1
- package/dist/core/mad-sks/executors/service-control-executor.js +3 -1
- package/dist/core/mad-sks/executors/shell-command-executor.js +3 -1
- package/dist/core/mad-sks/executors/sql-plane-executor.js +9 -1
- package/dist/core/managed-assets/managed-assets-manifest.js +2 -2
- package/dist/core/naruto/naruto-active-pool.js +2 -0
- package/dist/core/naruto/naruto-real-worker-child.js +1 -0
- package/dist/core/naruto/naruto-real-worker-runtime.js +54 -3
- package/dist/core/naruto/naruto-real-write-proof.js +9 -1
- package/dist/core/naruto/naruto-verification-dag.js +15 -2
- package/dist/core/naruto/naruto-write-e2e.js +1 -0
- package/dist/core/perf/perf-budget.js +8 -32
- package/dist/core/pipeline-internals/runtime-core.js +1 -1
- package/dist/core/pipeline-internals/runtime-gates.js +1 -1
- package/dist/core/proof/evidence-collector.js +2 -0
- package/dist/core/proof/route-finalizer.js +1 -0
- package/dist/core/provider/model-router.js +6 -5
- package/dist/core/release/release-gate-affected-selector.js +7 -3
- package/dist/core/routes/constants.js +5 -1
- package/dist/core/routes/dollar-manifest-lite.js +3 -3
- package/dist/core/routes.js +11 -1
- package/dist/core/update/update-migration-state.js +97 -24
- package/dist/core/version.js +1 -1
- package/dist/scripts/agent-role-config-repair-check.js +4 -2
- package/dist/scripts/build-dist.js +3 -1
- package/dist/scripts/codex-app-ui-preservation-check.js +19 -10
- package/dist/scripts/codex-lb-fast-ui-preservation-check.js +8 -9
- package/dist/scripts/codex-lb-gpt55-fast-profile-check.js +8 -7
- package/dist/scripts/codex-sdk-all-pipelines-check.js +1 -3
- package/dist/scripts/coding-bench-check.js +8 -2
- package/dist/scripts/doctor-fixes-codex-app-fast-ui-check.js +3 -3
- package/dist/scripts/install-update-preserves-config-check.js +7 -2
- package/dist/scripts/naruto-actual-worker-control-plane-check.js +1 -1
- package/dist/scripts/naruto-extreme-parallelism-real-check.js +3 -1
- package/dist/scripts/naruto-real-active-pool-runtime-check.js +6 -1
- package/dist/scripts/naruto-shadow-clone-swarm-check.js +5 -3
- package/dist/scripts/release-affected-selector-check.js +4 -4
- package/dist/scripts/release-gate-dag-runner-check.js +4 -6
- package/dist/scripts/release-provenance-check.js +4 -1
- package/dist/scripts/release-version-truth-check.js +8 -2
- package/dist/scripts/sizecheck.js +6 -3
- package/package.json +3 -3
- package/dist/scripts/agent-codex-child-overlap-check.js +0 -21
- package/dist/scripts/agent-model-authored-patch-envelope-check.js +0 -15
- package/dist/scripts/agent-native-cli-session-proof-check.js +0 -7
- package/dist/scripts/agent-no-subagent-scaling-check.js +0 -7
- package/dist/scripts/brand-neutrality-rename-map-check.js +0 -4
- package/dist/scripts/changelog-loop-productionization-check.js +0 -3
- package/dist/scripts/cli-check-tiers-check.js +0 -10
- package/dist/scripts/codex-0139-code-mode-web-search-check.js +0 -25
- package/dist/scripts/codex-agent-type-probe-check.js +0 -4
- package/dist/scripts/codex-native-interop-policy-check.js +0 -4
- package/dist/scripts/codex-sdk-core-skill-pipeline-check.js +0 -9
- package/dist/scripts/codex-sdk-dfix-pipeline-check.js +0 -9
- package/dist/scripts/core-skill-legacy-promotion-api-audit.js +0 -54
- package/dist/scripts/docs-brand-neutrality-check.js +0 -4
- package/dist/scripts/doctor-codex-0138-fix-check.js +0 -10
- package/dist/scripts/doctor-codex-0139-real-probes-check.js +0 -25
- package/dist/scripts/doctor-codex-doctor-parity-check.js +0 -17
- package/dist/scripts/doctor-codex-native-readiness-ux-check.js +0 -29
- package/dist/scripts/doctor-codex-native-repair-actions-check.js +0 -24
- package/dist/scripts/gate-pack-manifest-check.js +0 -9
- package/dist/scripts/git-worktree-batch-allocation-check.js +0 -10
- package/dist/scripts/github-release-body-helper.js +0 -65
- package/dist/scripts/local-llm-all-pipelines-check.js +0 -11
- package/dist/scripts/mad-db-ledger-check.js +0 -8
- package/dist/scripts/native-swarm-heartbeat-does-not-serialize-launch-check.js +0 -8
- package/dist/scripts/no-ts-nocheck-core-check.js +0 -4
- package/dist/scripts/orphan-gate-detection-check.js +0 -53
- package/dist/scripts/orphan-purge-final-check.js +0 -5
- package/dist/scripts/parallel-claim-enforcement-check.js +0 -30
- package/dist/scripts/release-batch-runner-check.js +0 -6
- package/dist/scripts/release-gate-planner.js +0 -55
- package/dist/scripts/release-runtime-truth-matrix-check.js +0 -47
- package/dist/scripts/research-quality-gate-check.js +0 -112
- package/dist/scripts/runtime-no-mjs-scripts-check.js +0 -45
- package/dist/scripts/scheduler-no-false-pending-block-check.js +0 -7
- package/dist/scripts/team-alias-to-naruto-check.js +0 -7
- package/dist/scripts/terminal-keyboard-enhancement-safety-check.js +0 -12
- package/dist/scripts/test-no-orphan-dist-imports-check.js +0 -73
- package/dist/scripts/update-gate-removed-check.js +0 -9
package/README.md
CHANGED
|
@@ -25,7 +25,7 @@ sneakoscope is a proof-first Codex trust layer for bounded agent workflows, sear
|
|
|
25
25
|
|
|
26
26
|
Sneakoscope Codex (`sks`) is a Codex CLI and Codex App harness for people who want parallel AI coding without losing proof. It gives Codex a simple front door, a dynamic worker swarm, a local dashboard, TriWiki project memory, and release gates that separate machine evidence from LLM opinion.
|
|
27
27
|
|
|
28
|
-
Current release: SKS **
|
|
28
|
+
Current release: SKS **6.0.1**. New in this release: GPT-5.6 Codex App model selection repair, Sol/Terra/Luna compatibility, removal of legacy `multi_agent_v2`/Fast-mode config stamps, renewed Codex App feature flags, safer menu bar and doctor repair paths, and release metadata prepared for `npm publish --ignore-scripts`. See [CHANGELOG.md](CHANGELOG.md).
|
|
29
29
|
|
|
30
30
|
## Install
|
|
31
31
|
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"schema": "sks.coding-bench-baseline.v1",
|
|
3
3
|
"baseline_version": "5.0.0",
|
|
4
|
-
"pass_rate": 0,
|
|
5
|
-
"min_pass_rate": 0,
|
|
6
|
-
"notes": "Real model coding bench is skipped with no_backend unless SKS_RUN_CODING_BENCH_REAL=1 and a backend credential is present."
|
|
4
|
+
"pass_rate": 0.5,
|
|
5
|
+
"min_pass_rate": 0.5,
|
|
6
|
+
"notes": "Real model coding bench is skipped (status: not_run, ok: false) with no_backend unless SKS_RUN_CODING_BENCH_REAL=1 and a backend credential is present. A fully-skipped run can no longer report ok:true (20차 P0-5)."
|
|
7
7
|
}
|
|
@@ -1,11 +1,16 @@
|
|
|
1
1
|
{
|
|
2
2
|
"schema": "sks.perf-budgets.v1",
|
|
3
|
+
"_note": "budget_p50_ms/budget_p95_ms are judged against raw wall-clock time (no node-startup-baseline deduction, 20차 P0-11). Calibrated from raw measurement on a warm dev machine (2026-07-09: version/root/commands/super-search-doctor ~40-70ms, dollar-commands ~50-130ms, doctor --json fast-mode ~40ms, plan --help/status --json/commands/mad-sks --help added after P2-2/P2-5d verification ~45-167ms) with headroom for slower/CI hosts; retighten once real CI raw numbers are collected. Gate-runtime and $Swarm-overhead budgets from the 20차 P2-6 table are NOT covered here — the former needs the P3 gate consolidation (207->~30) done first, the latter needs a real-backend E2E run (P4 E2E-1) to measure against plain `codex exec`, neither of which this repo state has yet.",
|
|
3
4
|
"commands": [
|
|
4
|
-
{ "name": "version", "argv": ["node", "./dist/bin/sks.js", "--version"], "budget_p50_ms":
|
|
5
|
-
{ "name": "commands-json", "argv": ["node", "./dist/bin/sks.js", "commands", "--json"], "budget_p50_ms":
|
|
6
|
-
{ "name": "
|
|
7
|
-
{ "name": "
|
|
8
|
-
{ "name": "
|
|
9
|
-
{ "name": "doctor-json", "argv": ["node", "./dist/bin/sks.js", "doctor", "--json"], "budget_p50_ms":
|
|
5
|
+
{ "name": "version", "argv": ["node", "./dist/bin/sks.js", "--version"], "budget_p50_ms": 100, "budget_p95_ms": 150 },
|
|
6
|
+
{ "name": "commands-json", "argv": ["node", "./dist/bin/sks.js", "commands", "--json"], "budget_p50_ms": 150, "budget_p95_ms": 220 },
|
|
7
|
+
{ "name": "commands", "argv": ["node", "./dist/bin/sks.js", "commands"], "budget_p50_ms": 250, "budget_p95_ms": 300 },
|
|
8
|
+
{ "name": "root-json", "argv": ["node", "./dist/bin/sks.js", "root", "--json"], "budget_p50_ms": 150, "budget_p95_ms": 220 },
|
|
9
|
+
{ "name": "dollar-commands-json", "argv": ["node", "./dist/bin/sks.js", "dollar-commands", "--json"], "budget_p50_ms": 200, "budget_p95_ms": 300 },
|
|
10
|
+
{ "name": "super-search-doctor-json", "argv": ["node", "./dist/bin/sks.js", "super-search", "doctor", "--json"], "budget_p50_ms": 150, "budget_p95_ms": 220 },
|
|
11
|
+
{ "name": "doctor-json", "argv": ["node", "./dist/bin/sks.js", "doctor", "--json"], "budget_p50_ms": 200, "budget_p95_ms": 300 },
|
|
12
|
+
{ "name": "status-json", "argv": ["node", "./dist/bin/sks.js", "status", "--json"], "budget_p50_ms": 220, "budget_p95_ms": 300 },
|
|
13
|
+
{ "name": "plan-help", "argv": ["node", "./dist/bin/sks.js", "plan", "--help"], "budget_p50_ms": 100, "budget_p95_ms": 150 },
|
|
14
|
+
{ "name": "mad-sks-help", "argv": ["node", "./dist/bin/sks.js", "mad-sks", "--help"], "budget_p50_ms": 100, "budget_p95_ms": 150 }
|
|
10
15
|
]
|
|
11
16
|
}
|
|
@@ -4,7 +4,7 @@ use std::io::{self, Read, Seek, SeekFrom};
|
|
|
4
4
|
fn main() {
|
|
5
5
|
let mut args = std::env::args().skip(1);
|
|
6
6
|
match args.next().as_deref() {
|
|
7
|
-
Some("--version") => println!("sks-rs
|
|
7
|
+
Some("--version") => println!("sks-rs {}", env!("CARGO_PKG_VERSION")),
|
|
8
8
|
Some("compact-info") => {
|
|
9
9
|
let mut input = String::new();
|
|
10
10
|
let _ = io::stdin().read_to_string(&mut input);
|
package/dist/bin/fast-inline.js
CHANGED
|
@@ -156,3 +156,58 @@ exports.rootJsonFastInline = rootJsonFastInline;
|
|
|
156
156
|
exports.doctorJsonFastInline = doctorJsonFastInline;
|
|
157
157
|
exports.narutoHelpJsonFastInline = narutoHelpJsonFastInline;
|
|
158
158
|
exports.hookUserPromptSubmitPerfInline = hookUserPromptSubmitPerfInline;
|
|
159
|
+
|
|
160
|
+
exports.rootJsonFastInline = rootJsonFastInline;
|
|
161
|
+
exports.doctorJsonFastInline = doctorJsonFastInline;
|
|
162
|
+
exports.narutoHelpJsonFastInline = narutoHelpJsonFastInline;
|
|
163
|
+
exports.hookUserPromptSubmitPerfInline = hookUserPromptSubmitPerfInline;
|
|
164
|
+
|
|
165
|
+
exports.rootJsonFastInline = rootJsonFastInline;
|
|
166
|
+
exports.doctorJsonFastInline = doctorJsonFastInline;
|
|
167
|
+
exports.narutoHelpJsonFastInline = narutoHelpJsonFastInline;
|
|
168
|
+
exports.hookUserPromptSubmitPerfInline = hookUserPromptSubmitPerfInline;
|
|
169
|
+
|
|
170
|
+
exports.rootJsonFastInline = rootJsonFastInline;
|
|
171
|
+
exports.doctorJsonFastInline = doctorJsonFastInline;
|
|
172
|
+
exports.narutoHelpJsonFastInline = narutoHelpJsonFastInline;
|
|
173
|
+
exports.hookUserPromptSubmitPerfInline = hookUserPromptSubmitPerfInline;
|
|
174
|
+
|
|
175
|
+
exports.rootJsonFastInline = rootJsonFastInline;
|
|
176
|
+
exports.doctorJsonFastInline = doctorJsonFastInline;
|
|
177
|
+
exports.narutoHelpJsonFastInline = narutoHelpJsonFastInline;
|
|
178
|
+
exports.hookUserPromptSubmitPerfInline = hookUserPromptSubmitPerfInline;
|
|
179
|
+
|
|
180
|
+
exports.rootJsonFastInline = rootJsonFastInline;
|
|
181
|
+
exports.doctorJsonFastInline = doctorJsonFastInline;
|
|
182
|
+
exports.narutoHelpJsonFastInline = narutoHelpJsonFastInline;
|
|
183
|
+
exports.hookUserPromptSubmitPerfInline = hookUserPromptSubmitPerfInline;
|
|
184
|
+
|
|
185
|
+
exports.rootJsonFastInline = rootJsonFastInline;
|
|
186
|
+
exports.doctorJsonFastInline = doctorJsonFastInline;
|
|
187
|
+
exports.narutoHelpJsonFastInline = narutoHelpJsonFastInline;
|
|
188
|
+
exports.hookUserPromptSubmitPerfInline = hookUserPromptSubmitPerfInline;
|
|
189
|
+
|
|
190
|
+
exports.rootJsonFastInline = rootJsonFastInline;
|
|
191
|
+
exports.doctorJsonFastInline = doctorJsonFastInline;
|
|
192
|
+
exports.narutoHelpJsonFastInline = narutoHelpJsonFastInline;
|
|
193
|
+
exports.hookUserPromptSubmitPerfInline = hookUserPromptSubmitPerfInline;
|
|
194
|
+
|
|
195
|
+
exports.rootJsonFastInline = rootJsonFastInline;
|
|
196
|
+
exports.doctorJsonFastInline = doctorJsonFastInline;
|
|
197
|
+
exports.narutoHelpJsonFastInline = narutoHelpJsonFastInline;
|
|
198
|
+
exports.hookUserPromptSubmitPerfInline = hookUserPromptSubmitPerfInline;
|
|
199
|
+
|
|
200
|
+
exports.rootJsonFastInline = rootJsonFastInline;
|
|
201
|
+
exports.doctorJsonFastInline = doctorJsonFastInline;
|
|
202
|
+
exports.narutoHelpJsonFastInline = narutoHelpJsonFastInline;
|
|
203
|
+
exports.hookUserPromptSubmitPerfInline = hookUserPromptSubmitPerfInline;
|
|
204
|
+
|
|
205
|
+
exports.rootJsonFastInline = rootJsonFastInline;
|
|
206
|
+
exports.doctorJsonFastInline = doctorJsonFastInline;
|
|
207
|
+
exports.narutoHelpJsonFastInline = narutoHelpJsonFastInline;
|
|
208
|
+
exports.hookUserPromptSubmitPerfInline = hookUserPromptSubmitPerfInline;
|
|
209
|
+
|
|
210
|
+
exports.rootJsonFastInline = rootJsonFastInline;
|
|
211
|
+
exports.doctorJsonFastInline = doctorJsonFastInline;
|
|
212
|
+
exports.narutoHelpJsonFastInline = narutoHelpJsonFastInline;
|
|
213
|
+
exports.hookUserPromptSubmitPerfInline = hookUserPromptSubmitPerfInline;
|
package/dist/bin/sks-dispatch.js
CHANGED
|
@@ -32,6 +32,13 @@ async function runSks(args) {
|
|
|
32
32
|
const { hookUserPromptSubmitPerfInline } = await import('./fast-inline.js');
|
|
33
33
|
await hookUserPromptSubmitPerfInline();
|
|
34
34
|
}
|
|
35
|
+
else if (args[0] === 'hook' && args[1] && process.env.SKS_HOOK_DAEMON === '1') {
|
|
36
|
+
// 20차 P2-1: opt-in daemon-accelerated hook path. Default hook behavior
|
|
37
|
+
// (.codex/hooks.json's actual command) is unchanged until this has been
|
|
38
|
+
// verified and deliberately turned on.
|
|
39
|
+
const { hookDaemonInline } = await import('../core/daemon/sksd-hook-dispatch.js');
|
|
40
|
+
await hookDaemonInline(args[1]);
|
|
41
|
+
}
|
|
35
42
|
else if (args[0] === 'naruto' && (args[1] === 'help' || args.includes('--help')) && args.includes('--json')) {
|
|
36
43
|
const { narutoHelpJsonFastInline } = await import('./fast-inline.js');
|
|
37
44
|
narutoHelpJsonFastInline();
|
|
@@ -55,3 +62,25 @@ async function runSks(args) {
|
|
|
55
62
|
exports.runSks = runSks;
|
|
56
63
|
|
|
57
64
|
exports.runSks = runSks;
|
|
65
|
+
|
|
66
|
+
exports.runSks = runSks;
|
|
67
|
+
|
|
68
|
+
exports.runSks = runSks;
|
|
69
|
+
|
|
70
|
+
exports.runSks = runSks;
|
|
71
|
+
|
|
72
|
+
exports.runSks = runSks;
|
|
73
|
+
|
|
74
|
+
exports.runSks = runSks;
|
|
75
|
+
|
|
76
|
+
exports.runSks = runSks;
|
|
77
|
+
|
|
78
|
+
exports.runSks = runSks;
|
|
79
|
+
|
|
80
|
+
exports.runSks = runSks;
|
|
81
|
+
|
|
82
|
+
exports.runSks = runSks;
|
|
83
|
+
|
|
84
|
+
exports.runSks = runSks;
|
|
85
|
+
|
|
86
|
+
exports.runSks = runSks;
|
package/dist/bin/sks.js
CHANGED
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
|
-
const
|
|
2
|
+
const { PACKAGE_VERSION } = require('../core/version.js');
|
|
3
3
|
const firstArg = process.argv[2];
|
|
4
4
|
if (firstArg === '--version' || firstArg === '-v' || firstArg === 'version') {
|
|
5
|
-
process.stdout.write(`sneakoscope ${
|
|
5
|
+
process.stdout.write(`sneakoscope ${PACKAGE_VERSION}\n`);
|
|
6
6
|
}
|
|
7
7
|
else {
|
|
8
8
|
import('./sks-dispatch.js').then(({ runSks }) => runSks(process.argv.slice(2))).catch((err) => {
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { spawn } from 'node:child_process';
|
|
2
2
|
import { codexRemoteControlStatus, formatCodexRemoteControlStatus } from '../core/codex-app.js';
|
|
3
|
-
import {
|
|
3
|
+
import { forceRequiredCodexModelConfigArgs } from '../core/codex-model-guard.js';
|
|
4
4
|
export async function codexAppRemoteControlCommand(args = [], opts = {}) {
|
|
5
5
|
const controlArgs = argsBeforeSeparator(args);
|
|
6
6
|
if (controlArgs.includes('--help') || controlArgs.includes('-h')) {
|
|
@@ -25,7 +25,7 @@ export async function codexAppRemoteControlCommand(args = [], opts = {}) {
|
|
|
25
25
|
process.exitCode = 1;
|
|
26
26
|
return;
|
|
27
27
|
}
|
|
28
|
-
const passthrough =
|
|
28
|
+
const passthrough = forceRequiredCodexModelConfigArgs(stripSeparator(args));
|
|
29
29
|
const spawnFn = opts.spawn || spawn;
|
|
30
30
|
const code = await spawnInherited(spawnFn, status.codex_cli.bin, ['remote-control', ...passthrough], {
|
|
31
31
|
cwd: process.cwd(),
|
|
@@ -23,7 +23,7 @@ import { extractTomlTable, writeCodexConfigGuarded } from '../core/codex/codex-c
|
|
|
23
23
|
import { cleanupCodexConfigBackups, validateCodexConfigRoundTrip } from '../core/codex/codex-config-toml.js';
|
|
24
24
|
import { runPostinstallGlobalDoctorAndMarkPending } from '../core/update/update-migration-state.js';
|
|
25
25
|
import { repairCodexImagegen } from '../core/doctor/imagegen-repair.js';
|
|
26
|
-
import { REQUIRED_CODEX_MODEL } from '../core/codex-model-guard.js';
|
|
26
|
+
import { GPT55_CODEX_MODEL, GPT56_CODEX_MODELS, REQUIRED_CODEX_MODEL } from '../core/codex-model-guard.js';
|
|
27
27
|
const CODEX_LB_PROVIDER_NAME = 'openai';
|
|
28
28
|
const CODEX_LB_PROVIDER_ENV_KEY = 'CODEX_LB_API_KEY';
|
|
29
29
|
const CODEX_LB_CANONICAL_FAST_SERVICE_TIER = 'priority';
|
|
@@ -993,12 +993,12 @@ function codexLbFastModeConfigStatus(text = '') {
|
|
|
993
993
|
const globalServiceTier = topLevelTomlString(text, 'service_tier');
|
|
994
994
|
const profileBlock = String(text || '').match(/(^|\n)\[profiles\.sks-fast-high\]([\s\S]*?)(?=\n\[[^\]]+\]|\s*$)/)?.[2] || '';
|
|
995
995
|
const profileServiceTier = profileBlock.match(/(^|\n)\s*service_tier\s*=\s*"([^"]+)"/)?.[2] || '';
|
|
996
|
-
const configured = globalServiceTier === 'fast' || globalServiceTier === CODEX_LB_CANONICAL_FAST_SERVICE_TIER
|
|
996
|
+
const configured = globalServiceTier === 'fast' || globalServiceTier === CODEX_LB_CANONICAL_FAST_SERVICE_TIER;
|
|
997
997
|
return {
|
|
998
998
|
schema: 'sks.codex-lb-fast-mode-config.v1',
|
|
999
999
|
configured,
|
|
1000
1000
|
top_level_service_tier: globalServiceTier || null,
|
|
1001
|
-
|
|
1001
|
+
legacy_profile_service_tier: profileServiceTier || null,
|
|
1002
1002
|
codex_request_service_tier: configured ? 'fast' : null,
|
|
1003
1003
|
codex_lb_upstream_service_tier: configured ? CODEX_LB_CANONICAL_FAST_SERVICE_TIER : null,
|
|
1004
1004
|
actual_service_tier_verified: false,
|
|
@@ -1030,10 +1030,7 @@ export async function repairCodexLbAuth(opts = {}) {
|
|
|
1030
1030
|
}
|
|
1031
1031
|
if (status.env_key_configured && status.base_url && (!status.provider_contract_ok || !status.selected || legacyAuthMigrated || hasTopLevelCodexModeLock(currentConfig) || (opts.forceCodexLbApiKeyAuth === true && !status.ok))) {
|
|
1032
1032
|
await ensureDir(path.dirname(status.config_path));
|
|
1033
|
-
const preservedUserFastMode = extractTomlTable(currentConfig, 'user.fast_mode');
|
|
1034
1033
|
let next = upsertCodexLbConfig(currentConfig, status.base_url);
|
|
1035
|
-
if (preservedUserFastMode)
|
|
1036
|
-
next = upsertTomlTable(next, 'user.fast_mode', preservedUserFastMode);
|
|
1037
1034
|
next = normalizeCodexFastModeUiConfig(next, {
|
|
1038
1035
|
forceFastMode: opts.forceFastMode === true || opts.forceCodexLbApiKeyAuth === true
|
|
1039
1036
|
});
|
|
@@ -1873,7 +1870,9 @@ export async function ensureGlobalCodexFastModeDuringInstall(opts = {}) {
|
|
|
1873
1870
|
});
|
|
1874
1871
|
if (next === ensureTrailingNewline(current))
|
|
1875
1872
|
return { status: 'present', config_path: configPath };
|
|
1876
|
-
const safeWrite = await safeWriteCodexConfigToml(configPath, current, next, 'codex-fast-mode-install'
|
|
1873
|
+
const safeWrite = await safeWriteCodexConfigToml(configPath, current, next, 'codex-fast-mode-install', {
|
|
1874
|
+
preserveFastUiKeys: opts.forceFastModeOff !== true
|
|
1875
|
+
});
|
|
1877
1876
|
return {
|
|
1878
1877
|
status: safeWrite.status === 'written' ? 'updated' : safeWrite.status,
|
|
1879
1878
|
config_path: configPath,
|
|
@@ -1891,65 +1890,42 @@ export function normalizeCodexFastModeUiConfig(text = '', opts = {}) {
|
|
|
1891
1890
|
return normalizeCodexFastModeUiConfigOnce(normalizeCodexFastModeUiConfigOnce(text, opts), opts);
|
|
1892
1891
|
}
|
|
1893
1892
|
function normalizeCodexFastModeUiConfigOnce(text = '', opts = {}) {
|
|
1894
|
-
//
|
|
1895
|
-
//
|
|
1896
|
-
//
|
|
1893
|
+
// 2026-07 Codex App renewal (ChatGPT desktop merge): the config schema removed
|
|
1894
|
+
// `default_profile`, `[profiles.<name>]` tables, `[user.fast_mode]`, and
|
|
1895
|
+
// `notice.fast_default_opt_out`. The only documented fast-default mechanism is
|
|
1896
|
+
// the plain top-level `service_tier = "fast"`. This pass strips every legacy
|
|
1897
|
+
// stamp SKS ever wrote and keeps user-authored top-level choices intact.
|
|
1897
1898
|
let next = String(text || '');
|
|
1898
|
-
const misplacedDefaultProfile = tomlTableString(next, 'user.fast_mode', 'default_profile');
|
|
1899
1899
|
next = removeLegacyTopLevelCodexModeLocks(next);
|
|
1900
|
-
next =
|
|
1900
|
+
next = normalizeCodexAppDefaultModel(next);
|
|
1901
|
+
next = removeTopLevelTomlKeyIfValue(next, 'default_profile', 'sks-fast-high');
|
|
1902
|
+
next = removeTomlTable(next, 'user.fast_mode');
|
|
1903
|
+
next = removeTomlTable(next, 'profiles.sks-fast-high');
|
|
1901
1904
|
next = removeTomlTableKey(next, 'notice', 'fast_default_opt_out');
|
|
1902
|
-
|
|
1905
|
+
// Feature flags SKS wrote in earlier versions that are not in the current
|
|
1906
|
+
// [features] reference (renewal removed/renamed them). They only trigger the
|
|
1907
|
+
// under-development warning now — strip our own stamps.
|
|
1908
|
+
for (const legacyFlag of [
|
|
1909
|
+
'codex_hooks', 'remote_control', 'fast_mode_ui', 'codex_git_commit', 'computer_use',
|
|
1910
|
+
'browser_use', 'browser_use_external', 'image_generation', 'in_app_browser',
|
|
1911
|
+
'guardian_approval', 'tool_suggest', 'plugins'
|
|
1912
|
+
]) {
|
|
1913
|
+
next = removeTomlTableKey(next, 'features', legacyFlag);
|
|
1914
|
+
}
|
|
1903
1915
|
if (opts.forceFastMode === true) {
|
|
1904
1916
|
next = upsertTopLevelTomlString(next, 'service_tier', 'fast');
|
|
1905
1917
|
}
|
|
1906
1918
|
else if (opts.forceFastModeOff === true) {
|
|
1907
|
-
|
|
1919
|
+
// "off" = remove the tier and let Codex's own default apply. The old code
|
|
1920
|
+
// wrote service_tier = "default", which is not a documented tier value.
|
|
1921
|
+
next = removeTopLevelTomlKey(next, 'service_tier');
|
|
1908
1922
|
}
|
|
1909
|
-
//
|
|
1910
|
-
//
|
|
1911
|
-
// user disabled in the App, and never rejects-then-hides UI by forcing an unrecognized
|
|
1912
|
-
// flag on an older App build. This is what stops SKS from "removing/blocking" the App UI.
|
|
1923
|
+
// Documented, currently-valid feature flags are SET-IF-ABSENT: a fresh config
|
|
1924
|
+
// gets SKS's defaults, but SKS never re-enables a feature the user disabled.
|
|
1913
1925
|
next = upsertTopLevelTomlBooleanIfAbsent(next, 'suppress_unstable_features_warning', true);
|
|
1914
|
-
for (const featureLine of [
|
|
1915
|
-
|
|
1916
|
-
'fast_mode_ui = true', 'codex_git_commit = true', 'computer_use = true', 'browser_use = true',
|
|
1917
|
-
'browser_use_external = true', 'image_generation = true', 'in_app_browser = true',
|
|
1918
|
-
'guardian_approval = true', 'tool_suggest = true', 'apps = true', 'plugins = true'
|
|
1919
|
-
]) {
|
|
1920
|
-
const featureKey = featureLine.split('=')[0]?.trim();
|
|
1921
|
-
next = opts.forceFastMode === true && ['fast_mode', 'fast_mode_ui'].includes(String(featureKey || ''))
|
|
1922
|
-
? upsertTomlTableKey(next, 'features', featureLine)
|
|
1923
|
-
: upsertTomlTableKeyIfAbsent(next, 'features', featureLine);
|
|
1924
|
-
}
|
|
1925
|
-
if (opts.forceFastMode === true || opts.forceFastModeOff === true) {
|
|
1926
|
-
next = upsertTomlTableKey(next, 'user.fast_mode', 'visible = true');
|
|
1927
|
-
next = upsertTomlTableKey(next, 'user.fast_mode', 'enabled = true');
|
|
1928
|
-
next = opts.forceFastMode === true
|
|
1929
|
-
? upsertTopLevelTomlString(next, 'default_profile', 'sks-fast-high')
|
|
1930
|
-
: removeTopLevelTomlKeyIfValue(next, 'default_profile', 'sks-fast-high');
|
|
1931
|
-
}
|
|
1932
|
-
else {
|
|
1933
|
-
next = upsertTomlTableKeyIfAbsent(next, 'user.fast_mode', 'visible = true');
|
|
1934
|
-
next = upsertTomlTableKeyIfAbsent(next, 'user.fast_mode', 'enabled = true');
|
|
1935
|
-
if (misplacedDefaultProfile === 'sks-fast-high') {
|
|
1936
|
-
next = upsertTopLevelTomlString(next, 'default_profile', 'sks-fast-high');
|
|
1937
|
-
}
|
|
1926
|
+
for (const featureLine of ['hooks = true', 'multi_agent = true', 'fast_mode = true', 'apps = true']) {
|
|
1927
|
+
next = upsertTomlTableKeyIfAbsent(next, 'features', featureLine);
|
|
1938
1928
|
}
|
|
1939
|
-
// Keep ONLY the sks-fast-high config-profile table for explicit fast-mode opt-in
|
|
1940
|
-
// and CLI `--profile` use. The other SKS config profiles are
|
|
1941
|
-
// no longer written as `[profiles.sks-*]` tables here (Codex 0.134+ deprecates them);
|
|
1942
|
-
// they are managed as per-file `<name>.config.toml` overlays by
|
|
1943
|
-
// migrateSksProfilesToPerFile (src/core/auto-review.ts), which also writes the
|
|
1944
|
-
// sks-fast-high overlay for CLI `--profile` use.
|
|
1945
|
-
next = upsertTomlTableKey(next, 'profiles.sks-fast-high', `model = "${REQUIRED_CODEX_MODEL}"`);
|
|
1946
|
-
next = upsertTomlTableKey(next, 'profiles.sks-fast-high', 'service_tier = "fast"');
|
|
1947
|
-
next = upsertTomlTableKey(next, 'profiles.sks-fast-high', 'approval_policy = "on-request"');
|
|
1948
|
-
// Do not force a sandbox from the Codex App fast profile. The App/IDE
|
|
1949
|
-
// permissions selector owns full-access vs workspace-write; this profile only
|
|
1950
|
-
// supplies SKS's model, speed, approval, and reasoning defaults.
|
|
1951
|
-
next = removeTomlTableKey(next, 'profiles.sks-fast-high', 'sandbox_mode');
|
|
1952
|
-
next = upsertTomlTableKey(next, 'profiles.sks-fast-high', 'model_reasoning_effort = "high"');
|
|
1953
1929
|
// Plugin auto-enable is OPT-IN only. Force-writing `[plugins."name@marketplace"] enabled =
|
|
1954
1930
|
// true` for marketplace plugins the App may not have installed (different build/channel)
|
|
1955
1931
|
// makes the App reference plugins it cannot load -> broken/blocked plugin UI. It also
|
|
@@ -1964,20 +1940,55 @@ function normalizeCodexFastModeUiConfigOnce(text = '', opts = {}) {
|
|
|
1964
1940
|
}
|
|
1965
1941
|
return ensureTrailingNewline(next);
|
|
1966
1942
|
}
|
|
1943
|
+
function removeTopLevelTomlKey(text = '', key = '') {
|
|
1944
|
+
const lines = String(text || '').split('\n');
|
|
1945
|
+
const firstTable = lines.findIndex((x) => /^\s*\[.+\]\s*$/.test(x));
|
|
1946
|
+
const end = firstTable === -1 ? lines.length : firstTable;
|
|
1947
|
+
const keyPattern = new RegExp(`^\\s*${escapeRegExp(key)}\\s*=`);
|
|
1948
|
+
return lines.filter((line, index) => index >= end || !keyPattern.test(line)).join('\n').replace(/^\n+/, '').replace(/\n{3,}/g, '\n\n');
|
|
1949
|
+
}
|
|
1950
|
+
function removeTomlTable(text, table) {
|
|
1951
|
+
const lines = String(text || '').trimEnd().split('\n');
|
|
1952
|
+
const header = `[${table}]`;
|
|
1953
|
+
const start = lines.findIndex((x) => x.trim() === header);
|
|
1954
|
+
if (start === -1)
|
|
1955
|
+
return String(text || '');
|
|
1956
|
+
let end = lines.length;
|
|
1957
|
+
for (let i = start + 1; i < lines.length; i += 1) {
|
|
1958
|
+
const ln = lines[i];
|
|
1959
|
+
if (ln !== undefined && /^\s*\[.+\]\s*$/.test(ln)) {
|
|
1960
|
+
end = i;
|
|
1961
|
+
break;
|
|
1962
|
+
}
|
|
1963
|
+
}
|
|
1964
|
+
return lines.filter((_, index) => index < start || index >= end).join('\n').replace(/^\n+/, '').replace(/\n{3,}/g, '\n\n');
|
|
1965
|
+
}
|
|
1967
1966
|
function removeLegacyTopLevelCodexModeLocks(text = '') {
|
|
1968
1967
|
const lines = String(text || '').split('\n');
|
|
1969
1968
|
const firstTable = lines.findIndex((x) => /^\s*\[.+\]\s*$/.test(x));
|
|
1970
1969
|
const end = firstTable === -1 ? lines.length : firstTable;
|
|
1971
1970
|
const topLevelModel = topLevelTomlString(text, 'model');
|
|
1972
|
-
const removeSksOwnedModeLock = topLevelModel
|
|
1971
|
+
const removeSksOwnedModeLock = isLegacySksCodexModelStamp(topLevelModel);
|
|
1973
1972
|
return lines.filter((line, index) => {
|
|
1974
1973
|
if (index >= end)
|
|
1975
1974
|
return true;
|
|
1976
1975
|
if (!removeSksOwnedModeLock)
|
|
1977
1976
|
return true;
|
|
1978
|
-
return !/^\s*
|
|
1977
|
+
return !/^\s*model_reasoning_effort\s*=/.test(line);
|
|
1979
1978
|
}).join('\n').replace(/^\n+/, '').replace(/\n{3,}/g, '\n\n');
|
|
1980
1979
|
}
|
|
1980
|
+
function normalizeCodexAppDefaultModel(text = '') {
|
|
1981
|
+
const currentModel = topLevelTomlString(text, 'model');
|
|
1982
|
+
if (!currentModel)
|
|
1983
|
+
return upsertTopLevelTomlString(text, 'model', REQUIRED_CODEX_MODEL);
|
|
1984
|
+
if (isLegacySksCodexModelStamp(currentModel))
|
|
1985
|
+
return upsertTopLevelTomlString(text, 'model', REQUIRED_CODEX_MODEL);
|
|
1986
|
+
return String(text || '');
|
|
1987
|
+
}
|
|
1988
|
+
function isLegacySksCodexModelStamp(value = '') {
|
|
1989
|
+
const model = String(value || '').trim().toLowerCase();
|
|
1990
|
+
return model === REQUIRED_CODEX_MODEL || model === GPT55_CODEX_MODEL || GPT56_CODEX_MODELS.includes(model);
|
|
1991
|
+
}
|
|
1981
1992
|
function removeTopLevelTomlKeyIfValue(text = '', key = '', value = '') {
|
|
1982
1993
|
const lines = String(text || '').split('\n');
|
|
1983
1994
|
const firstTable = lines.findIndex((x) => /^\s*\[.+\]\s*$/.test(x));
|
|
@@ -2134,31 +2145,29 @@ async function backupCodexConfig(configPath, text, tag) {
|
|
|
2134
2145
|
// - refuse to WRITE a result that would not parse (e.g. a regex helper mangled a multiline
|
|
2135
2146
|
// string), leaving the existing config untouched,
|
|
2136
2147
|
// - otherwise back up the prior config before mutating.
|
|
2137
|
-
export async function safeWriteCodexConfigToml(configPath, current, next, tag = 'codex-lb') {
|
|
2148
|
+
export async function safeWriteCodexConfigToml(configPath, current, next, tag = 'codex-lb', opts = {}) {
|
|
2138
2149
|
return writeCodexConfigGuarded({
|
|
2139
2150
|
configPath,
|
|
2140
2151
|
before: String(current || ''),
|
|
2141
2152
|
cause: tag,
|
|
2142
2153
|
removeTopLevelModeLocks: true,
|
|
2154
|
+
...(opts.preserveFastUiKeys === undefined ? {} : { preserveFastUiKeys: opts.preserveFastUiKeys }),
|
|
2143
2155
|
mutate: () => String(next || '')
|
|
2144
2156
|
});
|
|
2145
2157
|
}
|
|
2146
2158
|
export function codexFastModeDesktopStatus(text = '') {
|
|
2147
2159
|
const validation = validateCodexConfigRoundTrip(String(text || ''));
|
|
2148
|
-
|
|
2149
|
-
|
|
2150
|
-
|
|
2151
|
-
|
|
2152
|
-
&& profile?.service_tier === 'fast';
|
|
2160
|
+
// Post-renewal contract: the fast default is the plain top-level
|
|
2161
|
+
// service_tier = "fast". default_profile/[profiles.*]/[user.fast_mode] are
|
|
2162
|
+
// gone from the Codex config schema and are only reported as legacy_keys.
|
|
2163
|
+
const globalOn = validation.ok && validation.service_tier === 'fast';
|
|
2153
2164
|
return {
|
|
2154
|
-
schema: 'sks.codex-fast-mode-desktop-status.
|
|
2165
|
+
schema: 'sks.codex-fast-mode-desktop-status.v2',
|
|
2155
2166
|
ok: validation.ok,
|
|
2156
2167
|
on: Boolean(globalOn),
|
|
2157
|
-
|
|
2158
|
-
|
|
2159
|
-
|
|
2160
|
-
profile_model: profile?.model || null,
|
|
2161
|
-
profile_service_tier: profile?.service_tier || null,
|
|
2168
|
+
service_tier: validation.service_tier ?? null,
|
|
2169
|
+
model: validation.model ?? null,
|
|
2170
|
+
legacy_keys: validation.legacy_keys,
|
|
2162
2171
|
validation
|
|
2163
2172
|
};
|
|
2164
2173
|
}
|
|
@@ -3397,8 +3406,14 @@ export async function selftestCodexLb(tmp) {
|
|
|
3397
3406
|
});
|
|
3398
3407
|
if (brokenChain.ok || brokenChain.status !== 'previous_response_not_found' || brokenChain.chain_unhealthy !== true)
|
|
3399
3408
|
throw new Error('selftest: codex-lb response chain health check did not detect previous_response_not_found');
|
|
3400
|
-
|
|
3401
|
-
|
|
3409
|
+
// 2026-07 renewal contract: only documented [features] flags remain; the flags,
|
|
3410
|
+
// [user.fast_mode], [profiles.sks-fast-high], and notice.fast_default_opt_out SKS
|
|
3411
|
+
// used to write must be STRIPPED by setup. User-authored tables ([profiles.custom])
|
|
3412
|
+
// are preserved untouched even though the schema dropped profile tables.
|
|
3413
|
+
const legacyStamps = ['remote_control = true', 'fast_mode_ui = true', 'codex_git_commit = true', 'computer_use = true', 'browser_use = true', 'browser_use_external = true', 'guardian_approval = true', 'tool_suggest = true', 'plugins = true', '[user.fast_mode]', '[profiles.sks-fast-high]', 'fast_default_opt_out = true'];
|
|
3414
|
+
const survivingLegacy = legacyStamps.filter((stamp) => codexLbConfig.includes(stamp));
|
|
3415
|
+
if (!codexLbConfig.includes('hooks = true') || hasDeprecatedCodexHooksFeatureFlag(codexLbConfig) || !codexLbConfig.includes('multi_agent = true') || !codexLbConfig.includes('fast_mode = true') || !codexLbConfig.includes('apps = true') || survivingLegacy.length || !/\[profiles\.custom\][\s\S]*?model_reasoning_effort = "low"/.test(codexLbConfig) || hasTopLevelCodexModeLock(codexLbConfig))
|
|
3416
|
+
throw new Error(`selftest: codex-lb setup did not enforce the renewed feature-flag contract (documented flags present, legacy stamps stripped, user profile tables preserved)${survivingLegacy.length ? ` — surviving legacy stamps: ${survivingLegacy.join(', ')}` : ''}`);
|
|
3402
3417
|
if (!hasCodexUnstableFeatureWarningSuppression(codexLbConfig))
|
|
3403
3418
|
throw new Error('selftest: codex-lb setup did not suppress Codex unstable feature warning');
|
|
3404
3419
|
const codexLbLaunch = `source ${path.join(tmp, '.codex', 'sks-codex-lb.env')} && codex '--model' '${REQUIRED_CODEX_MODEL}'`;
|
|
@@ -3414,7 +3429,7 @@ function hasTopLevelCodexModeLock(text = '') {
|
|
|
3414
3429
|
const lines = String(text || '').split('\n');
|
|
3415
3430
|
const firstTable = lines.findIndex((x) => /^\s*\[.+\]\s*$/.test(x));
|
|
3416
3431
|
const top = (firstTable === -1 ? lines : lines.slice(0, firstTable)).join('\n');
|
|
3417
|
-
return /(^|\n)\s*
|
|
3432
|
+
return /(^|\n)\s*model_reasoning_effort\s*=/.test(top);
|
|
3418
3433
|
}
|
|
3419
3434
|
function hasDeprecatedCodexHooksFeatureFlag(text = '') {
|
|
3420
3435
|
const lines = String(text || '').split('\n');
|
package/dist/cli/router.js
CHANGED
|
@@ -76,32 +76,39 @@ async function dispatchInner(argv) {
|
|
|
76
76
|
return result;
|
|
77
77
|
}
|
|
78
78
|
const entry = COMMAND_MANIFEST_BY_NAME[command];
|
|
79
|
-
const
|
|
80
|
-
if (!
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
console.error(
|
|
99
|
-
|
|
100
|
-
console.error(`
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
79
|
+
const helpRequest = isHelpRequest(rest);
|
|
80
|
+
if (!helpRequest) {
|
|
81
|
+
const commandGate = await ensureActiveRouteCommandGate(command, rest);
|
|
82
|
+
if (!commandGate.ok) {
|
|
83
|
+
console.error(commandGate.message);
|
|
84
|
+
process.exitCode = 1;
|
|
85
|
+
return commandGate;
|
|
86
|
+
}
|
|
87
|
+
// 20차 P2-2: --help/-h/help must never wait on (or be blocked by) the
|
|
88
|
+
// migration gate's lock — a stuck/contended migration lock previously
|
|
89
|
+
// made `sks <cmd> --help` take the full MIGRATION_LOCK_WAIT_MS (20s) and
|
|
90
|
+
// then fail, for a request that only wants usage text.
|
|
91
|
+
const { ensureCurrentMigrationBeforeCommand } = await import('../core/update/update-migration-state.js');
|
|
92
|
+
const migrationGate = await ensureCurrentMigrationBeforeCommand({
|
|
93
|
+
command,
|
|
94
|
+
args: rest,
|
|
95
|
+
skipMigrationGate: entry.skipMigrationGate === true || entry.readonly === true
|
|
96
|
+
});
|
|
97
|
+
if (!migrationGate.ok) {
|
|
98
|
+
console.error('SKS project migration blocked.');
|
|
99
|
+
console.error(`Scope: ${migrationGate.scope || 'project'}`);
|
|
100
|
+
console.error(`Stage: ${migrationGate.failed_stage_id || migrationGate.status}`);
|
|
101
|
+
if (migrationGate.failed_stage_id)
|
|
102
|
+
console.error(`Failed stage: ${migrationGate.failed_stage_id}`);
|
|
103
|
+
for (const blocker of migrationGate.blockers)
|
|
104
|
+
console.error(`Required blocker: ${blocker}`);
|
|
105
|
+
for (const warning of migrationGate.warnings)
|
|
106
|
+
console.error(`Optional warning: ${warning}`);
|
|
107
|
+
console.error(`Receipt: ${migrationGate.receipt_path}`);
|
|
108
|
+
console.error('Remedies: run `sks doctor --fix --yes`, then retry; diagnostics that must bypass this gate are marked skipMigrationGate in the command registry.');
|
|
109
|
+
process.exitCode = 1;
|
|
110
|
+
return migrationGate;
|
|
111
|
+
}
|
|
105
112
|
}
|
|
106
113
|
const { COMMANDS } = await import('./command-registry.js');
|
|
107
114
|
const commandEntry = COMMANDS[command];
|
|
@@ -110,6 +117,16 @@ async function dispatchInner(argv) {
|
|
|
110
117
|
throw new Error(`Command ${command} must export run(command, args)`);
|
|
111
118
|
return mod.run(rawCommand || command, rest);
|
|
112
119
|
}
|
|
120
|
+
// --help/-h/help must skip the active-route and migration gates regardless
|
|
121
|
+
// of where it appears in args — a pure usage-text request should never wait
|
|
122
|
+
// on (or be blocked by) project state (20차 P2-2).
|
|
123
|
+
function isHelpRequest(args) {
|
|
124
|
+
// --help/-h are unambiguous flags wherever they appear; bare "help" is
|
|
125
|
+
// only treated as the request when it's the subcommand position (args[0])
|
|
126
|
+
// so an arbitrary value elsewhere (e.g. a commit message of "help") can't
|
|
127
|
+
// accidentally bypass the gates.
|
|
128
|
+
return args.includes('--help') || args.includes('-h') || String(args[0] || '').toLowerCase() === 'help';
|
|
129
|
+
}
|
|
113
130
|
async function ensureActiveRouteCommandGate(command, args) {
|
|
114
131
|
const entry = COMMAND_MANIFEST_BY_NAME[command];
|
|
115
132
|
if (command === 'route' || entry.readonly === true || entry.allowedDuringActiveRoute === true && entry.mutatesRouteState !== true) {
|
package/dist/commands/doctor.js
CHANGED
|
@@ -254,10 +254,9 @@ async function runDoctor(args = [], root, doctorFix) {
|
|
|
254
254
|
global_skills: installScope === 'global' && !flag(args, '--local-only')
|
|
255
255
|
? deepDiagnostics ? await (await import('../cli/install-helpers.js')).ensureGlobalCodexSkillsDuringInstall({ force: true }) : { status: 'skipped', reason: 'default_doctor_no_global_skill_regeneration' }
|
|
256
256
|
: { status: 'skipped', reason: 'project or local-only repair' },
|
|
257
|
-
//
|
|
258
|
-
//
|
|
259
|
-
//
|
|
260
|
-
// backs up + parse-validates before writing, no-op when already present.
|
|
257
|
+
// Normalize global Codex fast-mode config to the 2026-07 schema: preserve
|
|
258
|
+
// service_tier="fast" when requested, strip legacy [user.fast_mode] and
|
|
259
|
+
// [profiles.sks-fast-high] stamps, and parse-validate before writing.
|
|
261
260
|
codex_app_fast_mode: flag(args, '--local-only')
|
|
262
261
|
? { status: 'skipped', reason: 'local-only repair' }
|
|
263
262
|
: await (await import('../cli/install-helpers.js')).ensureGlobalCodexFastModeDuringInstall().catch((err) => ({ status: 'failed', error: err?.message || String(err) }))
|