@mu-crew/mu 3.12.0 → 3.13.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (58) hide show
  1. package/dist/chunk-3BARPJLY.js +44 -0
  2. package/dist/{chunk-R2SVBZAB.js → chunk-45KQLMEL.js} +193 -93
  3. package/dist/chunk-45KQLMEL.js.map +1 -0
  4. package/dist/{chunk-TEGZOXML.js → chunk-54WJCMJR.js} +12 -10
  5. package/dist/chunk-54WJCMJR.js.map +1 -0
  6. package/dist/{chunk-XV7J56GD.js → chunk-EPCEEDHG.js} +4 -3
  7. package/dist/{chunk-XV7J56GD.js.map → chunk-EPCEEDHG.js.map} +1 -1
  8. package/dist/{chunk-77GBZ2KR.js → chunk-QITLNZEM.js} +3 -1
  9. package/dist/{chunk-77GBZ2KR.js.map → chunk-QITLNZEM.js.map} +1 -1
  10. package/dist/{chunk-IRPTNVJC.js → chunk-TXV34VWT.js} +8614 -6029
  11. package/dist/chunk-TXV34VWT.js.map +1 -0
  12. package/dist/{chunk-L2ABBTYG.js → chunk-WI6AWCMK.js} +3 -1
  13. package/dist/{chunk-L2ABBTYG.js.map → chunk-WI6AWCMK.js.map} +1 -1
  14. package/dist/{cli-MDCJEU74.js → cli-GMJUOXPW.js} +3581 -107
  15. package/dist/cli-GMJUOXPW.js.map +1 -0
  16. package/dist/cli.js +4 -3
  17. package/dist/cli.js.map +1 -1
  18. package/dist/devtools-LS4ZEPWM.js +3772 -0
  19. package/dist/devtools-LS4ZEPWM.js.map +1 -0
  20. package/dist/extension/mu-pi.js +206 -61
  21. package/dist/extension/mu-pi.js.map +1 -1
  22. package/dist/index.d.ts +309 -228
  23. package/dist/index.js +12 -5
  24. package/dist/tui-WSDDTA4K.js +40956 -0
  25. package/dist/tui-WSDDTA4K.js.map +1 -0
  26. package/dist/tui-sync-worker.js +4 -3
  27. package/dist/tui-sync-worker.js.map +1 -1
  28. package/dist/yank-XDOONQSL.js +13 -0
  29. package/docs/ARCHITECTURE.md +4 -1
  30. package/docs/ROADMAP.md +43 -38
  31. package/docs/VISION.md +8 -0
  32. package/docs/VOCABULARY.md +3 -1
  33. package/docs/architecture/dag.md +4 -0
  34. package/docs/architecture/sync.md +8 -0
  35. package/docs/architecture/tui.md +11 -2
  36. package/docs/guide/delegate.md +6 -4
  37. package/docs/guide/recovery.md +4 -0
  38. package/docs/reference/env.md +2 -2
  39. package/package.json +2 -1
  40. package/skills/mu/SKILL.md +12 -2
  41. package/skills/mu/recipes/adversarial-review.md +3 -0
  42. package/skills/mu/recipes/backlog-triage.md +2 -0
  43. package/skills/mu/recipes/findings.md +7 -0
  44. package/skills/mu/recipes/long-run.md +3 -1
  45. package/skills/mu/recipes/loop-until-done.md +3 -1
  46. package/skills/mu/recipes/orchestrator-loop.md +4 -0
  47. package/skills/mu/recipes/ultrathink.md +3 -1
  48. package/skills/mu/recipes/watcher.md +6 -1
  49. package/dist/chunk-IRPTNVJC.js.map +0 -1
  50. package/dist/chunk-PZ5AY32C.js +0 -10
  51. package/dist/chunk-R2SVBZAB.js.map +0 -1
  52. package/dist/chunk-TEGZOXML.js.map +0 -1
  53. package/dist/cli-MDCJEU74.js.map +0 -1
  54. package/dist/tui-LO75XA3O.js +0 -6452
  55. package/dist/tui-LO75XA3O.js.map +0 -1
  56. package/dist/yank-T3AYQTVR.js +0 -12
  57. /package/dist/{chunk-PZ5AY32C.js.map → chunk-3BARPJLY.js.map} +0 -0
  58. /package/dist/{yank-T3AYQTVR.js.map → yank-XDOONQSL.js.map} +0 -0
