sneakoscope 8.0.0 → 8.0.2

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 (110) hide show
  1. package/README.md +13 -2
  2. package/config/skills-hash-ledger.v1.json +63 -0
  3. package/crates/sks-core/Cargo.lock +1 -1
  4. package/crates/sks-core/Cargo.toml +1 -1
  5. package/dist/bin/fast-inline.js +14 -3
  6. package/dist/bin/sks-dispatch.js +1 -1
  7. package/dist/cli/codex-lb-setup-warning-output.js +17 -0
  8. package/dist/cli/command-manifest-lite.js +2 -13
  9. package/dist/cli/install-helpers-codex-lb-config.js +475 -8
  10. package/dist/cli/install-helpers-install-support.js +1 -1
  11. package/dist/cli/install-helpers.js +764 -68
  12. package/dist/cli/router.js +5 -2
  13. package/dist/commands/codex-lb.js +77 -47
  14. package/dist/commands/doctor-profile.js +1 -0
  15. package/dist/commands/doctor.js +165 -58
  16. package/dist/config/skills-manifest.json +193 -97
  17. package/dist/core/codex/codex-config-guard.js +70 -16
  18. package/dist/core/codex/oauth-callback-port-diagnostic.js +121 -0
  19. package/dist/core/codex-app/codex-app-fast-ui-repair.js +7 -2
  20. package/dist/core/codex-app/menubar/constants.js +3 -0
  21. package/dist/core/codex-app/menubar/installer.js +32 -9
  22. package/dist/core/codex-app/menubar/launch-agent.js +58 -6
  23. package/dist/core/codex-app/menubar/migration.js +17 -6
  24. package/dist/core/codex-app/menubar/status.js +15 -3
  25. package/dist/core/codex-app.js +15 -20
  26. package/dist/core/codex-control/codex-lb-launch-recovery.js +26 -0
  27. package/dist/core/codex-lb/capability-runner.js +1 -0
  28. package/dist/core/codex-lb/codex-lb-env.js +52 -41
  29. package/dist/core/codex-lb/codex-lb-setup.js +85 -8
  30. package/dist/core/codex-lb/desktop-center-credentials.js +474 -39
  31. package/dist/core/codex-lb/desktop-controller.js +118 -4
  32. package/dist/core/codex-lb/legacy-migration.js +6 -3
  33. package/dist/core/codex-native/codex-native-feature-broker.js +5 -1
  34. package/dist/core/codex-native/core-skill-manifest.js +1 -1
  35. package/dist/core/codex-native/managed-skill-generation-lock.js +13 -0
  36. package/dist/core/codex-native/sks-skill-paths.js +97 -10
  37. package/dist/core/codex-runtime/codex-desktop-config-policy.js +1 -0
  38. package/dist/core/commands/basic-cli.js +54 -4
  39. package/dist/core/commands/mad-sks-command.js +1 -1
  40. package/dist/core/commands/menubar-command.js +24 -8
  41. package/dist/core/commands/naruto-command.js +42 -217
  42. package/dist/core/doctor/codex-config-syntax-repair.js +368 -0
  43. package/dist/core/doctor/doctor-native-capability-repair.js +12 -5
  44. package/dist/core/doctor/doctor-readiness-matrix.js +51 -4
  45. package/dist/core/doctor/skill-legacy-surface.js +0 -1
  46. package/dist/core/doctor/sks-menubar-doctor.js +21 -0
  47. package/dist/core/fsx.js +7 -14
  48. package/dist/core/hooks-runtime/hook-context.js +30 -16
  49. package/dist/core/hooks-runtime/managed-skill-admission.js +17 -0
  50. package/dist/core/hooks-runtime/managed-skill-generation-heal.js +891 -30
  51. package/dist/core/hooks-runtime/official-subagent-lifecycle.js +99 -6
  52. package/dist/core/hooks-runtime/subagent-skill-availability-contract.js +3 -1
  53. package/dist/core/hooks-runtime/subagent-skill-availability-evidence.js +1 -1
  54. package/dist/core/hooks-runtime/subagent-skill-availability-guards.js +4 -4
  55. package/dist/core/hooks-runtime/subagent-skill-availability.js +9 -7
  56. package/dist/core/hooks-runtime/subagent-stop-hook.js +19 -0
  57. package/dist/core/hooks-runtime.js +41 -14
  58. package/dist/core/init/skills.js +270 -11
  59. package/dist/core/mission.js +20 -0
  60. package/dist/core/naruto/hardware-capacity-probe.js +3 -1
  61. package/dist/core/naruto/naruto-concurrency-governor.js +9 -3
  62. package/dist/core/pipeline-internals/runtime-core.js +68 -9
  63. package/dist/core/pipeline-internals/runtime-gates.js +10 -2
  64. package/dist/core/preflight/parallel-preflight-engine.js +18 -4
  65. package/dist/core/release/package-dist-snapshot.js +50 -8
  66. package/dist/core/routes.js +1 -1
  67. package/dist/core/safety/command-contract/contracts.js +10 -13
  68. package/dist/core/safety/command-contract/json-schema.js +38 -1
  69. package/dist/core/subagents/agent-catalog.js +37 -13
  70. package/dist/core/subagents/model-policy.js +14 -9
  71. package/dist/core/subagents/naruto-command-args.js +237 -0
  72. package/dist/core/subagents/naruto-command-input-contract.js +123 -0
  73. package/dist/core/subagents/naruto-help-contract.js +35 -2
  74. package/dist/core/subagents/naruto-launch-diagnostics.js +35 -0
  75. package/dist/core/subagents/official-subagent-config.js +30 -3
  76. package/dist/core/subagents/official-subagent-preparation.js +30 -5
  77. package/dist/core/subagents/official-subagent-prompt.js +4 -3
  78. package/dist/core/subagents/official-subagent-runner.js +12 -0
  79. package/dist/core/subagents/subagent-evidence.js +10 -0
  80. package/dist/core/subagents/thread-budget.js +1 -1
  81. package/dist/core/subagents/wave-lifecycle.js +41 -11
  82. package/dist/core/subagents/wave-parent-guidance.js +10 -3
  83. package/dist/core/update/update-migration-state.js +694 -63
  84. package/dist/core/update/update-operation.js +498 -32
  85. package/dist/core/update-check.js +990 -509
  86. package/dist/core/version.js +1 -1
  87. package/dist/native/sks-menubar/Sources/AppDelegate.swift +1 -0
  88. package/dist/native/sks-menubar/Sources/DiagnosticsViewController.swift +1 -1
  89. package/dist/native/sks-menubar/Sources/MCPServersViewController.swift +1 -1
  90. package/dist/native/sks-menubar/Sources/OperationCoordinator.swift +127 -12
  91. package/dist/native/sks-menubar/Sources/OverviewViewController.swift +7 -2
  92. package/dist/native/sks-menubar/Sources/ProcessClient.swift +287 -84
  93. package/dist/native/sks-menubar/Sources/ProcessExecutionState.swift +45 -0
  94. package/dist/native/sks-menubar/Sources/ProcessIdentityGuard.swift +196 -0
  95. package/dist/native/sks-menubar/Sources/SecureProcessEnvelope.swift +169 -0
  96. package/dist/native/sks-menubar/Sources/StatusItemController.swift +23 -5
  97. package/dist/native/sks-menubar/Sources/UpdatesViewController.swift +113 -24
  98. package/dist/native/sks-menubar/Sources/main.swift +12 -0
  99. package/dist/native/sks-menubar/Tests/AppRuntimeTestSupport.swift +14 -0
  100. package/dist/native/sks-menubar/Tests/OperationCoordinatorTests.swift +174 -0
  101. package/dist/native/sks-menubar/Tests/ProcessClientTests.swift +4 -0
  102. package/dist/scripts/current-surface-update-e2e-check.js +24 -5
  103. package/dist/scripts/lib/ensure-dist-fresh.js +12 -8
  104. package/dist/scripts/mutation-callsite-analysis.js +381 -0
  105. package/dist/scripts/mutation-callsite-coverage-check.js +127 -62
  106. package/dist/scripts/official-subagent-workflow-check.js +1 -1
  107. package/dist/scripts/skills-manifest-continuity-check.js +19 -1
  108. package/package.json +5 -3
  109. package/runtime-required-scripts.json +5 -0
  110. package/scripts/build-clean-atomic.mjs +323 -0
