sneakoscope 4.7.0 → 4.7.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/dist/cli/install-helpers.js +7 -9
- package/dist/commands/doctor.js +1 -1
- package/dist/core/codex-app/codex-app-fast-ui-repair.js +4 -2
- package/dist/core/codex-app/codex-app-ui-state-snapshot.js +14 -3
- package/dist/core/codex-app.js +2 -0
- package/dist/core/init.js +4 -7
- package/dist/scripts/doctor-fixes-codex-app-fast-ui-check.js +6 -2
- package/package.json +1 -1
|
@@ -1666,14 +1666,12 @@ export function normalizeCodexFastModeUiConfig(text = '', opts = {}) {
|
|
|
1666
1666
|
return normalizeCodexFastModeUiConfigOnce(normalizeCodexFastModeUiConfigOnce(text, opts), opts);
|
|
1667
1667
|
}
|
|
1668
1668
|
function normalizeCodexFastModeUiConfigOnce(text = '', opts = {}) {
|
|
1669
|
-
//
|
|
1670
|
-
//
|
|
1671
|
-
// user's own reasoning effort. SKS continues to manage its own namespaced tables below
|
|
1672
|
-
// ([features], [profiles.sks-*], [user.fast_mode], [plugins]).
|
|
1669
|
+
// Keep model and reasoning selection out of top-level config so Codex Desktop can
|
|
1670
|
+
// expose its native model/speed selectors. SKS-owned defaults live in profiles below.
|
|
1673
1671
|
let next = String(text || '');
|
|
1672
|
+
next = removeLegacyTopLevelCodexModeLocks(next);
|
|
1674
1673
|
next = removeTomlTableKey(next, 'notice', 'fast_default_opt_out');
|
|
1675
1674
|
next = removeTomlTableKey(next, 'features', 'codex_hooks');
|
|
1676
|
-
next = upsertTopLevelTomlStringIfAbsent(next, 'model', 'gpt-5.5');
|
|
1677
1675
|
if (opts.forceFastMode === true) {
|
|
1678
1676
|
next = upsertTopLevelTomlString(next, 'service_tier', 'fast');
|
|
1679
1677
|
}
|
|
@@ -1739,7 +1737,7 @@ function removeLegacyTopLevelCodexModeLocks(text = '') {
|
|
|
1739
1737
|
return lines.filter((line, index) => {
|
|
1740
1738
|
if (index >= end)
|
|
1741
1739
|
return true;
|
|
1742
|
-
return !/^\s*model_reasoning_effort\s*=/.test(line);
|
|
1740
|
+
return !/^\s*(?:model|model_reasoning_effort)\s*=/.test(line);
|
|
1743
1741
|
}).join('\n').replace(/^\n+/, '').replace(/\n{3,}/g, '\n\n');
|
|
1744
1742
|
}
|
|
1745
1743
|
function removeTopLevelTomlKeyIfValue(text = '', key = '', value = '') {
|
|
@@ -3118,8 +3116,8 @@ export async function selftestCodexLb(tmp) {
|
|
|
3118
3116
|
});
|
|
3119
3117
|
if (brokenChain.ok || brokenChain.status !== 'previous_response_not_found' || brokenChain.chain_unhealthy !== true)
|
|
3120
3118
|
throw new Error('selftest: codex-lb response chain health check did not detect previous_response_not_found');
|
|
3121
|
-
if (
|
|
3122
|
-
throw new Error('selftest: codex-lb setup did not preserve Codex App feature flags, default plugins, profile-scoped reasoning effort, explicit Fast profile, Codex Git commit generation,
|
|
3119
|
+
if (!codexLbConfig.includes('hooks = true') || hasDeprecatedCodexHooksFeatureFlag(codexLbConfig) || !codexLbConfig.includes('remote_control = true') || !codexLbConfig.includes('multi_agent = true') || !codexLbConfig.includes('fast_mode = true') || !codexLbConfig.includes('fast_mode_ui = true') || !codexLbConfig.includes('codex_git_commit = true') || !codexLbConfig.includes('computer_use = true') || !codexLbConfig.includes('browser_use = true') || !codexLbConfig.includes('browser_use_external = true') || !codexLbConfig.includes('guardian_approval = true') || !codexLbConfig.includes('tool_suggest = true') || !codexLbConfig.includes('apps = true') || !codexLbConfig.includes('plugins = true') || !codexLbConfig.includes('[plugins."latex@openai-bundled"]') || !codexLbConfig.includes('[plugins."documents@openai-primary-runtime"]') || !codexLbConfig.includes('[user.fast_mode]') || !codexLbConfig.includes('visible = true') || !codexLbConfig.includes('enabled = true') || !/\[profiles\.custom\][\s\S]*?model_reasoning_effort = "low"/.test(codexLbConfig) || !/\[profiles\.sks-fast-high\][\s\S]*?service_tier = "fast"/.test(codexLbConfig) || codexLbConfig.includes('fast_default_opt_out = true') || hasTopLevelCodexModeLock(codexLbConfig))
|
|
3120
|
+
throw new Error('selftest: codex-lb setup did not preserve Codex App feature flags, default plugins, profile-scoped reasoning effort, explicit Fast profile, Codex Git commit generation, or migrate the hooks feature flag');
|
|
3123
3121
|
if (!hasCodexUnstableFeatureWarningSuppression(codexLbConfig))
|
|
3124
3122
|
throw new Error('selftest: codex-lb setup did not suppress Codex unstable feature warning');
|
|
3125
3123
|
const codexLbLaunch = `source ${path.join(tmp, '.codex', 'sks-codex-lb.env')} && codex '--model' 'gpt-5.5'`;
|
|
@@ -3135,7 +3133,7 @@ function hasTopLevelCodexModeLock(text = '') {
|
|
|
3135
3133
|
const lines = String(text || '').split('\n');
|
|
3136
3134
|
const firstTable = lines.findIndex((x) => /^\s*\[.+\]\s*$/.test(x));
|
|
3137
3135
|
const top = (firstTable === -1 ? lines : lines.slice(0, firstTable)).join('\n');
|
|
3138
|
-
return /(^|\n)\s*model_reasoning_effort\s*=/.test(top);
|
|
3136
|
+
return /(^|\n)\s*(?:model|model_reasoning_effort)\s*=/.test(top);
|
|
3139
3137
|
}
|
|
3140
3138
|
function hasDeprecatedCodexHooksFeatureFlag(text = '') {
|
|
3141
3139
|
const lines = String(text || '').split('\n');
|
package/dist/commands/doctor.js
CHANGED
|
@@ -56,7 +56,7 @@ async function runDoctor(args = [], root, doctorFix) {
|
|
|
56
56
|
const actualCodexProbeRequested = flag(args, '--actual-codex') || flag(args, '--require-actual-codex') || Boolean(codexBin);
|
|
57
57
|
const actualCodexProbeEnabled = deepDiagnostics || actualCodexProbeRequested;
|
|
58
58
|
const requireActualCodexProbe = flag(args, '--require-actual-codex') || (deepDiagnostics && doctorFix);
|
|
59
|
-
const shouldEvaluateCodexAppUiRepair = deepDiagnostics || flag(args, '--repair-codex-app-ui');
|
|
59
|
+
const shouldEvaluateCodexAppUiRepair = doctorFix || deepDiagnostics || flag(args, '--repair-codex-app-ui');
|
|
60
60
|
const shouldRunZellijRepair = deepDiagnostics || flag(args, '--repair-zellij') || flag(args, '--install-homebrew') || process.env.SKS_REQUIRE_ZELLIJ === '1';
|
|
61
61
|
const nativeCapabilityDiagnosticsRequested = deepDiagnostics || flag(args, '--repair-native-capabilities');
|
|
62
62
|
const doctorPhaseIds = doctorPhaseIdsForProfile(doctorProfile);
|
|
@@ -4,7 +4,8 @@ import { ensureDir, nowIso, readText, sha256, writeJsonAtomic, writeTextAtomic }
|
|
|
4
4
|
import { codexHome, scanProjectLocalForbiddenKeys, snapshotCodexAppUiState } from './codex-app-ui-state-snapshot.js';
|
|
5
5
|
import { assertCodexAppUiMutationAllowed } from './codex-app-ui-clobber-guard.js';
|
|
6
6
|
export const CODEX_APP_FAST_UI_REPAIR_SCHEMA = 'sks.codex-app-fast-ui-repair.v1';
|
|
7
|
-
const FAST_UI_TOP_LEVEL_RE = /^\s*service_tier\s*=/;
|
|
7
|
+
const FAST_UI_TOP_LEVEL_RE = /^\s*(?:model|model_reasoning_effort|service_tier)\s*=/;
|
|
8
|
+
const CODEX_APP_MODE_LOCK_TOP_LEVEL_RE = /^\s*(?:model|model_reasoning_effort)\s*=/;
|
|
8
9
|
const FAST_UI_FEATURE_LINE_RE = /^\s*fast_mode\s*=/;
|
|
9
10
|
const FAST_UI_USER_TABLE_LINE_RE = /^\s*(enabled|visible|locked|hidden|disabled)\s*=/;
|
|
10
11
|
const SKS_CAUSED_RE = /(?:SKS|Sneakoscope|codex-lb|sks-mad|sks fast)/i;
|
|
@@ -125,10 +126,11 @@ function stripProjectLocalForbiddenKeys(text) {
|
|
|
125
126
|
}
|
|
126
127
|
function stripSksCausedHostOwnedLines(text) {
|
|
127
128
|
return stripMatchingLines(text, (line, table, previous, next) => {
|
|
129
|
+
const isCodexAppModeLock = !table && CODEX_APP_MODE_LOCK_TOP_LEVEL_RE.test(line);
|
|
128
130
|
const isFastUiLine = FAST_UI_TOP_LEVEL_RE.test(line)
|
|
129
131
|
|| (table === 'features' && FAST_UI_FEATURE_LINE_RE.test(line))
|
|
130
132
|
|| (table === 'user.fast_mode' && FAST_UI_USER_TABLE_LINE_RE.test(line));
|
|
131
|
-
return isFastUiLine && (SKS_CAUSED_RE.test(line) || SKS_CAUSED_RE.test(previous) || SKS_CAUSED_RE.test(next));
|
|
133
|
+
return isCodexAppModeLock || (isFastUiLine && (SKS_CAUSED_RE.test(line) || SKS_CAUSED_RE.test(previous) || SKS_CAUSED_RE.test(next)));
|
|
132
134
|
});
|
|
133
135
|
}
|
|
134
136
|
function stripMatchingLines(text, shouldRemove) {
|
|
@@ -4,6 +4,8 @@ import path from 'node:path';
|
|
|
4
4
|
import { exists, nowIso, readText, sha256, writeJsonAtomic } from '../fsx.js';
|
|
5
5
|
export const CODEX_APP_UI_STATE_SNAPSHOT_SCHEMA = 'sks.codex-app-ui-state-snapshot.v1';
|
|
6
6
|
export const PROJECT_LOCAL_FORBIDDEN_CODEX_KEYS = [
|
|
7
|
+
'model',
|
|
8
|
+
'model_reasoning_effort',
|
|
7
9
|
'openai_base_url',
|
|
8
10
|
'chatgpt_base_url',
|
|
9
11
|
'apps_mcp_product_sku',
|
|
@@ -15,7 +17,7 @@ export const PROJECT_LOCAL_FORBIDDEN_CODEX_KEYS = [
|
|
|
15
17
|
'experimental_realtime_ws_base_url',
|
|
16
18
|
'otel'
|
|
17
19
|
];
|
|
18
|
-
const HOST_OWNED_KEY_RE = /^(?:openai_base_url|chatgpt_base_url|apps_mcp_product_sku|model_provider|model_providers(?:\.|$)|notify|profile|profiles(?:\.|$)|experimental_realtime_ws_base_url|otel(?:\.|$)|features\.fast_mode|service_tier|user\.fast_mode(?:\.|$))/;
|
|
20
|
+
const HOST_OWNED_KEY_RE = /^(?:model|model_reasoning_effort|openai_base_url|chatgpt_base_url|apps_mcp_product_sku|model_provider|model_providers(?:\.|$)|notify|profile|profiles(?:\.|$)|experimental_realtime_ws_base_url|otel(?:\.|$)|features\.fast_mode|service_tier|user\.fast_mode(?:\.|$))/;
|
|
19
21
|
const SECRET_KEY_RE = /(?:key|token|secret|password|credential|cookie|authorization|bearer|refresh|access)/i;
|
|
20
22
|
export function codexHome(input) {
|
|
21
23
|
return path.resolve(String(input?.codexHome || process.env.CODEX_HOME || path.join(os.homedir(), '.codex')));
|
|
@@ -35,11 +37,16 @@ export async function snapshotCodexAppUiState(root = process.cwd(), input = {})
|
|
|
35
37
|
const providerSignals = hostOwnedSignals
|
|
36
38
|
.filter((signal) => signal.provider_related)
|
|
37
39
|
.map((signal) => `${signal.key_path}=${signal.value_preview}`);
|
|
38
|
-
const
|
|
40
|
+
const baseConfigHostOwnedSignals = files
|
|
41
|
+
.filter((file) => !isProfileConfigSnapshotPath(file.path))
|
|
42
|
+
.flatMap((file) => file.signals.filter((signal) => signal.host_owned));
|
|
43
|
+
const fastSelectorLocked = baseConfigHostOwnedSignals.some((signal) => {
|
|
39
44
|
if (signal.key_path === 'features.fast_mode' && signal.value_preview === 'false')
|
|
40
45
|
return true;
|
|
41
46
|
if (signal.key_path.startsWith('user.fast_mode') && /hidden|fixed|disabled|false/i.test(signal.value_preview))
|
|
42
47
|
return true;
|
|
48
|
+
if (signal.key_path === 'model' || signal.key_path === 'model_reasoning_effort')
|
|
49
|
+
return true;
|
|
43
50
|
if (signal.key_path === 'service_tier' && signal.sks_related)
|
|
44
51
|
return true;
|
|
45
52
|
return false;
|
|
@@ -120,7 +127,7 @@ export function scanTomlSignals(text) {
|
|
|
120
127
|
value_hash: sha256(value),
|
|
121
128
|
line: index + 1,
|
|
122
129
|
host_owned: HOST_OWNED_KEY_RE.test(keyPath),
|
|
123
|
-
fast_ui_related: /(?:fast_mode|service_tier)/i.test(keyPath) || /(?:fast|priority|default)/i.test(value),
|
|
130
|
+
fast_ui_related: /(?:fast_mode|service_tier|model_reasoning_effort|^model$)/i.test(keyPath) || /(?:fast|priority|default)/i.test(value),
|
|
124
131
|
provider_related: /(?:provider|base_url|auth|profile|openai|chatgpt|codex-lb)/i.test(lowerPath),
|
|
125
132
|
sks_related: /(?:sks|sneakoscope|codex-lb)/i.test(lineText)
|
|
126
133
|
});
|
|
@@ -176,6 +183,10 @@ async function profileConfigFiles(home) {
|
|
|
176
183
|
return [];
|
|
177
184
|
}
|
|
178
185
|
}
|
|
186
|
+
function isProfileConfigSnapshotPath(file) {
|
|
187
|
+
const base = path.basename(file);
|
|
188
|
+
return /^profile-.+\.config\.toml$/.test(base) || /^[A-Za-z0-9_-]+\.config\.toml$/.test(base);
|
|
189
|
+
}
|
|
179
190
|
async function readAuthMetadata(file) {
|
|
180
191
|
const text = await readText(file, null);
|
|
181
192
|
if (text == null)
|
package/dist/core/codex-app.js
CHANGED
|
@@ -798,6 +798,8 @@ async function codexFastModeConfigStatus(opts = {}) {
|
|
|
798
798
|
if (!config.text)
|
|
799
799
|
continue;
|
|
800
800
|
const topLevel = topLevelToml(config.text);
|
|
801
|
+
if (/(^|\n)\s*model\s*=/.test(topLevel))
|
|
802
|
+
blockers.push(`${config.scope}:top_level_model`);
|
|
801
803
|
if (/(^|\n)\s*model_reasoning_effort\s*=/.test(topLevel))
|
|
802
804
|
blockers.push(`${config.scope}:top_level_model_reasoning_effort`);
|
|
803
805
|
if (/(^|\n)\s*fast_default_opt_out\s*=\s*true\s*(?:#.*)?(?=\n|$)/.test(tomlTable(config.text, 'notice')))
|
package/dist/core/init.js
CHANGED
|
@@ -69,8 +69,7 @@ export function hasTopLevelCodexModeLock(text = '') {
|
|
|
69
69
|
const lines = String(text || '').split('\n');
|
|
70
70
|
const firstTable = lines.findIndex((x) => /^\s*\[.+\]\s*$/.test(x));
|
|
71
71
|
const top = (firstTable === -1 ? lines : lines.slice(0, firstTable)).join('\n');
|
|
72
|
-
|
|
73
|
-
return (Boolean(model) && model !== 'gpt-5.5') || /^model_reasoning_effort\s*=/m.test(top);
|
|
72
|
+
return /^model\s*=/.test(top) || /^model_reasoning_effort\s*=/m.test(top);
|
|
74
73
|
}
|
|
75
74
|
export function hasDeprecatedCodexHooksFeatureFlag(text = '') {
|
|
76
75
|
const lines = String(text || '').split('\n');
|
|
@@ -590,10 +589,8 @@ export async function initProject(root, opts = {}) {
|
|
|
590
589
|
let next = removeLegacyTopLevelCodexModeLocks(String(existingContent || '').trimEnd());
|
|
591
590
|
next = removeTomlTableKey(next, 'notice', 'fast_default_opt_out');
|
|
592
591
|
next = removeTomlTableKey(next, 'features', 'codex_hooks');
|
|
593
|
-
//
|
|
594
|
-
//
|
|
595
|
-
// is intentionally left untouched at the top level.
|
|
596
|
-
next = upsertTopLevelTomlStringIfAbsent(next, 'model', 'gpt-5.5');
|
|
592
|
+
// Model/reasoning defaults live in profiles. Leaving them out of top-level config
|
|
593
|
+
// keeps Codex Desktop's native model and speed selectors available.
|
|
597
594
|
next = upsertTopLevelTomlBooleanIfAbsent(next, 'suppress_unstable_features_warning', true);
|
|
598
595
|
// Codex App feature flags: SET-IF-ABSENT only (see note above).
|
|
599
596
|
for (const flag of MANAGED_CODEX_FEATURE_FLAGS) {
|
|
@@ -704,7 +701,7 @@ export async function initProject(root, opts = {}) {
|
|
|
704
701
|
return lines.filter((line, index) => {
|
|
705
702
|
if (index >= end)
|
|
706
703
|
return true;
|
|
707
|
-
return !/^\s*model_reasoning_effort\s*=/.test(line);
|
|
704
|
+
return !/^\s*(?:model|model_reasoning_effort)\s*=/.test(line);
|
|
708
705
|
}).join('\n').replace(/^\n+/, '').replace(/\n{3,}/g, '\n\n');
|
|
709
706
|
}
|
|
710
707
|
function removeTopLevelTomlKeyIfValue(text = '', key = '', value = '') {
|
|
@@ -7,8 +7,8 @@ const root = await fs.mkdtemp(path.join(os.tmpdir(), 'sks-doctor-fast-ui-'));
|
|
|
7
7
|
const codexHome = path.join(root, 'home', '.codex');
|
|
8
8
|
await fs.mkdir(path.join(root, '.codex'), { recursive: true });
|
|
9
9
|
await fs.mkdir(codexHome, { recursive: true });
|
|
10
|
-
await fs.writeFile(path.join(root, '.codex', 'config.toml'), '
|
|
11
|
-
await fs.writeFile(path.join(codexHome, 'config.toml'), '# SKS forced fast UI during legacy install\nmodel_provider = "codex-lb"\nservice_tier = "fast"\n[features]\nfast_mode = false # user disabled, must remain untouched\n\n[profiles.sks-fast-high]\nmodel = "gpt-5.5"\nservice_tier = "fast"\n\n[model_providers.codex-lb]\nname = "OpenAI"\nbase_url = "https://lb.example.test/backend-api/codex"\nwire_api = "responses"\nenv_key = "CODEX_LB_API_KEY"\nsupports_websockets = true\nrequires_openai_auth = false\n');
|
|
10
|
+
await fs.writeFile(path.join(root, '.codex', 'config.toml'), 'model = "gpt-5.5"\nmodel_reasoning_effort = "medium"\nmodel_provider = "codex-lb"\n');
|
|
11
|
+
await fs.writeFile(path.join(codexHome, 'config.toml'), '# SKS forced fast UI during legacy install\nmodel = "z-ai/glm-5.2"\nmodel_reasoning_effort = "xhigh"\nmodel_provider = "codex-lb"\nservice_tier = "fast"\n[features]\nfast_mode = false # user disabled, must remain untouched\n\n[profiles.sks-fast-high]\nmodel = "gpt-5.5"\nservice_tier = "fast"\n\n[model_providers.codex-lb]\nname = "OpenAI"\nbase_url = "https://lb.example.test/backend-api/codex"\nwire_api = "responses"\nenv_key = "CODEX_LB_API_KEY"\nsupports_websockets = true\nrequires_openai_auth = false\n');
|
|
12
12
|
const plan = await repairCodexAppFastUi(root, { codexHome, apply: false });
|
|
13
13
|
const repaired = await repairCodexAppFastUi(root, { codexHome, apply: true });
|
|
14
14
|
const projectAfter = await fs.readFile(path.join(root, '.codex', 'config.toml'), 'utf8');
|
|
@@ -26,6 +26,10 @@ const ok = plan.fast_selector === 'manual_action_required'
|
|
|
26
26
|
&& repaired.fast_selector === 'repaired'
|
|
27
27
|
&& repaired.safe_auto_apply === true
|
|
28
28
|
&& backups.length >= 2
|
|
29
|
+
&& !/^model\s*=/m.test(projectAfter.split(/\n\s*\[/)[0] || '')
|
|
30
|
+
&& !/^model_reasoning_effort\s*=/m.test(projectAfter.split(/\n\s*\[/)[0] || '')
|
|
31
|
+
&& !/^model\s*=/m.test(homeTopLevel)
|
|
32
|
+
&& !/^model_reasoning_effort\s*=/m.test(homeTopLevel)
|
|
29
33
|
&& !/model_provider\s*=/.test(projectAfter)
|
|
30
34
|
&& !/service_tier\s*=/.test(homeTopLevel)
|
|
31
35
|
&& /fast_mode = false/.test(homeAfter)
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "sneakoscope",
|
|
3
3
|
"displayName": "ㅅㅋㅅ",
|
|
4
|
-
"version": "4.7.
|
|
4
|
+
"version": "4.7.1",
|
|
5
5
|
"description": "Sneakoscope Codex: fast proof-first Codex trust layer with image-based Voxel TriWiki.",
|
|
6
6
|
"type": "module",
|
|
7
7
|
"homepage": "https://github.com/mandarange/Sneakoscope-Codex#readme",
|