@@ -0,0 +1,44 @@
1
+ import { createRequire as __muCreateRequire } from "node:module"; const require = __muCreateRequire(import.meta.url);
2
+ var __create = Object.create;
3
+ var __defProp = Object.defineProperty;
4
+ var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
5
+ var __getOwnPropNames = Object.getOwnPropertyNames;
6
+ var __getProtoOf = Object.getPrototypeOf;
7
+ var __hasOwnProp = Object.prototype.hasOwnProperty;
8
+ var __require = /* @__PURE__ */ ((x) => typeof require !== "undefined" ? require : typeof Proxy !== "undefined" ? new Proxy(x, {
9
+ get: (a, b) => (typeof require !== "undefined" ? require : a)[b]
10
+ }) : x)(function(x) {
11
+ if (typeof require !== "undefined") return require.apply(this, arguments);
12
+ throw Error('Dynamic require of "' + x + '" is not supported');
13
+ });
14
+ var __commonJS = (cb, mod) => function __require2() {
15
+ return mod || (0, cb[__getOwnPropNames(cb)[0]])((mod = { exports: {} }).exports, mod), mod.exports;
16
+ };
17
+ var __export = (target, all) => {
18
+ for (var name in all)
19
+ __defProp(target, name, { get: all[name], enumerable: true });
20
+ };
21
+ var __copyProps = (to, from, except, desc) => {
22
+ if (from && typeof from === "object" || typeof from === "function") {
23
+ for (let key of __getOwnPropNames(from))
24
+ if (!__hasOwnProp.call(to, key) && key !== except)
25
+ __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
26
+ }
27
+ return to;
28
+ };
29
+ var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps(
30
+ // If the importer is in node compatibility mode or this is not an ESM
31
+ // file that has been converted to a CommonJS file using a Babel-
32
+ // compatible transform (i.e. "__esModule" has not been set), then set
33
+ // "default" to the CommonJS "module.exports" for node compatibility.
34
+ isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: true }) : target,
35
+ mod
36
+ ));
37
+
38
+ export {
39
+ __require,
40
+ __commonJS,
41
+ __export,
42
+ __toESM
43
+ };
44
+ //# sourceMappingURL=chunk-3BARPJLY.js.map
@@ -1,7 +1,8 @@
1
+ import { createRequire as __muCreateRequire } from "node:module"; const require = __muCreateRequire(import.meta.url);
1
2
  import {
2
3
  defaultStateDir,
3
4
  xdgStateHome
4
- } from "./chunk-L2ABBTYG.js";
5
+ } from "./chunk-WI6AWCMK.js";
5
6
 
6
7
  // src/capture.ts
7
8
  var UNRESOLVED = "<unresolved>";
