sneakoscope 5.6.1 → 5.7.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/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/sks.js +1 -1
- package/dist/cli/command-registry.js +1 -1
- package/dist/cli/install-helpers.js +21 -15
- package/dist/commands/doctor.js +44 -22
- package/dist/config/skills-manifest.json +58 -58
- package/dist/core/codex/agent-config-file-repair.js +2 -1
- package/dist/core/codex/codex-config-guard.js +10 -0
- package/dist/core/codex-app/sks-menubar.js +66 -19
- package/dist/core/commands/run-command.js +5 -1
- package/dist/core/fsx.js +1 -1
- package/dist/core/update/update-migration-state.js +178 -33
- package/dist/core/version.js +1 -1
- package/dist/scripts/codex-lb-gpt55-fast-profile-check.js +3 -2
- package/dist/scripts/packlist-performance-check.js +4 -2
- package/dist/scripts/release-metadata-1-19-check.js +12 -1
- package/dist/scripts/sks-menubar-install-check.js +83 -0
- package/package.json +14 -5
|
@@ -15,6 +15,8 @@ const MENU_ITEMS = [
|
|
|
15
15
|
'Use ChatGPT OAuth',
|
|
16
16
|
'Set codex-lb Domain and Key',
|
|
17
17
|
'Set OpenRouter Key and GLM Profiles',
|
|
18
|
+
'Fast Mode On',
|
|
19
|
+
'Fast Mode Off',
|
|
18
20
|
'Fast Check',
|
|
19
21
|
'SKS Version Check',
|
|
20
22
|
'Update SKS Now',
|
|
@@ -63,6 +65,7 @@ export async function installSksMenuBar(opts = {}) {
|
|
|
63
65
|
const nextActions = defaultNextActions();
|
|
64
66
|
let secretEnvCleanup;
|
|
65
67
|
let codexBundleId = null;
|
|
68
|
+
let lastTargetCheck;
|
|
66
69
|
if (process.platform !== 'darwin') {
|
|
67
70
|
const result = {
|
|
68
71
|
schema: 'sks.codex-app-sks-menubar.v1',
|
|
@@ -170,15 +173,11 @@ export async function installSksMenuBar(opts = {}) {
|
|
|
170
173
|
actionScriptPath: paths.action_script_path,
|
|
171
174
|
warnings
|
|
172
175
|
});
|
|
173
|
-
|
|
174
|
-
if (!target.exists
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
}
|
|
179
|
-
const actionScript = target.used_previous_script
|
|
180
|
-
? previousActionScript
|
|
181
|
-
: actionScriptSource({ nodeBin: process.execPath, sksEntry: target.resolved || target.packaged });
|
|
176
|
+
lastTargetCheck = target;
|
|
177
|
+
if (!target.exists) {
|
|
178
|
+
return await blockedResult('sks_entry_unresolved', `Resolved SKS entry does not exist: ${target.requested || target.resolved || target.packaged}`);
|
|
179
|
+
}
|
|
180
|
+
const actionScript = actionScriptSource({ nodeBin: process.execPath, sksEntry: target.resolved || target.packaged });
|
|
182
181
|
const swiftSource = swiftMenuSource({
|
|
183
182
|
actionScriptPath: paths.action_script_path,
|
|
184
183
|
buildStampPath: paths.build_stamp_path,
|
|
@@ -201,7 +200,9 @@ export async function installSksMenuBar(opts = {}) {
|
|
|
201
200
|
};
|
|
202
201
|
const previousStamp = await readJson(paths.build_stamp_path, null);
|
|
203
202
|
const appInstalled = await exists(paths.executable_path);
|
|
204
|
-
const
|
|
203
|
+
const currentActionScript = await readText(paths.action_script_path, '');
|
|
204
|
+
const actionScriptCurrent = currentActionScript === actionScript;
|
|
205
|
+
const stampMatches = appInstalled && buildStampEquals(previousStamp, stamp) && actionScriptCurrent;
|
|
205
206
|
const binaryStable = appInstalled
|
|
206
207
|
&& previousStamp?.schema === stamp.schema
|
|
207
208
|
&& previousStamp.package_version === stamp.package_version
|
|
@@ -213,7 +214,7 @@ export async function installSksMenuBar(opts = {}) {
|
|
|
213
214
|
actions.push('menubar_up_to_date');
|
|
214
215
|
}
|
|
215
216
|
else {
|
|
216
|
-
if (
|
|
217
|
+
if (currentActionScript !== actionScript) {
|
|
217
218
|
await writeTextAtomic(paths.action_script_path, actionScript);
|
|
218
219
|
actions.push(`wrote ${paths.action_script_path}`);
|
|
219
220
|
}
|
|
@@ -342,6 +343,7 @@ export async function installSksMenuBar(opts = {}) {
|
|
|
342
343
|
menu_items: MENU_ITEMS,
|
|
343
344
|
actions,
|
|
344
345
|
launch: { requested: false, method: 'none', ok: false, error: detail || reason },
|
|
346
|
+
target_check: lastTargetCheck,
|
|
345
347
|
build_stamp: null,
|
|
346
348
|
tcc_automation_status: 'unknown',
|
|
347
349
|
secret_env_cleanup: secretEnvCleanup,
|
|
@@ -394,7 +396,7 @@ async function writeDefaultMenuBarConfig(configPath, codexBundleId) {
|
|
|
394
396
|
const previous = await readMenuBarConfig(configPath);
|
|
395
397
|
const config = {
|
|
396
398
|
schema: 'sks.sks-menubar-config.v1',
|
|
397
|
-
codex_bundle_id: codexBundleId,
|
|
399
|
+
codex_bundle_id: codexBundleId || previous.codex_bundle_id,
|
|
398
400
|
quit_with_codex: previous.quit_with_codex === true
|
|
399
401
|
};
|
|
400
402
|
await writeJsonAtomic(configPath, config);
|
|
@@ -691,16 +693,15 @@ async function resolveSksEntryForInstall(input) {
|
|
|
691
693
|
if (projectLocal) {
|
|
692
694
|
input.warnings.push('sks_entry_project_local');
|
|
693
695
|
}
|
|
694
|
-
|
|
695
|
-
|
|
696
|
-
input.warnings.push('sks_entry_unresolved_kept_previous_script');
|
|
696
|
+
if (!existsResolved && await exists(input.actionScriptPath))
|
|
697
|
+
input.warnings.push('sks_entry_unresolved_stale_action_script_not_reused');
|
|
697
698
|
return {
|
|
698
699
|
requested: input.explicit ? path.resolve(input.explicit) : null,
|
|
699
700
|
resolved: existsResolved ? resolved : null,
|
|
700
701
|
packaged,
|
|
701
702
|
exists: existsResolved,
|
|
702
703
|
project_local: projectLocal,
|
|
703
|
-
used_previous_script:
|
|
704
|
+
used_previous_script: false
|
|
704
705
|
};
|
|
705
706
|
}
|
|
706
707
|
export function actionScriptSource(input) {
|
|
@@ -960,6 +961,11 @@ func promptChoice(title: String, message: String, options: [String]) -> String?
|
|
|
960
961
|
return popup.titleOfSelectedItem
|
|
961
962
|
}
|
|
962
963
|
|
|
964
|
+
func parseJsonObject(_ text: String) -> [String: Any]? {
|
|
965
|
+
guard let data = text.data(using: .utf8) else { return nil }
|
|
966
|
+
return (try? JSONSerialization.jsonObject(with: data, options: [])) as? [String: Any]
|
|
967
|
+
}
|
|
968
|
+
|
|
963
969
|
func runProcess(_ executable: String, _ args: [String] = [], stdinText: String? = nil, completion: ((Int32, String) -> Void)? = nil) {
|
|
964
970
|
let process = Process()
|
|
965
971
|
let output = Pipe()
|
|
@@ -1052,6 +1058,8 @@ final class AppDelegate: NSObject, NSApplicationDelegate, NSMenuDelegate {
|
|
|
1052
1058
|
var statusLineItem: NSMenuItem!
|
|
1053
1059
|
var codexLbItem: NSMenuItem!
|
|
1054
1060
|
var oauthItem: NSMenuItem!
|
|
1061
|
+
var fastModeOnItem: NSMenuItem!
|
|
1062
|
+
var fastModeOffItem: NSMenuItem!
|
|
1055
1063
|
var timer: Timer?
|
|
1056
1064
|
var busy = false
|
|
1057
1065
|
var lastFailure = false
|
|
@@ -1077,6 +1085,8 @@ final class AppDelegate: NSObject, NSApplicationDelegate, NSMenuDelegate {
|
|
|
1077
1085
|
add(menu, "Set codex-lb Domain and Key", #selector(setCodexLbDomainAndKey))
|
|
1078
1086
|
menu.addItem(NSMenuItem.separator())
|
|
1079
1087
|
add(menu, "Set OpenRouter Key and GLM Profiles", #selector(setOpenRouterKey))
|
|
1088
|
+
fastModeOnItem = add(menu, "Fast Mode On", #selector(fastModeOn))
|
|
1089
|
+
fastModeOffItem = add(menu, "Fast Mode Off", #selector(fastModeOff))
|
|
1080
1090
|
add(menu, "Fast Check", #selector(fastCheck))
|
|
1081
1091
|
add(menu, "SKS Version Check", #selector(sksVersionCheck))
|
|
1082
1092
|
add(menu, "Update SKS Now", #selector(updateSksNow))
|
|
@@ -1096,6 +1106,7 @@ final class AppDelegate: NSObject, NSApplicationDelegate, NSMenuDelegate {
|
|
|
1096
1106
|
func menuWillOpen(_ menu: NSMenu) {
|
|
1097
1107
|
updateState()
|
|
1098
1108
|
updateAuthModeChecks()
|
|
1109
|
+
updateFastModeChecks()
|
|
1099
1110
|
}
|
|
1100
1111
|
|
|
1101
1112
|
func configureStatusButton(_ button: NSStatusBarButton, title: String) {
|
|
@@ -1197,6 +1208,15 @@ ${codexLifecycleSource}
|
|
|
1197
1208
|
runSksCapture(args, title: title, stdinText: stdinText, notify: true, completion: completion)
|
|
1198
1209
|
}
|
|
1199
1210
|
|
|
1211
|
+
func runSksSilent(_ args: [String], completion: ((Int32, String) -> Void)? = nil) {
|
|
1212
|
+
runProcess(actionScript, args) { code, output in
|
|
1213
|
+
let redacted = redactSecrets(output)
|
|
1214
|
+
DispatchQueue.main.async {
|
|
1215
|
+
completion?(code, redacted)
|
|
1216
|
+
}
|
|
1217
|
+
}
|
|
1218
|
+
}
|
|
1219
|
+
|
|
1200
1220
|
func startSksDetached(_ args: [String], title: String) {
|
|
1201
1221
|
let process = Process()
|
|
1202
1222
|
process.executableURL = URL(fileURLWithPath: actionScript)
|
|
@@ -1215,15 +1235,30 @@ ${codexLifecycleSource}
|
|
|
1215
1235
|
}
|
|
1216
1236
|
|
|
1217
1237
|
func updateAuthModeChecks() {
|
|
1218
|
-
|
|
1238
|
+
runSksSilent(["codex-lb", "status", "--json"]) { [weak self] code, output in
|
|
1219
1239
|
guard let self = self else { return }
|
|
1220
|
-
let
|
|
1221
|
-
let
|
|
1240
|
+
let json = parseJsonObject(output)
|
|
1241
|
+
let selected = json?["selected"] as? Bool == true
|
|
1242
|
+
let provider = (json?["model_provider"] as? String)?.lowercased() == "codex-lb"
|
|
1243
|
+
let mode = (json?["mode"] as? String)?.lowercased() == "codex-lb"
|
|
1244
|
+
let codexLbActive = code == 0 && (selected || provider || mode)
|
|
1222
1245
|
self.codexLbItem.state = codexLbActive ? .on : .off
|
|
1223
1246
|
self.oauthItem.state = codexLbActive ? .off : .on
|
|
1224
1247
|
}
|
|
1225
1248
|
}
|
|
1226
1249
|
|
|
1250
|
+
func updateFastModeChecks() {
|
|
1251
|
+
runSksSilent(["fast-mode", "status", "--json"]) { [weak self] code, output in
|
|
1252
|
+
guard let self = self else { return }
|
|
1253
|
+
let json = parseJsonObject(output)
|
|
1254
|
+
let fastMode = json?["fast_mode"] as? Bool == true
|
|
1255
|
+
let serviceTier = (json?["service_tier"] as? String)?.lowercased()
|
|
1256
|
+
let fastActive = code == 0 && (fastMode || serviceTier == "fast" || serviceTier == "priority")
|
|
1257
|
+
self.fastModeOnItem.state = fastActive ? .on : .off
|
|
1258
|
+
self.fastModeOffItem.state = fastActive ? .off : .on
|
|
1259
|
+
}
|
|
1260
|
+
}
|
|
1261
|
+
|
|
1227
1262
|
@objc func useCodexLb() {
|
|
1228
1263
|
runSksBackground(["codex-lb", "use-codex-lb", "--json"], title: "Use codex-lb") { [weak self] code, _ in
|
|
1229
1264
|
if code == 0 { self?.updateAuthModeChecks() }
|
|
@@ -1249,6 +1284,18 @@ ${codexLifecycleSource}
|
|
|
1249
1284
|
runSksBackground(["codex-app", "set-openrouter-key", "--api-key-stdin", "--json"], title: "Set OpenRouter Key", stdinText: key + "\\n")
|
|
1250
1285
|
}
|
|
1251
1286
|
|
|
1287
|
+
@objc func fastModeOn() {
|
|
1288
|
+
runSksBackground(["fast-mode", "on", "--json"], title: "Fast Mode On") { [weak self] code, _ in
|
|
1289
|
+
if code == 0 { self?.updateFastModeChecks() }
|
|
1290
|
+
}
|
|
1291
|
+
}
|
|
1292
|
+
|
|
1293
|
+
@objc func fastModeOff() {
|
|
1294
|
+
runSksBackground(["fast-mode", "off", "--json"], title: "Fast Mode Off") { [weak self] code, _ in
|
|
1295
|
+
if code == 0 { self?.updateFastModeChecks() }
|
|
1296
|
+
}
|
|
1297
|
+
}
|
|
1298
|
+
|
|
1252
1299
|
@objc func fastCheck() {
|
|
1253
1300
|
runSksBackground(["codex-lb", "fast-check"], title: "SKS Fast Check")
|
|
1254
1301
|
}
|
|
@@ -256,14 +256,18 @@ async function executeRouteCommand(root, route, prompt, { auto = false } = {}) {
|
|
|
256
256
|
// that never saw the prompt cannot claim to have addressed it.
|
|
257
257
|
const isMockFallback = commandArgs.includes('--mock');
|
|
258
258
|
const promptDelivered = Boolean(prompt) && commandArgs.includes(prompt);
|
|
259
|
+
const deterministicRoute = isSafeDeterministicRoute(route.command);
|
|
259
260
|
const result = await runSks(root, commandArgs);
|
|
260
261
|
return routeExecutionResult(route, ['sks', ...commandArgs].join(' '), result, {
|
|
261
262
|
okStatus: isMockFallback ? 'verified_partial' : 'completed',
|
|
262
263
|
trustStatus: isMockFallback ? 'mock_only' : 'verified_partial',
|
|
263
|
-
executionKind: isMockFallback ? 'mock_safe' : 'live_route',
|
|
264
|
+
executionKind: isMockFallback ? 'mock_safe' : deterministicRoute ? 'safe_deterministic' : 'live_route',
|
|
264
265
|
promptDelivered,
|
|
265
266
|
});
|
|
266
267
|
}
|
|
268
|
+
function isSafeDeterministicRoute(command) {
|
|
269
|
+
return new Set(['$DB', '$Wiki', '$Fast-Mode', '$with-local-llm-on', '$Commit', '$Commit-And-Push']).has(command);
|
|
270
|
+
}
|
|
267
271
|
async function runAutoVerification(root, missionId) {
|
|
268
272
|
const trust = await runSks(root, ['trust', 'validate', missionId, '--json']);
|
|
269
273
|
const status = await runSks(root, ['status', '--json']);
|
package/dist/core/fsx.js
CHANGED
|
@@ -5,7 +5,7 @@ import os from 'node:os';
|
|
|
5
5
|
import crypto from 'node:crypto';
|
|
6
6
|
import { spawn } from 'node:child_process';
|
|
7
7
|
import { fileURLToPath } from 'node:url';
|
|
8
|
-
export const PACKAGE_VERSION = '5.
|
|
8
|
+
export const PACKAGE_VERSION = '5.7.0';
|
|
9
9
|
export const DEFAULT_PROCESS_TAIL_BYTES = 256 * 1024;
|
|
10
10
|
export const DEFAULT_PROCESS_TIMEOUT_MS = 30 * 60 * 1000;
|
|
11
11
|
export function nowIso() {
|
|
@@ -8,6 +8,7 @@ import { COMMANDS } from '../../cli/command-registry.js';
|
|
|
8
8
|
import { reconcileSkills } from '../init/skills.js';
|
|
9
9
|
import { codexHookTrustDoctor } from '../codex-hooks/codex-hook-trust-doctor.js';
|
|
10
10
|
import { writeCodexConfigGuarded } from '../codex/codex-config-guard.js';
|
|
11
|
+
import { REQUIRED_CODEX_MODEL } from '../codex-model-guard.js';
|
|
11
12
|
export const UPDATE_MIGRATION_SCHEMA = 'sks.project-migration-receipt.v2';
|
|
12
13
|
export const INSTALLATION_EPOCH_SCHEMA = 'sks.installation-epoch.v1';
|
|
13
14
|
export function installationEpochPath() {
|
|
@@ -343,53 +344,71 @@ async function runMenubarRetargetStage(root) {
|
|
|
343
344
|
return { ok: true, status: 'ok', actions: ['menubar_action_script_absent'], blockers: [], warnings: [] };
|
|
344
345
|
const desired = path.join(packageRoot(), 'dist', 'bin', 'sks.js');
|
|
345
346
|
const line = `SKS_ENTRY=${JSON.stringify(desired)}`;
|
|
347
|
+
const actions = [];
|
|
346
348
|
const next = /^\s*SKS_ENTRY\s*=.*$/m.test(text)
|
|
347
349
|
? text.replace(/^\s*SKS_ENTRY\s*=.*$/m, line)
|
|
348
350
|
: `${line}\n${text}`;
|
|
349
351
|
if (next !== text) {
|
|
350
352
|
await writeTextAtomic(actionScript, next);
|
|
351
|
-
|
|
353
|
+
actions.push('retargeted_menubar_action_script');
|
|
354
|
+
}
|
|
355
|
+
const stat = await fsp.stat(actionScript).catch(() => null);
|
|
356
|
+
if (!stat || (stat.mode & 0o111) === 0) {
|
|
357
|
+
await fsp.chmod(actionScript, 0o755);
|
|
358
|
+
actions.push('restored_menubar_action_executable_bit');
|
|
352
359
|
}
|
|
353
|
-
return {
|
|
360
|
+
return {
|
|
361
|
+
ok: true,
|
|
362
|
+
status: 'ok',
|
|
363
|
+
actions: actions.length ? actions : ['menubar_action_script_current'],
|
|
364
|
+
blockers: [],
|
|
365
|
+
warnings: [],
|
|
366
|
+
detail: { action_script: actionScript }
|
|
367
|
+
};
|
|
354
368
|
}
|
|
355
369
|
async function runConfigFastModeNormalizeStage() {
|
|
356
370
|
const configPath = path.join(os.homedir(), '.codex', 'config.toml');
|
|
357
371
|
const text = await readText(configPath, null);
|
|
358
372
|
if (typeof text !== 'string')
|
|
359
373
|
return { ok: true, status: 'ok', actions: ['codex_config_absent'], blockers: [], warnings: [] };
|
|
360
|
-
const
|
|
361
|
-
|
|
362
|
-
|
|
363
|
-
|
|
364
|
-
|
|
365
|
-
|
|
366
|
-
|
|
367
|
-
|
|
368
|
-
|
|
369
|
-
|
|
370
|
-
|
|
374
|
+
const normalized = normalizeLegacyFastModeConfigForUpdate(text);
|
|
375
|
+
if (normalized.text === ensureTrailingNewline(text)) {
|
|
376
|
+
return {
|
|
377
|
+
ok: true,
|
|
378
|
+
status: 'ok',
|
|
379
|
+
actions: ['fastmode_config_current'],
|
|
380
|
+
blockers: [],
|
|
381
|
+
warnings: [],
|
|
382
|
+
detail: { config_path: configPath, default_profile: normalized.defaultProfile }
|
|
383
|
+
};
|
|
384
|
+
}
|
|
371
385
|
let guardResult = null;
|
|
372
|
-
|
|
373
|
-
|
|
374
|
-
|
|
375
|
-
|
|
376
|
-
|
|
377
|
-
|
|
378
|
-
|
|
379
|
-
|
|
380
|
-
|
|
381
|
-
|
|
382
|
-
|
|
383
|
-
|
|
384
|
-
|
|
385
|
-
|
|
386
|
-
|
|
387
|
-
|
|
388
|
-
|
|
389
|
-
};
|
|
390
|
-
}
|
|
386
|
+
guardResult = await writeCodexConfigGuarded({
|
|
387
|
+
configPath,
|
|
388
|
+
before: text,
|
|
389
|
+
mutate: () => normalized.text,
|
|
390
|
+
cause: 'project-update-fastmode-normalize',
|
|
391
|
+
backupTag: 'project-update-fastmode-normalize',
|
|
392
|
+
preserveFastUiKeys: true
|
|
393
|
+
});
|
|
394
|
+
if (!guardResult.ok) {
|
|
395
|
+
return {
|
|
396
|
+
ok: false,
|
|
397
|
+
status: 'failed',
|
|
398
|
+
actions: ['normalize_fastmode_config_blocked'],
|
|
399
|
+
blockers: [`codex_config_guard:${guardResult.status}`],
|
|
400
|
+
warnings: [],
|
|
401
|
+
detail: { config_path: configPath, default_profile: normalized.defaultProfile, guard: guardResult }
|
|
402
|
+
};
|
|
391
403
|
}
|
|
392
|
-
return {
|
|
404
|
+
return {
|
|
405
|
+
ok: true,
|
|
406
|
+
status: 'ok',
|
|
407
|
+
actions: normalized.actions.length ? normalized.actions : ['fastmode_config_current'],
|
|
408
|
+
blockers: [],
|
|
409
|
+
warnings: [],
|
|
410
|
+
detail: { config_path: configPath, default_profile: normalized.defaultProfile, guard: guardResult }
|
|
411
|
+
};
|
|
393
412
|
}
|
|
394
413
|
async function runHookTrustRefreshStage(root) {
|
|
395
414
|
const result = await codexHookTrustDoctor(root, { fix: true, managed: true, actual: true });
|
|
@@ -456,6 +475,132 @@ function insertTopLevelTomlKey(text, line) {
|
|
|
456
475
|
return `${line}\n${raw}`.trim() + '\n';
|
|
457
476
|
return `${raw.slice(0, firstTable).trimEnd()}\n${line}\n\n${raw.slice(firstTable).trimStart()}`.trim() + '\n';
|
|
458
477
|
}
|
|
478
|
+
function normalizeLegacyFastModeConfigForUpdate(text) {
|
|
479
|
+
let next = String(text || '');
|
|
480
|
+
const actions = [];
|
|
481
|
+
const misplaced = tomlTableString(next, 'user.fast_mode', 'default_profile');
|
|
482
|
+
const topLevel = topLevelTomlString(next, 'default_profile');
|
|
483
|
+
if (misplaced) {
|
|
484
|
+
next = removeTomlTableKeyLocal(next, 'user.fast_mode', 'default_profile');
|
|
485
|
+
actions.push('normalized_fastmode_default_profile_location');
|
|
486
|
+
}
|
|
487
|
+
if (topLevel && topLevel !== 'sks-fast-high' && !tomlTableBlock(next, `profiles.${topLevel}`)) {
|
|
488
|
+
next = upsertTopLevelTomlStringLocal(next, 'default_profile', 'sks-fast-high');
|
|
489
|
+
actions.push('retargeted_missing_fastmode_default_profile_target');
|
|
490
|
+
}
|
|
491
|
+
else if (!topLevel && misplaced === 'sks-fast-high') {
|
|
492
|
+
next = insertTopLevelTomlKey(next, `default_profile = ${JSON.stringify(misplaced)}`);
|
|
493
|
+
actions.push('restored_fastmode_top_level_default_profile');
|
|
494
|
+
}
|
|
495
|
+
const beforeUi = next;
|
|
496
|
+
next = upsertTomlTableKeyIfAbsentLocal(next, 'user.fast_mode', 'visible = true');
|
|
497
|
+
next = upsertTomlTableKeyIfAbsentLocal(next, 'user.fast_mode', 'enabled = true');
|
|
498
|
+
if (next !== beforeUi)
|
|
499
|
+
actions.push('ensured_fastmode_ui_visibility');
|
|
500
|
+
const beforeProfile = next;
|
|
501
|
+
next = upsertTomlTableKeyLocal(next, 'profiles.sks-fast-high', `model = "${REQUIRED_CODEX_MODEL}"`);
|
|
502
|
+
next = upsertTomlTableKeyLocal(next, 'profiles.sks-fast-high', 'service_tier = "fast"');
|
|
503
|
+
if (next !== beforeProfile)
|
|
504
|
+
actions.push('normalized_sks_fast_high_profile');
|
|
505
|
+
return { text: ensureTrailingNewline(next), actions, defaultProfile: misplaced || topLevel };
|
|
506
|
+
}
|
|
507
|
+
function tomlTableString(text, table, key) {
|
|
508
|
+
const block = tomlTableBlock(text, table);
|
|
509
|
+
const match = block?.match(new RegExp(`^\\s*${escapeRegExp(key)}\\s*=\\s*"([^"]*)"\\s*$`, 'm'));
|
|
510
|
+
return match?.[1] || null;
|
|
511
|
+
}
|
|
512
|
+
function topLevelTomlString(text, key) {
|
|
513
|
+
const top = String(text || '').slice(0, Math.max(0, String(text || '').search(/^\s*\[/m)));
|
|
514
|
+
const match = top.match(new RegExp(`^\\s*${escapeRegExp(key)}\\s*=\\s*"([^"]*)"\\s*$`, 'm'));
|
|
515
|
+
return match?.[1] || null;
|
|
516
|
+
}
|
|
517
|
+
function tomlTableBlock(text, table) {
|
|
518
|
+
const lines = String(text || '').split(/\r?\n/);
|
|
519
|
+
const start = lines.findIndex((line) => tableHeaderMatches(line, table));
|
|
520
|
+
if (start < 0)
|
|
521
|
+
return null;
|
|
522
|
+
let end = lines.length;
|
|
523
|
+
for (let index = start + 1; index < lines.length; index += 1) {
|
|
524
|
+
if (/^\s*\[[^\]]+\]\s*$/.test(lines[index] || '')) {
|
|
525
|
+
end = index;
|
|
526
|
+
break;
|
|
527
|
+
}
|
|
528
|
+
}
|
|
529
|
+
return lines.slice(start, end).join('\n');
|
|
530
|
+
}
|
|
531
|
+
function removeTomlTableKeyLocal(text, table, key) {
|
|
532
|
+
const lines = String(text || '').split(/\r?\n/);
|
|
533
|
+
let inTable = false;
|
|
534
|
+
const out = [];
|
|
535
|
+
for (const line of lines) {
|
|
536
|
+
if (/^\s*\[[^\]]+\]\s*$/.test(line))
|
|
537
|
+
inTable = tableHeaderMatches(line, table);
|
|
538
|
+
if (inTable && new RegExp(`^\\s*${escapeRegExp(key)}\\s*=`).test(line))
|
|
539
|
+
continue;
|
|
540
|
+
out.push(line);
|
|
541
|
+
}
|
|
542
|
+
return out.join('\n');
|
|
543
|
+
}
|
|
544
|
+
function upsertTomlTableKeyIfAbsentLocal(text, table, line) {
|
|
545
|
+
const key = tomlLineKey(line);
|
|
546
|
+
return tomlTableHasKey(text, table, key) ? text : upsertTomlTableKeyLocal(text, table, line);
|
|
547
|
+
}
|
|
548
|
+
function upsertTomlTableKeyLocal(text, table, line) {
|
|
549
|
+
const raw = String(text || '').trimEnd();
|
|
550
|
+
const key = tomlLineKey(line);
|
|
551
|
+
const lines = raw ? raw.split(/\r?\n/) : [];
|
|
552
|
+
const start = lines.findIndex((candidate) => tableHeaderMatches(candidate, table));
|
|
553
|
+
if (start < 0) {
|
|
554
|
+
return `${raw}${raw ? '\n\n' : ''}[${table}]\n${line}\n`;
|
|
555
|
+
}
|
|
556
|
+
let end = lines.length;
|
|
557
|
+
for (let index = start + 1; index < lines.length; index += 1) {
|
|
558
|
+
if (/^\s*\[[^\]]+\]\s*$/.test(lines[index] || '')) {
|
|
559
|
+
end = index;
|
|
560
|
+
break;
|
|
561
|
+
}
|
|
562
|
+
}
|
|
563
|
+
for (let index = start + 1; index < end; index += 1) {
|
|
564
|
+
if (new RegExp(`^\\s*${escapeRegExp(key)}\\s*=`).test(lines[index] || '')) {
|
|
565
|
+
if (lines[index] === line)
|
|
566
|
+
return `${lines.join('\n')}\n`;
|
|
567
|
+
lines[index] = line;
|
|
568
|
+
return `${lines.join('\n')}\n`;
|
|
569
|
+
}
|
|
570
|
+
}
|
|
571
|
+
lines.splice(end, 0, line);
|
|
572
|
+
return `${lines.join('\n')}\n`;
|
|
573
|
+
}
|
|
574
|
+
function upsertTopLevelTomlStringLocal(text, key, value) {
|
|
575
|
+
const raw = String(text || '').trimEnd();
|
|
576
|
+
const line = `${key} = ${JSON.stringify(value)}`;
|
|
577
|
+
const lines = raw ? raw.split(/\r?\n/) : [];
|
|
578
|
+
const firstTable = lines.findIndex((candidate) => /^\s*\[[^\]]+\]\s*$/.test(candidate || ''));
|
|
579
|
+
const end = firstTable < 0 ? lines.length : firstTable;
|
|
580
|
+
for (let index = 0; index < end; index += 1) {
|
|
581
|
+
if (new RegExp(`^\\s*${escapeRegExp(key)}\\s*=`).test(lines[index] || '')) {
|
|
582
|
+
lines[index] = line;
|
|
583
|
+
return `${lines.join('\n')}\n`;
|
|
584
|
+
}
|
|
585
|
+
}
|
|
586
|
+
return insertTopLevelTomlKey(raw, line);
|
|
587
|
+
}
|
|
588
|
+
function tomlTableHasKey(text, table, key) {
|
|
589
|
+
const block = tomlTableBlock(text, table);
|
|
590
|
+
return Boolean(block && new RegExp(`^\\s*${escapeRegExp(key)}\\s*=`, 'm').test(block));
|
|
591
|
+
}
|
|
592
|
+
function tableHeaderMatches(line, table) {
|
|
593
|
+
return new RegExp(`^\\s*\\[${escapeRegExp(table)}\\]\\s*$`).test(line || '');
|
|
594
|
+
}
|
|
595
|
+
function tomlLineKey(line) {
|
|
596
|
+
return String(line || '').split('=')[0]?.trim() || '';
|
|
597
|
+
}
|
|
598
|
+
function ensureTrailingNewline(text) {
|
|
599
|
+
return `${String(text || '').trim()}\n`;
|
|
600
|
+
}
|
|
601
|
+
function escapeRegExp(value) {
|
|
602
|
+
return String(value || '').replace(/[.*+?^${}()|[\]\\]/g, '\\$&');
|
|
603
|
+
}
|
|
459
604
|
export async function ensureCurrentMigrationBeforeCommand(input) {
|
|
460
605
|
const env = input.env || process.env;
|
|
461
606
|
const command = input.command;
|
package/dist/core/version.js
CHANGED
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
export const PACKAGE_VERSION = '5.
|
|
1
|
+
export const PACKAGE_VERSION = '5.7.0';
|
|
2
2
|
//# sourceMappingURL=version.js.map
|
|
@@ -5,6 +5,7 @@ import path from 'node:path';
|
|
|
5
5
|
import { codexFastModeDesktopStatus, codexLbConfigPath, configureCodexLb, ensureGlobalCodexFastModeDuringInstall, releaseCodexLbAuthHold, repairCodexLbAuth } from '../cli/install-helpers.js';
|
|
6
6
|
import { repairCodexConfigStructure, splitCodexProjectConfigPolicy } from '../core/codex/codex-project-config-policy.js';
|
|
7
7
|
import { parseCodexConfigToml, validateCodexConfigRoundTrip } from '../core/codex/codex-config-toml.js';
|
|
8
|
+
import { REQUIRED_CODEX_MODEL } from '../core/codex-model-guard.js';
|
|
8
9
|
const tmp = await fs.mkdtemp(path.join(os.tmpdir(), 'sks-codex-lb-gpt55-fast-'));
|
|
9
10
|
const home = path.join(tmp, 'home');
|
|
10
11
|
const root = path.join(tmp, 'project');
|
|
@@ -44,7 +45,7 @@ await fs.writeFile(projectConfig, [
|
|
|
44
45
|
'enabled = true',
|
|
45
46
|
'',
|
|
46
47
|
'[profiles.sks-fast-high]',
|
|
47
|
-
|
|
48
|
+
`model = "${REQUIRED_CODEX_MODEL}"`,
|
|
48
49
|
'service_tier = "fast"',
|
|
49
50
|
''
|
|
50
51
|
].join('\n'));
|
|
@@ -85,7 +86,7 @@ function assertFastProfile(text, label) {
|
|
|
85
86
|
...validation.blockers,
|
|
86
87
|
...(parsed.default_profile === 'sks-fast-high' ? [] : ['default_profile_not_sks_fast_high']),
|
|
87
88
|
...(parsed.user?.fast_mode?.default_profile === undefined ? [] : ['default_profile_inside_user_fast_mode']),
|
|
88
|
-
...(profile.model ===
|
|
89
|
+
...(profile.model === REQUIRED_CODEX_MODEL ? [] : ['sks_fast_high_model_not_required_codex_model']),
|
|
89
90
|
...(profile.service_tier === 'fast' ? [] : ['sks_fast_high_service_tier_not_fast']),
|
|
90
91
|
...(provider.requires_openai_auth === true ? [] : ['codex_lb_requires_openai_auth_not_true']),
|
|
91
92
|
...(provider.wire_api === 'responses' ? [] : ['codex_lb_wire_api_not_responses']),
|
|
@@ -12,8 +12,10 @@ const MAX_UNPACKED = Number(process.env.SKS_MAX_UNPACKED_BYTES || 10 * 1024 * 10
|
|
|
12
12
|
// (route-success-helpers.ts, seo-command.ts, ppt-command.ts, qa-loop-command.ts,
|
|
13
13
|
// research-command.ts, image-ux-review-command.ts, mad-sks-command.ts,
|
|
14
14
|
// sks-menubar.ts) with genuine new production logic, pushing the packed size
|
|
15
|
-
// to ~2306 KiB.
|
|
16
|
-
|
|
15
|
+
// to ~2306 KiB. 5.7.0 adds doctor/update migration repair coverage and publish
|
|
16
|
+
// contract checks, pushing the packed tarball to ~2345 KiB. Keep a narrow cap
|
|
17
|
+
// rather than giving the package a broad size budget.
|
|
18
|
+
const MAX_PACKED = Number(process.env.SKS_MAX_PACK_BYTES || 2350 * 1024);
|
|
17
19
|
function runNpmPack() {
|
|
18
20
|
const npmCli = process.env.npm_execpath; // set when invoked via `npm run`
|
|
19
21
|
const npmCache = process.env.SKS_RELEASE_NPM_CACHE || path.join(os.tmpdir(), 'sneakoscope-npm-cache');
|
|
@@ -393,7 +393,18 @@ for (const gate of allManifestGates)
|
|
|
393
393
|
assertGate(pkg.bin?.sks === 'dist/bin/sks.js', 'package runtime must use dist/bin/sks.js');
|
|
394
394
|
assertGate(pkg.bin?.sneakoscope === 'dist/bin/sks.js', 'sneakoscope runtime must use dist/bin/sks.js');
|
|
395
395
|
assertGate(!pkg.files?.includes('src'), 'package files must not include src runtime shadows');
|
|
396
|
-
|
|
396
|
+
const publishPrepIgnoreScripts = String(pkg.scripts?.['publish:prep-ignore-scripts'] || '');
|
|
397
|
+
assertGate(!/\bprepublishOnly\b/.test(publishPrepIgnoreScripts), 'publish:prep-ignore-scripts must not depend on npm lifecycle hooks that --ignore-scripts disables', { script: publishPrepIgnoreScripts || null });
|
|
398
|
+
for (const required of [
|
|
399
|
+
'build:incremental',
|
|
400
|
+
'release:version-truth',
|
|
401
|
+
'publish:packlist-performance',
|
|
402
|
+
'package-published-contract-check.js',
|
|
403
|
+
'release-registry-check.js --require-unpublished --require-publish-auth',
|
|
404
|
+
'publish-tag:check'
|
|
405
|
+
]) {
|
|
406
|
+
assertGate(publishPrepIgnoreScripts.includes(required), `publish:prep-ignore-scripts missing lifecycle-disabled publish preflight: ${required}`, { script: publishPrepIgnoreScripts || null });
|
|
407
|
+
}
|
|
397
408
|
assertGate(String(pkg.scripts?.['publish:ignore-scripts'] || '').includes('npm run publish:prep-ignore-scripts'), 'publish:ignore-scripts must run publish:prep-ignore-scripts before npm publish --ignore-scripts', { script: pkg.scripts?.['publish:ignore-scripts'] || null });
|
|
398
409
|
assertGate(String(pkg.scripts?.['publish:ignore-scripts'] || '').includes('--ignore-scripts'), 'publish:ignore-scripts must keep npm lifecycle scripts disabled for the final publish', { script: pkg.scripts?.['publish:ignore-scripts'] || null });
|
|
399
410
|
for (const file of requiredDocs) {
|