wiki-graph-sdk 0.8.4 → 0.9.1

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 (51) hide show
  1. package/dist/archives.cjs +345 -152
  2. package/dist/archives.cjs.map +1 -1
  3. package/dist/archives.js +356 -157
  4. package/dist/archives.js.map +1 -1
  5. package/dist/conversions.cjs +269 -99
  6. package/dist/conversions.cjs.map +1 -1
  7. package/dist/conversions.js +275 -103
  8. package/dist/conversions.js.map +1 -1
  9. package/dist/default-worker.cjs +278 -108
  10. package/dist/default-worker.cjs.map +1 -1
  11. package/dist/default-worker.js +285 -112
  12. package/dist/default-worker.js.map +1 -1
  13. package/dist/embedding.cjs +214 -54
  14. package/dist/embedding.cjs.map +1 -1
  15. package/dist/embedding.js +214 -54
  16. package/dist/embedding.js.map +1 -1
  17. package/dist/gc.cjs +214 -54
  18. package/dist/gc.cjs.map +1 -1
  19. package/dist/gc.js +214 -54
  20. package/dist/gc.js.map +1 -1
  21. package/dist/index.cjs +442 -226
  22. package/dist/index.cjs.map +1 -1
  23. package/dist/index.d.ts +1 -1
  24. package/dist/index.js +461 -236
  25. package/dist/index.js.map +1 -1
  26. package/dist/local-config.cjs +214 -54
  27. package/dist/local-config.cjs.map +1 -1
  28. package/dist/local-config.js +214 -54
  29. package/dist/local-config.js.map +1 -1
  30. package/dist/maintenance.cjs +265 -97
  31. package/dist/maintenance.cjs.map +1 -1
  32. package/dist/maintenance.js +271 -101
  33. package/dist/maintenance.js.map +1 -1
  34. package/dist/node-platform.cjs +214 -54
  35. package/dist/node-platform.cjs.map +1 -1
  36. package/dist/node-platform.d.ts +2 -0
  37. package/dist/node-platform.js +214 -54
  38. package/dist/node-platform.js.map +1 -1
  39. package/dist/runtime-config.cjs +214 -54
  40. package/dist/runtime-config.cjs.map +1 -1
  41. package/dist/runtime-config.js +214 -54
  42. package/dist/runtime-config.js.map +1 -1
  43. package/dist/stage.cjs +214 -54
  44. package/dist/stage.cjs.map +1 -1
  45. package/dist/stage.js +214 -54
  46. package/dist/stage.js.map +1 -1
  47. package/dist/worker.cjs +277 -103
  48. package/dist/worker.cjs.map +1 -1
  49. package/dist/worker.js +284 -107
  50. package/dist/worker.js.map +1 -1
  51. package/package.json +2 -2
package/dist/index.js CHANGED
@@ -11,7 +11,9 @@ import { Readable as Readable2 } from "stream";
11
11
  import {
12
12
  addChapter,
13
13
  applyChapterTree,
14
- assertArchiveIndexArtifactsReady,
14
+ assertArchiveQueryReady,
15
+ resolveIndexedArchiveChapterScope,
16
+ ensureWikiGraphArchiveSchemaCurrent,
15
17
  assertNoActiveBuildJobConflicts,
16
18
  assertNoActiveBuildJobs,
17
19
  deleteArchiveSearchSessions,
@@ -43,6 +45,7 @@ import {
43
45
  getChapterTree,
44
46
  WikiGraph as WikiGraph2,
45
47
  WikiGraphArchiveFile as WikiGraphArchiveFile2,
48
+ WikiGraphDirectoryFile as WikiGraphDirectoryFile2,
46
49
  TOC_FILE_VERSION,
47
50
  writeWikgArchive,
48
51
  ObjectMetadataKind
@@ -161,6 +164,15 @@ var NodeFile = class {
161
164
  this.name = name;
162
165
  }
163
166
  path;
167
+ async getPhysicalIdentity() {
168
+ const value = await fsPromises.stat(this.path).catch((error) => {
169
+ if (typeof error === "object" && error !== null && "code" in error && error.code === "ENOENT")
170
+ return void 0;
171
+ throw error;
172
+ });
173
+ if (value === void 0) return void 0;
174
+ return `${value.dev}:${value.ino}`;
175
+ }
164
176
  kind = "file";
165
177
  [NODE_RESOURCE_KIND] = "file";
166
178
  identity;
@@ -285,6 +297,15 @@ var NodeDirectory = class _NodeDirectory {
285
297
  this.name = pathModule.basename(path);
286
298
  }
287
299
  path;
300
+ async getPhysicalIdentity() {
301
+ const value = await fsPromises.stat(this.path).catch((error) => {
302
+ if (typeof error === "object" && error !== null && "code" in error && error.code === "ENOENT")
303
+ return void 0;
304
+ throw error;
305
+ });
306
+ if (value === void 0) return void 0;
307
+ return `${value.dev}:${value.ino}`;
308
+ }
288
309
  kind = "directory";
289
310
  [NODE_RESOURCE_KIND] = "directory";
290
311
  identity;
@@ -294,8 +315,10 @@ var NodeDirectory = class _NodeDirectory {
294
315
  const file = new NodeFile(pathModule.join(this.path, name));
295
316
  try {
296
317
  return (await fsPromises.stat(file.path)).isFile() ? file : void 0;
297
- } catch {
298
- return void 0;
318
+ } catch (error) {
319
+ if (typeof error === "object" && error !== null && "code" in error && (error.code === "ENOENT" || error.code === "ENOTDIR"))
320
+ return void 0;
321
+ throw error;
299
322
  }
300
323
  }
301
324
  async getLastModified() {
@@ -313,8 +336,10 @@ var NodeDirectory = class _NodeDirectory {
313
336
  const directory = new _NodeDirectory(pathModule.join(this.path, name));
314
337
  try {
315
338
  return (await fsPromises.stat(directory.path)).isDirectory() ? directory : void 0;
316
- } catch {
317
- return void 0;
339
+ } catch (error) {
340
+ if (typeof error === "object" && error !== null && "code" in error && (error.code === "ENOENT" || error.code === "ENOTDIR"))
341
+ return void 0;
342
+ throw error;
318
343
  }
319
344
  }
320
345
  async list() {
@@ -438,14 +463,23 @@ async function openNativeNodeDatabase(file, flags) {
438
463
  });
439
464
  });
440
465
  }