@@ -768,6 +769,9 @@ CREATE TABLE IF NOT EXISTS sync_peers (
768
769
  -- when ingest read that segment cleanly to its end (src/segments.ts
769
770
  -- segmentCaughtUp). Keyed like sync_peers; a watermark write without a
770
771
  -- clean read deletes the row. A cache: losing it costs one full read.
772
+ -- The value may carry tab-separated resume fields after the key
773
+ -- (src/segment-resume.ts): byte offset and sha256 state for ingest
774
+ -- to read only appended bytes.
771
775
  -- Additive, so no schema bump: an older mu ignores it, and any
772
776
  -- watermark it writes can no longer match a stale fingerprint.
773
777
  CREATE TABLE IF NOT EXISTS sync_fingerprints (
@@ -1788,22 +1792,118 @@ function readManifest(segment) {
1788
1792
  }
1789
1793
 
1790
1794
  // src/segments.ts
1791
- import { createHash as createHash2 } from "crypto";
1795
+ import { createHash as createHash3 } from "crypto";
1792
1796
  import {
1793
1797
  appendFileSync,
1794
- closeSync,
1798
+ closeSync as closeSync2,
1795
1799
  existsSync as existsSync2,
1796
1800
  mkdirSync as mkdirSync2,
1797
- openSync,
1801
+ openSync as openSync2,
1798
1802
  readdirSync,
1799
- readFileSync as readFileSync2,
1800
- readSync,
1801
- statSync,
1803
+ readFileSync as readFileSync3,
1804
+ readSync as readSync2,
1805
+ statSync as statSync2,
1802
1806
  writeFileSync as writeFileSync2
1803
1807
  } from "fs";
1804
1808
  import { tmpdir } from "os";
1805
1809
  import { join as join3, resolve as resolve2, sep } from "path";
1806
1810
  import { crc32 } from "zlib";
1811
+
1812
+ // src/compare.ts
1813
+ function compareStrings(a, b) {
1814
+ return a < b ? -1 : a > b ? 1 : 0;
1815
+ }
1816
+
1817
+ // src/segment-resume.ts
1818
+ import { createHash as createHash2 } from "crypto";
1819
+ import { closeSync, fstatSync, openSync, readFileSync as readFileSync2, readSync, statSync } from "fs";
1820
+ function usableShaState(state, length) {
1821
+ if (typeof state !== "object" || state === null) return null;
1822
+ const { h, n, tail } = state;
1823
+ if (typeof h !== "string" || !/^[0-9a-f]{64}$/.test(h)) return null;
1824
+ if (typeof n !== "number" || !Number.isSafeInteger(n) || n < 0 || n !== length) return null;
1825
+ if (typeof tail !== "string") return null;
1826
+ const raw = Buffer.from(tail, "base64");
1827
+ if (raw.length !== n % 64 || raw.toString("base64") !== tail) return null;
1828
+ return { h, n, tail };
1829
+ }
1830
+ function encodeFingerprint(key, resume) {
1831
+ if (resume === null) return key;
1832
+ const { lines, size, lastHlc, state } = resume;
1833
+ return [key, lines, size, lastHlc, state.h, state.tail].join(" ");
1834
+ }
1835
+ function decodeFingerprint(raw) {
1836
+ const [key = "", lines, size, lastHlc, h, tail] = raw.split(" ");
1837
+ if (h === void 0 || tail === void 0 || lines === void 0 || size === void 0) {
1838
+ return { key, resume: null };
1839
+ }
1840
+ const n = Number(size);
1841
+ const count = Number(lines);
1842
+ if (!Number.isSafeInteger(n) || n <= 0 || !Number.isSafeInteger(count) || count <= 0) {
1843
+ return { key, resume: null };
1844
+ }
1845
+ if (!lastHlc || !/^[0-9a-f]{64}$/.test(h)) return { key, resume: null };
1846
+ return { key, resume: { lines: count, size: n, lastHlc, state: { h, n, tail } } };
1847
+ }
1848
+ function readAppended(path, resume, manifestSha) {
1849
+ let fd;
1850
+ try {
1851
+ fd = openSync(path, "r");
1852
+ } catch {
1853
+ return null;
1854
+ }
1855
+ try {
1856
+ const size = fstatSync(fd).size;
1857
+ if (size <= resume.size) return null;
1858
+ const bytes = Buffer.alloc(size - resume.size);
1859
+ for (let got = 0; got < bytes.length; ) {
1860
+ const n = readSync(fd, bytes, got, bytes.length - got, resume.size + got);
1861
+ if (n === 0) return null;
1862
+ got += n;
1863
+ }
1864
+ const state = sha256Update(resume.state, bytes);
1865
+ return sha256Digest(state) === manifestSha ? { bytes, state } : null;
1866
+ } finally {
1867
+ closeSync(fd);
1868
+ }
1869
+ }
1870
+ function segmentFingerprint(path) {
1871
+ try {
1872
+ const { size, mtimeMs } = statSync(path);
1873
+ const manifest = readFileSync2(manifestPath(path));
1874
+ const sha = createHash2("sha256").update(manifest).digest("hex");
1875
+ let count = null;
1876
+ let parsed = null;
1877
+ try {
1878
+ parsed = JSON.parse(manifest.toString("utf8"));
1879
+ count = parsed?.count;
1880
+ } catch {
1881
+ }
1882
+ return { key: `${size} ${mtimeMs} ${sha}`, count, manifest: parsed };
1883
+ } catch {
1884
+ return null;
1885
+ }
1886
+ }
1887
+ function recordedFingerprint(db, watermarkKey) {
1888
+ const row = prepareCached(
1889
+ db,
1890
+ "SELECT fingerprint FROM sync_fingerprints WHERE machine_id = ?"
1891
+ ).get(watermarkKey);
1892
+ return row?.fingerprint ?? null;
1893
+ }
1894
+ function segmentCaughtUp(db, watermarkKey, path, lines) {
1895
+ const recorded = recordedFingerprint(db, watermarkKey);
1896
+ if (recorded === null) return false;
1897
+ const now = segmentFingerprint(path);
1898
+ return now !== null && now.count === lines && now.key === decodeFingerprint(recorded).key;
1899
+ }
1900
+ function resumePoint(db, watermarkKey, lines) {
1901
+ const recorded = recordedFingerprint(db, watermarkKey);
1902
+ const resume = recorded === null ? null : decodeFingerprint(recorded).resume;
1903
+ return resume !== null && resume.lines === lines ? resume : null;
1904
+ }
1905
+
1906
+ // src/segments.ts
1807
1907
  var SEGMENT_FORMAT_VERSION = 1;
1808
1908
  var SEGMENT_EXT2 = ".jsonl";
1809
1909
  function syncDir() {
@@ -1983,7 +2083,7 @@ async function flushSegment(db, dir = syncDir(), opts) {
1983
2083
  };
1984
2084
  }
1985
2085
  }
1986
- const lockName = createHash2("sha256").update(`${dir}${machineId}`).digest("hex").slice(0, 16);
2086
+ const lockName = createHash3("sha256").update(`${dir}${machineId}`).digest("hex").slice(0, 16);
1987
2087
  return withFileLock(
1988
2088
  join3(locksDir(), `segment-${lockName}.lock`),
1989
2089
  `segment:${machineId}`,
@@ -2105,7 +2205,7 @@ function trustedTail(path, machineId) {
2105
2205
  const { count, lastHlc, size, mtimeMs, shaState } = m;
2106
2206
  let stat2;
2107
2207
  try {
2108
- stat2 = statSync(path);
2208
+ stat2 = statSync2(path);
2109
2209
  } catch {
2110
2210
  return null;
2111
2211
  }
@@ -2119,17 +2219,17 @@ function trustedTail(path, machineId) {
2119
2219
  }
2120
2220
  function readLastLine(path, size) {
2121
2221
  if (size === 0) return null;
2122
- const fd = openSync(path, "r");
2222
+ const fd = openSync2(path, "r");
2123
2223
  try {
2124
2224
  const last = Buffer.alloc(1);
2125
- readSync(fd, last, 0, 1, size - 1);
2225
+ readSync2(fd, last, 0, 1, size - 1);
2126
2226
  if (last[0] !== 10) return null;
2127
2227
  const chunks = [];
2128
2228
  let end = size - 1;
2129
2229
  while (end > 0) {
2130
2230
  const start = Math.max(0, end - 64 * 1024);
2131
2231
  const buf = Buffer.alloc(end - start);
2132
- readSync(fd, buf, 0, buf.length, start);
2232
+ readSync2(fd, buf, 0, buf.length, start);
2133
2233
  const nl = buf.lastIndexOf(10);
2134
2234
  if (nl >= 0) {
2135
2235
  chunks.unshift(buf.subarray(nl + 1));
@@ -2140,43 +2240,15 @@ function readLastLine(path, size) {
2140
2240
  }
2141
2241
  return Buffer.concat(chunks).toString("utf8");
2142
2242
  } finally {
2143
- closeSync(fd);
2144
- }
2145
- }
2146
- function segmentFingerprint(path) {
2147
- try {
2148
- const { size, mtimeMs } = statSync(path);
2149
- const manifest = readFileSync2(manifestPath(path));
2150
- const sha = createHash2("sha256").update(manifest).digest("hex");
2151
- let count = null;
2152
- try {
2153
- count = JSON.parse(manifest.toString("utf8")).count;
2154
- } catch {
2155
- }
2156
- return { key: `${size} ${mtimeMs} ${sha}`, count };
2157
- } catch {
2158
- return null;
2243
+ closeSync2(fd);
2159
2244
  }
2160
2245
  }
2161
- function recordedFingerprint(db, watermarkKey) {
2162
- const row = prepareCached(
2163
- db,
2164
- "SELECT fingerprint FROM sync_fingerprints WHERE machine_id = ?"
2165
- ).get(watermarkKey);
2166
- return row?.fingerprint ?? null;
2167
- }
2168
- function segmentCaughtUp(db, watermarkKey, path, lines) {
2169
- const recorded = recordedFingerprint(db, watermarkKey);
2170
- if (recorded === null) return false;
2171
- const now = segmentFingerprint(path);
2172
- return now !== null && now.count === lines && now.key === recorded;
2173
- }
2174
2246
  function segmentLineCount(path) {
2175
2247
  return readSegmentTail(path).count;
2176
2248
  }
2177
2249
  function readSegmentTail(path) {
2178
2250
  if (!existsSync2(path)) return { count: 0, lastHlc: null, goodLines: [], defect: null };
2179
- const lines = segmentLines(readFileSync2(path, "utf8"));
2251
+ const lines = segmentLines(readFileSync3(path, "utf8"));
2180
2252
  let lastHlc = null;
2181
2253
  let count = 0;
2182
2254
  let defect = null;
@@ -2203,14 +2275,14 @@ function segmentLines(raw) {
2203
2275
  return lines;
2204
2276
  }
2205
2277
  function writeManifest(path, machine, count, lastHlc, incremental) {
2206
- let stat2 = statSync(path);
2278
+ let stat2 = statSync2(path);
2207
2279
  let shaState;
2208
2280
  if (incremental !== null && stat2.size === incremental.size + incremental.appended.length) {
2209
2281
  shaState = sha256Update(incremental.state, incremental.appended);
2210
2282
  } else {
2211
- const bytes = readFileSync2(path);
2283
+ const bytes = readFileSync3(path);
2212
2284
  shaState = sha256Update(sha256Initial(), bytes);
2213
- stat2 = statSync(path);
2285
+ stat2 = statSync2(path);
2214
2286
  }
2215
2287
  writeManifestFile(path, {
2216
2288
  v: SEGMENT_FORMAT_VERSION,
@@ -2227,11 +2299,14 @@ function verifyAgainstManifest(segment) {
2227
2299
  const manifest = readManifest(segment);
2228
2300
  if (manifest === null) return { ok: true };
2229
2301
  if (!existsSync2(segment)) return { ok: false, reason: "segment missing but manifest present" };
2230
- const sha = createHash2("sha256").update(readFileSync2(segment)).digest("hex");
2231
- if (sha === manifest.sha256) return { ok: true };
2302
+ return checkBytesAgainstManifest(segment, manifest, readFileSync3(segment));
2303
+ }
2304
+ function checkBytesAgainstManifest(segment, manifest, bytes) {
2305
+ const sha = createHash3("sha256").update(bytes).digest("hex");
2306
+ if (sha === manifest.sha256) return { ok: true, exact: true };
2232
2307
  const tail = readSegmentTail(segment);
2233
2308
  if (tail.count >= manifest.count) {
2234
- return { ok: true };
2309
+ return { ok: true, exact: false };
2235
2310
  }
2236
2311
  return {
2237
2312
  ok: false,
@@ -2250,13 +2325,13 @@ function discoverPeers(dir, selfMachineId) {
2250
2325
  if (machineId === selfMachineId && !conflictCopy) continue;
2251
2326
  const path = join3(dir, name);
2252
2327
  try {
2253
- if (!statSync(path).isFile()) continue;
2328
+ if (!statSync2(path).isFile()) continue;
2254
2329
  } catch {
2255
2330
  continue;
2256
2331
  }
2257
2332
  peers.push({ machineId, watermarkKey: conflictCopy ? stem : machineId, path, conflictCopy });
2258
2333
  }
2259
- return peers.sort((a, b) => a.path.localeCompare(b.path));
2334
+ return peers.sort((a, b) => compareStrings(a.path, b.path));
2260
2335
  }
2261
2336
  function peerWatermarkKey(peer) {
2262
2337
  return peer.watermarkKey ?? peer.machineId;
@@ -2304,52 +2379,68 @@ function ingestSegment(db, peer, opts) {
2304
2379
  const defects = [];
2305
2380
  const watermarkKey = peerWatermarkKey(peer);
2306
2381
  const start = getWatermark(db, watermarkKey);
2307
- if (opts?.verify !== true && segmentCaughtUp(db, watermarkKey, peer.path, start)) {
2308
- return {
2309
- machineId: peer.machineId,
2310
- path: peer.path,
2311
- read: 0,
2312
- applied: 0,
2313
- changed: 0,
2314
- watermark: start,
2315
- defects,
2316
- truncatedAt: null
2317
- };
2318
- }
2319
- if (!existsSync2(peer.path)) {
2320
- return {
2321
- machineId: peer.machineId,
2322
- path: peer.path,
2323
- read: 0,
2324
- applied: 0,
2325
- changed: 0,
2326
- watermark: start,
2327
- defects,
2328
- truncatedAt: null
2329
- };
2330
- }
2382
+ const nothing = {
2383
+ machineId: peer.machineId,
2384
+ path: peer.path,
2385
+ read: 0,
2386
+ applied: 0,
2387
+ changed: 0,
2388
+ watermark: start,
2389
+ defects,
2390
+ truncatedAt: null
2391
+ };
2392
+ if (opts?.verify !== true && segmentCaughtUp(db, watermarkKey, peer.path, start)) return nothing;
2393
+ if (!existsSync2(peer.path)) return nothing;
2331
2394
  const fingerprint = segmentFingerprint(peer.path);
2332
- const verified = verifyAgainstManifest(peer.path);
2333
- if (!verified.ok) {
2334
- defects.push({ kind: "manifest-mismatch", line: 0, detail: verified.reason });
2395
+ const resume = opts?.verify !== true && fingerprint?.manifest != null && start > 0 ? resumePoint(db, watermarkKey, start) : null;
2396
+ const appended = resume !== null && fingerprint?.manifest != null ? readAppended(peer.path, resume, fingerprint.manifest.sha256) : null;
2397
+ let lines;
2398
+ let base;
2399
+ let seedHlc = null;
2400
+ let nextResume = null;
2401
+ let resumeState = null;
2402
+ let resumeSize = 0;
2403
+ if (resume !== null && appended !== null) {
2404
+ lines = segmentLines(appended.bytes.toString("utf8"));
2405
+ base = resume.lines;
2406
+ seedHlc = resume.lastHlc;
2407
+ resumeState = appended.bytes[appended.bytes.length - 1] === 10 ? appended.state : null;
2408
+ resumeSize = appended.state.n;
2409
+ } else {
2410
+ const manifest = readManifest(peer.path);
2411
+ const bytes = readFileSync3(peer.path);
2412
+ if (manifest !== null) {
2413
+ const verified = checkBytesAgainstManifest(peer.path, manifest, bytes);
2414
+ if (!verified.ok) {
2415
+ defects.push({ kind: "manifest-mismatch", line: 0, detail: verified.reason });
2416
+ } else if (verified.exact) {
2417
+ const state = usableShaState(manifest.shaState, bytes.length);
2418
+ if (state !== null && bytes[bytes.length - 1] === 10 && sha256Digest(state) === manifest.sha256) {
2419
+ resumeState = state;
2420
+ resumeSize = bytes.length;
2421
+ }
2422
+ }
2423
+ }
2424
+ lines = segmentLines(bytes.toString("utf8"));
2425
+ base = 0;
2426
+ if (start > 0 && start <= lines.length) {
2427
+ const prior = lines[start - 1];
2428
+ if (prior !== void 0) {
2429
+ const decoded = decodeLine(prior);
2430
+ if (decoded.ok) seedHlc = decoded.line.hlc;
2431
+ }
2432
+ }
2335
2433
  }
2336
- const lines = segmentLines(readFileSync2(peer.path, "utf8"));
2434
+ const total = base + lines.length;
2337
2435
  let applied = 0;
2338
2436
  let changed = 0;
2339
2437
  let watermark = start;
2340
2438
  let truncatedAt = null;
2341
- let previousHlc = null;
2342
- if (start > 0 && start <= lines.length) {
2343
- const prior = lines[start - 1];
2344
- if (prior !== void 0) {
2345
- const decoded = decodeLine(prior);
2346
- if (decoded.ok) previousHlc = decoded.line.hlc;
2347
- }
2348
- }
2439
+ let previousHlc = seedHlc;
2349
2440
  const run = db.transaction(() => {
2350
- for (let index = start; index < lines.length; index++) {
2441
+ for (let index = start - base; index < lines.length; index++) {
2351
2442
  const raw = lines[index];
2352
- const lineNo = index + 1;
2443
+ const lineNo = base + index + 1;
2353
2444
  if (raw === void 0 || raw.trim() === "") {
2354
2445
  defects.push({ kind: "malformed-shape", line: lineNo, detail: "blank line" });
2355
2446
  truncatedAt = lineNo;
@@ -2415,8 +2506,16 @@ function ingestSegment(db, peer, opts) {
2415
2506
  previousHlc = op.hlc;
2416
2507
  watermark = lineNo;
2417
2508
  }
2418
- const clean = defects.length === 0 && watermark === lines.length;
2419
- setWatermark(db, watermarkKey, watermark, clean ? fingerprint?.key ?? null : null);
2509
+ const clean = defects.length === 0 && watermark === total;
2510
+ if (clean && resumeState !== null && previousHlc !== null) {
2511
+ nextResume = { lines: total, size: resumeSize, lastHlc: previousHlc, state: resumeState };
2512
+ }
2513
+ setWatermark(
2514
+ db,
2515
+ watermarkKey,
2516
+ watermark,
2517
+ clean && fingerprint !== null ? encodeFingerprint(fingerprint.key, nextResume) : null
2518
+ );
2420
2519
  });
2421
2520
  run.immediate();
2422
2521
  return {
@@ -2491,7 +2590,7 @@ async function syncPass(db, dir = syncDir()) {
2491
2590
  }
2492
2591
 
2493
2592
  // src/sync.ts
2494
- import { existsSync as existsSync3, statSync as statSync2 } from "fs";
2593
+ import { existsSync as existsSync3, statSync as statSync3 } from "fs";
2495
2594
  import Database2 from "better-sqlite3";
2496
2595
  var SyncPeerNotFoundError = class extends Error {
2497
2596
  constructor(ref, known) {
@@ -2533,7 +2632,7 @@ function peerStatuses(db, dir) {
2533
2632
  const rows = discoverPeers(dir, self).map((peer) => {
2534
2633
  let lastSeenMs = null;
2535
2634
  try {
2536
- lastSeenMs = statSync2(peer.path).mtimeMs;
2635
+ lastSeenMs = statSync3(peer.path).mtimeMs;
2537
2636
  } catch {
2538
2637
  lastSeenMs = null;
2539
2638
  }
@@ -2775,6 +2874,7 @@ export {
2775
2874
  repairTaskPair,
2776
2875
  applyOp,
2777
2876
  applyOps,
2877
+ compareStrings,
2778
2878
  readManifest,
2779
2879
  SEGMENT_FORMAT_VERSION,
2780
2880
  syncDir,
@@ -2805,4 +2905,4 @@ export {
2805
2905
  ingestFromDb,
2806
2906
  transportNextSteps
2807
2907
  };
2808
- //# sourceMappingURL=chunk-R2SVBZAB.js.map
2908
+ //# sourceMappingURL=chunk-45KQLMEL.js.map