githolon 0.13.0 → 0.15.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (2) hide show
  1. package/dist/cli.mjs +105 -66
  2. package/package.json +3 -3
package/dist/cli.mjs CHANGED
@@ -476,7 +476,14 @@ function call(ex, mode, fields, STDERR) {
476
476
  const reqPtr = ex.git_holon_alloc(req.length);
477
477
  try {
478
478
  new Uint8Array(ex.memory.buffer, reqPtr, req.length).set(req);
479
- const { ptr, len } = unpack(ex.git_holon_call(reqPtr, req.length));
479
+ let packed;
480
+ try {
481
+ packed = ex.git_holon_call(reqPtr, req.length);
482
+ } catch (e) {
483
+ const tail = STDERR.length ? ` | stderr: ${STDERR.slice(-8).join(" / ")}` : "";
484
+ throw new Error(`${String(e && e.stack || e)}${tail}`);
485
+ }
486
+ const { ptr, len } = unpack(packed);
480
487
  try {
481
488
  const e = JSON.parse(dec2.decode(new Uint8Array(ex.memory.buffer, ptr, len).slice()));
482
489
  if (!e.ok) throw new Error((e.error || "holon error") + (STDERR.length ? ` | ${STDERR.slice(-4).join(" / ")}` : ""));
@@ -488,14 +495,9 @@ function call(ex, mode, fields, STDERR) {
488
495
  ex.git_holon_dealloc(reqPtr, req.length);
489
496
  }
490
497
  }
491
- function seedManifests(m, strings) {
492
- m.set("domain_manifests.json", new File(enc2.encode(strings.read)));
493
- m.set("identity-manifests.json", new File(enc2.encode(strings.identity)));
494
- }
495
- async function createEngine({ wasmModule, bootstrapPkg, nomosPkg, manifestStrings, replica, installedBy = "nomos-cloud" }) {
498
+ async function createEngine({ wasmModule, bootstrapPkg, nomosPkg, replica, installedBy = "nomos-cloud" }) {
496
499
  const hashes = { bootstrap: await sha256hex(bootstrapPkg), nomos: await sha256hex(nomosPkg) };
497
500
  const root = /* @__PURE__ */ new Map();
498
- seedManifests(root, manifestStrings);
499
501
  root.set("domain.package.usda", new File(enc2.encode(bootstrapPkg)));
500
502
  root.set("ws", new Directory(/* @__PURE__ */ new Map()));
501
503
  const preopen = new PreopenDirectory("/work", root);
@@ -516,55 +518,56 @@ async function createEngine({ wasmModule, bootstrapPkg, nomosPkg, manifestString
516
518
  hashes,
517
519
  bootstrapPkg,
518
520
  nomosPkg,
519
- manifestStrings,
520
521
  installedBy,
521
522
  fs: makeGitFs(preopen, "/work", { File, Directory }),
522
523
  mounted: /* @__PURE__ */ new Map(),
523
524
  // ws -> { restored, remoteMain, restoreError }
524
- mainIntents: /* @__PURE__ */ new Map(),
525
+ mainIntents: /* @__PURE__ */ new Map()
525
526
  // ws -> { head, ids:Set, oids:Set } (admission idempotence)
526
- knownDomainsCache: null
527
527
  };
528
528
  return eng;
529
529
  }
530
- function setManifests(eng, strings) {
531
- eng.manifestStrings = strings;
532
- eng.knownDomainsCache = null;
533
- eng.directiveRoutesCache = null;
534
- eng.scopedReadsCache = null;
535
- eng.placementDirectivesCache = null;
536
- eng.tenantTypesCache = null;
537
- eng.globalAggregatesCache = null;
538
- const root = eng.preopen.dir.contents;
539
- seedManifests(root, strings);
540
- const wsRoot = root.get("ws");
541
- for (const ws of eng.mounted.keys()) {
542
- const wsDir = wsRoot.contents.get(ws);
543
- if (wsDir) seedManifests(wsDir.contents, strings);
544
- }
530
+ function stageWorkspaceDir(eng, ws) {
531
+ const wsContents = /* @__PURE__ */ new Map();
532
+ eng.preopen.dir.contents.get("ws").contents.set(ws, new Directory(wsContents));
545
533
  }
546
534
  async function mountWorkspace(eng, ws, ledger) {
547
535
  if (eng.mounted.has(ws)) return eng.mounted.get(ws);
548
- const wsContents = /* @__PURE__ */ new Map();
549
- seedManifests(wsContents, eng.manifestStrings);
550
- eng.preopen.dir.contents.get("ws").contents.set(ws, new Directory(wsContents));
536
+ stageWorkspaceDir(eng, ws);
551
537
  const gitdir = gitdirOf(ws);
552
- let restored = false, remoteMain = null, restoreError = null;
538
+ let restored = false, remoteMain = null, restoreError = null, checkpoint = null;
553
539
  try {
554
540
  const info = await git.getRemoteInfo({ http, url: ledger.remote, headers: ledger.headers });
555
541
  remoteMain = info.refs && info.refs.heads && info.refs.heads.main || null;
556
542
  if (remoteMain) {
557
543
  await git.init({ fs: eng.fs, gitdir, bare: true, defaultBranch: "main" });
558
544
  await git.addRemote({ fs: eng.fs, gitdir, remote: "origin", url: ledger.remote, force: true });
559
- await git.fetch({ fs: eng.fs, http, gitdir, remote: "origin", ref: "main", singleBranch: true, headers: ledger.headers });
545
+ const ckpt = await discoverCheckpointFromCustody(ledger).catch(() => null);
546
+ let shallowOk = false;
547
+ if (ckpt?.cursor && ckpt.frontier) {
548
+ const steps = [32, 96, 256, 1024];
549
+ for (let i = 0; i < steps.length; i++) {
550
+ const depth = steps[i], relative = i > 0;
551
+ await git.fetch({ fs: eng.fs, http, gitdir, remote: "origin", ref: "main", singleBranch: true, depth, relative, headers: ledger.headers });
552
+ if (await git.readCommit({ fs: eng.fs, gitdir, oid: ckpt.cursor }).then(() => true, () => false)) {
553
+ shallowOk = true;
554
+ break;
555
+ }
556
+ }
557
+ }
558
+ if (!shallowOk) await git.fetch({ fs: eng.fs, http, gitdir, remote: "origin", ref: "main", singleBranch: true, headers: ledger.headers });
560
559
  await git.writeRef({ fs: eng.fs, gitdir, ref: "refs/heads/main", value: remoteMain, force: true });
561
560
  await git.writeRef({ fs: eng.fs, gitdir, ref: "HEAD", value: "ref: refs/heads/main", force: true, symbolic: true });
561
+ if (shallowOk && ckpt?.blob) {
562
+ const r = importCheckpoint(eng, ws, ckpt.blob, ckpt.frontier);
563
+ checkpoint = { restored: !!(r && r.restored), frontierSeeded: !!(r && r.frontierSeeded), cursor: r && r.cursor ? r.cursor : ckpt.cursor, ref: ckpt.ref };
564
+ }
562
565
  restored = true;
563
566
  }
564
567
  } catch (e) {
565
568
  restoreError = String(e && e.stack || e).split("\n").slice(0, 5).join(" | ");
566
569
  }
567
- const m = { restored, remoteMain, restoreError };
570
+ const m = { restored, remoteMain, restoreError, checkpoint };
568
571
  eng.mounted.set(ws, m);
569
572
  return m;
570
573
  }
@@ -591,6 +594,71 @@ function author(eng, ws, domain, directiveId, payload, controllerHash, opts = {}
591
594
  if (defer && res.ok) (eng.pendingProjection ??= /* @__PURE__ */ new Set()).add(ws);
592
595
  return res;
593
596
  }
597
+ function importCheckpoint(eng, ws, blobB64, frontierB64) {
598
+ return JSON.parse(call(eng.ex, "checkpoint_import", { repoArg: repoArgOf(ws), workspace: ws, branch: BRANCH, blob: blobB64, ...frontierB64 ? { frontier: frontierB64 } : {} }, eng.STDERR));
599
+ }
600
+ async function streamAll(stream) {
601
+ const chunks = [];
602
+ const reader = stream.getReader();
603
+ for (; ; ) {
604
+ const { done, value } = await reader.read();
605
+ if (done) break;
606
+ chunks.push(value);
607
+ }
608
+ let len = 0;
609
+ for (const c of chunks) len += c.length;
610
+ const out10 = new Uint8Array(len);
611
+ let at = 0;
612
+ for (const c of chunks) {
613
+ out10.set(c, at);
614
+ at += c.length;
615
+ }
616
+ return out10;
617
+ }
618
+ async function gunzip(bytes) {
619
+ const ds = new DecompressionStream("gzip");
620
+ return streamAll(new Response(bytes).body.pipeThrough(ds));
621
+ }
622
+ async function discoverCheckpointFromCustody(ledger) {
623
+ const freshHeaders = () => ({ ...ledger.headers || {} });
624
+ const refs = (await git.listServerRefs({ http, url: ledger.remote, headers: freshHeaders(), prefix: "refs/meta/checkpoint/", protocolVersion: 2 }) || []).filter((r) => r.ref && r.ref.startsWith("refs/meta/checkpoint/") && r.oid);
625
+ if (!refs.length) return null;
626
+ const root = /* @__PURE__ */ new Map();
627
+ root.set("ckpt", new Directory(/* @__PURE__ */ new Map()));
628
+ const preopen = new PreopenDirectory("/work", root);
629
+ const fs = makeGitFs(preopen, "/work", { File, Directory });
630
+ const gitdir = "/work/ckpt/nomos.git";
631
+ await git.init({ fs, gitdir, bare: true, defaultBranch: BRANCH });
632
+ await git.addRemote({ fs, gitdir, remote: "origin", url: ledger.remote, force: true });
633
+ const readFile = async (oid, filepath) => {
634
+ try {
635
+ return (await git.readBlob({ fs, gitdir, oid, filepath })).blob;
636
+ } catch {
637
+ return null;
638
+ }
639
+ };
640
+ for (let i = refs.length - 1; i >= 0 && i >= refs.length - 3; i--) {
641
+ const { ref, oid } = refs[i];
642
+ try {
643
+ await git.fetch({ fs, http, gitdir, remote: "origin", ref, singleBranch: true, depth: 1, headers: freshHeaders() });
644
+ const gz = await readFile(oid, "checkpoint");
645
+ if (!gz) continue;
646
+ let meta = {};
647
+ try {
648
+ const mb = await readFile(oid, "meta");
649
+ if (mb) meta = JSON.parse(dec2.decode(mb));
650
+ } catch {
651
+ }
652
+ const codec = meta.codec ?? "gzip";
653
+ const blob = dec2.decode(codec === "gzip" ? await gunzip(gz) : gz);
654
+ const fgz = await readFile(oid, "frontier");
655
+ const frontier = fgz ? dec2.decode(codec === "gzip" ? await gunzip(fgz) : fgz) : null;
656
+ return { ref, oid, cursor: meta.cursor || null, blob, frontier };
657
+ } catch {
658
+ }
659
+ }
660
+ return null;
661
+ }
594
662
  function applyIntentBytes(eng, ws, bytes) {
595
663
  const name = `intent-in-${eng.seq++}.json`;
596
664
  writeWork(eng, name, bytes);
@@ -648,9 +716,8 @@ async function fetchRuntime(cloud) {
648
716
  const localWasm = process.env["NOMOS_LOCAL_WASM"];
649
717
  if (localWasm) {
650
718
  const bytes = readFileSync2(localWasm);
651
- const manifests2 = await fetchJsonCached(`${cloud}/v1/runtime/manifests`, join4(cache, "manifests.json"));
652
719
  const packages2 = await fetchJsonCached(`${cloud}/v1/runtime/packages`, join4(cache, "packages.json"));
653
- return { wasmBytes: bytes, manifests: manifests2, packages: packages2 };
720
+ return { wasmBytes: bytes, packages: packages2 };
654
721
  }
655
722
  try {
656
723
  const r = await fetch(`${cloud}/v1/runtime/holon.wasm`);
@@ -662,25 +729,8 @@ async function fetchRuntime(cloud) {
662
729
  if (!existsSync3(wasmCache)) throw e;
663
730
  wasmBytes = readFileSync2(wasmCache);
664
731
  }
665
- const manifests = await fetchJsonCached(`${cloud}/v1/runtime/manifests`, join4(cache, "manifests.json"));
666
732
  const packages = await fetchJsonCached(`${cloud}/v1/runtime/packages`, join4(cache, "packages.json"));
667
- return { wasmBytes, manifests, packages };
668
- }
669
- function mergeManifests(baked, overlay) {
670
- const read = JSON.parse(baked.domainManifests);
671
- const identity = JSON.parse(baked.identityManifests);
672
- for (const [k, v] of Object.entries(overlay.identityManifests ?? {})) identity[k] = v;
673
- const r = overlay.readManifest;
674
- if (r !== void 0) {
675
- for (const [t, schema] of Object.entries(r["aggregateFieldKinds"] ?? {})) read["aggregateFieldKinds"][t] = schema;
676
- for (const key of ["queries", "counts", "sums", "mins", "maxes", "spatials", "deriveds", "combineds"]) {
677
- for (const d of r[key] ?? []) {
678
- const list = read[key] = read[key] ?? [];
679
- if (!list.some((x) => JSON.stringify(x) === JSON.stringify(d))) list.push(d);
680
- }
681
- }
682
- }
683
- return { read: JSON.stringify(read), identity: JSON.stringify(identity) };
733
+ return { wasmBytes, packages };
684
734
  }
685
735
  function writeTreeToDisk(dir, diskPath) {
686
736
  mkdirSync3(diskPath, { recursive: true });
@@ -701,13 +751,11 @@ function readTreeFromDisk(diskPath) {
701
751
  }
702
752
  async function holonEngine(cloud, overlay, installedBy) {
703
753
  const runtime = await fetchRuntime(cloud);
704
- const manifestStrings = overlay === void 0 ? { read: runtime.manifests.domainManifests, identity: runtime.manifests.identityManifests } : mergeManifests(runtime.manifests, overlay);
705
754
  const replica = BigInt(`0x${randomBytes(8).toString("hex")}`) & (1n << 63n) - 1n;
706
755
  const eng = await createEngine({
707
756
  wasmModule: await WebAssembly.compile(runtime.wasmBytes),
708
757
  bootstrapPkg: runtime.packages.bootstrap,
709
758
  nomosPkg: runtime.packages.nomos,
710
- manifestStrings,
711
759
  replica,
712
760
  installedBy
713
761
  });
@@ -1475,12 +1523,9 @@ function readDeployBody(cwd, packageName) {
1475
1523
  async function installLaw(s, deployBody, installedBy) {
1476
1524
  const newHash = await sha256hex(deployBody.packageUsda);
1477
1525
  if (newHash === s.lawHash) return { ok: true };
1478
- const previous = { ...s.eng.manifestStrings };
1479
1526
  const t0 = performance.now();
1480
- setManifests(s.eng, mergeManifests(s.runtime.manifests, deployBody));
1481
1527
  const res = author(s.eng, WS, "nomos", "installDomain", installPayload(newHash, deployBody.packageUsda, installedBy), s.eng.hashes.nomos);
1482
1528
  if (res.ok === false) {
1483
- setManifests(s.eng, previous);
1484
1529
  return { ok: false, error: `law install refused: ${res.error ?? "unknown"} \u2014 the previous law (${s.lawHash.slice(0, 12)}\u2026) keeps serving; fix and save again` };
1485
1530
  }
1486
1531
  s.lawHash = newHash;
@@ -1758,7 +1803,7 @@ async function gitRemote(ws, name, opts) {
1758
1803
  var HELP = {
1759
1804
  compile: {
1760
1805
  usage: "githolon compile [config] [--layered]",
1761
- what: "Compile the package by ./nomos.package.mjs (the @githolon/dsl launcher): ONE deterministic\n.package.usda (sha256 = the law's content hash) + read/identity manifests + the deploy body +\nthe typed TS client + the generated proof \u2014 all into build/.",
1806
+ what: "Compile the package by ./nomos.package.mjs (the @githolon/dsl launcher): ONE deterministic\n.package.usda (sha256 = the law's content hash) + the deploy body +\nthe typed TS client + the generated proof \u2014 all into build/.",
1762
1807
  flags: [
1763
1808
  ["[config]", "an alternate config file (default: nomos.package.mjs)"],
1764
1809
  ["--layered", "also emit the per-domain layered USD view"]
@@ -1792,7 +1837,7 @@ var HELP = {
1792
1837
  ["<ws|dir>", "a workspace name on the cloud, or a local holon directory (githolon ledger init)"],
1793
1838
  ["--step N", "non-interactive; print the running tallies every N intents"],
1794
1839
  ["--json", "one JSON line per step + the final verdict (pipe it)"],
1795
- ["--file <deploy.json>", "stage this deploy body's read manifests (default: the one in ./build)"]
1840
+ ["--file <deploy.json>", "reserved for local package hints (default: the one in ./build)"]
1796
1841
  ],
1797
1842
  examples: ["githolon replay my-guestbook", "githolon replay ./my-holon --step 10", "githolon replay my-guestbook --json | jq .directive"]
1798
1843
  },
@@ -1965,7 +2010,7 @@ init_engine();
1965
2010
  init_engine();
1966
2011
  init_cloud();
1967
2012
  init_local_holon();
1968
- import { existsSync as existsSync8, readFileSync as readFileSync7 } from "node:fs";
2013
+ import { existsSync as existsSync8 } from "node:fs";
1969
2014
  import { join as join9 } from "node:path";
1970
2015
  import git3 from "isomorphic-git";
1971
2016
  var out7 = (s) => void process.stdout.write(s + "\n");
@@ -2055,15 +2100,9 @@ async function replay(target, opts) {
2055
2100
  const cloud = cloudBase(opts.cloud);
2056
2101
  const json = opts.json === true;
2057
2102
  const emit = (o) => out7(JSON.stringify(o));
2058
- let overlay;
2059
- try {
2060
- overlay = JSON.parse(readFileSync7(discoverDeployJson(process.cwd(), opts.file), "utf8"));
2061
- } catch {
2062
- overlay = void 0;
2063
- }
2064
2103
  let eng;
2065
2104
  try {
2066
- ({ eng } = await holonEngine(cloud, overlay, "githolon-replay"));
2105
+ ({ eng } = await holonEngine(cloud, void 0, "githolon-replay"));
2067
2106
  } catch (e) {
2068
2107
  err7(`cannot boot the local holon: ${String(e.message ?? e)}
2069
2108
  the runtime rides ${cloud}/v1/runtime/* (cached in ~/.holon/runtime after one fetch)`);
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "githolon",
3
- "version": "0.13.0",
3
+ "version": "0.15.0",
4
4
  "type": "module",
5
5
  "description": "githolon — the Nomos developer CLI: Rails-style generators for @githolon/dsl domains + the package compiler. Kernel-independent.",
6
6
  "license": "SEE LICENSE IN LICENSE.md",
@@ -10,7 +10,7 @@
10
10
  "directory": "cli"
11
11
  },
12
12
  "bin": {
13
- "githolon": "./dist/cli.mjs"
13
+ "githolon": "dist/cli.mjs"
14
14
  },
15
15
  "files": [
16
16
  "dist"
@@ -27,7 +27,7 @@
27
27
  },
28
28
  "dependencies": {
29
29
  "@bjorn3/browser_wasi_shim": "0.4.2",
30
- "@githolon/dsl": "^0.13.0",
30
+ "@githolon/dsl": "^0.15.0",
31
31
  "isomorphic-git": "^1.38.4"
32
32
  },
33
33
  "devDependencies": {