midsummer-sol 0.3.2 → 0.3.6

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 (3) hide show
  1. package/package.json +1 -1
  2. package/sol-mcp.js +122 -39
  3. package/sol.js +122 -39
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "midsummer-sol",
3
- "version": "0.3.2",
3
+ "version": "0.3.6",
4
4
  "description": "Sol — agent-native version control (a new git). CLI, MCP server, and no-filesystem SDK.",
5
5
  "bin": { "sol": "./sol.js", "sol-mcp": "./sol-mcp.js", "sol-secret-mcp": "./sol-secret-mcp.js" },
6
6
  "main": "./index.js",
package/sol-mcp.js CHANGED
@@ -4156,11 +4156,11 @@ var init_lib = __esm(() => {
4156
4156
  var exports_remote = {};
4157
4157
  __export(exports_remote, {
4158
4158
  writeBundle: () => writeBundle,
4159
+ splitLeafPacks: () => splitLeafPacks,
4159
4160
  saveRemote: () => saveRemote,
4160
4161
  remoteRefs: () => remoteRefs,
4161
- remotePushFinalize: () => remotePushFinalize,
4162
- remotePushChunked: () => remotePushChunked,
4163
- remotePushBatch: () => remotePushBatch,
4162
+ remotePushPack: () => remotePushPack,
4163
+ remotePushBlobs: () => remotePushBlobs,
4164
4164
  remotePush: () => remotePush,
4165
4165
  remotePromote: () => remotePromote,
4166
4166
  remoteHead: () => remoteHead,
@@ -4184,12 +4184,13 @@ __export(exports_remote, {
4184
4184
  loadRemote: () => loadRemote,
4185
4185
  forksList: () => forksList,
4186
4186
  forkMeta: () => forkMeta,
4187
+ classifyNodes: () => classifyNodes,
4187
4188
  accessSet: () => accessSet,
4188
4189
  accessGet: () => accessGet
4189
4190
  });
4190
4191
  import { appendFileSync as appendFileSync4, existsSync as existsSync6, readFileSync as readFileSync6, writeFileSync as writeFileSync6 } from "node:fs";
4191
4192
  import { join as join6 } from "node:path";
4192
- import { gzipSync as gzipSync3 } from "node:zlib";
4193
+ import { gunzipSync as gunzipSync3, gzipSync as gzipSync3 } from "node:zlib";
4193
4194
  async function call(cfg, token, path, init) {
4194
4195
  const res = await fetch(endpoint(cfg, path), {
4195
4196
  ...init,
@@ -4199,44 +4200,125 @@ async function call(cfg, token, path, init) {
4199
4200
  throw new Error(`remote ${path} -> ${res.status}: ${(await res.text().catch(() => "")).slice(0, 200)}`);
4200
4201
  return res.json();
4201
4202
  }
4202
- function splitNodes(nodes, batchSizeBytes) {
4203
- const batches = [];
4203
+ function decodePackLine(line) {
4204
+ const map = JSON.parse(gunzipSync3(Buffer.from(line, "base64")).toString("utf8"));
4205
+ return Object.values(map);
4206
+ }
4207
+ async function exportStreaming(cfg, token) {
4208
+ const res = await fetch(endpoint(cfg, "/export?stream=1"), {
4209
+ headers: { authorization: `Bearer ${token}`, "content-type": "application/json" }
4210
+ });
4211
+ if (!res.ok)
4212
+ throw new Error(`remote /export -> ${res.status}: ${(await res.text().catch(() => "")).slice(0, 200)}`);
4213
+ if (!res.body)
4214
+ return res.json();
4215
+ const reader = res.body.getReader();
4216
+ const td = new TextDecoder;
4217
+ let buf = "";
4218
+ let header;
4219
+ const nodes = [];
4220
+ const consumeLine = (line) => {
4221
+ if (line === "")
4222
+ return;
4223
+ if (!header) {
4224
+ header = JSON.parse(line);
4225
+ if (Array.isArray(header.nodes))
4226
+ for (const n of header.nodes)
4227
+ nodes.push(n);
4228
+ return;
4229
+ }
4230
+ for (const n of decodePackLine(line))
4231
+ nodes.push(n);
4232
+ };
4233
+ for (;; ) {
4234
+ const { done, value } = await reader.read();
4235
+ if (value)
4236
+ buf += td.decode(value, { stream: true });
4237
+ let nl;
4238
+ while ((nl = buf.indexOf(`
4239
+ `)) >= 0) {
4240
+ consumeLine(buf.slice(0, nl));
4241
+ buf = buf.slice(nl + 1);
4242
+ }
4243
+ if (done)
4244
+ break;
4245
+ }
4246
+ buf += td.decode();
4247
+ if (buf.length)
4248
+ consumeLine(buf);
4249
+ if (!header)
4250
+ throw new Error("remote /export returned an empty stream");
4251
+ return { ...header, nodes };
4252
+ }
4253
+ function classifyNodes(nodes) {
4254
+ const trees = [];
4255
+ const leaves = [];
4256
+ let total = 0;
4257
+ for (const n of nodes) {
4258
+ total += nodeBytes(n);
4259
+ (n.kind === "tree" ? trees : leaves).push(n);
4260
+ }
4261
+ return { trees, leaves, total };
4262
+ }
4263
+ function splitLeafPacks(leaves, maxBytes) {
4264
+ const packs = [];
4204
4265
  let cur = [];
4205
- let curBytes = 0;
4206
- for (const node of nodes) {
4207
- const nb = sizeOf(node);
4208
- if (cur.length && curBytes + nb > batchSizeBytes) {
4209
- batches.push(cur);
4266
+ let size = 0;
4267
+ for (const n of leaves) {
4268
+ const b = nodeBytes(n);
4269
+ if (cur.length && size + b > maxBytes) {
4270
+ packs.push(cur);
4210
4271
  cur = [];
4211
- curBytes = 0;
4272
+ size = 0;
4212
4273
  }
4213
- cur.push(node);
4214
- curBytes += nb;
4274
+ cur.push(n);
4275
+ size += b;
4215
4276
  }
4216
4277
  if (cur.length)
4217
- batches.push(cur);
4218
- return batches.length ? batches : [[]];
4219
- }
4220
- async function remotePushChunked(cfg, token, body, batchSizeBytes = DEFAULT_BATCH_BYTES) {
4221
- const totalBytes = sizeOf(body.nodes) + sizeOf(body.ops);
4222
- if (totalBytes <= batchSizeBytes)
4223
- return remotePush(cfg, token, body);
4224
- const stamp = `${body.head ?? "h"}-${Date.now()}`;
4225
- const nodeBatches = splitNodes(body.nodes, batchSizeBytes);
4226
- const batchIds = [];
4227
- const CONC = 12;
4228
- for (let i = 0;i < nodeBatches.length; i++)
4229
- batchIds.push(`${stamp}-${i}`);
4230
- try {
4231
- for (let w = 0;w < nodeBatches.length; w += CONC) {
4232
- await Promise.all(nodeBatches.slice(w, w + CONC).map((nodes, j) => remotePushBatch(cfg, token, batchIds[w + j], nodes, w + j === 0 ? body.ops : [], w + j)));
4278
+ packs.push(cur);
4279
+ return packs;
4280
+ }
4281
+ async function pool(tasks, limit) {
4282
+ const out = new Array(tasks.length);
4283
+ let next = 0;
4284
+ const worker = async () => {
4285
+ for (;; ) {
4286
+ const i = next++;
4287
+ if (i >= tasks.length)
4288
+ return;
4289
+ out[i] = await tasks[i]();
4233
4290
  }
4234
- } catch (e) {
4235
- if (e instanceof Error && /-> 404/.test(e.message))
4236
- return remotePush(cfg, token, body);
4237
- throw e;
4238
- }
4239
- return remotePushFinalize(cfg, token, batchIds, body.branch, body.head, body.expectedHead);
4291
+ };
4292
+ await Promise.all(Array.from({ length: Math.min(limit, tasks.length) }, worker));
4293
+ return out;
4294
+ }
4295
+ async function retryTransient(fn, attempts = 5) {
4296
+ let last;
4297
+ for (let i = 0;i < attempts; i++) {
4298
+ try {
4299
+ return await fn();
4300
+ } catch (e) {
4301
+ last = e;
4302
+ const m = e instanceof Error ? e.message : String(e);
4303
+ if (!/-> 5dd|reset|fetch failed|network|ECONN|terminated|timeout/i.test(m))
4304
+ throw e;
4305
+ await new Promise((r) => setTimeout(r, 400 * (i + 1)));
4306
+ }
4307
+ }
4308
+ throw last;
4309
+ }
4310
+ async function remotePushPack(cfg, token, body) {
4311
+ const { trees, leaves, total } = classifyNodes(body.nodes);
4312
+ if (total <= SMALL_PUSH_BYTES) {
4313
+ return retryTransient(() => call(cfg, token, "/push/pack", { method: "POST", body: gzipSync3(JSON.stringify(body)), headers: { "content-encoding": "gzip" } }));
4314
+ }
4315
+ const blobPacks = splitLeafPacks(leaves, BLOB_PACK_BYTES);
4316
+ await pool(blobPacks.map((pack) => () => remotePushBlobs(cfg, token, pack)), BLOB_PACK_CONCURRENCY);
4317
+ return retryTransient(() => call(cfg, token, "/push/pack", {
4318
+ method: "POST",
4319
+ body: gzipSync3(JSON.stringify({ ...body, nodes: trees })),
4320
+ headers: { "content-encoding": "gzip" }
4321
+ }));
4240
4322
  }
4241
4323
  function loadRemote(solDir2) {
4242
4324
  const p = join6(solDir2, "remote.json");
@@ -4258,10 +4340,11 @@ async function writeBundle(solDir2, bundle, from = 0) {
4258
4340
  writeFileSync6(join6(solDir2, "HEAD"), JSON.stringify({ head: bundle.head, seq: bundle.seq, logTip: bundle.tip }));
4259
4341
  return fresh.length;
4260
4342
  }
4261
- var endpoint = (cfg, path) => `${cfg.url.replace(/\/+$/, "")}${path}${path.includes("?") ? "&" : "?"}repo=${encodeURIComponent(cfg.repo)}`, remoteHead = (cfg, token) => call(cfg, token, "/head"), remoteGate = (cfg, token, branch) => call(cfg, token, `/head?gateState=true${branch ? `&branch=${encodeURIComponent(branch)}` : ""}`), remoteExport = (cfg, token) => call(cfg, token, "/export"), remoteRefs = (cfg, token) => call(cfg, token, "/refs"), remotePush = (cfg, token, body) => call(cfg, token, "/push", { method: "POST", body: JSON.stringify(body) }), remotePromote = (cfg, token, branch) => call(cfg, token, "/promote", { method: "POST", body: JSON.stringify({ branch }) }), remotePushBatch = (cfg, token, batchId, nodes, ops, seq) => call(cfg, token, "/push/batch", { method: "POST", body: gzipSync3(JSON.stringify({ batchId, nodes, ops, seq })), headers: { "content-encoding": "gzip" } }), remotePushFinalize = (cfg, token, batchIds, branch, head, expectedHead) => call(cfg, token, "/push/finalize", { method: "POST", body: JSON.stringify({ batchIds, branch, head, expectedHead }) }), DEFAULT_BATCH_BYTES, sizeOf = (v) => JSON.stringify(v).length, mrOpen = (cfg, token, body) => call(cfg, token, "/mr", { method: "POST", body: JSON.stringify(body) }), mrList = (cfg, token) => call(cfg, token, "/mrs"), mrDiff = (cfg, token, id) => call(cfg, token, `/mr/diff?id=${id}`), mrGet = (cfg, token, id) => call(cfg, token, `/mr?id=${id}`), mrAction = (cfg, token, action, body) => call(cfg, token, `/mr/${action}`, { method: "POST", body: JSON.stringify(body) }), accessGet = (cfg, token) => call(cfg, token, "/access"), ownerSet = (cfg, token, ownerHandle) => call(cfg, token, "/owner", { method: "POST", body: JSON.stringify({ ownerHandle }) }), accessSet = (cfg, token, body) => call(cfg, token, "/access", { method: "POST", body: JSON.stringify(body) }), policyCheck = (cfg, token, paths) => call(cfg, token, "/policy/check", { method: "POST", body: JSON.stringify({ paths }) }), policyGet = (cfg, token) => call(cfg, token, "/policy"), policyUpsert = (cfg, token, rule) => call(cfg, token, "/policy?write=1", { method: "POST", body: JSON.stringify({ op: "upsert", rule }) }), policyRemove = (cfg, token, pattern) => call(cfg, token, "/policy?write=1", { method: "POST", body: JSON.stringify({ op: "remove", pattern }) }), recipientsForPath = (cfg, token, path) => call(cfg, token, `/recipients?path=${encodeURIComponent(path)}`), recipientsForAudience = (cfg, token, audience, recovery) => call(cfg, token, `/recipients?audience=${encodeURIComponent(JSON.stringify(audience))}${recovery?.length ? `&recovery=${encodeURIComponent(recovery.join(","))}` : ""}`), remoteEnvPush = (cfg, token, bundle) => call(cfg, token, "/env/push", { method: "POST", body: JSON.stringify(bundle) }), remoteEnvAnchor = (cfg, token) => call(cfg, token, "/env/anchor"), remoteEnvPull = (cfg, token) => call(cfg, token, "/env/pull"), forkMeta = (cfg, token, parent) => call(cfg, token, "/fork-meta", { method: "POST", body: JSON.stringify({ parent }) }), forksList = (cfg, token) => call(cfg, token, "/forks"), saveRemote = (solDir2, cfg) => writeFileSync6(join6(solDir2, "remote.json"), JSON.stringify(cfg, null, 2));
4343
+ var endpoint = (cfg, path) => `${cfg.url.replace(/\/+$/, "")}${path}${path.includes("?") ? "&" : "?"}repo=${encodeURIComponent(cfg.repo)}`, remoteHead = (cfg, token) => call(cfg, token, "/head"), remoteGate = (cfg, token, branch) => call(cfg, token, `/head?gateState=true${branch ? `&branch=${encodeURIComponent(branch)}` : ""}`), remoteExport = (cfg, token) => exportStreaming(cfg, token), remoteRefs = (cfg, token) => call(cfg, token, "/refs"), remotePush = (cfg, token, body) => call(cfg, token, "/push", { method: "POST", body: JSON.stringify(body) }), remotePromote = (cfg, token, branch) => call(cfg, token, "/promote", { method: "POST", body: JSON.stringify({ branch }) }), SMALL_PUSH_BYTES, BLOB_PACK_BYTES, BLOB_PACK_CONCURRENCY = 1, nodeBytes = (n) => JSON.stringify(n).length, remotePushBlobs = (cfg, token, nodes) => retryTransient(() => call(cfg, token, "/push/blobs", { method: "POST", body: gzipSync3(JSON.stringify({ nodes })), headers: { "content-encoding": "gzip" } })), mrOpen = (cfg, token, body) => call(cfg, token, "/mr", { method: "POST", body: JSON.stringify(body) }), mrList = (cfg, token) => call(cfg, token, "/mrs"), mrDiff = (cfg, token, id) => call(cfg, token, `/mr/diff?id=${id}`), mrGet = (cfg, token, id) => call(cfg, token, `/mr?id=${id}`), mrAction = (cfg, token, action, body) => call(cfg, token, `/mr/${action}`, { method: "POST", body: JSON.stringify(body) }), accessGet = (cfg, token) => call(cfg, token, "/access"), ownerSet = (cfg, token, ownerHandle) => call(cfg, token, "/owner", { method: "POST", body: JSON.stringify({ ownerHandle }) }), accessSet = (cfg, token, body) => call(cfg, token, "/access", { method: "POST", body: JSON.stringify(body) }), policyCheck = (cfg, token, paths) => call(cfg, token, "/policy/check", { method: "POST", body: JSON.stringify({ paths }) }), policyGet = (cfg, token) => call(cfg, token, "/policy"), policyUpsert = (cfg, token, rule) => call(cfg, token, "/policy?write=1", { method: "POST", body: JSON.stringify({ op: "upsert", rule }) }), policyRemove = (cfg, token, pattern) => call(cfg, token, "/policy?write=1", { method: "POST", body: JSON.stringify({ op: "remove", pattern }) }), recipientsForPath = (cfg, token, path) => call(cfg, token, `/recipients?path=${encodeURIComponent(path)}`), recipientsForAudience = (cfg, token, audience, recovery) => call(cfg, token, `/recipients?audience=${encodeURIComponent(JSON.stringify(audience))}${recovery?.length ? `&recovery=${encodeURIComponent(recovery.join(","))}` : ""}`), remoteEnvPush = (cfg, token, bundle) => call(cfg, token, "/env/push", { method: "POST", body: JSON.stringify(bundle) }), remoteEnvAnchor = (cfg, token) => call(cfg, token, "/env/anchor"), remoteEnvPull = (cfg, token) => call(cfg, token, "/env/pull"), forkMeta = (cfg, token, parent) => call(cfg, token, "/fork-meta", { method: "POST", body: JSON.stringify({ parent }) }), forksList = (cfg, token) => call(cfg, token, "/forks"), saveRemote = (solDir2, cfg) => writeFileSync6(join6(solDir2, "remote.json"), JSON.stringify(cfg, null, 2));
4262
4344
  var init_remote = __esm(() => {
4263
4345
  init_file_store2();
4264
- DEFAULT_BATCH_BYTES = 5 * 1024 * 1024;
4346
+ SMALL_PUSH_BYTES = 24 * 1024 * 1024;
4347
+ BLOB_PACK_BYTES = 16 * 1024 * 1024;
4265
4348
  });
4266
4349
 
4267
4350
  // src/bin/test-gate.ts
@@ -12550,7 +12633,7 @@ WARNING: "${path}" was committed as PLAINTEXT before this seal — the pre-seal
12550
12633
  const forkBase = localRefs?.branches[branch]?.remote;
12551
12634
  const baseOp = forkBase ? ops.find((o) => o.rootAfter === forkBase) : undefined;
12552
12635
  const fromSeq = baseOp ? baseOp.seq : rh.seq;
12553
- const res = await remotePushChunked(cfg, token, {
12636
+ const res = await remotePushPack(cfg, token, {
12554
12637
  nodes: allLocalNodes(),
12555
12638
  ops: ops.filter((o) => o.seq > fromSeq),
12556
12639
  branch,
package/sol.js CHANGED
@@ -3389,11 +3389,11 @@ var init_lib = __esm(() => {
3389
3389
  var exports_remote = {};
3390
3390
  __export(exports_remote, {
3391
3391
  writeBundle: () => writeBundle,
3392
+ splitLeafPacks: () => splitLeafPacks,
3392
3393
  saveRemote: () => saveRemote,
3393
3394
  remoteRefs: () => remoteRefs,
3394
- remotePushFinalize: () => remotePushFinalize,
3395
- remotePushChunked: () => remotePushChunked,
3396
- remotePushBatch: () => remotePushBatch,
3395
+ remotePushPack: () => remotePushPack,
3396
+ remotePushBlobs: () => remotePushBlobs,
3397
3397
  remotePush: () => remotePush,
3398
3398
  remotePromote: () => remotePromote,
3399
3399
  remoteHead: () => remoteHead,
@@ -3417,12 +3417,13 @@ __export(exports_remote, {
3417
3417
  loadRemote: () => loadRemote,
3418
3418
  forksList: () => forksList,
3419
3419
  forkMeta: () => forkMeta,
3420
+ classifyNodes: () => classifyNodes,
3420
3421
  accessSet: () => accessSet,
3421
3422
  accessGet: () => accessGet
3422
3423
  });
3423
3424
  import { appendFileSync as appendFileSync3, existsSync as existsSync5, readFileSync as readFileSync5, writeFileSync as writeFileSync5 } from "node:fs";
3424
3425
  import { join as join5 } from "node:path";
3425
- import { gzipSync as gzipSync2 } from "node:zlib";
3426
+ import { gunzipSync as gunzipSync2, gzipSync as gzipSync2 } from "node:zlib";
3426
3427
  async function call(cfg, token, path, init) {
3427
3428
  const res = await fetch(endpoint(cfg, path), {
3428
3429
  ...init,
@@ -3432,44 +3433,125 @@ async function call(cfg, token, path, init) {
3432
3433
  throw new Error(`remote ${path} -> ${res.status}: ${(await res.text().catch(() => "")).slice(0, 200)}`);
3433
3434
  return res.json();
3434
3435
  }
3435
- function splitNodes(nodes, batchSizeBytes) {
3436
- const batches = [];
3436
+ function decodePackLine(line) {
3437
+ const map = JSON.parse(gunzipSync2(Buffer.from(line, "base64")).toString("utf8"));
3438
+ return Object.values(map);
3439
+ }
3440
+ async function exportStreaming(cfg, token) {
3441
+ const res = await fetch(endpoint(cfg, "/export?stream=1"), {
3442
+ headers: { authorization: `Bearer ${token}`, "content-type": "application/json" }
3443
+ });
3444
+ if (!res.ok)
3445
+ throw new Error(`remote /export -> ${res.status}: ${(await res.text().catch(() => "")).slice(0, 200)}`);
3446
+ if (!res.body)
3447
+ return res.json();
3448
+ const reader = res.body.getReader();
3449
+ const td = new TextDecoder;
3450
+ let buf = "";
3451
+ let header;
3452
+ const nodes = [];
3453
+ const consumeLine = (line) => {
3454
+ if (line === "")
3455
+ return;
3456
+ if (!header) {
3457
+ header = JSON.parse(line);
3458
+ if (Array.isArray(header.nodes))
3459
+ for (const n of header.nodes)
3460
+ nodes.push(n);
3461
+ return;
3462
+ }
3463
+ for (const n of decodePackLine(line))
3464
+ nodes.push(n);
3465
+ };
3466
+ for (;; ) {
3467
+ const { done, value } = await reader.read();
3468
+ if (value)
3469
+ buf += td.decode(value, { stream: true });
3470
+ let nl;
3471
+ while ((nl = buf.indexOf(`
3472
+ `)) >= 0) {
3473
+ consumeLine(buf.slice(0, nl));
3474
+ buf = buf.slice(nl + 1);
3475
+ }
3476
+ if (done)
3477
+ break;
3478
+ }
3479
+ buf += td.decode();
3480
+ if (buf.length)
3481
+ consumeLine(buf);
3482
+ if (!header)
3483
+ throw new Error("remote /export returned an empty stream");
3484
+ return { ...header, nodes };
3485
+ }
3486
+ function classifyNodes(nodes) {
3487
+ const trees = [];
3488
+ const leaves = [];
3489
+ let total = 0;
3490
+ for (const n of nodes) {
3491
+ total += nodeBytes(n);
3492
+ (n.kind === "tree" ? trees : leaves).push(n);
3493
+ }
3494
+ return { trees, leaves, total };
3495
+ }
3496
+ function splitLeafPacks(leaves, maxBytes) {
3497
+ const packs = [];
3437
3498
  let cur = [];
3438
- let curBytes = 0;
3439
- for (const node of nodes) {
3440
- const nb = sizeOf(node);
3441
- if (cur.length && curBytes + nb > batchSizeBytes) {
3442
- batches.push(cur);
3499
+ let size = 0;
3500
+ for (const n of leaves) {
3501
+ const b = nodeBytes(n);
3502
+ if (cur.length && size + b > maxBytes) {
3503
+ packs.push(cur);
3443
3504
  cur = [];
3444
- curBytes = 0;
3505
+ size = 0;
3445
3506
  }
3446
- cur.push(node);
3447
- curBytes += nb;
3507
+ cur.push(n);
3508
+ size += b;
3448
3509
  }
3449
3510
  if (cur.length)
3450
- batches.push(cur);
3451
- return batches.length ? batches : [[]];
3452
- }
3453
- async function remotePushChunked(cfg, token, body, batchSizeBytes = DEFAULT_BATCH_BYTES) {
3454
- const totalBytes = sizeOf(body.nodes) + sizeOf(body.ops);
3455
- if (totalBytes <= batchSizeBytes)
3456
- return remotePush(cfg, token, body);
3457
- const stamp = `${body.head ?? "h"}-${Date.now()}`;
3458
- const nodeBatches = splitNodes(body.nodes, batchSizeBytes);
3459
- const batchIds = [];
3460
- const CONC = 12;
3461
- for (let i = 0;i < nodeBatches.length; i++)
3462
- batchIds.push(`${stamp}-${i}`);
3463
- try {
3464
- for (let w = 0;w < nodeBatches.length; w += CONC) {
3465
- await Promise.all(nodeBatches.slice(w, w + CONC).map((nodes, j) => remotePushBatch(cfg, token, batchIds[w + j], nodes, w + j === 0 ? body.ops : [], w + j)));
3511
+ packs.push(cur);
3512
+ return packs;
3513
+ }
3514
+ async function pool(tasks, limit) {
3515
+ const out = new Array(tasks.length);
3516
+ let next = 0;
3517
+ const worker = async () => {
3518
+ for (;; ) {
3519
+ const i = next++;
3520
+ if (i >= tasks.length)
3521
+ return;
3522
+ out[i] = await tasks[i]();
3523
+ }
3524
+ };
3525
+ await Promise.all(Array.from({ length: Math.min(limit, tasks.length) }, worker));
3526
+ return out;
3527
+ }
3528
+ async function retryTransient(fn, attempts = 5) {
3529
+ let last;
3530
+ for (let i = 0;i < attempts; i++) {
3531
+ try {
3532
+ return await fn();
3533
+ } catch (e) {
3534
+ last = e;
3535
+ const m = e instanceof Error ? e.message : String(e);
3536
+ if (!/-> 5dd|reset|fetch failed|network|ECONN|terminated|timeout/i.test(m))
3537
+ throw e;
3538
+ await new Promise((r) => setTimeout(r, 400 * (i + 1)));
3466
3539
  }
3467
- } catch (e) {
3468
- if (e instanceof Error && /-> 404/.test(e.message))
3469
- return remotePush(cfg, token, body);
3470
- throw e;
3471
3540
  }
3472
- return remotePushFinalize(cfg, token, batchIds, body.branch, body.head, body.expectedHead);
3541
+ throw last;
3542
+ }
3543
+ async function remotePushPack(cfg, token, body) {
3544
+ const { trees, leaves, total } = classifyNodes(body.nodes);
3545
+ if (total <= SMALL_PUSH_BYTES) {
3546
+ return retryTransient(() => call(cfg, token, "/push/pack", { method: "POST", body: gzipSync2(JSON.stringify(body)), headers: { "content-encoding": "gzip" } }));
3547
+ }
3548
+ const blobPacks = splitLeafPacks(leaves, BLOB_PACK_BYTES);
3549
+ await pool(blobPacks.map((pack) => () => remotePushBlobs(cfg, token, pack)), BLOB_PACK_CONCURRENCY);
3550
+ return retryTransient(() => call(cfg, token, "/push/pack", {
3551
+ method: "POST",
3552
+ body: gzipSync2(JSON.stringify({ ...body, nodes: trees })),
3553
+ headers: { "content-encoding": "gzip" }
3554
+ }));
3473
3555
  }
3474
3556
  function loadRemote(solDir2) {
3475
3557
  const p = join5(solDir2, "remote.json");
@@ -3491,10 +3573,11 @@ async function writeBundle(solDir2, bundle, from = 0) {
3491
3573
  writeFileSync5(join5(solDir2, "HEAD"), JSON.stringify({ head: bundle.head, seq: bundle.seq, logTip: bundle.tip }));
3492
3574
  return fresh.length;
3493
3575
  }
3494
- var endpoint = (cfg, path) => `${cfg.url.replace(/\/+$/, "")}${path}${path.includes("?") ? "&" : "?"}repo=${encodeURIComponent(cfg.repo)}`, remoteHead = (cfg, token) => call(cfg, token, "/head"), remoteGate = (cfg, token, branch) => call(cfg, token, `/head?gateState=true${branch ? `&branch=${encodeURIComponent(branch)}` : ""}`), remoteExport = (cfg, token) => call(cfg, token, "/export"), remoteRefs = (cfg, token) => call(cfg, token, "/refs"), remotePush = (cfg, token, body) => call(cfg, token, "/push", { method: "POST", body: JSON.stringify(body) }), remotePromote = (cfg, token, branch) => call(cfg, token, "/promote", { method: "POST", body: JSON.stringify({ branch }) }), remotePushBatch = (cfg, token, batchId, nodes, ops, seq) => call(cfg, token, "/push/batch", { method: "POST", body: gzipSync2(JSON.stringify({ batchId, nodes, ops, seq })), headers: { "content-encoding": "gzip" } }), remotePushFinalize = (cfg, token, batchIds, branch, head, expectedHead) => call(cfg, token, "/push/finalize", { method: "POST", body: JSON.stringify({ batchIds, branch, head, expectedHead }) }), DEFAULT_BATCH_BYTES, sizeOf = (v) => JSON.stringify(v).length, mrOpen = (cfg, token, body) => call(cfg, token, "/mr", { method: "POST", body: JSON.stringify(body) }), mrList = (cfg, token) => call(cfg, token, "/mrs"), mrDiff = (cfg, token, id) => call(cfg, token, `/mr/diff?id=${id}`), mrGet = (cfg, token, id) => call(cfg, token, `/mr?id=${id}`), mrAction = (cfg, token, action, body) => call(cfg, token, `/mr/${action}`, { method: "POST", body: JSON.stringify(body) }), accessGet = (cfg, token) => call(cfg, token, "/access"), ownerSet = (cfg, token, ownerHandle) => call(cfg, token, "/owner", { method: "POST", body: JSON.stringify({ ownerHandle }) }), accessSet = (cfg, token, body) => call(cfg, token, "/access", { method: "POST", body: JSON.stringify(body) }), policyCheck = (cfg, token, paths) => call(cfg, token, "/policy/check", { method: "POST", body: JSON.stringify({ paths }) }), policyGet = (cfg, token) => call(cfg, token, "/policy"), policyUpsert = (cfg, token, rule) => call(cfg, token, "/policy?write=1", { method: "POST", body: JSON.stringify({ op: "upsert", rule }) }), policyRemove = (cfg, token, pattern) => call(cfg, token, "/policy?write=1", { method: "POST", body: JSON.stringify({ op: "remove", pattern }) }), recipientsForPath = (cfg, token, path) => call(cfg, token, `/recipients?path=${encodeURIComponent(path)}`), recipientsForAudience = (cfg, token, audience, recovery) => call(cfg, token, `/recipients?audience=${encodeURIComponent(JSON.stringify(audience))}${recovery?.length ? `&recovery=${encodeURIComponent(recovery.join(","))}` : ""}`), remoteEnvPush = (cfg, token, bundle) => call(cfg, token, "/env/push", { method: "POST", body: JSON.stringify(bundle) }), remoteEnvAnchor = (cfg, token) => call(cfg, token, "/env/anchor"), remoteEnvPull = (cfg, token) => call(cfg, token, "/env/pull"), forkMeta = (cfg, token, parent) => call(cfg, token, "/fork-meta", { method: "POST", body: JSON.stringify({ parent }) }), forksList = (cfg, token) => call(cfg, token, "/forks"), saveRemote = (solDir2, cfg) => writeFileSync5(join5(solDir2, "remote.json"), JSON.stringify(cfg, null, 2));
3576
+ var endpoint = (cfg, path) => `${cfg.url.replace(/\/+$/, "")}${path}${path.includes("?") ? "&" : "?"}repo=${encodeURIComponent(cfg.repo)}`, remoteHead = (cfg, token) => call(cfg, token, "/head"), remoteGate = (cfg, token, branch) => call(cfg, token, `/head?gateState=true${branch ? `&branch=${encodeURIComponent(branch)}` : ""}`), remoteExport = (cfg, token) => exportStreaming(cfg, token), remoteRefs = (cfg, token) => call(cfg, token, "/refs"), remotePush = (cfg, token, body) => call(cfg, token, "/push", { method: "POST", body: JSON.stringify(body) }), remotePromote = (cfg, token, branch) => call(cfg, token, "/promote", { method: "POST", body: JSON.stringify({ branch }) }), SMALL_PUSH_BYTES, BLOB_PACK_BYTES, BLOB_PACK_CONCURRENCY = 1, nodeBytes = (n) => JSON.stringify(n).length, remotePushBlobs = (cfg, token, nodes) => retryTransient(() => call(cfg, token, "/push/blobs", { method: "POST", body: gzipSync2(JSON.stringify({ nodes })), headers: { "content-encoding": "gzip" } })), mrOpen = (cfg, token, body) => call(cfg, token, "/mr", { method: "POST", body: JSON.stringify(body) }), mrList = (cfg, token) => call(cfg, token, "/mrs"), mrDiff = (cfg, token, id) => call(cfg, token, `/mr/diff?id=${id}`), mrGet = (cfg, token, id) => call(cfg, token, `/mr?id=${id}`), mrAction = (cfg, token, action, body) => call(cfg, token, `/mr/${action}`, { method: "POST", body: JSON.stringify(body) }), accessGet = (cfg, token) => call(cfg, token, "/access"), ownerSet = (cfg, token, ownerHandle) => call(cfg, token, "/owner", { method: "POST", body: JSON.stringify({ ownerHandle }) }), accessSet = (cfg, token, body) => call(cfg, token, "/access", { method: "POST", body: JSON.stringify(body) }), policyCheck = (cfg, token, paths) => call(cfg, token, "/policy/check", { method: "POST", body: JSON.stringify({ paths }) }), policyGet = (cfg, token) => call(cfg, token, "/policy"), policyUpsert = (cfg, token, rule) => call(cfg, token, "/policy?write=1", { method: "POST", body: JSON.stringify({ op: "upsert", rule }) }), policyRemove = (cfg, token, pattern) => call(cfg, token, "/policy?write=1", { method: "POST", body: JSON.stringify({ op: "remove", pattern }) }), recipientsForPath = (cfg, token, path) => call(cfg, token, `/recipients?path=${encodeURIComponent(path)}`), recipientsForAudience = (cfg, token, audience, recovery) => call(cfg, token, `/recipients?audience=${encodeURIComponent(JSON.stringify(audience))}${recovery?.length ? `&recovery=${encodeURIComponent(recovery.join(","))}` : ""}`), remoteEnvPush = (cfg, token, bundle) => call(cfg, token, "/env/push", { method: "POST", body: JSON.stringify(bundle) }), remoteEnvAnchor = (cfg, token) => call(cfg, token, "/env/anchor"), remoteEnvPull = (cfg, token) => call(cfg, token, "/env/pull"), forkMeta = (cfg, token, parent) => call(cfg, token, "/fork-meta", { method: "POST", body: JSON.stringify({ parent }) }), forksList = (cfg, token) => call(cfg, token, "/forks"), saveRemote = (solDir2, cfg) => writeFileSync5(join5(solDir2, "remote.json"), JSON.stringify(cfg, null, 2));
3495
3577
  var init_remote = __esm(() => {
3496
3578
  init_file_store();
3497
- DEFAULT_BATCH_BYTES = 5 * 1024 * 1024;
3579
+ SMALL_PUSH_BYTES = 24 * 1024 * 1024;
3580
+ BLOB_PACK_BYTES = 16 * 1024 * 1024;
3498
3581
  });
3499
3582
 
3500
3583
  // src/bin/test-gate.ts
@@ -12318,7 +12401,7 @@ WARNING: "${path}" was committed as PLAINTEXT before this seal — the pre-seal
12318
12401
  const forkBase = localRefs?.branches[branch]?.remote;
12319
12402
  const baseOp = forkBase ? ops.find((o) => o.rootAfter === forkBase) : undefined;
12320
12403
  const fromSeq = baseOp ? baseOp.seq : rh.seq;
12321
- const res = await remotePushChunked(cfg, token, {
12404
+ const res = await remotePushPack(cfg, token, {
12322
12405
  nodes: allLocalNodes(),
12323
12406
  ops: ops.filter((o) => o.seq > fromSeq),
12324
12407
  branch,
@@ -16602,7 +16685,7 @@ WARNING: "${path}" was committed as PLAINTEXT before this seal — the pre-seal
16602
16685
  const forkBase = localRefs?.branches[branch]?.remote;
16603
16686
  const baseOp = forkBase ? ops.find((o) => o.rootAfter === forkBase) : undefined;
16604
16687
  const fromSeq = baseOp ? baseOp.seq : rh.seq;
16605
- const res = await remotePushChunked(cfg, token, {
16688
+ const res = await remotePushPack(cfg, token, {
16606
16689
  nodes: allLocalNodes(),
16607
16690
  ops: ops.filter((o) => o.seq > fromSeq),
16608
16691
  branch,