githolon 0.92.0 → 0.94.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/dist/cli.mjs CHANGED
@@ -9,7 +9,7 @@ var __export = (target, all) => {
9
9
  __defProp(target, name, { get: all[name], enumerable: true });
10
10
  };
11
11
 
12
- // vendor/engine/git-fs.mjs
12
+ // vendor/engine/git-fs.ts
13
13
  function fsErr(code, p) {
14
14
  const e = new Error(`${code}: ${p}`);
15
15
  e.code = code;
@@ -17,7 +17,7 @@ function fsErr(code, p) {
17
17
  }
18
18
  function makeGitFs(preopen, mount, { File: File3, Directory: Directory3 }) {
19
19
  const root = preopen.dir;
20
- const isDir = (n) => n && n.contents instanceof Map;
20
+ const isDir = (n) => !!n && n.contents instanceof Map;
21
21
  function parts(p) {
22
22
  if (p === mount) return [];
23
23
  if (!p.startsWith(mount + "/")) throw fsErr("ENOENT", p);
@@ -107,14 +107,14 @@ function makeGitFs(preopen, mount, { File: File3, Directory: Directory3 }) {
107
107
  return { promises };
108
108
  }
109
109
  var init_git_fs = __esm({
110
- "vendor/engine/git-fs.mjs"() {
110
+ "vendor/engine/git-fs.ts"() {
111
111
  "use strict";
112
112
  }
113
113
  });
114
114
 
115
- // vendor/engine/tree.mjs
115
+ // vendor/engine/tree.ts
116
116
  function flatten(dir, prefix, out13) {
117
- for (const [name, inode] of dir.contents) {
117
+ for (const [name, inode] of dir.contents ?? /* @__PURE__ */ new Map()) {
118
118
  const path = prefix ? prefix + "/" + name : name;
119
119
  if (inode.contents instanceof Map) {
120
120
  out13.push({ path, dir: true });
@@ -153,14 +153,14 @@ function serializeTree(workTree) {
153
153
  }
154
154
  var enc, dec;
155
155
  var init_tree = __esm({
156
- "vendor/engine/tree.mjs"() {
156
+ "vendor/engine/tree.ts"() {
157
157
  "use strict";
158
158
  enc = new TextEncoder();
159
159
  dec = new TextDecoder();
160
160
  }
161
161
  });
162
162
 
163
- // vendor/engine/custody-transport.mjs
163
+ // vendor/engine/custody-transport.ts
164
164
  function concatBytes(chunks) {
165
165
  let n = 0;
166
166
  for (const c of chunks) n += c.length;
@@ -284,7 +284,7 @@ async function pushPack(remote, headers = {}, { updates = [], pack = null } = {}
284
284
  }
285
285
  var enc2, dec2, ZERO_OID, EMPTY_PACK, FLUSH;
286
286
  var init_custody_transport = __esm({
287
- "vendor/engine/custody-transport.mjs"() {
287
+ "vendor/engine/custody-transport.ts"() {
288
288
  "use strict";
289
289
  enc2 = new TextEncoder();
290
290
  dec2 = new TextDecoder();
@@ -329,7 +329,7 @@ var init_custody_transport = __esm({
329
329
  }
330
330
  });
331
331
 
332
- // vendor/engine/engine.mjs
332
+ // vendor/engine/engine.ts
333
333
  var engine_exports = {};
334
334
  __export(engine_exports, {
335
335
  NOMOS_SHARD_ROWS_READ: () => NOMOS_SHARD_ROWS_READ,
@@ -485,7 +485,7 @@ function call(ex, mode, fields, STDERR) {
485
485
  packed = ex.git_holon_call(reqPtr, req.length);
486
486
  } catch (e) {
487
487
  const tail = STDERR.length ? ` | stderr: ${STDERR.slice(-8).join(" / ")}` : "";
488
- throw new Error(`${String(e && e.stack || e)}${tail}`);
488
+ throw new Error(`${String(e?.stack || e)}${tail}`);
489
489
  }
490
490
  const { ptr, len } = unpack(packed);
491
491
  try {
@@ -516,9 +516,10 @@ async function createEngine({ wasmModule, bootstrapPkg, nomosPkg, replica, insta
516
516
  const inst = await WebAssembly.instantiate(wasmModule, { wasi_snapshot_preview1: wasi.wasiImport });
517
517
  const code = wasi.start(inst);
518
518
  if (code !== 0) throw new Error(`reactor init exited ${code}; stderr=${STDERR.join("\n")}`);
519
- for (const n of ["memory", "git_holon_alloc", "git_holon_dealloc", "git_holon_call"]) if (!inst.exports[n]) throw new Error(`missing export ${n}`);
519
+ const instExports = inst.exports;
520
+ for (const n of ["memory", "git_holon_alloc", "git_holon_dealloc", "git_holon_call"]) if (!instExports[n]) throw new Error(`missing export ${n}`);
520
521
  const eng = {
521
- ex: inst.exports,
522
+ ex: instExports,
522
523
  preopen,
523
524
  STDERR,
524
525
  seq: 0,
@@ -555,7 +556,7 @@ async function wrongHomeVerdict(shardRouting, route, payload) {
555
556
  const tag = routeTagHexOfMintedId(value);
556
557
  if (tag !== void 0) {
557
558
  for (const a of rows) {
558
- if (await routeTagHexOfHomeKey(a.homeKey) === tag) {
559
+ if (await routeTagHexOfHomeKey(String(a.homeKey)) === tag) {
559
560
  assignment = a;
560
561
  break;
561
562
  }
@@ -827,7 +828,7 @@ async function deriveSummarySuffix(eng, ws, fromOid) {
827
828
  touchedBuckets.add(ak);
828
829
  }
829
830
  for (const bk of touchedBuckets) {
830
- const ov = extRunning.has(bk) ? extRunning.get(bk) : null;
831
+ const ov = extRunning.has(bk) ? extRunning.get(bk) ?? null : null;
831
832
  const nv = recomputeExt(read, bk);
832
833
  if (nv === ov) continue;
833
834
  extRunning.set(bk, nv);
@@ -839,7 +840,7 @@ async function deriveSummarySuffix(eng, ws, fromOid) {
839
840
  }
840
841
  } else {
841
842
  for (const d of contributionDiff(read, before, after)) {
842
- bump(summaryKey(d.readId, d.group), d.delta);
843
+ bump(summaryKey(d.readId, d.group), d.delta ?? 0);
843
844
  deltas.push(d);
844
845
  }
845
846
  }
@@ -872,6 +873,7 @@ async function deriveSummarySuffix(eng, ws, fromOid) {
872
873
  }
873
874
  }
874
875
  if (!sawFrom) return { ok: false, error: `fromOid ${String(fromOid).slice(0, 12)} is not on this shard's main \u2014 cannot derive the suffix` };
876
+ if (!prevs) prevs = /* @__PURE__ */ new Map();
875
877
  const touched = /* @__PURE__ */ new Set();
876
878
  for (const ev of events) for (const d of ev.deltas) touched.add(summaryKey(d.readId, d.group));
877
879
  const subtotals = [];
@@ -1213,7 +1215,7 @@ async function admitIntentOffers(eng, ws, ledger, offers, { receiptFence = null,
1213
1215
  admittedTotal += 1;
1214
1216
  if (Array.isArray(res.born) && res.born.length) born.push(...res.born);
1215
1217
  if (Array.isArray(res.birthOutcomes) && res.birthOutcomes.length) birthOutcomes.push(...res.birthOutcomes);
1216
- if (cap2) finishSummaryCapture(eng, ws, summaryCtx, cap2, res.head, intentId);
1218
+ if (cap2) finishSummaryCapture(eng, ws, summaryCtx, cap2, res.head ?? "", intentId);
1217
1219
  } else {
1218
1220
  const error = `${String(res.error || "").slice(0, 300)} \u2014 dead-lettered; fix the law (or the payload), then POST /v1/workspaces/${ws}/dead-letters/retry`;
1219
1221
  rec.rejected.push({ oid, error, deadLettered: true });
@@ -1247,7 +1249,7 @@ async function admitIntentOffers(eng, ws, ledger, offers, { receiptFence = null,
1247
1249
  let resultPackB64 = null;
1248
1250
  if (admittedTotal && head && /^[0-9a-f]{40}$/i.test(clientBase || "") && clientBase !== head) {
1249
1251
  try {
1250
- const p = servePack(eng, ws, clientBase);
1252
+ const p = servePack(eng, ws, clientBase ?? "");
1251
1253
  if (p && p.packB64 && p.bytes && p.bytes <= RESULT_PACK_INLINE_MAX) resultPackB64 = p.packB64;
1252
1254
  } catch {
1253
1255
  }
@@ -1270,7 +1272,7 @@ async function authorOn(eng, ws, ledger, domain, directiveId, payload, lawHash,
1270
1272
  try {
1271
1273
  res = author(eng, ws, domain, directiveId, payload, lawHash, opts);
1272
1274
  } catch (e) {
1273
- return { ok: false, error: String(e && e.message || e).slice(0, 500) };
1275
+ return { ok: false, error: String(e?.message || e).slice(0, 500) };
1274
1276
  }
1275
1277
  if (res && res.ok === false) return { ok: false, error: String(res.error || "the law refused this intent").slice(0, 500) };
1276
1278
  await commitAndPush(eng, ws, ledger);
@@ -1322,7 +1324,7 @@ async function deepVerifyShard(eng, shardWs, shardLedger, coordinatorRows) {
1322
1324
  }
1323
1325
  function stageWorkspaceDir(eng, ws) {
1324
1326
  const wsContents = /* @__PURE__ */ new Map();
1325
- eng.preopen.dir.contents.get("ws").contents.set(ws, new Directory(wsContents));
1327
+ dirOf(eng.preopen.dir.contents.get("ws")).contents.set(ws, new Directory(wsContents));
1326
1328
  }
1327
1329
  async function mountWorkspace(eng, ws, ledger) {
1328
1330
  if (eng.mounted.has(ws)) return eng.mounted.get(ws);
@@ -1337,7 +1339,7 @@ async function mountWorkspace(eng, ws, ledger) {
1337
1339
  restored = true;
1338
1340
  }
1339
1341
  } catch (e) {
1340
- restoreError = String(e && e.stack || e).split("\n").slice(0, 5).join(" | ");
1342
+ restoreError = String(e?.stack || e).split("\n").slice(0, 5).join(" | ");
1341
1343
  }
1342
1344
  const m = { restored, remoteMain, restoreError };
1343
1345
  eng.mounted.set(ws, m);
@@ -1379,7 +1381,7 @@ async function queryEphemeral(eng, ws, mountOpts, queryId, paramsJson, principal
1379
1381
  function unmount(eng, ws) {
1380
1382
  eng.mounted.delete(ws);
1381
1383
  eng.mainIntents.delete(ws);
1382
- const wsRoot = eng.preopen.dir.contents.get("ws");
1384
+ const wsRoot = dirOf(eng.preopen.dir.contents.get("ws"));
1383
1385
  if (wsRoot) wsRoot.contents.delete(ws);
1384
1386
  }
1385
1387
  function writeWork(eng, name, bytes) {
@@ -1540,7 +1542,7 @@ async function readCheckpointBlob(eng, ws, commitOid) {
1540
1542
  let codec = "gzip";
1541
1543
  let stateRoot = null;
1542
1544
  try {
1543
- const m = JSON.parse(dec3.decode(kgit.readBlob(eng, gitdir, commitOid, "meta")));
1545
+ const m = JSON.parse(dec3.decode(kgit.readBlob(eng, gitdir, commitOid, "meta") ?? new Uint8Array()));
1544
1546
  codec = m.codec ?? "gzip";
1545
1547
  stateRoot = m.stateRoot ?? null;
1546
1548
  } catch {
@@ -1571,7 +1573,7 @@ async function lawParity(eng, ws, lawHash) {
1571
1573
  }
1572
1574
  async function pushCheckpoint(eng, ws, ledger, lawHash) {
1573
1575
  try {
1574
- lawHash = await lawParity(eng, ws, lawHash);
1576
+ lawHash = await lawParity(eng, ws, lawHash) ?? "";
1575
1577
  if (!lawHash) return { pushed: false, reason: "no-law" };
1576
1578
  const gitdir = gitdirOf(ws);
1577
1579
  const head = kgit.resolveRef(eng, gitdir, "refs/heads/main");
@@ -1588,12 +1590,12 @@ async function pushCheckpoint(eng, ws, ledger, lawHash) {
1588
1590
  eng._ckptPushed.set(ws, tag);
1589
1591
  return { pushed: true, cursor: ex.cursor, bytes: ex.bytes ?? 0 };
1590
1592
  } catch (e) {
1591
- return { pushed: false, reason: String(e && e.message || e).slice(0, 160) };
1593
+ return { pushed: false, reason: String(e?.message || e).slice(0, 160) };
1592
1594
  }
1593
1595
  }
1594
1596
  async function stageCheckpoint(eng, ws, lawHash) {
1595
1597
  try {
1596
- lawHash = await lawParity(eng, ws, lawHash);
1598
+ lawHash = await lawParity(eng, ws, lawHash) ?? "";
1597
1599
  if (!lawHash) return null;
1598
1600
  eng._ckptPushed ??= /* @__PURE__ */ new Map();
1599
1601
  const ex = exportCheckpoint(eng, ws);
@@ -1631,7 +1633,7 @@ async function restoreCheckpointFromCustody(eng, ws, ledger, lawHash) {
1631
1633
  if (mounted?.checkpoint?.restored) {
1632
1634
  return { restored: false, reason: "already-mounted-checkpoint" };
1633
1635
  }
1634
- lawHash = await lawParity(eng, ws, lawHash);
1636
+ lawHash = await lawParity(eng, ws, lawHash) ?? "";
1635
1637
  if (!lawHash) return { restored: false, reason: "no-law" };
1636
1638
  const ref = CKPT_REF(lawHash);
1637
1639
  const serverRefs = await custodyLsRefs(ledger, ref);
@@ -1646,7 +1648,7 @@ async function restoreCheckpointFromCustody(eng, ws, ledger, lawHash) {
1646
1648
  }
1647
1649
  return { restored: r && r.restored === true, frontierSeeded: r && r.frontierSeeded === true, cursor: r && r.cursor, reason: r && r.reason };
1648
1650
  } catch (e) {
1649
- return { restored: false, reason: String(e && e.message || e).slice(0, 160) };
1651
+ return { restored: false, reason: String(e?.message || e).slice(0, 160) };
1650
1652
  }
1651
1653
  }
1652
1654
  async function custodySkeleton(eng, gitdir) {
@@ -1655,7 +1657,7 @@ async function custodySkeleton(eng, gitdir) {
1655
1657
  try {
1656
1658
  await p.mkdir(`${gitdir}${d}`);
1657
1659
  } catch (e) {
1658
- if (e && e.code !== "EEXIST") throw e;
1660
+ if (e?.code !== "EEXIST") throw e;
1659
1661
  }
1660
1662
  }
1661
1663
  try {
@@ -1673,11 +1675,14 @@ async function custodyFetch(eng, ws, ledger, { remoteRef = "refs/heads/main", lo
1673
1675
  const refs = await custodyLsRefs(ledger, remoteRefFull);
1674
1676
  const tip = refs[remoteRefFull] || null;
1675
1677
  if (!tip) return null;
1676
- if (tip !== have) applyPackInto(eng, ws, await fetchPack(ledger.remote, ledger.headers || {}, { wants: [tip], haves: have ? [have] : [] }));
1678
+ if (tip !== have) {
1679
+ const pk = await fetchPack(ledger.remote, ledger.headers || {}, { wants: [tip], haves: have ? [have] : [] });
1680
+ if (pk) applyPackInto(eng, ws, pk);
1681
+ }
1677
1682
  kgit.writeRef(eng, gitdirOf(ws), fullRef(localRef || remoteRef), tip);
1678
1683
  return tip;
1679
1684
  }
1680
- async function custodyPush(eng, ws, ledger, { localRef = null, remoteRef, del = false, pointer = false, newOid = null } = {}) {
1685
+ async function custodyPush(eng, ws, ledger, { localRef = null, remoteRef, del = false, pointer = false, newOid = null }) {
1681
1686
  const headers = ledger.headers || {};
1682
1687
  const remoteRefFull = fullRef(remoteRef);
1683
1688
  const remote = await lsRefs(ledger.remote, headers, { service: "git-receive-pack", prefix: remoteRefFull });
@@ -1849,18 +1854,18 @@ async function ingestPackAsCustody(eng, ws, packBytes, head) {
1849
1854
  eng.mounted.set(ws, { restored: true, remoteMain: head, restoreError: null });
1850
1855
  return { ok: true, head: kgit.resolveRef(eng, gitdir, "refs/heads/main") };
1851
1856
  }
1852
- function offerIntent(eng, ws, bytes, opts) {
1857
+ function offerIntent(eng, ws, bytes, opts = {}) {
1853
1858
  const name = `offer-in-${eng.seq++}.json`;
1854
1859
  writeWork(eng, name, bytes);
1855
1860
  const deferProjection = !!(opts && opts.defer);
1856
1861
  const branch = opts && opts.branch || BRANCH;
1857
1862
  return JSON.parse(call(eng.ex, "offer", { repoArg: repoArgOf(ws), workspace: ws, intentFile: `/work/${name}`, branch, deferProjection }, eng.STDERR));
1858
1863
  }
1859
- function offerAdmit(eng, ws, bytes, opts) {
1864
+ function offerAdmit(eng, ws, bytes, opts = {}) {
1860
1865
  const v = offerIntent(eng, ws, bytes, opts);
1861
1866
  return v.outcome === "admitted" ? { ok: true, head: v.head, ...v.born ? { born: v.born } : {} } : { ok: false, error: v.verdict?.reason ?? v.error ?? "the offer was refused" };
1862
1867
  }
1863
- function applyIntentBytes(eng, ws, bytes, opts) {
1868
+ function applyIntentBytes(eng, ws, bytes, opts = {}) {
1864
1869
  return offerAdmit(eng, ws, bytes, opts);
1865
1870
  }
1866
1871
  async function mainIntentIds(eng, ws) {
@@ -1936,7 +1941,7 @@ async function admitAll(eng, ws, ledger, { receiptFence = null, shardRouting = n
1936
1941
  try {
1937
1942
  await custodyFetch(eng, ws, ledger, { remoteRef: ref, have: localMain });
1938
1943
  } catch (thinErr) {
1939
- log("thin-fetch-fallback", { ws, cid, error: String(thinErr && thinErr.message || thinErr).slice(0, 160) });
1944
+ log("thin-fetch-fallback", { ws, cid, error: String(thinErr?.message || thinErr).slice(0, 160) });
1940
1945
  await custodyFetch(eng, ws, ledger, { remoteRef: ref, have: null });
1941
1946
  }
1942
1947
  } finally {
@@ -1945,7 +1950,7 @@ async function admitAll(eng, ws, ledger, { receiptFence = null, shardRouting = n
1945
1950
  }
1946
1951
  const _walkDone = _span(`walk ${shortCid}`, "cwalk", 2, { client: cid });
1947
1952
  const main2 = await mainIntentIds(eng, ws);
1948
- const recent = kgit.intentsAbove(eng, gitdir, head, "", 100);
1953
+ const recent = kgit.intentsAbove(eng, gitdir, head ?? "", "", 100);
1949
1954
  const chain = [];
1950
1955
  for (let i = recent.length - 1; i >= 0; i--) {
1951
1956
  if (main2.oids.has(recent[i].oid)) break;
@@ -2034,7 +2039,7 @@ async function admitAll(eng, ws, ledger, { receiptFence = null, shardRouting = n
2034
2039
  main2.oids.add(res.head);
2035
2040
  main2.head = res.head;
2036
2041
  admitted.push({ oid: oid.slice(0, 10), head: res.head });
2037
- if (cap2) finishSummaryCapture(eng, ws, summaryCtx, cap2, res.head, intentId);
2042
+ if (cap2) finishSummaryCapture(eng, ws, summaryCtx, cap2, res.head ?? "", intentId);
2038
2043
  if (shardRouting && dirId) {
2039
2044
  const placement = placementDirectives(eng).get(dirId);
2040
2045
  if (placement) {
@@ -2043,7 +2048,7 @@ async function admitAll(eng, ws, ledger, { receiptFence = null, shardRouting = n
2043
2048
  p = JSON.parse(dec3.decode(blob)).payload?.payload ?? null;
2044
2049
  } catch {
2045
2050
  }
2046
- const homeKey = p ? p[placement.keyField] : void 0;
2051
+ const homeKey = p ? p[String(placement.keyField)] : void 0;
2047
2052
  if (typeof homeKey === "string" && typeof p?.shard === "string") {
2048
2053
  placements.push({ directive: dirId, homeKey, shard: p.shard, mapVersion: 1 });
2049
2054
  }
@@ -2171,7 +2176,7 @@ async function backupHead(eng, ws, ledger, head) {
2171
2176
  await custodyPush(eng, ws, ledger, { remoteRef: "refs/heads/main", newOid: head });
2172
2177
  return { ok: true, head };
2173
2178
  } catch (e) {
2174
- return { ok: false, error: String(e && e.message || e).slice(0, 200), head };
2179
+ return { ok: false, error: String(e?.message || e).slice(0, 200), head };
2175
2180
  }
2176
2181
  }
2177
2182
  async function backupToCustody(eng, ws, ledger, { consumed = [] } = {}) {
@@ -2227,7 +2232,7 @@ async function rebirthCompact(eng, ws, ledger, { reason = "", supersededAt = 0,
2227
2232
  return false;
2228
2233
  }
2229
2234
  };
2230
- const transformState = (sealedBytes) => sealedBytes;
2235
+ const transformState = (sealedBytes, _ctx) => sealedBytes;
2231
2236
  const carried = [];
2232
2237
  const parkedIntents = [];
2233
2238
  const parkedBlobs = [];
@@ -2322,7 +2327,7 @@ async function rebirthCompact(eng, ws, ledger, { reason = "", supersededAt = 0,
2322
2327
  unmount(eng, incWs);
2323
2328
  } catch {
2324
2329
  }
2325
- return { ok: false, error: String(e && e.message || e).slice(0, 300) };
2330
+ return { ok: false, error: String(e?.message || e).slice(0, 300) };
2326
2331
  }
2327
2332
  }
2328
2333
  async function archiveRefusedMain(eng, ws, ledger, label) {
@@ -2349,7 +2354,7 @@ async function writeRefusedRef(eng, ws, dl) {
2349
2354
  try {
2350
2355
  const prevOid = kgit.resolveRef(eng, gitdir, refForStamp);
2351
2356
  if (prevOid) {
2352
- const prev = JSON.parse(dec3.decode(kgit.readBlob(eng, gitdir, prevOid, "verdict.json")));
2357
+ const prev = JSON.parse(dec3.decode(kgit.readBlob(eng, gitdir, prevOid, "verdict.json") ?? new Uint8Array()));
2353
2358
  if (prev && typeof prev.parkedAt === "string") parkedAt = prev.parkedAt;
2354
2359
  }
2355
2360
  } catch {
@@ -2379,8 +2384,8 @@ async function listRefusedRefs(eng, ws) {
2379
2384
  const out13 = [];
2380
2385
  for (const { ref, oid } of refs) {
2381
2386
  try {
2382
- const vb = kgit.readBlob(eng, gitdir, oid, "verdict.json");
2383
- const ib = kgit.readBlob(eng, gitdir, oid, "intent.json");
2387
+ const vb = kgit.readBlob(eng, gitdir, oid, "verdict.json") ?? new Uint8Array();
2388
+ const ib = kgit.readBlob(eng, gitdir, oid, "intent.json") ?? new Uint8Array();
2384
2389
  const v = JSON.parse(dec3.decode(vb));
2385
2390
  out13.push({ ref, ...v, intentB64: b64Bytes(ib) });
2386
2391
  } catch {
@@ -2394,7 +2399,7 @@ async function refusedSummary(eng, ws) {
2394
2399
  let count2 = 0, latestParkedAt = null;
2395
2400
  for (const { oid } of refs) {
2396
2401
  try {
2397
- const v = JSON.parse(dec3.decode(kgit.readBlob(eng, gitdir, oid, "verdict.json")));
2402
+ const v = JSON.parse(dec3.decode(kgit.readBlob(eng, gitdir, oid, "verdict.json") ?? new Uint8Array()));
2398
2403
  count2++;
2399
2404
  if (v && typeof v.parkedAt === "string" && (!latestParkedAt || v.parkedAt > latestParkedAt)) latestParkedAt = v.parkedAt;
2400
2405
  } catch {
@@ -2532,7 +2537,7 @@ async function deploy(eng, ws, ledger, usda, domainHash, dispositions, opts = {}
2532
2537
  return { head: result.head, installation };
2533
2538
  }
2534
2539
  function snapshot(eng, ws) {
2535
- const wsDir = eng.preopen.dir.contents.get("ws").contents.get(ws);
2540
+ const wsDir = dirOf(eng.preopen.dir.contents.get("ws")).contents.get(ws);
2536
2541
  return serializeTree(wsDir);
2537
2542
  }
2538
2543
  function stats(eng) {
@@ -2562,7 +2567,7 @@ async function ledgerStats(eng, ws, ledger = null) {
2562
2567
  }
2563
2568
  if (!head) return { head: null, commits: 0 };
2564
2569
  const mounted = eng.mounted.get(ws);
2565
- if (mounted?.ledgerStats?.head === head) return mounted.ledgerStats;
2570
+ if (mounted && mounted.ledgerStats?.head === head) return mounted.ledgerStats;
2566
2571
  const commits = kgit.intentsAbove(eng, gitdir, head).length;
2567
2572
  const out13 = { head, commits };
2568
2573
  if (mounted) mounted.ledgerStats = out13;
@@ -2580,7 +2585,7 @@ async function countRemoteCommits(eng, ledger) {
2580
2585
  return { head, commits };
2581
2586
  } finally {
2582
2587
  try {
2583
- eng.preopen.dir.contents.get("ws").contents.delete(scratch);
2588
+ dirOf(eng.preopen.dir.contents.get("ws")).contents.delete(scratch);
2584
2589
  } catch {
2585
2590
  }
2586
2591
  }
@@ -2629,9 +2634,9 @@ function sealAttestationBatches(eng, ws, domain, controllerHash, opts = {}) {
2629
2634
  }
2630
2635
  return outcomes;
2631
2636
  }
2632
- var enc3, dec3, BRANCH, RESULT_PACK_INLINE_MAX, repoArgOf, gitdirOf, unpack, log, repoArgOfGitdir, bytesFromB64, kgit, installPayload, routeTagHexOfHomeKey, SUMMARY_SEP, summaryKey, splitSummaryKey, NOMOS_SHARD_ROWS_READ, groupOf, tallyOf, isExtremumRead, extremumMonotone, CKPT_REF, pushVia, fullRef, applyPackInto, custodyLsRefs, qById, query, check, expand, cryptoSealField, cryptoKeygen, authorKeygen, eraCertSign, delegationCertSign, attestationSign, attestedRead, certSign, cryptoWrapKey, cryptoUnwrapKey, readPosture, count, sum, pendingConflicts, spatialBboxParams, spatialWithin, extremum, nomosActive, refusedRefName, outboxRefName, projectionStats;
2637
+ var enc3, dec3, BRANCH, RESULT_PACK_INLINE_MAX, dirOf, repoArgOf, gitdirOf, unpack, log, repoArgOfGitdir, bytesFromB64, kgit, installPayload, routeTagHexOfHomeKey, SUMMARY_SEP, summaryKey, splitSummaryKey, NOMOS_SHARD_ROWS_READ, groupOf, tallyOf, isExtremumRead, extremumMonotone, CKPT_REF, pushVia, fullRef, applyPackInto, custodyLsRefs, qById, query, check, expand, cryptoSealField, cryptoKeygen, authorKeygen, eraCertSign, delegationCertSign, attestationSign, attestedRead, certSign, cryptoWrapKey, cryptoUnwrapKey, readPosture, count, sum, pendingConflicts, spatialBboxParams, spatialWithin, extremum, nomosActive, refusedRefName, outboxRefName, projectionStats;
2633
2638
  var init_engine = __esm({
2634
- "vendor/engine/engine.mjs"() {
2639
+ "vendor/engine/engine.ts"() {
2635
2640
  "use strict";
2636
2641
  init_git_fs();
2637
2642
  init_tree();
@@ -2640,6 +2645,7 @@ var init_engine = __esm({
2640
2645
  dec3 = new TextDecoder();
2641
2646
  BRANCH = "main";
2642
2647
  RESULT_PACK_INLINE_MAX = 256 * 1024;
2648
+ dirOf = (n) => n;
2643
2649
  repoArgOf = (ws) => `/work/ws/${ws}`;
2644
2650
  gitdirOf = (ws) => `/work/ws/${ws}/nomos.git`;
2645
2651
  unpack = (p) => {
@@ -2724,7 +2730,7 @@ var init_engine = __esm({
2724
2730
  certSign = (eng, { child, founder, verified, parentKey, parentId, epoch, secret }) => JSON.parse(call(eng.ex, "query", { queryBytes: b64Json({ op: "certSign", child, founder, verified, parentKey, parentId, epoch, secret }) }, eng.STDERR)).cert;
2725
2731
  cryptoWrapKey = (eng, { recipientPub, scopeKey }) => JSON.parse(call(eng.ex, "query", { queryBytes: b64Json({ op: "cryptoWrapKey", recipientPub, scopeKey }) }, eng.STDERR));
2726
2732
  cryptoUnwrapKey = (eng, { secret, hpkeEpk, ct }) => JSON.parse(call(eng.ex, "query", { queryBytes: b64Json({ op: "cryptoUnwrapKey", secret, hpkeEpk, ct }) }, eng.STDERR)).scopeKey;
2727
- readPosture = (eng, ws, principal = "") => JSON.parse(call(eng.ex, "query", { repoArg: repoArgOf(ws), workspace: ws, queryBytes: b64Json({ op: "readPosture" }), principal, branch: BRANCH }, eng.STDERR));
2733
+ readPosture = (eng, ws, principal = "", authToken = "", nowUnix = 0) => JSON.parse(call(eng.ex, "query", { repoArg: repoArgOf(ws), workspace: ws, queryBytes: b64Json({ op: "readPosture", authToken, nowUnix }), principal, branch: BRANCH }, eng.STDERR));
2728
2734
  count = (eng, ws, countId, groupKey, principal = "") => JSON.parse(call(eng.ex, "query", { repoArg: repoArgOf(ws), workspace: ws, queryBytes: b64Json({ op: "count", countId, groupKey }), principal, branch: BRANCH }, eng.STDERR));
2729
2735
  sum = (eng, ws, sumId, groupKey, principal = "") => JSON.parse(call(eng.ex, "query", { repoArg: repoArgOf(ws), workspace: ws, queryBytes: b64Json({ op: "sum", sumId, groupKey }), principal, branch: BRANCH }, eng.STDERR));
2730
2736
  pendingConflicts = (eng, ws, principal = "") => JSON.parse(call(eng.ex, "query", { repoArg: repoArgOf(ws), workspace: ws, queryBytes: b64Json({ op: "pendingConflicts" }), principal, branch: BRANCH }, eng.STDERR));
@@ -4480,6 +4486,108 @@ var init_governance = __esm({
4480
4486
  }
4481
4487
  });
4482
4488
 
4489
+ // src/capabilities.ts
4490
+ var capabilities_exports = {};
4491
+ __export(capabilities_exports, {
4492
+ INLINE_OFFER_CAP_CHARS: () => INLINE_OFFER_CAP_CHARS,
4493
+ negotiateDeployRoute: () => negotiateDeployRoute,
4494
+ openapiRoutesDirective: () => openapiRoutesDirective,
4495
+ probeCloudCapabilities: () => probeCloudCapabilities,
4496
+ probeKernelCapabilities: () => probeKernelCapabilities,
4497
+ probeOfferLane: () => probeOfferLane,
4498
+ probeStageLane: () => probeStageLane
4499
+ });
4500
+ async function probeStageLane(cloud, fetchImpl = fetch) {
4501
+ try {
4502
+ const r = await fetchImpl(`${cloud}/v2/stage/${ZERO_SHA}`, { method: "GET" });
4503
+ const body = await r.json().catch(() => void 0);
4504
+ return typeof body?.staged === "boolean";
4505
+ } catch {
4506
+ return void 0;
4507
+ }
4508
+ }
4509
+ async function probeKernelCapabilities(cloud, fetchImpl = fetch) {
4510
+ try {
4511
+ const r = await fetchImpl(`${cloud.replace(/\/+$/, "")}/v1/runtime/capabilities`, { method: "GET" });
4512
+ if (!r.ok) return void 0;
4513
+ const body = await r.json().catch(() => void 0);
4514
+ return body && typeof body === "object" ? body : void 0;
4515
+ } catch {
4516
+ return void 0;
4517
+ }
4518
+ }
4519
+ function openapiRoutesDirective(spec, domain, directiveId) {
4520
+ const paths = spec?.paths ?? {};
4521
+ const wantPath = `/${domain}/${directiveId}`;
4522
+ const wantBare = `/${directiveId}`;
4523
+ const wantOp = `${domain}__${directiveId}`;
4524
+ for (const [p, ops] of Object.entries(paths)) {
4525
+ if (p === wantPath || p === wantBare) return true;
4526
+ for (const method of Object.values(ops ?? {})) {
4527
+ if (method?.operationId === wantOp) return true;
4528
+ }
4529
+ }
4530
+ return false;
4531
+ }
4532
+ async function probeOfferLane(cloud, ws, route, fetchImpl = fetch) {
4533
+ try {
4534
+ const r = await fetchImpl(`${cloud}/v2/workspaces/${ws}/openapi.json`, { method: "GET" });
4535
+ if (!r.ok) return { served: false, routesTarget: void 0 };
4536
+ const spec = await r.json().catch(() => void 0);
4537
+ if (spec === void 0 || typeof spec !== "object") return { served: false, routesTarget: void 0 };
4538
+ const served = true;
4539
+ const routesTarget = route === void 0 ? void 0 : openapiRoutesDirective(spec, route.domain, route.directiveId);
4540
+ return { served, routesTarget };
4541
+ } catch {
4542
+ return { served: void 0, routesTarget: void 0 };
4543
+ }
4544
+ }
4545
+ async function probeCloudCapabilities(cloud, ws, route, fetchImpl = fetch) {
4546
+ const [stage, offer] = await Promise.all([
4547
+ probeStageLane(cloud, fetchImpl),
4548
+ probeOfferLane(cloud, ws, route, fetchImpl)
4549
+ ]);
4550
+ return {
4551
+ cloud,
4552
+ stage,
4553
+ offerLane: offer.served,
4554
+ routesTarget: offer.routesTarget,
4555
+ openDeploy: void 0
4556
+ // the open /domains lane is universal in every worker/dev-server; not separately probed
4557
+ };
4558
+ }
4559
+ function negotiateDeployRoute(caps, opts) {
4560
+ if (opts.signed) {
4561
+ if (caps.offerLane === false) {
4562
+ return {
4563
+ fail: `${caps.cloud} does not serve the SIGNED OFFER lane \u2014 POST /v2/workspaces/${opts.ws}/${opts.route.domain}/${opts.route.directiveId} is not routed (the workspace serves no self-describing OpenAPI, so this cloud has no gateway to route a signed offer). This is often a lightweight cloud (e.g. \`githolon cloud dev\`) without the offer gateway.
4564
+ \u2192 deploy the OPEN (unsigned) lane instead (drop --as/--principal) if this workspace is unwarranted, or target a cloud that serves the offer gateway.`
4565
+ };
4566
+ }
4567
+ if (caps.offerLane === true && caps.routesTarget === false) {
4568
+ return {
4569
+ fail: `${caps.cloud} serves the offer gateway for ${opts.ws}, but its OpenAPI does not name the route ${opts.route.domain}/${opts.route.directiveId} \u2014 the ${opts.route.domain} controller is not installed here, so a signed ${opts.route.directiveId} would 404.
4570
+ \u2192 confirm the workspace is born and the controller is deployed, or deploy the OPEN lane (drop --as).`
4571
+ };
4572
+ }
4573
+ if (opts.sealedSizeChars > INLINE_OFFER_CAP_CHARS && caps.stage === false) {
4574
+ return {
4575
+ fail: `this signed package is ~${Math.round(opts.sealedSizeChars / (1024 * 1024))} MiB sealed \u2014 over the ${INLINE_OFFER_CAP_CHARS / (1024 * 1024)} MiB inline offer cap \u2014 and ${caps.cloud} has no /v2/stage content-addressed lane to carry it.
4576
+ \u2192 target a cloud that serves /v2/stage, or shrink the package (githolon compile --compact).`
4577
+ };
4578
+ }
4579
+ }
4580
+ return void 0;
4581
+ }
4582
+ var INLINE_OFFER_CAP_CHARS, ZERO_SHA;
4583
+ var init_capabilities = __esm({
4584
+ "src/capabilities.ts"() {
4585
+ "use strict";
4586
+ INLINE_OFFER_CAP_CHARS = 8 * 1024 * 1024;
4587
+ ZERO_SHA = "0".repeat(64);
4588
+ }
4589
+ });
4590
+
4483
4591
  // src/lifecycle.ts
4484
4592
  var lifecycle_exports = {};
4485
4593
  __export(lifecycle_exports, {
@@ -4791,97 +4899,6 @@ var init_lifecycle = __esm({
4791
4899
  }
4792
4900
  });
4793
4901
 
4794
- // src/capabilities.ts
4795
- var capabilities_exports = {};
4796
- __export(capabilities_exports, {
4797
- INLINE_OFFER_CAP_CHARS: () => INLINE_OFFER_CAP_CHARS,
4798
- negotiateDeployRoute: () => negotiateDeployRoute,
4799
- openapiRoutesDirective: () => openapiRoutesDirective,
4800
- probeCloudCapabilities: () => probeCloudCapabilities,
4801
- probeOfferLane: () => probeOfferLane,
4802
- probeStageLane: () => probeStageLane
4803
- });
4804
- async function probeStageLane(cloud, fetchImpl = fetch) {
4805
- try {
4806
- const r = await fetchImpl(`${cloud}/v2/stage/${ZERO_SHA}`, { method: "GET" });
4807
- const body = await r.json().catch(() => void 0);
4808
- return typeof body?.staged === "boolean";
4809
- } catch {
4810
- return void 0;
4811
- }
4812
- }
4813
- function openapiRoutesDirective(spec, domain, directiveId) {
4814
- const paths = spec?.paths ?? {};
4815
- const wantPath = `/${domain}/${directiveId}`;
4816
- const wantBare = `/${directiveId}`;
4817
- const wantOp = `${domain}__${directiveId}`;
4818
- for (const [p, ops] of Object.entries(paths)) {
4819
- if (p === wantPath || p === wantBare) return true;
4820
- for (const method of Object.values(ops ?? {})) {
4821
- if (method?.operationId === wantOp) return true;
4822
- }
4823
- }
4824
- return false;
4825
- }
4826
- async function probeOfferLane(cloud, ws, route, fetchImpl = fetch) {
4827
- try {
4828
- const r = await fetchImpl(`${cloud}/v2/workspaces/${ws}/openapi.json`, { method: "GET" });
4829
- if (!r.ok) return { served: false, routesTarget: void 0 };
4830
- const spec = await r.json().catch(() => void 0);
4831
- if (spec === void 0 || typeof spec !== "object") return { served: false, routesTarget: void 0 };
4832
- const served = true;
4833
- const routesTarget = route === void 0 ? void 0 : openapiRoutesDirective(spec, route.domain, route.directiveId);
4834
- return { served, routesTarget };
4835
- } catch {
4836
- return { served: void 0, routesTarget: void 0 };
4837
- }
4838
- }
4839
- async function probeCloudCapabilities(cloud, ws, route, fetchImpl = fetch) {
4840
- const [stage, offer] = await Promise.all([
4841
- probeStageLane(cloud, fetchImpl),
4842
- probeOfferLane(cloud, ws, route, fetchImpl)
4843
- ]);
4844
- return {
4845
- cloud,
4846
- stage,
4847
- offerLane: offer.served,
4848
- routesTarget: offer.routesTarget,
4849
- openDeploy: void 0
4850
- // the open /domains lane is universal in every worker/dev-server; not separately probed
4851
- };
4852
- }
4853
- function negotiateDeployRoute(caps, opts) {
4854
- if (opts.signed) {
4855
- if (caps.offerLane === false) {
4856
- return {
4857
- fail: `${caps.cloud} does not serve the SIGNED OFFER lane \u2014 POST /v2/workspaces/${opts.ws}/${opts.route.domain}/${opts.route.directiveId} is not routed (the workspace serves no self-describing OpenAPI, so this cloud has no gateway to route a signed offer). This is often a lightweight cloud (e.g. \`githolon cloud dev\`) without the offer gateway.
4858
- \u2192 deploy the OPEN (unsigned) lane instead (drop --as/--principal) if this workspace is unwarranted, or target a cloud that serves the offer gateway.`
4859
- };
4860
- }
4861
- if (caps.offerLane === true && caps.routesTarget === false) {
4862
- return {
4863
- fail: `${caps.cloud} serves the offer gateway for ${opts.ws}, but its OpenAPI does not name the route ${opts.route.domain}/${opts.route.directiveId} \u2014 the ${opts.route.domain} controller is not installed here, so a signed ${opts.route.directiveId} would 404.
4864
- \u2192 confirm the workspace is born and the controller is deployed, or deploy the OPEN lane (drop --as).`
4865
- };
4866
- }
4867
- if (opts.sealedSizeChars > INLINE_OFFER_CAP_CHARS && caps.stage === false) {
4868
- return {
4869
- fail: `this signed package is ~${Math.round(opts.sealedSizeChars / (1024 * 1024))} MiB sealed \u2014 over the ${INLINE_OFFER_CAP_CHARS / (1024 * 1024)} MiB inline offer cap \u2014 and ${caps.cloud} has no /v2/stage content-addressed lane to carry it.
4870
- \u2192 target a cloud that serves /v2/stage, or shrink the package (githolon compile --compact).`
4871
- };
4872
- }
4873
- }
4874
- return void 0;
4875
- }
4876
- var INLINE_OFFER_CAP_CHARS, ZERO_SHA;
4877
- var init_capabilities = __esm({
4878
- "src/capabilities.ts"() {
4879
- "use strict";
4880
- INLINE_OFFER_CAP_CHARS = 8 * 1024 * 1024;
4881
- ZERO_SHA = "0".repeat(64);
4882
- }
4883
- });
4884
-
4885
4902
  // src/cloud.ts
4886
4903
  var cloud_exports = {};
4887
4904
  __export(cloud_exports, {
@@ -5273,6 +5290,29 @@ async function deploy2(ws, opts) {
5273
5290
  const beforeLaw = await fetch(`${cloud}/v2/workspaces/${ws}/domains`).then((br) => br.json()).then((bd) => bd.ok === true ? bd : {}).catch(() => ({}));
5274
5291
  const before = beforeLaw.domains ?? [];
5275
5292
  const currentLaw2 = beforeLaw.currentLaw ?? {};
5293
+ try {
5294
+ const compat = JSON.parse(readFileSync5(file, "utf8")).nomosCompat;
5295
+ const requires = compat?.requiresKernel ?? [];
5296
+ if (requires.length > 0) {
5297
+ const { probeKernelCapabilities: probeKernelCapabilities2 } = await Promise.resolve().then(() => (init_capabilities(), capabilities_exports));
5298
+ const report = await probeKernelCapabilities2(cloud);
5299
+ const kernel = report?.prod;
5300
+ if (kernel?.features) {
5301
+ const missing = requires.filter((f) => !kernel.features.includes(f));
5302
+ if (missing.length > 0) {
5303
+ const lawH = String(compat?.lawHash ?? "").slice(0, 8);
5304
+ const kernH = String(kernel.hash ?? "").slice(0, 8);
5305
+ err4(
5306
+ `deploy '${ws}' REFUSED \u2014 release coherence: kernel ${kernH} lacks capability '${missing.join("', '")}' that law ${lawH} requires (the cloud runs a STALE kernel: ${kernel.note ?? kernel.version}).` + (missing.includes("compoundKeys") ? `
5307
+ A compound-key query (\`.key(a, b, \u2026)\`) would be refused deep in a law fold ("query declares N index keys; the read router supports exactly one").` : "") + `
5308
+ Point at a cloud whose kernel is coherent with this release, or upgrade the cloud's kernel.`
5309
+ );
5310
+ return 1;
5311
+ }
5312
+ }
5313
+ }
5314
+ } catch {
5315
+ }
5276
5316
  const { readDeployBody: readDeployBody3, domainKeysOf: domainKeysOf2, packageHashOf: packageHashOf2, resolveDeployPlan: resolveDeployPlan2, describeDeployPlan: describeDeployPlan2 } = await Promise.resolve().then(() => (init_lifecycle(), lifecycle_exports));
5277
5317
  let plan;
5278
5318
  let targetHash;
@@ -5339,9 +5379,10 @@ async function deploy2(ws, opts) {
5339
5379
  }
5340
5380
  deployedHash = targetHash2;
5341
5381
  } else {
5382
+ const presented = opts.principal ?? await sessionToken().catch(() => void 0) ?? activePrincipal();
5342
5383
  const r = await fetch(`${cloud}/v2/workspaces/${ws}/domains`, {
5343
5384
  method: "POST",
5344
- headers: { "content-type": "application/json" },
5385
+ headers: { "content-type": "application/json", ...presented !== void 0 ? principalHeaders(presented) : {} },
5345
5386
  body: readFileSync5(file, "utf8")
5346
5387
  });
5347
5388
  const d = await r.json().catch(() => void 0);
@@ -5645,9 +5686,9 @@ function parseOfflineLegs(proofSource) {
5645
5686
  }
5646
5687
  const domain = dom[1];
5647
5688
  const autoStamped = [];
5648
- const stampLine = proofSource.split("\n").find((l) => l.includes("omitted \u2014 the client auto-stamps ISO now()"));
5649
- if (stampLine !== void 0) {
5650
- for (const m of stampLine.matchAll(/`(\w+)`/g)) autoStamped.push(m[1]);
5689
+ const stampLine2 = proofSource.split("\n").find((l) => l.includes("omitted \u2014 the client auto-stamps ISO now()"));
5690
+ if (stampLine2 !== void 0) {
5691
+ for (const m of stampLine2.matchAll(/`(\w+)`/g)) autoStamped.push(m[1]);
5651
5692
  }
5652
5693
  let queryLeg;
5653
5694
  const q = proofSource.match(/local declared query (\w+):/);
@@ -6553,6 +6594,84 @@ var init_harness = __esm({
6553
6594
  }
6554
6595
  });
6555
6596
 
6597
+ // src/doctor.ts
6598
+ var doctor_exports = {};
6599
+ __export(doctor_exports, {
6600
+ doctor: () => doctor
6601
+ });
6602
+ import { existsSync as existsSync14, readFileSync as readFileSync15 } from "node:fs";
6603
+ function readLocalCompat(cwd, file) {
6604
+ try {
6605
+ const path = discoverDeployJson(cwd, file);
6606
+ if (!existsSync14(path)) return void 0;
6607
+ const body = JSON.parse(readFileSync15(path, "utf8"));
6608
+ return body.nomosCompat;
6609
+ } catch {
6610
+ return void 0;
6611
+ }
6612
+ }
6613
+ function stampLine(label, stamp) {
6614
+ if (!stamp) return ` ${label.padEnd(12)}: (not advertised)`;
6615
+ const h = String(stamp.hash || "").slice(0, 12);
6616
+ const caps = stamp.features?.length ? `[${stamp.features.join(", ")}]` : "[]";
6617
+ const known = stamp.known ? "" : " \u26A0 UNKNOWN to registry";
6618
+ return ` ${label.padEnd(12)}: ${h}\u2026 ${stamp.version ?? ""}${known}
6619
+ caps ${caps}`;
6620
+ }
6621
+ async function doctor(opts = {}) {
6622
+ const cloud = cloudBase(opts.cloud);
6623
+ const compat = readLocalCompat(process.cwd(), opts.file);
6624
+ const report = await probeKernelCapabilities(cloud);
6625
+ const out13 = [];
6626
+ out13.push(`githolon doctor \u2014 release coherence`);
6627
+ out13.push(` cloud : ${cloud}`);
6628
+ out13.push(` compiler : @githolon/dsl ${compat?.generator?.dsl ?? "(no local build \u2014 run `githolon compile`)"}`);
6629
+ out13.push(` runner : cloud expects bundle version ${report?.expectedBundleVersion ?? "(not advertised)"}`);
6630
+ out13.push(stampLine("prod kernel", report?.prod));
6631
+ out13.push(stampLine("test kernel", report?.testmint));
6632
+ const requires = compat?.requiresKernel ?? [];
6633
+ if (!compat) {
6634
+ out13.push(``);
6635
+ out13.push(` \u26A0 no local build found \u2014 cannot check the law\u2194kernel fit. Run \`githolon compile\` first.`);
6636
+ process.stdout.write(out13.join("\n") + "\n");
6637
+ return report ? 0 : 1;
6638
+ }
6639
+ if (!report?.prod) {
6640
+ out13.push(``);
6641
+ out13.push(` \u26A0 cloud advertises no kernel capabilities (older worker?) \u2014 coherence UNVERIFIABLE.`);
6642
+ out13.push(` law ${String(compat.lawHash).slice(0, 8)} requires: [${requires.join(", ") || "none"}]`);
6643
+ process.stdout.write(out13.join("\n") + "\n");
6644
+ return 0;
6645
+ }
6646
+ const feats = report.prod.features ?? [];
6647
+ const missing = requires.filter((f) => !feats.includes(f));
6648
+ out13.push(``);
6649
+ const lawH = String(compat.lawHash || "").slice(0, 8);
6650
+ const kernH = String(report.prod.hash || "").slice(0, 8);
6651
+ if (requires.length === 0) {
6652
+ out13.push(` \u2713 COHERENT \u2014 law ${lawH} requires no special kernel capabilities.`);
6653
+ } else if (missing.length === 0) {
6654
+ out13.push(` \u2713 COHERENT \u2014 kernel ${kernH} supports all capabilities law ${lawH} requires: [${requires.join(", ")}].`);
6655
+ } else {
6656
+ out13.push(` \u2717 SKEW \u2014 kernel ${kernH} lacks capability '${missing.join("', '")}' that law ${lawH} requires.`);
6657
+ out13.push(` The cloud is running a STALE kernel (${report.prod.note ?? report.prod.version ?? "unknown build"}).`);
6658
+ if (missing.includes("compoundKeys")) {
6659
+ out13.push(` A compound-key query (\`.key(a, b, \u2026)\`) will be refused deep in a law fold with`);
6660
+ out13.push(` "query declares N index keys; the read router supports exactly one".`);
6661
+ }
6662
+ out13.push(` Point at a cloud whose kernel is coherent with this release, or upgrade the cloud's kernel.`);
6663
+ }
6664
+ process.stdout.write(out13.join("\n") + "\n");
6665
+ return missing.length > 0 ? 1 : 0;
6666
+ }
6667
+ var init_doctor = __esm({
6668
+ "src/doctor.ts"() {
6669
+ "use strict";
6670
+ init_cloud();
6671
+ init_capabilities();
6672
+ }
6673
+ });
6674
+
6556
6675
  // src/scene_projector.ts
6557
6676
  import { createHash as createHash4 } from "node:crypto";
6558
6677
  function fnv1a32(s) {
@@ -7609,7 +7728,7 @@ var scene_exports = {};
7609
7728
  __export(scene_exports, {
7610
7729
  scene: () => scene
7611
7730
  });
7612
- import { existsSync as existsSync14, mkdirSync as mkdirSync6, writeFileSync as writeFileSync9 } from "node:fs";
7731
+ import { existsSync as existsSync15, mkdirSync as mkdirSync6, writeFileSync as writeFileSync9 } from "node:fs";
7613
7732
  import { join as join16, resolve as resolve4 } from "node:path";
7614
7733
  import { createHash as createHash5 } from "node:crypto";
7615
7734
  import git3 from "isomorphic-git";
@@ -7631,8 +7750,8 @@ async function projectOnce(cloud, target, isDir, name) {
7631
7750
  const { eng } = await holonEngine(cloud, void 0, "githolon-scene");
7632
7751
  const SOURCE3 = "source";
7633
7752
  if (isDir) {
7634
- const gitDir = existsSync14(join16(target, ".git")) ? join16(target, ".git") : target;
7635
- if (!existsSync14(join16(gitDir, "HEAD"))) throw new Error(`${target} is not a git repo (no HEAD)`);
7753
+ const gitDir = existsSync15(join16(target, ".git")) ? join16(target, ".git") : target;
7754
+ if (!existsSync15(join16(gitDir, "HEAD"))) throw new Error(`${target} is not a git repo (no HEAD)`);
7636
7755
  await mountFresh(eng, SOURCE3);
7637
7756
  eng.preopen.dir.contents.get("ws").contents.get(SOURCE3).contents.set("nomos.git", readTreeFromDisk(gitDir));
7638
7757
  } else {
@@ -7691,7 +7810,7 @@ async function projectOnce(cloud, target, isDir, name) {
7691
7810
  }
7692
7811
  async function scene(target, opts) {
7693
7812
  const cloud = cloudBase(opts.cloud);
7694
- const isDir = existsSync14(target) || target.includes("/") || target.startsWith(".");
7813
+ const isDir = existsSync15(target) || target.includes("/") || target.startsWith(".");
7695
7814
  const name = isDir ? (resolve4(target).split("/").filter(Boolean).pop() ?? "scene").replace(/\.git$/, "") : target;
7696
7815
  out11(`scene \u2014 ${name} (${isDir ? resolve4(target) : `${cloud} :: ${target}`})`);
7697
7816
  let first, second;
@@ -7802,7 +7921,7 @@ var init_dlq = __esm({
7802
7921
  });
7803
7922
 
7804
7923
  // src/cli.ts
7805
- import { existsSync as existsSync15, readdirSync as readdirSync6, readFileSync as readFileSync15 } from "node:fs";
7924
+ import { existsSync as existsSync16, readdirSync as readdirSync6, readFileSync as readFileSync16 } from "node:fs";
7806
7925
  import { spawnSync as spawnSync6 } from "node:child_process";
7807
7926
  import { createRequire as createRequire3 } from "node:module";
7808
7927
  import { dirname as dirname9, join as join17, resolve as resolve5 } from "node:path";
@@ -8436,23 +8555,21 @@ async function gitRemote(ws, name, opts) {
8436
8555
  }
8437
8556
  }
8438
8557
  const token = await sessionToken().catch(() => void 0);
8439
- if (token === void 0) {
8440
- const principal = loadCreds().principal;
8441
- if (principal === void 0) {
8442
- err6(
8443
- `remote '${name}' \u2192 ${url} is wired, but a BIRTH push needs a principal:
8558
+ const principal = currentPrincipal();
8559
+ if (principal === void 0) {
8560
+ err6(
8561
+ `remote '${name}' \u2192 ${url} is wired, but a BIRTH push needs a principal:
8444
8562
  githolon login --agent (then just push)
8445
8563
  \u2014 or re-run after githolon ws create/login so a principal is on file`
8446
- );
8447
- return 1;
8448
- }
8449
- if (git(["config", `http.${url}.extraHeader`, `x-nomos-principal: ${principal}`]) !== 0) {
8450
- err6("git config failed setting the principal header");
8451
- return 1;
8452
- }
8564
+ );
8565
+ return 1;
8566
+ }
8567
+ if (git(["config", `http.${url}.extraHeader`, `x-nomos-principal: ${principal}`]) !== 0) {
8568
+ err6("git config failed setting the principal header");
8569
+ return 1;
8453
8570
  }
8454
8571
  out6(`\u2713 remote '${name}' \u2192 ${url}`);
8455
- out6(` workspace secret on file; ${token !== void 0 ? "births ride your session (verified)" : "births ride x-nomos-principal (bare uid)"}`);
8572
+ out6(` workspace secret on file; ${token !== void 0 ? "births ride your session token (verified) + x-nomos-principal claim" : "births ride x-nomos-principal (bare uid)"}`);
8456
8573
  out6(` birth/deploy by push: git push ${name} main`);
8457
8574
  return 0;
8458
8575
  }
@@ -9436,10 +9553,10 @@ async function runProof(args) {
9436
9553
  let proofPath;
9437
9554
  if (explicit !== void 0) {
9438
9555
  proofPath = resolve5(process.cwd(), explicit);
9439
- if (!existsSync15(proofPath)) return refuse(`proof not found: ${proofPath} \u2014 run \`githolon compile\` to (re)generate it`);
9556
+ if (!existsSync16(proofPath)) return refuse(`proof not found: ${proofPath} \u2014 run \`githolon compile\` to (re)generate it`);
9440
9557
  } else {
9441
9558
  const buildDir = join17(process.cwd(), "build");
9442
- if (!existsSync15(buildDir)) {
9559
+ if (!existsSync16(buildDir)) {
9443
9560
  return refuse("no build/ directory here \u2014 run `githolon compile` first (every compile generates build/<name>.proof.mts from your law)");
9444
9561
  }
9445
9562
  const proofs = readdirSync6(buildDir).filter((f) => f.endsWith(".proof.mts"));
@@ -9482,7 +9599,7 @@ async function runProof(args) {
9482
9599
  if (tsxDir === void 0) {
9483
9600
  return refuse("tsx not found \u2014 add @githolon/dsl to your project's dependencies (tsx rides along) and npm install");
9484
9601
  }
9485
- const tsxPkg = JSON.parse(readFileSync15(join17(tsxDir, "package.json"), "utf8"));
9602
+ const tsxPkg = JSON.parse(readFileSync16(join17(tsxDir, "package.json"), "utf8"));
9486
9603
  const tsxBinRel = typeof tsxPkg.bin === "string" ? tsxPkg.bin : tsxPkg.bin?.["tsx"];
9487
9604
  const tsxCli = join17(tsxDir, tsxBinRel ?? "dist/cli.mjs");
9488
9605
  console.log("githolon proof --live \u2014 the full cloud loop (throwaway workspace, retired on exit" + (keep ? "; --keep: kept" : "") + ")");
@@ -9687,6 +9804,17 @@ ${commandHelp("dev")}`);
9687
9804
  ...once ? { once: true } : {}
9688
9805
  });
9689
9806
  }
9807
+ if (argv[0] === "doctor") {
9808
+ const rest = argv.slice(1);
9809
+ let cloudFlag;
9810
+ let fileFlag;
9811
+ for (let i = 0; i < rest.length; i++) {
9812
+ if (rest[i] === "--cloud") cloudFlag = rest[++i];
9813
+ else if (rest[i] === "--file") fileFlag = rest[++i];
9814
+ }
9815
+ const { doctor: doctor2 } = await Promise.resolve().then(() => (init_doctor(), doctor_exports));
9816
+ return doctor2({ ...cloudFlag !== void 0 ? { cloud: cloudFlag } : {}, ...fileFlag !== void 0 ? { file: fileFlag } : {} });
9817
+ }
9690
9818
  if (argv[0] === "cloud") {
9691
9819
  const sub2 = argv[1];
9692
9820
  if (sub2 !== "dev") {
@@ -9707,7 +9835,7 @@ usage: githolon cloud dev [--port <n>] [--data <dir>] [--ephemeral]
9707
9835
  resolve5(here, "../../../cloud/dev-server/server.mjs"),
9708
9836
  resolve5(process.cwd(), "cloud/dev-server/server.mjs")
9709
9837
  ];
9710
- const serverPath = candidates.find((p) => existsSync15(p));
9838
+ const serverPath = candidates.find((p) => existsSync16(p));
9711
9839
  if (!serverPath) {
9712
9840
  process.stderr.write("error: dev-server not found \u2014 reinstall `githolon` or run `npm run build` in the cli package\n");
9713
9841
  return 1;