sneakoscope 5.12.0 → 6.0.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 +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 +35 -0
- package/dist/bin/sks-dispatch.js +21 -0
- package/dist/bin/sks.js +2 -2
- package/dist/cli/codex-app-command.js +2 -2
- package/dist/cli/install-helpers.js +75 -71
- 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 +8 -8
- 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 +3 -2
- package/dist/core/codex-app.js +5 -5
- 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 +52 -6
- package/dist/core/commands/fast-mode-command.js +1 -1
- package/dist/core/commands/mad-db-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 +36 -22
- 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 +80 -23
- 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 +6 -7
- package/dist/scripts/codex-lb-gpt55-fast-profile-check.js +6 -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 +2 -2
- 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/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.0**. New in this release: GPT-5.6 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,38 @@ 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;
|
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,17 @@ 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;
|
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, 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,41 @@ 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 = removeTopLevelTomlKeyIfValue(next, 'default_profile', 'sks-fast-high');
|
|
1901
|
+
next = removeTomlTable(next, 'user.fast_mode');
|
|
1902
|
+
next = removeTomlTable(next, 'profiles.sks-fast-high');
|
|
1901
1903
|
next = removeTomlTableKey(next, 'notice', 'fast_default_opt_out');
|
|
1902
|
-
|
|
1904
|
+
// Feature flags SKS wrote in earlier versions that are not in the current
|
|
1905
|
+
// [features] reference (renewal removed/renamed them). They only trigger the
|
|
1906
|
+
// under-development warning now — strip our own stamps.
|
|
1907
|
+
for (const legacyFlag of [
|
|
1908
|
+
'codex_hooks', 'remote_control', 'fast_mode_ui', 'codex_git_commit', 'computer_use',
|
|
1909
|
+
'browser_use', 'browser_use_external', 'image_generation', 'in_app_browser',
|
|
1910
|
+
'guardian_approval', 'tool_suggest', 'plugins'
|
|
1911
|
+
]) {
|
|
1912
|
+
next = removeTomlTableKey(next, 'features', legacyFlag);
|
|
1913
|
+
}
|
|
1903
1914
|
if (opts.forceFastMode === true) {
|
|
1904
1915
|
next = upsertTopLevelTomlString(next, 'service_tier', 'fast');
|
|
1905
1916
|
}
|
|
1906
1917
|
else if (opts.forceFastModeOff === true) {
|
|
1907
|
-
|
|
1918
|
+
// "off" = remove the tier and let Codex's own default apply. The old code
|
|
1919
|
+
// wrote service_tier = "default", which is not a documented tier value.
|
|
1920
|
+
next = removeTopLevelTomlKey(next, 'service_tier');
|
|
1908
1921
|
}
|
|
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.
|
|
1922
|
+
// Documented, currently-valid feature flags are SET-IF-ABSENT: a fresh config
|
|
1923
|
+
// gets SKS's defaults, but SKS never re-enables a feature the user disabled.
|
|
1913
1924
|
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
|
-
}
|
|
1925
|
+
for (const featureLine of ['hooks = true', 'multi_agent = true', 'fast_mode = true', 'apps = true']) {
|
|
1926
|
+
next = upsertTomlTableKeyIfAbsent(next, 'features', featureLine);
|
|
1938
1927
|
}
|
|
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
1928
|
// Plugin auto-enable is OPT-IN only. Force-writing `[plugins."name@marketplace"] enabled =
|
|
1954
1929
|
// true` for marketplace plugins the App may not have installed (different build/channel)
|
|
1955
1930
|
// makes the App reference plugins it cannot load -> broken/blocked plugin UI. It also
|
|
@@ -1964,12 +1939,37 @@ function normalizeCodexFastModeUiConfigOnce(text = '', opts = {}) {
|
|
|
1964
1939
|
}
|
|
1965
1940
|
return ensureTrailingNewline(next);
|
|
1966
1941
|
}
|
|
1942
|
+
function removeTopLevelTomlKey(text = '', key = '') {
|
|
1943
|
+
const lines = String(text || '').split('\n');
|
|
1944
|
+
const firstTable = lines.findIndex((x) => /^\s*\[.+\]\s*$/.test(x));
|
|
1945
|
+
const end = firstTable === -1 ? lines.length : firstTable;
|
|
1946
|
+
const keyPattern = new RegExp(`^\\s*${escapeRegExp(key)}\\s*=`);
|
|
1947
|
+
return lines.filter((line, index) => index >= end || !keyPattern.test(line)).join('\n').replace(/^\n+/, '').replace(/\n{3,}/g, '\n\n');
|
|
1948
|
+
}
|
|
1949
|
+
function removeTomlTable(text, table) {
|
|
1950
|
+
const lines = String(text || '').trimEnd().split('\n');
|
|
1951
|
+
const header = `[${table}]`;
|
|
1952
|
+
const start = lines.findIndex((x) => x.trim() === header);
|
|
1953
|
+
if (start === -1)
|
|
1954
|
+
return String(text || '');
|
|
1955
|
+
let end = lines.length;
|
|
1956
|
+
for (let i = start + 1; i < lines.length; i += 1) {
|
|
1957
|
+
const ln = lines[i];
|
|
1958
|
+
if (ln !== undefined && /^\s*\[.+\]\s*$/.test(ln)) {
|
|
1959
|
+
end = i;
|
|
1960
|
+
break;
|
|
1961
|
+
}
|
|
1962
|
+
}
|
|
1963
|
+
return lines.filter((_, index) => index < start || index >= end).join('\n').replace(/^\n+/, '').replace(/\n{3,}/g, '\n\n');
|
|
1964
|
+
}
|
|
1967
1965
|
function removeLegacyTopLevelCodexModeLocks(text = '') {
|
|
1968
1966
|
const lines = String(text || '').split('\n');
|
|
1969
1967
|
const firstTable = lines.findIndex((x) => /^\s*\[.+\]\s*$/.test(x));
|
|
1970
1968
|
const end = firstTable === -1 ? lines.length : firstTable;
|
|
1971
1969
|
const topLevelModel = topLevelTomlString(text, 'model');
|
|
1972
|
-
|
|
1970
|
+
// Recognize both the current default stamp and the legacy gpt-5.5 stamp older
|
|
1971
|
+
// SKS versions wrote, so upgrades keep cleaning locks written before the 5.6 bump.
|
|
1972
|
+
const removeSksOwnedModeLock = topLevelModel === REQUIRED_CODEX_MODEL || topLevelModel === GPT55_CODEX_MODEL;
|
|
1973
1973
|
return lines.filter((line, index) => {
|
|
1974
1974
|
if (index >= end)
|
|
1975
1975
|
return true;
|
|
@@ -2134,31 +2134,29 @@ async function backupCodexConfig(configPath, text, tag) {
|
|
|
2134
2134
|
// - refuse to WRITE a result that would not parse (e.g. a regex helper mangled a multiline
|
|
2135
2135
|
// string), leaving the existing config untouched,
|
|
2136
2136
|
// - otherwise back up the prior config before mutating.
|
|
2137
|
-
export async function safeWriteCodexConfigToml(configPath, current, next, tag = 'codex-lb') {
|
|
2137
|
+
export async function safeWriteCodexConfigToml(configPath, current, next, tag = 'codex-lb', opts = {}) {
|
|
2138
2138
|
return writeCodexConfigGuarded({
|
|
2139
2139
|
configPath,
|
|
2140
2140
|
before: String(current || ''),
|
|
2141
2141
|
cause: tag,
|
|
2142
2142
|
removeTopLevelModeLocks: true,
|
|
2143
|
+
...(opts.preserveFastUiKeys === undefined ? {} : { preserveFastUiKeys: opts.preserveFastUiKeys }),
|
|
2143
2144
|
mutate: () => String(next || '')
|
|
2144
2145
|
});
|
|
2145
2146
|
}
|
|
2146
2147
|
export function codexFastModeDesktopStatus(text = '') {
|
|
2147
2148
|
const validation = validateCodexConfigRoundTrip(String(text || ''));
|
|
2148
|
-
|
|
2149
|
-
|
|
2150
|
-
|
|
2151
|
-
|
|
2152
|
-
&& profile?.service_tier === 'fast';
|
|
2149
|
+
// Post-renewal contract: the fast default is the plain top-level
|
|
2150
|
+
// service_tier = "fast". default_profile/[profiles.*]/[user.fast_mode] are
|
|
2151
|
+
// gone from the Codex config schema and are only reported as legacy_keys.
|
|
2152
|
+
const globalOn = validation.ok && validation.service_tier === 'fast';
|
|
2153
2153
|
return {
|
|
2154
|
-
schema: 'sks.codex-fast-mode-desktop-status.
|
|
2154
|
+
schema: 'sks.codex-fast-mode-desktop-status.v2',
|
|
2155
2155
|
ok: validation.ok,
|
|
2156
2156
|
on: Boolean(globalOn),
|
|
2157
|
-
|
|
2158
|
-
|
|
2159
|
-
|
|
2160
|
-
profile_model: profile?.model || null,
|
|
2161
|
-
profile_service_tier: profile?.service_tier || null,
|
|
2157
|
+
service_tier: validation.service_tier ?? null,
|
|
2158
|
+
model: validation.model ?? null,
|
|
2159
|
+
legacy_keys: validation.legacy_keys,
|
|
2162
2160
|
validation
|
|
2163
2161
|
};
|
|
2164
2162
|
}
|
|
@@ -3397,8 +3395,14 @@ export async function selftestCodexLb(tmp) {
|
|
|
3397
3395
|
});
|
|
3398
3396
|
if (brokenChain.ok || brokenChain.status !== 'previous_response_not_found' || brokenChain.chain_unhealthy !== true)
|
|
3399
3397
|
throw new Error('selftest: codex-lb response chain health check did not detect previous_response_not_found');
|
|
3400
|
-
|
|
3401
|
-
|
|
3398
|
+
// 2026-07 renewal contract: only documented [features] flags remain; the flags,
|
|
3399
|
+
// [user.fast_mode], [profiles.sks-fast-high], and notice.fast_default_opt_out SKS
|
|
3400
|
+
// used to write must be STRIPPED by setup. User-authored tables ([profiles.custom])
|
|
3401
|
+
// are preserved untouched even though the schema dropped profile tables.
|
|
3402
|
+
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'];
|
|
3403
|
+
const survivingLegacy = legacyStamps.filter((stamp) => codexLbConfig.includes(stamp));
|
|
3404
|
+
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))
|
|
3405
|
+
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
3406
|
if (!hasCodexUnstableFeatureWarningSuppression(codexLbConfig))
|
|
3403
3407
|
throw new Error('selftest: codex-lb setup did not suppress Codex unstable feature warning');
|
|
3404
3408
|
const codexLbLaunch = `source ${path.join(tmp, '.codex', 'sks-codex-lb.env')} && codex '--model' '${REQUIRED_CODEX_MODEL}'`;
|
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) }))
|