githolon 0.13.0 → 0.14.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 +98 -6
  2. package/package.json +2 -2
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(" / ")}` : ""));
@@ -543,28 +550,48 @@ function setManifests(eng, strings) {
543
550
  if (wsDir) seedManifests(wsDir.contents, strings);
544
551
  }
545
552
  }
546
- async function mountWorkspace(eng, ws, ledger) {
547
- if (eng.mounted.has(ws)) return eng.mounted.get(ws);
553
+ function stageWorkspaceDir(eng, ws) {
548
554
  const wsContents = /* @__PURE__ */ new Map();
549
555
  seedManifests(wsContents, eng.manifestStrings);
550
556
  eng.preopen.dir.contents.get("ws").contents.set(ws, new Directory(wsContents));
557
+ }
558
+ async function mountWorkspace(eng, ws, ledger) {
559
+ if (eng.mounted.has(ws)) return eng.mounted.get(ws);
560
+ stageWorkspaceDir(eng, ws);
551
561
  const gitdir = gitdirOf(ws);
552
- let restored = false, remoteMain = null, restoreError = null;
562
+ let restored = false, remoteMain = null, restoreError = null, checkpoint = null;
553
563
  try {
554
564
  const info = await git.getRemoteInfo({ http, url: ledger.remote, headers: ledger.headers });
555
565
  remoteMain = info.refs && info.refs.heads && info.refs.heads.main || null;
556
566
  if (remoteMain) {
557
567
  await git.init({ fs: eng.fs, gitdir, bare: true, defaultBranch: "main" });
558
568
  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 });
569
+ const ckpt = await discoverCheckpointFromCustody(ledger).catch(() => null);
570
+ let shallowOk = false;
571
+ if (ckpt?.cursor && ckpt.frontier) {
572
+ const steps = [32, 96, 256, 1024];
573
+ for (let i = 0; i < steps.length; i++) {
574
+ const depth = steps[i], relative = i > 0;
575
+ await git.fetch({ fs: eng.fs, http, gitdir, remote: "origin", ref: "main", singleBranch: true, depth, relative, headers: ledger.headers });
576
+ if (await git.readCommit({ fs: eng.fs, gitdir, oid: ckpt.cursor }).then(() => true, () => false)) {
577
+ shallowOk = true;
578
+ break;
579
+ }
580
+ }
581
+ }
582
+ if (!shallowOk) await git.fetch({ fs: eng.fs, http, gitdir, remote: "origin", ref: "main", singleBranch: true, headers: ledger.headers });
560
583
  await git.writeRef({ fs: eng.fs, gitdir, ref: "refs/heads/main", value: remoteMain, force: true });
561
584
  await git.writeRef({ fs: eng.fs, gitdir, ref: "HEAD", value: "ref: refs/heads/main", force: true, symbolic: true });
585
+ if (shallowOk && ckpt?.blob) {
586
+ const r = importCheckpoint(eng, ws, ckpt.blob, ckpt.frontier);
587
+ checkpoint = { restored: !!(r && r.restored), frontierSeeded: !!(r && r.frontierSeeded), cursor: r && r.cursor ? r.cursor : ckpt.cursor, ref: ckpt.ref };
588
+ }
562
589
  restored = true;
563
590
  }
564
591
  } catch (e) {
565
592
  restoreError = String(e && e.stack || e).split("\n").slice(0, 5).join(" | ");
566
593
  }
567
- const m = { restored, remoteMain, restoreError };
594
+ const m = { restored, remoteMain, restoreError, checkpoint };
568
595
  eng.mounted.set(ws, m);
569
596
  return m;
570
597
  }
@@ -591,6 +618,71 @@ function author(eng, ws, domain, directiveId, payload, controllerHash, opts = {}
591
618
  if (defer && res.ok) (eng.pendingProjection ??= /* @__PURE__ */ new Set()).add(ws);
592
619
  return res;
593
620
  }
621
+ function importCheckpoint(eng, ws, blobB64, frontierB64) {
622
+ return JSON.parse(call(eng.ex, "checkpoint_import", { repoArg: repoArgOf(ws), workspace: ws, branch: BRANCH, blob: blobB64, ...frontierB64 ? { frontier: frontierB64 } : {} }, eng.STDERR));
623
+ }
624
+ async function streamAll(stream) {
625
+ const chunks = [];
626
+ const reader = stream.getReader();
627
+ for (; ; ) {
628
+ const { done, value } = await reader.read();
629
+ if (done) break;
630
+ chunks.push(value);
631
+ }
632
+ let len = 0;
633
+ for (const c of chunks) len += c.length;
634
+ const out10 = new Uint8Array(len);
635
+ let at = 0;
636
+ for (const c of chunks) {
637
+ out10.set(c, at);
638
+ at += c.length;
639
+ }
640
+ return out10;
641
+ }
642
+ async function gunzip(bytes) {
643
+ const ds = new DecompressionStream("gzip");
644
+ return streamAll(new Response(bytes).body.pipeThrough(ds));
645
+ }
646
+ async function discoverCheckpointFromCustody(ledger) {
647
+ const freshHeaders = () => ({ ...ledger.headers || {} });
648
+ 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);
649
+ if (!refs.length) return null;
650
+ const root = /* @__PURE__ */ new Map();
651
+ root.set("ckpt", new Directory(/* @__PURE__ */ new Map()));
652
+ const preopen = new PreopenDirectory("/work", root);
653
+ const fs = makeGitFs(preopen, "/work", { File, Directory });
654
+ const gitdir = "/work/ckpt/nomos.git";
655
+ await git.init({ fs, gitdir, bare: true, defaultBranch: BRANCH });
656
+ await git.addRemote({ fs, gitdir, remote: "origin", url: ledger.remote, force: true });
657
+ const readFile = async (oid, filepath) => {
658
+ try {
659
+ return (await git.readBlob({ fs, gitdir, oid, filepath })).blob;
660
+ } catch {
661
+ return null;
662
+ }
663
+ };
664
+ for (let i = refs.length - 1; i >= 0 && i >= refs.length - 3; i--) {
665
+ const { ref, oid } = refs[i];
666
+ try {
667
+ await git.fetch({ fs, http, gitdir, remote: "origin", ref, singleBranch: true, depth: 1, headers: freshHeaders() });
668
+ const gz = await readFile(oid, "checkpoint");
669
+ if (!gz) continue;
670
+ let meta = {};
671
+ try {
672
+ const mb = await readFile(oid, "meta");
673
+ if (mb) meta = JSON.parse(dec2.decode(mb));
674
+ } catch {
675
+ }
676
+ const codec = meta.codec ?? "gzip";
677
+ const blob = dec2.decode(codec === "gzip" ? await gunzip(gz) : gz);
678
+ const fgz = await readFile(oid, "frontier");
679
+ const frontier = fgz ? dec2.decode(codec === "gzip" ? await gunzip(fgz) : fgz) : null;
680
+ return { ref, oid, cursor: meta.cursor || null, blob, frontier };
681
+ } catch {
682
+ }
683
+ }
684
+ return null;
685
+ }
594
686
  function applyIntentBytes(eng, ws, bytes) {
595
687
  const name = `intent-in-${eng.seq++}.json`;
596
688
  writeWork(eng, name, bytes);
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "githolon",
3
- "version": "0.13.0",
3
+ "version": "0.14.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",
@@ -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.14.0",
31
31
  "isomorphic-git": "^1.38.4"
32
32
  },
33
33
  "devDependencies": {