sneakoscope 9.0.5 → 9.1.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 CHANGED
@@ -22,7 +22,7 @@ Proof-first orchestration for Codex CLI, ChatGPT Desktop, AI coding agents, mult
22
22
  Sneakoscope Codex (`sks`) is an open-source trust layer for Codex CLI and ChatGPT Desktop. It coordinates bounded AI coding agents, records machine-verifiable evidence, preserves project memory, and blocks release claims that are not supported by current tests or artifacts. Search visibility outcomes are measured separately; SKS does not promise rankings or traffic.
23
23
  <!-- END SKS SEARCH VISIBILITY MARKETING -->
24
24
 
25
- This README documents package **SKS 9.0.5** — its own identity, read from `package.json` and subject to release-gate verification, not advice about what to install.
25
+ This README documents package **SKS 9.1.0** — its own identity, read from `package.json` and subject to release-gate verification, not advice about what to install.
26
26
 
27
27
  Use the official latest stable SKS and Codex CLI releases. The Codex compatibility SSOT is always the **current latest stable** host; capability probes measure what that host can actually do. Product docs do not crown a fixed `0.x.y` string as SSOT (release pins and schema directories are measured artifacts for the current package, not a permanent product version claim). Menu Bar / Center induce updates to the latest stable build. Run `sks update-check` for what is installed and read the capability report for what is supported. Install SSOT is npm `sneakoscope@latest`; PATH `sks` and Menu Bar stamped generation must match that version or gates fail. It resolves managed SKS skills from the authoritative global install, preserves a runnable Naruto child slot when `max_threads=2`, and keeps Menu Bar repair transactional so stamped generations remain verifiable. Naruto uses stable opt-in multi-agent V2 when the host exposes it (Codex official multi-agent wrap-only; SKS does not reimplement a parallel runtime). Local code search is mode-separated (`sks search files|text|structure|symbol|context`); `context` is answered by the compiled TriWiki Context Graph (`context-graph.json` is exhaustive authority; `context-pack.json` and managed `AGENTS.md` are bounded projections) — see [docs/architecture/context-graph.md](https://github.com/mandarange/Sneakoscope-Codex/blob/main/docs/architecture/context-graph.md) and [docs/PRODUCT-CONTRACT.md](https://github.com/mandarange/Sneakoscope-Codex/blob/main/docs/PRODUCT-CONTRACT.md). See [CHANGELOG.md](https://github.com/mandarange/Sneakoscope-Codex/blob/main/CHANGELOG.md).
28
28
 
@@ -259,7 +259,7 @@ dependencies = [
259
259
 
260
260
  [[package]]
261
261
  name = "sks-core"
262
- version = "9.0.5"
262
+ version = "9.1.0"
263
263
  dependencies = [
264
264
  "globset",
265
265
  "grep-matcher",
@@ -1,6 +1,6 @@
1
1
  [package]
2
2
  name = "sks-core"
3
- version = "9.0.5"
3
+ version = "9.1.0"
4
4
  edition = "2021"
5
5
 
6
6
  [dependencies]
@@ -302,6 +302,9 @@ export function safeReadOnlySubcommand(command, args) {
302
302
  if (command === 'mcp' && sub === 'config' && ['list', 'test', 'backups', 'show'].includes(nested)) {
303
303
  return !args.some((arg) => ['--fix', '--yes', '-y', '--write', '--apply', '--execute', '--force', '--real'].includes(String(arg)));
304
304
  }
305
+ if (command === 'codex-app' && sub === 'context-1m' && (nested === 'status' || nested === '' || nested.startsWith('--'))) {
306
+ return !args.some((arg) => ['--fix', '--yes', '-y', '--write', '--apply', '--execute', '--force', '--real'].includes(String(arg)));
307
+ }
305
308
  if (command === 'remote' && ['readiness', 'status', 'show'].includes(sub)) {
306
309
  return !args.some((arg) => ['--fix', '--yes', '-y', '--write', '--apply', '--execute', '--force', '--real'].includes(String(arg)));
307
310
  }
@@ -16,6 +16,35 @@ export async function run(_command, args = []) {
16
16
  const action = args[0] || 'check';
17
17
  if (action === 'restart')
18
18
  return printCodexAppResult(args, await restartCodexApp());
19
+ if (action === 'context-1m') {
20
+ const { codexContext1mCommand } = await import('../core/codex-app/codex-context-window.js');
21
+ const result = await codexContext1mCommand(args.slice(1));
22
+ if (flag(args, '--json')) {
23
+ printJson(result);
24
+ if (!result.ok)
25
+ process.exitCode = 1;
26
+ return;
27
+ }
28
+ console.log(`Codex 1M Context: ${result.enabled ? 'enabled' : 'disabled'}`);
29
+ console.log(`Config: ${result.config_path}`);
30
+ console.log(`Model: ${result.model || 'not set'} (documented for ${result.expected_model})`);
31
+ for (const [key, target] of Object.entries(result.target)) {
32
+ const state = result.keys[key];
33
+ const detail = state?.present ? `${state.value ?? 'unparsed'}${state.managed ? ' (SKS-managed)' : ''}` : 'not set';
34
+ console.log(`${key}: ${detail} · target ${target}`);
35
+ }
36
+ if (result.restart)
37
+ console.log(`Restart: ${result.restart.status}${result.restart.reason ? ` (${result.restart.reason})` : ''}`);
38
+ for (const note of result.notes)
39
+ console.log(`Note: ${note}`);
40
+ for (const warning of result.warnings)
41
+ console.log(`- warning: ${warning}`);
42
+ for (const blocker of result.blockers)
43
+ console.log(`- blocker: ${blocker}`);
44
+ if (!result.ok)
45
+ process.exitCode = 1;
46
+ return;
47
+ }
19
48
  if (action === 'remote-control' || action === 'remote')
20
49
  return codexAppRemoteControlCommand(args.slice(1));
21
50
  if (action === 'harness-matrix') {
@@ -108,7 +137,7 @@ export async function run(_command, args = []) {
108
137
  process.exitCode = 1;
109
138
  return;
110
139
  }
111
- console.error('Usage: sks codex-app check|status|restart|harness-matrix|skill-sync|agent-role-sync|init-deep|hook-lifecycle|execution-profile|role-models|set-role-model --role <name> [--provider <id>] --model <catalog-slug> --reasoning <effort>|reset-role-model --role <name>|product-design [--check-only]|ensure-product-design|chrome-extension|pat status|remote-control [--json]');
140
+ console.error('Usage: sks codex-app check|status|restart|context-1m [status|on|off] [--no-restart]|harness-matrix|skill-sync|agent-role-sync|init-deep|hook-lifecycle|execution-profile|role-models|set-role-model --role <name> [--provider <id>] --model <catalog-slug> --reasoning <effort>|reset-role-model --role <name>|product-design [--check-only]|ensure-product-design|chrome-extension|pat status|remote-control [--json]');
112
141
  console.error('Provider routing moved to: sks bridge provider configure|validate|enable; sks bridge catalog sync; sks bridge route set-default.');
113
142
  process.exitCode = 1;
114
143
  }
@@ -7,10 +7,8 @@ import { ui as cliUi } from '../cli/cli-theme.js';
7
7
  import { getCodexInfo } from '../core/codex-adapter.js';
8
8
  import { rustInfo } from '../core/rust-accelerator.js';
9
9
  import { codexAppIntegrationStatus } from '../core/codex-app.js';
10
- import { desktopBridgeStatusV3, executeDesktopBridgeCommandV3 } from '../core/codex-lb/desktop-controller-v3.js';
11
- import { bootstrapExistingDesktopBridgeService, desktopBridgeServiceStatus } from '../core/codex-lb/desktop-service.js';
12
- import { desktopBridgeRuntimeVersion, desktopBridgeRuntimeVersionStale } from '../core/codex-lb/desktop-bridge/state.js';
13
- import { PACKAGE_VERSION } from '../core/version.js';
10
+ import { desktopBridgeStatusV3 } from '../core/codex-lb/desktop-controller-v3.js';
11
+ import { repairDoctorDesktopBridgeCatalog } from '../core/doctor/desktop-bridge-catalog-repair.js';
14
12
  import { inspectCodexConfigReadability } from '../core/codex/codex-config-readability.js';
15
13
  import { inspectOAuthCallbackPortConflict, oauthCallbackDoctorGuidance } from '../core/codex/oauth-callback-port-diagnostic.js';
16
14
  import { inventoryCodexPermissionProfiles } from '../core/codex/codex-permission-profiles.js';
@@ -37,29 +35,7 @@ export { buildCodexAppUiDiagnosticFailure, buildRuntimeReadiness, formatCodexDoc
37
35
  export function doctorArgWarnings(args = []) {
38
36
  return baseDoctorArgWarnings(args);
39
37
  }
40
- export async function restartStaleDesktopBridgeRuntime(input) {
41
- if (process.env.SKS_TEST_ISOLATION === '1' || process.env.SKS_RELEASE_UPGRADE_SMOKE === '1') {
42
- return { restarted: false, warnings: [], blockers: [] };
43
- }
44
- const service = await desktopBridgeServiceStatus({ home: input.home }).catch(() => null);
45
- if (!service?.running || !desktopBridgeRuntimeVersionStale(service.state)) {
46
- return { restarted: false, warnings: [], blockers: [] };
47
- }
48
- const running = desktopBridgeRuntimeVersion(service.state) || 'pre-8.6.2';
49
- if (!input.fix) {
50
- return {
51
- restarted: false,
52
- warnings: [],
53
- blockers: [`desktop_bridge_runtime_version_stale:${running}:${PACKAGE_VERSION}`]
54
- };
55
- }
56
- const restarted = await bootstrapExistingDesktopBridgeService({ home: input.home }).catch(() => null);
57
- const nowRunning = restarted?.running === true && !desktopBridgeRuntimeVersionStale(restarted.state);
58
- return nowRunning
59
- ? { restarted: true, warnings: [`desktop_bridge_runtime_restarted:${running}:${PACKAGE_VERSION}`], blockers: [] }
60
- : { restarted: false, warnings: [], blockers: [`desktop_bridge_runtime_version_stale:${running}:${PACKAGE_VERSION}`] };
61
- }
62
- export const CATALOG_REPAIR_MAX_ATTEMPTS = 2;
38
+ export { CATALOG_REPAIR_MAX_ATTEMPTS, repairDoctorDesktopBridgeCatalog, restartStaleDesktopBridgeRuntime } from '../core/doctor/desktop-bridge-catalog-repair.js';
63
39
  export function deferCommandAliasCleanupToMigrationReceipt(result) {
64
40
  const observedBlockers = Array.isArray(result?.blockers)
65
41
  ? result.blockers.map(String).filter(Boolean)
@@ -214,19 +190,41 @@ export async function executeDoctorGlobalOnlyFix(args = [], root, deps = {}) {
214
190
  status: 'failed',
215
191
  error: err?.message || String(err)
216
192
  }));
217
- const menuBar = await installMenuBarImpl({
218
- home,
219
- root: home,
220
- apply: true,
221
- launch: !sksMenuBarRestartDeferred(doctorEnv),
222
- env: doctorEnv,
223
- quiet: flag(args, '--json') || flag(args, '--machine-only')
224
- }).catch((err) => ({
225
- schema: 'sks.codex-app-sks-menubar.v1',
193
+ const doctorProfile = doctorProfileFromArgs(args, true);
194
+ const menuBarPolicy = doctorMenuBarInstallPolicy(args, true, doctorEnv);
195
+ const menuBar = menuBarPolicy.phase_enabled
196
+ ? await installMenuBarImpl({
197
+ home,
198
+ root: home,
199
+ apply: true,
200
+ launch: !sksMenuBarRestartDeferred(doctorEnv),
201
+ env: doctorEnv,
202
+ quiet: flag(args, '--json') || flag(args, '--machine-only')
203
+ }).catch((err) => ({
204
+ schema: 'sks.codex-app-sks-menubar.v1',
205
+ ok: false,
206
+ status: 'blocked',
207
+ blockers: [err?.message || String(err)],
208
+ warnings: []
209
+ }))
210
+ : {
211
+ schema: 'sks.codex-app-sks-menubar.v1',
212
+ ok: true,
213
+ status: 'skipped_by_profile',
214
+ skipped: true,
215
+ blockers: [],
216
+ warnings: [`sks_menubar_phase_skipped_for_profile:${doctorProfile}`]
217
+ };
218
+ const desktopBridgeRepairImpl = deps.desktopBridgeRepairImpl || repairDoctorDesktopBridgeCatalog;
219
+ const desktopBridgeRepair = await desktopBridgeRepairImpl({ fix: true }).catch((err) => ({
220
+ id: 'desktop_bridge_catalog_repair',
226
221
  ok: false,
227
- status: 'blocked',
228
- blockers: [err?.message || String(err)],
229
- warnings: []
222
+ repaired: false,
223
+ required_for_ready: false,
224
+ manual_required: false,
225
+ warnings: [],
226
+ blockers: [`desktop_bridge_catalog_repair_failed:${err?.message || String(err)}`],
227
+ rollback_evidence: 'combined_catalog_previous_generation_preserved'
230
228
  }));
231
229
  const desktopBridge = await inspectDoctorDesktopBridgeStatus({
232
230
  home,
@@ -238,15 +236,54 @@ export async function executeDoctorGlobalOnlyFix(args = [], root, deps = {}) {
238
236
  const globalFastModeReady = globalFastMode?.status !== 'failed'
239
237
  && globalFastMode?.ok !== false;
240
238
  const menuBarReady = menuBar?.ok !== false;
241
- const blockers = [...new Set([
239
+ const migrationScopeBlockers = [...new Set([
242
240
  ...(!globalSkillsReady ? [`global_skills_reconcile_failed:${globalSkills?.error || 'core_skill_integrity'}`] : []),
243
241
  ...(currentSurface?.ok !== true ? (currentSurface?.blockers || ['global_current_surface_reconcile_failed']) : []),
244
- ...(!globalFastModeReady ? [`global_fast_mode_repair_failed:${globalFastMode?.error || globalFastMode?.status || 'unknown'}`] : []),
245
- ...(!menuBarReady ? (menuBar?.blockers || ['sks_menubar_repair_failed']) : []),
242
+ ...(!globalFastModeReady ? [`global_fast_mode_repair_failed:${globalFastMode?.error || globalFastMode?.status || 'unknown'}`] : [])
243
+ ].map(String).filter(Boolean))];
244
+ const bridgeBlockers = [...new Set([
245
+ ...(desktopBridgeRepair?.ok === false
246
+ ? (desktopBridgeRepair?.blockers?.length ? desktopBridgeRepair.blockers : ['desktop_bridge_catalog_repair_failed'])
247
+ : []),
246
248
  ...(desktopBridge.ok === false
247
249
  ? (desktopBridge.blockers || ['desktop_bridge_unavailable'])
248
250
  : [])
249
251
  ].map(String).filter(Boolean))];
252
+ const bridgeReadinessRequired = doctorProfileRequiresDesktopBridgeReadiness(doctorProfile);
253
+ let migrationReceipt = null;
254
+ if (doctorProfile === 'migration') {
255
+ const writeReceiptImpl = deps.writeProjectUpdateMigrationReceiptImpl || writeProjectUpdateMigrationReceipt;
256
+ migrationReceipt = await writeReceiptImpl({
257
+ root: home,
258
+ source: `doctor-${doctorProfile}`,
259
+ blockers: migrationScopeBlockers,
260
+ warnings: ['global_only_home_scope_migration_receipt'],
261
+ ...(migrationScopeBlockers.length ? { status: 'blocked' } : {})
262
+ }).catch((err) => ({
263
+ schema: 'sks.project-migration-receipt.v2',
264
+ status: 'blocked',
265
+ sks_version: null,
266
+ root: home,
267
+ source: `doctor-${doctorProfile}`,
268
+ generated_at: new Date().toISOString(),
269
+ blockers: [`migration_receipt_failed:${err?.message || String(err)}`],
270
+ warnings: []
271
+ }));
272
+ }
273
+ const migrationReceiptBlockers = migrationReceipt && !isUpdateMigrationReceiptCurrent(migrationReceipt)
274
+ ? ((migrationReceipt.blockers || []).length ? migrationReceipt.blockers : ['global_migration_receipt_not_current'])
275
+ : [];
276
+ const blockers = [...new Set([
277
+ ...migrationScopeBlockers,
278
+ ...(!menuBarReady ? (menuBar?.blockers || ['sks_menubar_repair_failed']) : []),
279
+ ...(bridgeReadinessRequired ? bridgeBlockers : []),
280
+ ...migrationReceiptBlockers
281
+ ].map(String).filter(Boolean))];
282
+ const warnings = [...new Set([
283
+ ...(!bridgeReadinessRequired ? bridgeBlockers.map((blocker) => `migration_optional_blocker:${blocker}`) : []),
284
+ ...(desktopBridgeRepair?.warnings || []),
285
+ ...(desktopBridge?.warnings || [])
286
+ ].map(String).filter(Boolean))];
250
287
  const ok = blockers.length === 0;
251
288
  const projectRootAliasDetected = path.resolve(root) === home;
252
289
  return {
@@ -257,6 +294,7 @@ export async function executeDoctorGlobalOnlyFix(args = [], root, deps = {}) {
257
294
  diagnostic_depth: 'global-only',
258
295
  global_only: true,
259
296
  install_scope: 'global',
297
+ doctor_profile: doctorProfile,
260
298
  root,
261
299
  home,
262
300
  project_root_alias_detected: projectRootAliasDetected,
@@ -268,20 +306,26 @@ export async function executeDoctorGlobalOnlyFix(args = [], root, deps = {}) {
268
306
  'project_supabase_mcp_repair',
269
307
  'project_hook_trust_repair',
270
308
  'project_command_alias_cleanup',
271
- 'project_migration_receipt'
309
+ ...(migrationReceipt ? [] : ['project_migration_receipt'])
272
310
  ],
273
311
  skills: { global: globalSkills, project: { skipped: true, reason: 'global_only_doctor' } },
274
312
  current_public_surface: currentSurface,
275
313
  codex_app_fast_mode: globalFastMode,
276
314
  openrouter_provider: desktopBridge.providers?.openrouter || null,
277
315
  sks_menubar: menuBar,
316
+ desktop_bridge_repair: desktopBridgeRepair,
278
317
  desktop_bridge: desktopBridge,
318
+ ...(migrationReceipt ? { migration_receipt: migrationReceipt } : {}),
279
319
  blockers,
320
+ warnings,
280
321
  next_actions: [
281
322
  ...(projectRootAliasDetected
282
323
  ? ['Project checks were skipped because this directory is your home folder. Run them from your project: cd <your-project> && sks doctor --fix']
283
324
  : []),
284
325
  ...(desktopBridge.ok === false ? desktopBridge.recovery_actions || [] : []),
326
+ ...(!bridgeReadinessRequired && bridgeBlockers.length
327
+ ? ['Desktop Bridge still reports blockers: run `sks doctor --fix` to repair the bridge catalog.']
328
+ : []),
285
329
  'Run `sks doctor --fix --json` from a specific project directory when project-scoped repair is required.'
286
330
  ]
287
331
  };
@@ -300,10 +344,19 @@ async function runDoctorGlobalOnlyFix(args = [], root, deps = {}) {
300
344
  printJson(result);
301
345
  }
302
346
  else {
347
+ const bridgeRepair = result.desktop_bridge_repair;
303
348
  console.log(`SKS Doctor global repair: ${result.ok ? 'ok' : 'blocked'}`);
304
349
  console.log(`Global skills: ${result.skills.global?.error ? 'blocked' : 'reconciled'}`);
305
350
  console.log(`SKS menu bar: ${result.sks_menubar?.status || (result.sks_menubar?.ok ? 'ok' : 'blocked')}`);
351
+ console.log(`Desktop Bridge repair: ${bridgeRepair?.skipped_reason
352
+ ? bridgeRepair.skipped_reason
353
+ : bridgeRepair?.repaired
354
+ ? 'repaired'
355
+ : bridgeRepair?.ok === false ? 'failed' : 'nothing_to_repair'}`);
306
356
  console.log(`Desktop Bridge: ${result.desktop_bridge.ok ? 'ready' : 'blocked'} (${result.desktop_bridge.status?.readiness?.state || 'unavailable'})`);
357
+ if (result.migration_receipt) {
358
+ console.log(`Migration receipt: ${result.migration_receipt.status} (${result.home})`);
359
+ }
307
360
  for (const blocker of result.blockers)
308
361
  console.log(`- blocker: ${blocker}`);
309
362
  for (const action of result.next_actions)
@@ -1027,61 +1080,7 @@ async function runDoctor(args = [], root, doctorFix, deps = {}) {
1027
1080
  {
1028
1081
  id: 'desktop_bridge_catalog_repair',
1029
1082
  required_for_ready: false,
1030
- run: async () => {
1031
- const base = {
1032
- id: 'desktop_bridge_catalog_repair',
1033
- required_for_ready: false,
1034
- manual_required: false,
1035
- warnings: [],
1036
- rollback_evidence: 'combined_catalog_previous_generation_preserved'
1037
- };
1038
- try {
1039
- const bridgeHome = path.resolve(process.env.HOME || os.homedir());
1040
- const restarted = await restartStaleDesktopBridgeRuntime({
1041
- home: bridgeHome,
1042
- fix: doctorFix,
1043
- });
1044
- const status = await desktopBridgeStatusV3({ home: bridgeHome, env: process.env });
1045
- const blockers = (status?.readiness?.blockers || []).map(String);
1046
- const stale = blockers.filter((blocker) => blocker.endsWith('_catalog_stale'));
1047
- if (!status?.management?.managed || stale.length === 0) {
1048
- return {
1049
- ...base,
1050
- ok: restarted.blockers.length === 0,
1051
- repaired: restarted.restarted,
1052
- warnings: restarted.warnings,
1053
- blockers: restarted.blockers
1054
- };
1055
- }
1056
- const attempts = [];
1057
- let syncedAndVerified = false;
1058
- for (let attempt = 1; attempt <= CATALOG_REPAIR_MAX_ATTEMPTS; attempt += 1) {
1059
- const sync = await executeDesktopBridgeCommandV3({ operation: 'catalog.sync' }, { home: bridgeHome, env: process.env });
1060
- const commandOk = sync?.ok === true && sync?.execution?.ok === true;
1061
- const after = await desktopBridgeStatusV3({ home: bridgeHome, env: process.env });
1062
- const stillStale = (after?.readiness?.blockers || [])
1063
- .map(String).filter((blocker) => blocker.endsWith('_catalog_stale'));
1064
- if (commandOk && stillStale.length === 0) {
1065
- syncedAndVerified = true;
1066
- break;
1067
- }
1068
- attempts.push(`catalog_sync_attempt_${attempt}:${commandOk ? `still_stale:${stillStale.join(',')}` : (sync?.execution?.blockers || ['failed']).map(String).join(',')}`);
1069
- }
1070
- return {
1071
- ...base,
1072
- ok: syncedAndVerified && restarted.blockers.length === 0,
1073
- repaired: syncedAndVerified || restarted.restarted,
1074
- warnings: [...restarted.warnings, ...(syncedAndVerified ? attempts : [])],
1075
- blockers: [
1076
- ...(syncedAndVerified ? [] : ['desktop_bridge_catalog_still_stale_after_repair', ...attempts]),
1077
- ...restarted.blockers
1078
- ]
1079
- };
1080
- }
1081
- catch (error) {
1082
- return { ...base, ok: false, repaired: false, blockers: [String(error?.message || 'desktop_bridge_catalog_sync_failed')] };
1083
- }
1084
- }
1083
+ run: async () => repairDoctorDesktopBridgeCatalog({ fix: doctorFix })
1085
1084
  }
1086
1085
  ].filter((phase) => doctorPhaseIds.includes(phase.id))
1087
1086
  }).catch((err) => ({
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "schema": "sks.skills-manifest.v1",
3
- "package_version": "9.0.5",
3
+ "package_version": "9.1.0",
4
4
  "skills": [
5
5
  {
6
6
  "canonical_name": "sks",
@@ -0,0 +1,227 @@
1
+ import { exists, readText } from '../fsx.js';
2
+ import { escapeRegExp } from '../text/regex.js';
3
+ import { safeWriteCodexConfigToml } from '../codex-runtime/codex-desktop-config-policy.js';
4
+ import { codexUserConfigPath, readTopLevelTomlString } from './codex-model-catalog.js';
5
+ import { isCodexAppRunningByBundleId } from './menubar/config.js';
6
+ import { restartCodexApp } from './codex-app-restart.js';
7
+ export const CODEX_CONTEXT_1M_SCHEMA = 'sks.codex-context-1m.v1';
8
+ export const CODEX_CONTEXT_1M_MARKER = 'sks-codex-context-1m';
9
+ export const CODEX_CONTEXT_1M_TARGETS = {
10
+ model_context_window: 1_000_000,
11
+ model_auto_compact_token_limit: 900_000
12
+ };
13
+ export const CODEX_CONTEXT_1M_MODEL = 'gpt-5.6-sol';
14
+ const MANAGED_KEYS = Object.keys(CODEX_CONTEXT_1M_TARGETS);
15
+ function topLevelRegionEnd(lines) {
16
+ const first = lines.findIndex((line) => /^\s*\[.+\]\s*$/.test(line));
17
+ return first === -1 ? lines.length : first;
18
+ }
19
+ function managedLine(key, previous) {
20
+ return `${key} = ${CODEX_CONTEXT_1M_TARGETS[key]} # ${CODEX_CONTEXT_1M_MARKER} prev=${previous}`;
21
+ }
22
+ function inspectKeyLines(lines, key) {
23
+ const end = topLevelRegionEnd(lines);
24
+ const keyPattern = new RegExp(`^\\s*${escapeRegExp(key)}\\s*=`);
25
+ const managedPattern = new RegExp(`^\\s*${escapeRegExp(key)}\\s*=\\s*(\\d+)\\s*#\\s*${escapeRegExp(CODEX_CONTEXT_1M_MARKER)}\\s+prev=(unset|\\d+)\\s*$`);
26
+ const valuePattern = new RegExp(`^\\s*${escapeRegExp(key)}\\s*=\\s*(\\d+)\\s*(?:#.*)?$`);
27
+ let state = null;
28
+ let duplicate = false;
29
+ for (let index = 0; index < end; index += 1) {
30
+ const line = lines[index] || '';
31
+ if (!keyPattern.test(line))
32
+ continue;
33
+ if (state) {
34
+ duplicate = true;
35
+ continue;
36
+ }
37
+ const managed = line.match(managedPattern);
38
+ const value = line.match(valuePattern);
39
+ state = {
40
+ present: true,
41
+ managed: Boolean(managed),
42
+ value: managed ? Number(managed[1]) : value ? Number(value[1]) : null,
43
+ previous: managed ? (managed[2] === 'unset' ? 'unset' : Number(managed[2])) : null,
44
+ duplicate: false,
45
+ lineIndex: index
46
+ };
47
+ }
48
+ if (!state)
49
+ return { present: false, managed: false, value: null, previous: null, duplicate: false, lineIndex: -1 };
50
+ return { ...state, duplicate };
51
+ }
52
+ export function inspectCodexContext1m(text) {
53
+ const lines = String(text || '').split('\n');
54
+ const warnings = [];
55
+ const keys = {};
56
+ for (const key of MANAGED_KEYS) {
57
+ const { lineIndex: _lineIndex, ...state } = inspectKeyLines(lines, key);
58
+ keys[key] = state;
59
+ if (state.duplicate)
60
+ warnings.push(`codex_context_duplicate_key:${key}`);
61
+ if (state.managed && state.value !== CODEX_CONTEXT_1M_TARGETS[key])
62
+ warnings.push(`codex_context_managed_value_drift:${key}`);
63
+ }
64
+ const enabled = MANAGED_KEYS.every((key) => keys[key].managed && keys[key].value === CODEX_CONTEXT_1M_TARGETS[key]);
65
+ return { enabled, model: readTopLevelTomlString(String(text || ''), 'model'), keys, warnings };
66
+ }
67
+ export function enableCodexContext1m(text) {
68
+ const source = String(text || '');
69
+ const lines = source.split('\n');
70
+ const blockers = [];
71
+ const previous = {};
72
+ for (const key of MANAGED_KEYS) {
73
+ const state = inspectKeyLines(lines, key);
74
+ if (state.duplicate)
75
+ blockers.push(`codex_context_duplicate_key:${key}`);
76
+ if (state.present && !state.managed && state.value === null)
77
+ blockers.push(`codex_context_unparseable_value:${key}`);
78
+ }
79
+ if (blockers.length)
80
+ return { next: source, changed: false, previous: {}, restored: {}, blockers, warnings: [] };
81
+ for (const key of MANAGED_KEYS) {
82
+ const state = inspectKeyLines(lines, key);
83
+ if (state.present) {
84
+ const prior = state.managed ? (state.previous ?? 'unset') : state.value;
85
+ previous[key] = prior;
86
+ lines[state.lineIndex] = managedLine(key, prior);
87
+ }
88
+ else {
89
+ previous[key] = 'unset';
90
+ lines.splice(topLevelRegionEnd(lines), 0, managedLine(key, 'unset'));
91
+ }
92
+ }
93
+ const next = lines.join('\n').replace(/^\n+/, '').replace(/\n{3,}/g, '\n\n');
94
+ return { next, changed: next !== source, previous, restored: {}, blockers: [], warnings: [] };
95
+ }
96
+ export function disableCodexContext1m(text) {
97
+ const source = String(text || '');
98
+ const lines = source.split('\n');
99
+ const warnings = [];
100
+ const restored = {};
101
+ for (const key of MANAGED_KEYS) {
102
+ const state = inspectKeyLines(lines, key);
103
+ if (state.duplicate) {
104
+ return { next: source, changed: false, previous: {}, restored: {}, blockers: [`codex_context_duplicate_key:${key}`], warnings: [] };
105
+ }
106
+ if (!state.present)
107
+ continue;
108
+ if (!state.managed) {
109
+ warnings.push(`codex_context_unmanaged_key_left:${key}`);
110
+ continue;
111
+ }
112
+ const prior = state.previous ?? 'unset';
113
+ restored[key] = prior;
114
+ if (prior === 'unset')
115
+ lines.splice(state.lineIndex, 1);
116
+ else
117
+ lines[state.lineIndex] = `${key} = ${prior}`;
118
+ }
119
+ const next = lines.join('\n').replace(/^\n+/, '').replace(/\n{3,}/g, '\n\n');
120
+ return { next, changed: next !== source, previous: {}, restored, blockers: [], warnings };
121
+ }
122
+ export function normalizeCodexContext1mAction(value) {
123
+ const text = String(value || 'status').toLowerCase();
124
+ if (['on', 'enable', 'enabled', '1m'].includes(text))
125
+ return 'on';
126
+ if (['off', 'disable', 'disabled', 'default'].includes(text))
127
+ return 'off';
128
+ return 'status';
129
+ }
130
+ export async function codexContext1mCommand(args = [], opts = {}) {
131
+ const env = opts.env || process.env;
132
+ const action = normalizeCodexContext1mAction(args[0]);
133
+ const noRestart = args.includes('--no-restart');
134
+ const configPath = codexUserConfigPath({ env, ...(opts.home ? { home: opts.home } : {}) });
135
+ const before = String(await readText(configPath, ''));
136
+ const fileExists = await exists(configPath);
137
+ const blockers = [];
138
+ const warnings = [];
139
+ let write = null;
140
+ let changed = false;
141
+ let afterText = before;
142
+ let mutation = null;
143
+ if (action === 'on' || action === 'off') {
144
+ mutation = action === 'on' ? enableCodexContext1m(before) : disableCodexContext1m(before);
145
+ blockers.push(...mutation.blockers);
146
+ warnings.push(...mutation.warnings);
147
+ if (!blockers.length && mutation.changed) {
148
+ write = await safeWriteCodexConfigToml(configPath, before, mutation.next, 'codex-context-1m', {
149
+ verifyUnchangedBeforeWrite: true,
150
+ expectedBeforeExists: fileExists
151
+ });
152
+ if (!write.ok) {
153
+ blockers.push(`codex_config_write_${write.status}`);
154
+ }
155
+ else {
156
+ changed = write.changed;
157
+ afterText = write.expected_after?.text ?? mutation.next;
158
+ }
159
+ }
160
+ }
161
+ const inspection = inspectCodexContext1m(afterText);
162
+ warnings.push(...inspection.warnings);
163
+ if (action === 'on' || inspection.enabled) {
164
+ if (!inspection.model)
165
+ warnings.push('codex_context_model_line_missing');
166
+ else if (inspection.model !== CODEX_CONTEXT_1M_MODEL)
167
+ warnings.push(`codex_context_active_model_not_${CODEX_CONTEXT_1M_MODEL}:${inspection.model}`);
168
+ }
169
+ let restart = null;
170
+ if ((action === 'on' || action === 'off') && !blockers.length) {
171
+ restart = await maybeRestartCodexApp({
172
+ env,
173
+ changed,
174
+ noRestart,
175
+ ...(opts.root === undefined ? {} : { root: opts.root }),
176
+ ...(opts.isRunningImpl === undefined ? {} : { isRunningImpl: opts.isRunningImpl }),
177
+ ...(opts.restartImpl === undefined ? {} : { restartImpl: opts.restartImpl })
178
+ });
179
+ if (restart.attempted && !restart.ok)
180
+ warnings.push('codex_restart_failed_manual_restart_required');
181
+ }
182
+ return {
183
+ schema: CODEX_CONTEXT_1M_SCHEMA,
184
+ ok: blockers.length === 0,
185
+ action,
186
+ enabled: inspection.enabled,
187
+ config_path: configPath,
188
+ model: inspection.model,
189
+ expected_model: CODEX_CONTEXT_1M_MODEL,
190
+ target: { ...CODEX_CONTEXT_1M_TARGETS },
191
+ keys: inspection.keys,
192
+ previous: mutation && action === 'on' ? mutation.previous : null,
193
+ restored: mutation && action === 'off' ? mutation.restored : null,
194
+ changed,
195
+ write: write ? { status: write.status, backup_path: write.backup_path } : null,
196
+ restart,
197
+ blockers,
198
+ warnings,
199
+ notes: [
200
+ 'Only new Codex sessions pick up context-window changes; existing conversations keep their previous limits.',
201
+ 'Requests with more than 272K input tokens are billed at the long-context rate (2x input / 1.5x output) for the entire request.'
202
+ ],
203
+ cli_commands: {
204
+ status: 'sks codex-app context-1m status',
205
+ on: 'sks codex-app context-1m on',
206
+ off: 'sks codex-app context-1m off'
207
+ }
208
+ };
209
+ }
210
+ async function maybeRestartCodexApp(input) {
211
+ const skippedOutcome = (reason) => ({ attempted: false, running: null, status: 'skipped', reason, ok: true, blockers: [] });
212
+ if (input.noRestart)
213
+ return skippedOutcome('no_restart_flag');
214
+ if (!input.changed)
215
+ return skippedOutcome('config_unchanged');
216
+ if (input.env.SKS_SKIP_CODEX_APP_RESTART === '1')
217
+ return skippedOutcome('SKS_SKIP_CODEX_APP_RESTART');
218
+ if (process.platform !== 'darwin')
219
+ return skippedOutcome('not_macos');
220
+ const bundleId = String(input.env.SKS_CODEX_APP_BUNDLE_ID || 'com.openai.codex');
221
+ const running = await (input.isRunningImpl || isCodexAppRunningByBundleId)(bundleId, input.env);
222
+ if (!running) {
223
+ return { attempted: false, running: false, status: 'skipped', reason: 'codex_not_running', ok: true, blockers: [] };
224
+ }
225
+ const result = await (input.restartImpl || restartCodexApp)({ env: input.env, ...(input.root ? { root: input.root } : {}) });
226
+ return { attempted: true, running: true, status: result.status, reason: null, ok: result.ok, blockers: result.blockers };
227
+ }
@@ -274,7 +274,13 @@ export async function forwardHttp(req, res, config, prepared, authenticatedLocal
274
274
  const statusCode = response.statusCode || 502;
275
275
  if (statusCode >= 400) {
276
276
  void readRedactedUpstreamError(response).then(({ body, upstreamCode, upstreamType }) => {
277
- const transientMislabel = statusCode === 404 && upstreamType === 'upstream_error' && !upstreamCode;
277
+ const transientMislabel = statusCode === 404
278
+ && (upstreamType === 'upstream_error' || upstreamCode === 'upstream_error');
279
+ if (transientMislabel && replayable && !useFreshConnection) {
280
+ responseStarted = true;
281
+ finish(new StalePooledSocketFailure(new DesktopBridgeError('bridge_upstream_transient_mislabel')));
282
+ return;
283
+ }
278
284
  const clientStatus = transientMislabel ? 503 : statusCode;
279
285
  logHttpRejection({
280
286
  code: transientMislabel
@@ -255,6 +255,11 @@ export async function updateCommand(sub = 'now', args = []) {
255
255
  console.log(`New version: ${result.new_version}`);
256
256
  if (result.project_receipt)
257
257
  console.log(`Migration receipt: ${result.project_receipt.root} (${result.migration_current ? 'current' : 'not current'})`);
258
+ for (const warning of (result.project_receipt?.optional_warnings || [])
259
+ .filter((entry) => String(entry).includes('sks doctor --fix'))
260
+ .slice(0, 3)) {
261
+ console.log(`Follow-up: ${warning}`);
262
+ }
258
263
  if (result.sks_menubar)
259
264
  console.log(`SKS menu bar: ${result.sks_menubar.status}${result.sks_menubar.app_path ? ` (${result.sks_menubar.app_path})` : ''}`);
260
265
  if (result.operation_receipt_path)
@@ -0,0 +1,102 @@
1
+ import os from 'node:os';
2
+ import path from 'node:path';
3
+ import { desktopBridgeStatusV3, executeDesktopBridgeCommandV3 } from '../codex-lb/desktop-controller-v3.js';
4
+ import { bootstrapExistingDesktopBridgeService, desktopBridgeServiceStatus } from '../codex-lb/desktop-service.js';
5
+ import { desktopBridgeRuntimeVersion, desktopBridgeRuntimeVersionStale } from '../codex-lb/desktop-bridge/state.js';
6
+ import { PACKAGE_VERSION } from '../version.js';
7
+ export async function restartStaleDesktopBridgeRuntime(input) {
8
+ if (process.env.SKS_TEST_ISOLATION === '1' || process.env.SKS_RELEASE_UPGRADE_SMOKE === '1') {
9
+ return { restarted: false, warnings: [], blockers: [] };
10
+ }
11
+ const service = await desktopBridgeServiceStatus({ home: input.home }).catch(() => null);
12
+ if (!service?.running || !desktopBridgeRuntimeVersionStale(service.state)) {
13
+ return { restarted: false, warnings: [], blockers: [] };
14
+ }
15
+ const running = desktopBridgeRuntimeVersion(service.state) || 'pre-8.6.2';
16
+ if (!input.fix) {
17
+ return {
18
+ restarted: false,
19
+ warnings: [],
20
+ blockers: [`desktop_bridge_runtime_version_stale:${running}:${PACKAGE_VERSION}`]
21
+ };
22
+ }
23
+ const restarted = await bootstrapExistingDesktopBridgeService({ home: input.home }).catch(() => null);
24
+ const nowRunning = restarted?.running === true && !desktopBridgeRuntimeVersionStale(restarted.state);
25
+ return nowRunning
26
+ ? { restarted: true, warnings: [`desktop_bridge_runtime_restarted:${running}:${PACKAGE_VERSION}`], blockers: [] }
27
+ : { restarted: false, warnings: [], blockers: [`desktop_bridge_runtime_version_stale:${running}:${PACKAGE_VERSION}`] };
28
+ }
29
+ export const CATALOG_REPAIR_MAX_ATTEMPTS = 2;
30
+ export async function repairDoctorDesktopBridgeCatalog(input, deps = {}) {
31
+ const base = {
32
+ id: 'desktop_bridge_catalog_repair',
33
+ required_for_ready: false,
34
+ manual_required: false,
35
+ warnings: [],
36
+ rollback_evidence: 'combined_catalog_previous_generation_preserved'
37
+ };
38
+ const usingRealImpls = !deps.restartStaleDesktopBridgeRuntimeImpl
39
+ && !deps.desktopBridgeStatusImpl
40
+ && !deps.executeDesktopBridgeCommandImpl;
41
+ if (usingRealImpls
42
+ && (process.env.NODE_TEST_CONTEXT !== undefined
43
+ || process.env.SKS_TEST_ISOLATION === '1'
44
+ || process.env.SKS_RELEASE_UPGRADE_SMOKE === '1')) {
45
+ return {
46
+ ...base,
47
+ ok: true,
48
+ repaired: false,
49
+ blockers: [],
50
+ skipped_reason: 'desktop_bridge_catalog_repair_skipped_under_tests'
51
+ };
52
+ }
53
+ const restartImpl = deps.restartStaleDesktopBridgeRuntimeImpl || restartStaleDesktopBridgeRuntime;
54
+ const statusImpl = deps.desktopBridgeStatusImpl || desktopBridgeStatusV3;
55
+ const executeImpl = deps.executeDesktopBridgeCommandImpl || executeDesktopBridgeCommandV3;
56
+ try {
57
+ const bridgeHome = path.resolve(process.env.HOME || os.homedir());
58
+ const restarted = await restartImpl({
59
+ home: bridgeHome,
60
+ fix: input.fix
61
+ });
62
+ const status = await statusImpl({ home: bridgeHome, env: process.env });
63
+ const blockers = (status?.readiness?.blockers || []).map(String);
64
+ const stale = blockers.filter((blocker) => blocker.endsWith('_catalog_stale'));
65
+ if (!status?.management?.managed || stale.length === 0) {
66
+ return {
67
+ ...base,
68
+ ok: restarted.blockers.length === 0,
69
+ repaired: restarted.restarted,
70
+ warnings: restarted.warnings,
71
+ blockers: restarted.blockers
72
+ };
73
+ }
74
+ const attempts = [];
75
+ let syncedAndVerified = false;
76
+ for (let attempt = 1; attempt <= CATALOG_REPAIR_MAX_ATTEMPTS; attempt += 1) {
77
+ const sync = await executeImpl({ operation: 'catalog.sync' }, { home: bridgeHome, env: process.env });
78
+ const commandOk = sync?.ok === true && sync?.execution?.ok === true;
79
+ const after = await statusImpl({ home: bridgeHome, env: process.env });
80
+ const stillStale = (after?.readiness?.blockers || [])
81
+ .map(String).filter((blocker) => blocker.endsWith('_catalog_stale'));
82
+ if (commandOk && stillStale.length === 0) {
83
+ syncedAndVerified = true;
84
+ break;
85
+ }
86
+ attempts.push(`catalog_sync_attempt_${attempt}:${commandOk ? `still_stale:${stillStale.join(',')}` : (sync?.execution?.blockers || ['failed']).map(String).join(',')}`);
87
+ }
88
+ return {
89
+ ...base,
90
+ ok: syncedAndVerified && restarted.blockers.length === 0,
91
+ repaired: syncedAndVerified || restarted.restarted,
92
+ warnings: [...restarted.warnings, ...(syncedAndVerified ? attempts : [])],
93
+ blockers: [
94
+ ...(syncedAndVerified ? [] : ['desktop_bridge_catalog_still_stale_after_repair', ...attempts]),
95
+ ...restarted.blockers
96
+ ]
97
+ };
98
+ }
99
+ catch (error) {
100
+ return { ...base, ok: false, repaired: false, blockers: [String(error?.message || 'desktop_bridge_catalog_sync_failed')] };
101
+ }
102
+ }
@@ -644,7 +644,7 @@ export const COMMAND_CATALOG = [
644
644
  { name: 'uninstall', usage: 'sks uninstall [--dry-run] [--yes] [--keep-config] [--keep-data] [--purge-projects] [--json]', description: 'Remove SKS global skills, hooks, menu bar, state, temp files, and optional project residue while preserving user-owned content by default.' },
645
645
  { name: 'deps', usage: 'sks deps check [--json] [--yes]', description: 'Check Node/npm and Codex CLI readiness; pass --yes to repair missing Codex CLI tooling when supported.' },
646
646
  { name: 'codex', usage: 'sks codex compatibility|version|update-status [--refresh]|update|doctor|schema|current [--json]', description: 'Check Codex CLI compatibility/version/update status, run the official `codex update`, and inspect current manifest, capability, and hook-schema evidence.' },
647
- { name: 'codex-app', usage: 'sks codex-app [check|status|restart|product-design|chrome-extension|pat status|remote-control]', description: 'Check Codex App integration, Desktop Bridge readiness, Product Design plugin readiness, Codex Chrome Extension web verification readiness, PAT-safe status, first-party MCP/plugin readiness, and Codex CLI remote-control availability. Provider routing is managed only by sks bridge.' },
647
+ { name: 'codex-app', usage: 'sks codex-app [check|status|restart|context-1m [status|on|off]|product-design|chrome-extension|pat status|remote-control]', description: 'Check Codex App integration, Desktop Bridge readiness, Product Design plugin readiness, Codex Chrome Extension web verification readiness, PAT-safe status, first-party MCP/plugin readiness, Codex CLI remote-control availability, and the opt-in GPT-5.6 Sol 1M context window toggle with automatic Codex restart. Provider routing is managed only by sks bridge.' },
648
648
  { name: 'codex-native', usage: 'sks codex-native status|feature-broker|invocation-plan|init-deep [--json]', description: 'Inspect Codex Native feature broker readiness, invocation routing, pattern evidence, and managed memory setup.' },
649
649
  { name: 'hooks', usage: 'sks hooks explain|status|trust-report|replay|codex-validate|warning-check ... [--json]', description: 'Explain Codex hook events, validate current vendored event output schemas, replay fixtures, and enforce warning-zero SKS hook policies.' },
650
650
  { name: 'remote', usage: 'sks remote readiness|machines|worker ... [--json]', description: 'Inspect official Codex Remote readiness and the allowlisted proof-aware SSH stdio worker surface.' },
@@ -0,0 +1,67 @@
1
+ import os from 'node:os';
2
+ import path from 'node:path';
3
+ export async function runCurrentPublicSurfaceReconcileStage(root) {
4
+ const [{ runDoctorCommandAliasCleanup }, { migrateSksProfilesToPerFile }, { cleanupRetiredRemoteBridgeLaunchAgent, quarantineRetiredRemoteBridgeBindings }] = await Promise.all([
5
+ import('../../doctor/command-alias-cleanup.js'),
6
+ import('../../auto-review.js'),
7
+ import('../../codex-app/menubar/migration.js')
8
+ ]);
9
+ const home = path.resolve(process.env.HOME || os.homedir());
10
+ const globalRuntimeRoot = path.resolve(process.env.SKS_GLOBAL_ROOT || path.join(home, '.sneakoscope-global'));
11
+ const publicSurface = await runDoctorCommandAliasCleanup({
12
+ root,
13
+ home,
14
+ globalRuntimeRoot,
15
+ fix: true,
16
+ managedGenerationAlreadyConverged: true
17
+ });
18
+ const profileMigration = await migrateSksProfilesToPerFile({ env: process.env }).catch((err) => ({
19
+ error: err?.message || String(err),
20
+ retired_profile_table_count: 0,
21
+ retired_profile_file_removed_count: 0
22
+ }));
23
+ const retiredLaunchAgent = await cleanupRetiredRemoteBridgeLaunchAgent({ home, env: process.env });
24
+ const retiredBindings = await quarantineRetiredRemoteBridgeBindings(root);
25
+ const remainingCount = Number(publicSurface.cleanup?.remaining_count || 0)
26
+ + Number(publicSurface.cleanup?.managed_runtime?.remaining_managed_artifact_count || 0)
27
+ + Number(publicSurface.cleanup?.project_guidance?.remaining_count || 0);
28
+ const blockers = [
29
+ ...(publicSurface.ok === true ? [] : ['public_surface_reconcile_failed']),
30
+ ...(retiredLaunchAgent.ok ? [] : retiredLaunchAgent.blockers),
31
+ ...(retiredBindings.ok ? [] : retiredBindings.blockers),
32
+ ...(profileMigration.error ? [`retired_profile_migration_failed:${profileMigration.error}`] : []),
33
+ ...(remainingCount > 0 ? [`public_surface_remaining:${remainingCount}`] : [])
34
+ ];
35
+ return {
36
+ ok: blockers.length === 0,
37
+ status: blockers.length ? 'failed' : 'ok',
38
+ actions: [
39
+ 'reconciled_current_public_surface',
40
+ ...(retiredLaunchAgent.status === 'removed' ? ['retired_remote_bridge_launch_agent_removed'] : []),
41
+ ...(retiredBindings.status === 'quarantined' ? ['retired_remote_bridge_bindings_quarantined'] : [])
42
+ ],
43
+ blockers,
44
+ warnings: [
45
+ ...(publicSurface.warnings || []),
46
+ ...retiredLaunchAgent.warnings,
47
+ ...retiredBindings.warnings
48
+ ],
49
+ detail: {
50
+ removed_skill_count: Number(publicSurface.cleanup?.removed_count || 0),
51
+ quarantined_skill_collision_count: Number(publicSurface.cleanup?.preserved_user_collision_count || 0),
52
+ removed_runtime_artifact_count: Number(publicSurface.cleanup?.managed_runtime?.removed_managed_artifact_count || 0),
53
+ quarantined_runtime_collision_count: Number(publicSurface.cleanup?.managed_runtime?.preserved_user_file_count || 0),
54
+ reconciled_guidance_count: Number(publicSurface.cleanup?.project_guidance?.reconciled_count || 0),
55
+ quarantined_guidance_collision_count: Number(publicSurface.cleanup?.project_guidance?.preserved_user_file_count || 0),
56
+ removed_retired_role_count: 0,
57
+ quarantined_retired_role_collision_count: 0,
58
+ retired_profile_table_count: Number(profileMigration.retired_profile_table_count || 0),
59
+ retired_profile_file_removed_count: Number(profileMigration.retired_profile_file_removed_count || 0),
60
+ retired_remote_bridge_launch_agent_status: retiredLaunchAgent.status,
61
+ retired_remote_bridge_binding_status: retiredBindings.status,
62
+ retired_remote_bridge_binding_count: retiredBindings.retired_binding_count,
63
+ retired_remote_bridge_binding_quarantine_path: retiredBindings.quarantine_path,
64
+ remaining_count: remainingCount
65
+ }
66
+ };
67
+ }
@@ -0,0 +1,45 @@
1
+ import os from 'node:os';
2
+ import path from 'node:path';
3
+ import { exists } from '../../fsx.js';
4
+ import { desktopBridgeServicePaths } from '../../codex-lb/desktop-service.js';
5
+ import { repairDoctorDesktopBridgeCatalog } from '../../doctor/desktop-bridge-catalog-repair.js';
6
+ export async function runDesktopBridgeCatalogRepairStage() {
7
+ const skip = (reason) => ({ ok: true, status: 'ok', actions: [reason], blockers: [], warnings: [] });
8
+ if (process.platform !== 'darwin')
9
+ return skip('desktop_bridge_catalog_repair_not_macos');
10
+ if (process.env.NODE_TEST_CONTEXT !== undefined)
11
+ return skip('desktop_bridge_catalog_repair_skipped_under_tests');
12
+ if (process.env.SKS_TEST_ISOLATION === '1')
13
+ return skip('desktop_bridge_catalog_repair_skipped_under_tests');
14
+ if (process.env.SKS_SKIP_BRIDGE_CATALOG_REPAIR === '1')
15
+ return skip('desktop_bridge_catalog_repair_disabled');
16
+ const home = path.resolve(process.env.HOME || os.homedir());
17
+ if (!(await exists(desktopBridgeServicePaths(home).settings_path))) {
18
+ return skip('desktop_bridge_catalog_repair_no_managed_bridge');
19
+ }
20
+ const repair = await repairDoctorDesktopBridgeCatalog({ fix: true }).catch((error) => ({
21
+ ok: false,
22
+ repaired: false,
23
+ warnings: [],
24
+ blockers: [`desktop_bridge_catalog_repair_failed:${error?.message || String(error)}`]
25
+ }));
26
+ if (repair.ok) {
27
+ return {
28
+ ok: true,
29
+ status: 'ok',
30
+ actions: [repair.repaired ? 'desktop_bridge_catalog_repaired' : 'desktop_bridge_catalog_clean'],
31
+ blockers: [],
32
+ warnings: repair.warnings || []
33
+ };
34
+ }
35
+ return {
36
+ ok: true,
37
+ status: 'ok',
38
+ actions: [],
39
+ blockers: [],
40
+ warnings: [
41
+ ...(repair.blockers || []).map((blocker) => `desktop_bridge_catalog_repair_incomplete:${blocker}`),
42
+ 'Desktop Bridge catalog still needs repair: run `sks doctor --fix`'
43
+ ]
44
+ };
45
+ }
@@ -10,6 +10,8 @@ import { enforceRetention } from '../retention.js';
10
10
  import { COMMANDS } from '../../cli/command-registry.js';
11
11
  import { reconcileLegacyManagedGeneration } from '../init/legacy-generation-convergence.js';
12
12
  import { runConfigFastModeNormalizeStage } from './update-migration-state/fast-mode-config.js';
13
+ import { runCurrentPublicSurfaceReconcileStage } from './update-migration-state/current-public-surface-stage.js';
14
+ import { runDesktopBridgeCatalogRepairStage } from './update-migration-state/desktop-bridge-catalog-repair-stage.js';
13
15
  import { runDesktopBridgeRestageStage } from './update-migration-state/desktop-bridge-restage.js';
14
16
  import { runSessionStateSplitStage } from './update-migration-state/session-state-split.js';
15
17
  import { runHookTrustRefreshStage, runOtherHarnessCleanupStage } from './update-migration-state/simple-stages.js';
@@ -264,73 +266,13 @@ const UPDATE_MIGRATION_STAGES = [
264
266
  id: 'desktop-bridge-restage',
265
267
  min_from_version: '0.0.0',
266
268
  run: runDesktopBridgeRestageStage
269
+ },
270
+ {
271
+ id: 'desktop-bridge-catalog-repair',
272
+ min_from_version: '0.0.0',
273
+ run: runDesktopBridgeCatalogRepairStage
267
274
  }
268
275
  ];
269
- async function runCurrentPublicSurfaceReconcileStage(root) {
270
- const [{ runDoctorCommandAliasCleanup }, { migrateSksProfilesToPerFile }, { cleanupRetiredRemoteBridgeLaunchAgent, quarantineRetiredRemoteBridgeBindings }] = await Promise.all([
271
- import('../doctor/command-alias-cleanup.js'),
272
- import('../auto-review.js'),
273
- import('../codex-app/menubar/migration.js')
274
- ]);
275
- const home = path.resolve(process.env.HOME || os.homedir());
276
- const globalRuntimeRoot = path.resolve(process.env.SKS_GLOBAL_ROOT || path.join(home, '.sneakoscope-global'));
277
- const publicSurface = await runDoctorCommandAliasCleanup({
278
- root,
279
- home,
280
- globalRuntimeRoot,
281
- fix: true,
282
- managedGenerationAlreadyConverged: true
283
- });
284
- const profileMigration = await migrateSksProfilesToPerFile({ env: process.env }).catch((err) => ({
285
- error: err?.message || String(err),
286
- retired_profile_table_count: 0,
287
- retired_profile_file_removed_count: 0
288
- }));
289
- const retiredLaunchAgent = await cleanupRetiredRemoteBridgeLaunchAgent({ home, env: process.env });
290
- const retiredBindings = await quarantineRetiredRemoteBridgeBindings(root);
291
- const remainingCount = Number(publicSurface.cleanup?.remaining_count || 0)
292
- + Number(publicSurface.cleanup?.managed_runtime?.remaining_managed_artifact_count || 0)
293
- + Number(publicSurface.cleanup?.project_guidance?.remaining_count || 0);
294
- const blockers = [
295
- ...(publicSurface.ok === true ? [] : ['public_surface_reconcile_failed']),
296
- ...(retiredLaunchAgent.ok ? [] : retiredLaunchAgent.blockers),
297
- ...(retiredBindings.ok ? [] : retiredBindings.blockers),
298
- ...(profileMigration.error ? [`retired_profile_migration_failed:${profileMigration.error}`] : []),
299
- ...(remainingCount > 0 ? [`public_surface_remaining:${remainingCount}`] : [])
300
- ];
301
- return {
302
- ok: blockers.length === 0,
303
- status: blockers.length ? 'failed' : 'ok',
304
- actions: [
305
- 'reconciled_current_public_surface',
306
- ...(retiredLaunchAgent.status === 'removed' ? ['retired_remote_bridge_launch_agent_removed'] : []),
307
- ...(retiredBindings.status === 'quarantined' ? ['retired_remote_bridge_bindings_quarantined'] : [])
308
- ],
309
- blockers,
310
- warnings: [
311
- ...(publicSurface.warnings || []),
312
- ...retiredLaunchAgent.warnings,
313
- ...retiredBindings.warnings
314
- ],
315
- detail: {
316
- removed_skill_count: Number(publicSurface.cleanup?.removed_count || 0),
317
- quarantined_skill_collision_count: Number(publicSurface.cleanup?.preserved_user_collision_count || 0),
318
- removed_runtime_artifact_count: Number(publicSurface.cleanup?.managed_runtime?.removed_managed_artifact_count || 0),
319
- quarantined_runtime_collision_count: Number(publicSurface.cleanup?.managed_runtime?.preserved_user_file_count || 0),
320
- reconciled_guidance_count: Number(publicSurface.cleanup?.project_guidance?.reconciled_count || 0),
321
- quarantined_guidance_collision_count: Number(publicSurface.cleanup?.project_guidance?.preserved_user_file_count || 0),
322
- removed_retired_role_count: 0,
323
- quarantined_retired_role_collision_count: 0,
324
- retired_profile_table_count: Number(profileMigration.retired_profile_table_count || 0),
325
- retired_profile_file_removed_count: Number(profileMigration.retired_profile_file_removed_count || 0),
326
- retired_remote_bridge_launch_agent_status: retiredLaunchAgent.status,
327
- retired_remote_bridge_binding_status: retiredBindings.status,
328
- retired_remote_bridge_binding_count: retiredBindings.retired_binding_count,
329
- retired_remote_bridge_binding_quarantine_path: retiredBindings.quarantine_path,
330
- remaining_count: remainingCount
331
- }
332
- };
333
- }
334
276
  export async function runUpdateMigrationStages(root, opts = {}) {
335
277
  const fromVersion = opts.fromVersion || null;
336
278
  const runs = [];
@@ -1 +1 @@
1
- export const PACKAGE_VERSION = '9.0.5';
1
+ export const PACKAGE_VERSION = '9.1.0';
@@ -30,7 +30,7 @@ final class ControlCenterWindowController: NSWindowController, NSTableViewDataSo
30
30
  .providers: ProvidersViewController(processClient: processClient, operations: operations),
31
31
  .remoteCoding: RemoteCodingViewController(),
32
32
  .diagnostics: DiagnosticsViewController(processClient: processClient, operations: operations),
33
- .settings: SettingsViewController(notifications: notifications)
33
+ .settings: SettingsViewController(processClient: processClient, operations: operations, notifications: notifications)
34
34
  ]
35
35
  let window = NSWindow(
36
36
  contentRect: NSRect(x: 0, y: 0, width: 860, height: 560),
@@ -8,22 +8,41 @@ final class SettingsViewController: NSViewController, ControlCenterPage {
8
8
  case malformed
9
9
  }
10
10
 
11
+ private let processClient: ProcessClient
12
+ private let operations: OperationCoordinator
11
13
  private let notifications: NotificationCoordinator
12
14
  private let followCodexLifecycle = NSButton(checkboxWithTitle: "Show SKS Menu only while Codex is running", target: nil, action: nil)
13
15
  private let status = NativeView.detail("Settings use the native app configuration file.")
16
+ private let contextStatus = NativeView.detail("Codex 1M context: checking current state…")
14
17
  private var notificationButton: NSButton!
15
- init(notifications: NotificationCoordinator) { self.notifications = notifications; super.init(nibName: nil, bundle: nil) }
18
+ private var contextToggleButton: NSButton!
19
+ private var contextEnabled: Bool?
20
+ private var contextBusy = false
21
+ private var contextGeneration = 0
22
+ init(processClient: ProcessClient, operations: OperationCoordinator, notifications: NotificationCoordinator) {
23
+ self.processClient = processClient
24
+ self.operations = operations
25
+ self.notifications = notifications
26
+ super.init(nibName: nil, bundle: nil)
27
+ }
16
28
  required init?(coder: NSCoder) { nil }
17
29
 
18
30
  override func loadView() {
19
31
  followCodexLifecycle.target = self; followCodexLifecycle.action = #selector(save)
20
32
  followCodexLifecycle.setAccessibilityLabel("Show SKS Menu only while Codex is running")
21
33
  notificationButton = NativeView.button("Enable Notifications", target: self, action: #selector(enableNotifications))
34
+ contextToggleButton = NativeView.button("Enable 1M Context", target: self, action: #selector(toggleContext1m))
35
+ contextToggleButton.isEnabled = false
22
36
  let lifecycleCard = NativeView.card(
23
37
  title: "Codex lifecycle",
24
38
  subtitle: "On keeps a lightweight observer running, hides the icon when Codex is closed, and shows it automatically when Codex opens.",
25
39
  views: [followCodexLifecycle]
26
40
  )
41
+ let contextCard = NativeView.card(
42
+ title: "Codex 1M Context",
43
+ subtitle: "Opt Codex into the documented 1,000,000-token context window for GPT-5.6 Sol (model_context_window = 1000000, model_auto_compact_token_limit = 900000 in ~/.codex/config.toml). Requests beyond 272K input tokens bill the entire request at the long-context rate, only new sessions pick up the change, and Codex restarts automatically when it is running. Off restores the previous value.",
44
+ views: [NativeView.row([contextToggleButton]), contextStatus]
45
+ )
27
46
  let notificationsCard = NativeView.card(
28
47
  title: "Notifications",
29
48
  subtitle: "Operation results always stay available in Control Center, even when notifications are denied.",
@@ -31,11 +50,12 @@ final class SettingsViewController: NSViewController, ControlCenterPage {
31
50
  )
32
51
  view = NativeView.page([
33
52
  ControlKit.header("Settings", "These options stay on this Mac. Notification permission and Codex lifecycle behavior never leave the machine."),
34
- lifecycleCard, notificationsCard
53
+ lifecycleCard, contextCard, notificationsCard
35
54
  ])
36
55
  }
37
56
 
38
57
  func refreshOnAppear() {
58
+ refreshContext1m()
39
59
  let configResult = readConfig()
40
60
  switch configResult {
41
61
  case .loaded(let config):
@@ -67,6 +87,101 @@ final class SettingsViewController: NSViewController, ControlCenterPage {
67
87
  }
68
88
  }
69
89
 
90
+ private func refreshContext1m(preserveStatusText: Bool = false) {
91
+ contextGeneration += 1
92
+ let requestGeneration = contextGeneration
93
+ processClient.run(["codex-app", "context-1m", "status", "--json"], timeout: NativeView.statusTimeout) { [weak self] result in
94
+ guard let self = self, self.contextGeneration == requestGeneration, !self.contextBusy else { return }
95
+ guard let json = self.json(result.output),
96
+ json["schema"] as? String == "sks.codex-context-1m.v1",
97
+ json["ok"] as? Bool == true,
98
+ let enabled = json["enabled"] as? Bool else {
99
+ self.contextEnabled = nil
100
+ self.contextToggleButton.isEnabled = false
101
+ if !preserveStatusText {
102
+ self.contextStatus.stringValue = "Codex 1M context state unavailable · update SKS, then reopen Settings."
103
+ self.contextStatus.textColor = .systemOrange
104
+ }
105
+ return
106
+ }
107
+ self.contextEnabled = enabled
108
+ self.contextToggleButton.isEnabled = true
109
+ self.contextToggleButton.title = enabled ? "Disable 1M Context" : "Enable 1M Context"
110
+ guard !preserveStatusText else { return }
111
+ let model = json["model"] as? String
112
+ var text = enabled
113
+ ? "Enabled · window 1,000,000 · auto-compact 900,000 · applies to new sessions only."
114
+ : "Disabled · Codex uses its tuned default context window."
115
+ var tone: NSColor = enabled ? .systemGreen : .secondaryLabelColor
116
+ if enabled, let model = model, model != "gpt-5.6-sol" {
117
+ text += " Active model is \(model); the 1M window is documented for gpt-5.6-sol."
118
+ tone = .systemOrange
119
+ }
120
+ self.contextStatus.stringValue = text
121
+ self.contextStatus.textColor = tone
122
+ }
123
+ }
124
+
125
+ @objc private func toggleContext1m() {
126
+ guard !contextBusy, let enabled = contextEnabled else { return }
127
+ let verb = enabled ? "off" : "on"
128
+ guard let snapshot = operations.begin(
129
+ kind: "codex-context-1m",
130
+ mutationGroup: "codex-config",
131
+ summary: enabled ? "Disable Codex 1M context" : "Enable Codex 1M context"
132
+ ) else {
133
+ contextStatus.stringValue = "Another guarded mutation is running. Try again after it completes."
134
+ contextStatus.textColor = .systemOrange
135
+ return
136
+ }
137
+ contextBusy = true
138
+ contextToggleButton.isEnabled = false
139
+ contextStatus.stringValue = enabled ? "Disabling 1M context…" : "Enabling 1M context and restarting Codex if it is running…"
140
+ contextStatus.textColor = .secondaryLabelColor
141
+ _ = operations.update(snapshot, state: .running, stage: "applying", progress: nil, summary: contextStatus.stringValue)
142
+ processClient.run(["codex-app", "context-1m", verb, "--json"], timeout: NativeView.mutationTimeout) { [weak self] result in
143
+ guard let self = self else { return }
144
+ self.contextBusy = false
145
+ self.contextToggleButton.isEnabled = true
146
+ let json = self.json(result.output)
147
+ let ok = result.code == 0
148
+ && json?["schema"] as? String == "sks.codex-context-1m.v1"
149
+ && json?["ok"] as? Bool == true
150
+ let summary: String
151
+ if ok {
152
+ let restart = json?["restart"] as? [String: Any]
153
+ let applied = verb == "on" ? "1M context enabled" : "1M context disabled"
154
+ if restart?["status"] as? String == "restarted" {
155
+ summary = "\(applied) · Codex restarted — start a new session to apply it."
156
+ } else if restart?["reason"] as? String == "codex_not_running" {
157
+ summary = "\(applied) · Codex is not running — the change applies on its next launch."
158
+ } else if restart?["reason"] as? String == "config_unchanged" {
159
+ summary = "\(applied) · configuration already matched; nothing restarted."
160
+ } else {
161
+ summary = "\(applied) · restart Codex manually, then start a new session."
162
+ }
163
+ } else {
164
+ let blocker = (json?["blockers"] as? [String])?.first
165
+ summary = blocker.map { "1M context change failed · \($0)" } ?? "1M context change failed · unexpected CLI response."
166
+ }
167
+ _ = self.operations.update(snapshot, state: ok ? .succeeded : .failed, stage: "complete", progress: 1, summary: summary)
168
+ self.contextStatus.stringValue = summary
169
+ self.contextStatus.textColor = ok ? .systemGreen : .systemRed
170
+ self.refreshContext1m(preserveStatusText: true)
171
+ }
172
+ }
173
+
174
+ private func json(_ text: String) -> [String: Any]? {
175
+ guard let data = text.data(using: .utf8) else { return nil }
176
+ if let object = try? JSONSerialization.jsonObject(with: data) as? [String: Any] { return object }
177
+ // Child processes may print banner lines before JSON; prefer the last
178
+ // top-level object payload, matching the Overview parser.
179
+ guard let start = text.range(of: "{", options: [.backwards])?.lowerBound else { return nil }
180
+ let slice = String(text[start...])
181
+ guard let sliced = slice.data(using: .utf8) else { return nil }
182
+ return try? JSONSerialization.jsonObject(with: sliced) as? [String: Any]
183
+ }
184
+
70
185
  @objc private func enableNotifications() {
71
186
  if notifications.authorizationDenied {
72
187
  guard openSystemSettings() else {
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "sneakoscope",
3
3
  "displayName": "ㅅㅋㅅ",
4
- "version": "9.0.5",
4
+ "version": "9.1.0",
5
5
  "description": "Sneakoscope Codex (`sks`) is an open-source trust layer for Codex CLI and ChatGPT Desktop. It coordinates bounded AI coding agents, records machine-verifiable evidence, preserves project memory, and blocks release claims that are not supported by current tests or artifacts. Search visibility outcomes are measured separately; SKS does not promise rankings or traffic.",
6
6
  "type": "module",
7
7
  "homepage": "https://github.com/mandarange/Sneakoscope-Codex#readme",