441
- async function openNodeZip(file) {
466
+ async function openNodeZip(file, options = {}) {
442
467
  const path = getBrandedNodeResourcePath(file, "file");
443
468
  if (path === void 0) {
444
469
  throw new TypeError("The Node ZIP adapter requires a NodeFile");
445
470
  }
446
- const zipFile = await new Promise((resolve4, reject) => {
447
- yauzl.open(
448
- path,
471
+ const handle = await fsPromises.open(path, "r");
472
+ let size;
473
+ try {
474
+ size = (await handle.stat()).size;
475
+ } catch (error) {
476
+ await handle.close();
477
+ throw error;
478
+ }
479
+ const open2 = () => new Promise((resolve4, reject) => {
480
+ yauzl.fromRandomAccessReader(
481
+ new NodeZipSource(handle),
482
+ size,
449
483
  { autoClose: false, lazyEntries: true },
450
484
  (error, opened) => {
451
485
  if (error || opened === void 0)
@@ -454,63 +488,192 @@ async function openNodeZip(file) {
454
488
  }
455
489
  );
456
490
  });
457
- const entries = await new Promise(
458
- (resolve4, reject) => {
459
- const discovered = /* @__PURE__ */ new Map();
460
- const rejectAndClose = (error) => {
461
- zipFile.close();
462
- reject(
463
- error instanceof Error ? error : new Error("Cannot scan ZIP central directory")
464
- );
465
- };
466
- const resolveEntries = () => {
467
- zipFile.off("error", rejectAndClose);
468
- resolve4(discovered);
469
- };
470
- zipFile.on("entry", (entry) => {
471
- if (!entry.fileName.endsWith("/")) {
472
- discovered.set(entry.fileName, entry);
473
- }
474
- zipFile.readEntry();
475
- });
476
- zipFile.once("error", rejectAndClose);
477
- zipFile.once("end", resolveEntries);
478
- zipFile.readEntry();
479
- }
480
- );
491
+ try {
492
+ (await open2()).close();
493
+ } catch (error) {
494
+ await handle.close();
495
+ throw error;
496
+ }
481
497
  let closed = false;
498
+ let pending = Promise.resolve();
499
+ let closing;
500
+ const run = (operation) => {
501
+ if (closed)
502
+ return Promise.reject(new Error("Cannot read a closed ZIP archive"));
503
+ const result = pending.then(async () => {
504
+ const zip = await open2();
505
+ try {
506
+ return await operation(zip);
507
+ } finally {
508
+ zip.close();
509
+ }
510
+ });
511
+ pending = result.then(
512
+ () => void 0,
513
+ () => void 0
514
+ );
515
+ return result;
516
+ };
517
+ const withEntry = (name, operation) => run(async (zip) => {
518
+ let exact;
519
+ let alias;
520
+ let aliasCollision = false;
521
+ await scanNodeZip(zip, (entry) => {
522
+ if (entry.fileName === name) exact = entry;
523
+ if (normalizeNodeZipName(entry.fileName) === name) {
524
+ if (alias !== void 0 && alias.fileName !== entry.fileName)
525
+ aliasCollision = true;
526
+ alias = entry;
527
+ }
528
+ });
529
+ if ((exact === void 0 || options.entryNameMode === "normalized") && aliasCollision) {
530
+ let bestPosition = -1;
531
+ const candidates = await open2();
532
+ try {
533
+ await scanNodeZip(candidates, async (entry) => {
534
+ if (normalizeNodeZipName(entry.fileName) !== name) return;
535
+ const probe = await open2();
536
+ let position = 0;
537
+ try {
538
+ await scanNodeZip(probe, (candidate) => {
539
+ if (candidate.fileName === entry.fileName) return false;
540
+ position++;
541
+ });
542
+ } finally {
543
+ probe.close();
544
+ }
545
+ if (position >= bestPosition) {
546
+ bestPosition = position;
547
+ alias = entry;
548
+ }
549
+ });
550
+ return await operation(candidates, alias);
551
+ } finally {
552
+ candidates.close();
553
+ }
554
+ }
555
+ return await operation(
556
+ zip,
557
+ options.entryNameMode === "normalized" ? alias : exact ?? alias
558
+ );
559
+ });
482
560
  return {
483
561
  close: () => {
484
- if (!closed) zipFile.close();
485
562
  closed = true;
486
- return Promise.resolve();
563
+ closing ??= pending.then(() => handle.close());
564
+ return closing;
487
565
  },
488
- copyEntry: async (name, target) => {
489
- if (closed) throw new Error("Cannot read a closed ZIP archive");
490
- const entry = entries.get(name);
566
+ copyEntry: (name, target) => withEntry(name, async (zip, entry) => {
491
567
  if (entry === void 0) return false;
492
- await copyNodeZipEntry(zipFile, entry, target);
568
+ await copyNodeZipEntry(zip, entry, target);
493
569
  return true;
494
- },
495
- getEntrySize: (name) => {
496
- if (closed) throw new Error("Cannot read a closed ZIP archive");
497
- return Promise.resolve(entries.get(name)?.uncompressedSize);
498
- },
499
- listEntries: () => Promise.resolve([...entries.keys()]),
500
- readEntryRange: async (name, offset, length) => {
501
- if (closed) throw new Error("Cannot read a closed ZIP archive");
502
- const entry = entries.get(name);
570
+ }),
571
+ getEntrySize: (name) => withEntry(
572
+ name,
573
+ (_zip, entry) => Promise.resolve(entry?.uncompressedSize)
574
+ ),
575
+ listEntries: () => run(async (zip) => {
576
+ const names = /* @__PURE__ */ new Set();
577
+ await scanNodeZip(zip, (entry) => {
578
+ names.add(entry.fileName);
579
+ });
580
+ return [...names];
581
+ }),
582
+ readEntryRange: (name, offset, length) => withEntry(name, async (zip, entry) => {
503
583
  if (entry === void 0) return void 0;
504
- return await readNodeZipEntryRange(zipFile, entry, offset, length);
505
- },
506
- readEntry: async (name) => {
507
- if (closed) throw new Error("Cannot read a closed ZIP archive");
508
- const entry = entries.get(name);
584
+ return await readNodeZipEntryRange(zip, entry, offset, length);
585
+ }),
586
+ readEntry: (name) => withEntry(name, async (zip, entry) => {
509
587
  if (entry === void 0) return void 0;
510
- return await readNodeZipEntry(zipFile, entry);
511
- }
588
+ return await readNodeZipEntry(zip, entry);
589
+ })
512
590
  };
513
591
  }
592
+ var NodeZipSource = class extends yauzl.RandomAccessReader {
593
+ constructor(handle) {
594
+ super();
595
+ this.handle = handle;
596
+ }
597
+ handle;
598
+ read(buffer, offset, length, position, callback) {
599
+ const read2 = (written) => {
600
+ if (written === length) {
601
+ callback(null);
602
+ return;
603
+ }
604
+ fs.read(
605
+ this.handle.fd,
606
+ buffer,
607
+ offset + written,
608
+ length - written,
609
+ position + written,
610
+ (error, bytesRead) => {
611
+ if (error) callback(error);
612
+ else if (bytesRead === 0)
613
+ callback(new Error("Unexpected end of ZIP file"));
614
+ else read2(written + bytesRead);
615
+ }
616
+ );
617
+ };
618
+ read2(0);
619
+ }
620
+ _readStreamForRange(start, end) {
621
+ const handle = this.handle;
622
+ return Readable.from(
623
+ (async function* () {
624
+ for (let position = start; position < end; ) {
625
+ const buffer = Buffer.allocUnsafe(
626
+ Math.min(64 * 1024, end - position)
627
+ );
628
+ const { bytesRead } = await handle.read(
629
+ buffer,
630
+ 0,
631
+ buffer.length,
632
+ position
633
+ );
634
+ if (bytesRead === 0) return;
635
+ position += bytesRead;
636
+ yield buffer.subarray(0, bytesRead);
637
+ }
638
+ })()
639
+ );
640
+ }
641
+ };
642
+ function normalizeNodeZipName(name) {
643
+ const normalized = name.replaceAll("\\", "/").trim().split("/").filter((part) => part !== "" && part !== ".").join("/");
644
+ return normalized.split("/").includes("..") ? void 0 : normalized;
645
+ }
646
+ async function scanNodeZip(zip, visit) {
647
+ await new Promise((resolve4, reject) => {
648
+ const cleanup = () => {
649
+ zip.off("entry", onEntry);
650
+ zip.off("end", onEnd);
651
+ zip.off("error", onError);
652
+ };
653
+ const onError = (error) => {
654
+ cleanup();
655
+ reject(error);
656
+ };
657
+ const onEnd = () => {
658
+ cleanup();
659
+ resolve4();
660
+ };
661
+ const onEntry = (entry) => {
662
+ void Promise.resolve().then(() => entry.fileName.endsWith("/") ? void 0 : visit(entry)).then((keepReading) => {
663
+ if (keepReading === false) onEnd();
664
+ else zip.readEntry();
665
+ }).catch(
666
+ (error) => onError(
667
+ error instanceof Error ? error : new Error("Cannot scan ZIP", { cause: error })
668
+ )
669
+ );
670
+ };
671
+ zip.on("entry", onEntry);
672
+ zip.once("end", onEnd);
673
+ zip.once("error", onError);
674
+ zip.readEntry();
675
+ });
676
+ }
514
677
  async function copyNodeZipEntry(zipFile, entry, target) {
515
678
  const writer = await target.openWriter();
516
679
  try {
@@ -1409,17 +1572,32 @@ function resolveWikiGraphRuntimePath(path) {
1409
1572
 
1410
1573
  // src/archive/target.ts
1411
1574
  import { realpath, stat as stat2 } from "fs/promises";
1412
- import { basename as basename2, dirname as dirname2, isAbsolute as isAbsolute3, join as join3, relative, resolve as resolve3 } from "path";
1575
+ import { basename as basename2, dirname as dirname2, join as join3, resolve as resolve3 } from "path";
1413
1576
  import {
1414
1577
  formatLocatedWikiGraphUri,
1415
1578
  formatWikiGraphLibraryUri,
1416
- listWikiGraphLibraries,
1417
- listWikiGraphLibraryArchives,
1579
+ findWikiGraphLibraryByPhysicalIdentity,
1580
+ findWikiGraphLibraryArchivePhysicalAliases,
1418
1581
  parseLocatedWikiGraphUri,
1419
1582
  parseWikiGraphLibraryUri,
1420
1583
  resolveWikiGraphLibrary,
1421
- resolveWikiGraphLibraryArchiveFile
1584
+ resolveWikiGraphLibraryArchiveFile,
1585
+ isWikiGraphSchemaVersionError,
1586
+ WikiGraphSchemaVersionError
1422
1587
  } from "wiki-graph-core";
1588
+ function rethrowArchiveSchemaError(error, target) {
1589
+ if (isWikiGraphSchemaVersionError(error) && error.target.kind === "archive") {
1590
+ throw new WikiGraphSchemaVersionError(
1591
+ target.kind === "standalone" ? { kind: "archive", path: resolveWikiGraphRuntimePath(target.path) } : { kind: "library", uri: target.uri.split("/arc/")[0] },
1592
+ error.actualVersion,
1593
+ error.supportedVersion
1594
+ );
1595
+ }
1596
+ throw error;
1597
+ }
1598
+ function requireWikiGraphArchiveFile(location) {
1599
+ return location.archiveFile;
1600
+ }
1423
1601
  var WikiGraphArchiveOwnershipError = class extends Error {
1424
1602
  code = "WIKI_GRAPH_ARCHIVE_OWNERSHIP_MISMATCH";
1425
1603
  constructor(message) {
@@ -1437,12 +1615,7 @@ async function assertStandaloneWikiGraphArchivePath(inputPath) {
1437
1615
  const path = resolveWikiGraphRuntimePath(inputPath);
1438
1616
  const candidate = await canonicalPath(path);
1439
1617
  const candidateIdentity = await readFileIdentity(path);
1440
- const libraries = await listWikiGraphLibraries();
1441
- const matches = await findMatchingMembers(
1442
- libraries,
1443
- candidate,
1444
- candidateIdentity
1445
- );
1618
+ const matches = await findMatchingMembers(candidate, candidateIdentity);
1446
1619
  if (matches.length > 0) {
1447
1620
  const match = requireUnambiguousManagedMatch(path, matches);
1448
1621
  throw new WikiGraphArchiveOwnershipError(
@@ -1451,15 +1624,26 @@ async function assertStandaloneWikiGraphArchivePath(inputPath) {
1451
1624
  )}: ${path}. Use the library UUID URI ${match.archive.uri} instead.`
1452
1625
  );
1453
1626
  }
1454
- for (const library of libraries) {
1455
- const rootPath = getNodeResourcePath(library.folder);
1456
- const root = await canonicalPath(rootPath);
1457
- if (!isWithin(root, candidate)) continue;
1458
- throw new WikiGraphArchiveOwnershipError(
1459
- `Standalone archive path belongs to registered library ${formatWikiGraphLibraryUri(
1460
- library.isDefault ? void 0 : library.publicId
1461
- )}: ${path}. Scan the library, then address the archive by its library UUID URI.`
1627
+ const ancestors = /* @__PURE__ */ new Set();
1628
+ for (const start of [candidate, resolve3(path)]) {
1629
+ for (let parent = dirname2(start); ; parent = dirname2(parent)) {
1630
+ ancestors.add(parent);
1631
+ if (dirname2(parent) === parent) break;
1632
+ }
1633
+ }
1634
+ for (const parent of ancestors) {
1635
+ const identity = await readFileIdentity(parent);
1636
+ const library = await findWikiGraphLibraryByPhysicalIdentity(
1637
+ identity,
1638
+ new NodeDirectory(parent).identity
1462
1639
  );
1640
+ if (library !== void 0) {
1641
+ throw new WikiGraphArchiveOwnershipError(
1642
+ `Standalone archive path belongs to registered library ${formatWikiGraphLibraryUri(
1643
+ library.isDefault ? void 0 : library.publicId
1644
+ )}: ${path}. Scan the library, then address the archive by its library UUID URI.`
1645
+ );
1646
+ }
1463
1647
  }
1464
1648
  return path;
1465
1649
  }
@@ -1477,11 +1661,7 @@ async function resolveWikiGraphArchiveTarget(file) {
1477
1661
  const path = getNodeResourcePath(file);
1478
1662
  const candidate = await canonicalPath(path);
1479
1663
  const candidateIdentity = await readFileIdentity(path);
1480
- const matches = await findMatchingMembers(
1481
- await listWikiGraphLibraries(),
1482
- candidate,
1483
- candidateIdentity
1484
- );
1664
+ const matches = await findMatchingMembers(candidate, candidateIdentity);
1485
1665
  if (matches.length > 0) {
1486
1666
  const match = requireUnambiguousManagedMatch(path, matches);
1487
1667
  return { kind: "library", uri: match.archive.uri };
@@ -1547,47 +1727,35 @@ function withObjectUri(archiveLocator, objectUri) {
1547
1727
  async function canonicalPath(path) {
1548
1728
  try {
1549
1729
  return await realpath(path);
1550
- } catch {
1730
+ } catch (error) {
1731
+ if (!(typeof error === "object" && error !== null && "code" in error && (error.code === "ENOENT" || error.code === "ENOTDIR")))
1732
+ throw error;
1551
1733
  const absolute = resolve3(path);
1552
1734
  const parent = dirname2(absolute);
1553
1735
  return parent === absolute ? absolute : join3(await canonicalPath(parent), basename2(absolute));
1554
1736
  }
1555
1737
  }
1556
- function isWithin(root, candidate) {
1557
- const child = relative(root, candidate);
1558
- return child === "" || !child.startsWith("..") && !isAbsolute3(child);
1559
- }
1560
- async function findMatchingMembers(libraries, candidate, candidateIdentity) {
1738
+ async function findMatchingMembers(candidate, candidateIdentity) {
1739
+ if (candidateIdentity === void 0) return [];
1740
+ const archives = await findWikiGraphLibraryArchivePhysicalAliases(candidateIdentity);
1561
1741
  const members = [];
1562
- for (const library of libraries) {
1563
- const archives = await listWikiGraphLibraryArchives({
1564
- isDefault: library.isDefault,
1565
- kind: "scope",
1566
- ...library.isDefault ? {} : { publicId: library.publicId }
1567
- });
1568
- for (const archive of archives) {
1569
- if (archive.file === void 0) continue;
1742
+ for (const archive of archives) {
1743
+ const parsed = parseWikiGraphLibraryUri(archive.libraryUri);
1744
+ const library = await resolveWikiGraphLibrary(parsed);
1745
+ const physical = archive.file ?? archive.directory;
1746
+ if (library !== void 0 && physical !== void 0)
1570
1747
  members.push({
1571
1748
  archive,
1572
1749
  library,
1573
- memberPath: getNodeResourcePath(archive.file)
1750
+ memberPath: getNodeResourcePath(physical)
1574
1751
  });
1575
- }
1576
1752
  }
1577
1753
  const exact = [];
1578
1754
  for (const member of members) {
1579
- if (await canonicalPath(member.memberPath) === candidate) {
1755
+ if (await canonicalPath(member.memberPath) === candidate)
1580
1756
  exact.push(member);
1581
- }
1582
1757
  }
1583
- if (exact.length > 0 || candidateIdentity === void 0) return exact;
1584
- const identityMatches = [];
1585
- for (const member of members) {
1586
- if (await readFileIdentity(member.memberPath) === candidateIdentity) {
1587
- identityMatches.push(member);
1588
- }
1589
- }
1590
- return identityMatches;
1758
+ return exact.length > 0 ? exact : members;
1591
1759
  }
1592
1760
  function requireUnambiguousManagedMatch(path, matches) {
1593
1761
  if (matches.length === 1) return matches[0];
@@ -1599,8 +1767,10 @@ async function readFileIdentity(path) {
1599
1767
  try {
1600
1768
  const value = await stat2(path);
1601
1769
  return `${value.dev}:${value.ino}`;
1602
- } catch {
1603
- return void 0;
1770
+ } catch (error) {
1771
+ if (typeof error === "object" && error !== null && "code" in error && (error.code === "ENOENT" || error.code === "ENOTDIR"))
1772
+ return void 0;
1773
+ throw error;
1604
1774
  }
1605
1775
  }
1606
1776
 
@@ -1662,11 +1832,15 @@ var WikiGraphConversionManager = class {
1662
1832
  if (!("path" in options.input)) {
1663
1833
  throw new Error("wikg input requires a file path.");
1664
1834
  }
1835
+ const inputPath = options.input.path;
1665
1836
  await app.openSession(
1666
- new NodeFile(
1667
- await assertStandaloneWikiGraphArchivePath(options.input.path)
1668
- ),
1837
+ new NodeFile(await assertStandaloneWikiGraphArchivePath(inputPath)),
1669
1838
  write
1839
+ ).catch(
1840
+ (error) => rethrowArchiveSchemaError(error, {
1841
+ kind: "standalone",
1842
+ path: inputPath
1843
+ })
1670
1844
  );
1671
1845
  } else if ("stream" in options.input) {
1672
1846
  await app.digestTextStreamSession(
@@ -2085,17 +2259,36 @@ function formatLocatedChapterUri(archiveUri, chapter) {
2085
2259
  // src/archive/write.ts
2086
2260
  import {
2087
2261
  WikiGraphArchiveFile,
2262
+ WikiGraphDirectoryFile,
2088
2263
  writeWikiGraphLibraryArchive
2089
2264
  } from "wiki-graph-core";
2090
2265
  async function writeWikiGraphArchiveLocation(location, operation, options = {}) {
2091
2266
  const cacheOnly = options.searchIndexWritebackPolicy === "cache";
2092
- const write = async (archiveFile = location.archiveFile) => await new WikiGraphArchiveFile(archiveFile).write(operation, {
2093
- ...cacheOnly ? {} : { derivedStateKeys: [location.archiveKey, location.archivePath] },
2094
- ...options.invalidateContinuationCursors === void 0 ? {} : {
2095
- invalidateContinuationCursors: options.invalidateContinuationCursors
2096
- },
2097
- ...options.searchIndexWritebackPolicy === void 0 ? {} : { searchIndexWritebackPolicy: options.searchIndexWritebackPolicy }
2098
- });
2267
+ const write = async (archiveFile = location.archiveFile) => {
2268
+ if (cacheOnly) {
2269
+ return await new WikiGraphArchiveFile(archiveFile).readDocument(
2270
+ operation,
2271
+ { searchIndexWritebackPolicy: "cache" }
2272
+ );
2273
+ }
2274
+ const writeOptions = {
2275
+ ...cacheOnly ? {} : { derivedStateKeys: [location.archiveKey, location.archivePath] },
2276
+ ...options.invalidateContinuationCursors === void 0 ? {} : {
2277
+ invalidateContinuationCursors: options.invalidateContinuationCursors
2278
+ },
2279
+ ...options.searchIndexWritebackPolicy === void 0 ? {} : { searchIndexWritebackPolicy: options.searchIndexWritebackPolicy }
2280
+ };
2281
+ if (archiveFile.kind === "directory") {
2282
+ return await new WikiGraphDirectoryFile(archiveFile).write(
2283
+ operation,
2284
+ writeOptions
2285
+ );
2286
+ }
2287
+ return await new WikiGraphArchiveFile(archiveFile).write(
2288
+ operation,
2289
+ writeOptions
2290
+ );
2291
+ };
2099
2292
  if (location.libraryArchiveTarget === void 0 || cacheOnly || options.refreshLibraryIndex === false) {
2100
2293
  return await write();
2101
2294
  }
@@ -2453,10 +2646,15 @@ var WikiGraphArchiveManager = class {
2453
2646
  }, options.signal);
2454
2647
  }
2455
2648
  async open(target, options = {}) {
2456
- const location = await this.#runtime.run(
2457
- async () => await resolveWikiGraphArchiveLocation(target),
2458
- options.signal
2459
- );
2649
+ const location = await this.#runtime.run(async () => {
2650
+ const location2 = await resolveWikiGraphArchiveLocation(target);
2651
+ try {
2652
+ await ensureWikiGraphArchiveSchemaCurrent(location2.archiveFile);
2653
+ } catch (error) {
2654
+ rethrowArchiveSchemaError(error, target);
2655
+ }
2656
+ return location2;
2657
+ }, options.signal);
2460
2658
  return new WikiGraphArchiveHandle(this.#runtime, location);
2461
2659
  }
2462
2660
  };
@@ -2507,15 +2705,11 @@ var WikiGraphArchiveHandle = class {
2507
2705
  options.queryMode,
2508
2706
  options.signal
2509
2707
  );
2510
- const result = await this.#writeDocument(
2708
+ const result = await this.#readDocument(
2511
2709
  async (document) => {
2512
2710
  const chapters = await this.#resolveQueryChapters(document, options, {
2513
2711
  embeddingProvider
2514
2712
  });
2515
- await ensureArchiveSearchIndex(document, {
2516
- ...chapters === void 0 ? {} : { chapters },
2517
- ...embeddingProvider === void 0 ? {} : { embeddingProvider }
2518
- });
2519
2713
  return await findArchiveObjects(document, query, {
2520
2714
  ...withoutOperationAndScope(options),
2521
2715
  archiveKey: this.archiveKey,
@@ -2524,7 +2718,6 @@ var WikiGraphArchiveHandle = class {
2524
2718
  });
2525
2719
  },
2526
2720
  {
2527
- searchIndexWritebackPolicy: "cache",
2528
2721
  ...options.signal === void 0 ? {} : { signal: options.signal }
2529
2722
  }
2530
2723
  );
@@ -2629,6 +2822,7 @@ var WikiGraphArchiveHandle = class {
2629
2822
  async (document) => {
2630
2823
  const chapters = await this.#resolveScope(document, options);
2631
2824
  await ensureArchiveSearchIndex(document, {
2825
+ rebuild: true,
2632
2826
  ...chapters === void 0 ? {} : { chapters },
2633
2827
  ...embeddingProvider === void 0 ? {} : { embeddingProvider }
2634
2828
  });
@@ -2807,7 +3001,7 @@ var WikiGraphArchiveHandle = class {
2807
3001
  return await this.#writeDocument(async (document) => {
2808
3002
  const chapterId = await resolveChapterPathReadonly(document, path);
2809
3003
  await assertChapterResetAllowed(
2810
- this.#location.archiveFile,
3004
+ requireWikiGraphArchiveFile(this.#location),
2811
3005
  chapterId,
2812
3006
  stage
2813
3007
  );
@@ -2918,15 +3112,11 @@ var WikiGraphArchiveHandle = class {
2918
3112
  options.queryMode,
2919
3113
  options.signal
2920
3114
  );
2921
- const result = await this.#writeDocument(
3115
+ const result = await this.#readDocument(
2922
3116
  async (document) => {
2923
3117
  const chapters = await this.#resolveQueryChapters(document, options, {
2924
3118
  embeddingProvider
2925
3119
  });
2926
- await ensureArchiveSearchIndex(document, {
2927
- ...chapters === void 0 ? {} : { chapters },
2928
- ...embeddingProvider === void 0 ? {} : { embeddingProvider }
2929
- });
2930
3120
  return await listRelatedArchiveObjects(document, objectUri, {
2931
3121
  ...withoutOperation(options),
2932
3122
  ...embeddingProvider === void 0 ? {} : { embeddingProvider },
@@ -2934,7 +3124,6 @@ var WikiGraphArchiveHandle = class {
2934
3124
  });
2935
3125
  },
2936
3126
  {
2937
- searchIndexWritebackPolicy: "cache",
2938
3127
  ...options.signal === void 0 ? {} : { signal: options.signal }
2939
3128
  }
2940
3129
  );
@@ -2978,15 +3167,11 @@ var WikiGraphArchiveHandle = class {
2978
3167
  options.queryMode,
2979
3168
  options.signal
2980
3169
  );
2981
- const result = await this.#writeDocument(
3170
+ const result = await this.#readDocument(
2982
3171
  async (document) => {
2983
3172
  const chapters = await this.#resolveQueryChapters(document, options, {
2984
3173
  embeddingProvider
2985
3174
  });
2986
- await ensureArchiveSearchIndex(document, {
2987
- ...chapters === void 0 ? {} : { chapters },
2988
- ...embeddingProvider === void 0 ? {} : { embeddingProvider }
2989
- });
2990
3175
  return await listArchiveEvidence(document, objectUri, {
2991
3176
  ...withoutOperation(options),
2992
3177
  ...embeddingProvider === void 0 ? {} : { embeddingProvider },
@@ -2994,7 +3179,6 @@ var WikiGraphArchiveHandle = class {
2994
3179
  });
2995
3180
  },
2996
3181
  {
2997
- searchIndexWritebackPolicy: "cache",
2998
3182
  ...options.signal === void 0 ? {} : { signal: options.signal }
2999
3183
  }
3000
3184
  );
@@ -3053,14 +3237,18 @@ var WikiGraphArchiveHandle = class {
3053
3237
  }, options);
3054
3238
  }
3055
3239
  async readCover(options = {}) {
3056
- const app = new WikiGraph2({});
3057
- return await this.#runtime.run(
3058
- async () => await app.openSession(
3240
+ return await this.#runtime.run(async () => {
3241
+ if (this.#location.archiveFile.kind === "directory") {
3242
+ return await this.#readDocument(
3243
+ async (document) => await document.readCover()
3244
+ );
3245
+ }
3246
+ const app = new WikiGraph2({});
3247
+ return await app.openSession(
3059
3248
  this.#location.archiveFile,
3060
3249
  async (archive) => await archive.readCover()
3061
- ),
3062
- options.signal
3063
- );
3250
+ );
3251
+ }, options.signal);
3064
3252
  }
3065
3253
  async replaceMetadata(objectPath, value, options = {}) {
3066
3254
  return await this.#writeDocument(async (document) => {
@@ -3101,10 +3289,14 @@ var WikiGraphArchiveHandle = class {
3101
3289
  }
3102
3290
  async #readDocument(operation, options = {}) {
3103
3291
  return await this.#runtime.run(
3104
- async () => await new WikiGraphArchiveFile2(this.#location.archiveFile).readDocument(
3105
- operation
3106
- ),
3292
+ async () => this.#location.archiveFile.kind === "directory" ? await new WikiGraphDirectoryFile2(
3293
+ this.#location.archiveFile
3294
+ ).readDocument(operation) : await new WikiGraphArchiveFile2(
3295
+ this.#location.archiveFile
3296
+ ).readDocument(operation),
3107
3297
  options.signal
3298
+ ).catch(
3299
+ (error) => rethrowArchiveSchemaError(error, this.#location.target)
3108
3300
  );
3109
3301
  }
3110
3302
  async #writeDocument(operation, options = {}) {
@@ -3116,33 +3308,32 @@ var WikiGraphArchiveHandle = class {
3116
3308
  searchIndexWritebackPolicy: options.searchIndexWritebackPolicy
3117
3309
  }
3118
3310
  });
3119
- }, options.signal);
3311
+ }, options.signal).catch(
3312
+ (error) => rethrowArchiveSchemaError(error, this.#location.target)
3313
+ );
3120
3314
  }
3121
3315
  async #resolveScope(document, options) {
3122
3316
  if (options.chapters !== void 0) return options.chapters;
3123
3317
  return (await resolveArchiveScope(document, this.objectUri, options.depth))?.chapterIds;
3124
3318
  }
3125
3319
  async #resolveQueryChapters(document, options, capabilities) {
3126
- const chapters = await this.#resolveScope(document, options);
3320
+ const parsed = parseChapterScopePath(this.objectUri);
3321
+ const chapters = options.chapters ?? (parsed === void 0 || parsed.kind === "collection" && options.depth === void 0 ? void 0 : await resolveIndexedArchiveChapterScope(
3322
+ document,
3323
+ parsed.kind === "chapter" ? parsed.chapterPath : void 0,
3324
+ options.depth
3325
+ ));
3127
3326
  const coverageOptions = {
3128
3327
  ...chapters === void 0 ? {} : { chapters },
3129
3328
  ...capabilities.embeddingProvider === void 0 ? {} : { embeddingProvider: capabilities.embeddingProvider },
3130
3329
  requireEmbeddingProvider: true,
3131
3330
  ...options.queryMode === void 0 ? {} : { queryMode: options.queryMode }
3132
3331
  };
3133
- if (options.skipUnindexed !== true) {
3134
- await assertArchiveIndexArtifactsReady(document, coverageOptions);
3135
- return chapters;
3136
- }
3137
- const queryable = await listArchiveQueryableChapterIds(document, {
3138
- ...coverageOptions
3332
+ await assertArchiveQueryReady(document, {
3333
+ ...coverageOptions,
3334
+ ...options.skipUnindexed === void 0 ? {} : { skipUnindexed: options.skipUnindexed }
3139
3335
  });
3140
- if (queryable.length === 0) {
3141
- throw new Error(
3142
- "Wiki Graph query is not ready. No chapters in this scope have a current FTS artifact or source embedding artifact."
3143
- );
3144
- }
3145
- return queryable;
3336
+ return chapters;
3146
3337
  }
3147
3338
  async #resolveQueryEmbeddingProvider(queryMode, signal) {
3148
3339
  if (queryMode === "fts") return void 0;
@@ -3161,6 +3352,10 @@ var WikiGraphArchiveHandle = class {
3161
3352
  async function ensureArchiveSearchIndex(document, options = {}) {
3162
3353
  const scope = options.chapters === void 0 ? {} : { chapters: options.chapters };
3163
3354
  if (await isArchiveSearchIndexCurrent2(document, scope)) return;
3355
+ if (options.rebuild !== true)
3356
+ throw new Error(
3357
+ "Archive search index is missing or dirty. Run `wg <archive-uri>/index sync` explicitly before querying."
3358
+ );
3164
3359
  await rebuildArchiveSearchIndex(document, void 0, {
3165
3360
  ...scope,
3166
3361
  ...options.embeddingProvider === void 0 ? {} : { embeddingProvider: options.embeddingProvider }
@@ -3506,7 +3701,8 @@ import {
3506
3701
  listWikiGraphLibraryObjects,
3507
3702
  readContinuationCursor,
3508
3703
  resolveWikiGraphLibraryQueryTargetById,
3509
- WikiGraphArchiveFile as WikiGraphArchiveFile3
3704
+ WikiGraphArchiveFile as WikiGraphArchiveFile3,
3705
+ WikiGraphDirectoryFile as WikiGraphDirectoryFile3
3510
3706
  } from "wiki-graph-core";
3511
3707
  var WikiGraphContinuationManager = class {
3512
3708
  #runtime;
@@ -3556,53 +3752,54 @@ async function continueArchiveCursor(cursor, limit) {
3556
3752
  const location = await resolveWikiGraphArchiveLocation(
3557
3753
  archiveTargetFromLogicalLocator(getCursorArchivePath(cursor))
3558
3754
  );
3559
- return await new WikiGraphArchiveFile3(location.archiveFile).readDocument(
3560
- async (document) => {
3561
- switch (cursor.kind) {
3562
- case "source-locators":
3563
- return await listArchiveSourceLocators2(document, cursor.targetUri, {
3564
- cursor: cursor.cursor,
3565
- limit
3566
- });
3567
- case "collection":
3568
- return await listArchiveCollection2(
3569
- document,
3570
- createCollectionOptions(cursor, limit)
3571
- );
3572
- case "search":
3573
- return await findArchiveObjects2(
3574
- document,
3575
- cursor.query ?? "",
3576
- await createFindOptions(cursor, limit)
3577
- );
3578
- case "evidence":
3579
- return await listArchiveEvidence2(document, cursor.targetUri, {
3580
- ...cursor.chapters === null ? {} : { chapters: cursor.chapters },
3581
- cursor: cursor.cursor,
3582
- limit,
3583
- order: cursor.order,
3584
- ...cursor.query === void 0 ? {} : { query: cursor.query },
3585
- ...cursor.queryMode === void 0 ? {} : { queryMode: cursor.queryMode },
3586
- ...embeddingProvider === void 0 ? {} : { embeddingProvider },
3587
- ...cursor.skipUnindexed === void 0 ? {} : { skipUnindexed: cursor.skipUnindexed },
3588
- ...cursor.sourceContext === void 0 ? {} : { sourceContext: cursor.sourceContext }
3589
- });
3590
- case "related":
3591
- return await listRelatedArchiveObjects2(document, cursor.targetUri, {
3592
- ...cursor.chapters === null ? {} : { chapters: cursor.chapters },
3593
- cursor: cursor.cursor,
3594
- ...cursor.evidenceLimit === void 0 ? {} : { evidenceLimit: cursor.evidenceLimit },
3595
- limit,
3596
- order: cursor.order,
3597
- ...cursor.query === void 0 ? {} : { query: cursor.query },
3598
- ...cursor.queryMode === void 0 ? {} : { queryMode: cursor.queryMode },
3599
- ...embeddingProvider === void 0 ? {} : { embeddingProvider },
3600
- ...cursor.role === void 0 ? {} : { role: cursor.role },
3601
- ...cursor.skipUnindexed === void 0 ? {} : { skipUnindexed: cursor.skipUnindexed },
3602
- ...cursor.sourceContext === void 0 ? {} : { sourceContext: cursor.sourceContext }
3603
- });
3604
- }
3755
+ const read2 = async (document) => {
3756
+ switch (cursor.kind) {
3757
+ case "source-locators":
3758
+ return await listArchiveSourceLocators2(document, cursor.targetUri, {
3759
+ cursor: cursor.cursor,
3760
+ limit
3761
+ });
3762
+ case "collection":
3763
+ return await listArchiveCollection2(
3764
+ document,
3765
+ createCollectionOptions(cursor, limit)
3766
+ );
3767
+ case "search":
3768
+ return await findArchiveObjects2(
3769
+ document,
3770
+ cursor.query ?? "",
3771
+ await createFindOptions(cursor, limit)
3772
+ );
3773
+ case "evidence":
3774
+ return await listArchiveEvidence2(document, cursor.targetUri, {
3775
+ ...cursor.chapters === null ? {} : { chapters: cursor.chapters },
3776
+ cursor: cursor.cursor,
3777
+ limit,
3778
+ order: cursor.order,
3779
+ ...cursor.query === void 0 ? {} : { query: cursor.query },
3780
+ ...cursor.queryMode === void 0 ? {} : { queryMode: cursor.queryMode },
3781
+ ...embeddingProvider === void 0 ? {} : { embeddingProvider },
3782
+ ...cursor.skipUnindexed === void 0 ? {} : { skipUnindexed: cursor.skipUnindexed },
3783
+ ...cursor.sourceContext === void 0 ? {} : { sourceContext: cursor.sourceContext }
3784
+ });
3785
+ case "related":
3786
+ return await listRelatedArchiveObjects2(document, cursor.targetUri, {
3787
+ ...cursor.chapters === null ? {} : { chapters: cursor.chapters },
3788
+ cursor: cursor.cursor,
3789
+ ...cursor.evidenceLimit === void 0 ? {} : { evidenceLimit: cursor.evidenceLimit },
3790
+ limit,
3791
+ order: cursor.order,
3792
+ ...cursor.query === void 0 ? {} : { query: cursor.query },
3793
+ ...cursor.queryMode === void 0 ? {} : { queryMode: cursor.queryMode },
3794
+ ...embeddingProvider === void 0 ? {} : { embeddingProvider },
3795
+ ...cursor.role === void 0 ? {} : { role: cursor.role },
3796
+ ...cursor.skipUnindexed === void 0 ? {} : { skipUnindexed: cursor.skipUnindexed },
3797
+ ...cursor.sourceContext === void 0 ? {} : { sourceContext: cursor.sourceContext }
3798
+ });
3605
3799
  }
3800
+ };
3801
+ return await (location.archiveFile.kind === "directory" ? new WikiGraphDirectoryFile3(location.archiveFile).readDocument(read2) : new WikiGraphArchiveFile3(location.archiveFile).readDocument(read2)).catch(
3802
+ (error) => rethrowArchiveSchemaError(error, location.target)
3606
3803
  );
3607
3804
  }
3608
3805
  async function continueLibraryCursor(cursor, limit) {
@@ -4491,7 +4688,7 @@ var WikiGraphJobManager = class {
4491
4688
  return {
4492
4689
  job: await this.#backend.add({
4493
4690
  ...options,
4494
- archive: location.archiveFile
4691
+ archive: requireWikiGraphArchiveFile(location)
4495
4692
  }),
4496
4693
  target: location.target
4497
4694
  };
@@ -4523,7 +4720,9 @@ var WikiGraphJobManager = class {
4523
4720
  ...options.activeOnly === void 0 ? {} : { activeOnly: options.activeOnly },
4524
4721
  ...options.all === void 0 ? {} : { all: options.all },
4525
4722
  ...options.archive === void 0 ? {} : {
4526
- archive: (await resolveWikiGraphArchiveLocation(options.archive)).archiveFile
4723
+ archive: requireWikiGraphArchiveFile(
4724
+ await resolveWikiGraphArchiveLocation(options.archive)
4725
+ )
4527
4726
  }
4528
4727
  };
4529
4728
  const jobs = await this.#backend.list(normalized);
@@ -4548,7 +4747,7 @@ var WikiGraphJobManager = class {
4548
4747
  archiveJobs[0].archive
4549
4748
  );
4550
4749
  const chapters = await new WikiGraphArchiveFile6(
4551
- location.archiveFile
4750
+ requireWikiGraphArchiveFile(location)
4552
4751
  ).readDocument(async (document) => await listChapters3(document));
4553
4752
  const chaptersById = new Map(
4554
4753
  chapters.map((chapter) => [chapter.chapterId, chapter])
@@ -4591,7 +4790,7 @@ var WikiGraphJobManager = class {
4591
4790
  await validateQueueTargetConfig(target, llmJSON);
4592
4791
  const selectedExplicitly = options.chapterId !== void 0 || options.chapterIds !== void 0 || options.chapterPath !== void 0 || options.depth !== void 0;
4593
4792
  const candidates = await new WikiGraphArchiveFile6(
4594
- location.archiveFile
4793
+ requireWikiGraphArchiveFile(location)
4595
4794
  ).readDocument(async (document) => {
4596
4795
  const chapters = await listChapters3(document);
4597
4796
  const selected = await selectQueueChapters(
@@ -4635,7 +4834,7 @@ var WikiGraphJobManager = class {
4635
4834
  chapter: candidate.chapter,
4636
4835
  job: await this.#createHandle(
4637
4836
  await this.#backend.add({
4638
- archive: location.archiveFile,
4837
+ archive: requireWikiGraphArchiveFile(location),
4639
4838
  boost: options.boost ?? false,
4640
4839
  chapterId: candidate.chapter.chapterId,
4641
4840
  ...llmJSON === void 0 ? {} : { llmJSON },
@@ -4666,7 +4865,7 @@ var WikiGraphJobManager = class {
4666
4865
  await validateQueueTargetConfig(target, llmJSON);
4667
4866
  const selectedExplicitly = options.chapterId !== void 0 || options.chapterIds !== void 0 || options.chapterPath !== void 0 || options.depth !== void 0;
4668
4867
  const candidates = await new WikiGraphArchiveFile6(
4669
- location.archiveFile
4868
+ requireWikiGraphArchiveFile(location)
4670
4869
  ).readDocument(async (document) => {
4671
4870
  const chapters = await listChapters3(document);
4672
4871
  const selected = await selectQueueChapters(document, chapters, options);
@@ -4996,6 +5195,7 @@ function forwardAbort(source, target) {
4996
5195
  // src/libraries.ts
4997
5196
  import {
4998
5197
  addWikiGraphLibraryArchive,
5198
+ ensureWikiGraphArchiveSchemaCurrent as ensureWikiGraphArchiveSchemaCurrent2,
4999
5199
  assertWikiGraphLibrarySchemaCurrent,
5000
5200
  cleanWikiGraphLibraryIndex,
5001
5201
  clearWikiGraphLibraryMetadata,
@@ -5009,8 +5209,8 @@ import {
5009
5209
  getWikiGraphLibraryArchive,
5010
5210
  getWikiGraphLibraryMetadata,
5011
5211
  listRelatedWikiGraphLibraryObjects as listRelatedWikiGraphLibraryObjects2,
5012
- listWikiGraphLibraries as listWikiGraphLibraries2,
5013
- listWikiGraphLibraryArchives as listWikiGraphLibraryArchives2,
5212
+ listWikiGraphLibraries,
5213
+ listWikiGraphLibraryArchives,
5014
5214
  listWikiGraphLibraryArchiveMembers as listWikiGraphLibraryArchiveMembers2,
5015
5215
  listWikiGraphLibraryEvidence as listWikiGraphLibraryEvidence2,
5016
5216
  listWikiGraphLibraryObjects as listWikiGraphLibraryObjects2,
@@ -5028,9 +5228,12 @@ import {
5028
5228
  replaceWikiGraphLibraryMetadata,
5029
5229
  resolveWikiGraphLibrary as resolveWikiGraphLibrary2,
5030
5230
  scanWikiGraphLibrary,
5031
- withWikiGraphLibraryLock
5231
+ withWikiGraphLibraryLock,
5232
+ writeWikgArchive as writeWikgArchive2
5032
5233
  } from "wiki-graph-core";
5033
- import { mkdir as mkdir3 } from "fs/promises";
5234
+ import { mkdir as mkdir3, mkdtemp as mkdtemp2, rm as rm4 } from "fs/promises";
5235
+ import { tmpdir as tmpdir2 } from "os";
5236
+ import { join as join5 } from "path";
5034
5237
  async function resolveQueryEmbeddingProvider(queryMode) {
5035
5238
  if (queryMode === "fts") return void 0;
5036
5239
  const provider = await createConfiguredEmbeddingProvider();
@@ -5120,10 +5323,28 @@ var WikiGraphLibraryManager = class {
5120
5323
  async () => {
5121
5324
  throwIfAborted(options.signal);
5122
5325
  const archive = await getWikiGraphLibraryArchive(parsedTarget);
5123
- const file = requireReadableLibraryArchiveFile(archive);
5124
- const reader = await file.openReader();
5326
+ const source = requireReadableLibraryArchiveFile(archive);
5327
+ await ensureWikiGraphArchiveSchemaCurrent2(source).catch(
5328
+ (error) => rethrowArchiveSchemaError(error, {
5329
+ kind: "library",
5330
+ uri: archive.uri
5331
+ })
5332
+ );
5333
+ let temporaryDirectory;
5334
+ let reader;
5125
5335
  let active = true;
5126
5336
  try {
5337
+ const file = source.kind === "directory" ? await (async () => {
5338
+ temporaryDirectory = await mkdtemp2(
5339
+ join5(tmpdir2(), "wikigraph-library-read-")
5340
+ );
5341
+ const output = new NodeFile(
5342
+ join5(temporaryDirectory, "archive.wikg")
5343
+ );
5344
+ await writeWikgArchive2(source, output);
5345
+ return output;
5346
+ })() : source;
5347
+ reader = await file.openReader();
5127
5348
  const content = {
5128
5349
  mediaType: "application/vnd.wiki-graph.archive",
5129
5350
  size: reader.size,
@@ -5140,7 +5361,12 @@ var WikiGraphLibraryManager = class {
5140
5361
  );
5141
5362
  } finally {
5142
5363
  active = false;
5143
- await reader.close();
5364
+ try {
5365
+ await reader?.close();
5366
+ } finally {
5367
+ if (temporaryDirectory !== void 0)
5368
+ await rm4(temporaryDirectory, { force: true, recursive: true });
5369
+ }
5144
5370
  }
5145
5371
  },
5146
5372
  options.signal === void 0 ? {} : { signal: options.signal }
@@ -5450,7 +5676,7 @@ var WikiGraphLibraryManager = class {
5450
5676
  }
5451
5677
  async list() {
5452
5678
  const records = await this.#runtime.run(
5453
- async () => await listWikiGraphLibraries2()
5679
+ async () => await listWikiGraphLibraries()
5454
5680
  );
5455
5681
  return records.map((record) => new WikiGraphLibrary(this.#runtime, record));
5456
5682
  }
@@ -5473,7 +5699,7 @@ var WikiGraphLibrary = class {
5473
5699
  async archives() {
5474
5700
  const target = requireLibraryTarget(this.uri);
5475
5701
  return (await this.#runtime.run(
5476
- async () => await listWikiGraphLibraryArchives2(target)
5702
+ async () => await listWikiGraphLibraryArchives(target)
5477
5703
  )).map(toArchiveSnapshot);
5478
5704
  }
5479
5705
  async scan() {
@@ -5502,7 +5728,7 @@ function toLibrarySnapshot(record) {
5502
5728
  };
5503
5729
  }
5504
5730
  function toArchiveSnapshot(record) {
5505
- const { file: _file, ...snapshot } = record;
5731
+ const { file: _file, directory: _directory, ...snapshot } = record;
5506
5732
  return snapshot;
5507
5733
  }
5508
5734
  function toScanSnapshot(result) {
@@ -5535,12 +5761,12 @@ function requireReadableLibraryArchiveFile(archive) {
5535
5761
  `Wiki Graph library archive has a conflict and cannot be read: ${archive.uri}`
5536
5762
  );
5537
5763
  }
5538
- if (archive.file === void 0) {
5764
+ if (archive.file === void 0 && archive.directory === void 0) {
5539
5765
  throw new Error(
5540
5766
  `Wiki Graph library archive is unavailable: ${archive.uri}`
5541
5767
  );
5542
5768
  }
5543
- return archive.file;
5769
+ return archive.file ?? archive.directory;
5544
5770
  }
5545
5771
  var ARCHIVE_STREAM_CHUNK_SIZE = 64 * 1024;
5546
5772
  function createCallbackScopedArchiveStream(reader, isActive, signal) {
@@ -5645,7 +5871,9 @@ var WikiGraphMaintenanceManager = class {
5645
5871
  return await upgradeWikiGraphMaintenanceTarget({
5646
5872
  file: new NodeFile(path),
5647
5873
  kind: "archive"
5648
- });
5874
+ }).catch(
5875
+ (error) => rethrowArchiveSchemaError(error, { kind: "standalone", path })
5876
+ );
5649
5877
  },
5650
5878
  void 0,
5651
5879
  { skipHomeBootstrap: target.kind === "home" }
@@ -5674,7 +5902,6 @@ function defaultWikgOutputPath(inputPath) {
5674
5902
  import { ensureWikiGraphHomeSchemaCurrent } from "wiki-graph-core";
5675
5903
  var WikiGraphSDK = class {
5676
5904
  #context;
5677
- #homeReady;
5678
5905
  archives;
5679
5906
  conversions;
5680
5907
  config;
@@ -5705,13 +5932,7 @@ var WikiGraphSDK = class {
5705
5932
  throwIfAborted2(signal);
5706
5933
  const runWithContext = async () => await withWikiGraphSDKRuntimeContext(this.#context, async () => {
5707
5934
  if (options.skipHomeBootstrap !== true) {
5708
- this.#homeReady ??= ensureWikiGraphHomeSchemaCurrent().catch(
5709
- (error) => {
5710
- this.#homeReady = void 0;
5711
- throw error;
5712
- }
5713
- );
5714
- await this.#homeReady;
5935
+ await ensureWikiGraphHomeSchemaCurrent();
5715
5936
  }
5716
5937
  return await operation();
5717
5938
  });
@@ -5742,6 +5963,8 @@ import {
5742
5963
  LLMPaymentRequiredError,
5743
5964
  WIKI_GRAPH_URI_PREFIX,
5744
5965
  WikiGraphError,
5966
+ WikiGraphSchemaVersionError as WikiGraphSchemaVersionError2,
5967
+ isWikiGraphSchemaVersionError as isWikiGraphSchemaVersionError2,
5745
5968
  formatError as formatError3,
5746
5969
  formatLocatedChapterResourceUri,
5747
5970
  formatLocatedChapterSourceCollectionUri,
@@ -5798,6 +6021,7 @@ export {
5798
6021
  WikiGraphLibraryManager,
5799
6022
  WikiGraphMaintenanceManager,
5800
6023
  WikiGraphSDK,
6024
+ WikiGraphSchemaVersionError2 as WikiGraphSchemaVersionError,
5801
6025
  buildSearchIndexEmbeddingProvider,
5802
6026
  buildWikiGraphLLMOptions,
5803
6027
  clearLocalConfigSection,
@@ -5840,6 +6064,7 @@ export {
5840
6064
  isSourceLocatorScopeUri2 as isSourceLocatorScopeUri,
5841
6065
  isWikiGraphJobUri,
5842
6066
  isWikiGraphLibraryUri,
6067
+ isWikiGraphSchemaVersionError2 as isWikiGraphSchemaVersionError,
5843
6068
  isWikiGraphUri,
5844
6069
  iterateItems,
5845
6070
  iteratePages,