sneakoscope 8.3.2 → 8.6.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 (122) hide show
  1. package/README.md +1 -1
  2. package/config/architecture-map-policy.v1.json +168 -0
  3. package/crates/sks-core/Cargo.lock +1 -1
  4. package/crates/sks-core/Cargo.toml +1 -1
  5. package/dist/commands/bridge.js +19 -1
  6. package/dist/commands/doctor-profile.js +1 -1
  7. package/dist/commands/doctor.js +97 -16
  8. package/dist/config/skills-manifest.json +1 -1
  9. package/dist/core/align/align-route.js +8 -2
  10. package/dist/core/align/code-navigation-align.js +88 -32
  11. package/dist/core/architecture-map-pipeline.js +173 -0
  12. package/dist/core/architecture-map-review.js +180 -0
  13. package/dist/core/codex/agent-config-file-repair.js +17 -3
  14. package/dist/core/codex/codex-config-guard.js +3 -1
  15. package/dist/core/codex/codex-feature-flags.js +10 -0
  16. package/dist/core/codex/codex-project-config-policy.js +54 -30
  17. package/dist/core/codex/codex-startup-config-postcheck.js +5 -0
  18. package/dist/core/codex-app/codex-app-fast-ui-repair.js +2 -1
  19. package/dist/core/codex-app/menubar/constants.js +1 -0
  20. package/dist/core/codex-hooks/codex-hook-state-writer.js +2 -0
  21. package/dist/core/codex-lb/codex-lb-env.js +25 -3
  22. package/dist/core/codex-lb/combined-catalog/builder.js +7 -2
  23. package/dist/core/codex-lb/combined-catalog/model-selection.js +71 -0
  24. package/dist/core/codex-lb/combined-catalog/normalize.js +20 -3
  25. package/dist/core/codex-lb/desktop-bridge/security.js +11 -8
  26. package/dist/core/codex-lb/desktop-controller-v3/catalog.js +75 -4
  27. package/dist/core/codex-lb/desktop-controller-v3.js +5 -1
  28. package/dist/core/codex-lb/request-route-resolver.js +21 -18
  29. package/dist/core/commands/triwiki-atlas-command.js +372 -0
  30. package/dist/core/commands/triwiki-command.js +12 -1
  31. package/dist/core/doctor/doctor-dirty-planner.js +16 -1
  32. package/dist/core/doctor/doctor-idempotence.js +11 -0
  33. package/dist/core/doctor/doctor-repair-postcheck.js +49 -0
  34. package/dist/core/doctor/doctor-transaction.js +47 -2
  35. package/dist/core/doctor/legacy-global-hook-cleanup.js +1 -1
  36. package/dist/core/fsx.js +14 -0
  37. package/dist/core/git-hygiene/git-policy.js +4 -0
  38. package/dist/core/git-hygiene/gitignore-writer.js +2 -0
  39. package/dist/core/gx-renderer.js +2 -1
  40. package/dist/core/init.js +40 -17
  41. package/dist/core/managed-paths.js +1 -0
  42. package/dist/core/perf/release-latency-slo.js +57 -11
  43. package/dist/core/pipeline-internals/pipeline-stage-builder.js +181 -0
  44. package/dist/core/pipeline-internals/runtime-core.js +18 -172
  45. package/dist/core/pipeline-internals/runtime-gates.js +12 -1
  46. package/dist/core/release/content-digest-cache.js +70 -0
  47. package/dist/core/release/gate-manifest.js +9 -0
  48. package/dist/core/release/main-push-guard.js +4 -3
  49. package/dist/core/release/package-dist-snapshot.js +18 -2
  50. package/dist/core/release/physical-release-gates.js +26 -3
  51. package/dist/core/release/release-authorization-snapshot.js +4 -0
  52. package/dist/core/release/release-gate-cache-v2.js +27 -3
  53. package/dist/core/release/release-gate-contract.js +2 -0
  54. package/dist/core/release/release-gate-dag.js +3 -0
  55. package/dist/core/release/release-inspection-memo.js +69 -0
  56. package/dist/core/release/release-pack-content-scanner.js +5 -0
  57. package/dist/core/release/release-pack-receipt.js +28 -18
  58. package/dist/core/release/release-pack-tarball.js +10 -0
  59. package/dist/core/release/release-upgrade-baseline.js +4 -0
  60. package/dist/core/routes.js +1 -1
  61. package/dist/core/safety/ssot-authority-inventory.js +114 -0
  62. package/dist/core/safety/ssot-guard.js +2 -44
  63. package/dist/core/subagents/agent-catalog.js +4 -2
  64. package/dist/core/subagents/official-subagent-config.js +92 -15
  65. package/dist/core/subagents/official-subagent-preparation.js +1 -0
  66. package/dist/core/triwiki/context-graph/architecture/baseline.js +81 -0
  67. package/dist/core/triwiki/context-graph/architecture/capsule.js +34 -0
  68. package/dist/core/triwiki/context-graph/architecture/contracts.js +67 -0
  69. package/dist/core/triwiki/context-graph/architecture/delta.js +149 -0
  70. package/dist/core/triwiki/context-graph/architecture/finding-factory.js +28 -0
  71. package/dist/core/triwiki/context-graph/architecture/findings.js +173 -0
  72. package/dist/core/triwiki/context-graph/architecture/fingerprint.js +75 -0
  73. package/dist/core/triwiki/context-graph/architecture/index.js +15 -0
  74. package/dist/core/triwiki/context-graph/architecture/input-bundle.js +66 -0
  75. package/dist/core/triwiki/context-graph/architecture/metrics.js +137 -0
  76. package/dist/core/triwiki/context-graph/architecture/policy.js +321 -0
  77. package/dist/core/triwiki/context-graph/architecture/slice.js +100 -0
  78. package/dist/core/triwiki/context-graph/architecture/ssot-analysis.js +59 -0
  79. package/dist/core/triwiki/context-graph/architecture/topology-overlay.js +106 -0
  80. package/dist/core/triwiki/context-graph/architecture/validation.js +145 -0
  81. package/dist/core/triwiki/context-graph/architecture/voxel-context.js +39 -0
  82. package/dist/core/triwiki/context-graph/extractors/index.js +4 -0
  83. package/dist/core/triwiki/context-graph/projections/index.js +2 -0
  84. package/dist/core/triwiki/context-graph/projections/mermaid/architecture-delta.js +68 -0
  85. package/dist/core/triwiki/context-graph/projections/mermaid/ast.js +49 -0
  86. package/dist/core/triwiki/context-graph/projections/mermaid/change-impact.js +43 -0
  87. package/dist/core/triwiki/context-graph/projections/mermaid/contracts.js +5 -0
  88. package/dist/core/triwiki/context-graph/projections/mermaid/escape.js +45 -0
  89. package/dist/core/triwiki/context-graph/projections/mermaid/ids.js +73 -0
  90. package/dist/core/triwiki/context-graph/projections/mermaid/index.js +113 -0
  91. package/dist/core/triwiki/context-graph/projections/mermaid/manifest.js +37 -0
  92. package/dist/core/triwiki/context-graph/projections/mermaid/module-dependency.js +21 -0
  93. package/dist/core/triwiki/context-graph/projections/mermaid/ownership-workstream.js +21 -0
  94. package/dist/core/triwiki/context-graph/projections/mermaid/project-topology.js +13 -0
  95. package/dist/core/triwiki/context-graph/projections/mermaid/public-surface.js +17 -0
  96. package/dist/core/triwiki/context-graph/projections/mermaid/reduce.js +44 -0
  97. package/dist/core/triwiki/context-graph/projections/mermaid/risk-domains.js +23 -0
  98. package/dist/core/triwiki/context-graph/projections/mermaid/runtime-control.js +20 -0
  99. package/dist/core/triwiki/context-graph/projections/mermaid/selection-ledger.js +94 -0
  100. package/dist/core/triwiki/context-graph/projections/mermaid/serializer.js +81 -0
  101. package/dist/core/triwiki/context-graph/projections/mermaid/ssot-provenance.js +17 -0
  102. package/dist/core/triwiki/context-graph/projections/mermaid/verification-coverage.js +17 -0
  103. package/dist/core/triwiki/context-graph/projections/mermaid/view-builder-common.js +1 -0
  104. package/dist/core/triwiki/context-graph/projections/mermaid/view-builder.js +173 -0
  105. package/dist/core/triwiki/context-graph/projections/mermaid/view-specs.js +33 -0
  106. package/dist/core/triwiki/context-graph/store/architecture-map-store.js +71 -0
  107. package/dist/core/triwiki/triwiki-proof-bank-index.js +26 -1
  108. package/dist/core/triwiki/triwiki-proof-bank.js +82 -2
  109. package/dist/core/version.js +1 -1
  110. package/dist/native/sks-menubar/Sources/OverviewViewController.swift +2 -2
  111. package/dist/native/sks-menubar/Sources/ProvidersModelExposure.swift +178 -0
  112. package/dist/native/sks-menubar/Sources/ProvidersViewController.swift +10 -1
  113. package/dist/scripts/architecture-map-check.js +299 -0
  114. package/dist/scripts/lib/ensure-dist-fresh.js +48 -1
  115. package/dist/scripts/release-metadata-check.js +2 -0
  116. package/package.json +6 -3
  117. package/release-gates.v2.json +204 -0
  118. package/schemas/architecture-baseline.v1.schema.json +47 -0
  119. package/schemas/architecture-map-manifest.v1.schema.json +40 -0
  120. package/schemas/architecture-map-policy.v1.schema.json +147 -0
  121. package/schemas/architecture-review.v1.schema.json +46 -0
  122. package/schemas/mermaid-projection.v1.schema.json +47 -0
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 8.3.2** — 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 8.6.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
 
