sneakoscope 4.0.15 → 4.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.
Files changed (46) hide show
  1. package/README.md +10 -1
  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/install-helpers.js +12 -0
  7. package/dist/cli/router.js +8 -0
  8. package/dist/commands/doctor.js +89 -25
  9. package/dist/core/agents/agent-role-config.js +18 -41
  10. package/dist/core/codex-app/codex-agent-role-sync.js +3 -3
  11. package/dist/core/codex-control/codex-app-server-v2-client.js +1 -1
  12. package/dist/core/codex-native/codex-native-feature-broker.js +63 -10
  13. package/dist/core/codex-native/codex-native-feature-matrix.js +11 -2
  14. package/dist/core/commands/basic-cli.js +9 -0
  15. package/dist/core/doctor/codex-doctor-bridge.js +135 -21
  16. package/dist/core/doctor/doctor-dirty-planner.js +43 -4
  17. package/dist/core/doctor/doctor-readiness-matrix.js +117 -5
  18. package/dist/core/doctor/doctor-repair-postcheck.js +3 -2
  19. package/dist/core/doctor/doctor-transaction.js +10 -3
  20. package/dist/core/fsx.js +1 -1
  21. package/dist/core/init.js +2 -2
  22. package/dist/core/managed-assets/managed-assets-manifest.js +106 -0
  23. package/dist/core/providers/glm/bench/glm-benchmark-runner.js +3 -3
  24. package/dist/core/providers/glm/bench/glm-benchmark-types.js +1 -1
  25. package/dist/core/routes.js +8 -4
  26. package/dist/core/update/update-migration-state.js +280 -0
  27. package/dist/core/update-check.js +151 -4
  28. package/dist/core/version.js +1 -1
  29. package/dist/scripts/codex-0142-doctor-wiring-check.js +21 -0
  30. package/dist/scripts/codex-0142-manifest-check.js +1 -1
  31. package/dist/scripts/doctor-fix-production-blackbox.js +4 -4
  32. package/dist/scripts/doctor-plain-fix-native-assets-check.js +12 -0
  33. package/dist/scripts/doctor-post-repair-authoritative-check.js +39 -0
  34. package/dist/scripts/doctor-transaction-owns-mutations-check.js +14 -0
  35. package/dist/scripts/doctor-warning-only-not-blocker-check.js +39 -0
  36. package/dist/scripts/loop-directive-check-lib.js +1 -1
  37. package/dist/scripts/machine-local-evidence-zero-check.js +22 -0
  38. package/dist/scripts/managed-role-manifest-parity-check.js +20 -0
  39. package/dist/scripts/postinstall-global-doctor-blackbox.js +12 -0
  40. package/dist/scripts/update-concurrent-lock-check.js +10 -0
  41. package/dist/scripts/update-doctor-lifecycle-check.js +13 -0
  42. package/dist/scripts/update-first-command-migration-check.js +13 -0
  43. package/dist/scripts/update-new-binary-reexec-check.js +12 -0
  44. package/package.json +13 -1
  45. package/schemas/doctor-status-v2.schema.json +42 -0
  46. package/schemas/update-migration.schema.json +35 -0
