sneakoscope 8.3.2 → 8.4.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +1 -1
- package/config/architecture-map-policy.v1.json +168 -0
- package/crates/sks-core/Cargo.lock +1 -1
- package/crates/sks-core/Cargo.toml +1 -1
- package/dist/commands/bridge.js +19 -1
- package/dist/commands/doctor-profile.js +1 -1
- package/dist/commands/doctor.js +33 -1
- package/dist/config/skills-manifest.json +1 -1
- package/dist/core/align/align-route.js +8 -2
- package/dist/core/align/code-navigation-align.js +88 -32
- package/dist/core/architecture-map-pipeline.js +172 -0
- package/dist/core/architecture-map-review.js +180 -0
- package/dist/core/codex-app/codex-app-fast-ui-repair.js +2 -1
- package/dist/core/codex-app/menubar/constants.js +1 -0
- package/dist/core/codex-lb/codex-lb-env.js +25 -3
- package/dist/core/codex-lb/combined-catalog/builder.js +7 -2
- package/dist/core/codex-lb/combined-catalog/model-selection.js +71 -0
- package/dist/core/codex-lb/combined-catalog/normalize.js +20 -3
- package/dist/core/codex-lb/desktop-controller-v3/catalog.js +75 -4
- package/dist/core/codex-lb/desktop-controller-v3.js +5 -1
- package/dist/core/commands/triwiki-atlas-command.js +372 -0
- package/dist/core/commands/triwiki-command.js +12 -1
- package/dist/core/fsx.js +14 -0
- package/dist/core/git-hygiene/git-policy.js +4 -0
- package/dist/core/git-hygiene/gitignore-writer.js +2 -0
- package/dist/core/gx-renderer.js +2 -1
- package/dist/core/managed-paths.js +1 -0
- package/dist/core/perf/release-latency-slo.js +57 -11
- package/dist/core/pipeline-internals/pipeline-stage-builder.js +181 -0
- package/dist/core/pipeline-internals/runtime-core.js +13 -172
- package/dist/core/pipeline-internals/runtime-gates.js +12 -1
- package/dist/core/release/content-digest-cache.js +70 -0
- package/dist/core/release/gate-manifest.js +9 -0
- package/dist/core/release/main-push-guard.js +4 -3
- package/dist/core/release/package-dist-snapshot.js +18 -2
- package/dist/core/release/physical-release-gates.js +26 -3
- package/dist/core/release/release-authorization-snapshot.js +4 -0
- package/dist/core/release/release-gate-cache-v2.js +27 -3
- package/dist/core/release/release-gate-contract.js +2 -0
- package/dist/core/release/release-gate-dag.js +3 -0
- package/dist/core/release/release-inspection-memo.js +69 -0
- package/dist/core/release/release-pack-content-scanner.js +5 -0
- package/dist/core/release/release-pack-receipt.js +28 -18
- package/dist/core/release/release-pack-tarball.js +10 -0
- package/dist/core/release/release-upgrade-baseline.js +4 -0
- package/dist/core/routes.js +1 -1
- package/dist/core/safety/ssot-authority-inventory.js +114 -0
- package/dist/core/safety/ssot-guard.js +2 -44
- package/dist/core/triwiki/context-graph/architecture/baseline.js +81 -0
- package/dist/core/triwiki/context-graph/architecture/capsule.js +34 -0
- package/dist/core/triwiki/context-graph/architecture/contracts.js +67 -0
- package/dist/core/triwiki/context-graph/architecture/delta.js +149 -0
- package/dist/core/triwiki/context-graph/architecture/finding-factory.js +28 -0
- package/dist/core/triwiki/context-graph/architecture/findings.js +173 -0
- package/dist/core/triwiki/context-graph/architecture/fingerprint.js +75 -0
- package/dist/core/triwiki/context-graph/architecture/index.js +15 -0
- package/dist/core/triwiki/context-graph/architecture/input-bundle.js +66 -0
- package/dist/core/triwiki/context-graph/architecture/metrics.js +137 -0
- package/dist/core/triwiki/context-graph/architecture/policy.js +321 -0
- package/dist/core/triwiki/context-graph/architecture/slice.js +100 -0
- package/dist/core/triwiki/context-graph/architecture/ssot-analysis.js +59 -0
- package/dist/core/triwiki/context-graph/architecture/topology-overlay.js +106 -0
- package/dist/core/triwiki/context-graph/architecture/validation.js +145 -0
- package/dist/core/triwiki/context-graph/architecture/voxel-context.js +39 -0
- package/dist/core/triwiki/context-graph/extractors/index.js +4 -0
- package/dist/core/triwiki/context-graph/projections/index.js +2 -0
- package/dist/core/triwiki/context-graph/projections/mermaid/architecture-delta.js +68 -0
- package/dist/core/triwiki/context-graph/projections/mermaid/ast.js +49 -0
- package/dist/core/triwiki/context-graph/projections/mermaid/change-impact.js +43 -0
- package/dist/core/triwiki/context-graph/projections/mermaid/contracts.js +5 -0
- package/dist/core/triwiki/context-graph/projections/mermaid/escape.js +45 -0
- package/dist/core/triwiki/context-graph/projections/mermaid/ids.js +73 -0
- package/dist/core/triwiki/context-graph/projections/mermaid/index.js +113 -0
- package/dist/core/triwiki/context-graph/projections/mermaid/manifest.js +37 -0
- package/dist/core/triwiki/context-graph/projections/mermaid/module-dependency.js +21 -0
- package/dist/core/triwiki/context-graph/projections/mermaid/ownership-workstream.js +21 -0
- package/dist/core/triwiki/context-graph/projections/mermaid/project-topology.js +13 -0
- package/dist/core/triwiki/context-graph/projections/mermaid/public-surface.js +17 -0
- package/dist/core/triwiki/context-graph/projections/mermaid/reduce.js +44 -0
- package/dist/core/triwiki/context-graph/projections/mermaid/risk-domains.js +23 -0
- package/dist/core/triwiki/context-graph/projections/mermaid/runtime-control.js +20 -0
- package/dist/core/triwiki/context-graph/projections/mermaid/selection-ledger.js +94 -0
- package/dist/core/triwiki/context-graph/projections/mermaid/serializer.js +81 -0
- package/dist/core/triwiki/context-graph/projections/mermaid/ssot-provenance.js +17 -0
- package/dist/core/triwiki/context-graph/projections/mermaid/verification-coverage.js +17 -0
- package/dist/core/triwiki/context-graph/projections/mermaid/view-builder-common.js +1 -0
- package/dist/core/triwiki/context-graph/projections/mermaid/view-builder.js +173 -0
- package/dist/core/triwiki/context-graph/projections/mermaid/view-specs.js +33 -0
- package/dist/core/triwiki/context-graph/store/architecture-map-store.js +71 -0
- package/dist/core/triwiki/triwiki-proof-bank-index.js +26 -1
- package/dist/core/triwiki/triwiki-proof-bank.js +82 -2
- package/dist/core/version.js +1 -1
- package/dist/native/sks-menubar/Sources/OverviewViewController.swift +2 -2
- package/dist/native/sks-menubar/Sources/ProvidersModelExposure.swift +178 -0
- package/dist/native/sks-menubar/Sources/ProvidersViewController.swift +10 -1
- package/dist/scripts/architecture-map-check.js +299 -0
- package/dist/scripts/lib/ensure-dist-fresh.js +48 -1
- package/dist/scripts/release-metadata-check.js +2 -0
- package/package.json +6 -3
- package/release-gates.v2.json +204 -0
- package/schemas/architecture-baseline.v1.schema.json +47 -0
- package/schemas/architecture-map-manifest.v1.schema.json +40 -0
- package/schemas/architecture-map-policy.v1.schema.json +147 -0
- package/schemas/architecture-review.v1.schema.json +46 -0
- 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.
|
|
25
|
+
This README documents package **SKS 8.4.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
|
+
}
|
package/dist/commands/bridge.js
CHANGED
|
@@ -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];
|
package/dist/commands/doctor.js
CHANGED
|
@@ -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';
|
|
@@ -984,6 +984,38 @@ async function runDoctor(args = [], root, doctorFix, deps = {}) {
|
|
|
984
984
|
route_blockers: doctorNativeCapabilityRepair?.route_blockers || {},
|
|
985
985
|
rollback_evidence: doctorNativeCapabilityRepair?.secret_preservation_guard || 'native_capability_repair_report'
|
|
986
986
|
})
|
|
987
|
+
},
|
|
988
|
+
{
|
|
989
|
+
id: 'desktop_bridge_catalog_repair',
|
|
990
|
+
required_for_ready: false,
|
|
991
|
+
run: async () => {
|
|
992
|
+
const base = {
|
|
993
|
+
id: 'desktop_bridge_catalog_repair',
|
|
994
|
+
required_for_ready: false,
|
|
995
|
+
manual_required: false,
|
|
996
|
+
warnings: [],
|
|
997
|
+
rollback_evidence: 'combined_catalog_previous_generation_preserved'
|
|
998
|
+
};
|
|
999
|
+
try {
|
|
1000
|
+
const status = await desktopBridgeStatusV3({ home: root, env: process.env });
|
|
1001
|
+
const blockers = (status?.readiness?.blockers || []).map(String);
|
|
1002
|
+
const stale = blockers.filter((blocker) => blocker.endsWith('_catalog_stale'));
|
|
1003
|
+
if (!status?.management?.managed || stale.length === 0) {
|
|
1004
|
+
return { ...base, ok: true, repaired: false, blockers: [] };
|
|
1005
|
+
}
|
|
1006
|
+
const sync = await executeDesktopBridgeCommandV3({ operation: 'catalog.sync' }, { home: root, env: process.env });
|
|
1007
|
+
const synced = sync?.ok === true && sync?.execution?.ok === true;
|
|
1008
|
+
return {
|
|
1009
|
+
...base,
|
|
1010
|
+
ok: synced,
|
|
1011
|
+
repaired: synced,
|
|
1012
|
+
blockers: synced ? [] : (sync?.execution?.blockers || ['desktop_bridge_catalog_sync_failed']).map(String)
|
|
1013
|
+
};
|
|
1014
|
+
}
|
|
1015
|
+
catch (error) {
|
|
1016
|
+
return { ...base, ok: false, repaired: false, blockers: [String(error?.message || 'desktop_bridge_catalog_sync_failed')] };
|
|
1017
|
+
}
|
|
1018
|
+
}
|
|
987
1019
|
}
|
|
988
1020
|
].filter((phase) => doctorPhaseIds.includes(phase.id))
|
|
989
1021
|
}).catch((err) => ({
|
|
@@ -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
|
|
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,
|
|
@@ -7,15 +7,40 @@ import { guardedRename, guardedRm, guardContextForRoute } from '../safety/mutati
|
|
|
7
7
|
import { createRequestedScopeContract } from '../safety/requested-scope-contract.js';
|
|
8
8
|
import { projectTriwikiToAgentsMdTransactional } from '../triwiki/agents-md-projector.js';
|
|
9
9
|
import { buildCodeNavigationContextPack, validateCodeNavigationContextPack } from '../triwiki/code-navigation-context-pack.js';
|
|
10
|
-
import { CODE_NAVIGATION_FATAL_SKIP_REASONS, CODE_NAVIGATION_LIMITS
|
|
10
|
+
import { CODE_NAVIGATION_FATAL_SKIP_REASONS, CODE_NAVIGATION_LIMITS } from '../triwiki/code-navigation-policy.js';
|
|
11
11
|
import { isCodePackProjectionBoundToSnapshot, projectCodePackFromGraph, validateCodePack } from '../triwiki/code-pack.js';
|
|
12
12
|
import { validateContextGraphSnapshot } from '../triwiki/context-graph/contracts.js';
|
|
13
13
|
import { compileContextGraph } from '../triwiki/context-graph/compiler/index.js';
|
|
14
14
|
import { readSourceHashes } from '../triwiki/context-graph/compiler/freshness.js';
|
|
15
|
-
import {
|
|
15
|
+
import { ARCHITECTURE_MAP_EXTRACTOR_IDS, architectureMapGraphExtractors } from '../triwiki/context-graph/extractors/index.js';
|
|
16
|
+
import { computeContextGraphCacheKey } from '../triwiki/context-graph/compiler/cache-key.js';
|
|
17
|
+
import { walkCodeInventory } from '../triwiki/context-graph/extractors/code/inventory.js';
|
|
18
|
+
import { codeInventoryInputHashes } from '../triwiki/code-navigation-policy.js';
|
|
16
19
|
import { clearContextGraphSnapshotCache } from '../triwiki/context-graph/query/snapshot-cache.js';
|
|
17
20
|
import { withTriWikiStateLock } from '../triwiki/triwiki-cleanup.js';
|
|
21
|
+
import { publishArchitectureMapToStage } from '../triwiki/context-graph/store/architecture-map-store.js';
|
|
18
22
|
import { ALIGN_GATE_ARTIFACT, ALIGN_LEDGER_ARTIFACT, ALIGN_OUTPUT_ARTIFACTS, ALIGN_PLAN_ARTIFACT, ALIGN_STAGING_ROOT_REL, buildInitialAlignLedger, refreshAlignGate } from './align-route.js';
|
|
23
|
+
const WIKI_PREFIX = '.sneakoscope/wiki/';
|
|
24
|
+
function isArchitectureMapOptionalSkip(skip) {
|
|
25
|
+
const rel = skip.path.replace(/\\/g, '/');
|
|
26
|
+
if (skip.reason !== 'unreadable' && skip.reason !== 'excluded')
|
|
27
|
+
return false;
|
|
28
|
+
if (rel === '.sneakoscope/wiki/context-pack.json')
|
|
29
|
+
return true;
|
|
30
|
+
if (rel.startsWith('.sneakoscope/triwiki/proof-bank'))
|
|
31
|
+
return true;
|
|
32
|
+
if (rel.startsWith('.sneakoscope/wiki/'))
|
|
33
|
+
return true;
|
|
34
|
+
return false;
|
|
35
|
+
}
|
|
36
|
+
function isAlignFatalSkip(skip) {
|
|
37
|
+
if (!CODE_NAVIGATION_FATAL_SKIP_REASONS.has(skip.reason))
|
|
38
|
+
return false;
|
|
39
|
+
return !isArchitectureMapOptionalSkip(skip);
|
|
40
|
+
}
|
|
41
|
+
if (new Set(ALIGN_OUTPUT_ARTIFACTS).size !== ALIGN_OUTPUT_ARTIFACTS.length) {
|
|
42
|
+
throw new Error('align_output_artifacts_not_unique');
|
|
43
|
+
}
|
|
19
44
|
const ALIGN_REPLACED_SURFACES = Object.freeze([
|
|
20
45
|
{ key: 'wiki', rel: '.sneakoscope/wiki' },
|
|
21
46
|
{ key: 'memory', rel: '.sneakoscope/memory' },
|
|
@@ -116,19 +141,19 @@ async function buildPack(root, snapshot, meta, generatedAt) {
|
|
|
116
141
|
observedSourceHashes: observed
|
|
117
142
|
}).pack;
|
|
118
143
|
}
|
|
119
|
-
function buildManifest(generatedAt,
|
|
144
|
+
function buildManifest(generatedAt, inventory, inventoryDigest, snapshot) {
|
|
120
145
|
return {
|
|
121
146
|
schema: 'sks.code-navigation-manifest.v1',
|
|
122
147
|
generated_at: generatedAt,
|
|
123
148
|
source_policy: 'repository_code_only',
|
|
124
149
|
exhaustive_graph: 'context-graph.json',
|
|
125
|
-
inventory_digest:
|
|
150
|
+
inventory_digest: inventoryDigest,
|
|
126
151
|
snapshot_hash: snapshot.snapshotHash,
|
|
127
|
-
source_file_count:
|
|
152
|
+
source_file_count: inventory.files.length,
|
|
128
153
|
symbol_count: snapshot.nodes.filter((node) => node.kind === 'symbol').length,
|
|
129
154
|
edge_count: snapshot.edgeCount,
|
|
130
155
|
extractors: snapshot.extractors.map(({ id, revision }) => ({ id, revision })),
|
|
131
|
-
source_files:
|
|
156
|
+
source_files: inventory.files.map((file) => ({
|
|
132
157
|
path: file.rel,
|
|
133
158
|
sha256: file.hash,
|
|
134
159
|
language: file.language,
|
|
@@ -141,13 +166,15 @@ function buildManifest(generatedAt, inspection, snapshot) {
|
|
|
141
166
|
}
|
|
142
167
|
async function validateStaging(input) {
|
|
143
168
|
for (const artifact of ALIGN_OUTPUT_ARTIFACTS) {
|
|
144
|
-
|
|
169
|
+
if (!artifact.startsWith(WIKI_PREFIX))
|
|
170
|
+
return false;
|
|
171
|
+
const stageFile = path.join(input.stageWiki, artifact.slice(WIKI_PREFIX.length));
|
|
145
172
|
const stat = await fsp.stat(stageFile).catch(() => null);
|
|
146
173
|
if (!stat?.isFile() || stat.size <= 0)
|
|
147
174
|
return false;
|
|
148
175
|
}
|
|
149
176
|
const meta = await readJson(path.join(input.stageWiki, 'context-graph.meta.json'), null);
|
|
150
|
-
if (meta?.snapshotHash !== input.snapshot.snapshotHash || meta?.cacheKeyParts?.sourcePolicy !== '
|
|
177
|
+
if (meta?.snapshotHash !== input.snapshot.snapshotHash || meta?.cacheKeyParts?.sourcePolicy !== 'workspace')
|
|
151
178
|
return false;
|
|
152
179
|
const manifest = await readJson(path.join(input.stageWiki, 'code-navigation-manifest.json'), null);
|
|
153
180
|
if (manifest?.inventory_digest !== input.manifest.inventory_digest || manifest?.source_file_count !== input.manifest.source_file_count)
|
|
@@ -174,21 +201,31 @@ async function runLocked(root, dir, missionId, plan, ledger, beforeFinalSourceCa
|
|
|
174
201
|
ledger.validation.absent_or_existing_input_supported = plan.requires_cleanup_receipt === false
|
|
175
202
|
&& plan.acceptance.absent_or_existing_triwiki_supported === true;
|
|
176
203
|
ledger.validation.prior_state_ignored = true;
|
|
177
|
-
const extractorIdentities =
|
|
178
|
-
const
|
|
179
|
-
const
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
.
|
|
204
|
+
const extractorIdentities = architectureMapGraphExtractors();
|
|
205
|
+
const inventory = walkCodeInventory(root, CODE_NAVIGATION_LIMITS);
|
|
206
|
+
const inputHashes = codeInventoryInputHashes(inventory);
|
|
207
|
+
const codeInventoryDigest = crypto
|
|
208
|
+
.createHash('sha256')
|
|
209
|
+
.update(Object.entries(inputHashes)
|
|
210
|
+
.sort(([left], [right]) => (left < right ? -1 : left > right ? 1 : 0))
|
|
211
|
+
.map(([relative, hash]) => `${relative}\0${hash}`)
|
|
212
|
+
.join('\n'))
|
|
213
|
+
.digest('hex');
|
|
214
|
+
const cacheKey = await computeContextGraphCacheKey({ root, extractors: extractorIdentities });
|
|
215
|
+
const fatalSkips = inventory.skipped.filter((skip) => isAlignFatalSkip(skip));
|
|
216
|
+
ledger.scan.inventory_digest = codeInventoryDigest;
|
|
217
|
+
ledger.scan.source_file_count = inventory.files.length;
|
|
218
|
+
ledger.scan.source_bytes = inventory.files.reduce((sum, file) => sum + file.bytes, 0);
|
|
219
|
+
ledger.scan.source_lines = inventory.files.reduce((sum, file) => sum + file.lines, 0);
|
|
220
|
+
ledger.scan.languages = countsBy(inventory.files, (file) => file.language);
|
|
221
|
+
ledger.scan.allowed_exclusions = inventory.skipped
|
|
222
|
+
.filter((skip) => !isAlignFatalSkip(skip))
|
|
187
223
|
.map((skip) => ({ path: skip.path, reason: skip.reason }));
|
|
188
|
-
ledger.scan.fatal_skips =
|
|
189
|
-
ledger.validation.source_inventory_complete =
|
|
190
|
-
if (
|
|
191
|
-
throw new Error(`code_navigation_fatal_skips:${
|
|
224
|
+
ledger.scan.fatal_skips = fatalSkips.map((skip) => ({ ...skip }));
|
|
225
|
+
ledger.validation.source_inventory_complete = fatalSkips.length === 0;
|
|
226
|
+
if (fatalSkips.length)
|
|
227
|
+
throw new Error(`code_navigation_fatal_skips:${fatalSkips.map((skip) => `${skip.reason}:${skip.path}`).join('|')}`);
|
|
228
|
+
const extractors = architectureMapGraphExtractors({ preparedInventory: inventory });
|
|
192
229
|
const generatedAt = nowIso();
|
|
193
230
|
const compiled = await compileContextGraph({
|
|
194
231
|
root,
|
|
@@ -197,12 +234,12 @@ async function runLocked(root, dir, missionId, plan, ledger, beforeFinalSourceCa
|
|
|
197
234
|
limits: CODE_NAVIGATION_LIMITS,
|
|
198
235
|
observedAt: generatedAt,
|
|
199
236
|
useFragmentCache: false,
|
|
200
|
-
cacheKey
|
|
237
|
+
cacheKey,
|
|
201
238
|
persistArtifacts: false,
|
|
202
239
|
useCompileLock: false
|
|
203
240
|
});
|
|
204
241
|
ledger.validation.graph_compile = compiled.ok;
|
|
205
|
-
const compileFatal = compiled.skipped.filter((skip) =>
|
|
242
|
+
const compileFatal = compiled.skipped.filter((skip) => isAlignFatalSkip(skip));
|
|
206
243
|
if (compileFatal.length)
|
|
207
244
|
ledger.scan.fatal_skips.push(...compileFatal.map((skip) => ({ ...skip })));
|
|
208
245
|
if (!compiled.ok || !compiled.snapshot || !compiled.meta || compileFatal.length) {
|
|
@@ -218,7 +255,7 @@ async function runLocked(root, dir, missionId, plan, ledger, beforeFinalSourceCa
|
|
|
218
255
|
ledger.graph.test_nodes = snapshot.nodes.filter((node) => node.kind === 'test').length;
|
|
219
256
|
ledger.graph.edge_count = snapshot.edgeCount;
|
|
220
257
|
ledger.graph.edges_by_type = countsBy(snapshot.edges, (edge) => edge.type);
|
|
221
|
-
const inventoryPaths =
|
|
258
|
+
const inventoryPaths = inventory.files.map((file) => file.rel).sort();
|
|
222
259
|
const fileNodePaths = snapshot.nodes.filter((node) => node.kind === 'file').map((node) => String(node.path || '')).filter(Boolean).sort();
|
|
223
260
|
const inventorySet = new Set(inventoryPaths);
|
|
224
261
|
const fileNodeSet = new Set(fileNodePaths);
|
|
@@ -229,12 +266,16 @@ async function runLocked(root, dir, missionId, plan, ledger, beforeFinalSourceCa
|
|
|
229
266
|
&& fileNodePaths.length === inventoryPaths.length;
|
|
230
267
|
if (!ledger.graph.exact_file_coverage)
|
|
231
268
|
throw new Error('code_navigation_exact_file_coverage_failed');
|
|
232
|
-
|
|
233
|
-
|
|
269
|
+
const expectedExtractors = [...ARCHITECTURE_MAP_EXTRACTOR_IDS];
|
|
270
|
+
if (ledger.graph.extractor_ids.length !== expectedExtractors.length
|
|
271
|
+
|| expectedExtractors.some((id, index) => ledger.graph.extractor_ids[index] !== id)) {
|
|
272
|
+
throw new Error(`code_navigation_architecture_map_extractors_mismatch:${ledger.graph.extractor_ids.join(',')}`);
|
|
273
|
+
}
|
|
234
274
|
const graphValidation = validateContextGraphSnapshot(snapshot);
|
|
235
275
|
ledger.validation.graph_schema = graphValidation.ok;
|
|
236
|
-
if (!graphValidation.ok || meta.cacheKeyParts.sourcePolicy !== '
|
|
276
|
+
if (!graphValidation.ok || meta.cacheKeyParts.sourcePolicy !== 'workspace') {
|
|
237
277
|
throw new Error('code_navigation_graph_validation_failed');
|
|
278
|
+
}
|
|
238
279
|
const pack = await buildPack(root, snapshot, meta, generatedAt);
|
|
239
280
|
const packValidation = await validateCodePack(pack, root);
|
|
240
281
|
ledger.validation.code_pack = packValidation.ok
|
|
@@ -255,7 +296,7 @@ async function runLocked(root, dir, missionId, plan, ledger, beforeFinalSourceCa
|
|
|
255
296
|
ledger.validation.context_pack = contextValidation.ok;
|
|
256
297
|
if (!contextValidation.ok)
|
|
257
298
|
throw new Error('code_navigation_context_pack_invalid');
|
|
258
|
-
const manifest = buildManifest(generatedAt,
|
|
299
|
+
const manifest = buildManifest(generatedAt, inventory, codeInventoryDigest, snapshot);
|
|
259
300
|
const stageRoot = path.join(stageBase, `${missionId}-${randomUUID().slice(0, 8)}`);
|
|
260
301
|
const stageWiki = path.join(stageRoot, 'new-wiki');
|
|
261
302
|
const previousRoot = path.join(stageRoot, 'previous');
|
|
@@ -271,6 +312,7 @@ async function runLocked(root, dir, missionId, plan, ledger, beforeFinalSourceCa
|
|
|
271
312
|
await writeJsonAtomic(path.join(stageWiki, 'code-navigation-manifest.json'), manifest);
|
|
272
313
|
await writeJsonAtomic(path.join(stageWiki, 'code-pack.json'), pack);
|
|
273
314
|
await writeJsonAtomic(path.join(stageWiki, 'context-pack.json'), contextPack);
|
|
315
|
+
await publishArchitectureMapToStage(stageWiki, snapshot, { root, missionId });
|
|
274
316
|
ledger.publication.staged = true;
|
|
275
317
|
ledger.validation.staged_readback = await validateStaging({ stageWiki, root, snapshot, pack, contextPack, manifest });
|
|
276
318
|
if (!ledger.validation.staged_readback)
|
|
@@ -308,9 +350,23 @@ async function runLocked(root, dir, missionId, plan, ledger, beforeFinalSourceCa
|
|
|
308
350
|
}
|
|
309
351
|
ledger.validation.artifact_hashes = Object.keys(ledger.publication.artifact_sha256).length === ALIGN_OUTPUT_ARTIFACTS.length;
|
|
310
352
|
await beforeFinalSourceCas?.();
|
|
311
|
-
const
|
|
312
|
-
|
|
313
|
-
|
|
353
|
+
const finalInventory = walkCodeInventory(root, CODE_NAVIGATION_LIMITS);
|
|
354
|
+
const finalFatal = finalInventory.skipped.filter((skip) => isAlignFatalSkip(skip));
|
|
355
|
+
const finalCacheKey = await computeContextGraphCacheKey({ root, extractors: extractorIdentities });
|
|
356
|
+
const finalCodeDigest = crypto
|
|
357
|
+
.createHash('sha256')
|
|
358
|
+
.update(Object.entries(codeInventoryInputHashes(finalInventory))
|
|
359
|
+
.sort(([left], [right]) => (left < right ? -1 : left > right ? 1 : 0))
|
|
360
|
+
.map(([relative, hash]) => `${relative}\0${hash}`)
|
|
361
|
+
.join('\n'))
|
|
362
|
+
.digest('hex');
|
|
363
|
+
const casStable = finalCacheKey.parts.tsconfigHash === cacheKey.parts.tsconfigHash
|
|
364
|
+
&& finalCacheKey.parts.commandManifestHash === cacheKey.parts.commandManifestHash
|
|
365
|
+
&& finalCacheKey.parts.gateManifestHash === cacheKey.parts.gateManifestHash
|
|
366
|
+
&& finalCacheKey.parts.schemaRevision === cacheKey.parts.schemaRevision
|
|
367
|
+
&& finalCacheKey.parts.proofIndexHash === cacheKey.parts.proofIndexHash
|
|
368
|
+
&& finalCodeDigest === codeInventoryDigest;
|
|
369
|
+
ledger.scan.source_cas_verified = finalFatal.length === 0 && casStable;
|
|
314
370
|
if (!ledger.scan.source_cas_verified)
|
|
315
371
|
throw new Error('code_navigation_source_changed_during_scan');
|
|
316
372
|
commitStarted = true;
|