sneakoscope 0.9.13 → 0.9.15
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 +32 -39
- package/crates/sks-core/Cargo.lock +99 -1
- package/crates/sks-core/Cargo.toml +2 -1
- package/crates/sks-core/src/main.rs +77 -43
- package/package.json +8 -5
- package/src/cli/command-registry.mjs +73 -114
- package/src/cli/feature-commands.mjs +44 -5
- package/src/cli/install-helpers.mjs +2 -2
- package/src/cli/router.mjs +2 -3
- package/src/commands/aliases.mjs +2 -0
- package/src/commands/auto-review.mjs +5 -0
- package/src/commands/autoresearch.mjs +5 -0
- package/src/commands/bootstrap.mjs +2 -0
- package/src/commands/code-structure.mjs +5 -0
- package/src/commands/codex-lb.mjs +61 -3
- package/src/commands/commands.mjs +5 -0
- package/src/commands/commit-and-push.mjs +5 -0
- package/src/commands/commit.mjs +5 -0
- package/src/commands/computer-use.mjs +31 -0
- package/src/commands/conflicts.mjs +13 -0
- package/src/commands/context7.mjs +5 -0
- package/src/commands/db.mjs +1 -1
- package/src/commands/deps.mjs +5 -0
- package/src/commands/dfix.mjs +2 -0
- package/src/commands/doctor.mjs +2 -2
- package/src/commands/dollar-commands.mjs +2 -0
- package/src/commands/eval.mjs +5 -0
- package/src/commands/fix-path.mjs +2 -0
- package/src/commands/gc.mjs +2 -0
- package/src/commands/goal.mjs +5 -0
- package/src/commands/guard.mjs +10 -0
- package/src/commands/gx.mjs +5 -0
- package/src/commands/harness.mjs +5 -0
- package/src/commands/help.mjs +3 -74
- package/src/commands/hook.mjs +8 -0
- package/src/commands/hproof.mjs +5 -0
- package/src/commands/image-ux-review.mjs +38 -0
- package/src/commands/init.mjs +2 -0
- package/src/commands/mad-sks.mjs +14 -0
- package/src/commands/memory.mjs +5 -0
- package/src/commands/openclaw.mjs +2 -0
- package/src/commands/perf.mjs +2 -2
- package/src/commands/pipeline.mjs +25 -0
- package/src/commands/postinstall.mjs +2 -0
- package/src/commands/ppt.mjs +44 -0
- package/src/commands/profile.mjs +5 -0
- package/src/commands/proof-field.mjs +5 -0
- package/src/commands/proof.mjs +22 -1
- package/src/commands/qa-loop.mjs +5 -0
- package/src/commands/quickstart.mjs +2 -0
- package/src/commands/reasoning.mjs +2 -0
- package/src/commands/recallpulse.mjs +5 -0
- package/src/commands/research.mjs +5 -0
- package/src/commands/selftest.mjs +2 -0
- package/src/commands/setup.mjs +2 -0
- package/src/commands/skill-dream.mjs +5 -0
- package/src/commands/stats.mjs +2 -0
- package/src/commands/team.mjs +2 -0
- package/src/commands/tmux.mjs +5 -0
- package/src/commands/update-check.mjs +2 -0
- package/src/commands/usage.mjs +2 -0
- package/src/commands/validate-artifacts.mjs +2 -0
- package/src/commands/versioning.mjs +16 -0
- package/src/commands/wiki.mjs +2 -2
- package/src/core/codex-lb-circuit.mjs +18 -0
- package/src/core/commands/basic-cli.mjs +315 -0
- package/src/{cli/maintenance-commands.mjs → core/commands/route-cli.mjs} +37 -37
- package/src/core/feature-fixture-runner.mjs +109 -0
- package/src/core/feature-fixtures.mjs +1 -1
- package/src/core/feature-registry.mjs +19 -7
- package/src/core/fsx.mjs +1 -1
- package/src/core/git-simple.mjs +118 -0
- package/src/core/pipeline.mjs +1 -1
- package/src/core/proof/route-finalizer-fixtures.mjs +21 -0
- package/src/core/proof/route-finalizer-policy.mjs +13 -0
- package/src/core/proof/route-finalizer.mjs +82 -0
- package/src/core/proof-field.mjs +2 -2
- package/src/core/routes.mjs +31 -1
- package/src/core/rust-accelerator.mjs +8 -3
- package/src/core/version.mjs +1 -1
- package/src/core/wiki-image/before-after-relation.mjs +1 -0
- package/src/core/wiki-image/computer-use-evidence.mjs +1 -0
- package/src/core/wiki-image/generated-review-parser.mjs +1 -0
- package/src/core/wiki-image/image-ux-evidence.mjs +1 -0
- package/src/core/wiki-image/image-voxel-ledger.mjs +10 -3
- package/src/core/wiki-image/ppt-image-evidence.mjs +1 -0
- package/src/core/wiki-image/route-image-evidence.mjs +107 -0
- package/src/cli/legacy-main.mjs +0 -4147
package/README.md
CHANGED
|
@@ -1,8 +1,29 @@
|
|
|
1
1
|
# Sneakoscope Codex
|
|
2
2
|
|
|
3
|
-
Fast proof-first Codex trust layer with image-based Voxel TriWiki.
|
|
3
|
+
Fast legacy-free proof-first Codex trust layer with image-based Voxel TriWiki.
|
|
4
4
|
|
|
5
|
-
Sneakoscope Codex (`sks`) is a Codex CLI/App harness
|
|
5
|
+
Sneakoscope Codex (`sks`) is a Codex CLI/App harness that makes repeatable Codex work auditable. `0.9.15` runs through split command modules, automatically seals serious routes with Completion Proof, binds visual/UI claims to Image Voxel TriWiki anchors and relations, and release-gates hooks, codex-lb, executable fixtures, Rust parity, and DB safety evidence.
|
|
6
|
+
|
|
7
|
+
## 0.9.15 Current Release
|
|
8
|
+
|
|
9
|
+
`0.9.15` preserves the 0.9.14 legacy-free trust layer and fixes global npm postinstall auto-bootstrap.
|
|
10
|
+
|
|
11
|
+
`0.9.14` turned SKS into a legacy-free proof-first trust layer for Codex work:
|
|
12
|
+
|
|
13
|
+
- Command registry entries load independent command modules without runtime fallback to archived 0.9.13 CLI bundles.
|
|
14
|
+
- Serious routes write Completion Proof through the central route finalizer before completion is claimed.
|
|
15
|
+
- Visual/UI routes require Image Voxel TriWiki anchors, with before/after relations for visual fix claims.
|
|
16
|
+
- Executable feature fixtures validate expected artifact existence and schema contracts.
|
|
17
|
+
- Hook replay strictly matches decision, reason, gate, issues, continuation, and redaction policy.
|
|
18
|
+
- codex-lb launch failures feed both global and active-project circuit health; stateless `previous_response_not_found` stays a warning.
|
|
19
|
+
- Rust `image-hash` and semantic `voxel-validate` commands match JS fallback behavior.
|
|
20
|
+
- `$Commit` and `$Commit-And-Push` provide a simple git-only route for staging, committing, and optionally pushing without the full SKS pipeline.
|
|
21
|
+
|
|
22
|
+
Learn more:
|
|
23
|
+
- Completion Proof: [docs/completion-proof.md](docs/completion-proof.md)
|
|
24
|
+
- Image Voxel TriWiki: [docs/image-voxel-ledger.md](docs/image-voxel-ledger.md)
|
|
25
|
+
- Codex App Hooks/PAT: [docs/hooks-pat.md](docs/hooks-pat.md)
|
|
26
|
+
- codex-lb: [docs/codex-lb.md](docs/codex-lb.md)
|
|
6
27
|
|
|
7
28
|
## 60-second start
|
|
8
29
|
|
|
@@ -16,28 +37,20 @@ sks selftest --mock
|
|
|
16
37
|
|
|
17
38
|
## Three core promises
|
|
18
39
|
|
|
19
|
-
1.
|
|
20
|
-
2.
|
|
21
|
-
3.
|
|
40
|
+
1. Completion Proof for every serious route
|
|
41
|
+
2. Image Voxel TriWiki anchors and relations for every visual route
|
|
42
|
+
3. Codex App, codex-lb, hooks, Rust, DB, and fixtures verified by release gates
|
|
22
43
|
|
|
23
|
-
##
|
|
44
|
+
## Install Options
|
|
24
45
|
|
|
25
46
|
Install globally, then run `sks` from either a project or any global shell location:
|
|
26
47
|
|
|
27
48
|
```sh
|
|
28
49
|
npm i -g sneakoscope
|
|
29
50
|
sks root
|
|
30
|
-
sks
|
|
51
|
+
sks doctor
|
|
31
52
|
```
|
|
32
53
|
|
|
33
|
-
`0.9.13` connects serious routes to Completion Proof, visual routes to image voxel anchors, hook replay to shared runtime policy, codex-lb launch failures to circuit health, and Rust accelerator commands to JS fallback parity. Rust accelerator source is included in the npm package; until prebuilt binaries ship, SKS uses JS fallbacks unless `SKS_RS_BIN` or a source-checkout `sks-rs` binary is available.
|
|
34
|
-
|
|
35
|
-
Learn more:
|
|
36
|
-
- Completion Proof: [docs/completion-proof.md](docs/completion-proof.md)
|
|
37
|
-
- Image Voxel TriWiki: [docs/image-voxel-ledger.md](docs/image-voxel-ledger.md)
|
|
38
|
-
- Codex App Hooks/PAT: [docs/hooks-pat.md](docs/hooks-pat.md)
|
|
39
|
-
- codex-lb: [docs/codex-lb.md](docs/codex-lb.md)
|
|
40
|
-
|
|
41
54
|
`npm i -g sneakoscope` automatically refreshes the `sks` command shim, global Codex App `$` skills, and SKS bootstrap surface. When the install is run from a project, postinstall bootstraps that project. When it is run outside a repo/project marker, postinstall bootstraps the per-user global runtime root instead of writing `.sneakoscope` into a random current directory. `sks root` tells you which root SKS will use.
|
|
42
55
|
|
|
43
56
|
If you only want a one-shot run without keeping `sks` installed globally:
|
|
@@ -59,6 +72,7 @@ Check that the install is usable:
|
|
|
59
72
|
sks deps check
|
|
60
73
|
sks codex-app check
|
|
61
74
|
sks dollar-commands
|
|
75
|
+
sks commit --json
|
|
62
76
|
sks selftest --mock
|
|
63
77
|
```
|
|
64
78
|
|
|
@@ -66,32 +80,11 @@ sks selftest --mock
|
|
|
66
80
|
|
|
67
81
|
`sks` adds a tmux Codex CLI runtime, Codex App `$` commands, Team/QA/PPT/Research/DB/GX/Wiki routes, OpenClaw skill generation, Context7-gated current docs, TriWiki context packs, DB safety, design SSOT policy, skill dreaming, release checks, and Honest Mode.
|
|
68
82
|
|
|
69
|
-
##
|
|
70
|
-
|
|
71
|
-
Sneakoscope 0.8.0 introduces the RecallPulse planning spine: a report-only active-recall layer that records what the pipeline should remember before a stage proceeds. RecallPulse maps TriWiki into L1/L2/L3 cache behavior, writes durable status ledgers instead of relying on ephemeral hook text, suppresses duplicate reminder loops, and emits RouteProofCapsule plus EvidenceEnvelope artifacts for later gate comparison. These artifacts are evidence surfaces first; speed or accuracy gains remain benchmark-gated until scored evals prove them.
|
|
72
|
-
|
|
73
|
-
Inspect the new report-only artifacts with:
|
|
74
|
-
|
|
75
|
-
```sh
|
|
76
|
-
sks recallpulse run latest
|
|
77
|
-
sks recallpulse status latest --json
|
|
78
|
-
sks recallpulse eval latest --json
|
|
79
|
-
sks recallpulse governance latest --json
|
|
80
|
-
sks recallpulse checklist latest --json
|
|
81
|
-
sks recallpulse checklist latest --task T001 --apply --evidence src/core/recallpulse.mjs
|
|
82
|
-
```
|
|
83
|
-
|
|
84
|
-
Research scouts now use named persona-inspired cognitive lenses: Einstein Scout, Feynman Scout, Turing Scout, von Neumann Scout, and Skeptic Scout. They are not impersonations; each scout ledger row must carry `display_name`, `persona`, `persona_boundary`, `reasoning_effort=xhigh`, a literal `Eureka!` idea, falsifiers, cheap probes, and debate participation evidence.
|
|
85
|
-
|
|
86
|
-
For existing 0.7.x users, the visible change is new report-only evidence, not a route personality rewrite. Team still feels like Team, DFix stays ultralight, DB remains conservative, QA-LOOP still dogfoods, PPT stays information-first, imagegen still requires real raster evidence, and Honest Mode remains the final truth pass. The original strong reminder idea became neutral RecallPulse so user-facing prompts stay short, professional, and non-repetitive; hook messages can point at status, but `mission-status-ledger.json` is the durable source when app-visible text disappears. The planning source is `docs/RECALLPULSE_0_8_0_TASKS.md`, and implementation is designed to land in safe task-sized slices before any enforcement promotion.
|
|
87
|
-
|
|
88
|
-
## 0.9.0 Report-Only Decision Lattice
|
|
89
|
-
|
|
90
|
-
Sneakoscope 0.9.0 adds a report-only Decision Lattice planner that uses A* over proof-debt signals to explain which route or verification path the pipeline would prefer. It is an evidence and planning surface, not a runtime shortcut: SKS must not claim speedup, fast-lane accuracy, or reduced verification cost from the lattice until replay or scored eval evidence demonstrates those outcomes.
|
|
83
|
+
## Report-Only Planning Surfaces
|
|
91
84
|
|
|
92
|
-
|
|
85
|
+
Decision Lattice and RecallPulse remain report-only planning and evidence surfaces. They can explain route choices and proof-debt signals, but SKS does not claim speedup, fast-lane accuracy, or reduced verification cost from them until scored evals prove those outcomes.
|
|
93
86
|
|
|
94
|
-
|
|
87
|
+
Useful checks:
|
|
95
88
|
|
|
96
89
|
```bash
|
|
97
90
|
sks proof-field scan --json --intent "small CLI change"
|
|
@@ -2,6 +2,104 @@
|
|
|
2
2
|
# It is not intended for manual editing.
|
|
3
3
|
version = 4
|
|
4
4
|
|
|
5
|
+
[[package]]
|
|
6
|
+
name = "itoa"
|
|
7
|
+
version = "1.0.18"
|
|
8
|
+
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
9
|
+
checksum = "8f42a60cbdf9a97f5d2305f08a87dc4e09308d1276d28c869c684d7777685682"
|
|
10
|
+
|
|
11
|
+
[[package]]
|
|
12
|
+
name = "memchr"
|
|
13
|
+
version = "2.8.0"
|
|
14
|
+
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
15
|
+
checksum = "f8ca58f447f06ed17d5fc4043ce1b10dd205e060fb3ce5b979b8ed8e59ff3f79"
|
|
16
|
+
|
|
17
|
+
[[package]]
|
|
18
|
+
name = "proc-macro2"
|
|
19
|
+
version = "1.0.106"
|
|
20
|
+
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
21
|
+
checksum = "8fd00f0bb2e90d81d1044c2b32617f68fcb9fa3bb7640c23e9c748e53fb30934"
|
|
22
|
+
dependencies = [
|
|
23
|
+
"unicode-ident",
|
|
24
|
+
]
|
|
25
|
+
|
|
26
|
+
[[package]]
|
|
27
|
+
name = "quote"
|
|
28
|
+
version = "1.0.45"
|
|
29
|
+
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
30
|
+
checksum = "41f2619966050689382d2b44f664f4bc593e129785a36d6ee376ddf37259b924"
|
|
31
|
+
dependencies = [
|
|
32
|
+
"proc-macro2",
|
|
33
|
+
]
|
|
34
|
+
|
|
35
|
+
[[package]]
|
|
36
|
+
name = "serde"
|
|
37
|
+
version = "1.0.228"
|
|
38
|
+
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
39
|
+
checksum = "9a8e94ea7f378bd32cbbd37198a4a91436180c5bb472411e48b5ec2e2124ae9e"
|
|
40
|
+
dependencies = [
|
|
41
|
+
"serde_core",
|
|
42
|
+
]
|
|
43
|
+
|
|
44
|
+
[[package]]
|
|
45
|
+
name = "serde_core"
|
|
46
|
+
version = "1.0.228"
|
|
47
|
+
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
48
|
+
checksum = "41d385c7d4ca58e59fc732af25c3983b67ac852c1a25000afe1175de458b67ad"
|
|
49
|
+
dependencies = [
|
|
50
|
+
"serde_derive",
|
|
51
|
+
]
|
|
52
|
+
|
|
53
|
+
[[package]]
|
|
54
|
+
name = "serde_derive"
|
|
55
|
+
version = "1.0.228"
|
|
56
|
+
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
57
|
+
checksum = "d540f220d3187173da220f885ab66608367b6574e925011a9353e4badda91d79"
|
|
58
|
+
dependencies = [
|
|
59
|
+
"proc-macro2",
|
|
60
|
+
"quote",
|
|
61
|
+
"syn",
|
|
62
|
+
]
|
|
63
|
+
|
|
64
|
+
[[package]]
|
|
65
|
+
name = "serde_json"
|
|
66
|
+
version = "1.0.149"
|
|
67
|
+
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
68
|
+
checksum = "83fc039473c5595ace860d8c4fafa220ff474b3fc6bfdb4293327f1a37e94d86"
|
|
69
|
+
dependencies = [
|
|
70
|
+
"itoa",
|
|
71
|
+
"memchr",
|
|
72
|
+
"serde",
|
|
73
|
+
"serde_core",
|
|
74
|
+
"zmij",
|
|
75
|
+
]
|
|
76
|
+
|
|
5
77
|
[[package]]
|
|
6
78
|
name = "sks-core"
|
|
7
|
-
version = "0.9.
|
|
79
|
+
version = "0.9.15"
|
|
80
|
+
dependencies = [
|
|
81
|
+
"serde_json",
|
|
82
|
+
]
|
|
83
|
+
|
|
84
|
+
[[package]]
|
|
85
|
+
name = "syn"
|
|
86
|
+
version = "2.0.117"
|
|
87
|
+
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
88
|
+
checksum = "e665b8803e7b1d2a727f4023456bbbbe74da67099c585258af0ad9c5013b9b99"
|
|
89
|
+
dependencies = [
|
|
90
|
+
"proc-macro2",
|
|
91
|
+
"quote",
|
|
92
|
+
"unicode-ident",
|
|
93
|
+
]
|
|
94
|
+
|
|
95
|
+
[[package]]
|
|
96
|
+
name = "unicode-ident"
|
|
97
|
+
version = "1.0.24"
|
|
98
|
+
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
99
|
+
checksum = "e6e4313cd5fcd3dad5cafa179702e2b244f760991f45397d14d4ebf38247da75"
|
|
100
|
+
|
|
101
|
+
[[package]]
|
|
102
|
+
name = "zmij"
|
|
103
|
+
version = "1.0.21"
|
|
104
|
+
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
105
|
+
checksum = "b8848ee67ecc8aedbaf3e4122217aff892639231befc6a1b58d29fff4c2cabaa"
|
|
@@ -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 0.9.
|
|
7
|
+
Some("--version") => println!("sks-rs 0.9.15"),
|
|
8
8
|
Some("compact-info") => {
|
|
9
9
|
let mut input = String::new();
|
|
10
10
|
let _ = io::stdin().read_to_string(&mut input);
|
|
@@ -40,9 +40,15 @@ fn main() {
|
|
|
40
40
|
}
|
|
41
41
|
Some("voxel-validate") => {
|
|
42
42
|
let path = args.next().unwrap_or_default();
|
|
43
|
+
let mut require_anchors = false;
|
|
44
|
+
let mut require_relations = false;
|
|
45
|
+
while let Some(arg) = args.next() {
|
|
46
|
+
if arg == "--require-anchors" { require_anchors = true; }
|
|
47
|
+
if arg == "--require-relations" { require_relations = true; }
|
|
48
|
+
}
|
|
43
49
|
match std::fs::read_to_string(&path) {
|
|
44
50
|
Ok(text) => {
|
|
45
|
-
let report = voxel_validate(&text);
|
|
51
|
+
let report = voxel_validate(&text, require_anchors, require_relations);
|
|
46
52
|
println!("{}", report);
|
|
47
53
|
if report.contains("\"ok\":false") { std::process::exit(1); }
|
|
48
54
|
}
|
|
@@ -139,52 +145,80 @@ fn sha256_hex(data: &[u8]) -> String {
|
|
|
139
145
|
h.iter().map(|x| format!("{:08x}", x)).collect::<String>()
|
|
140
146
|
}
|
|
141
147
|
|
|
142
|
-
fn voxel_validate(text: &str) -> String {
|
|
143
|
-
let
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
let image_count = count_object_entries(text, "images");
|
|
148
|
-
let anchor_count = count_object_entries(text, "anchors");
|
|
149
|
-
if image_count == 0 { issues.push("missing_images"); }
|
|
150
|
-
if anchor_count == 0 { issues.push("missing_anchors"); }
|
|
151
|
-
issues.sort();
|
|
152
|
-
issues.dedup();
|
|
153
|
-
let ok = issues.is_empty();
|
|
154
|
-
let issue_json = issues.iter().map(|x| format!("\"{}\"", json_escape(x))).collect::<Vec<_>>().join(",");
|
|
155
|
-
format!("{{\"ok\":{},\"engine\":\"rust\",\"schema\":\"sks.image-voxel-ledger.v1\",\"images\":{},\"anchors\":{},\"issues\":[{}]}}", if ok { "true" } else { "false" }, image_count, anchor_count, issue_json)
|
|
156
|
-
}
|
|
157
|
-
|
|
158
|
-
fn count_object_entries(text: &str, key: &str) -> usize {
|
|
159
|
-
let marker = format!("\"{}\"", key);
|
|
160
|
-
let Some(start) = text.find(&marker) else { return 0; };
|
|
161
|
-
let Some(open) = text[start..].find('[').map(|i| start + i) else { return 0; };
|
|
162
|
-
let mut depth = 0i32;
|
|
163
|
-
let mut entries = 0usize;
|
|
164
|
-
let mut in_string = false;
|
|
165
|
-
let mut escape = false;
|
|
166
|
-
for ch in text[open..].chars() {
|
|
167
|
-
if escape {
|
|
168
|
-
escape = false;
|
|
169
|
-
continue;
|
|
148
|
+
fn voxel_validate(text: &str, require_anchors: bool, require_relations: bool) -> String {
|
|
149
|
+
let parsed: serde_json::Value = match serde_json::from_str(text) {
|
|
150
|
+
Ok(value) => value,
|
|
151
|
+
Err(err) => {
|
|
152
|
+
return format!("{{\"ok\":false,\"engine\":\"rust\",\"schema\":\"sks.image-voxel-ledger.v1\",\"images\":0,\"anchors\":0,\"relations\":0,\"issues\":[\"json_parse\"],\"error\":\"{}\"}}", json_escape(&err.to_string()));
|
|
170
153
|
}
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
154
|
+
};
|
|
155
|
+
let mut issues: Vec<String> = Vec::new();
|
|
156
|
+
if parsed.get("schema").and_then(|v| v.as_str()) != Some("sks.image-voxel-ledger.v1") { issues.push("schema".to_string()); }
|
|
157
|
+
let images = parsed.get("images").and_then(|v| v.as_array()).cloned().unwrap_or_default();
|
|
158
|
+
let anchors = parsed.get("anchors").and_then(|v| v.as_array()).cloned().unwrap_or_default();
|
|
159
|
+
let relations = parsed.get("relations").and_then(|v| v.as_array()).cloned().unwrap_or_default();
|
|
160
|
+
if !parsed.get("images").map(|v| v.is_array()).unwrap_or(false) { issues.push("missing_images".to_string()); }
|
|
161
|
+
if !parsed.get("anchors").map(|v| v.is_array()).unwrap_or(false) { issues.push("missing_anchors".to_string()); }
|
|
162
|
+
if require_anchors && anchors.is_empty() { issues.push("missing_anchors:visual-route".to_string()); }
|
|
163
|
+
if require_relations && relations.is_empty() { issues.push("missing_relations:visual-route".to_string()); }
|
|
164
|
+
let mut image_ids: Vec<String> = Vec::new();
|
|
165
|
+
let mut anchor_ids: Vec<String> = Vec::new();
|
|
166
|
+
for image in &images {
|
|
167
|
+
let id = image.get("id").and_then(|v| v.as_str()).unwrap_or("");
|
|
168
|
+
if id.is_empty() { issues.push("image_id".to_string()); }
|
|
169
|
+
if !id.is_empty() && image_ids.iter().any(|x| x == id) { issues.push(format!("duplicate_image:{}", id)); }
|
|
170
|
+
if !id.is_empty() { image_ids.push(id.to_string()); }
|
|
171
|
+
if image.get("path").and_then(|v| v.as_str()).unwrap_or("").is_empty() { issues.push(format!("image_path:{}", if id.is_empty() { "unknown" } else { id })); }
|
|
172
|
+
if image.get("sha256").and_then(|v| v.as_str()).unwrap_or("").is_empty() { issues.push(format!("image_sha256:{}", if id.is_empty() { "unknown" } else { id })); }
|
|
173
|
+
let w = image.get("width").and_then(|v| v.as_f64());
|
|
174
|
+
let h = image.get("height").and_then(|v| v.as_f64());
|
|
175
|
+
if !w.map(|n| n.is_finite()).unwrap_or(false) || !h.map(|n| n.is_finite()).unwrap_or(false) {
|
|
176
|
+
issues.push(format!("image_dimensions:{}", if id.is_empty() { "unknown" } else { id }));
|
|
174
177
|
}
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
+
}
|
|
179
|
+
for anchor in &anchors {
|
|
180
|
+
let id = anchor.get("id").and_then(|v| v.as_str()).unwrap_or("");
|
|
181
|
+
if id.is_empty() { issues.push("anchor_id".to_string()); }
|
|
182
|
+
if !id.is_empty() && anchor_ids.iter().any(|x| x == id) { issues.push(format!("duplicate_anchor:{}", id)); }
|
|
183
|
+
if !id.is_empty() { anchor_ids.push(id.to_string()); }
|
|
184
|
+
let image_id = anchor.get("image_id").and_then(|v| v.as_str()).unwrap_or("");
|
|
185
|
+
if image_id.is_empty() || !image_ids.iter().any(|x| x == image_id) { issues.push(format!("anchor_image_ref:{}", if id.is_empty() { "unknown" } else { id })); }
|
|
186
|
+
let image = images.iter().find(|img| img.get("id").and_then(|v| v.as_str()) == Some(image_id));
|
|
187
|
+
let w = image.and_then(|img| img.get("width")).and_then(|v| v.as_f64()).unwrap_or(f64::NAN);
|
|
188
|
+
let h = image.and_then(|img| img.get("height")).and_then(|v| v.as_f64()).unwrap_or(f64::NAN);
|
|
189
|
+
match anchor.get("bbox").and_then(|v| v.as_array()) {
|
|
190
|
+
Some(bbox) if bbox.len() == 4 => {
|
|
191
|
+
let vals: Vec<f64> = bbox.iter().map(|v| v.as_f64().unwrap_or(f64::NAN)).collect();
|
|
192
|
+
if vals.iter().any(|n| !n.is_finite()) { issues.push(format!("bbox_number:{}", if id.is_empty() { "unknown" } else { id })); }
|
|
193
|
+
if vals[2] <= 0.0 || vals[3] <= 0.0 { issues.push(format!("bbox_positive:{}", if id.is_empty() { "unknown" } else { id })); }
|
|
194
|
+
if w.is_finite() && vals[0] + vals[2] > w {
|
|
195
|
+
issues.push(format!("bbox_width_out_of_bounds:{}", if id.is_empty() { "unknown" } else { id }));
|
|
196
|
+
}
|
|
197
|
+
if h.is_finite() && vals[1] + vals[3] > h {
|
|
198
|
+
issues.push(format!("bbox_height_out_of_bounds:{}", if id.is_empty() { "unknown" } else { id }));
|
|
199
|
+
}
|
|
200
|
+
}
|
|
201
|
+
Some(_) => issues.push(format!("bbox_shape:{}", if id.is_empty() { "unknown" } else { id })),
|
|
202
|
+
None => issues.push(format!("anchor_bbox:{}", if id.is_empty() { "unknown" } else { id })),
|
|
203
|
+
}
|
|
204
|
+
}
|
|
205
|
+
for relation in &relations {
|
|
206
|
+
if let Some(before) = relation.get("before_image_id").and_then(|v| v.as_str()) {
|
|
207
|
+
if !image_ids.iter().any(|x| x == before) { issues.push(format!("relation_before:{}", before)); }
|
|
208
|
+
}
|
|
209
|
+
if let Some(after) = relation.get("after_image_id").and_then(|v| v.as_str()) {
|
|
210
|
+
if !image_ids.iter().any(|x| x == after) { issues.push(format!("relation_after:{}", after)); }
|
|
178
211
|
}
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
depth -= 1;
|
|
183
|
-
if depth == 0 { break; }
|
|
212
|
+
let changed = relation.get("changed_anchor_ids").or_else(|| relation.get("anchors")).and_then(|v| v.as_array()).cloned().unwrap_or_default();
|
|
213
|
+
for anchor_id in changed.iter().filter_map(|v| v.as_str()) {
|
|
214
|
+
if !anchor_ids.iter().any(|x| x == anchor_id) { issues.push(format!("relation_anchor:{}", anchor_id)); }
|
|
184
215
|
}
|
|
185
|
-
else if ch == '{' && depth == 1 { entries += 1; }
|
|
186
216
|
}
|
|
187
|
-
|
|
217
|
+
issues.sort();
|
|
218
|
+
issues.dedup();
|
|
219
|
+
let ok = issues.is_empty();
|
|
220
|
+
let issue_json = issues.iter().map(|x| format!("\"{}\"", json_escape(x))).collect::<Vec<_>>().join(",");
|
|
221
|
+
format!("{{\"ok\":{},\"engine\":\"rust\",\"schema\":\"sks.image-voxel-ledger.v1\",\"images\":{},\"anchors\":{},\"relations\":{},\"issues\":[{}]}}", if ok { "true" } else { "false" }, images.len(), anchors.len(), relations.len(), issue_json)
|
|
188
222
|
}
|
|
189
223
|
|
|
190
224
|
fn json_escape(value: &str) -> String {
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "sneakoscope",
|
|
3
3
|
"displayName": "ㅅㅋㅅ",
|
|
4
|
-
"version": "0.9.
|
|
4
|
+
"version": "0.9.15",
|
|
5
5
|
"description": "Sneakoscope Codex: fast proof-first Codex trust layer with image-based Voxel TriWiki.",
|
|
6
6
|
"type": "module",
|
|
7
7
|
"homepage": "https://github.com/mandarange/Sneakoscope-Codex#readme",
|
|
@@ -37,22 +37,25 @@
|
|
|
37
37
|
"postinstall": "node ./bin/sks.mjs postinstall",
|
|
38
38
|
"selftest": "node ./bin/sks.mjs selftest --mock",
|
|
39
39
|
"doctor": "node ./bin/sks.mjs doctor",
|
|
40
|
-
"packcheck": "find bin src scripts -name '*.mjs' -print0 | xargs -0 -n1 node --check",
|
|
40
|
+
"packcheck": "find bin src scripts test -name '*.mjs' -print0 | xargs -0 -n1 node --check",
|
|
41
41
|
"changelog:check": "node ./scripts/changelog-check.mjs",
|
|
42
42
|
"cli-entrypoint:check": "node ./scripts/check-cli-entrypoint.mjs",
|
|
43
|
-
"legacy-
|
|
43
|
+
"legacy-free:check": "node ./scripts/check-legacy-free.mjs",
|
|
44
44
|
"sizecheck": "node ./scripts/sizecheck.mjs",
|
|
45
45
|
"registry:check": "node ./scripts/release-registry-check.mjs",
|
|
46
46
|
"feature:check": "node ./bin/sks.mjs features check --json",
|
|
47
47
|
"all-features:selftest": "node ./bin/sks.mjs all-features selftest --mock --json",
|
|
48
|
-
"all-features:execute-fixtures": "node ./bin/sks.mjs all-features selftest --mock --execute-fixtures --json",
|
|
48
|
+
"all-features:execute-fixtures": "node ./bin/sks.mjs all-features selftest --mock --execute-fixtures --strict-artifacts --json",
|
|
49
49
|
"perf:cold-start": "node ./bin/sks.mjs perf cold-start --json",
|
|
50
50
|
"perf:gate": "node ./scripts/perf-gate.mjs",
|
|
51
51
|
"test": "node --test \"test/**/*.test.mjs\"",
|
|
52
52
|
"test:unit": "node --test \"test/unit/**/*.test.mjs\"",
|
|
53
53
|
"test:integration:mock": "node --test \"test/integration/**/*.test.mjs\"",
|
|
54
|
+
"test:e2e:mock": "node --test \"test/e2e/**/*.test.mjs\"",
|
|
55
|
+
"rust:check": "cargo check --manifest-path crates/sks-core/Cargo.toml",
|
|
56
|
+
"rust:smoke": "node ./scripts/rust-smoke.mjs",
|
|
54
57
|
"coverage": "node --experimental-test-coverage --test \"test/**/*.test.mjs\"",
|
|
55
|
-
"release:check": "npm run repo-audit && npm run changelog:check && npm run cli-entrypoint:check && npm run legacy-
|
|
58
|
+
"release:check": "npm run repo-audit && npm run changelog:check && npm run cli-entrypoint:check && npm run legacy-free:check && npm run packcheck && npm run feature:check && npm run all-features:selftest && npm run all-features:execute-fixtures && npm run selftest && npm run test:unit && npm run test:integration:mock && npm run test:e2e:mock && npm run rust:check && npm run rust:smoke && npm run perf:gate && npm run sizecheck && npm run registry:check",
|
|
56
59
|
"publish:dry": "npm run release:check && npm --cache /tmp/sks-npm-cache publish --dry-run --registry https://registry.npmjs.org/ --access public",
|
|
57
60
|
"publish:npm": "npm --cache /tmp/sks-npm-cache publish --registry https://registry.npmjs.org/ --access public",
|
|
58
61
|
"prepublishOnly": "npm run release:check && node ./scripts/release-registry-check.mjs --require-unpublished"
|