sneakoscope 4.7.1 → 4.7.4

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.
Files changed (36) hide show
  1. package/README.md +11 -11
  2. package/crates/sks-core/Cargo.lock +1 -1
  3. package/crates/sks-core/Cargo.toml +1 -1
  4. package/crates/sks-core/src/main.rs +1 -1
  5. package/dist/bin/sks.js +1 -1
  6. package/dist/cli/command-registry.js +1 -1
  7. package/dist/cli/install-helpers.js +215 -57
  8. package/dist/commands/codex-lb.js +143 -7
  9. package/dist/commands/doctor.js +59 -2
  10. package/dist/core/codex-app/codex-app-fast-ui-repair.js +11 -1
  11. package/dist/core/codex-app/codex-app-restart.js +65 -0
  12. package/dist/core/codex-app/sks-menubar.js +445 -0
  13. package/dist/core/codex-app.js +239 -3
  14. package/dist/core/codex-control/codex-sdk-config-policy.js +2 -2
  15. package/dist/core/codex-control/codex-task-runner.js +2 -2
  16. package/dist/core/codex-lb/codex-lb-setup.js +1 -1
  17. package/dist/core/commands/basic-cli.js +14 -7
  18. package/dist/core/doctor/doctor-dirty-planner.js +2 -0
  19. package/dist/core/doctor/doctor-readiness-matrix.js +4 -0
  20. package/dist/core/fsx.js +1 -1
  21. package/dist/core/imagegen/imagegen-capability.js +2 -2
  22. package/dist/core/init.js +1 -1
  23. package/dist/core/managed-assets/managed-assets-manifest.js +1 -1
  24. package/dist/core/provider/provider-context.js +1 -1
  25. package/dist/core/routes.js +2 -2
  26. package/dist/core/update-check.js +67 -18
  27. package/dist/core/version.js +1 -1
  28. package/dist/scripts/codex-app-provider-model-ui-check.js +114 -0
  29. package/dist/scripts/codex-lb-fast-mode-truth-check.js +90 -0
  30. package/dist/scripts/codex-lb-setup-truthfulness-check.js +6 -1
  31. package/dist/scripts/doctor-fixes-codex-app-fast-ui-check.js +5 -1
  32. package/dist/scripts/gpt-image-2-real-file-smoke.js +2 -2
  33. package/dist/scripts/provider-context-config-toml-check.js +2 -2
  34. package/dist/scripts/sks-menubar-install-check.js +59 -0
  35. package/dist/scripts/update-default-command-check.js +28 -0
  36. package/package.json +5 -1
@@ -4,6 +4,7 @@ import { PACKAGE_VERSION, packageRoot, readJson, runProcess, which } from './fsx
4
4
  import { createRequestedScopeContract } from './safety/requested-scope-contract.js';
5
5
  import { guardedPackageInstall, guardContextForRoute } from './safety/mutation-guard.js';
6
6
  import { isUpdateMigrationReceiptCurrent, resolveInstalledSksEntrypoint, runPackageLocalDoctor, writeProjectUpdateMigrationReceipt } from './update/update-migration-state.js';
7
+ import { installSksMenuBar } from './codex-app/sks-menubar.js';
7
8
  const DEFAULT_REGISTRY = 'https://registry.npmjs.org/';
8
9
  export async function runSksUpdateCheck(options = {}) {
9
10
  const packageName = options.packageName || 'sneakoscope';
@@ -164,6 +165,9 @@ export async function runSksUpdateNow(options = {}) {
164
165
  }).catch(() => null);
165
166
  const migrationCurrent = isUpdateMigrationReceiptCurrent(receipt);
166
167
  stage('project_receipt', migrationCurrent, migrationCurrent ? 'current' : 'failed', { root: projectReceiptRoot });
168
+ const sksMenuBar = migrationCurrent
169
+ ? await installUpdateSksMenuBar({ root: projectReceiptRoot, env, stage })
170
+ : null;
167
171
  return buildUpdateNowResult({
168
172
  packageName,
169
173
  from: check.current,
@@ -185,19 +189,14 @@ export async function runSksUpdateNow(options = {}) {
185
189
  newVersionDoctor: null,
186
190
  projectReceipt: receipt,
187
191
  migrationCurrent,
192
+ sksMenuBar,
188
193
  stages,
189
194
  error: null
190
195
  });
191
196
  }