@@ -12,6 +12,7 @@ import { codexLbStatus } from '../cli/install-helpers.js';
12
12
  import { codexLbToolOutputRecoveryOverrideAcknowledged } from '../core/codex-lb/codex-lb-tool-output-recovery.js';
13
13
  import { normalizeInstallScope } from '../core/init.js';
14
14
  import { inspectCodexConfigReadability } from '../core/codex/codex-config-readability.js';
15
+ import { inspectOAuthCallbackPortConflict, oauthCallbackDoctorGuidance } from '../core/codex/oauth-callback-port-diagnostic.js';
15
16
  import { checkZellijCapability } from '../core/zellij/zellij-capability.js';
16
17
  import { inventoryCodexPermissionProfiles } from '../core/codex/codex-permission-profiles.js';
17
18
  import { appendMigrationEvents, hashConfigText } from '../core/migration/migration-transaction-journal.js';
@@ -24,6 +25,7 @@ import { buildCodexAppHarnessMatrix } from '../core/codex-app/codex-app-harness-
24
25
  import { buildCodexNativeFeatureMatrix } from '../core/codex-native/codex-native-feature-broker.js';
25
26
  import { withSecretPreservationGuard } from '../core/config/config-migration-journal.js';
26
27
  import { reconcileDoctorSkills } from '../core/doctor/doctor-skill-reconcile.js';
28
+ import { buildSksMenuBarDoctorPostcheck } from '../core/doctor/sks-menubar-doctor.js';
27
29
  import { isUpdateMigrationReceiptCurrent, projectUpdateMigrationReceiptPath, writeProjectUpdateMigrationReceipt } from '../core/update/update-migration-state.js';
