wiki-graph-sdk 0.7.1 → 0.8.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 (58) hide show
  1. package/README.md +22 -1
  2. package/dist/archives.cjs +494 -656
  3. package/dist/archives.cjs.map +1 -1
  4. package/dist/archives.d.ts +48 -80
  5. package/dist/archives.js +431 -585
  6. package/dist/archives.js.map +1 -1
  7. package/dist/conversions.cjs +183 -33
  8. package/dist/conversions.cjs.map +1 -1
  9. package/dist/conversions.d.ts +8 -1
  10. package/dist/conversions.js +188 -29
  11. package/dist/conversions.js.map +1 -1
  12. package/dist/default-worker.cjs +322 -62
  13. package/dist/default-worker.cjs.map +1 -1
  14. package/dist/default-worker.d.ts +1 -0
  15. package/dist/default-worker.js +336 -60
  16. package/dist/default-worker.js.map +1 -1
  17. package/dist/embedding.cjs +2 -1
  18. package/dist/embedding.cjs.map +1 -1
  19. package/dist/embedding.d.ts +4 -4
  20. package/dist/embedding.js +2 -1
  21. package/dist/embedding.js.map +1 -1
  22. package/dist/index.cjs +1295 -949
  23. package/dist/index.cjs.map +1 -1
  24. package/dist/index.d.ts +58 -24
  25. package/dist/index.js +1164 -805
  26. package/dist/index.js.map +1 -1
  27. package/dist/{jobs-Dd5PMSId.d.ts → jobs-CRK-DZ40.d.ts} +27 -14
  28. package/dist/local-config.cjs +2 -1
  29. package/dist/local-config.cjs.map +1 -1
  30. package/dist/local-config.js +2 -1
  31. package/dist/local-config.js.map +1 -1
  32. package/dist/maintenance.cjs +140 -30
  33. package/dist/maintenance.cjs.map +1 -1
  34. package/dist/maintenance.d.ts +5 -1
  35. package/dist/maintenance.js +145 -26
  36. package/dist/maintenance.js.map +1 -1
  37. package/dist/runtime-config.cjs +4 -3
  38. package/dist/runtime-config.cjs.map +1 -1
  39. package/dist/runtime-config.d.ts +4 -1
  40. package/dist/runtime-config.js +4 -3
  41. package/dist/runtime-config.js.map +1 -1
  42. package/dist/stage-BnWI3Rqt.d.ts +33 -0
  43. package/dist/stage.cjs +22 -12
  44. package/dist/stage.cjs.map +1 -1
  45. package/dist/stage.d.ts +2 -14
  46. package/dist/stage.js +22 -12
  47. package/dist/stage.js.map +1 -1
  48. package/dist/target-CZ7elwmj.d.ts +14 -0
  49. package/dist/wikispine.cjs +14 -10
  50. package/dist/wikispine.cjs.map +1 -1
  51. package/dist/wikispine.js +14 -10
  52. package/dist/wikispine.js.map +1 -1
  53. package/dist/worker.cjs +295 -25
  54. package/dist/worker.cjs.map +1 -1
  55. package/dist/worker.d.ts +28 -5
  56. package/dist/worker.js +313 -28
  57. package/dist/worker.js.map +1 -1
  58. package/package.json +2 -2
@@ -2,6 +2,7 @@ import { WikiGraphRuntimeConfig } from './runtime-config.js';
2
2
  import 'zod';
3
3
 
4
4
  interface WikiGraphQueueWorkerOptions {
5
+ readonly idleTimeoutMs?: number;
5
6
  readonly signal?: AbortSignal;
6
7
  }
7
8
  declare function runWikiGraphQueueWorker(options?: WikiGraphQueueWorkerOptions): Promise<void>;
@@ -8,14 +8,14 @@ import {
8
8
  getChapterDetails,
9
9
  openWikimediaResolver,
10
10
  recordBuildJobInputRevision,
11
- WikiGraphArchiveFile as WikiGraphArchiveFile2,
11
+ WikiGraphArchiveFile as WikiGraphArchiveFile3,
12
12
  WikiGraphScope,
13
13
  withLoggingContext
14
14
  } from "wiki-graph-core";
15
15
  import {
16
16
  applyChapterJobArtifactFile as applyChapterJobArtifactFile3,
17
17
  createLocalChapterJobFileExecutor as createLocalChapterJobFileExecutor2,
18
- writeChapterJobInputFile as writeChapterJobInputFile2
18
+ writeChapterJobInputFile as writeChapterJobInputFile3
19
19
  } from "wiki-graph-core/worker";
20
20
 
21
21
  // src/embedding.ts
