githolon 0.105.24 → 0.106.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.
@@ -265,13 +265,23 @@ async function fetchPack(remote, headers = {}, { wants = [], haves = [] } = {})
265
265
  for (const h of haves) if (/^[0-9a-f]{40}$/.test(h) && h !== ZERO_OID) parts.push(pkt(`have ${h}
266
266
  `));
267
267
  parts.push(pkt("done\n"));
268
- const r = await fetch(`${remote}/git-upload-pack`, {
269
- method: "POST",
270
- headers: { "content-type": "application/x-git-upload-pack-request", "accept": "application/x-git-upload-pack-result", ...headers },
271
- body: concatBytes(parts)
272
- });
273
- if (!r.ok) throw new Error(`upload-pack ${r.status}: ${(await r.text()).slice(0, 180)}`);
274
- const buf = new Uint8Array(await r.arrayBuffer());
268
+ const body = concatBytes(parts);
269
+ const reqHeaders = { "content-type": "application/x-git-upload-pack-request", "accept": "application/x-git-upload-pack-result", ...headers };
270
+ const MAX_ATTEMPTS = 6;
271
+ let buf;
272
+ for (let attempt = 1; ; attempt++) {
273
+ try {
274
+ const r = await fetch(`${remote}/git-upload-pack`, { method: "POST", headers: reqHeaders, body, signal: AbortSignal.timeout(18e4) });
275
+ if (!r.ok) throw new Error(`upload-pack ${r.status}: ${(await r.text()).slice(0, 180)}`);
276
+ buf = new Uint8Array(await r.arrayBuffer());
277
+ break;
278
+ } catch (e) {
279
+ const msg = String(e?.message || e);
280
+ const transient = /terminated|other side closed|socket|ECONNRESET|ECONNREFUSED|UND_ERR|fetch failed|network|aborted|timeout/i.test(msg) && !/upload-pack \d{3}:/.test(msg);
281
+ if (!transient || attempt >= MAX_ATTEMPTS) throw e;
282
+ await new Promise((res) => setTimeout(res, Math.min(4e3, 400 * attempt)));
283
+ }
284
+ }
275
285
  const { lines, rest } = readPktLines(buf, 0);
276
286
  const packChunks = [];
277
287
  let sideband = false;
@@ -248,13 +248,23 @@ async function fetchPack(remote, headers = {}, { wants = [], haves = [] } = {})
248
248
  for (const h of haves) if (/^[0-9a-f]{40}$/.test(h) && h !== ZERO_OID) parts.push(pkt(`have ${h}
249
249
  `));
250
250
  parts.push(pkt("done\n"));
251
- const r = await fetch(`${remote}/git-upload-pack`, {
252
- method: "POST",
253
- headers: { "content-type": "application/x-git-upload-pack-request", "accept": "application/x-git-upload-pack-result", ...headers },
254
- body: concatBytes(parts)
255
- });
256
- if (!r.ok) throw new Error(`upload-pack ${r.status}: ${(await r.text()).slice(0, 180)}`);
257
- const buf = new Uint8Array(await r.arrayBuffer());
251
+ const body = concatBytes(parts);
252
+ const reqHeaders = { "content-type": "application/x-git-upload-pack-request", "accept": "application/x-git-upload-pack-result", ...headers };
253
+ const MAX_ATTEMPTS = 6;
254
+ let buf;
255
+ for (let attempt = 1; ; attempt++) {
256
+ try {
257
+ const r = await fetch(`${remote}/git-upload-pack`, { method: "POST", headers: reqHeaders, body, signal: AbortSignal.timeout(18e4) });
258
+ if (!r.ok) throw new Error(`upload-pack ${r.status}: ${(await r.text()).slice(0, 180)}`);
259
+ buf = new Uint8Array(await r.arrayBuffer());
260
+ break;
261
+ } catch (e) {
262
+ const msg = String(e?.message || e);
263
+ const transient = /terminated|other side closed|socket|ECONNRESET|ECONNREFUSED|UND_ERR|fetch failed|network|aborted|timeout/i.test(msg) && !/upload-pack \d{3}:/.test(msg);
264
+ if (!transient || attempt >= MAX_ATTEMPTS) throw e;
265
+ await new Promise((res) => setTimeout(res, Math.min(4e3, 400 * attempt)));
266
+ }
267
+ }
258
268
  const { lines, rest } = readPktLines(buf, 0);