28
30
  import { inspectSksMenuBarStatus, installSksMenuBar, sksMenuBarRestartDeferred } from '../core/codex-app/menubar/index.js';
29
31
  import { sweepSksTempDirs } from '../core/retention.js';
@@ -32,6 +34,25 @@ import { CURRENT_CODEX_RELEASE_MANIFEST } from '../core/codex-compat/codex-relea
32
34
  import { formatHarnessConflictReport, scanHarnessConflicts } from '../core/harness-conflicts.js';
33
35
  import { doctorArgWarnings, doctorMenuBarInstallPolicy, doctorPhaseIdsForProfile, doctorProfileFromArgs } from './doctor-profile.js';
34
36
  export { doctorArgWarnings, doctorMenuBarInstallPolicy, doctorProfileFromArgs } from './doctor-profile.js';
37
+ export function deferCommandAliasCleanupToMigrationReceipt(result) {
38
+ const observedBlockers = Array.isArray(result?.blockers)
39
+ ? result.blockers.map(String).filter(Boolean)
40
+ : [];
41
+ return {
42
+ ...result,
43
+ ok: true,
44
+ status: 'deferred_to_project_migration_receipt',
45
+ fix: false,
46
+ repair_owner: 'project_migration_receipt',
47
+ pre_migration_blockers: observedBlockers,
48
+ actions: [],
49
+ blockers: [],
50
+ warnings: [
51
+ ...(Array.isArray(result?.warnings) ? result.warnings.map(String).filter(Boolean) : []),
52
+ ...(observedBlockers.length ? [`pre_migration_public_surface_findings_deferred:${observedBlockers.length}`] : [])
53
+ ]
54
+ };
55
+ }
35
56
  export async function run(_command, args = [], deps = {}) {
36
57
  const root = await projectRoot();
37
58
  if (flag(args, '--search')) {
@@ -268,7 +289,7 @@ async function runDoctorJsonFastPath(args = [], root) {
268
289
  requireActualCodex: false,
269
290
  codexBin: codexBin || undefined
270
291
  };
271
- const [codex, rust, codexConfig, sneakoscopeExists] = await Promise.all([
292
+ const [codex, rust, codexConfig, sneakoscopeExists, oauthCallbackPortDiagnostic] = await Promise.all([
272
293
  codexBin
273
294
  ? Promise.resolve({ bin: codexBin, version: 'fixture-or-explicit', available: true })
274
295
  : getCodexInfo().catch(() => ({ bin: null, version: null, available: false })),
@@ -279,8 +300,10 @@ async function runDoctorJsonFastPath(args = [], root) {
279
300
  operator_actions: [],
280
301
  blockers: [err?.message || String(err)]
281
302
  })),
282
- exists(`${root}/.sneakoscope`)
303
+ exists(`${root}/.sneakoscope`),
304
+ inspectOAuthCallbackPortConflict()
283
305
  ]);
306
+ const oauthCallbackOperatorActions = oauthCallbackDoctorGuidance(oauthCallbackPortDiagnostic);
284
307
  const ready = {
285
308
  schema: 'sks.doctor-readiness-matrix.v2',
286
309
  generated_at: nowIso(),
@@ -322,8 +345,11 @@ async function runDoctorJsonFastPath(args = [], root) {
322
345
  fast_path: true,
323
346
  no_fix_write_policy: reportFile ? 'report_file_only' : 'no_writes_performed',
324
347
  arg_warnings: doctorArgWarnings(args),
348
+ warnings: [...oauthCallbackPortDiagnostic.warnings],
349
+ operator_actions: oauthCallbackOperatorActions,
325
350
  node: { ok: Number(process.versions.node.split('.')[0]) >= 20, version: process.version },
326
351
  codex,
352
+ oauth_callback_port_diagnostic: oauthCallbackPortDiagnostic,
327
353
  codex_config: codexConfig,
328
354
  rust,
329
355
  codex_app: { ok: false, skipped: true, warnings: ['codex_app_optional_diagnostic_skipped'] },
@@ -428,6 +454,8 @@ async function runDoctorJsonFastPath(args = [], root) {
428
454
  }
429
455
  async function runDoctor(args = [], root, doctorFix) {
430
456
  const startedAtMs = Date.now();
457
+ const oauthCallbackPortDiagnostic = await inspectOAuthCallbackPortConflict();
458
+ const oauthCallbackOperatorActions = oauthCallbackDoctorGuidance(oauthCallbackPortDiagnostic);
431
459
  const sksTempSweep = doctorFix ? await sweepSksTempDirs(root, { maxAgeHours: 24 }).catch((err) => ({
432
460
  ok: false,
433
461
  error: err?.message || String(err),
@@ -445,6 +473,8 @@ async function runDoctor(args = [], root, doctorFix) {
445
473
  const shouldEvaluateCodexAppUiRepair = doctorFix || deepDiagnostics || flag(args, '--repair-codex-app-ui');
446
474
  const shouldRunZellijRepair = deepDiagnostics || flag(args, '--repair-zellij') || flag(args, '--install-homebrew') || process.env.SKS_REQUIRE_ZELLIJ === '1';
447
475
  const nativeCapabilityDiagnosticsRequested = deepDiagnostics || flag(args, '--repair-native-capabilities');
476
+ const requireLegacyGlobalHookCleanup = doctorFix && doctorProfile === 'migration';
477
+ const migrationReceiptOwnsReconcile = doctorFix && doctorProfile === 'migration';
448
478
  const doctorPhaseIds = doctorPhaseIdsForProfile(doctorProfile);
449
479
  const { runDoctorCommandAliasCleanup } = await import('../core/doctor/command-alias-cleanup.js');
450
480
  const { runDoctorNativeCapabilityRepair } = await import('../core/doctor/doctor-native-capability-repair.js');
@@ -490,16 +520,16 @@ async function runDoctor(args = [], root, doctorFix) {
490
520
  openrouter_provider: openRouterProviderRepair
491
521
  };
492
522
  }
493
- const skillsReconcile = await reconcileDoctorSkills(root, doctorFix);
494
- const commandAliasCleanup = await runDoctorCommandAliasCleanup({
523
+ const skillsReconcile = await reconcileDoctorSkills(root, doctorFix && !migrationReceiptOwnsReconcile);
524
+ const inspectCommandAliasCleanup = (fix) => runDoctorCommandAliasCleanup({
495
525
  root,
496
- fix: doctorFix
526
+ fix
497
527
  }).catch((err) => ({
498
528
  schema: 'sks.command-alias-cleanup.v1',
499
529
  ok: false,
500
530
  status: 'blocked',
501
531
  root,
502
- fix: doctorFix,
532
+ fix,
503
533
  report_path: `${root}/.sneakoscope/reports/command-alias-cleanup.json`,
504
534
  canonical_command_count: 0,
505
535
  current_alias_count: 0,
@@ -507,12 +537,17 @@ async function runDoctor(args = [], root, doctorFix) {
507
537
  actions: [],
508
538
  blockers: [err?.message || String(err)]
509
539
  }));
540
+ let commandAliasCleanup = await inspectCommandAliasCleanup(doctorFix && !migrationReceiptOwnsReconcile);
541
+ const commandAliasCleanupBeforeReceipt = migrationReceiptOwnsReconcile
542
+ ? deferCommandAliasCleanupToMigrationReceipt(commandAliasCleanup)
543
+ : commandAliasCleanup;
510
544
  const doctorNativeCapabilityRepair = await runDoctorNativeCapabilityRepair({
511
545
  root,
512
546
  fix: nativeCapabilityDiagnosticsRequested && doctorFix,
513
547
  yes: flag(args, '--yes') || flag(args, '-y'),
514
548
  flags: args.map((arg) => String(arg)),
515
- skipNativeCapabilities: !nativeCapabilityDiagnosticsRequested
549
+ skipNativeCapabilities: !nativeCapabilityDiagnosticsRequested,
550
+ requireLegacyGlobalHookCleanup
516
551
  }).catch((err) => ({
517
552
  schema: 'sks.doctor-native-capability-repair.v1',
518
553
  ok: false,
@@ -522,11 +557,19 @@ async function runDoctor(args = [], root, doctorFix) {
522
557
  core_skills: null,
523
558
  skill_dedupe: null,
524
559
  native_capabilities: null,
560
+ legacy_global_hooks: {
561
+ ok: false,
562
+ blockers: [`cleanup_failed_before_report:${err?.message || String(err)}`],
563
+ warnings: []
564
+ },
525
565
  secret_preservation_guard: '.sneakoscope/reports/secret-preservation-guard.json',
526
566
  core_blockers: [err?.message || String(err)],
527
567
  route_blockers: {},
528
568
  optional_manual_required: [],
529
569
  optional_warnings: [],
570
+ required_blockers: requireLegacyGlobalHookCleanup
571
+ ? [`legacy_global_hooks:cleanup_failed_before_report:${err?.message || String(err)}`]
572
+ : [],
530
573
  blockers: [err?.message || String(err)]
531
574
  }));
532
575
  const configProbeOpts = {
@@ -559,6 +602,20 @@ async function runDoctor(args = [], root, doctorFix) {
559
602
  : null;
560
603
  const codexDoctorDiff = compareCodexDoctorBridge(codexDoctorBefore, preRepairCodexDoctor);
561
604
  codexStartupRepair = mergeObservedCodexStartupWarnings(codexStartupRepair, preRepairCodexDoctor);
605
+ const codexConfigSyntaxRepair = doctorPhaseIds.includes('codex_config_syntax_repair')
606
+ ? await (await import('../core/doctor/codex-config-syntax-repair.js')).runCodexConfigSyntaxRepair({ root, fix: doctorFix }).catch((err) => ({
607
+ schema: 'sks.codex-config-syntax-repair.v1',
608
+ ok: false,
609
+ generated_at: new Date().toISOString(),
610
+ fix: doctorFix,
611
+ configs: [],
612
+ actions: [],
613
+ manual_actions: [],
614
+ blockers: [err?.message || String(err)],
615
+ warnings: [],
616
+ report_path: `${root}/.sneakoscope/reports/codex-config-syntax-repair.json`
617
+ }))
618
+ : null;
562
619
  const codex = codexBin
563
620
  ? { bin: codexBin, version: 'fixture-or-explicit', available: true }
564
621
  : await getCodexInfo().catch(() => ({ bin: null, version: null, available: false }));
@@ -641,19 +698,7 @@ async function runDoctor(args = [], root, doctorFix) {
641
698
  ? await repairCodexAppFastUi(root, {
642
699
  apply: false,
643
700
  reportPath: `${root}/.sneakoscope/reports/codex-app-fast-ui-repair-plan.json`
644
- }).catch((err) => ({
645
- schema: 'sks.codex-app-fast-ui-repair.v1',
646
- ok: false,
647
- apply: false,
648
- safe_auto_apply: false,
649
- requires_confirmation: true,
650
- fast_selector: 'manual_action_required',
651
- provider_selector: 'ok',
652
- host_owned_config: 'diagnostic_failed',
653
- next_action: 'Review Codex App UI config manually.',
654
- actions: [],
655
- blockers: [err?.message || String(err)]
656
- }))
701
+ }).catch((err) => buildCodexAppUiDiagnosticFailure(false, err))
657
702
  : {
658
703
  schema: 'sks.codex-app-fast-ui-repair.v1',
659
704
  ok: true,
@@ -676,19 +721,7 @@ async function runDoctor(args = [], root, doctorFix) {
676
721
  apply: true,
677
722
  force: explicitCodexAppUiRepair,
678
723
  reportPath: `${root}/.sneakoscope/reports/codex-app-fast-ui-repair.json`
679
- }).catch((err) => ({
680
- schema: 'sks.codex-app-fast-ui-repair.v1',
681
- ok: false,
682
- apply: true,
683
- safe_auto_apply: false,
684
- requires_confirmation: true,
685
- fast_selector: 'manual_action_required',
686
- provider_selector: 'ok',
687
- host_owned_config: 'diagnostic_failed',
688
- next_action: 'Review Codex App UI config manually.',
689
- actions: [],
690
- blockers: [err?.message || String(err)]
691
- }))
724
+ }).catch((err) => buildCodexAppUiDiagnosticFailure(true, err))
692
725
  : codexAppUiPlan;
693
726
  const menuBarPolicy = doctorMenuBarInstallPolicy(args, doctorFix, process.env);
694
727
  const menuBarLaunchRequested = menuBarPolicy.launch;
@@ -810,7 +843,9 @@ async function runDoctor(args = [], root, doctorFix) {
810
843
  raw_secret_values_recorded: false
811
844
  }))
812
845
  : null;
813
- const hookTrustRepair = doctorFix && doctorPhaseIds.includes('hook_trust_repair')
846
+ const hookTrustRepair = doctorFix
847
+ && !migrationReceiptOwnsReconcile
848
+ && doctorPhaseIds.includes('hook_trust_repair')
814
849
  ? await (await import('../core/codex-hooks/codex-hook-trust-doctor.js')).codexHookTrustDoctor(root, { fix: true, managed: true, actual: true }).catch((err) => ({
815
850
  schema: 'sks.codex-hook-trust-doctor.v2',
816
851
  ok: false,
@@ -858,6 +893,17 @@ async function runDoctor(args = [], root, doctorFix) {
858
893
  rollback_evidence: startupConfigRepair?.backup_path || 'startup_config_repair_idempotent_report'
859
894
  })
860
895
  },
896
+ {
897
+ id: 'codex_config_syntax_repair',
898
+ run: async () => ({
899
+ id: 'codex_config_syntax_repair',
900
+ ok: codexConfigSyntaxRepair?.ok !== false,
901
+ repaired: doctorFix && (codexConfigSyntaxRepair?.configs || []).some((entry) => entry.changed),
902
+ blockers: codexConfigSyntaxRepair?.blockers || [],
903
+ warnings: codexConfigSyntaxRepair?.warnings || [],
904
+ rollback_evidence: codexConfigSyntaxRepair?.report_path || 'codex_config_syntax_repair_report'
905
+ })
906
+ },
861
907
  {
862
908
  id: 'context7_repair',
863
909
  run: async () => ({
@@ -900,10 +946,12 @@ async function runDoctor(args = [], root, doctorFix) {
900
946
  run: async () => ({
901
947
  id: 'hook_trust_repair',
902
948
  ok: hookTrustRepair?.ok !== false,
903
- repaired: doctorFix,
949
+ repaired: doctorFix && !migrationReceiptOwnsReconcile,
904
950
  blockers: hookTrustRepair?.blockers || [],
905
951
  warnings: hookTrustRepair?.warnings || [],
906
- rollback_evidence: hookTrustRepair?.fixed?.managed_hook_file || 'codex_hook_trust_repair_idempotent'
952
+ rollback_evidence: migrationReceiptOwnsReconcile
953
+ ? 'project_migration_receipt_owns_hook_trust_refresh'
954
+ : hookTrustRepair?.fixed?.managed_hook_file || 'codex_hook_trust_repair_idempotent'
907
955
  })
908
956
  },
909
957
  {
@@ -927,29 +975,18 @@ async function runDoctor(args = [], root, doctorFix) {
927
975
  blockers: [err?.message || String(err)],
928
976
  warnings: []
929
977
  }));
930
- const blockers = [
931
- ...(status.launchd?.ok === true ? [] : [`launchd_not_running:${status.launchd?.error || status.launchd?.state || 'unknown'}`]),
932
- ...(status.action_target?.ok === true ? [] : [`action_script_smoke_failed:${status.action_target?.smoke_code ?? 'no_code'}`]),
933
- ...(status.ok === true ? [] : (status.blockers || ['menubar_status_not_ok']))
934
- ];
935
- return {
936
- ok: blockers.length === 0,
937
- blockers,
938
- warnings: [
939
- ...(status.warnings || []),
940
- blockers.length === 0 ? 'menubar_postcheck_passed' : 'menubar_postcheck_failed'
941
- ]
942
- };
978
+ return buildSksMenuBarDoctorPostcheck(status);
943
979
  }
944
980
  },
945
981
  {
946
982
  id: 'command_alias_cleanup',
947
983
  run: async () => ({
948
984
  id: 'command_alias_cleanup',
949
- ok: commandAliasCleanup?.ok !== false,
950
- repaired: Array.isArray(commandAliasCleanup?.actions) && commandAliasCleanup.actions.length > 0,
951
- blockers: commandAliasCleanup?.blockers || [],
952
- rollback_evidence: commandAliasCleanup?.report_path || 'command_alias_cleanup_report'
985
+ ok: commandAliasCleanupBeforeReceipt?.ok !== false,
986
+ repaired: Array.isArray(commandAliasCleanupBeforeReceipt?.actions) && commandAliasCleanupBeforeReceipt.actions.length > 0,
987
+ blockers: commandAliasCleanupBeforeReceipt?.blockers || [],
988
+ warnings: commandAliasCleanupBeforeReceipt?.warnings || [],
989
+ rollback_evidence: commandAliasCleanupBeforeReceipt?.report_path || 'command_alias_cleanup_report'
953
990
  })
954
991
  },
955
992
  {
@@ -1219,7 +1256,7 @@ async function runDoctor(args = [], root, doctorFix) {
1219
1256
  const authoritativeCodexDoctor = postRepairCodexDoctor;
1220
1257
  const codexDoctorAuthoritativeDiff = compareCodexDoctorBridge(codexDoctorBefore, authoritativeCodexDoctor);
1221
1258
  const pkgBytes = 0;
1222
- const ready = await writeDoctorReadinessMatrix(root, {
1259
+ const doctorReadinessInput = {
1223
1260
  codex,
1224
1261
  codex_config: codexConfig,
1225
1262
  codex_app: codexApp,
@@ -1232,12 +1269,15 @@ async function runDoctor(args = [], root, doctorFix) {
1232
1269
  context7_repair: context7Repair,
1233
1270
  codex_startup_repair: codexStartupRepair,
1234
1271
  startup_config_repair: startupConfigRepair,
1272
+ codex_config_syntax_repair: codexConfigSyntaxRepair,
1235
1273
  context7_mcp_repair: context7McpRepair,
1236
1274
  supabase_mcp_repair: supabaseMcpRepair,
1237
1275
  doctor_fix_transaction: doctorFixTransaction,
1238
1276
  doctor_dirty_plan: doctorDirtyPlan,
1239
1277
  doctor_fix_postcheck: doctorFixPostcheck,
1278
+ command_aliases: migrationReceiptOwnsReconcile ? commandAliasCleanupBeforeReceipt : undefined,
1240
1279
  doctor_native_capability: doctorNativeCapabilityRepair,
1280
+ require_legacy_global_hook_cleanup: requireLegacyGlobalHookCleanup,
1241
1281
  skills: skillsReconcile,
1242
1282
  local_model: localModel,
1243
1283
  agent_role_config: agentRoleConfigRepair,
@@ -1254,28 +1294,45 @@ async function runDoctor(args = [], root, doctorFix) {
1254
1294
  ...(configRepair?.operator_actions || []),
1255
1295
  ...(zellijRepair && !zellijRepair.ok && zellijRepair.command ? [`Run: ${zellijRepair.command}`] : []),
1256
1296
  ...(codexStartupRepair.manual_actions || []),
1297
+ ...(codexConfigSyntaxRepair?.manual_actions || []),
1257
1298
  ...(pluginPolicy?.doctor_warnings || [])
1258
1299
  ]
1259
- });
1300
+ };
1301
+ let ready = await writeDoctorReadinessMatrix(root, doctorReadinessInput);
1260
1302
  if (doctorFix) {
1303
+ if (migrationReceiptOwnsReconcile) {
1304
+ commandAliasCleanup = await inspectCommandAliasCleanup(false);
1305
+ doctorReadinessInput.command_aliases = commandAliasCleanup;
1306
+ ready = await writeDoctorReadinessMatrix(root, doctorReadinessInput);
1307
+ }
1261
1308
  const readinessBlockers = [
1262
1309
  ...(Array.isArray(ready.blockers) ? ready.blockers.map(String).filter(Boolean) : []),
1263
1310
  ...(openRouterProviderRepair?.ok === false
1264
1311
  ? ((openRouterProviderRepair?.blockers || ['openrouter_provider_repair_failed']).map(String))
1265
1312
  : [])
1266
1313
  ];
1314
+ const preservedUserOwnedConfig = doctorProfile === 'migration'
1315
+ && readinessBlockers.length > 0
1316
+ && readinessBlockers.every(isMigrationUserOwnedProjectConfigBlocker);
1317
+ const receiptBlockers = preservedUserOwnedConfig ? [] : readinessBlockers;
1267
1318
  const migrationWarnings = [
1268
1319
  ...(doctorNativeCapabilityRepair?.optional_warnings || []),
1269
- ...(doctorFixPostcheck?.optional_warnings || [])
1320
+ ...(doctorFixPostcheck?.optional_warnings || []),
1321
+ ...(preservedUserOwnedConfig
1322
+ ? [
1323
+ 'migration_doctor_preserved_user_owned_project_config',
1324
+ ...readinessBlockers.map((blocker) => `migration_optional_blocker:${blocker}`)
1325
+ ]
1326
+ : [])
1270
1327
  ];
1271
1328
  try {
1272
1329
  const receiptInput = {
1273
1330
  root,
1274
1331
  source: `doctor-${doctorProfile}`,
1275
- blockers: readinessBlockers,
1332
+ blockers: receiptBlockers,
1276
1333
  warnings: migrationWarnings
1277
1334
  };
1278
- if (readinessBlockers.length)
1335
+ if (receiptBlockers.length)
1279
1336
  receiptInput.status = 'blocked';
1280
1337
  const receipt = await writeProjectUpdateMigrationReceipt(receiptInput);
1281
1338
  sksUpdate = {
@@ -1310,6 +1367,7 @@ async function runDoctor(args = [], root, doctorFix) {
1310
1367
  && (!sksUpdate || sksUpdate.ok !== false)
1311
1368
  && commandAliasCleanup.ok !== false
1312
1369
  && codexStartupRepair.ok !== false
1370
+ && codexConfigSyntaxRepair?.ok !== false
1313
1371
  && agentRoleConfigRepair.ok !== false
1314
1372
  && openRouterProviderRepair.ok !== false
1315
1373
  && (officialSubagentConfig.blockers || []).length === 0
@@ -1319,14 +1377,20 @@ async function runDoctor(args = [], root, doctorFix) {
1319
1377
  elapsed_ms: Date.now() - startedAtMs,
1320
1378
  ok: resultOk,
1321
1379
  status: resultOk ? (doctorFix ? 'fix_ok' : deepDiagnostics ? 'full_ok' : 'fast_ok') : 'blocked',
1380
+ core_ready: ready.core_ready === true,
1381
+ center_ready: ready.center_ready === true,
1382
+ center_attempted: ready.center_attempted === true,
1322
1383
  diagnostic_depth: deepDiagnostics ? 'full' : doctorFix ? 'fix' : 'fast',
1323
1384
  deep_diagnostics_skipped: !deepDiagnostics,
1324
1385
  deep_ok: deepDiagnostics ? resultOk : null,
1325
1386
  not_counted_as_full_doctor: !deepDiagnostics,
1326
1387
  root,
1327
1388
  arg_warnings: argWarnings,
1389
+ warnings: [...oauthCallbackPortDiagnostic.warnings],
1390
+ operator_actions: oauthCallbackOperatorActions,
1328
1391
  node: { ok: Number(process.versions.node.split('.')[0]) >= 20, version: process.version },
1329
1392
  codex,
1393
+ oauth_callback_port_diagnostic: oauthCallbackPortDiagnostic,
1330
1394
  codex_config: codexConfig,
1331
1395
  rust,
1332
1396
  codex_app: codexApp,
@@ -1345,6 +1409,7 @@ async function runDoctor(args = [], root, doctorFix) {
1345
1409
  context7_repair: context7Repair,
1346
1410
  codex_startup_repair: codexStartupRepair,
1347
1411
  startup_config_repair: startupConfigRepair,
1412
+ codex_config_syntax_repair: codexConfigSyntaxRepair,
1348
1413
  context7_mcp_repair: context7McpRepair,
1349
1414
  supabase_mcp_repair: supabaseMcpRepair,
1350
1415
  doctor_fix_transaction: doctorFixTransaction,
@@ -1415,6 +1480,14 @@ async function runDoctor(args = [], root, doctorFix) {
1415
1480
  console.log(`Root: ${root}`);
1416
1481
  console.log(`Node: ${result.node.ok ? 'ok' : 'fail'} ${result.node.version}`);
1417
1482
  console.log(`Codex: ${codex.bin ? 'ok' : 'missing'} ${codex.version || ''}`);
1483
+ if (oauthCallbackPortDiagnostic.conflict) {
1484
+ const listeners = oauthCallbackPortDiagnostic.listeners
1485
+ .map((listener) => `${listener.command} pid ${listener.pid} ${listener.address}`)
1486
+ .join(', ');
1487
+ console.log(`OAuth callback port 1455: warning (${listeners})`);
1488
+ for (const action of oauthCallbackOperatorActions)
1489
+ console.log(` action: ${action}`);
1490
+ }
1418
1491
  const actual = (codexConfig.checks || []).find((check) => check.name === 'actual_codex_cli_config_load');
1419
1492
  console.log('Project config:');
1420
1493
  console.log(` node read: ${ready.codex_config_readable_by_node ? 'ok' : 'failed'}`);
@@ -1443,6 +1516,16 @@ async function runDoctor(args = [], root, doctorFix) {
1443
1516
  console.log(` manual: ${action}`);
1444
1517
  for (const warning of codexStartupRepair.warnings || [])
1445
1518
  console.log(` warning: ${warning}`);
1519
+ if (codexConfigSyntaxRepair) {
1520
+ console.log('Codex config syntax:');
1521
+ console.log(` repair: ${codexConfigSyntaxRepair.ok ? 'ok' : 'blocked'}`);
1522
+ for (const action of codexConfigSyntaxRepair.actions || [])
1523
+ console.log(` - ${action}`);
1524
+ for (const action of codexConfigSyntaxRepair.manual_actions || [])
1525
+ console.log(` manual: ${action}`);
1526
+ for (const warning of codexConfigSyntaxRepair.warnings || [])
1527
+ console.log(` warning: ${warning}`);
1528
+ }
1446
1529
  console.log(` codex doctor: ${formatCodexDoctorConsoleStatus(authoritativeCodexDoctor)}`);
1447
1530
  console.log(`Rust acc.: ${rust.mode || (rust.available ? 'rust_accelerated' : 'js_fallback')} ${rust.version || rust.status || ''}`);
1448
1531
  console.log(`Codex App: ${ready.codex_app_ready ? 'ok' : 'optional_missing'}`);
@@ -1613,6 +1696,8 @@ async function runDoctor(args = [], root, doctorFix) {
1613
1696
  console.log(` cli_ready: ${ready.cli_ready ? 'yes' : 'no'}`);
1614
1697
  console.log(` mad_ready: ${ready.mad_ready ? 'yes' : 'no'}`);
1615
1698
  console.log(` managed_state_current: ${ready.managed_state_current ? 'yes' : 'no'}`);
1699
+ console.log(` core_ready: ${ready.core_ready ? 'yes' : 'no'}`);
1700
+ console.log(` center_ready: ${ready.center_ready ? 'yes' : 'no'}${ready.center_attempted ? ' (repair attempted)' : ' (not attempted)'}`);
1616
1701
  console.log(` ready: ${ready.ready ? 'yes' : 'no'}`);
1617
1702
  if (!ready.ready) {
1618
1703
  console.log('Primary blocker:');
@@ -1895,10 +1980,32 @@ function installScopeFromArgs(args = []) {
1895
1980
  const index = args.indexOf('--install-scope');
1896
1981
  return normalizeInstallScope(index >= 0 && args[index + 1] ? args[index + 1] : 'global');
1897
1982
  }
1983
+ function isMigrationUserOwnedProjectConfigBlocker(blocker) {
1984
+ const value = String(blocker || '').trim();
1985
+ return value === 'user_owned_file_without_sks_marker'
1986
+ || value.endsWith(':user_owned_file_without_sks_marker')
1987
+ || value === 'config_write_guard:blocked_unmanaged_project_config'
1988
+ || value.endsWith(':config_write_guard:blocked_unmanaged_project_config');
1989
+ }
1898
1990
  function readOption(args = [], name, fallback = null) {
1899
1991
  const index = args.indexOf(name);
1900
1992
  return index >= 0 && args[index + 1] ? args[index + 1] : fallback;
1901
1993
  }
1994
+ export function buildCodexAppUiDiagnosticFailure(apply, error) {
1995
+ return {
1996
+ schema: 'sks.codex-app-fast-ui-repair.v1',
1997
+ ok: false,
1998
+ apply,
1999
+ safe_auto_apply: false,
2000
+ requires_confirmation: true,
2001
+ fast_selector: 'manual_action_required',
2002
+ provider_selector: 'manual_action_required',
2003
+ host_owned_config: 'diagnostic_failed',
2004
+ next_action: 'Review Codex App UI config manually.',
2005
+ actions: [],
2006
+ blockers: [error instanceof Error ? error.message : String(error)]
2007
+ };
2008
+ }
1902
2009
  export function formatCodexDoctorConsoleStatus(report) {
1903
2010
  if (!report || report.available !== true)
1904
2011
  return 'unavailable';