@@ -0,0 +1,168 @@
1
+ {
2
+ "schema": "sks.architecture-map-policy.v1",
3
+ "version": 1,
4
+ "module_id_source": "context-graph module node id, as produced by src/core/triwiki/context-graph/extractors/code/modules.ts: the owning directory, capped at depth 3 under src|source|lib and depth 2 elsewhere. Entries below are exact module ids, never globs; a module not named by any layer is unconstrained.",
5
+ "layers": [
6
+ {
7
+ "id": "entrypoint",
8
+ "purpose": "Process entry. Nothing in the repository imports these modules, so argv arrives here and only leaves downward.",
9
+ "modules": ["src/bin"]
10
+ },
11
+ {
12
+ "id": "cli_surface",
13
+ "purpose": "Argument parsing, terminal output, the command registry and the command manifest.",
14
+ "modules": ["src/cli"]
15
+ },
16
+ {
17
+ "id": "command",
18
+ "purpose": "One handler per user-facing command, split across a thin dispatch root and the heavier implementations.",
19
+ "modules": ["src/commands", "src/core/commands"]
20
+ },
21
+ {
22
+ "id": "orchestration",
23
+ "purpose": "Route classification, pipeline plans, gate profiles and the stop gate.",
24
+ "modules": [
25
+ "src/core/pipeline",
26
+ "src/core/pipeline-internals",
27
+ "src/core/router",
28
+ "src/core/routes",
29
+ "src/core/runtime",
30
+ "src/core/stop-gate"
31
+ ]
32
+ },
33
+ {
34
+ "id": "release",
35
+ "purpose": "Release gate manifest, gate DAG, scheduling and publish contracts.",
36
+ "modules": ["src/core/release"]
37
+ },
38
+ {
39
+ "id": "knowledge",
40
+ "purpose": "TriWiki: the context graph, code packs, the proof bank and the wrongness ledger.",
41
+ "modules": ["src/core/triwiki", "src/core/triwiki-wrongness"]
42
+ },
43
+ {
44
+ "id": "foundation",
45
+ "purpose": "Domain-free primitives: error shapes, JSON records, file locks, regex helpers.",
46
+ "modules": ["src/core/errors", "src/core/json", "src/core/locks", "src/core/text"]
47
+ },
48
+ {
49
+ "id": "gate_script",
50
+ "purpose": "Standalone check executables invoked by npm scripts and the release DAG.",
51
+ "modules": ["src/scripts", "src/scripts/lib"]
52
+ }
53
+ ],
54
+ "boundaries": {
55
+ "mode": "allow-list",
56
+ "allow": [
57
+ { "from": "entrypoint", "to": ["cli_surface", "command", "orchestration"] },
58
+ {
59
+ "from": "cli_surface",
60
+ "to": ["command", "orchestration", "release", "knowledge", "foundation"]
61
+ },
62
+ { "from": "command", "to": ["orchestration", "release", "knowledge", "foundation"] },
63
+ { "from": "orchestration", "to": ["release", "knowledge", "foundation"] },
64
+ { "from": "release", "to": ["knowledge", "foundation"] },
65
+ { "from": "knowledge", "to": ["foundation"] },
66
+ { "from": "foundation", "to": [] },
67
+ {
68
+ "from": "gate_script",
69
+ "to": ["cli_surface", "command", "orchestration", "release", "knowledge", "foundation"]
70
+ }
71
+ ]
72
+ },
73
+ "thresholds": {
74
+ "max_diagram_nodes": 240,
75
+ "max_diagram_edges": 900,
76
+ "max_diagram_bytes": 45000,
77
+ "max_module_fan_out": 56,
78
+ "max_module_fan_in": 96
79
+ },
80
+ "profiles": {
81
+ "global": { "maxNodes": 240, "maxEdges": 360, "maxLabelChars": 56, "tokenBudget": 0 },
82
+ "planning": { "maxNodes": 48, "maxEdges": 72, "maxLabelChars": 56, "tokenBudget": 900 },
83
+ "implementation": { "maxNodes": 64, "maxEdges": 96, "maxLabelChars": 56, "tokenBudget": 1200 },
84
+ "review": { "maxNodes": 72, "maxEdges": 108, "maxLabelChars": 56, "tokenBudget": 1600 },
85
+ "protected": { "maxNodes": 96, "maxEdges": 144, "maxLabelChars": 56, "tokenBudget": 2400 }
86
+ },
87
+ "absoluteTokenCeiling": 3200,
88
+ "globalAtlasMaxBytes": 1572864,
89
+ "missionArtifactsMaxBytes": 358400,
90
+ "accuracyFloors": {
91
+ "changedPathAccounting": 1,
92
+ "projectionAccounting": 1,
93
+ "protectedRelationRecall": 1,
94
+ "eligibleExtractionSuccess": 0.995,
95
+ "deterministicHashRuns": 3
96
+ },
97
+ "dependencyRules": [
98
+ {
99
+ "id": "boundary-allow-list",
100
+ "effect": "deny",
101
+ "severity": "blocking",
102
+ "description": "Module edges that cross layers outside boundaries.allow (and outside shrink-only exceptions) are forbidden_dependency findings."
103
+ }
104
+ ],
105
+ "viewBudgets": {
106
+ "project-topology": { "maxNodes": 240, "maxEdges": 360 },
107
+ "module-dependency": { "maxNodes": 240, "maxEdges": 900 },
108
+ "public-surface": { "maxNodes": 120, "maxEdges": 180 },
109
+ "ssot-provenance": { "maxNodes": 96, "maxEdges": 144 },
110
+ "runtime-control": { "maxNodes": 120, "maxEdges": 180 },
111
+ "verification-coverage": { "maxNodes": 160, "maxEdges": 240 },
112
+ "risk-domains": { "maxNodes": 96, "maxEdges": 144 }
113
+ },
114
+ "blockingCodes": [
115
+ "baseline_missing",
116
+ "baseline_late",
117
+ "baseline_stale",
118
+ "baseline_tampered",
119
+ "graph_stale",
120
+ "map_parity_failure",
121
+ "unaccounted_changed_file",
122
+ "new_cycle",
123
+ "cycle_expansion",
124
+ "forbidden_dependency",
125
+ "layer_skip",
126
+ "ssot_collision",
127
+ "authority_bypass",
128
+ "protected_verification_gap",
129
+ "insufficient_graph"
130
+ ],
131
+ "exceptions": {
132
+ "mode": "shrink-only",
133
+ "entries": [
134
+ {
135
+ "id": "cli-layer-hosts-shared-surfaces",
136
+ "reason": "src/cli owns dispatch surface and terminal presentation toolkit; handlers reach up for formatting.",
137
+ "edges": [
138
+ "command -> cli_surface",
139
+ "orchestration -> cli_surface",
140
+ "knowledge -> cli_surface"
141
+ ],
142
+ "baseline_module_edges": 4,
143
+ "ceiling_module_edges": 4
144
+ },
145
+ {
146
+ "id": "command-layer-hosts-shared-contracts",
147
+ "reason": "Shared shapes hosted in the command layer rather than below it.",
148
+ "edges": ["knowledge -> command", "release -> command"],
149
+ "baseline_module_edges": 2,
150
+ "ceiling_module_edges": 2
151
+ },
152
+ {
153
+ "id": "release-knowledge-cycle",
154
+ "reason": "release and triwiki form a real two-module cycle; only the upward half is excepted.",
155
+ "edges": ["knowledge -> release"],
156
+ "baseline_module_edges": 1,
157
+ "ceiling_module_edges": 1
158
+ },
159
+ {
160
+ "id": "script-root-hosts-libraries",
161
+ "reason": "src/scripts is an entry root but some files are imported as libraries.",
162
+ "edges": ["cli_surface -> gate_script", "release -> gate_script"],
163
+ "baseline_module_edges": 2,
164
+ "ceiling_module_edges": 2
165
+ }
166
+ ]
167
+ }
168
+ }
@@ -259,7 +259,7 @@ dependencies = [
259
259
 
260
260
  [[package]]
261
261
  name = "sks-core"
262
- version = "8.3.2"
262
+ version = "8.6.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 = "8.3.2"
3
+ version = "8.6.0"
4
4
  edition = "2021"
5
5
 
6
6
  [dependencies]
@@ -23,6 +23,8 @@ export function usage(command = 'bridge') {
23
23
  ` sks ${command} provider validate|enable|disable <codex-lb|openrouter> [--json]`,
24
24
  ` sks ${command} provider remove-credential <codex-lb|openrouter> --confirm [--json]`,
25
25
  ` sks ${command} catalog sync|status [--json]`,
26
+ ` sks ${command} models list [--json]`,
27
+ ` sks ${command} models select --set <public-id,...> [--json]`,
26
28
  ` sks ${command} route list [--json]`,
27
29
  ` sks ${command} route set-default <codex-lb|openrouter> [--json]`,
28
30
  ` sks ${command} route explain <model> [--json]`,
@@ -204,6 +206,22 @@ async function parseInvocation(args, io) {
204
206
  label: `Combined catalog ${action}`
205
207
  };
206
208
  }
209
+ if (area === 'models') {
210
+ if (action === 'list' && target === undefined) {
211
+ allowOnly(parsed, ['--json'], []);
212
+ return { ...base, request: { operation: 'models.list' }, label: 'Selectable bridge models' };
213
+ }
214
+ if (action === 'select') {
215
+ allowOnly(parsed, ['--json'], ['--set']);
216
+ const raw = parsed.values.get('--set') || '';
217
+ const publicIds = raw.split(',').map((id) => id.trim()).filter(Boolean);
218
+ return {
219
+ ...base,
220
+ request: { operation: 'models.select', public_ids: publicIds },
221
+ label: 'Select exposed bridge models'
222
+ };
223
+ }
224
+ }
207
225
  if (area === 'route') {
208
226
  if (action === 'list' && target === undefined) {
209
227
  allowOnly(parsed, ['--json'], []);
@@ -254,7 +272,7 @@ function parseArgs(args) {
254
272
  const booleanOptions = new Set([
255
273
  '--json', '--strict', '--require-ready', '--api-key-stdin', '--confirm'
256
274
  ]);
257
- const valueOptions = new Set(['--level', '--host', '--settings']);
275
+ const valueOptions = new Set(['--level', '--host', '--settings', '--set']);
258
276
  for (let index = 0; index < args.length; index += 1) {
259
277
  const value = String(args[index] || '');
260
278
  if (!value.startsWith('--')) {
@@ -43,7 +43,7 @@ export function doctorPhaseIdsForProfile(profile) {
43
43
  ];
44
44
  if (profile === 'migration')
45
45
  return required;
46
- const optional = ['supabase_mcp_repair', 'native_capability_repair', 'sks_menubar'];
46
+ const optional = ['supabase_mcp_repair', 'native_capability_repair', 'sks_menubar', 'desktop_bridge_catalog_repair'];
47
47
  if (profile === 'full' || profile === 'capabilities')
48
48
  return ['setup', ...required, ...optional];
49
49
  return [...required, ...optional];
@@ -7,7 +7,7 @@ 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 } from '../core/codex-lb/desktop-controller-v3.js';
10
+ import { desktopBridgeStatusV3, executeDesktopBridgeCommandV3 } from '../core/codex-lb/desktop-controller-v3.js';
11
11
  import { inspectCodexConfigReadability } from '../core/codex/codex-config-readability.js';
12
12
  import { inspectOAuthCallbackPortConflict, oauthCallbackDoctorGuidance } from '../core/codex/oauth-callback-port-diagnostic.js';
13
13
  import { inventoryCodexPermissionProfiles } from '../core/codex/codex-permission-profiles.js';
@@ -825,6 +825,7 @@ async function runDoctor(args = [], root, doctorFix, deps = {}) {
825
825
  phases: [
826
826
  {
827
827
  id: 'setup',
828
+ report: () => setupRepair,
828
829
  run: async () => ({
829
830
  id: 'setup',
830
831
  ok: setupRepair !== null,
@@ -835,6 +836,7 @@ async function runDoctor(args = [], root, doctorFix, deps = {}) {
835
836
  },
836
837
  {
837
838
  id: 'codex_startup_repair',
839
+ report: () => codexStartupRepair,
838
840
  run: async () => ({
839
841
  id: 'codex_startup_repair',
840
842
  ok: codexStartupRepair?.ok !== false,
@@ -846,6 +848,7 @@ async function runDoctor(args = [], root, doctorFix, deps = {}) {
846
848
  },
847
849
  {
848
850
  id: 'startup_config_repair',
851
+ report: () => startupConfigRepair,
849
852
  run: async () => ({
850
853
  id: 'startup_config_repair',
851
854
  ok: startupConfigRepair?.ok === true,
@@ -856,6 +859,7 @@ async function runDoctor(args = [], root, doctorFix, deps = {}) {
856
859
  },
857
860
  {
858
861
  id: 'codex_config_syntax_repair',
862
+ report: () => codexConfigSyntaxRepair,
859
863
  run: async () => ({
860
864
  id: 'codex_config_syntax_repair',
861
865
  ok: codexConfigSyntaxRepair?.ok !== false,
@@ -867,6 +871,7 @@ async function runDoctor(args = [], root, doctorFix, deps = {}) {
867
871
  },
868
872
  {
869
873
  id: 'context7_repair',
874
+ report: () => context7Repair,
870
875
  run: async () => ({
871
876
  id: 'context7_repair',
872
877
  ok: context7Repair?.ok !== false,
@@ -878,6 +883,7 @@ async function runDoctor(args = [], root, doctorFix, deps = {}) {
878
883
  },
879
884
  {
880
885
  id: 'context7_mcp_repair',
886
+ report: () => context7McpRepair,
881
887
  run: async () => ({
882
888
  id: 'context7_mcp_repair',
883
889
  ok: context7McpRepair?.ok === true,
@@ -890,6 +896,7 @@ async function runDoctor(args = [], root, doctorFix, deps = {}) {
890
896
  },
891
897
  {
892
898
  id: 'supabase_mcp_repair',
899
+ report: () => supabaseMcpRepair,
893
900
  required_for_ready: false,
894
901
  run: async () => ({
895
902
  id: 'supabase_mcp_repair',
@@ -904,6 +911,7 @@ async function runDoctor(args = [], root, doctorFix, deps = {}) {
904
911
  },
905
912
  {
906
913
  id: 'hook_trust_repair',
914
+ report: () => hookTrustRepair,
907
915
  run: async () => ({
908
916
  id: 'hook_trust_repair',
909
917
  ok: hookTrustRepair?.ok !== false,
@@ -917,6 +925,7 @@ async function runDoctor(args = [], root, doctorFix, deps = {}) {
917
925
  },
918
926
  {
919
927
  id: 'sks_menubar',
928
+ report: () => sksMenuBar,
920
929
  required_for_ready: false,
921
930
  run: async () => ({
922
931
  id: 'sks_menubar',
@@ -961,6 +970,7 @@ async function runDoctor(args = [], root, doctorFix, deps = {}) {
961
970
  },
962
971
  {
963
972
  id: 'command_alias_cleanup',
973
+ report: () => commandAliasCleanupBeforeReceipt,
964
974
  run: async () => ({
965
975
  id: 'command_alias_cleanup',
966
976
  ok: commandAliasCleanupBeforeReceipt?.ok !== false,
@@ -972,6 +982,7 @@ async function runDoctor(args = [], root, doctorFix, deps = {}) {
972
982
  },
973
983
  {
974
984
  id: 'native_capability_repair',
985
+ report: () => doctorNativeCapabilityRepair,
975
986
  required_for_ready: false,
976
987
  run: async () => ({
977
988
  id: 'native_capability_repair',
@@ -984,6 +995,38 @@ async function runDoctor(args = [], root, doctorFix, deps = {}) {
984
995
  route_blockers: doctorNativeCapabilityRepair?.route_blockers || {},
985
996
  rollback_evidence: doctorNativeCapabilityRepair?.secret_preservation_guard || 'native_capability_repair_report'
986
997
  })
998
+ },
999
+ {
1000
+ id: 'desktop_bridge_catalog_repair',
1001
+ required_for_ready: false,
1002
+ run: async () => {
1003
+ const base = {
1004
+ id: 'desktop_bridge_catalog_repair',
1005
+ required_for_ready: false,
1006
+ manual_required: false,
1007
+ warnings: [],
1008
+ rollback_evidence: 'combined_catalog_previous_generation_preserved'
1009
+ };
1010
+ try {
1011
+ const status = await desktopBridgeStatusV3({ home: root, env: process.env });
1012
+ const blockers = (status?.readiness?.blockers || []).map(String);
1013
+ const stale = blockers.filter((blocker) => blocker.endsWith('_catalog_stale'));
1014
+ if (!status?.management?.managed || stale.length === 0) {
1015
+ return { ...base, ok: true, repaired: false, blockers: [] };
1016
+ }
1017
+ const sync = await executeDesktopBridgeCommandV3({ operation: 'catalog.sync' }, { home: root, env: process.env });
1018
+ const synced = sync?.ok === true && sync?.execution?.ok === true;
1019
+ return {
1020
+ ...base,
1021
+ ok: synced,
1022
+ repaired: synced,
1023
+ blockers: synced ? [] : (sync?.execution?.blockers || ['desktop_bridge_catalog_sync_failed']).map(String)
1024
+ };
1025
+ }
1026
+ catch (error) {
1027
+ return { ...base, ok: false, repaired: false, blockers: [String(error?.message || 'desktop_bridge_catalog_sync_failed')] };
1028
+ }
1029
+ }
987
1030
  }
988
1031
  ].filter((phase) => doctorPhaseIds.includes(phase.id))
989
1032
  }).catch((err) => ({
@@ -1182,6 +1225,20 @@ async function runDoctor(args = [], root, doctorFix, deps = {}) {
1182
1225
  warnings: []
1183
1226
  }))
1184
1227
  : null;
1228
+ const configDiskVerification = doctorFix
1229
+ ? await (await import('../core/doctor/doctor-repair-postcheck.js')).verifyCodexConfigsOnDisk({ root })
1230
+ .catch((err) => ({
1231
+ schema: 'sks.doctor-config-disk-verification.v1',
1232
+ ok: false,
1233
+ project_config_path: '',
1234
+ codex_home_config_path: '',
1235
+ project_config_present: false,
1236
+ codex_home_config_present: false,
1237
+ multi_agent_v2_enabled: null,
1238
+ agents_enabled: null,
1239
+ blockers: [`config_disk_verification_failed:${err?.message || String(err)}`]
1240
+ }))
1241
+ : null;
1185
1242
  const codexAppHarnessMatrix = deepDiagnostics
1186
1243
  ? await buildCodexAppHarnessMatrix({ root, mode: 'read-only' }).catch((err) => ({
1187
1244
  schema: 'sks.codex-app-harness-matrix.v1',
@@ -1353,16 +1410,36 @@ async function runDoctor(args = [], root, doctorFix, deps = {}) {
1353
1410
  }
1354
1411
  }
1355
1412
  const runtimeReadiness = buildRuntimeReadiness(codexNativeFeatureMatrix);
1356
- const resultOk = ready.ready
1357
- && (!sksUpdate || sksUpdate.ok !== false)
1358
- && (!doctorFix || migrationReceiptOwnsReconcile || skillsReconcile?.convergence?.ok === true)
1359
- && commandAliasCleanup.ok !== false
1360
- && codexStartupRepair.ok !== false
1361
- && codexConfigSyntaxRepair?.ok !== false
1362
- && agentRoleConfigRepair.ok !== false
1363
- && openRouterProviderRepair.ok !== false
1364
- && (officialSubagentConfig.blockers || []).length === 0
1365
- && (!doctorProfileRequiresDesktopBridgeReadiness(doctorProfile) || desktopBridge.ok !== false);
1413
+ const resultBlockers = [
1414
+ ...(ready.ready
1415
+ ? []
1416
+ : (Array.isArray(ready.blockers) && ready.blockers.length
1417
+ ? ready.blockers.map((blocker) => `readiness:${String(blocker)}`)
1418
+ : ['readiness_not_ready'])),
1419
+ ...(sksUpdate && sksUpdate.ok === false ? ['sks_update_blocked'] : []),
1420
+ ...(doctorFix && !migrationReceiptOwnsReconcile && skillsReconcile?.convergence?.ok !== true
1421
+ ? ['managed_skill_reconcile_not_converged']
1422
+ : []),
1423
+ ...(commandAliasCleanup.ok === false ? ['command_alias_cleanup_blocked'] : []),
1424
+ ...(codexStartupRepair.ok === false ? ['codex_startup_repair_blocked'] : []),
1425
+ ...(codexConfigSyntaxRepair?.ok === false ? ['codex_config_syntax_repair_blocked'] : []),
1426
+ ...(agentRoleConfigRepair.ok === false ? ['agent_role_config_repair_blocked'] : []),
1427
+ ...(openRouterProviderRepair.ok === false ? ['openrouter_provider_repair_blocked'] : []),
1428
+ ...((officialSubagentConfig.blockers || [])
1429
+ .map((blocker) => `official_subagent_config:${String(blocker)}`)),
1430
+ ...(doctorProfileRequiresDesktopBridgeReadiness(doctorProfile) && desktopBridge.ok === false
1431
+ ? ['desktop_bridge_not_ready']
1432
+ : []),
1433
+ ...(mcpTransportCollisionRepair?.ok === false ? ['mcp_transport_collision_repair_blocked'] : []),
1434
+ ...(codexNativeRepair?.ok === false ? ['codex_native_repair_blocked'] : []),
1435
+ ...(configDiskVerification?.blockers || [])
1436
+ .map((blocker) => `config_disk_verification:${String(blocker)}`)
1437
+ ];
1438
+ const resultOk = resultBlockers.length === 0;
1439
+ const repairOperatorActions = [
1440
+ ...(codexStartupRepair?.config_file_repair?.operator_actions || []),
1441
+ ...(agentRoleConfigRepair?.operator_actions || [])
1442
+ ].map(String).filter(Boolean);
1366
1443
  const result = {
1367
1444
  schema: 'sks.doctor-status.v3',
1368
1445
  elapsed_ms: Date.now() - startedAtMs,
@@ -1377,11 +1454,14 @@ async function runDoctor(args = [], root, doctorFix, deps = {}) {
1377
1454
  not_counted_as_full_doctor: !deepDiagnostics,
1378
1455
  root,
1379
1456
  arg_warnings: argWarnings,
1457
+ blockers: [...new Set(resultBlockers.map(String))],
1380
1458
  warnings: [...oauthCallbackPortDiagnostic.warnings, ...(desktopBridge.warnings || [])],
1381
- operator_actions: [
1382
- ...oauthCallbackOperatorActions,
1383
- ...(desktopBridge.ok === false ? desktopBridge.recovery_actions || [] : [])
1384
- ],
1459
+ operator_actions: [...new Set([
1460
+ ...oauthCallbackOperatorActions,
1461
+ ...(desktopBridge.ok === false ? desktopBridge.recovery_actions || [] : []),
1462
+ ...repairOperatorActions,
1463
+ ...(resultOk ? [] : ['Each blocker above names a report under .sneakoscope/reports/; re-run `sks doctor --full --json` after resolving them.'])
1464
+ ].map(String).filter(Boolean))],
1385
1465
  node: { ok: Number(process.versions.node.split('.')[0]) >= 20, version: process.version },
1386
1466
  codex,
1387
1467
  oauth_callback_port_diagnostic: oauthCallbackPortDiagnostic,
@@ -1406,8 +1486,9 @@ async function runDoctor(args = [], root, doctorFix, deps = {}) {
1406
1486
  supabase_mcp_repair: supabaseMcpRepair,
1407
1487
  doctor_fix_transaction: doctorFixTransaction,
1408
1488
  doctor_fix_postcheck: doctorFixPostcheck,
1489
+ config_disk_verification: configDiskVerification,
1409
1490
  postcheck: doctorFixPostcheck ? {
1410
- ok: doctorFixPostcheck.ok === true,
1491
+ ok: doctorFixPostcheck.ok === true && configDiskVerification?.ok !== false,
1411
1492
  pending_manual: doctorFixPostcheck.pending_manual || [],
1412
1493
  required_blockers: doctorFixPostcheck.required_blockers || [],
1413
1494
  optional_warnings: doctorFixPostcheck.optional_warnings || []
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "schema": "sks.skills-manifest.v1",
3
- "package_version": "8.3.2",
3
+ "package_version": "8.6.0",
4
4
  "skills": [
5
5
  {
6
6
  "canonical_name": "sks",
@@ -3,6 +3,7 @@ import fs from 'node:fs';
3
3
  import fsp from 'node:fs/promises';
4
4
  import path from 'node:path';
5
5
  import { nowIso, readJson, writeJsonAtomic } from '../fsx.js';
6
+ import { ARCHITECTURE_MAP_ARTIFACT_RELS } from '../triwiki/context-graph/store/architecture-map-store.js';
6
7
  import { CODE_NAVIGATION_LIMITS } from '../triwiki/code-navigation-policy.js';
7
8
  export const ALIGN_PLAN_ARTIFACT = 'align-plan.json';
8
9
  export const ALIGN_LEDGER_ARTIFACT = 'align-ledger.json';
@@ -21,7 +22,8 @@ export const ALIGN_OUTPUT_ARTIFACTS = Object.freeze([
21
22
  '.sneakoscope/wiki/context-graph.meta.json',
22
23
  '.sneakoscope/wiki/code-navigation-manifest.json',
23
24
  '.sneakoscope/wiki/code-pack.json',
24
- '.sneakoscope/wiki/context-pack.json'
25
+ '.sneakoscope/wiki/context-pack.json',
26
+ ...ARCHITECTURE_MAP_ARTIFACT_RELS
25
27
  ]);
26
28
  export function buildAlignPlan(missionId, task) {
27
29
  return {
@@ -143,7 +145,11 @@ export function evaluateAlignGate(plan, ledger, missionId, activeVerification =
143
145
  skips: (ledger?.scan.fatal_skips.length ?? 1) === 0,
144
146
  coverage: ledger?.graph.exact_file_coverage === true && ledger.graph.missing_files.length === 0 && ledger.graph.unexpected_files.length === 0,
145
147
  cas: ledger?.scan.source_cas_verified === true,
146
- extractor: ledger?.graph.extractor_ids.length === 1 && ledger.graph.extractor_ids[0] === 'code',
148
+ extractor: Array.isArray(ledger?.graph.extractor_ids)
149
+ && ledger.graph.extractor_ids.length === 3
150
+ && ledger.graph.extractor_ids[0] === 'code'
151
+ && ledger.graph.extractor_ids[1] === 'topology'
152
+ && ledger.graph.extractor_ids[2] === 'triwiki-evidence',
147
153
  publication: ledger?.publication.staged === true && ledger.publication.transactional_directory_replaced === true,
148
154
  artifacts: ledger?.validation.artifact_hashes === true && activeVerification.artifacts,
149
155
  projection: ledger?.validation.projection === true && activeVerification.projections,