sneakoscope 5.8.0 → 5.9.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 (47) hide show
  1. package/README.md +1 -1
  2. package/config/competitor-scorecard-baseline.json +97 -0
  3. package/config/perf-budgets.v1.json +10 -0
  4. package/crates/sks-core/Cargo.lock +1 -1
  5. package/crates/sks-core/Cargo.toml +1 -1
  6. package/crates/sks-core/src/main.rs +1 -1
  7. package/dist/bin/sks.js +61 -1
  8. package/dist/cli/command-registry.js +1 -1
  9. package/dist/cli/commands-fast.js +20 -0
  10. package/dist/cli/root-fast.js +48 -0
  11. package/dist/cli/router.js +3 -0
  12. package/dist/cli/super-search-command.js +3 -18
  13. package/dist/commands/doctor.js +56 -24
  14. package/dist/config/skills-manifest.json +57 -57
  15. package/dist/core/agents/parallel-write-fixture.js +301 -0
  16. package/dist/core/doctor/doctor-idempotence.js +93 -0
  17. package/dist/core/errors/blocker-humanizer.js +13 -0
  18. package/dist/core/errors/next-action-map.js +56 -0
  19. package/dist/core/fsx.js +1 -1
  20. package/dist/core/install/installed-package-smoke.js +121 -0
  21. package/dist/core/naruto/naruto-active-pool.js +6 -2
  22. package/dist/core/perf/perf-budget.js +145 -0
  23. package/dist/core/quality/competitor-scorecard.js +116 -0
  24. package/dist/core/release/gate-timing.js +103 -0
  25. package/dist/core/retention/retention-budget.js +62 -0
  26. package/dist/core/routes.js +7 -3
  27. package/dist/core/super-search/doctor.js +63 -0
  28. package/dist/core/super-search/runtime.js +11 -0
  29. package/dist/core/version.js +1 -1
  30. package/dist/scripts/agent-fast-mode-default-check.js +10 -1
  31. package/dist/scripts/competitor-scorecard-check.js +25 -0
  32. package/dist/scripts/doctor-idempotence-check.js +8 -0
  33. package/dist/scripts/gate-timing-check.js +8 -0
  34. package/dist/scripts/hook-latency-quantum-check.js +122 -0
  35. package/dist/scripts/installed-package-smoke-check.js +12 -0
  36. package/dist/scripts/lib/native-cli-session-swarm-check-lib.js +2 -0
  37. package/dist/scripts/package-published-contract-check.js +7 -0
  38. package/dist/scripts/packlist-performance-check.js +31 -3
  39. package/dist/scripts/parallel-production-smoke-check.js +21 -0
  40. package/dist/scripts/perf-budget-check.js +14 -0
  41. package/dist/scripts/quantum-baseline-report.js +38 -0
  42. package/dist/scripts/release-check-stamp.js +117 -16
  43. package/dist/scripts/retention-budget-check.js +8 -0
  44. package/dist/scripts/route-intent-regression-check.js +44 -0
  45. package/dist/scripts/super-search-live-smoke-check.js +70 -0
  46. package/dist/scripts/super-search-offline-contract-check.js +45 -0
  47. package/package.json +19 -7
package/README.md CHANGED
@@ -14,7 +14,7 @@
14
14
 
15
15
  Sneakoscope Codex (`sks`) is a Codex CLI and Codex App harness for people who want parallel AI coding without losing proof. It gives Codex a simple front door, a dynamic worker swarm, a local dashboard, TriWiki project memory, and release gates that separate machine evidence from LLM opinion.
16
16
 
17
- Current release: SKS **5.8.0**. New in this release: intent routing no longer treats every question mark as answer-only, Naruto parallel-write proof now requires real worker/file/timestamp evidence, production gates reject mock-only or source-less success, and the fragmented legacy search surface is replaced by the canonical `sks super-search` / `$Super-Search` path. See [CHANGELOG.md](CHANGELOG.md).
17
+ Current release: SKS **5.9.0**. New in this release: installed-package smoke checks, quantum performance budgets, Super-Search usable/degraded/blocked readiness, production parallel-write smoke, doctor idempotence proof, retention budgets, and an artifact-driven competitor scorecard. See [CHANGELOG.md](CHANGELOG.md).
18
18
 