@@ -49,12 +49,16 @@ function getWikiGraphSDKRuntimeContext() {
49
49
  return runtimeContext.getStore() ?? {
50
50
  cwd: process.cwd(),
51
51
  env: process.env,
52
- envPolicy: "production"
52
+ envPolicy: "production",
53
+ providers: {}
53
54
  };
54
55
  }
55
56
  function getWikiGraphSDKStateDir() {
56
57
  return getWikiGraphSDKRuntimeContext().stateDir;
57
58
  }
59
+ function getWikiGraphSDKProviders() {
60
+ return getWikiGraphSDKRuntimeContext().providers ?? {};
61
+ }
58
62
 
59
63
  // src/node-platform.ts
60
64
  import * as asyncHooks from "async_hooks";
@@ -289,6 +293,14 @@ function decodeNodeResourceIdentity(identity, kind) {
289
293
  return void 0;
290
294
  }
291
295
  }
296
+ function getNodeResourcePath(resource) {
297
+ const brandedPath = getBrandedNodeResourcePath(resource, resource.kind);
298
+ if (brandedPath !== void 0) return brandedPath;
299
+ if (typeof resource === "object" && resource !== null && "path" in resource && typeof resource.path === "string") {
300
+ return resource.path;
301
+ }
302
+ throw new TypeError("Expected a Node File or Directory resource");
303
+ }
292
304
  function assertChildName(name) {
293
305
  if (name.length === 0 || name === "." || name === ".." || pathModule.isAbsolute(name) || name.includes("/") || name.includes("\\")) {
294
306
  throw new TypeError(`Directory child must be a relative name: ${name}`);
@@ -300,42 +312,42 @@ var NodeDatabaseConnection = class {
300
312
  }
301
313
  database;
302
314
  async close() {
303
- await new Promise((resolve2, reject) => {
315
+ await new Promise((resolve4, reject) => {
304
316
  this.database.close((error) => {
305
317
  if (error) reject(error);
306
- else resolve2();
318
+ else resolve4();
307
319
  });
308
320
  });
309
321
  }
310
322
  async execute(sql) {
311
- await new Promise((resolve2, reject) => {
323
+ await new Promise((resolve4, reject) => {
312
324
  this.database.exec(sql, (error) => {
313
325
  if (error) reject(error);
314
- else resolve2();
326
+ else resolve4();
315
327
  });
316
328
  });
317
329
  }
318
330
  async queryAll(sql, params = []) {
319
- return await new Promise((resolve2, reject) => {
331
+ return await new Promise((resolve4, reject) => {
320
332
  this.database.all(sql, [...params], (error, rows) => {
321
333
  if (error) reject(error);
322
- else resolve2(rows);
334
+ else resolve4(rows);
323
335
  });
324
336
  });
325
337
  }
326
338
  async queryOne(sql, params = []) {
327
- return await new Promise((resolve2, reject) => {
339
+ return await new Promise((resolve4, reject) => {
328
340
  this.database.get(sql, [...params], (error, row) => {
329
341
  if (error) reject(error);
330
- else resolve2(row);
342
+ else resolve4(row);
331
343
  });
332
344
  });
333
345
  }
334
346
  async run(sql, params = []) {
335
- await new Promise((resolve2, reject) => {
347
+ await new Promise((resolve4, reject) => {
336
348
  this.database.run(sql, [...params], (error) => {
337
349
  if (error) reject(error);
338
- else resolve2();
350
+ else resolve4();
339
351
  });
340
352
  });
341
353
  }
@@ -349,10 +361,10 @@ async function openNativeNodeDatabase(file, flags) {
349
361
  if (path === void 0) {
350
362
  throw new TypeError("The Node database adapter requires a NodeFile");
351
363
  }
352
- return await new Promise((resolve2, reject) => {
364
+ return await new Promise((resolve4, reject) => {
353
365
  const database = new nodeSqlite3.Database(path, flags, (error) => {
354
366
  if (error) reject(error);
355
- else resolve2(database);
367
+ else resolve4(database);
356
368
  });
357
369
  });
358
370
  }
@@ -361,19 +373,19 @@ async function openNodeZip(file) {
361
373
  if (path === void 0) {
362
374
  throw new TypeError("The Node ZIP adapter requires a NodeFile");
363
375
  }
364
- const zipFile = await new Promise((resolve2, reject) => {
376
+ const zipFile = await new Promise((resolve4, reject) => {
365
377
  yauzl.open(
366
378
  path,
367
379
  { autoClose: false, lazyEntries: true },
368
380
  (error, opened) => {
369
381
  if (error || opened === void 0)
370
382
  reject(error ?? new Error("Cannot open ZIP"));
371
- else resolve2(opened);
383
+ else resolve4(opened);
372
384
  }
373
385
  );
374
386
  });
375
387
  const entries = await new Promise(
376
- (resolve2, reject) => {
388
+ (resolve4, reject) => {
377
389
  const discovered = /* @__PURE__ */ new Map();
378
390
  const rejectAndClose = (error) => {
379
391
  zipFile.close();
@@ -383,7 +395,7 @@ async function openNodeZip(file) {
383
395
  };
384
396
  const resolveEntries = () => {
385
397
  zipFile.off("error", rejectAndClose);
386
- resolve2(discovered);
398
+ resolve4(discovered);
387
399
  };
388
400
  zipFile.on("entry", (entry) => {
389
401
  if (!entry.fileName.endsWith("/")) {
@@ -493,12 +505,12 @@ async function collectDecodedNodeStreamRange(input, offset, length) {
493
505
  return Buffer.concat(chunks, collected);
494
506
  }
495
507
  async function openNodeZipEntryStream(zipFile, entry, options) {
496
- return await new Promise((resolve2, reject) => {
508
+ return await new Promise((resolve4, reject) => {
497
509
  const callback = (error, opened) => {
498
510
  if (error || opened === void 0) {
499
511
  reject(error ?? new Error(`Cannot read ZIP entry: ${entry.fileName}`));
500
512
  } else {
501
- resolve2(opened);
513
+ resolve4(opened);
502
514
  }
503
515
  };
504
516
  if (options === void 0) zipFile.openReadStream(entry, callback);
@@ -629,11 +641,11 @@ async function writeNodeStream(input, writer) {
629
641
  );
630
642
  }
631
643
  async function collectNodeStream(input) {
632
- return await new Promise((resolve2, reject) => {
644
+ return await new Promise((resolve4, reject) => {
633
645
  const chunks = [];
634
646
  input.on("data", (chunk) => chunks.push(chunk));
635
647
  input.once("error", reject);
636
- input.once("end", () => resolve2(Buffer.concat(chunks)));
648
+ input.once("end", () => resolve4(Buffer.concat(chunks)));
637
649
  });
638
650
  }
639
651
  var nodeWikiGraphPlatform = {
@@ -1068,8 +1080,8 @@ var inlineLLMConfigSchema = z.object({
1068
1080
  });
1069
1081
  async function loadWikiGraphRuntimeConfig(options) {
1070
1082
  const [embedding, localLLM, concurrent, wikimedia, wikispine] = await Promise.all([
1071
- readLocalConfigSection("embeddings"),
1072
- readLocalConfigSection("llm"),
1083
+ options?.skipEmbeddingConfig === true ? Promise.resolve({}) : readLocalConfigSection("embeddings"),
1084
+ options?.skipLLMConfig === true ? Promise.resolve({}) : readLocalConfigSection("llm"),
1073
1085
  readLocalConfigSection("concurrent"),
1074
1086
  readLocalConfigSection("wikimedia"),
1075
1087
  readLocalConfigSection("wikispine")
@@ -1349,7 +1361,10 @@ function createOpenAICompatibleName2(baseURL) {
1349
1361
 
1350
1362
  // src/stage.ts
1351
1363
  function createStageLLM(config, options) {
1352
- const llmOptions = buildWikiGraphLLMOptions(config);
1364
+ const llmOptions = options?.provider === void 0 ? buildWikiGraphLLMOptions(config) : {
1365
+ ...config.concurrent?.request === void 0 ? {} : { concurrent: config.concurrent.request },
1366
+ streamProvider: options.provider
1367
+ };
1353
1368
  return new LLM({
1354
1369
  sampling: createDefaultWikiGraphSampling({
1355
1370
  ...llmOptions.temperature === void 0 ? {} : { temperature: llmOptions.temperature },
@@ -1363,10 +1378,13 @@ function createStageLLM(config, options) {
1363
1378
  });
1364
1379
  }
1365
1380
  async function loadRequiredStageConfig(options) {
1381
+ const injected = options.llmJSON === void 0 ? getWikiGraphSDKProviders().llm : void 0;
1366
1382
  const config = await loadWikiGraphRuntimeConfig({
1367
- ...options.llmJSON === void 0 ? {} : { llmJSON: options.llmJSON }
1383
+ ...options.llmJSON === void 0 ? {} : { llmJSON: options.llmJSON },
1384
+ ...options.llmJSON === void 0 && injected !== void 0 ? { skipLLMConfig: true } : {},
1385
+ ...getWikiGraphSDKProviders().embedding === void 0 ? {} : { skipEmbeddingConfig: true }
1368
1386
  });
1369
- if (config.llm?.provider === void 0 || config.llm.model === void 0) {
1387
+ if (injected === void 0 && (config.llm?.provider === void 0 || config.llm.model === void 0)) {
1370
1388
  throw new Error(
1371
1389
  "Missing LLM configuration. Set --llm for one run, or configure `wikg://local/config/llm` with provider and model."
1372
1390
  );
@@ -1380,12 +1398,13 @@ var DEFAULT_GENERATION_JOB_CONCURRENCY = 3;
1380
1398
  // src/wikispine.ts
1381
1399
  import { spawn } from "child_process";
1382
1400
  var nodeWikispineCommandRunner = {
1383
- run: async ({ args, command, input, onStdout, signal }) => await new Promise((resolve2, reject) => {
1401
+ run: async ({ args, command, input, onStdout, signal }) => await new Promise((resolve4, reject) => {
1384
1402
  signal?.throwIfAborted();
1385
1403
  const child = spawn(command, [...args], {
1386
1404
  stdio: ["pipe", "pipe", "pipe"]
1387
1405
  });
1388
1406
  const stderr = [];
1407
+ let stdoutQueue = Promise.resolve();
1389
1408
  let settled = false;
1390
1409
  const settle = (operation) => {
1391
1410
  if (settled) return;
@@ -1401,14 +1420,15 @@ var nodeWikispineCommandRunner = {
1401
1420
  child.stdout.setEncoding("utf8");
1402
1421
  child.stdout.on("data", (chunk) => {
1403
1422
  if (settled) return;
1404
- try {
1405
- onStdout(chunk);
1406
- } catch (error) {
1423
+ child.stdout.pause();
1424
+ stdoutQueue = stdoutQueue.then(async () => await onStdout(chunk)).then(() => {
1425
+ child.stdout.resume();
1426
+ }).catch((error) => {
1407
1427
  child.kill();
1408
1428
  settle(
1409
1429
  () => reject(error instanceof Error ? error : new Error(String(error)))
1410
1430
  );
1411
- }
1431
+ });
1412
1432
  });
1413
1433
  child.stderr.on("data", (chunk) => stderr.push(chunk));
1414
1434
  child.on("error", (error) => {
@@ -1419,12 +1439,14 @@ var nodeWikispineCommandRunner = {
1419
1439
  );
1420
1440
  });
1421
1441
  child.on("close", (exitCode) => {
1422
- settle(
1423
- () => resolve2({
1424
- exitCode,
1425
- stderr: Buffer.concat(stderr).toString("utf8")
1426
- })
1427
- );
1442
+ void stdoutQueue.then(() => {
1443
+ settle(
1444
+ () => resolve4({
1445
+ exitCode,
1446
+ stderr: Buffer.concat(stderr).toString("utf8")
1447
+ })
1448
+ );
1449
+ });
1428
1450
  });
1429
1451
  child.stdin.end(input);
1430
1452
  })
@@ -1436,13 +1458,243 @@ function abortError(signal) {
1436
1458
  // src/worker.ts
1437
1459
  import {
1438
1460
  applyChapterJobArtifactFile,
1439
- runBuildJobWorker as runCoreBuildJobWorker
1461
+ runBuildJobWorker as runCoreBuildJobWorker,
1462
+ writeChapterJobInputFile
1440
1463
  } from "wiki-graph-core/worker";
1441
- import { WikiGraphArchiveFile } from "wiki-graph-core";
1464
+ import {
1465
+ resolveChapterPathReadonly,
1466
+ WikiGraphArchiveFile as WikiGraphArchiveFile2
1467
+ } from "wiki-graph-core";
1468
+
1469
+ // src/archive/target.ts
1470
+ import { realpath, stat as stat2 } from "fs/promises";
1471
+ import { basename as basename2, dirname as dirname2, isAbsolute as isAbsolute3, join as join3, relative, resolve as resolve3 } from "path";
1472
+ import {
1473
+ formatLocatedWikiGraphUri,
1474
+ formatWikiGraphLibraryUri,
1475
+ listWikiGraphLibraries,
1476
+ listWikiGraphLibraryArchives,
1477
+ parseLocatedWikiGraphUri,
1478
+ parseWikiGraphLibraryUri,
1479
+ resolveWikiGraphLibrary,
1480
+ resolveWikiGraphLibraryArchiveFile
1481
+ } from "wiki-graph-core";
1482
+
1483
+ // src/runtime-path.ts
1484
+ import { homedir as homedir3 } from "os";
1485
+ import { isAbsolute as isAbsolute2, resolve as resolve2 } from "path";
1486
+ function resolveWikiGraphRuntimePath(path) {
1487
+ const context = getWikiGraphSDKRuntimeContext();
1488
+ const environmentHome = context.env.HOME?.trim();
1489
+ const home = environmentHome === void 0 || environmentHome === "" ? homedir3() : environmentHome;
1490
+ if (path === "~") return home;
1491
+ if (path.startsWith("~/")) return resolve2(home, path.slice(2));
1492
+ return isAbsolute2(path) ? path : resolve2(context.cwd, path);
1493
+ }
1494
+
1495
+ // src/archive/target.ts
1496
+ var WikiGraphArchiveOwnershipError = class extends Error {
1497
+ code = "WIKI_GRAPH_ARCHIVE_OWNERSHIP_MISMATCH";
1498
+ constructor(message) {
1499
+ super(message);
1500
+ this.name = "WikiGraphArchiveOwnershipError";
1501
+ }
1502
+ };
1503
+ async function resolveWikiGraphArchiveLocation(target) {
1504
+ if (target.kind === "standalone") {
1505
+ return await resolveStandaloneLocation(target);
1506
+ }
1507
+ return await resolveLibraryLocation(target);
1508
+ }
1509
+ async function assertStandaloneWikiGraphArchivePath(inputPath) {
1510
+ const path = resolveWikiGraphRuntimePath(inputPath);
1511
+ const candidate = await canonicalPath(path);
1512
+ const candidateIdentity = await readFileIdentity(path);
1513
+ const libraries = await listWikiGraphLibraries();
1514
+ const matches = await findMatchingMembers(
1515
+ libraries,
1516
+ candidate,
1517
+ candidateIdentity
1518
+ );
1519
+ if (matches.length > 0) {
1520
+ const match = requireUnambiguousManagedMatch(path, matches);
1521
+ throw new WikiGraphArchiveOwnershipError(
1522
+ `Standalone archive path belongs to registered library ${formatWikiGraphLibraryUri(
1523
+ match.library.isDefault ? void 0 : match.library.publicId
1524
+ )}: ${path}. Use the library UUID URI ${match.archive.uri} instead.`
1525
+ );
1526
+ }
1527
+ for (const library of libraries) {
1528
+ const rootPath = getNodeResourcePath(library.folder);
1529
+ const root = await canonicalPath(rootPath);
1530
+ if (!isWithin(root, candidate)) continue;
1531
+ throw new WikiGraphArchiveOwnershipError(
1532
+ `Standalone archive path belongs to registered library ${formatWikiGraphLibraryUri(
1533
+ library.isDefault ? void 0 : library.publicId
1534
+ )}: ${path}. Scan the library, then address the archive by its library UUID URI.`
1535
+ );
1536
+ }
1537
+ return path;
1538
+ }
1539
+ async function resolveWikiGraphArchiveTarget(file) {
1540
+ const path = getNodeResourcePath(file);
1541
+ const candidate = await canonicalPath(path);
1542
+ const candidateIdentity = await readFileIdentity(path);
1543
+ const matches = await findMatchingMembers(
1544
+ await listWikiGraphLibraries(),
1545
+ candidate,
1546
+ candidateIdentity
1547
+ );
1548
+ if (matches.length > 0) {
1549
+ const match = requireUnambiguousManagedMatch(path, matches);
1550
+ return { kind: "library", uri: match.archive.uri };
1551
+ }
1552
+ return { kind: "standalone", path: getNodeResourcePath(file) };
1553
+ }
1554
+ async function resolveStandaloneLocation(target) {
1555
+ if (target.path.startsWith("wikg://lib/")) {
1556
+ throw new WikiGraphArchiveOwnershipError(
1557
+ `A library archive URI cannot be used as a standalone path: ${target.path}`
1558
+ );
1559
+ }
1560
+ const path = await assertStandaloneWikiGraphArchivePath(target.path);
1561
+ const normalized = {
1562
+ kind: "standalone",
1563
+ path,
1564
+ ...target.objectUri === void 0 ? {} : { objectUri: target.objectUri }
1565
+ };
1566
+ return {
1567
+ archiveFile: new NodeFile(path),
1568
+ archiveKey: path,
1569
+ archivePath: path,
1570
+ indexScope: { archiveKey: path, archivePath: path, kind: "archive-index" },
1571
+ locatedUri: formatLocatedWikiGraphUri(path, target.objectUri),
1572
+ target: normalized
1573
+ };
1574
+ }
1575
+ async function resolveLibraryLocation(target) {
1576
+ const parsedLocated = parseLocatedWikiGraphUri(target.uri);
1577
+ const archiveUri = parsedLocated.archivePath ?? target.uri;
1578
+ const parsed = parseWikiGraphLibraryUri(archiveUri);
1579
+ if (parsed?.kind !== "archive") {
1580
+ throw new WikiGraphArchiveOwnershipError(
1581
+ `Library archive target must be a UUID archive URI: ${target.uri}`
1582
+ );
1583
+ }
1584
+ await resolveWikiGraphLibrary(parsed);
1585
+ const archiveFile = await resolveWikiGraphLibraryArchiveFile(archiveUri);
1586
+ const normalized = {
1587
+ kind: "library",
1588
+ uri: target.uri
1589
+ };
1590
+ return {
1591
+ archiveFile,
1592
+ archiveKey: archiveUri,
1593
+ archivePath: archiveUri,
1594
+ indexScope: {
1595
+ archiveKey: archiveUri,
1596
+ archivePath: archiveUri,
1597
+ kind: "archive-index"
1598
+ },
1599
+ libraryArchiveTarget: parsed,
1600
+ locatedUri: target.uri,
1601
+ publicArchiveUri: archiveUri,
1602
+ target: normalized
1603
+ };
1604
+ }
1605
+ async function canonicalPath(path) {
1606
+ try {
1607
+ return await realpath(path);
1608
+ } catch {
1609
+ const absolute = resolve3(path);
1610
+ const parent = dirname2(absolute);
1611
+ return parent === absolute ? absolute : join3(await canonicalPath(parent), basename2(absolute));
1612
+ }
1613
+ }
1614
+ function isWithin(root, candidate) {
1615
+ const child = relative(root, candidate);
1616
+ return child === "" || !child.startsWith("..") && !isAbsolute3(child);
1617
+ }
1618
+ async function findMatchingMembers(libraries, candidate, candidateIdentity) {
1619
+ const members = [];
1620
+ for (const library of libraries) {
1621
+ const archives = await listWikiGraphLibraryArchives({
1622
+ isDefault: library.isDefault,
1623
+ kind: "scope",
1624
+ ...library.isDefault ? {} : { publicId: library.publicId }
1625
+ });
1626
+ for (const archive of archives) {
1627
+ if (archive.file === void 0) continue;
1628
+ members.push({
1629
+ archive,
1630
+ library,
1631
+ memberPath: getNodeResourcePath(archive.file)
1632
+ });
1633
+ }
1634
+ }
1635
+ const exact = [];
1636
+ for (const member of members) {
1637
+ if (await canonicalPath(member.memberPath) === candidate) {
1638
+ exact.push(member);
1639
+ }
1640
+ }
1641
+ if (exact.length > 0 || candidateIdentity === void 0) return exact;
1642
+ const identityMatches = [];
1643
+ for (const member of members) {
1644
+ if (await readFileIdentity(member.memberPath) === candidateIdentity) {
1645
+ identityMatches.push(member);
1646
+ }
1647
+ }
1648
+ return identityMatches;
1649
+ }
1650
+ function requireUnambiguousManagedMatch(path, matches) {
1651
+ if (matches.length === 1) return matches[0];
1652
+ throw new WikiGraphArchiveOwnershipError(
1653
+ `Archive file identity is ambiguous across managed archives: ${path}. Use an explicit library UUID URI (${matches.map((match) => match.archive.uri).join(", ")}).`
1654
+ );
1655
+ }
1656
+ async function readFileIdentity(path) {
1657
+ try {
1658
+ const value = await stat2(path);
1659
+ return `${value.dev}:${value.ino}`;
1660
+ } catch {
1661
+ return void 0;
1662
+ }
1663
+ }
1664
+
1665
+ // src/archive/write.ts
1666
+ import {
1667
+ WikiGraphArchiveFile,
1668
+ writeWikiGraphLibraryArchive
1669
+ } from "wiki-graph-core";
1670
+ async function writeWikiGraphArchiveLocation(location, operation, options = {}) {
1671
+ const cacheOnly = options.searchIndexWritebackPolicy === "cache";
1672
+ const write = async (archiveFile = location.archiveFile) => await new WikiGraphArchiveFile(archiveFile).write(operation, {
1673
+ ...cacheOnly ? {} : { derivedStateKeys: [location.archiveKey, location.archivePath] },
1674
+ ...options.invalidateContinuationCursors === void 0 ? {} : {
1675
+ invalidateContinuationCursors: options.invalidateContinuationCursors
1676
+ },
1677
+ ...options.searchIndexWritebackPolicy === void 0 ? {} : { searchIndexWritebackPolicy: options.searchIndexWritebackPolicy }
1678
+ });
1679
+ if (location.libraryArchiveTarget === void 0 || cacheOnly || options.refreshLibraryIndex === false) {
1680
+ return await write();
1681
+ }
1682
+ return await writeWikiGraphLibraryArchive({
1683
+ additionalDerivedStateKeys: [location.archiveKey, location.archivePath],
1684
+ ...options.invalidateContinuationCursors === void 0 ? {} : {
1685
+ invalidateContinuationCursors: options.invalidateContinuationCursors
1686
+ },
1687
+ ...options.onIndexSyncError === void 0 ? {} : { onIndexSyncError: options.onIndexSyncError },
1688
+ operation: async (archiveFile) => await write(archiveFile),
1689
+ target: location.libraryArchiveTarget
1690
+ });
1691
+ }
1692
+
1693
+ // src/worker.ts
1442
1694
  import {
1443
1695
  applyChapterJobArtifactFile as applyChapterJobArtifactFile2,
1444
1696
  createLocalChapterJobFileExecutor,
1445
- writeChapterJobInputFile
1697
+ writeChapterJobInputFile as writeChapterJobInputFile2
1446
1698
  } from "wiki-graph-core/worker";
1447
1699
  async function runBuildJobWorker(options) {
1448
1700
  installNodeWikiGraphPlatform();
@@ -1455,7 +1707,11 @@ async function runBuildJobWorker(options) {
1455
1707
 
1456
1708
  // src/default-worker.ts
1457
1709
  async function runWikiGraphQueueWorker(options = {}) {
1458
- const config = await loadWikiGraphRuntimeConfig();
1710
+ const providers = getWikiGraphSDKProviders();
1711
+ const config = await loadWikiGraphRuntimeConfig({
1712
+ ...providers.embedding === void 0 ? {} : { skipEmbeddingConfig: true },
1713
+ ...providers.llm === void 0 ? {} : { skipLLMConfig: true }
1714
+ });
1459
1715
  await runBuildJobWorker({
1460
1716
  concurrency: config.concurrent?.job ?? DEFAULT_GENERATION_JOB_CONCURRENCY,
1461
1717
  executeJob: async (job, reporter, context) => {
@@ -1464,12 +1720,16 @@ async function runWikiGraphQueueWorker(options = {}) {
1464
1720
  async () => await executeBuildJob(job, reporter, context)
1465
1721
  );
1466
1722
  },
1723
+ ...options.idleTimeoutMs === void 0 ? {} : { idleTimeoutMs: options.idleTimeoutMs },
1467
1724
  ...options.signal === void 0 ? {} : { signal: options.signal }
1468
1725
  });
1469
1726
  }
1470
1727
  async function executeBuildJob(job, reporter, context) {
1728
+ const providers = getWikiGraphSDKProviders();
1471
1729
  const config = await loadWikiGraphRuntimeConfig({
1472
- ...job.llmJSON === void 0 ? {} : { llmJSON: job.llmJSON }
1730
+ ...job.llmJSON === void 0 ? {} : { llmJSON: job.llmJSON },
1731
+ ...providers.embedding === void 0 ? {} : { skipEmbeddingConfig: true },
1732
+ ...job.llmJSON === void 0 && providers.llm !== void 0 ? { skipLLMConfig: true } : {}
1473
1733
  });
1474
1734
  const execution = await openJobExecutor(
1475
1735
  job,
@@ -1531,10 +1791,10 @@ async function executeStep(job, kind, execution, reporter, context, inputOptions
1531
1791
  const stepWorkspace = await resetStepWorkspace(job.workspace, kind);
1532
1792
  const inputFile = await stepWorkspace.createFile("input.jsonl");
1533
1793
  const outputWorkspace = await stepWorkspace.createDirectory("output");
1534
- const revision = await new WikiGraphArchiveFile2(job.archive).readDocument(
1794
+ const revision = await new WikiGraphArchiveFile3(job.archive).readDocument(
1535
1795
  async (document) => {
1536
1796
  await getChapterDetails(document, job.chapterId);
1537
- return await writeChapterJobInputFile2(
1797
+ return await writeChapterJobInputFile3(
1538
1798
  document,
1539
1799
  job.chapterId,
1540
1800
  kind,
@@ -1573,16 +1833,23 @@ async function executeStep(job, kind, execution, reporter, context, inputOptions
1573
1833
  total: 1,
1574
1834
  unit: "item"
1575
1835
  });
1576
- await new WikiGraphArchiveFile2(job.archive).write(async (document) => {
1577
- assertJobStillRunning(await getBuildJob(job.jobId));
1578
- await applyChapterJobArtifactFile3(
1579
- document,
1580
- job.chapterId,
1581
- kind,
1582
- revision,
1583
- result.artifactFile
1584
- );
1585
- });
1836
+ const target = await resolveWikiGraphArchiveTarget(job.archive);
1837
+ const resolvedLocation = await resolveWikiGraphArchiveLocation(target);
1838
+ const location = target.kind === "standalone" ? { ...resolvedLocation, archiveFile: job.archive } : resolvedLocation;
1839
+ await writeWikiGraphArchiveLocation(
1840
+ location,
1841
+ async (document) => {
1842
+ assertJobStillRunning(await getBuildJob(job.jobId));
1843
+ await applyChapterJobArtifactFile3(
1844
+ document,
1845
+ job.chapterId,
1846
+ kind,
1847
+ revision,
1848
+ result.artifactFile
1849
+ );
1850
+ },
1851
+ { invalidateContinuationCursors: true }
1852
+ );
1586
1853
  await reporter.updatePhase({
1587
1854
  done: 1,
1588
1855
  phase: "committing",
@@ -1597,12 +1864,17 @@ async function openJobExecutor(job, config, signal, reporter) {
1597
1864
  const stageConfig = generation ? await loadRequiredStageConfig({
1598
1865
  ...job.llmJSON === void 0 ? {} : { llmJSON: job.llmJSON }
1599
1866
  }) : void 0;
1867
+ const injectedLLM = job.llmJSON === void 0 ? getWikiGraphSDKProviders().llm : void 0;
1600
1868
  const llm = stageConfig === void 0 ? void 0 : createStageLLM(stageConfig, {
1601
1869
  cacheDirectory: job.cache,
1602
1870
  logDirectory: job.log,
1603
1871
  onTokenUsage: async (usage) => {
1604
1872
  await reporter.addTokenUsage(usage);
1605
- }
1873
+ },
1874
+ onStreamProgress: async ({ outputCharacters }) => {
1875
+ await reporter.addOutputCharacters(outputCharacters);
1876
+ },
1877
+ ...injectedLLM === void 0 ? {} : { provider: injectedLLM }
1606
1878
  });
1607
1879
  const promptSource = job.prompt ?? stageConfig?.prompt;
1608
1880
  const wikispine = job.target === "knowledge-graph" ? requireKnowledgeGraphWikispineConfig(config) : void 0;
@@ -1621,6 +1893,10 @@ async function openJobExecutor(job, config, signal, reporter) {
1621
1893
  llmRequest: requireValue(
1622
1894
  request,
1623
1895
  "Local Wikimedia resolution requires an LLM."
1896
+ ),
1897
+ llmModelId: requireValue(
1898
+ stageConfig?.llm?.model ?? injectedLLM?.model,
1899
+ "Local Wikimedia resolution requires an LLM model."
1624
1900
  )
1625
1901
  } : {
1626
1902
  endpoint: config.wikimedia.endpoint,
@@ -1628,7 +1904,7 @@ async function openJobExecutor(job, config, signal, reporter) {
1628
1904
  token: config.wikimedia.token
1629
1905
  }
1630
1906
  );
1631
- const embeddingProvider = job.target === "index-embedding-source" || job.target === "index-embedding-summary" ? buildSearchIndexEmbeddingProvider(requireEmbeddingConfig(config)) : void 0;
1907
+ const embeddingProvider = job.target === "index-embedding-source" || job.target === "index-embedding-summary" ? getWikiGraphSDKProviders().embedding ?? buildSearchIndexEmbeddingProvider(requireEmbeddingConfig(config)) : void 0;
1632
1908
  return {
1633
1909
  async close() {
1634
1910
  await wikimediaResolver?.close();
@@ -1658,12 +1934,12 @@ async function resetStepWorkspace(workspace, kind) {
1658
1934
  return await workspace.createDirectory(name);
1659
1935
  }
1660
1936
  async function readChapterStage(job) {
1661
- return await new WikiGraphArchiveFile2(job.archive).readDocument(
1937
+ return await new WikiGraphArchiveFile3(job.archive).readDocument(
1662
1938
  async (document) => (await getChapterDetails(document, job.chapterId)).stage
1663
1939
  );
1664
1940
  }
1665
1941
  async function assertCurrentFtsArtifact(job) {
1666
- await new WikiGraphArchiveFile2(job.archive).readDocument(async (document) => {
1942
+ await new WikiGraphArchiveFile3(job.archive).readDocument(async (document) => {
1667
1943
  const revision = await document.serials.getRevision(job.chapterId);
1668
1944
  const artifact = await document.indexArtifacts.get(job.chapterId, "fts");
1669
1945
  if (artifact?.sourceRevision !== revision) {