package/README.md CHANGED
@@ -35,7 +35,16 @@ Set up this agent project with Sneakoscope Codex. Use [[mandarange/Sneakoscope-C
35
35
 
36
36
  ## 🚀 Current Release
37
37
 
38
- SKS **4.0.15** prepares the Codex `rust-v0.142.0` compatibility surface while preserving the existing GPT/Codex/MAD `sks --mad` route. The release pins `@openai/codex-sdk` to `0.142.0`, records a Codex release manifest, resolves one Codex binary identity per mission, isolates SDK child environment variables, and restores the published tarball script contract by shipping the verification scripts that package metadata exposes.
38
+ SKS **4.1.0** turns the Codex `rust-v0.142.0` compatibility surface into the authoritative Doctor/update readiness path. Doctor now consumes structured Codex Doctor semantics, separates pre-repair observation from post-repair truth, repairs managed native assets from plain `sks doctor --fix`, and gates update completion on a current project migration receipt.
39
+
40
+ What changed in 4.1.0:
41
+
42
+ - **Semantic Doctor readiness.** Warning-only Codex Doctor output stays ready, blocking checks block readiness, and unknown non-zero/unparseable Doctor output fails closed.
43
+ - **Post-repair authority.** `sks doctor --fix` records pre-repair Codex Doctor output but bases readiness on the final post-repair Doctor run.
44
+ - **Managed native assets.** Skills, agent roles, hooks, and Context7 transport share the 4.1.0 managed manifest; stale directive markers no longer appear in generated role content.
45
+ - **Codex 0.142 wiring.** The native feature broker exposes multi-agent mode, rollout budget strategy, indexed web search, current time, app-server overload, MCP reconnect, plugin refresh, thread search, remote native environment, and terminal subagent error handling as current capabilities.
46
+ - **Update lifecycle receipts.** `sks update now` runs old-version Doctor preflight, installs through the guarded npm path, re-resolves the new package-local binary, runs new-version global Doctor, and writes a project migration receipt before reporting `updated`.
47
+ - **Local evidence hygiene.** Machine-local `.sneakoscope` runtime evidence is ignored and guarded so release commits do not carry host paths, secrets, or transient proof logs.
39
48
 
40
49
  What changed in 4.0.15:
41
50
 
@@ -76,7 +76,7 @@ dependencies = [
76
76
 
77
77
  [[package]]
78
78
  name = "sks-core"
79
- version = "4.0.15"
79
+ version = "4.1.0"
80
80
  dependencies = [
81
81
  "serde_json",
82
82
  ]
@@ -1,6 +1,6 @@
1
1
  [package]
2
2
  name = "sks-core"
3
- version = "4.0.15"
3
+ version = "4.1.0"
4
4
  edition = "2021"
5
5
 
6
6
  [dependencies]
@@ -4,7 +4,7 @@ use std::io::{self, Read, Seek, SeekFrom};
4
4
  fn main() {
5
5
  let mut args = std::env::args().skip(1);
6
6
  match args.next().as_deref() {
7
- Some("--version") => println!("sks-rs 4.0.15"),
7
+ Some("--version") => println!("sks-rs 4.1.0"),
8
8
  Some("compact-info") => {
9
9
  let mut input = String::new();
10
10
  let _ = io::stdin().read_to_string(&mut input);
package/dist/bin/sks.js CHANGED
@@ -1,5 +1,5 @@
1
1
  #!/usr/bin/env node
2
- const FAST_PACKAGE_VERSION = '4.0.15';
2
+ const FAST_PACKAGE_VERSION = '4.1.0';
3
3
  const args = process.argv.slice(2);
4
4
  try {
5
5
  if (args[0] === '--agent' && args[1] === 'worker') {
@@ -15,6 +15,7 @@ import { reconcileCodexAppUpgradeProcesses } from '../core/codex-app.js';
15
15
  import { recordCodexLbHealthEvent } from '../core/codex-lb-circuit.js';
16
16
  import { loadCodexLbEnv, writeCodexLbKeychain, codexLbMetadataPath } from '../core/codex-lb/codex-lb-env.js';
17
17
  import { buildCodexLbSetupPlan, codexLbPersistenceSummary, installCodexLbShellProfileSnippet, selectedCodexLbPersistenceModes } from '../core/codex-lb/codex-lb-setup.js';
18
+ import { runPostinstallGlobalDoctorAndMarkPending } from '../core/update/update-migration-state.js';
18
19
  const DEFAULT_CODEX_APP_PLUGINS = [
19
20
  ['browser', 'openai-bundled'],
20
21
  ['chrome', 'openai-bundled'],
@@ -80,6 +81,17 @@ export async function postinstall({ bootstrap, args = [] }) {
80
81
  console.log(`Codex App Fast mode: skipped (${fastModeRepair.reason}).`);
81
82
  else if (fastModeRepair.status === 'failed')
82
83
  console.log(`Codex App Fast mode: auto repair failed. Run \`sks setup\`. ${fastModeRepair.error || ''}`.trim());
84
+ const postinstallDoctor = await runPostinstallGlobalDoctorAndMarkPending().catch((err) => ({
85
+ ok: false,
86
+ doctor: null,
87
+ pending: null,
88
+ blockers: [err?.message || String(err)],
89
+ warnings: []
90
+ }));
91
+ if (postinstallDoctor.ok)
92
+ console.log('SKS update migration: global Doctor ran; project receipt will be finalized on first normal command.');
93
+ else
94
+ console.log(`SKS update migration: global Doctor did not complete; first normal command will retry. ${(postinstallDoctor.blockers || []).join(', ')}`.trim());
83
95
  // Terminating a third-party app's processes during `npm i` is unsafe by default; opt-in only.
84
96
  const appProcessRepair = process.env.SKS_POSTINSTALL_RECONCILE_APP_PROCESSES === '1'
85
97
  ? await reconcileCodexAppUpgradeProcesses()
@@ -1,5 +1,6 @@
1
1
  import { COMMAND_ALIASES, COMMANDS, } from './command-registry.js';
2
2
  import { detectGlobalMode, glmWithoutMadResult } from './global-mode-router.js';
3
+ import { ensureCurrentMigrationBeforeCommand } from '../core/update/update-migration-state.js';
3
4
  export function isCommandName(value) {
4
5
  return Object.prototype.hasOwnProperty.call(COMMANDS, value);
5
6
  }
@@ -48,6 +49,13 @@ export async function dispatch(args) {
48
49
  return result;
49
50
  }
50
51
  const entry = COMMANDS[command];
52
+ const migrationGate = await ensureCurrentMigrationBeforeCommand({ command, args: rest });
53
+ if (!migrationGate.ok) {
54
+ console.error(`SKS update migration blocked: ${migrationGate.blockers.join(', ')}`);
55
+ console.error('Run: sks doctor --fix --yes');
56
+ process.exitCode = 1;
57
+ return migrationGate;
58
+ }
51
59
  const mod = await entry.lazy();
52
60
  if (typeof mod.run !== 'function')
53
61
  throw new Error(`Command ${command} must export run(command, args)`);
@@ -49,10 +49,12 @@ async function runDoctor(args = [], root, doctorFix) {
49
49
  let setupRepair = null;
50
50
  const sksUpdate = doctorFix
51
51
  ? {
52
- schema: 'sks.update-now.v1',
52
+ schema: 'sks.update-now.v2',
53
53
  ok: true,
54
54
  status: 'skipped',
55
- reason: 'manual_update_commands_only'
55
+ reason: 'manual_update_commands_only',
56
+ stages: [],
57
+ migration_current: true
56
58
  }
57
59
  : null;
58
60
  let migrationPreFix = null;
@@ -145,9 +147,9 @@ async function runDoctor(args = [], root, doctorFix) {
145
147
  ? await writeFixMigrationJournal(root, migrationPreFix, configRepair, setupRepair).catch(() => null)
146
148
  : null;
147
149
  let codexConfig = configRepair?.after || await inspectCodexConfigReadability(root, configProbeOpts);
148
- const codexDoctor = await runCodexDoctorBridge({ codexBin: codexBin || null, cwd: root, required: flag(args, '--require-actual-codex') });
149
- const codexDoctorDiff = compareCodexDoctorBridge(codexDoctorBefore, codexDoctor);
150
- codexStartupRepair = mergeObservedCodexStartupWarnings(codexStartupRepair, codexDoctor);
150
+ const preRepairCodexDoctor = await runCodexDoctorBridge({ codexBin: codexBin || null, cwd: root, required: flag(args, '--require-actual-codex') });
151
+ const codexDoctorDiff = compareCodexDoctorBridge(codexDoctorBefore, preRepairCodexDoctor);
152
+ codexStartupRepair = mergeObservedCodexStartupWarnings(codexStartupRepair, preRepairCodexDoctor);
151
153
  const codex = codexBin
152
154
  ? { bin: codexBin, version: 'fixture-or-explicit', available: true }
153
155
  : await getCodexInfo().catch(() => ({ bin: null, version: null, available: false }));
@@ -308,7 +310,8 @@ async function runDoctor(args = [], root, doctorFix) {
308
310
  id: 'setup',
309
311
  ok: setupRepair !== null,
310
312
  repaired: setupRepair !== null,
311
- blockers: setupRepair === null ? ['setup_repair_not_recorded'] : []
313
+ blockers: setupRepair === null ? ['setup_repair_not_recorded'] : [],
314
+ rollback_evidence: setupRepair?.config_backup_path || 'setup_force_regeneration_idempotent_manifest'
312
315
  })
313
316
  },
314
317
  {
@@ -318,7 +321,8 @@ async function runDoctor(args = [], root, doctorFix) {
318
321
  ok: codexStartupRepair?.ok !== false,
319
322
  repaired: doctorFix,
320
323
  blockers: codexStartupRepair?.blockers || [],
321
- warnings: codexStartupRepair?.warnings || []
324
+ warnings: codexStartupRepair?.warnings || [],
325
+ rollback_evidence: codexStartupRepair?.report_path || 'codex_startup_repair_report'
322
326
  })
323
327
  },
324
328
  {
@@ -327,7 +331,8 @@ async function runDoctor(args = [], root, doctorFix) {
327
331
  id: 'startup_config_repair',
328
332
  ok: startupConfigRepair?.ok === true,
329
333
  repaired: startupConfigRepair?.apply === true,
330
- blockers: startupConfigRepair?.blockers || []
334
+ blockers: startupConfigRepair?.blockers || [],
335
+ rollback_evidence: startupConfigRepair?.backup_path || 'startup_config_repair_idempotent_report'
331
336
  })
332
337
  },
333
338
  {
@@ -337,7 +342,8 @@ async function runDoctor(args = [], root, doctorFix) {
337
342
  ok: context7Repair?.ok !== false,
338
343
  repaired: doctorFix,
339
344
  blockers: context7Repair?.blockers || [],
340
- warnings: context7Repair?.warnings || []
345
+ warnings: context7Repair?.warnings || [],
346
+ rollback_evidence: context7Repair?.report_path || 'context7_repair_report'
341
347
  })
342
348
  },
343
349
  {
@@ -348,7 +354,8 @@ async function runDoctor(args = [], root, doctorFix) {
348
354
  repaired: context7McpRepair?.repaired === true,
349
355
  manual_required: context7McpRepair?.manual_required === true,
350
356
  blockers: context7McpRepair?.blockers || [],
351
- warnings: context7McpRepair?.warnings || []
357
+ warnings: context7McpRepair?.warnings || [],
358
+ rollback_evidence: context7McpRepair?.backup_path || 'context7_mcp_repair_idempotent_report'
352
359
  })
353
360
  },
354
361
  {
@@ -361,7 +368,8 @@ async function runDoctor(args = [], root, doctorFix) {
361
368
  manual_required: supabaseMcpRepair?.manual_required === true,
362
369
  required_for_ready: false,
363
370
  blockers: supabaseMcpRepair?.blockers || [],
364
- warnings: supabaseMcpRepair?.warnings || []
371
+ warnings: supabaseMcpRepair?.warnings || [],
372
+ rollback_evidence: 'optional_supabase_no_ready_mutation_required'
365
373
  })
366
374
  },
367
375
  {
@@ -370,7 +378,8 @@ async function runDoctor(args = [], root, doctorFix) {
370
378
  id: 'command_alias_cleanup',
371
379
  ok: commandAliasCleanup?.ok !== false,
372
380
  repaired: Array.isArray(commandAliasCleanup?.actions) && commandAliasCleanup.actions.length > 0,
373
- blockers: commandAliasCleanup?.blockers || []
381
+ blockers: commandAliasCleanup?.blockers || [],
382
+ rollback_evidence: commandAliasCleanup?.report_path || 'command_alias_cleanup_report'
374
383
  })
375
384
  },
376
385
  {
@@ -379,14 +388,17 @@ async function runDoctor(args = [], root, doctorFix) {
379
388
  id: 'native_capability_repair',
380
389
  ok: doctorNativeCapabilityRepair?.ok !== false,
381
390
  repaired: doctorFix,
382
- blockers: doctorNativeCapabilityRepair?.blockers || []
391
+ blockers: doctorNativeCapabilityRepair?.blockers || [],
392
+ rollback_evidence: doctorNativeCapabilityRepair?.secret_preservation_guard || 'native_capability_repair_report'
383
393
  })
384
394
  }
385
395
  ]
386
396
  }).catch((err) => ({
387
- schema: 'sks.doctor-fix-transaction.v1',
397
+ schema: 'sks.doctor-fix-transaction.v2',
398
+ generated_at: new Date().toISOString(),
388
399
  ok: false,
389
400
  postcheck_ok: false,
401
+ dirty_plan: doctorDirtyPlan,
390
402
  phases: [
391
403
  {
392
404
  id: 'doctor_fix_transaction',
@@ -395,9 +407,11 @@ async function runDoctor(args = [], root, doctorFix) {
395
407
  manual_required: false,
396
408
  blockers: [err?.message || String(err)],
397
409
  warnings: [],
398
- artifact_path: null
410
+ artifact_path: null,
411
+ rollback_evidence: null
399
412
  }
400
413
  ],
414
+ mutations_without_rollback: 0,
401
415
  rollback_performed: false,
402
416
  raw_secret_values_recorded: false
403
417
  }))
@@ -432,7 +446,7 @@ async function runDoctor(args = [], root, doctorFix) {
432
446
  const mcpPluginInventory = pluginInventory?.report
433
447
  ? await writeMcpPluginInventoryArtifacts(root, { inventory: pluginInventory.report }).catch((err) => ({ error: err?.message || String(err), candidates: null }))
434
448
  : null;
435
- const repairCodexNative = doctorFix && flag(args, '--repair-codex-native');
449
+ const repairCodexNative = doctorFix;
436
450
  const codexNativeRepair = repairCodexNative
437
451
  ? await repairCodexNativeManagedAssets({
438
452
  root,
@@ -485,13 +499,41 @@ async function runDoctor(args = [], root, doctorFix) {
485
499
  if (reinspected)
486
500
  codexConfig = reinspected;
487
501
  }
502
+ const postRepairCodexDoctor = doctorFix
503
+ ? await runCodexDoctorBridge({ codexBin: codexBin || null, cwd: root, required: flag(args, '--fix') || flag(args, '--require-actual-codex') }).catch((err) => ({
504
+ schema: 'sks.codex-doctor-bridge.v2',
505
+ generated_at: new Date().toISOString(),
506
+ available: false,
507
+ exit_code: null,
508
+ process_exit_code: null,
509
+ disposition: 'block',
510
+ semantic_ok: false,
511
+ source_format: 'text-fallback',
512
+ blocking_checks: [],
513
+ warning_checks: [],
514
+ informational_checks: [],
515
+ environment_diagnostics_ok: false,
516
+ git_diagnostics_ok: false,
517
+ terminal_diagnostics_ok: false,
518
+ app_server_diagnostics_ok: false,
519
+ thread_inventory_ok: false,
520
+ stdout_tail: '',
521
+ stderr_tail: '',
522
+ blockers: [`post_repair_codex_doctor_exception:${err?.message || String(err)}`],
523
+ warnings: []
524
+ }))
525
+ : preRepairCodexDoctor;
526
+ const authoritativeCodexDoctor = postRepairCodexDoctor;
527
+ const codexDoctorAuthoritativeDiff = compareCodexDoctorBridge(codexDoctorBefore, authoritativeCodexDoctor);
488
528
  const pkgBytes = await dirSize(root).catch(() => 0);
489
529
  const ready = await writeDoctorReadinessMatrix(root, {
490
530
  codex,
491
531
  codex_config: codexConfig,
492
532
  codex_app: codexApp,
493
533
  codex_lb: codexLb,
494
- codex_doctor: codexDoctor,
534
+ codex_doctor: authoritativeCodexDoctor,
535
+ pre_repair_codex_doctor: preRepairCodexDoctor,
536
+ post_repair_codex_doctor: postRepairCodexDoctor,
495
537
  require_codex_doctor: flag(args, '--fix') || flag(args, '--require-actual-codex'),
496
538
  zellij,
497
539
  context7_repair: context7Repair,
@@ -502,6 +544,7 @@ async function runDoctor(args = [], root, doctorFix) {
502
544
  doctor_fix_transaction: doctorFixTransaction,
503
545
  doctor_dirty_plan: doctorDirtyPlan,
504
546
  doctor_fix_postcheck: doctorFixPostcheck,
547
+ doctor_native_capability: doctorNativeCapabilityRepair,
505
548
  local_model: localModel,
506
549
  agent_role_config: agentRoleConfigRepair,
507
550
  repair: configRepair,
@@ -522,7 +565,7 @@ async function runDoctor(args = [], root, doctorFix) {
522
565
  const zellijReadiness = buildZellijReadiness(root, zellij, ready);
523
566
  const runtimeReadiness = buildRuntimeReadiness(zellijReadiness, codexNativeFeatureMatrix);
524
567
  const result = {
525
- schema: 'sks.doctor-status.v1',
568
+ schema: 'sks.doctor-status.v2',
526
569
  ok: ready.ready && (!sksUpdate || sksUpdate.ok !== false) && commandAliasCleanup.ok !== false && codexStartupRepair.ok !== false && (!doctorFixPostcheck || doctorFixPostcheck.ok !== false),
527
570
  root,
528
571
  node: { ok: Number(process.versions.node.split('.')[0]) >= 20, version: process.version },
@@ -533,8 +576,11 @@ async function runDoctor(args = [], root, doctorFix) {
533
576
  codex_app_ui: codexAppUi,
534
577
  provider_context: providerContext,
535
578
  codex_lb: codexLb,
536
- codex_doctor: codexDoctor,
537
- codex_doctor_diff: codexDoctorDiff,
579
+ codex_doctor: authoritativeCodexDoctor,
580
+ pre_repair_codex_doctor: preRepairCodexDoctor,
581
+ post_repair_codex_doctor: postRepairCodexDoctor,
582
+ codex_doctor_diff: codexDoctorAuthoritativeDiff,
583
+ observational_codex_doctor_diff: codexDoctorDiff,
538
584
  zellij,
539
585
  zellij_repair: zellijRepair,
540
586
  context7_repair: context7Repair,
@@ -609,7 +655,7 @@ async function runDoctor(args = [], root, doctorFix) {
609
655
  console.log(` manual: ${action}`);
610
656
  for (const warning of codexStartupRepair.warnings || [])
611
657
  console.log(` warning: ${warning}`);
612
- console.log(` codex doctor: ${codexDoctor.available ? (codexDoctor.exit_code === 0 ? 'ok' : 'warning') : 'unavailable'}`);
658
+ console.log(` codex doctor: ${authoritativeCodexDoctor.available ? (authoritativeCodexDoctor.disposition || (authoritativeCodexDoctor.exit_code === 0 ? 'pass' : 'warn')) : 'unavailable'}`);
613
659
  console.log(`Rust acc.: ${rust.mode || (rust.available ? 'rust_accelerated' : 'js_fallback')} ${rust.version || rust.status || ''}`);
614
660
  console.log(`Codex App: ${ready.codex_app_ready ? 'ok' : 'optional_missing'}`);
615
661
  console.log('SKS Runtime Readiness:');
@@ -686,7 +732,14 @@ async function runDoctor(args = [], root, doctorFix) {
686
732
  }
687
733
  }
688
734
  const codex0138 = codex0138Capability.report || {};
689
- console.log('Codex 0.138 features:');
735
+ console.log('Codex current compatibility:');
736
+ console.log(` target: rust-v0.142.0`);
737
+ console.log(` runtime: ${codex.version || 'unknown'}`);
738
+ console.log(` multi-agent mode: ${codexNativeFeatureMatrix.features?.multi_agent_mode?.ok ? 'verified' : 'unverified'}`);
739
+ console.log(` rollout budget: ${codexNativeFeatureMatrix.features?.rollout_budget?.ok ? 'verified' : 'unverified'}`);
740
+ console.log(` indexed search: ${codexNativeFeatureMatrix.features?.indexed_web_search?.ok ? 'verified' : 'unverified'}`);
741
+ console.log(` current time: ${codexNativeFeatureMatrix.features?.current_time_read?.ok ? 'verified' : 'unverified'}`);
742
+ console.log('Historical compatibility: Codex 0.138 features');
690
743
  console.log(` /app handoff: ${codex0138.supports_app_handoff ? 'ok' : 'unavailable'}`);
691
744
  console.log(` plugin JSON: ${codex0138.supports_plugin_json ? 'ok' : 'unavailable'}`);
692
745
  console.log(` image path exposure: ${codex0138.supports_image_path_exposure ? 'ok' : 'unavailable'}`);
@@ -716,6 +769,7 @@ async function runDoctor(args = [], root, doctorFix) {
716
769
  console.log('Ready:');
717
770
  console.log(` cli_ready: ${ready.cli_ready ? 'yes' : 'no'}`);
718
771
  console.log(` mad_ready: ${ready.mad_ready ? 'yes' : 'no'}`);
772
+ console.log(` managed_state_current: ${ready.managed_state_current ? 'yes' : 'no'}`);
719
773
  console.log(` ready: ${ready.ready ? 'yes' : 'no'}`);
720
774
  if (!ready.ready) {
721
775
  console.log('Primary blocker:');
@@ -747,6 +801,9 @@ function buildRuntimeReadiness(zellijReadiness, matrix) {
747
801
  const defaults = matrix?.invocation_defaults || {};
748
802
  const hookPolicy = defaults.hook_evidence_policy || 'unknown-do-not-count';
749
803
  const agentStrategy = defaults.loop_worker_role_strategy || 'message-role';
804
+ const multiAgentMode = defaults.multi_agent_mode || 'none';
805
+ const rolloutBudget = defaults.rollout_budget_strategy || 'sks-local-only';
806
+ const researchSource = defaults.research_source_strategy || 'local-files';
750
807
  const zellijStatus = zellijReadiness?.status === 'ok'
751
808
  ? 'ok'
752
809
  : zellijReadiness?.cli_ready ? 'headless_available' : 'repair_required';
@@ -759,7 +816,7 @@ function buildRuntimeReadiness(zellijReadiness, matrix) {
759
816
  repairActions.push('Homebrew + Zellij: sks doctor --fix --install-homebrew --yes');
760
817
  }
761
818
  if (codexNative !== 'ok')
762
- repairActions.push('Codex Native managed assets: sks doctor --fix --repair-codex-native --yes');
819
+ repairActions.push('Codex Native managed assets: sks doctor --fix --yes');
763
820
  if (matrix?.features?.project_memory?.ok !== true)
764
821
  repairActions.push('Project memory: sks codex-native init-deep --apply --directory-local');
765
822
  return {
@@ -768,14 +825,21 @@ function buildRuntimeReadiness(zellijReadiness, matrix) {
768
825
  codex_native: codexNative,
769
826
  loop_mesh: agentStrategy === 'agent_type' ? 'ok' : 'fallback',
770
827
  qa_visual: defaults.qa_visual_review_strategy || 'blocked',
771
- research_sources: defaults.research_source_strategy || 'local-files',
828
+ research_sources: researchSource,
772
829
  image_followup: defaults.image_followup_strategy || 'blocked',
773
830
  hook_evidence_policy: hookPolicy,
774
831
  agent_role_strategy: agentStrategy,
832
+ multi_agent_mode: multiAgentMode,
833
+ rollout_budget_strategy: rolloutBudget,
834
+ current_time_source: defaults.current_time_source || 'external-clock',
835
+ overload_retry_policy: defaults.overload_retry_policy || 'generic',
775
836
  notes: [
776
837
  ...(zellijStatus === 'headless_available' ? ['MAD can run with --headless; live panes require repair'] : []),
777
838
  ...(hookPolicy !== 'approved-only' ? ['hook-derived evidence will not count'] : []),
778
- ...(agentStrategy !== 'agent_type' ? ['message-role fallback active'] : [])
839
+ ...(agentStrategy !== 'agent_type' ? ['message-role fallback active'] : []),
840
+ ...(multiAgentMode === 'proactive' ? ['Codex 0.142 multi-agent proactive mode available for Naruto-style routes'] : []),
841
+ ...(rolloutBudget === 'codex-0142-shared' ? ['Codex 0.142 rollout budget can be recorded in route proof'] : []),
842
+ ...(researchSource === 'indexed-web-search' ? ['Codex 0.142 indexed web search selected for source-intelligence routes'] : [])
779
843
  ],
780
844
  repair_actions: [...new Set(repairActions)]
781
845
  };
@@ -1,26 +1,19 @@
1
1
  import fs from 'node:fs';
2
2
  import path from 'node:path';
3
3
  import { ensureDir, nowIso, writeJsonAtomic, writeTextAtomic } from '../fsx.js';
4
- import { REQUIRED_CODEX_MODEL } from '../codex-model-guard.js';
4
+ import { MANAGED_AGENT_ROLES, managedAgentRoleByFile, managedAgentRoleByName, managedAgentRoleContent, managedAgentRoleOwnsText } from '../managed-assets/managed-assets-manifest.js';
5
5
  export const AGENT_ROLE_CONFIG_REPAIR_SCHEMA = 'sks.agent-role-config-repair.v1';
6
- export const SKS_OWNED_AGENT_CONFIGS = new Map([
7
- ['analysis-scout.toml', roleConfig('analysis_scout', 'Read-only SKS analysis scout retained for stale Codex agent-role config repair.', 'read-only')],
8
- ['native-agent-intake.toml', roleConfig('native_agent', 'Read-only Team native agent for repository/docs/tests/API/risk slices.', 'read-only')],
9
- ['team-consensus.toml', roleConfig('team_consensus', 'Planning and debate specialist for SKS Team mode.', 'read-only')],
10
- ['implementation-worker.toml', roleConfig('implementation_worker', 'Implementation specialist for bounded SKS Team write sets.', 'workspace-write')],
11
- ['db-safety-reviewer.toml', roleConfig('db_safety_reviewer', 'Read-only database safety reviewer for SQL, migrations, Supabase, and rollback safety.', 'read-only')],
12
- ['qa-reviewer.toml', roleConfig('qa_reviewer', 'Strict read-only verification reviewer for correctness, regressions, and final evidence.', 'read-only')]
13
- ]);
6
+ export const SKS_OWNED_AGENT_CONFIGS = new Map(MANAGED_AGENT_ROLES.map((role) => [
7
+ role.filename,
8
+ { name: role.codex_name, sandbox: role.sandbox, content: managedAgentRoleContent(role), id: role.id }
9
+ ]));
14
10
  export function managedAgentRoleConfigForFile(file) {
15
- return SKS_OWNED_AGENT_CONFIGS.get(path.basename(file))?.content || null;
11
+ const role = managedAgentRoleByFile(file);
12
+ return role ? managedAgentRoleContent(role) : null;
16
13
  }
17
14
  export function managedAgentRoleConfigForRole(role) {
18
- const normalized = String(role || '').trim().replace(/-/g, '_');
19
- for (const [file, config] of SKS_OWNED_AGENT_CONFIGS) {
20
- if (config.name === normalized || path.basename(file, '.toml').replace(/-/g, '_') === normalized)
21
- return { file, content: config.content };
22
- }
23
- return null;
15
+ const match = managedAgentRoleByName(role);
16
+ return match ? { file: match.filename, content: managedAgentRoleContent(match) } : null;
24
17
  }
25
18
  export async function repairAgentRoleConfigs(input) {
26
19
  const root = path.resolve(input.root);
@@ -31,12 +24,14 @@ export async function repairAgentRoleConfigs(input) {
31
24
  const created = [];
32
25
  const repaired = [];
33
26
  const existing = [];
34
- for (const [file, config] of SKS_OWNED_AGENT_CONFIGS) {
27
+ for (const role of MANAGED_AGENT_ROLES) {
28
+ const file = role.filename;
29
+ const content = managedAgentRoleContent(role);
35
30
  const found = candidates.find((dir) => fs.existsSync(path.join(dir, file)));
36
31
  if (found) {
37
32
  const foundPath = path.join(found, file);
38
33
  const text = fs.readFileSync(foundPath, 'utf8');
39
- if (isValidRoleConfig(text, config)) {
34
+ if (isValidRoleConfig(text, role)) {
40
35
  existing.push(path.relative(root, foundPath) || foundPath);
41
36
  continue;
42
37
  }
@@ -44,7 +39,7 @@ export async function repairAgentRoleConfigs(input) {
44
39
  if (input.apply) {
45
40
  const target = foundPath.startsWith(path.join(root, '.codex', 'agents')) ? foundPath : path.join(root, '.codex', 'agents', file);
46
41
  await ensureDir(path.dirname(target));
47
- await writeTextAtomic(target, config.content);
42
+ await writeTextAtomic(target, content);
48
43
  repaired.push(path.relative(root, target));
49
44
  }
50
45
  continue;
@@ -53,7 +48,7 @@ export async function repairAgentRoleConfigs(input) {
53
48
  if (input.apply) {
54
49
  const target = path.join(root, '.codex', 'agents', file);
55
50
  await ensureDir(path.dirname(target));
56
- await writeTextAtomic(target, config.content);
51
+ await writeTextAtomic(target, content);
57
52
  created.push(path.relative(root, target));
58
53
  }
59
54
  }
@@ -69,6 +64,7 @@ export async function repairAgentRoleConfigs(input) {
69
64
  existing,
70
65
  created,
71
66
  repaired,
67
+ manifest_role_ids: MANAGED_AGENT_ROLES.map((role) => role.id),
72
68
  warnings_suppressed: true,
73
69
  blockers: input.apply && requiredFixes !== appliedFixes ? ['agent_role_config_repair_incomplete'] : []
74
70
  };
@@ -76,28 +72,9 @@ export async function repairAgentRoleConfigs(input) {
76
72
  await writeJsonAtomic(input.reportPath, report);
77
73
  return report;
78
74
  }
79
- function roleConfig(name, description, sandbox) {
80
- const content = [
81
- `name = "${name}"`,
82
- `description = "${description}"`,
83
- `model = "${REQUIRED_CODEX_MODEL}"`,
84
- 'model_reasoning_effort = "medium"',
85
- `sandbox_mode = "${sandbox}"`,
86
- 'approval_policy = "never"',
87
- 'developer_instructions = """',
88
- `You are the SKS ${name} role.`,
89
- sandbox === 'read-only' ? 'Do not edit files.' : 'Only edit the bounded files assigned by the parent orchestrator.',
90
- 'Return concise source-backed findings and LIVE_EVENT lines when applicable.',
91
- '"""',
92
- ''
93
- ].join('\n');
94
- return { name, sandbox, content };
95
- }
96
- function isValidRoleConfig(text, config) {
97
- return text.includes(`name = "${config.name}"`)
75
+ function isValidRoleConfig(text, role) {
76
+ return managedAgentRoleOwnsText(text, role)
98
77
  && text.includes('description = "')
99
- && text.includes(`model = "${REQUIRED_CODEX_MODEL}"`)
100
- && text.includes(`sandbox_mode = "${config.sandbox}"`)
101
78
  && text.includes('developer_instructions = """');
102
79
  }
103
80
  //# sourceMappingURL=agent-role-config.js.map
@@ -86,12 +86,12 @@ export async function syncCodexAgentRoles(input) {
86
86
  function roleToml(role, payload) {
87
87
  return [
88
88
  `name = "${role}"`,
89
- `description = "SKS managed 3.1.11 directive role: ${role}"`,
89
+ `description = "SKS managed 4.1.0 directive role: ${role}"`,
90
90
  'model_reasoning_effort = "medium"',
91
91
  role.includes('implementer') ? 'sandbox_mode = "workspace-write"' : 'sandbox_mode = "read-only"',
92
92
  'approval_policy = "never"',
93
93
  'developer_instructions = """',
94
- `You are ${role}. SKS managed 3.1.7 directive role with bounded ownership.`,
94
+ `You are ${role}. SKS managed 4.1.0 directive role with bounded ownership.`,
95
95
  'Bounded ownership: use only the assigned owner files/directories and treat memory as guidance, not permission.',
96
96
  role.includes('implementer') ? 'Maker/checker separation: implementer may patch only owner scope and cannot self-approve.' : 'Maker/checker separation: checker is read-only and must reject missing gates or missing proof artifacts.',
97
97
  role.includes('implementer') ? 'Allowed sandbox: workspace-write only within assigned owner scope.' : 'Allowed sandbox: read-only; checker roles cannot mutate.',
@@ -107,7 +107,7 @@ function roleToml(role, payload) {
107
107
  ].join('\n');
108
108
  }
109
109
  function isSksManagedDirectiveRole(text) {
110
- return /SKS managed 3\.1\.(?:4|5|6|7|11) (?:directive|bounded) role/.test(text)
110
+ return /SKS managed (?:3\.1\.(?:4|5|6|7|11)|4\.1\.0) (?:directive|bounded) role/.test(text)
111
111
  || /\bmessage_role_prefix\s*=/.test(text) && /SKS managed 3\.1\./.test(text);
112
112
  }
113
113
  function blockersOf(value) {
@@ -28,7 +28,7 @@ export class CodexAppServerV2Client {
28
28
  clientInfo: {
29
29
  name: 'sneakoscope-codex-app-server-v2',
30
30
  title: 'Sneakoscope Codex app-server v2',
31
- version: '4.0.15'
31
+ version: '4.1.0'
32
32
  },
33
33
  capabilities: {
34
34
  experimentalApi: true,