code wiki / (root) / nx_mvault.nx

nx_mvault.nx source

↩ module page · 670 lines · 26881 B

1// nx_mvault.nx -- the vault CLI + MCP tool. Exposes the gate-proven vault 2// bricks as a callable capability (classify / tag / measure) so it registers 3// as an MCP tool + /api endpoint + is drivable by agents. 4// 5// nx_mvault classify <path> <gen|real> <source> <ext> 6// -> {"cid","class","type","mls","dsm_path"} (JSON) 7// nx_mvault tag <namespace> <value> -> ns:value 8// nx_mvault measure <axis> <value> <leg> <conf> -> axis=value@leg#conf 9// 10// Composes nx_mvault_{ingest,context,layout,tag,measure} + nx_canon_cid + 11// nx_media_sniff. license_tier: ORIGINAL 12 13import "nx_syscalls.nx" 14import "nx_canon_cid.nx" 15import "nx_media_pool.nx" 16import "nx_media_sniff.nx" 17import "nx_mvault_ingest.nx" 18import "nx_mvault_context.nx" 19import "nx_mvault_layout.nx" 20import "nx_mvault_tag.nx" 21import "nx_mvault_measure.nx" 22import "nx_mvault_record.nx" 23import "nx_mvault_coll.nx" 24import "nx_mvault_fetch.nx" 25import "nx_https_fetch_lib.nx" 26import "nx_registry.nx" 27const K_MAGIC_65536: i64 = 65536 28const K_MAGIC_1024: i64 = 1024 29const K_MAGIC_2048: i64 = 2048 30const K_MAGIC_4096: i64 = 4096 31const K_MAGIC_4194304: i64 = 4194304 32 33const MV_HDR: i64 = 8192 34const MV_SEEK_END: i64 = 2 35 36func argp(argv: *i64, i: i64) -> *u8 { return (argv[i]) as *u8 } 37 38// Byte length of a file without reading it; -1 when unopenable. 39func mv_file_size(path: *u8) -> i64 { 40 let fd: i64 = sys_openat_rd(path) 41 if fd < 0 { return 0 - 1 } 42 let n: i64 = sys_lseek(fd, 0, MV_SEEK_END) 43 sys_close(fd) 44 return n 45} 46 47// Read up to `cap` HEADER bytes into buf; returns bytes read or -1. 48// Format identity lives in the first few hundred bytes, so a sniffer never 49// needs more -- this is what replaces the old whole-file read. 50func mv_read_head(path: *u8, buf: *u8, cap: i64) -> i64 { 51 let fd: i64 = sys_openat_rd(path) 52 if fd < 0 { return 0 - 1 } 53 var got: i64 = 0 54 var go: i64 = 1 55 while go == 1 { 56 if got >= cap { go = 0 } 57 if go == 1 { 58 let dst: *u8 = ((buf as i64) + got) as *u8 59 let r: i64 = sys_read(fd, dst, cap - got) 60 if r <= 0 { go = 0 } 61 if r > 0 { got = got + r } 62 } 63 } 64 sys_close(fd) 65 return got 66} 67 68func mv_strlen(s: *u8) -> i64 { var n: i64 = 0; while s[n] != (0 as u8) { n = n + 1 } return n } 69 70func seq(a: *u8, b: *u8) -> i64 { 71 var i: i64 = 0 72 while 1 == 1 { 73 if a[i] != b[i] { return 0 } 74 if a[i] == (0 as u8) { return 1 } 75 i = i + 1 76 } 77 return 0 78} 79 80func p_ch(dst: *u8, off: i64, c: i64) -> i64 { dst[off] = c as u8; return off + 1 } 81func p_cat(dst: *u8, off: i64, s: *u8) -> i64 { 82 var i: i64 = 0 83 while s[i] != (0 as u8) { dst[off + i] = s[i]; i = i + 1 } 84 return off + i 85} 86// emit "key":"val" (comma-prefixed unless first) 87func p_kv(dst: *u8, off: i64, key: *u8, val: *u8, first: i64) -> i64 { 88 var o: i64 = off 89 if first == 0 { o = p_ch(dst, o, 44) } // , 90 o = p_ch(dst, o, 34); o = p_cat(dst, o, key); o = p_ch(dst, o, 34) 91 o = p_ch(dst, o, 58) // : 92 o = p_ch(dst, o, 34); o = p_cat(dst, o, val); o = p_ch(dst, o, 34) 93 return o 94} 95 96func mv_leg_parse(s: *u8) -> i64 { 97 let m: *u8 = "math" as *u8 98 let v: *u8 = "vlm" as *u8 99 let h: *u8 = "human" as *u8 100 let f: *u8 = "fused" as *u8 101 if seq(s, m) == 1 { return MV_LEG_MATH } 102 if seq(s, v) == 1 { return MV_LEG_VLM } 103 if seq(s, h) == 1 { return MV_LEG_HUMAN } 104 if seq(s, f) == 1 { return MV_LEG_FUSED } 105 return MV_LEG_VLM 106} 107 108func mv_atoi(s: *u8) -> i64 { 109 var n: i64 = 0 110 var i: i64 = 0 111 while s[i] != (0 as u8) { 112 let c: i64 = s[i] 113 if c >= 48 { 114 if c <= 57 { n = n * 10 + (c - 48) } 115 } 116 i = i + 1 117 } 118 return n 119} 120 121// contextual ctx from container magic + extension (pdf/epub -> book, cbz/cbr -> manga) 122func mv_ctx_from(b: *u8, n: i64, ext: *u8) -> i64 { 123 if mv_is_pdf(b, n) == 1 { return MV_CTX_PDF } 124 let e_epub: *u8 = "epub" as *u8 125 let e_cbz: *u8 = "cbz" as *u8 126 let e_cbr: *u8 = "cbr" as *u8 127 if mv_is_zip(b, n) == 1 { 128 if seq(ext, e_epub) == 1 { return MV_CTX_EPUB } 129 if seq(ext, e_cbz) == 1 { return MV_CTX_CBZ } 130 } 131 if mv_is_rar(b, n) == 1 { 132 if seq(ext, e_cbr) == 1 { return MV_CTX_CBR } 133 } 134 return MV_CTX_NONE 135} 136 137// Classify from a BOUNDED header window. Returns the vault type code, or -1 138// when the file cannot be read. out_size receives the true file size (the 139// binary-STL detector identifies purely by the size equation, so the sniffer 140// needs it) -- the single place where "what type is this item" is decided. 141func mv_type_of_path(path: *u8, ext: *u8, out_size: *i64) -> i64 { 142 let hdr: *u8 = sys_mmap(MV_HDR) 143 let hn: i64 = mv_read_head(path, hdr, MV_HDR) 144 if hn < 0 { return 0 - 1 } 145 let fsz: i64 = mv_file_size(path) 146 out_size[0] = fsz 147 let empty: *u8 = sys_mmap(1) 148 let mtype: i64 = nx_sniff_full(hdr, hn, fsz, empty, 0, path, mv_strlen(path)) 149 return mv_context_type(mtype, mv_ctx_from(hdr, hn, ext)) 150} 151 152// sniff = TYPE ONLY, no hashing. Reads a bounded header window and nothing 153// else, so triaging a 100k-item corpus costs one short read per file instead 154// of a full-content sha256. 155func do_sniff(argv: *i64) -> i64 { 156 let path: *u8 = argp(argv, 2) 157 var ext: *u8 = "" as *u8 158 if (argv[3]) != 0 { ext = argp(argv, 3) } 159 let szbox: *i64 = sys_mmap(8) as *i64 160 szbox[0] = 0 161 let vtype: i64 = mv_type_of_path(path, ext, szbox) 162 if vtype < 0 { 163 sys_write(2, "nx_mvault: cannot read file\n" as *u8, 28) 164 return 3 165 } 166 let k_path: *u8 = "path" as *u8 167 let k_typ: *u8 = "type" as *u8 168 let k_byt: *u8 = "bytes" as *u8 169 let buf: *u8 = sys_mmap(K_MAGIC_2048) 170 var o: i64 = 0 171 o = p_ch(buf, o, 123) 172 o = p_kv(buf, o, k_path, path, 1) 173 o = p_kv(buf, o, k_typ, mv_type_str(vtype), 0) 174 o = p_ch(buf, o, 44) 175 o = p_ch(buf, o, 34); o = p_cat(buf, o, k_byt); o = p_ch(buf, o, 34) 176 o = p_ch(buf, o, 58) 177 o = mv_u_dec(buf, o, szbox[0]) 178 o = p_ch(buf, o, 125) 179 o = p_ch(buf, o, 10) 180 sys_write(1, buf, o) 181 return 0 182} 183 184func do_classify(argv: *i64) -> i64 { 185 let path: *u8 = argp(argv, 2) 186 let prov_s: *u8 = argp(argv, 3) 187 let source: *u8 = argp(argv, 4) 188 let ext: *u8 = argp(argv, 5) 189 let szbox: *i64 = sys_mmap(8) as *i64 190 szbox[0] = 0 191 let vtype: i64 = mv_type_of_path(path, ext, szbox) 192 if vtype < 0 { 193 sys_write(2, "nx_mvault: cannot read file\n" as *u8, 28) 194 return 3 195 } 196 let g: *u8 = "gen" as *u8 197 var prov: i64 = MV_PROV_REAL 198 if seq(prov_s, g) == 1 { prov = MV_PROV_GEN } 199 let cls: i64 = mv_class(prov) 200 // Streaming CID (nx_canon_cid): byte-identical to the whole-file hash at 201 // O(1) memory, so a multi-GB recording never loads whole. 202 let cid: *u8 = sys_mmap(80) 203 if cid_of_file_chunk(path, CID_FILE_CHUNK, szbox, cid) < 0 { 204 sys_write(2, "nx_mvault: cannot read file\n" as *u8, 28) 205 return 3 206 } 207 let root: *u8 = "/volume1/vault" as *u8 208 let dpath: *u8 = sys_mmap(K_MAGIC_1024) 209 mv_disk_path(dpath, root, cls, vtype, cid, source, ext) 210 211 let k_cid: *u8 = "cid" as *u8 212 let k_cls: *u8 = "class" as *u8 213 let k_typ: *u8 = "type" as *u8 214 let k_mls: *u8 = "mls" as *u8 215 let k_path: *u8 = "dsm_path" as *u8 216 let v_ts: *u8 = "TS" as *u8 217 let buf: *u8 = sys_mmap(K_MAGIC_2048) 218 var o: i64 = 0 219 o = p_ch(buf, o, 123) // { 220 o = p_kv(buf, o, k_cid, cid, 1) 221 o = p_kv(buf, o, k_cls, mv_class_str(cls), 0) 222 o = p_kv(buf, o, k_typ, mv_type_str(vtype), 0) 223 o = p_kv(buf, o, k_mls, v_ts, 0) 224 o = p_kv(buf, o, k_path, dpath, 0) 225 o = p_ch(buf, o, 125) // } 226 o = p_ch(buf, o, 10) // \n 227 sys_write(1, buf, o) 228 return 0 229} 230 231// ===== retype backfill ===================================================== 232// Fixing the classifier does NOT fix records already written. The blobs were 233// never moved (record-only migration), so the original bytes are unreachable 234// from a record -- but the ref path carries the file EXTENSION, which is a 235// real sniffer tier and the one that resolves `.ts` -> video. Re-derive and 236// rewrite ONLY records whose type actually changed. DRY-RUN BY DEFAULT. 237 238const MV_FLDCAP: i64 = 1024 239const MV_BATCH: i64 = 16777216 // 16 MiB per commit batch; flushed, never truncated 240 241func mv_fld_eq(p: *u8, n: i64, s: *u8) -> i64 { 242 var i: i64 = 0 243 while i < n { 244 if s[i] == (0 as u8) { return 0 } 245 if p[i] != s[i] { return 0 } 246 i = i + 1 247 } 248 if s[n] != (0 as u8) { return 0 } 249 return 1 250} 251 252func mv_fld_cpy(dst: *u8, p: *u8, n: i64, cap: i64) -> i64 { 253 var m: i64 = n 254 if m > cap - 1 { m = cap - 1 } 255 var i: i64 = 0 256 while i < m { dst[i] = p[i]; i = i + 1 } 257 dst[m] = 0 as u8 258 return m 259} 260 261func do_retype(argv: *i64) -> i64 { 262 var commit: i64 = 0 263 var off0: i64 = 0 264 var lim: i64 = 0 265 if (argv[2]) != 0 { 266 let c: *u8 = "commit" as *u8 267 if seq(argp(argv, 2), c) == 1 { commit = 1 } 268 } 269 // BOUNDED WINDOW, declared not silent: reg_get sys_mmap's per call and 270 // never frees, so 37k lookups in ONE process exhausts it (measured: rc=1, 271 // zero output). Chunking bounds the mappings to one process-lifetime. 272 if (argv[3]) != 0 { off0 = mv_atoi(argp(argv, 3)) } 273 if (argv[4]) != 0 { lim = mv_atoi(argp(argv, 4)) } 274 let store: *u8 = "knowledge/store/mvault-" as *u8 275 // SEQUENTIAL SCAN, not point lookups: ss_get costs O(whole-store bytes) 276 // per call (it ss_readall's every live segment and returns a pointer INTO 277 // that mapping), so the point-lookup build died at 10k records. ss_cur_* 278 // maps each segment ONCE. 279 let st: *i64 = ss_cur_open(store) 280 let kout: *i64 = sys_mmap(16) as *i64 281 let klout: *i64 = sys_mmap(16) as *i64 282 let vout: *i64 = sys_mmap(16) as *i64 283 let vlout: *i64 = sys_mmap(16) as *i64 284 let fp: *i64 = sys_mmap(16) as *i64 285 let fl: *i64 = sys_mmap(16) as *i64 286 let cidb: *u8 = sys_mmap(128) 287 let refbuf: *u8 = sys_mmap(MV_FLDCAP) 288 let srcbuf: *u8 = sys_mmap(MV_FLDCAP) 289 let newref: *u8 = sys_mmap(MV_FLDCAP) 290 let rec2: *u8 = sys_mmap(K_MAGIC_4096) 291 let extb: *u8 = sys_mmap(64) 292 let root: *u8 = "/volume1/vault" as *u8 293 let k_ref: *u8 = "ref" as *u8 294 let k_typ: *u8 = "type" as *u8 295 let k_cls: *u8 = "class" as *u8 296 let k_src: *u8 = "source" as *u8 297 let s_gen: *u8 = "gen" as *u8 298 // BATCHED WRITE, not reg_put per record: reg_put mints a NEW SEGMENT and 299 // rewrites the whole id-index every call, so 17k corrections would be 17k 300 // segments. One ss_begin -> many ss_add2 -> one ss_commit instead. The 301 // id-index is deliberately untouched: retype only UPDATES existing keys, 302 // never introduces one, so enumeration is unchanged. 303 var w: *i64 = 0 as *i64 304 if commit == 1 { w = ss_begin_cap(MV_BATCH) } 305 var seen: i64 = 0 306 var changed: i64 = 0 307 var processed: i64 = 0 308 var more: i64 = 1 309 while more == 1 { 310 if ss_cur_next(store, st, kout, klout, vout, vlout) == 0 { more = 0 } 311 var isrec: i64 = 0 312 if more == 1 { 313 if st[6] == 1 { 314 let kb0: *u8 = (kout[0]) as *u8 315 let kl0: i64 = klout[0] 316 if kl0 > 3 { 317 if kb0[0] == (109 as u8) { 318 if kb0[1] == (118 as u8) { 319 if kb0[2] == (58 as u8) { isrec = 1 } 320 } 321 } 322 } 323 if kl0 == 6 { isrec = 0 } 324 } 325 } 326 if isrec == 1 { seen = seen + 1 } 327 var inwin: i64 = 0 328 if isrec == 1 { 329 if seen > off0 { 330 inwin = 1 331 if lim > 0 { if processed >= lim { inwin = 0 } } 332 } 333 } 334 if inwin == 1 { 335 processed = processed + 1 336 let kb: *u8 = (kout[0]) as *u8 337 let kl: i64 = klout[0] 338 let rec: *u8 = (vout[0]) as *u8 339 let rl: i64 = vlout[0] 340 if mv_rec_field(rec, rl, k_ref, 3, fp, fl) == 1 { 341 let refl: i64 = mv_fld_cpy(refbuf, (fp[0]) as *u8, fl[0], MV_FLDCAP) 342 let mt: i64 = nx_sniff_extension(refbuf, refl) 343 let nt: i64 = mv_type(MV_HINT_NONE, mt) 344 let nts: *u8 = mv_type_str(nt) 345 var differs: i64 = 0 346 if mv_rec_field(rec, rl, k_typ, 4, fp, fl) == 1 { 347 if mv_fld_eq((fp[0]) as *u8, fl[0], nts) == 0 { differs = 1 } 348 } 349 if nt == MV_TYPE_UNKNOWN { differs = 0 } 350 if differs == 1 { 351 changed = changed + 1 352 if commit == 1 { 353 mv_fld_cpy(cidb, ((kb as i64) + 3) as *u8, kl - 3, 128) 354 var cls: i64 = MV_CLASS_REAL 355 if mv_rec_field(rec, rl, k_cls, 5, fp, fl) == 1 { 356 if mv_fld_eq((fp[0]) as *u8, fl[0], s_gen) == 1 { cls = MV_CLASS_GEN } 357 } 358 srcbuf[0] = 0 as u8 359 if mv_rec_field(rec, rl, k_src, 6, fp, fl) == 1 { 360 mv_fld_cpy(srcbuf, (fp[0]) as *u8, fl[0], MV_FLDCAP) 361 } 362 let eoff: i64 = nx_sniff_ext_off(refbuf, refl) 363 extb[0] = 0 as u8 364 if eoff >= 0 { mv_fld_cpy(extb, ((refbuf as i64) + eoff) as *u8, refl - eoff, 64) } 365 mv_disk_path(newref, root, cls, nt, cidb, srcbuf, extb) 366 let rl2: i64 = mv_record_build(rec2, cls, nt, MV_LVL_TS, srcbuf, newref) 367 if ss_add2(w, 1, kb, kl, rec2, rl2) < 0 { 368 ss_commit(store, w, ss_next_segid(store)) 369 w = ss_begin_cap(MV_BATCH) 370 ss_add2(w, 1, kb, kl, rec2, rl2) 371 } 372 } 373 } 374 } 375 } 376 } 377 if commit == 1 { 378 if w[1] > 0 { ss_commit(store, w, ss_next_segid(store)) } 379 } 380 let k_seen: *u8 = "seen" as *u8 381 let k_chg: *u8 = "retyped" as *u8 382 let k_mode: *u8 = "mode" as *u8 383 let k_proc: *u8 = "processed" as *u8 384 let k_next: *u8 = "next" as *u8 385 let v_dry: *u8 = "dry" as *u8 386 let v_com: *u8 = "commit" as *u8 387 let out: *u8 = sys_mmap(512) 388 var o: i64 = 0 389 o = p_ch(out, o, 123) 390 o = p_ch(out, o, 34); o = p_cat(out, o, k_seen); o = p_ch(out, o, 34); o = p_ch(out, o, 58) 391 o = mv_u_dec(out, o, seen) 392 o = p_ch(out, o, 44) 393 o = p_ch(out, o, 34); o = p_cat(out, o, k_chg); o = p_ch(out, o, 34); o = p_ch(out, o, 58) 394 o = mv_u_dec(out, o, changed) 395 o = p_ch(out, o, 44) 396 o = p_ch(out, o, 34); o = p_cat(out, o, k_proc); o = p_ch(out, o, 34); o = p_ch(out, o, 58) 397 o = mv_u_dec(out, o, processed) 398 o = p_ch(out, o, 44) 399 o = p_ch(out, o, 34); o = p_cat(out, o, k_next); o = p_ch(out, o, 34); o = p_ch(out, o, 58) 400 o = mv_u_dec(out, o, off0 + processed) 401 if commit == 1 { o = p_kv(out, o, k_mode, v_com, 0) } else { o = p_kv(out, o, k_mode, v_dry, 0) } 402 o = p_ch(out, o, 125) 403 o = p_ch(out, o, 10) 404 sys_write(1, out, o) 405 return 0 406} 407 408// record = classify + write the NXR1 record to the sovereign seg-store (additive). 409func do_record(argv: *i64) -> i64 { 410 let path: *u8 = argp(argv, 2) 411 let prov_s: *u8 = argp(argv, 3) 412 let source: *u8 = argp(argv, 4) 413 let ext: *u8 = argp(argv, 5) 414 let szbox: *i64 = sys_mmap(8) as *i64 415 szbox[0] = 0 416 let vtype: i64 = mv_type_of_path(path, ext, szbox) 417 if vtype < 0 { sys_write(2, "nx_mvault: cannot read file\n" as *u8, 28); return 3 } 418 let g: *u8 = "gen" as *u8 419 var prov: i64 = MV_PROV_REAL 420 if seq(prov_s, g) == 1 { prov = MV_PROV_GEN } 421 let cls: i64 = mv_class(prov) 422 let cid: *u8 = sys_mmap(80) 423 if cid_of_file_chunk(path, CID_FILE_CHUNK, szbox, cid) < 0 { sys_write(2, "nx_mvault: cannot read file\n" as *u8, 28); return 3 } 424 let root: *u8 = "/volume1/vault" as *u8 425 let dpath: *u8 = sys_mmap(K_MAGIC_1024) 426 mv_disk_path(dpath, root, cls, vtype, cid, source, ext) 427 let store: *u8 = "knowledge/store/mvault-" as *u8 428 let rec: *u8 = sys_mmap(K_MAGIC_4096) 429 let rl: i64 = mv_record_build(rec, cls, vtype, MV_LVL_TS, source, dpath) 430 let rc: i64 = mv_store_put(store, cid, rec, rl) 431 let k_cid: *u8 = "cid" as *u8 432 let k_typ: *u8 = "type" as *u8 433 let k_rec: *u8 = "recorded" as *u8 434 let v_ok: *u8 = "1" as *u8 435 let buf: *u8 = sys_mmap(K_MAGIC_2048) 436 var o: i64 = 0 437 o = p_ch(buf, o, 123) 438 o = p_kv(buf, o, k_cid, cid, 1) 439 o = p_kv(buf, o, k_typ, mv_type_str(vtype), 0) 440 o = p_kv(buf, o, k_rec, v_ok, 0) 441 o = p_ch(buf, o, 125) 442 o = p_ch(buf, o, 10) 443 sys_write(1, buf, o) 444 if rc < 0 { return 4 } 445 return 0 446} 447 448// ---- ALBUM INGEST --------------------------------------------------------- 449// Exposes the album downloader so it is actually RUNNABLE (and therefore 450// callable over MCP). A capability with no verb is a capability nobody can use. 451func do_fetch(argc: i64, argv: *i64) -> i64 { 452 if argc < 3 { 453 sys_write(2, "usage: nx_mvault fetch <adapter|album|adapters>\n" as *u8, 47) 454 return 2 455 } 456 let sub: *u8 = argp(argv, 2) 457 458 if seq(sub, "adapter" as *u8) == 1 { 459 if argc < 9 { sys_write(2, "usage: nx_mvault fetch adapter <host> <link_tag> <link_attr> <link_pfx> <item_tag> <item_attr> [ua]\n" as *u8, 98); return 2 } 460 var ua: *u8 = "nishi" as *u8 461 if argc > 9 { ua = argp(argv, 9) } 462 // an empty item_tag means the album links ARE the media (one hop) 463 var itag: *u8 = argp(argv, 7) 464 if seq(itag, "-" as *u8) == 1 { itag = "" as *u8 } 465 let rc: i64 = mvf_adapter_put(argp(argv,3), argp(argv,4), argp(argv,5), argp(argv,6), itag, argp(argv,8), ua) 466 if rc < 0 { sys_write(2, "adapter put failed\n" as *u8, 19); return 4 } 467 sys_write(1, "{\"adapter\":\"" as *u8, 12) 468 sys_write(1, argp(argv,3), mv_strlen(argp(argv,3))) 469 sys_write(1, "\"}\n" as *u8, 3) 470 return 0 471 } 472 if seq(sub, "adapters" as *u8) == 1 { 473 let out: *u8 = sys_mmap(K_MAGIC_4194304) 474 let n: i64 = mvf_adapter_list(out, K_MAGIC_4194304) 475 if n < 0 { sys_write(2, "REFUSED: adapter index does not fit\n" as *u8, 36); return 4 } 476 sys_write(1, out, n) 477 return 0 478 } 479 if seq(sub, "album" as *u8) == 1 { 480 if argc < 5 { sys_write(2, "usage: nx_mvault fetch album <album-url> <dest-dir>\n" as *u8, 51); return 2 } 481 let store: i64 = hf_store_load() 482 if store <= 0 { sys_write(2, "ERR: trust store load failed (data/mozilla_certdata.txt on CWD?)\n" as *u8, 64); return 3 } 483 let rep: *u8 = sys_mmap(K_MAGIC_65536) 484 let got: i64 = mvf_fetch_album(store, argp(argv,3), argp(argv,4), rep, K_MAGIC_65536) 485 if got == (0-1) { sys_write(2, "REFUSED: no adapter for that host -- declare one first\n" as *u8, 54); return 5 } 486 if got == (0-2) { sys_write(2, "ERR: album page fetch failed\n" as *u8, 29); return 6 } 487 if got == (0-3) { sys_write(2, "ERR: no item links matched the adapter rule\n" as *u8, 44); return 7 } 488 sys_write(1, rep, mv_strlen(rep)) 489 return 0 490 } 491 sys_write(2, "nx_mvault fetch: unknown subcommand\n" as *u8, 36) 492 return 2 493} 494 495// ---- COLLECTION AXIS (site / album / source grouping) ---------------------- 496// Makes nx_mvault_coll operable from the CLI and therefore from MCP. A plane 497// with no verb is a plane nobody can use: the 07-30 tag plane shaped keys that 498// nothing could ever write or read, which is exactly how it stayed dark. 499func do_coll(argc: i64, argv: *i64) -> i64 { 500 if argc < 3 { 501 sys_write(2, "usage: nx_mvault coll <declare|add|get|items|of|list|count>\n" as *u8, 60) 502 return 2 503 } 504 let sub: *u8 = argp(argv, 2) 505 let out: *u8 = sys_mmap(K_MAGIC_4194304) 506 507 if seq(sub, "declare" as *u8) == 1 { 508 if argc < 7 { sys_write(2, "usage: nx_mvault coll declare <kind> <site> <key> <name> [url] [parent]\n" as *u8, 71); return 2 } 509 let cid: *u8 = sys_mmap(256) 510 var url: *u8 = "-" as *u8 511 var par: *u8 = "-" as *u8 512 if argc > 7 { url = argp(argv, 7) } 513 if argc > 8 { par = argp(argv, 8) } 514 mvc_declare(argp(argv,3), argp(argv,4), argp(argv,5), argp(argv,6), url, par, cid) 515 sys_write(1, cid, mv_strlen(cid)) 516 sys_write(1, "\n" as *u8, 1) 517 return 0 518 } 519 if seq(sub, "add" as *u8) == 1 { 520 if argc < 5 { sys_write(2, "usage: nx_mvault coll add <colid> <item-cid>\n" as *u8, 44); return 2 } 521 let item: *u8 = argp(argv, 4) 522 let buf: *u8 = sys_mmap(K_MAGIC_1024) 523 var o: i64 = 0 524 var i: i64 = 0 525 while item[i] != (0 as u8) { buf[o] = item[i]; o = o + 1; i = i + 1 } 526 buf[o] = 10 as u8; o = o + 1 527 let n: i64 = mvc_batch_add(argp(argv,3), buf, o) 528 sys_write(1, "{\"linked\":" as *u8, 10) 529 let d: *u8 = sys_mmap(32) 530 let dl: i64 = mv_u_dec(d, 0, n) 531 sys_write(1, d, dl) 532 sys_write(1, "}\n" as *u8, 2) 533 return 0 534 } 535 if seq(sub, "items" as *u8) == 1 { 536 if argc < 4 { sys_write(2, "usage: nx_mvault coll items <colid>\n" as *u8, 36); return 2 } 537 let n: i64 = mvc_items(argp(argv,3), out, K_MAGIC_4194304) 538 if n < 0 { sys_write(2, "REFUSED: collection does not fit the buffer\n" as *u8, 43); return 4 } 539 sys_write(1, out, n) 540 return 0 541 } 542 if seq(sub, "of" as *u8) == 1 { 543 if argc < 4 { sys_write(2, "usage: nx_mvault coll of <item-cid>\n" as *u8, 36); return 2 } 544 let n: i64 = mvc_of_item(argp(argv,3), out, K_MAGIC_4194304) 545 if n < 0 { sys_write(2, "REFUSED: does not fit the buffer\n" as *u8, 33); return 4 } 546 sys_write(1, out, n) 547 return 0 548 } 549 if seq(sub, "count" as *u8) == 1 { 550 if argc < 4 { sys_write(2, "usage: nx_mvault coll count <colid>\n" as *u8, 36); return 2 } 551 let c: i64 = mvc_count(argp(argv,3)) 552 let d: *u8 = sys_mmap(32) 553 let dl: i64 = mv_u_dec(d, 0, c) 554 sys_write(1, "{\"items\":" as *u8, 9) 555 sys_write(1, d, dl) 556 sys_write(1, "}\n" as *u8, 2) 557 return 0 558 } 559 if seq(sub, "get" as *u8) == 1 { 560 if argc < 4 { sys_write(2, "usage: nx_mvault coll get <colid>\n" as *u8, 34); return 2 } 561 let pp: *i64 = sys_mmap(16) as *i64 562 let ll: *i64 = sys_mmap(16) as *i64 563 mvc_get(argp(argv,3), pp, ll) 564 if ll[0] <= 0 { sys_write(2, "REFUSED: collection not found\n" as *u8, 30); return 4 } 565 sys_write(1, pp[0] as *u8, ll[0]) 566 sys_write(1, "\n" as *u8, 1) 567 return 0 568 } 569 if seq(sub, "list" as *u8) == 1 { 570 let n: i64 = mvc_list(out, K_MAGIC_4194304) 571 if n < 0 { sys_write(2, "REFUSED: index does not fit the buffer\n" as *u8, 38); return 4 } 572 sys_write(1, out, n) 573 return 0 574 } 575 sys_write(2, "nx_mvault coll: unknown subcommand\n" as *u8, 35) 576 return 2 577} 578 579// stats = count of items on the vault seg-store (the id index). 580func do_stats(argv: *i64) -> i64 { 581 let store: *u8 = "knowledge/store/mvault-" as *u8 582 let idx: *u8 = "mv:ids" as *u8 583 // ZERO-COPY (2026-07-31): this used to copy the whole id index into a fixed 584 // 4 MiB mapping. The live index passed 10 MiB, so the copy ran ~7 MiB off 585 // the end and this ruler died SILENTLY -- `nx_mvault stats` printed nothing 586 // at all, which reads as "no answer" rather than "I crashed". Counting the 587 // newlines directly in the store's own mapping needs no buffer, so the 588 // failure mode is gone by construction rather than pushed to a bigger cap. 589 let ipo: *i64 = sys_mmap(16) as *i64 590 let ilo: *i64 = sys_mmap(16) as *i64 591 var count: i64 = 0 592 if reg_index_open(store, idx, ipo, ilo) == 1 { 593 let buf: *u8 = ipo[0] as *u8 594 let ln: i64 = ilo[0] 595 var i: i64 = 0 596 while i < ln { 597 if buf[i] == (10 as u8) { count = count + 1 } 598 i = i + 1 599 } 600 } 601 let k_items: *u8 = "items" as *u8 602 let out: *u8 = sys_mmap(256) 603 var o: i64 = 0 604 o = p_ch(out, o, 123) 605 o = p_ch(out, o, 34); o = p_cat(out, o, k_items); o = p_ch(out, o, 34); o = p_ch(out, o, 58) 606 o = mv_u_dec(out, o, count) 607 o = p_ch(out, o, 125) 608 o = p_ch(out, o, 10) 609 sys_write(1, out, o) 610 return 0 611} 612 613func main(argc: i64, argv: *i64) -> i64 { 614 if argc < 2 { 615 sys_write(2, "usage: nx_mvault <sniff|classify|record|stats|tag|measure>\n" as *u8, 59) 616 return 2 617 } 618 let cmd: *u8 = argp(argv, 1) 619 let c_classify: *u8 = "classify" as *u8 620 let c_tag: *u8 = "tag" as *u8 621 let c_measure: *u8 = "measure" as *u8 622 623 if seq(cmd, c_classify) == 1 { 624 if argc < 6 { 625 sys_write(2, "usage: nx_mvault classify <path> <gen|real> <source> <ext>\n" as *u8, 59) 626 return 2 627 } 628 return do_classify(argv) 629 } 630 if seq(cmd, c_tag) == 1 { 631 if argc < 4 { sys_write(2, "usage: nx_mvault tag <ns> <value>\n" as *u8, 34); return 2 } 632 let out: *u8 = sys_mmap(512) 633 mv_tag_make(out, argp(argv, 2), argp(argv, 3)) 634 let ln: i64 = mv_strlen(out) 635 sys_write(1, out, ln) 636 sys_write(1, "\n" as *u8, 1) 637 return 0 638 } 639 if seq(cmd, c_measure) == 1 { 640 if argc < 6 { sys_write(2, "usage: nx_mvault measure <axis> <value> <leg> <conf>\n" as *u8, 53); return 2 } 641 let out: *u8 = sys_mmap(512) 642 let leg: i64 = mv_leg_parse(argp(argv, 4)) 643 let conf: i64 = mv_atoi(argp(argv, 5)) 644 mv_meas_make(out, argp(argv, 2), argp(argv, 3), leg, conf) 645 let ln: i64 = mv_strlen(out) 646 sys_write(1, out, ln) 647 sys_write(1, "\n" as *u8, 1) 648 return 0 649 } 650 let c_record: *u8 = "record" as *u8 651 if seq(cmd, c_record) == 1 { 652 if argc < 6 { sys_write(2, "usage: nx_mvault record <path> <gen|real> <source> <ext>\n" as *u8, 57); return 2 } 653 return do_record(argv) 654 } 655 let c_sniff: *u8 = "sniff" as *u8 656 if seq(cmd, c_sniff) == 1 { 657 if argc < 3 { sys_write(2, "usage: nx_mvault sniff <path> [ext]\n" as *u8, 36); return 2 } 658 return do_sniff(argv) 659 } 660 let c_coll: *u8 = "coll" as *u8 661 if seq(cmd, c_coll) == 1 { return do_coll(argc, argv) } 662 let c_fetch: *u8 = "fetch" as *u8 663 if seq(cmd, c_fetch) == 1 { return do_fetch(argc, argv) } 664 let c_retype: *u8 = "retype" as *u8 665 if seq(cmd, c_retype) == 1 { return do_retype(argv) } 666 let c_stats: *u8 = "stats" as *u8 667 if seq(cmd, c_stats) == 1 { return do_stats(argv) } 668 sys_write(2, "nx_mvault: unknown command\n" as *u8, 27) 669 return 2 670}