259
269
  const packChunks = [];
260
270
  let sideband = false;
Binary file
Binary file
package/dist/full-cli.mjs CHANGED
@@ -928,6 +928,14 @@ function aggregate(id, fields, opts) {
928
928
  const v = requires(cap2);
929
929
  return build({ kind: "readableBy", cap: v.requires }, v, contracts, dartNameDecl);
930
930
  },
931
+ // Owner-only, PLAINTEXT. Deliberately a `readableBy` audience gating on the framework owner-read
932
+ // relation — NOT `kind: "owned"`, so the encryption lowering below is skipped and content stays
933
+ // operator-readable. The relation is seated at workspace scope (`workspace:self#<rel>`) at birth
934
+ // (see framework/home.ts genesis), which is why an existing chain resolves it with no backfill.
935
+ // `owned()` is the same read gate PLUS per-record encryption; this is the confidentiality-free rung.
936
+ ownerReadable: () => {
937
+ return build({ kind: "readableBy", cap: OWNED_READ_RELATION }, requires(OWNED_READ_RELATION), contracts, dartNameDecl);
938
+ },
931
939
  owned: () => {
932
940
  return build({ kind: "owned", ownerField: OWNER_FIELD }, requires(OWNED_READ_RELATION), contracts, dartNameDecl);
933
941
  },
@@ -4364,6 +4372,56 @@ async function lsRefs(remote, headers = {}, { service = "git-upload-pack", prefi
4364
4372
  }
4365
4373
  return refs;
4366
4374
  }