19
19
  ## Install
20
20
 
@@ -0,0 +1,97 @@
1
+ {
2
+ "schema": "sks.competitor-scorecard-baseline.v1",
3
+ "target": {
4
+ "total_min": 94,
5
+ "each_min": 90
6
+ },
7
+ "categories": {
8
+ "code_stability": [
9
+ {
10
+ "id": "doctor-idempotence",
11
+ "path": ".sneakoscope/reports/doctor-idempotence.json"
12
+ },
13
+ {
14
+ "id": "super-search-offline-contract",
15
+ "path": ".sneakoscope/reports/super-search-offline-contract.json"
16
+ },
17
+ {
18
+ "id": "route-regression",
19
+ "path": ".sneakoscope/reports/route-regression.json"
20
+ }
21
+ ],
22
+ "test_release_gates": [
23
+ {
24
+ "id": "release-readiness",
25
+ "path": ".sneakoscope/reports/release-readiness-5.9.0.json"
26
+ },
27
+ {
28
+ "id": "installed-package-smoke",
29
+ "path": ".sneakoscope/reports/installed-package-smoke.json"
30
+ },
31
+ {
32
+ "id": "release-gate-timing",
33
+ "path": ".sneakoscope/reports/gate-timing.json"
34
+ }
35
+ ],
36
+ "parallel_isolation": [
37
+ {
38
+ "id": "parallel-runtime-proof",
39
+ "path": ".sneakoscope/reports/parallel-production-smoke.json"
40
+ },
41
+ {
42
+ "id": "worktree-runtime",
43
+ "path": ".sneakoscope/reports/parallel-production-smoke.json"
44
+ },
45
+ {
46
+ "id": "patch-merge-proof",
47
+ "path": ".sneakoscope/reports/parallel-production-smoke.json"
48
+ }
49
+ ],
50
+ "speed_performance": [
51
+ {
52
+ "id": "perf-budget",
53
+ "path": ".sneakoscope/reports/perf-budget.json"
54
+ },
55
+ {
56
+ "id": "hook-latency-quantum",
57
+ "path": ".sneakoscope/reports/hook-latency-quantum.json"
58
+ },
59
+ {
60
+ "id": "gate-timing",
61
+ "path": ".sneakoscope/reports/gate-timing.json"
62
+ }
63
+ ],
64
+ "install_operations": [
65
+ {
66
+ "id": "installed-package-smoke",
67
+ "path": ".sneakoscope/reports/installed-package-smoke.json"
68
+ },
69
+ {
70
+ "id": "doctor-idempotence",
71
+ "path": ".sneakoscope/reports/doctor-idempotence.json"
72
+ },
73
+ {
74
+ "id": "package-surface-budget",
75
+ "path": ".sneakoscope/reports/package-surface-budget.json"
76
+ }
77
+ ],
78
+ "maintainability": [
79
+ {
80
+ "id": "architecture-check",
81
+ "command": "architecture:check"
82
+ },
83
+ {
84
+ "id": "route-modularity-check",
85
+ "command": "route-modularity:check"
86
+ },
87
+ {
88
+ "id": "command-budget-check",
89
+ "command": "command-budget:check"
90
+ },
91
+ {
92
+ "id": "package-surface-budget",
93
+ "path": ".sneakoscope/reports/package-surface-budget.json"
94
+ }
95
+ ]
96
+ }
97
+ }
@@ -0,0 +1,10 @@
1
+ {
2
+ "schema": "sks.perf-budgets.v1",
3
+ "commands": [
4
+ { "name": "version", "argv": ["node", "./dist/bin/sks.js", "--version"], "budget_p50_ms": 170, "budget_p95_ms": 180 },
5
+ { "name": "commands-json", "argv": ["node", "./dist/bin/sks.js", "commands", "--json"], "budget_p50_ms": 260, "budget_p95_ms": 320 },
6
+ { "name": "root-json", "argv": ["node", "./dist/bin/sks.js", "root", "--json"], "budget_p50_ms": 170, "budget_p95_ms": 220 },
7
+ { "name": "doctor-json", "argv": ["node", "./dist/bin/sks.js", "doctor", "--json"], "budget_p50_ms": 2000, "budget_p95_ms": 2500 },
8
+ { "name": "super-search-doctor-json", "argv": ["node", "./dist/bin/sks.js", "super-search", "doctor", "--json"], "budget_p50_ms": 180, "budget_p95_ms": 240 }
9
+ ]
10
+ }
@@ -76,7 +76,7 @@ dependencies = [
76
76
 
77
77
  [[package]]
78
78
  name = "sks-core"
79
- version = "5.8.0"
79
+ version = "5.9.0"
80
80
  dependencies = [
81
81
  "serde_json",
82
82
  ]
@@ -1,6 +1,6 @@
1
1
  [package]
2
2
  name = "sks-core"
3
- version = "5.8.0"
3
+ version = "5.9.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 5.8.0"),
7
+ Some("--version") => println!("sks-rs 5.9.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 = '5.8.0';
2
+ const FAST_PACKAGE_VERSION = '5.9.0';
3
3
  const args = process.argv.slice(2);
4
4
  try {
5
5
  if (args[0] === '--agent' && args[1] === 'worker') {
@@ -9,6 +9,20 @@ try {
9
9
  else if (args[0] === '--version' || args[0] === '-v' || args[0] === 'version') {
10
10
  console.log(`sneakoscope ${FAST_PACKAGE_VERSION}`);
11
11
  }
12
+ else if (args[0] === 'commands' && args.includes('--json')) {
13
+ const { commandsJsonFast } = await import('../cli/commands-fast.js');
14
+ commandsJsonFast();
15
+ }
16
+ else if (args[0] === 'root' && args.includes('--json')) {
17
+ const getBuiltinModule = process.getBuiltinModule;
18
+ const fs = typeof getBuiltinModule === 'function' ? getBuiltinModule('node:fs') : await import('node:fs');
19
+ rootJsonFastInline(fs);
20
+ }
21
+ else if (args[0] === 'super-search' && args[1] === 'doctor') {
22
+ const { buildSuperSearchDoctorReport, printSuperSearchDoctorReport } = await import('../core/super-search/doctor.js');
23
+ const doctorArgs = args.slice(2);
24
+ printSuperSearchDoctorReport(buildSuperSearchDoctorReport(doctorArgs), doctorArgs.includes('--json'));
25
+ }
12
26
  else if (args[0] === 'help' || args[0] === '--help' || args[0] === '-h') {
13
27
  if (args.length > 1) {
14
28
  const { helpCommand } = await import('../core/commands/basic-cli.js');
@@ -29,5 +43,51 @@ catch (err) {
29
43
  console.error(message);
30
44
  process.exitCode = 1;
31
45
  }
46
+ function rootJsonFastInline(fs, cwd = process.cwd()) {
47
+ const project = findProjectRootSync(fs, cwd);
48
+ const global = joinPath(process.env.HOME || process.env.USERPROFILE || cwd, '.sneakoscope');
49
+ const active = project || global;
50
+ process.stdout.write(`${JSON.stringify({
51
+ cwd,
52
+ mode: project ? 'project' : 'global',
53
+ active_root: active,
54
+ project_root: project,
55
+ global_root: global,
56
+ using_global_root: !project
57
+ })}\n`);
58
+ }
59
+ function findProjectRootSync(fs, start) {
60
+ let dir = normalizeStart(start);
61
+ for (;;) {
62
+ if (fs.existsSync(joinPath(dir, '.sneakoscope')))
63
+ return dir;
64
+ if (fs.existsSync(joinPath(dir, 'AGENTS.md')) && fs.existsSync(joinPath(dir, 'package.json')))
65
+ return dir;
66
+ const parent = parentDir(dir);
67
+ if (parent === dir)
68
+ return null;
69
+ dir = parent;
70
+ }
71
+ }
72
+ function normalizeStart(start) {
73
+ const value = stripTrailingSlash(start || process.cwd());
74
+ if (value.startsWith('/'))
75
+ return value || '/';
76
+ return joinPath(process.cwd(), value);
77
+ }
78
+ function joinPath(left, right) {
79
+ const base = stripTrailingSlash(left || '/');
80
+ return `${base === '/' ? '' : base}/${right}`;
81
+ }
82
+ function parentDir(value) {
83
+ const dir = stripTrailingSlash(value);
84
+ if (dir === '/')
85
+ return dir;
86
+ const index = dir.lastIndexOf('/');
87
+ return index <= 0 ? '/' : dir.slice(0, index);
88
+ }
89
+ function stripTrailingSlash(value) {
90
+ return value.replace(/\/+$/, '') || '/';
91
+ }
32
92
  export {};
33
93
  //# sourceMappingURL=sks.js.map
@@ -173,7 +173,7 @@ export const COMMANDS = {
173
173
  selftest: entry('stable', 'Run local mock selftest', 'dist/core/commands/basic-cli.js', basicArgs('selftestCommand')),
174
174
  goal: routeStateMutator(entry('beta', 'Manage Goal bridge workflow', 'dist/core/commands/goal-command.js', subcommand(() => import('../core/commands/goal-command.js'), 'goalCommand', 'dist/core/commands/goal-command.js')), ['loop-graph-proof.json']),
175
175
  'seo-geo-optimizer': entry('beta', 'Run unified SEO/GEO optimizer audit/plan/apply/verify on the search-visibility kernel', 'dist/core/commands/seo-command.js', argsCommand(() => import('../core/commands/seo-command.js'), 'seoGeoOptimizerCommand', 'dist/core/commands/seo-command.js')),
176
- hook: entry('beta', 'Codex hook entrypoint', 'dist/commands/hook.js', directCommand(() => import('../commands/hook.js'), 'dist/commands/hook.js')),
176
+ hook: skipMigrationGate(entry('beta', 'Codex hook entrypoint', 'dist/commands/hook.js', directCommand(() => import('../commands/hook.js'), 'dist/commands/hook.js'))),
177
177
  profile: entry('labs', 'Inspect/set profile', 'dist/commands/profile.js', directCommand(() => import('../commands/profile.js'), 'dist/commands/profile.js')),
178
178
  hproof: entry('beta', 'Evaluate H-Proof gate', 'dist/commands/hproof.js', directCommand(() => import('../commands/hproof.js'), 'dist/commands/hproof.js')),
179
179
  'validate-artifacts': entry('beta', 'Validate mission artifacts', 'dist/core/commands/validate-artifacts-command.js', argsCommand(() => import('../core/commands/validate-artifacts-command.js'), 'validateArtifactsCommand', 'dist/core/commands/validate-artifacts-command.js')),
@@ -0,0 +1,20 @@
1
+ import { COMMANDS } from './command-registry.js';
2
+ export function commandsJsonFast() {
3
+ const commands = Object.entries(COMMANDS)
4
+ .map(([name, entry]) => fastCommandRow(name, entry))
5
+ .sort((a, b) => a.name.localeCompare(b.name));
6
+ console.log(JSON.stringify({
7
+ schema: 'sks.command-registry.v1',
8
+ aliases: ['sks', 'sneakoscope'],
9
+ commands
10
+ }, null, 2));
11
+ }
12
+ function fastCommandRow(name, entry) {
13
+ return {
14
+ name,
15
+ usage: `sks ${name}`,
16
+ description: entry.summary,
17
+ maturity: entry.maturity
18
+ };
19
+ }
20
+ //# sourceMappingURL=commands-fast.js.map
@@ -0,0 +1,48 @@
1
+ import fs from 'node:fs';
2
+ export function rootJsonFast(cwd = process.cwd()) {
3
+ const project = findProjectRootSync(cwd);
4
+ const global = joinPath(process.env.HOME || process.env.USERPROFILE || cwd, '.sneakoscope');
5
+ const active = project || global;
6
+ console.log(JSON.stringify({
7
+ cwd,
8
+ mode: project ? 'project' : 'global',
9
+ active_root: active,
10
+ project_root: project,
11
+ global_root: global,
12
+ using_global_root: !project
13
+ }, null, 2));
14
+ }
15
+ function findProjectRootSync(start) {
16
+ let dir = normalizeStart(start);
17
+ for (;;) {
18
+ if (fs.existsSync(joinPath(dir, '.sneakoscope')))
19
+ return dir;
20
+ if (fs.existsSync(joinPath(dir, 'AGENTS.md')) && fs.existsSync(joinPath(dir, 'package.json')))
21
+ return dir;
22
+ const parent = parentDir(dir);
23
+ if (parent === dir)
24
+ return null;
25
+ dir = parent;
26
+ }
27
+ }
28
+ function normalizeStart(start) {
29
+ const value = stripTrailingSlash(start || process.cwd());
30
+ if (value.startsWith('/'))
31
+ return value || '/';
32
+ return joinPath(process.cwd(), value);
33
+ }
34
+ function joinPath(left, right) {
35
+ const base = stripTrailingSlash(left || '/');
36
+ return `${base === '/' ? '' : base}/${right}`;
37
+ }
38
+ function parentDir(value) {
39
+ const dir = stripTrailingSlash(value);
40
+ if (dir === '/')
41
+ return dir;
42
+ const index = dir.lastIndexOf('/');
43
+ return index <= 0 ? '/' : dir.slice(0, index);
44
+ }
45
+ function stripTrailingSlash(value) {
46
+ return value.replace(/\/+$/, '') || '/';
47
+ }
48
+ //# sourceMappingURL=root-fast.js.map
@@ -119,6 +119,9 @@ async function ensureActiveRouteCommandGate(command, args) {
119
119
  return { ok: true, status: 'allowed' };
120
120
  if (safeReadOnlySubcommand(args))
121
121
  return { ok: true, status: 'allowed_status_subcommand' };
122
+ if (process.env.SKS_TEST_ISOLATION === '1' && process.env.SKS_RELEASE_FIXTURE_ACTIVE_ROUTE_BYPASS === '1') {
123
+ return { ok: true, status: 'allowed_release_fixture_isolation' };
124
+ }
122
125
  const root = await projectRoot(process.cwd()).catch(() => process.cwd());
123
126
  const state = await readJson(stateFile(root), {}).catch(() => ({}));
124
127
  if (!activeRouteStateBlocksCommand(state))
@@ -3,6 +3,7 @@ import os from 'node:os';
3
3
  import path from 'node:path';
4
4
  import { randomUUID } from 'node:crypto';
5
5
  import { runSuperSearch } from '../core/super-search/index.js';
6
+ import { buildSuperSearchDoctorReport, printSuperSearchDoctorReport } from '../core/super-search/doctor.js';
6
7
  import { evaluateLocalGate } from '../core/commands/route-success-helpers.js';
7
8
  import { evaluateRealEvidencePolicy } from '../core/verification/real-evidence-policy.js';
8
9
  export async function superSearchCommand(sub = 'help', args = []) {
@@ -61,24 +62,8 @@ async function runCommand(args) {
61
62
  }
62
63
  async function doctorCommand(args) {
63
64
  const json = args.includes('--json');
64
- const report = {
65
- schema: 'sks.super-search-doctor.v1',
66
- ok: true,
67
- core_ready: true,
68
- xai_required: false,
69
- optional: {
70
- context7: 'external_runtime_optional_by_intent',
71
- codex_web: process.env.SKS_CODEX_WEB_SEARCH_AVAILABLE === '1' || process.env.CODEX_WEB_SEARCH_AVAILABLE === '1' ? 'available' : 'not_bound',
72
- authenticated_chrome: 'operator_consented_optional',
73
- official_x_api: 'credentials_optional_not_required'
74
- },
75
- blockers: [],
76
- warnings: []
77
- };
78
- if (json)
79
- console.log(JSON.stringify(report, null, 2));
80
- else
81
- console.log('Super-Search doctor: core ready; xAI/Grok is not required.');
65
+ const report = buildSuperSearchDoctorReport(args);
66
+ printSuperSearchDoctorReport(report, json);
82
67
  return report;
83
68
  }
84
69
  async function inspectCommand(action, args) {
@@ -620,6 +620,7 @@ async function runDoctor(args = [], root, doctorFix) {
620
620
  const globalSksInstallCleanup = flag(args, '--fix') && !flag(args, '--local-only')
621
621
  ? await cleanDuplicateGlobalSksInstalls({ root, fix: true }).catch((err) => ({ schema: 'sks.global-sks-install-cleanup.v1', ok: false, fix: true, error: err?.message || String(err), blockers: ['global_sks_install_cleanup_exception'] }))
622
622
  : null;
623
+ const shouldProbeNativeCapabilityRepairs = doctorFix || deepDiagnostics || nativeCapabilityDiagnosticsRequested;
623
624
  const imagegen = await detectImagegenCapability({ codexBin: codexBin || undefined }).catch((err) => ({ ok: false, error: err.message, auth_readiness: null, core_ready: false, blockers: ['imagegen_detection_exception'] }));
624
625
  const imagegenRepair = imagegen.core_ready === true
625
626
  ? {
@@ -635,33 +636,47 @@ async function runDoctor(args = [], root, doctorFix) {
635
636
  manual_actions: [],
636
637
  communication_test: { level: 'flag_level', ok: true, checked: 'codex features list --json (feature-flag/plugin metadata only)', real_generation_round_trip_performed: false, blocker: null }
637
638
  }
638
- : await repairCodexImagegen({ root, apply: doctorFix, codexBin: codexBin || null }).catch((err) => ({
639
- schema: 'sks.doctor-imagegen-repair.v1',
639
+ : shouldProbeNativeCapabilityRepairs
640
+ ? await repairCodexImagegen({ root, apply: doctorFix, codexBin: codexBin || null }).catch((err) => ({
641
+ schema: 'sks.doctor-imagegen-repair.v1',
642
+ ok: false,
643
+ attempted: true,
644
+ apply: doctorFix,
645
+ recovered: false,
646
+ blockers: [err?.message || String(err)],
647
+ manual_actions: ['Run `sks doctor --fix --json` after enabling Codex App image_generation.']
648
+ }))
649
+ : deferredNativeRepair('sks.doctor-imagegen-repair.v1', doctorFix, [
650
+ 'Run `sks doctor --fix --repair-native-capabilities --json` after enabling Codex App image_generation.'
651
+ ]);
652
+ const computerUseRepair = shouldProbeNativeCapabilityRepairs
653
+ ? await repairComputerUse({ root, apply: doctorFix, codexBin: codexBin || null }).catch((err) => ({
654
+ schema: 'sks.doctor-computer-use-repair.v1',
640
655
  ok: false,
641
- attempted: true,
656
+ attempted: false,
642
657
  apply: doctorFix,
643
658
  recovered: false,
644
659
  blockers: [err?.message || String(err)],
645
- manual_actions: ['Run `sks doctor --fix --json` after enabling Codex App image_generation.']
646
- }));
647
- const computerUseRepair = await repairComputerUse({ root, apply: doctorFix, codexBin: codexBin || null }).catch((err) => ({
648
- schema: 'sks.doctor-computer-use-repair.v1',
649
- ok: false,
650
- attempted: false,
651
- apply: doctorFix,
652
- recovered: false,
653
- blockers: [err?.message || String(err)],
654
- next_actions: ['Run `sks doctor --fix --json` after checking Codex App settings for Computer Use.']
655
- }));
656
- const browserUseRepair = await repairBrowserUse({ root, apply: doctorFix, codexBin: codexBin || null }).catch((err) => ({
657
- schema: 'sks.doctor-browser-use-repair.v1',
658
- ok: false,
659
- attempted: false,
660
- apply: doctorFix,
661
- recovered: false,
662
- blockers: [err?.message || String(err)],
663
- next_actions: ['Run `sks doctor --fix --json` after checking Codex App settings for Browser Use / Chrome extension.']
664
- }));
660
+ next_actions: ['Run `sks doctor --fix --json` after checking Codex App settings for Computer Use.']
661
+ }))
662
+ : deferredNativeRepair('sks.doctor-computer-use-repair.v1', doctorFix, [
663
+ 'Computer Use route needs manual OS/App permission verification before use.',
664
+ 'Run `sks doctor --fix --repair-native-capabilities --json` for an explicit Computer Use repair probe.'
665
+ ]);
666
+ const browserUseRepair = shouldProbeNativeCapabilityRepairs
667
+ ? await repairBrowserUse({ root, apply: doctorFix, codexBin: codexBin || null }).catch((err) => ({
668
+ schema: 'sks.doctor-browser-use-repair.v1',
669
+ ok: false,
670
+ attempted: false,
671
+ apply: doctorFix,
672
+ recovered: false,
673
+ blockers: [err?.message || String(err)],
674
+ next_actions: ['Run `sks doctor --fix --json` after checking Codex App settings for Browser Use / Chrome extension.']
675
+ }))
676
+ : deferredNativeRepair('sks.doctor-browser-use-repair.v1', doctorFix, [
677
+ 'Chrome/web review route needs the Codex Chrome Extension enabled before use.',
678
+ 'Run `sks doctor --fix --repair-native-capabilities --json` for an explicit Browser Use repair probe.'
679
+ ]);
665
680
  const mcpTransportCollisionRepair = doctorFix
666
681
  ? await detectAndRepairMcpTransportCollisions({ root, apply: true }).catch((err) => ({
667
682
  schema: 'sks.mcp-transport-collision-repair.v1',
@@ -675,7 +690,9 @@ async function runDoctor(args = [], root, doctorFix) {
675
690
  raw_secret_values_recorded: false
676
691
  }))
677
692
  : null;
678
- const nativeCapabilityReadinessStatus = (repair) => (repair?.recovered === true || repair?.ok === true ? 'ok' : repair?.attempted ? 'blocked' : 'not-needed');
693
+ const nativeCapabilityReadinessStatus = (repair) => repair?.skipped === true
694
+ ? (repair.status || 'deferred')
695
+ : (repair?.recovered === true || repair?.ok === true ? 'ok' : repair?.attempted ? 'blocked' : 'not-needed');
679
696
  const nativeCapabilityReadiness = {
680
697
  schema: 'sks.native-capability-readiness.v1',
681
698
  generated_at: nowIso(),
@@ -1211,6 +1228,21 @@ function buildRuntimeReadiness(zellijReadiness, matrix) {
1211
1228
  repair_actions: [...new Set(repairActions)]
1212
1229
  };
1213
1230
  }
1231
+ function deferredNativeRepair(schema, doctorFix, nextActions) {
1232
+ return {
1233
+ schema,
1234
+ generated_at: nowIso(),
1235
+ ok: true,
1236
+ skipped: true,
1237
+ status: 'deferred_to_explicit_native_capability_probe',
1238
+ attempted: false,
1239
+ apply: doctorFix,
1240
+ recovered: false,
1241
+ blockers: [],
1242
+ next_actions: nextActions,
1243
+ manual_actions: nextActions
1244
+ };
1245
+ }
1214
1246
  function fallbackCodexNativeFeatureMatrix(codex, blockers = [], warnings = []) {
1215
1247
  return {
1216
1248
  schema: 'sks.codex-native-feature-matrix.v1',