192
- const oldVersionDoctor = await runPackageLocalDoctor({
193
- root: projectReceiptRoot,
194
- args: ['doctor', '--fix', '--yes', '--profile', 'migration', '--machine-only', '--report-file', path.join(projectReceiptRoot, '.sneakoscope', 'update', `old-version-doctor-${Date.now()}.json`)],
195
- env,
196
- timeoutMs: 15_000,
197
- maxOutputBytes: 32 * 1024
198
- });
199
- stage('old_version_doctor_preflight', oldVersionDoctor.ok, oldVersionDoctor.status, { entrypoint: oldVersionDoctor.entrypoint, exit_code: oldVersionDoctor.exit_code });
200
- if (!oldVersionDoctor.ok && env.SKS_UPDATE_SKIP_OLD_DOCTOR_PREFLIGHT !== '1') {
197
+ if (options.dryRun) {
198
+ stage('old_version_doctor_preflight', true, 'skipped_dry_run', { reason: 'dry_run_does_not_run_doctor_fix' });
199
+ stage('npm_install', true, 'dry_run', { command });
201
200
  return buildUpdateNowResult({
202
201
  packageName,
203
202
  from: check.current,
@@ -210,21 +209,32 @@ export async function runSksUpdateNow(options = {}) {
210
209
  cwd,
211
210
  registry,
212
211
  globalRoot,
213
- status: 'failed',
214
- ok: false,
212
+ status: 'dry_run',
213
+ ok: true,
215
214
  installCode: null,
216
- oldVersionDoctor,
215
+ oldVersionDoctor: null,
217
216
  newBinary: null,
218
217
  newVersion: null,
219
218
  newVersionDoctor: null,
220
219
  projectReceipt: null,
221
220
  migrationCurrent: false,
222
221
  stages,
223
- error: oldVersionDoctor.error || 'old-version Doctor preflight failed'
222
+ error: null
224
223
  });
225
224
  }
226
- if (options.dryRun) {
227
- stage('npm_install', true, 'dry_run', { command });
225
+ const oldDoctorTimeoutOverride = Number.parseInt(env.SKS_UPDATE_OLD_DOCTOR_TIMEOUT_MS || '', 10);
226
+ const oldDoctorTimeoutMs = Number.isFinite(oldDoctorTimeoutOverride) && oldDoctorTimeoutOverride > 0
227
+ ? oldDoctorTimeoutOverride
228
+ : 60_000;
229
+ const oldVersionDoctor = await runPackageLocalDoctor({
230
+ root: projectReceiptRoot,
231
+ args: ['doctor', '--fix', '--yes', '--profile', 'migration', '--machine-only', '--report-file', path.join(projectReceiptRoot, '.sneakoscope', 'update', `old-version-doctor-${Date.now()}.json`)],
232
+ env,
233
+ timeoutMs: oldDoctorTimeoutMs,
234
+ maxOutputBytes: 32 * 1024
235
+ });
236
+ stage('old_version_doctor_preflight', oldVersionDoctor.ok, oldVersionDoctor.status, { entrypoint: oldVersionDoctor.entrypoint, exit_code: oldVersionDoctor.exit_code, timeout_ms: oldDoctorTimeoutMs });
237
+ if (!oldVersionDoctor.ok && env.SKS_UPDATE_SKIP_OLD_DOCTOR_PREFLIGHT !== '1') {
228
238
  return buildUpdateNowResult({
229
239
  packageName,
230
240
  from: check.current,
@@ -237,8 +247,8 @@ export async function runSksUpdateNow(options = {}) {
237
247
  cwd,
238
248
  registry,
239
249
  globalRoot,
240
- status: 'dry_run',
241
- ok: true,
250
+ status: 'failed',
251
+ ok: false,
242
252
  installCode: null,
243
253
  oldVersionDoctor,
244
254
  newBinary: null,
@@ -247,7 +257,7 @@ export async function runSksUpdateNow(options = {}) {
247
257
  projectReceipt: null,
248
258
  migrationCurrent: false,
249
259
  stages,
250
- error: null
260
+ error: oldVersionDoctor.error || 'old-version Doctor preflight failed'
251
261
  });
252
262
  }
253
263
  const mutationLedgerRoot = env.SKS_MUTATION_LEDGER_ROOT || packageRoot();
@@ -277,6 +287,7 @@ export async function runSksUpdateNow(options = {}) {
277
287
  let newVersionDoctor = null;
278
288
  let projectReceipt = null;
279
289
  let migrationCurrent = false;
290
+ let sksMenuBar = null;
280
291
  if (installOk) {
281
292
  newBinary = await resolveInstalledSksEntrypoint({ packageName, globalRoot, env });
282
293
  stage('resolve_new_package_local_binary', Boolean(newBinary), newBinary ? 'resolved' : 'missing', { new_binary: newBinary });
@@ -310,6 +321,8 @@ export async function runSksUpdateNow(options = {}) {
310
321
  }).catch(() => null);
311
322
  migrationCurrent = isUpdateMigrationReceiptCurrent(projectReceipt);
312
323
  stage('project_receipt', migrationCurrent, migrationCurrent ? 'current' : 'failed', { root: projectReceiptRoot });
324
+ if (migrationCurrent)
325
+ sksMenuBar = await installUpdateSksMenuBar({ root: projectReceiptRoot, env, stage });
313
326
  }
314
327
  }
315
328
  const ok = installOk && Boolean(newBinary) && newVersionDoctor?.ok === true && migrationCurrent;
@@ -334,6 +347,7 @@ export async function runSksUpdateNow(options = {}) {
334
347
  newVersionDoctor,
335
348
  projectReceipt,
336
349
  migrationCurrent,
350
+ sksMenuBar,
337
351
  stages,
338
352
  error: ok ? null : updateNowError(install, newBinary, newVersionDoctor, migrationCurrent)
339
353
  });
@@ -500,10 +514,45 @@ function buildUpdateNowResult(input) {
500
514
  new_version_doctor: input.newVersionDoctor,
501
515
  project_receipt: input.projectReceipt,
502
516
  migration_current: input.migrationCurrent,
517
+ sks_menubar: input.sksMenuBar || null,
503
518
  stages: input.stages,
504
519
  error: input.error
505
520
  };
506
521
  }
522
+ async function installUpdateSksMenuBar(input) {
523
+ if (input.env.SKS_UPDATE_SKIP_SKS_MENUBAR === '1') {
524
+ input.stage('sks_menubar', true, 'skipped', { reason: 'SKS_UPDATE_SKIP_SKS_MENUBAR=1' });
525
+ return null;
526
+ }
527
+ const result = await installSksMenuBar({
528
+ root: input.root,
529
+ apply: true,
530
+ launch: true,
531
+ env: input.env
532
+ }).catch((err) => ({
533
+ schema: 'sks.codex-app-sks-menubar.v1',
534
+ ok: false,
535
+ apply: true,
536
+ status: 'blocked',
537
+ platform: process.platform,
538
+ app_path: null,
539
+ executable_path: null,
540
+ launch_agent_path: null,
541
+ action_script_path: null,
542
+ report_path: path.join(input.root, '.sneakoscope', 'reports', 'sks-menubar.json'),
543
+ menu_items: [],
544
+ actions: [],
545
+ launch: { requested: true, method: 'none', ok: false, error: err?.message || String(err) },
546
+ blockers: [err?.message || String(err)],
547
+ warnings: []
548
+ }));
549
+ input.stage('sks_menubar', result.ok !== false, result.status, {
550
+ app_path: result.app_path,
551
+ launch_agent_path: result.launch_agent_path,
552
+ launch: result.launch
553
+ });
554
+ return result;
555
+ }
507
556
  async function detectNpmGlobalRoot(npmBin, env, opts = {}) {
508
557
  const result = await runProcess(npmBin, ['root', '--global', '--silent'], {
509
558
  env,
@@ -1,2 +1,2 @@
1
- export const PACKAGE_VERSION = '4.7.0';
1
+ export const PACKAGE_VERSION = '4.7.4';
2
2
  //# sourceMappingURL=version.js.map
@@ -0,0 +1,114 @@
1
+ #!/usr/bin/env node
2
+ import fs from 'node:fs/promises';
3
+ import os from 'node:os';
4
+ import path from 'node:path';
5
+ import { codexProviderModelUiStatus, formatCodexAppStatus } from '../core/codex-app.js';
6
+ import { GLM_CODEX_CONFIG_PROVIDER_ID, GLM_CODEX_CONFIG_REASONING_PROFILES } from '../core/codex-app/glm-model-profile.js';
7
+ import { GLM_52_OPENROUTER_MODEL } from '../core/providers/glm/glm-52-settings.js';
8
+ const tmp = await fs.mkdtemp(path.join(os.tmpdir(), 'sks-codex-app-provider-ui-'));
9
+ const home = path.join(tmp, 'home');
10
+ const cwd = path.join(tmp, 'project');
11
+ await fs.mkdir(path.join(home, '.codex'), { recursive: true });
12
+ await fs.mkdir(path.join(cwd, '.codex'), { recursive: true });
13
+ const missing = await codexProviderModelUiStatus({ home, cwd, env: { HOME: home } });
14
+ const missingText = formatCodexAppStatus(statusFixture(missing));
15
+ await fs.writeFile(path.join(home, '.codex', 'config.toml'), readyConfig(), 'utf8');
16
+ await fs.writeFile(path.join(home, '.codex', 'sks-codex-lb.env'), "export CODEX_LB_BASE_URL='https://lb.example.test/backend-api/codex'\nexport CODEX_LB_API_KEY='sk-codex-lb-fixture'\n", 'utf8');
17
+ const ready = await codexProviderModelUiStatus({
18
+ home,
19
+ cwd,
20
+ env: { HOME: home, OPENROUTER_API_KEY: 'sk-or-fixture' }
21
+ });
22
+ const readyText = formatCodexAppStatus(statusFixture(ready));
23
+ const ok = missing.ok === false
24
+ && missing.glm.exposed === false
25
+ && missing.codex_lb.key_entry_visible === true
26
+ && missing.ui_actions.includes('sks codex-app set-openrouter-key --api-key-stdin')
27
+ && missing.ui_actions.includes('sks codex-lb setup --host <domain> --api-key-stdin --yes')
28
+ && /Provider UI:\s*setup/.test(missingText)
29
+ && /GLM Model:\s*setup/.test(missingText)
30
+ && /codex-lb Key:\s*missing \(input: sks codex-lb setup/.test(missingText)
31
+ && ready.ok === true
32
+ && ready.glm.exposed === true
33
+ && ready.glm.model === GLM_52_OPENROUTER_MODEL
34
+ && ready.glm.profiles_present.length === GLM_CODEX_CONFIG_REASONING_PROFILES.length
35
+ && ready.codex_lb.provider_present === true
36
+ && ready.codex_lb.key_present === true
37
+ && /Provider UI:\s*ok/.test(readyText)
38
+ && readyText.includes(`GLM Model: ok ${GLM_52_OPENROUTER_MODEL}`)
39
+ && /codex-lb Key:\s*configured/.test(readyText)
40
+ && !JSON.stringify({ missing, ready, missingText, readyText }).includes('sk-codex-lb-fixture');
41
+ emit({
42
+ schema: 'sks.codex-app-provider-model-ui-check.v1',
43
+ ok,
44
+ missing,
45
+ ready,
46
+ secret_safe: !JSON.stringify({ missing, ready, missingText, readyText }).includes('sk-codex-lb-fixture'),
47
+ blockers: ok ? [] : ['codex_app_provider_model_ui_check_failed']
48
+ });
49
+ function readyConfig() {
50
+ return [
51
+ `[model_providers.${GLM_CODEX_CONFIG_PROVIDER_ID}]`,
52
+ 'name = "OpenRouter"',
53
+ 'base_url = "https://openrouter.ai/api/v1"',
54
+ 'wire_api = "responses"',
55
+ 'env_key = "OPENROUTER_API_KEY"',
56
+ 'requires_openai_auth = false',
57
+ '',
58
+ ...GLM_CODEX_CONFIG_REASONING_PROFILES.flatMap((profile) => [
59
+ `[profiles.${profile.id}]`,
60
+ `model_provider = "${GLM_CODEX_CONFIG_PROVIDER_ID}"`,
61
+ `model = "${GLM_52_OPENROUTER_MODEL}"`,
62
+ `model_reasoning_effort = "${profile.reasoning_effort}"`,
63
+ 'service_tier = "default"',
64
+ 'approval_policy = "on-request"',
65
+ ''
66
+ ]),
67
+ '[model_providers.codex-lb]',
68
+ 'name = "openai"',
69
+ 'base_url = "https://lb.example.test/backend-api/codex"',
70
+ 'wire_api = "responses"',
71
+ 'env_key = "CODEX_LB_API_KEY"',
72
+ 'supports_websockets = true',
73
+ 'requires_openai_auth = true',
74
+ ''
75
+ ].join('\n');
76
+ }
77
+ function statusFixture(providerModelUi) {
78
+ return {
79
+ ok: providerModelUi.ok,
80
+ app: { installed: true, path: '/Applications/Codex.app' },
81
+ codex_cli: { ok: true, version: '0.142.0' },
82
+ remote_control: { ok: true, min_version: '0.130.0', codex_cli: { version_number: '0.142.0' } },
83
+ features: {
84
+ checked: true,
85
+ required_flags_ok: true,
86
+ required_flags: {},
87
+ fast_mode_config: { ok: true, blockers: [] },
88
+ provider_model_ui: providerModelUi,
89
+ git_actions: { ok: true, blockers: [] },
90
+ browser_tool_ready: true,
91
+ browser_tool_source: 'fixture',
92
+ image_generation: true
93
+ },
94
+ plugins: {
95
+ default_plugins: { ok: true },
96
+ design_product: { ok: true, id: 'product-design' },
97
+ picker: { ok: true }
98
+ },
99
+ chrome_extension: { ok: true, blockers: [] },
100
+ mcp: {
101
+ has_computer_use: true,
102
+ computer_use_source: 'mcp_list',
103
+ has_browser_use: true,
104
+ browser_use_source: 'mcp_list'
105
+ },
106
+ guidance: []
107
+ };
108
+ }
109
+ function emit(report) {
110
+ console.log(JSON.stringify(report, null, 2));
111
+ if (!report.ok)
112
+ process.exitCode = 1;
113
+ }
114
+ //# sourceMappingURL=codex-app-provider-model-ui-check.js.map
@@ -0,0 +1,90 @@
1
+ #!/usr/bin/env node
2
+ import fs from 'node:fs/promises';
3
+ import os from 'node:os';
4
+ import path from 'node:path';
5
+ import { run } from '../commands/codex-lb.js';
6
+ const calls = [];
7
+ const home = await fs.mkdtemp(path.join(os.tmpdir(), 'sks-codex-lb-fast-truth-'));
8
+ await fs.mkdir(path.join(home, '.codex'), { recursive: true });
9
+ await fs.writeFile(path.join(home, '.codex', 'config.toml'), [
10
+ 'model_provider = "codex-lb"',
11
+ 'service_tier = "fast"',
12
+ '',
13
+ '[model_providers.codex-lb]',
14
+ 'name = "openai"',
15
+ 'base_url = "https://lb.example.test/backend-api/codex"',
16
+ 'wire_api = "responses"',
17
+ 'env_key = "CODEX_LB_API_KEY"',
18
+ 'supports_websockets = true',
19
+ 'requires_openai_auth = true',
20
+ ''
21
+ ].join('\n'));
22
+ await fs.writeFile(path.join(home, '.codex', 'auth.json'), `${JSON.stringify({ auth_mode: 'apikey', OPENAI_API_KEY: 'sk-fixture' })}\n`);
23
+ await fs.writeFile(path.join(home, '.codex', 'sks-codex-lb.env'), "export CODEX_LB_BASE_URL='https://lb.example.test/backend-api/codex'\nexport CODEX_LB_API_KEY='sk-fixture'\n");
24
+ const chain = await runFastCheck({
25
+ HOME: home,
26
+ CODEX_LB_API_KEY: 'sk-fixture',
27
+ CODEX_LB_BASE_URL: 'https://lb.example.test/backend-api/codex'
28
+ });
29
+ const requestedOnly = await runFastCheck({
30
+ HOME: home,
31
+ CODEX_LB_API_KEY: 'sk-fixture',
32
+ CODEX_LB_BASE_URL: 'https://lb.example.test/backend-api/codex',
33
+ SKS_TEST_FAST_ACTUAL_DEFAULT: '1'
34
+ });
35
+ const ok = chain.ok === true
36
+ && chain.status === 'fast_verified'
37
+ && calls[0]?.body?.service_tier === 'priority'
38
+ && requestedOnly.ok === false
39
+ && requestedOnly.status === 'fast_requested_but_actual_unverified'
40
+ && requestedOnly.blockers.includes('codex_lb_actual_fast_service_tier_unverified');
41
+ console.log(JSON.stringify({
42
+ schema: 'sks.codex-lb-fast-mode-truth-check.v1',
43
+ ok,
44
+ priority_request_sent: calls[0]?.body?.service_tier === 'priority',
45
+ verified_case: chain,
46
+ requested_only_case: requestedOnly,
47
+ blockers: ok ? [] : ['codex_lb_fast_mode_truth_check_failed']
48
+ }, null, 2));
49
+ if (!ok)
50
+ process.exitCode = 1;
51
+ async function runFastCheck(env) {
52
+ const originalFetch = globalThis.fetch;
53
+ const originalEnv = { ...process.env };
54
+ const outputs = [];
55
+ const originalWrite = process.stdout.write.bind(process.stdout);
56
+ const originalExitCode = process.exitCode;
57
+ try {
58
+ Object.assign(process.env, env);
59
+ process.exitCode = 0;
60
+ globalThis.fetch = async (_url, init) => {
61
+ const body = JSON.parse(String(init.body || '{}'));
62
+ calls.push({ body });
63
+ const id = calls.length % 2 === 1 ? 'resp_fast_1' : 'resp_fast_2';
64
+ const actual = env.SKS_TEST_FAST_ACTUAL_DEFAULT === '1' ? 'default' : 'priority';
65
+ return new Response(JSON.stringify({
66
+ id,
67
+ requestedServiceTier: 'priority',
68
+ actualServiceTier: actual,
69
+ serviceTier: actual
70
+ }), { status: 200, headers: { 'content-type': 'application/json' } });
71
+ };
72
+ process.stdout.write = (chunk) => {
73
+ outputs.push(String(chunk));
74
+ return true;
75
+ };
76
+ await run(null, ['fast-check', '--json']);
77
+ return JSON.parse(outputs.join('') || '{}');
78
+ }
79
+ finally {
80
+ globalThis.fetch = originalFetch;
81
+ process.stdout.write = originalWrite;
82
+ process.exitCode = originalExitCode;
83
+ for (const key of Object.keys(process.env)) {
84
+ if (!(key in originalEnv))
85
+ delete process.env[key];
86
+ }
87
+ Object.assign(process.env, originalEnv);
88
+ }
89
+ }
90
+ //# sourceMappingURL=codex-lb-fast-mode-truth-check.js.map
@@ -46,9 +46,14 @@ async function runSetup(name, args, input = 'sk-clb-test\n') {
46
46
  }
47
47
  {
48
48
  const row = await runSetup('no-env', ['--no-env-file']);
49
+ const actions = row.json.applied_actions?.map((action) => action.type) || [];
49
50
  results.push({
50
51
  name: 'no_env_file',
51
- ok: row.code === 0 && row.json.ok === true && !(await exists(row.envPath))
52
+ ok: row.code === 0
53
+ && row.json.status === 'process_env'
54
+ && row.json.persistence?.applied_modes?.includes('process_only_ephemeral')
55
+ && !actions.includes('write_env_file')
56
+ && !(await exists(row.envPath))
52
57
  });
53
58
  }
54
59
  {
@@ -8,7 +8,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
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');
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 = true\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');
@@ -22,8 +22,12 @@ await fs.mkdir(unsafeCodexHome, { recursive: true });
22
22
  await fs.writeFile(path.join(unsafeCodexHome, 'config.toml'), 'service_tier = "standard"\n');
23
23
  const unsafePlan = await repairCodexAppFastUi(unsafeRoot, { codexHome: unsafeCodexHome, apply: false });
24
24
  const ok = plan.fast_selector === 'manual_action_required'
25
+ && plan.provider_selector === 'manual_action_required'
26
+ && plan.provider_actions.includes('sks codex-app set-openrouter-key --api-key-stdin')
27
+ && plan.provider_actions.includes('sks codex-lb setup --host <domain> --api-key-stdin --yes')
25
28
  && plan.safe_auto_apply === true
26
29
  && repaired.fast_selector === 'repaired'
30
+ && repaired.provider_selector === 'manual_action_required'
27
31
  && repaired.safe_auto_apply === true
28
32
  && backups.length >= 2
29
33
  && !/^model\s*=/m.test(projectAfter.split(/\n\s*\[/)[0] || '')
@@ -92,7 +92,7 @@ function authState() {
92
92
  };
93
93
  }
94
94
  const codexLb = readCodexLbAuth();
95
- if (codexLb.selected && codexLb.provider_configured && codexLb.requires_openai_auth === false && codexLb.key && codexLb.base_url) {
95
+ if (codexLb.selected && codexLb.provider_configured && codexLb.requires_openai_auth === true && codexLb.key && codexLb.base_url) {
96
96
  return {
97
97
  ok: true,
98
98
  provider: 'openai_responses_image_generation',
@@ -102,7 +102,7 @@ function authState() {
102
102
  codex_lb: {
103
103
  selected: true,
104
104
  provider_configured: true,
105
- requires_openai_auth: false,
105
+ requires_openai_auth: true,
106
106
  base_url: codexLb.base_url,
107
107
  env_key: codexLb.env_key,
108
108
  env_path: codexLb.env_path,
@@ -10,11 +10,11 @@ const codexLbConfig = [
10
10
  'model_provider = "codex-lb"',
11
11
  '',
12
12
  '[model_providers.codex-lb]',
13
- 'name = "OpenAI"',
13
+ 'name = "openai"',
14
14
  'base_url = "https://lb.example.test"',
15
15
  'wire_api = "responses"',
16
16
  'env_key = "CODEX_LB_API_KEY"',
17
- 'requires_openai_auth = false',
17
+ 'requires_openai_auth = true',
18
18
  ''
19
19
  ].join('\n');
20
20
  await fs.writeFile(path.join(codexHome, 'config.toml'), codexLbConfig);
@@ -0,0 +1,59 @@
1
+ import fs from 'node:fs/promises';
2
+ import os from 'node:os';
3
+ import path from 'node:path';
4
+ import { installSksMenuBar } from '../core/codex-app/sks-menubar.js';
5
+ const temp = await fs.mkdtemp(path.join(os.tmpdir(), 'sks-menubar-check-'));
6
+ const result = await installSksMenuBar({
7
+ apply: true,
8
+ launch: false,
9
+ home: temp,
10
+ root: temp,
11
+ sksEntry: path.join(process.cwd(), 'dist', 'bin', 'sks.js')
12
+ });
13
+ const executableExists = result.executable_path ? await exists(result.executable_path) : false;
14
+ const launchAgentExists = result.launch_agent_path ? await exists(result.launch_agent_path) : false;
15
+ const actionScriptExists = result.action_script_path ? await exists(result.action_script_path) : false;
16
+ const expectedMenuItems = [
17
+ 'Use codex-lb',
18
+ 'Use ChatGPT OAuth',
19
+ 'Set OpenRouter Key and GLM Profiles',
20
+ 'Fast Check',
21
+ 'SKS Version Check',
22
+ 'Update SKS Now'
23
+ ];
24
+ const missingExpectedItems = expectedMenuItems.filter((item) => !result.menu_items.includes(item));
25
+ const hasExpectedItems = missingExpectedItems.length === 0;
26
+ const ok = process.platform === 'darwin'
27
+ ? result.ok === true
28
+ && result.status === 'installed_launch_skipped'
29
+ && executableExists
30
+ && launchAgentExists
31
+ && actionScriptExists
32
+ && hasExpectedItems
33
+ : result.ok === true && result.status === 'unsupported_platform';
34
+ const report = {
35
+ schema: 'sks.sks-menubar-install-check.v1',
36
+ ok,
37
+ temp,
38
+ result,
39
+ executable_exists: executableExists,
40
+ launch_agent_exists: launchAgentExists,
41
+ action_script_exists: actionScriptExists,
42
+ expected_menu_items: expectedMenuItems,
43
+ missing_expected_items: missingExpectedItems,
44
+ has_expected_items: hasExpectedItems,
45
+ blockers: ok ? [] : ['sks_menubar_install_check_failed']
46
+ };
47
+ console.log(JSON.stringify(report, null, 2));
48
+ if (!ok)
49
+ process.exit(1);
50
+ async function exists(file) {
51
+ try {
52
+ await fs.access(file);
53
+ return true;
54
+ }
55
+ catch {
56
+ return false;
57
+ }
58
+ }
59
+ //# sourceMappingURL=sks-menubar-install-check.js.map
@@ -0,0 +1,28 @@
1
+ import fs from 'node:fs';
2
+ function assertGate(ok, message, detail) {
3
+ if (!ok) {
4
+ console.error(JSON.stringify({ schema: 'sks.update-default-command-check.v1', ok: false, message, detail }, null, 2));
5
+ process.exit(1);
6
+ }
7
+ }
8
+ const registry = fs.readFileSync('src/cli/command-registry.ts', 'utf8');
9
+ const basicCli = fs.readFileSync('src/core/commands/basic-cli.ts', 'utf8');
10
+ const update = fs.readFileSync('src/core/update-check.ts', 'utf8');
11
+ const routes = fs.readFileSync('src/core/routes.ts', 'utf8');
12
+ assertGate(registry.includes("subcommand(() => import(basicModule), 'updateCommand', 'dist/core/commands/basic-cli.js', 'now')"), 'bare sks update must default to update now');
13
+ assertGate(basicCli.includes("export async function updateCommand(sub: any = 'now'"), 'updateCommand default must be now');
14
+ assertGate(basicCli.includes("action.startsWith('-')") && basicCli.includes('effectiveArgs = [String(sub), ...args]'), 'sks update --json/--dry-run must be treated as update now with flags');
15
+ assertGate(update.includes('installSksMenuBar') && update.includes('sks_menubar'), 'update now must refresh the SKS menu bar companion stage');
16
+ assertGate(routes.includes('sks update [check|now]'), 'command catalog must document bare sks update as the default update path');
17
+ console.log(JSON.stringify({
18
+ schema: 'sks.update-default-command-check.v1',
19
+ ok: true,
20
+ checks: [
21
+ 'registry_default_now',
22
+ 'basic_cli_default_now',
23
+ 'flag_first_default_now',
24
+ 'update_menubar_stage',
25
+ 'command_catalog_usage'
26
+ ]
27
+ }, null, 2));
28
+ //# sourceMappingURL=update-default-command-check.js.map
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "sneakoscope",
3
3
  "displayName": "ㅅㅋㅅ",
4
- "version": "4.7.1",
4
+ "version": "4.7.4",
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",
@@ -114,6 +114,7 @@
114
114
  "codex-app:fast-ui-preservation": "node ./dist/scripts/codex-app-fast-ui-preservation-check.js",
115
115
  "codex-app:ui-clobber-guard": "node ./dist/scripts/codex-app-ui-clobber-guard-check.js",
116
116
  "doctor:fixes-codex-app-fast-ui": "node ./dist/scripts/doctor-fixes-codex-app-fast-ui-check.js",
117
+ "codex-app:provider-model-ui": "node ./dist/scripts/codex-app-provider-model-ui-check.js",
117
118
  "mad-sks:app-ui-no-mutation": "node ./dist/scripts/mad-sks-app-ui-no-mutation-check.js",
118
119
  "provider:badge-context": "node ./dist/scripts/provider-badge-context-check.js",
119
120
  "provider:context-config-toml": "node ./dist/scripts/provider-context-config-toml-check.js",
@@ -167,6 +168,8 @@
167
168
  "codex:0.135-compat:require-real": "node ./dist/scripts/codex-0-135-compat-check.js --require-real",
168
169
  "doctor:codex-doctor-parity": "node ./dist/scripts/doctor-codex-doctor-parity-check.js",
169
170
  "doctor:codex-doctor-parity:actual": "node ./dist/scripts/doctor-codex-doctor-parity-check.js --actual-codex",
171
+ "doctor:sks-menubar": "node ./dist/scripts/sks-menubar-install-check.js",
172
+ "update:default-command": "node ./dist/scripts/update-default-command-check.js",
170
173
  "codex:permission-profiles": "node ./dist/scripts/codex-permission-profiles-check.js",
171
174
  "codex:legacy-profile-consumers-removed": "node ./dist/scripts/codex-legacy-profile-consumers-removed-check.js",
172
175
  "terminal:keyboard-enhancement-safety": "node ./dist/scripts/terminal-keyboard-enhancement-safety-check.js",
@@ -303,6 +306,7 @@
303
306
  "codex-lb:setup-truthfulness": "node ./dist/scripts/codex-lb-setup-truthfulness-check.js",
304
307
  "codex-lb:persistence-truth": "node ./dist/scripts/codex-lb-persistence-truth-check.js",
305
308
  "codex-lb:missing-env-regression": "node ./dist/scripts/codex-lb-missing-env-regression.js",
309
+ "codex-lb:fast-mode-truth": "node ./dist/scripts/codex-lb-fast-mode-truth-check.js",
306
310
  "computer-use:policy-check": "node ./dist/scripts/computer-use-policy-check.js",
307
311
  "computer-use:visual-route-fixture": "node ./dist/scripts/computer-use-visual-route-fixture-check.js",
308
312
  "computer-use:live-optional": "node ./dist/scripts/computer-use-live-optional-check.js",