4375
+ async function fetchPack(remote, headers = {}, { wants = [], haves = [] } = {}) {
4376
+ wants = wants.filter((w) => /^[0-9a-f]{40}$/.test(w) && w !== ZERO_OID);
4377
+ if (!wants.length) return null;
4378
+ const caps = "ofs-delta agent=nomos-cloud";
4379
+ const parts = [];
4380
+ wants.forEach((w, i) => parts.push(pkt(`want ${w}${i === 0 ? " " + caps : ""}
4381
+ `)));
4382
+ parts.push(FLUSH);
4383
+ for (const h of haves) if (/^[0-9a-f]{40}$/.test(h) && h !== ZERO_OID) parts.push(pkt(`have ${h}
4384
+ `));
4385
+ parts.push(pkt("done\n"));
4386
+ const body = concatBytes(parts);
4387
+ const reqHeaders = { "content-type": "application/x-git-upload-pack-request", "accept": "application/x-git-upload-pack-result", ...headers };
4388
+ const MAX_ATTEMPTS = 6;
4389
+ let buf;
4390
+ for (let attempt = 1; ; attempt++) {
4391
+ try {
4392
+ const r = await fetch(`${remote}/git-upload-pack`, { method: "POST", headers: reqHeaders, body, signal: AbortSignal.timeout(18e4) });
4393
+ if (!r.ok) throw new Error(`upload-pack ${r.status}: ${(await r.text()).slice(0, 180)}`);
4394
+ buf = new Uint8Array(await r.arrayBuffer());
4395
+ break;
4396
+ } catch (e) {
4397
+ const msg = String(e?.message || e);
4398
+ const transient = /terminated|other side closed|socket|ECONNRESET|ECONNREFUSED|UND_ERR|fetch failed|network|aborted|timeout/i.test(msg) && !/upload-pack \d{3}:/.test(msg);
4399
+ if (!transient || attempt >= MAX_ATTEMPTS) throw e;
4400
+ await new Promise((res) => setTimeout(res, Math.min(4e3, 400 * attempt)));
4401
+ }
4402
+ }
4403
+ const { lines, rest } = readPktLines(buf, 0);
4404
+ const packChunks = [];
4405
+ let sideband = false;
4406
+ for (const line of lines) {
4407
+ if (line.length === 0) continue;
4408
+ const head = dec3.decode(line.subarray(0, Math.min(line.length, 3)));
4409
+ if (head === "NAK" || head === "ACK" || head === "ERR" || head.startsWith("sha")) continue;
4410
+ const band = line[0];
4411
+ if (band === 1) {
4412
+ packChunks.push(line.subarray(1));
4413
+ sideband = true;
4414
+ } else if (band === 2) {
4415
+ } else if (band === 3) {
4416
+ throw new Error("upload-pack fatal: " + dec3.decode(line.subarray(1)).slice(0, 180));
4417
+ }
4418
+ }
4419
+ const pack = sideband ? concatBytes(packChunks) : buf.subarray(rest);
4420
+ if (pack.length < 12 || dec3.decode(pack.subarray(0, 4)) !== "PACK") {
4421
+ throw new Error(`upload-pack: no pack in response (${pack.length}B, sideband=${sideband})`);
4422
+ }
4423
+ return pack;
4424
+ }
4367
4425
  async function pushPack(remote, headers = {}, { updates = [], pack = null } = {}, fetchImpl = fetch) {
4368
4426
  if (!updates.length) return { ok: true, noop: true };
4369
4427
  const body = concatBytes([receivePackCommandPrefix(updates), pack && pack.length ? pack : EMPTY_PACK]);
@@ -6066,6 +6124,33 @@ ${String(commit).toLowerCase()}`;
6066
6124
  const addReadRemote = async () => {
6067
6125
  };
6068
6126
  const applyPack = (packB64, head) => provider.applyPack(packB64, head);
6127
+ const directFullClone = async (label) => {
6128
+ let lease = null;
6129
+ try {
6130
+ const r = await _fetch(`${base}/v2/workspaces/${workspace}/git-read-lease`, { headers: authHeaders });
6131
+ if (r.ok) {
6132
+ const d = await r.json();
6133
+ if (d && d.ok && typeof d.remote === "string" && typeof d.token === "string") lease = { remote: d.remote, token: d.token };
6134
+ }
6135
+ } catch {
6136
+ }
6137
+ if (!lease) return false;
6138
+ const _f = span("receive", `${label} (direct artifacts)`, "cfetch", {});
6139
+ try {
6140
+ const auth = { Authorization: "Basic " + btoa("x:" + lease.token) };
6141
+ const refs = await lsRefs(lease.remote, auth, { service: "git-upload-pack", prefix: "refs/heads/main" });
6142
+ const head = refs["refs/heads/main"];
6143
+ if (!head || !/^[0-9a-f]{40}$/i.test(head)) return false;
6144
+ const pack = await fetchPack(lease.remote, auth, { wants: [head] });
6145
+ if (!pack || !pack.byteLength) return false;
6146
+ applyPack(nmsInternalSnapshotToBase64(pack), head);
6147
+ return true;
6148
+ } catch {
6149
+ return false;
6150
+ } finally {
6151
+ _f.end();
6152
+ }
6153
+ };
6069
6154
  try {
6070
6155
  await provider.boot({ base, workspace, branch: BRANCH, repoArg, restoreSnapshot: restoreFrom || null, fetchImpl: _fetch, authHeaders });
6071
6156
  } catch (error) {
@@ -6243,7 +6328,7 @@ ${String(commit).toLowerCase()}`;
6243
6328
  _bootLedger.end();
6244
6329
  if (!allowUnborn) throw new Error(`workspace '${workspace}' has no ledger main \u2014 create it first (POST /v2/workspaces/${workspace})`);
6245
6330
  } else {
6246
- await fetchAndApplyPack("", "boot: fetch full pack");
6331
+ if (!await directFullClone("boot: full pack")) await fetchAndApplyPack("", "boot: fetch full pack");
6247
6332
  const mounted = await mountWithResidency(remoteMain, "boot restore");
6248
6333
  if (mounted && typeof mounted === "object" && mounted.kernelSpans) {
6249
6334
  bootKernelSpans = mounted.kernelSpans;
@@ -6778,7 +6863,7 @@ ${String(commit).toLowerCase()}`;
6778
6863
  const forceFullMainHistory = async (why, _cause) => {
6779
6864
  const _full = span("receive", `${why}: re-pull FULL main`, "cfetch");
6780
6865
  try {
6781
- await fetchAndApplyPack("", `${why}: full main pack`);
6866
+ if (!await directFullClone(`${why}: full main`)) await fetchAndApplyPack("", `${why}: full main pack`);
6782
6867
  } finally {
6783
6868
  _full.end();
6784
6869
  }
@@ -12001,7 +12086,7 @@ async function lsRefs2(remote, headers = {}, { service = "git-upload-pack", pref
12001
12086
  }
12002
12087
  return refs;
12003
12088
  }
12004
- async function fetchPack(remote, headers = {}, { wants = [], haves = [] } = {}) {
12089
+ async function fetchPack2(remote, headers = {}, { wants = [], haves = [] } = {}) {
12005
12090
  wants = wants.filter((w) => /^[0-9a-f]{40}$/.test(w) && w !== ZERO_OID2);
12006
12091
  if (!wants.length) return null;
12007
12092
  const caps = "ofs-delta agent=nomos-cloud";
@@ -12012,13 +12097,23 @@ async function fetchPack(remote, headers = {}, { wants = [], haves = [] } = {})
12012
12097
  for (const h of haves) if (/^[0-9a-f]{40}$/.test(h) && h !== ZERO_OID2) parts.push(pkt2(`have ${h}
12013
12098
  `));
12014
12099
  parts.push(pkt2("done\n"));
12015
- const r = await fetch(`${remote}/git-upload-pack`, {
12016
- method: "POST",
12017
- headers: { "content-type": "application/x-git-upload-pack-request", "accept": "application/x-git-upload-pack-result", ...headers },
12018
- body: concatBytes2(parts)
12019
- });
12020
- if (!r.ok) throw new Error(`upload-pack ${r.status}: ${(await r.text()).slice(0, 180)}`);
12021
- const buf = new Uint8Array(await r.arrayBuffer());
12100
+ const body = concatBytes2(parts);
12101
+ const reqHeaders = { "content-type": "application/x-git-upload-pack-request", "accept": "application/x-git-upload-pack-result", ...headers };
12102
+ const MAX_ATTEMPTS = 6;
12103
+ let buf;
12104
+ for (let attempt = 1; ; attempt++) {
12105
+ try {
12106
+ const r = await fetch(`${remote}/git-upload-pack`, { method: "POST", headers: reqHeaders, body, signal: AbortSignal.timeout(18e4) });
12107
+ if (!r.ok) throw new Error(`upload-pack ${r.status}: ${(await r.text()).slice(0, 180)}`);
12108
+ buf = new Uint8Array(await r.arrayBuffer());
12109
+ break;
12110
+ } catch (e) {
12111
+ const msg = String(e?.message || e);
12112
+ const transient = /terminated|other side closed|socket|ECONNRESET|ECONNREFUSED|UND_ERR|fetch failed|network|aborted|timeout/i.test(msg) && !/upload-pack \d{3}:/.test(msg);
12113
+ if (!transient || attempt >= MAX_ATTEMPTS) throw e;
12114
+ await new Promise((res) => setTimeout(res, Math.min(4e3, 400 * attempt)));
12115
+ }
12116
+ }
12022
12117
  const { lines, rest } = readPktLines2(buf, 0);
12023
12118
  const packChunks = [];
12024
12119
  let sideband = false;
@@ -14228,7 +14323,7 @@ async function custodyFetch(eng, ws, ledger, { remoteRef = "refs/heads/main", lo
14228
14323
  const tip = refs[remoteRefFull] || null;
14229
14324
  if (!tip) return null;
14230
14325
  if (tip !== have) {
14231
- const pk = await fetchPack(ledger.remote, ledger.headers || {}, { wants: [tip], haves: have ? [have] : [] });
14326
+ const pk = await fetchPack2(ledger.remote, ledger.headers || {}, { wants: [tip], haves: have ? [have] : [] });
14232
14327
  if (pk) applyPackInto(eng, ws, pk, tip);
14233
14328
  }
14234
14329
  if (writeRef) kgit.writeRef(eng, gitdirOf(ws), fullRef(localRef || remoteRef), tip);
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "githolon",
3
- "version": "0.105.24",
3
+ "version": "0.106.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",
@@ -30,7 +30,7 @@
30
30
  "dependencies": {
31
31
  "@bjorn3/browser_wasi_shim": "0.4.2",
32
32
  "@bufbuild/protobuf": "^2.13.0",
33
- "@githolon/dsl": "^0.105.24",
33
+ "@githolon/dsl": "^0.106.0",
34
34
  "fast-xml-parser": "5.10.1",
35
35
  "isomorphic-git": "^1.38.4",
36
36
  "tsx": "^4.19.2"