wiki-graph-sdk 0.7.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 (98) hide show
  1. package/LICENSE +201 -0
  2. package/README.md +32 -0
  3. package/dist/archives.cjs +2799 -0
  4. package/dist/archives.cjs.map +1 -0
  5. package/dist/archives.d.ts +249 -0
  6. package/dist/archives.js +2814 -0
  7. package/dist/archives.js.map +1 -0
  8. package/dist/conversions.cjs +1332 -0
  9. package/dist/conversions.cjs.map +1 -0
  10. package/dist/conversions.d.ts +37 -0
  11. package/dist/conversions.js +1308 -0
  12. package/dist/conversions.js.map +1 -0
  13. package/dist/data/editor/clue_reviewer.jinja +410 -0
  14. package/dist/data/editor/clue_reviewer_generator.jinja +428 -0
  15. package/dist/data/editor/revision_feedback.jinja +5 -0
  16. package/dist/data/editor/text_compressor.jinja +131 -0
  17. package/dist/data/guaranteed/response_intent_classifier.jinja +8 -0
  18. package/dist/data/output/epub/cover.xhtml.jinja +13 -0
  19. package/dist/data/output/epub/nav.xhtml.jinja +12 -0
  20. package/dist/data/output/epub/package.opf.xml.jinja +39 -0
  21. package/dist/data/output/epub/section.xhtml.jinja +12 -0
  22. package/dist/data/topologization/book_coherence_extraction.jinja +223 -0
  23. package/dist/data/topologization/chunk_extraction.jinja +233 -0
  24. package/dist/data/topologization/evidence_choice.jinja +38 -0
  25. package/dist/data/topologization/translate_chunks.jinja +138 -0
  26. package/dist/data/topologization/user_focused_extraction.jinja +378 -0
  27. package/dist/default-worker.cjs +1709 -0
  28. package/dist/default-worker.cjs.map +1 -0
  29. package/dist/default-worker.d.ts +10 -0
  30. package/dist/default-worker.js +1705 -0
  31. package/dist/default-worker.js.map +1 -0
  32. package/dist/embedding.cjs +1091 -0
  33. package/dist/embedding.cjs.map +1 -0
  34. package/dist/embedding.d.ts +26 -0
  35. package/dist/embedding.js +1062 -0
  36. package/dist/embedding.js.map +1 -0
  37. package/dist/entry-context.cjs +91 -0
  38. package/dist/entry-context.cjs.map +1 -0
  39. package/dist/entry-context.d.ts +20 -0
  40. package/dist/entry-context.js +68 -0
  41. package/dist/entry-context.js.map +1 -0
  42. package/dist/gc.cjs +731 -0
  43. package/dist/gc.cjs.map +1 -0
  44. package/dist/gc.d.ts +14 -0
  45. package/dist/gc.js +707 -0
  46. package/dist/gc.js.map +1 -0
  47. package/dist/index.cjs +4760 -0
  48. package/dist/index.cjs.map +1 -0
  49. package/dist/index.d.ts +213 -0
  50. package/dist/index.js +4808 -0
  51. package/dist/index.js.map +1 -0
  52. package/dist/jobs-Dd5PMSId.d.ts +98 -0
  53. package/dist/llm.cjs +101 -0
  54. package/dist/llm.cjs.map +1 -0
  55. package/dist/llm.d.ts +7 -0
  56. package/dist/llm.js +79 -0
  57. package/dist/llm.js.map +1 -0
  58. package/dist/local-config.cjs +1024 -0
  59. package/dist/local-config.cjs.map +1 -0
  60. package/dist/local-config.d.ts +14 -0
  61. package/dist/local-config.js +989 -0
  62. package/dist/local-config.js.map +1 -0
  63. package/dist/maintenance.cjs +800 -0
  64. package/dist/maintenance.cjs.map +1 -0
  65. package/dist/maintenance.d.ts +24 -0
  66. package/dist/maintenance.js +778 -0
  67. package/dist/maintenance.js.map +1 -0
  68. package/dist/node-platform.cjs +758 -0
  69. package/dist/node-platform.cjs.map +1 -0
  70. package/dist/node-platform.d.ts +49 -0
  71. package/dist/node-platform.js +723 -0
  72. package/dist/node-platform.js.map +1 -0
  73. package/dist/planning.cjs +164 -0
  74. package/dist/planning.cjs.map +1 -0
  75. package/dist/planning.d.ts +43 -0
  76. package/dist/planning.js +137 -0
  77. package/dist/planning.js.map +1 -0
  78. package/dist/runtime-config.cjs +1155 -0
  79. package/dist/runtime-config.cjs.map +1 -0
  80. package/dist/runtime-config.d.ts +50 -0
  81. package/dist/runtime-config.js +1127 -0
  82. package/dist/runtime-config.js.map +1 -0
  83. package/dist/stage.cjs +1265 -0
  84. package/dist/stage.cjs.map +1 -0
  85. package/dist/stage.d.ts +16 -0
  86. package/dist/stage.js +1239 -0
  87. package/dist/stage.js.map +1 -0
  88. package/dist/wikispine.cjs +85 -0
  89. package/dist/wikispine.cjs.map +1 -0
  90. package/dist/wikispine.d.ts +6 -0
  91. package/dist/wikispine.js +63 -0
  92. package/dist/wikispine.js.map +1 -0
  93. package/dist/worker.cjs +738 -0
  94. package/dist/worker.cjs.map +1 -0
  95. package/dist/worker.d.ts +157 -0
  96. package/dist/worker.js +715 -0
  97. package/dist/worker.js.map +1 -0
  98. package/package.json +151 -0
@@ -0,0 +1,1709 @@
1
+ globalThis.__WIKIGRAPH_DATA_DIR__ ??= require("path").resolve(__dirname, "data");
2
+ "use strict";
3
+ var __create = Object.create;
4
+ var __defProp = Object.defineProperty;
5
+ var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
6
+ var __getOwnPropNames = Object.getOwnPropertyNames;
7
+ var __getProtoOf = Object.getPrototypeOf;
8
+ var __hasOwnProp = Object.prototype.hasOwnProperty;
9
+ var __export = (target, all) => {
10
+ for (var name in all)
11
+ __defProp(target, name, { get: all[name], enumerable: true });
12
+ };
13
+ var __copyProps = (to, from, except, desc) => {
14
+ if (from && typeof from === "object" || typeof from === "function") {
15
+ for (let key of __getOwnPropNames(from))
16
+ if (!__hasOwnProp.call(to, key) && key !== except)
17
+ __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
18
+ }
19
+ return to;
20
+ };
21
+ var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps(
22
+ // If the importer is in node compatibility mode or this is not an ESM
23
+ // file that has been converted to a CommonJS file using a Babel-
24
+ // compatible transform (i.e. "__esModule" has not been set), then set
25
+ // "default" to the CommonJS "module.exports" for node compatibility.
26
+ isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: true }) : target,
27
+ mod
28
+ ));
29
+ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
30
+
31
+ // src/default-worker.ts
32
+ var default_worker_exports = {};
33
+ __export(default_worker_exports, {
34
+ requireKnowledgeGraphWikispineConfig: () => requireKnowledgeGraphWikispineConfig,
35
+ runWikiGraphQueueWorker: () => runWikiGraphQueueWorker
36
+ });
37
+ module.exports = __toCommonJS(default_worker_exports);
38
+ var import_wiki_graph_core5 = require("wiki-graph-core");
39
+ var import_worker3 = require("wiki-graph-core/worker");
40
+
41
+ // src/embedding.ts
42
+ var import_ai = require("ai");
43
+ var import_openai = require("@ai-sdk/openai");
44
+ var import_openai_compatible = require("@ai-sdk/openai-compatible");
45
+
46
+ // src/local-config.ts
47
+ var import_wiki_graph_core = require("wiki-graph-core");
48
+
49
+ // src/runtime-context.ts
50
+ var import_async_hooks = require("async_hooks");
51
+ var RUNTIME_CONTEXT_KEY = /* @__PURE__ */ Symbol.for("wiki-graph-sdk.runtime-context.v1");
52
+ var runtimeContext = getRuntimeContextStorage();
53
+ function getRuntimeContextStorage() {
54
+ const runtimeGlobal = globalThis;
55
+ const existing = runtimeGlobal[RUNTIME_CONTEXT_KEY];
56
+ if (existing !== void 0) {
57
+ return existing;
58
+ }
59
+ const storage = new import_async_hooks.AsyncLocalStorage();
60
+ Object.defineProperty(runtimeGlobal, RUNTIME_CONTEXT_KEY, {
61
+ configurable: false,
62
+ enumerable: false,
63
+ value: storage,
64
+ writable: false
65
+ });
66
+ return storage;
67
+ }
68
+ function getWikiGraphSDKRuntimeContext() {
69
+ return runtimeContext.getStore() ?? {
70
+ cwd: process.cwd(),
71
+ env: process.env,
72
+ envPolicy: "production"
73
+ };
74
+ }
75
+ function getWikiGraphSDKStateDir() {
76
+ return getWikiGraphSDKRuntimeContext().stateDir;
77
+ }
78
+
79
+ // src/node-platform.ts
80
+ var asyncHooks = __toESM(require("async_hooks"), 1);
81
+ var crypto = __toESM(require("crypto"), 1);
82
+ var fs = __toESM(require("fs"), 1);
83
+ var fsPromises = __toESM(require("fs/promises"), 1);
84
+ var os = __toESM(require("os"), 1);
85
+ var pathModule = __toESM(require("path"), 1);
86
+ var process2 = __toESM(require("process"), 1);
87
+ var import_node_stream = require("stream");
88
+ var import_promises = require("stream/promises");
89
+ var sqlite3 = __toESM(require("sqlite3"), 1);
90
+ var yauzl = __toESM(require("yauzl"), 1);
91
+ var yazl = __toESM(require("yazl"), 1);
92
+ var import_nunjucks = require("nunjucks");
93
+ var import_platform = require("wiki-graph-core/platform");
94
+ var nodeProcess = process2.default ?? process2;
95
+ var nodeSqlite3 = sqlite3.default ?? sqlite3;
96
+ var NODE_RESOURCE_KIND = /* @__PURE__ */ Symbol.for("wiki-graph-sdk.node-resource.v1");
97
+ var NodeFile = class {
98
+ constructor(path, name = pathModule.basename(path)) {
99
+ this.path = path;
100
+ this.identity = encodeNodeResourceIdentity("file", path);
101
+ this.name = name;
102
+ }
103
+ path;
104
+ kind = "file";
105
+ [NODE_RESOURCE_KIND] = "file";
106
+ identity;
107
+ name;
108
+ async openReader() {
109
+ const handle = await fsPromises.open(this.path, "r");
110
+ let closed = false;
111
+ try {
112
+ const stats = await handle.stat();
113
+ if (!stats.isFile())
114
+ throw new Error("File reader requires a regular file");
115
+ const { size } = stats;
116
+ return {
117
+ size,
118
+ close: async () => {
119
+ if (!closed) await handle.close();
120
+ closed = true;
121
+ },
122
+ read: async (offset, length) => {
123
+ if (closed) throw new Error("Cannot read from a closed FileReader");
124
+ assertFileRange(offset, length, size);
125
+ const buffer = Buffer.allocUnsafe(length);
126
+ let bytesRead = 0;
127
+ while (bytesRead < length) {
128
+ const result = await handle.read(
129
+ buffer,
130
+ bytesRead,
131
+ length - bytesRead,
132
+ offset + bytesRead
133
+ );
134
+ if (result.bytesRead === 0) {
135
+ throw new Error("File changed while reading its byte range");
136
+ }
137
+ bytesRead += result.bytesRead;
138
+ }
139
+ return new Uint8Array(buffer.buffer, buffer.byteOffset, bytesRead);
140
+ }
141
+ };
142
+ } catch (error) {
143
+ await handle.close();
144
+ throw error;
145
+ }
146
+ }
147
+ async getLastModified() {
148
+ try {
149
+ return (await fsPromises.stat(this.path)).mtimeMs;
150
+ } catch (error) {
151
+ if (typeof error === "object" && error !== null && "code" in error && error.code === "ENOENT") {
152
+ return void 0;
153
+ }
154
+ throw error;
155
+ }
156
+ }
157
+ async openWriter() {
158
+ await fsPromises.mkdir(pathModule.dirname(this.path), { recursive: true });
159
+ const temporary = `${this.path}.tmp-${crypto.randomUUID()}`;
160
+ const handle = await fsPromises.open(temporary, "wx");
161
+ let closed = false;
162
+ return {
163
+ write: async (data) => {
164
+ if (closed) throw new Error("Cannot write to a closed FileWriter");
165
+ await writeNodeFileHandle(handle, data);
166
+ },
167
+ writeAt: async (offset, data) => {
168
+ if (closed) throw new Error("Cannot write to a closed FileWriter");
169
+ assertFileOffset(offset);
170
+ await writeNodeFileHandle(handle, data, offset);
171
+ },
172
+ commit: async () => {
173
+ if (!closed) {
174
+ await handle.close();
175
+ await fsPromises.rename(temporary, this.path);
176
+ }
177
+ closed = true;
178
+ },
179
+ abort: async () => {
180
+ if (!closed) {
181
+ await handle.close();
182
+ await fsPromises.rm(temporary, { force: true });
183
+ }
184
+ closed = true;
185
+ }
186
+ };
187
+ }
188
+ };
189
+ async function writeNodeFileHandle(handle, data, position) {
190
+ const buffer = Buffer.from(data);
191
+ let written = 0;
192
+ while (written < buffer.byteLength) {
193
+ const result = await handle.write(
194
+ buffer,
195
+ written,
196
+ buffer.byteLength - written,
197
+ position === void 0 ? null : position + written
198
+ );
199
+ if (result.bytesWritten === 0) {
200
+ throw new Error("File writer made no progress");
201
+ }
202
+ written += result.bytesWritten;
203
+ }
204
+ }
205
+ function assertFileRange(offset, length, size) {
206
+ assertFileOffset(offset);
207
+ if (!Number.isSafeInteger(length) || length < 0) {
208
+ throw new RangeError(
209
+ "File read length must be a non-negative safe integer"
210
+ );
211
+ }
212
+ if (offset > size || length > size - offset) {
213
+ throw new RangeError("File read range exceeds the file size");
214
+ }
215
+ }
216
+ function assertFileOffset(offset) {
217
+ if (!Number.isSafeInteger(offset) || offset < 0) {
218
+ throw new RangeError("File offset must be a non-negative safe integer");
219
+ }
220
+ }
221
+ var NodeDirectory = class _NodeDirectory {
222
+ constructor(path) {
223
+ this.path = path;
224
+ this.identity = encodeNodeResourceIdentity("directory", path);
225
+ this.name = pathModule.basename(path);
226
+ }
227
+ path;
228
+ kind = "directory";
229
+ [NODE_RESOURCE_KIND] = "directory";
230
+ identity;
231
+ name;
232
+ async getFile(name) {
233
+ assertChildName(name);
234
+ const file = new NodeFile(pathModule.join(this.path, name));
235
+ try {
236
+ return (await fsPromises.stat(file.path)).isFile() ? file : void 0;
237
+ } catch {
238
+ return void 0;
239
+ }
240
+ }
241
+ async getLastModified() {
242
+ try {
243
+ return (await fsPromises.stat(this.path)).mtimeMs;
244
+ } catch (error) {
245
+ if (typeof error === "object" && error !== null && "code" in error && error.code === "ENOENT") {
246
+ return void 0;
247
+ }
248
+ throw error;
249
+ }
250
+ }
251
+ async getDirectory(name) {
252
+ assertChildName(name);
253
+ const directory = new _NodeDirectory(pathModule.join(this.path, name));
254
+ try {
255
+ return (await fsPromises.stat(directory.path)).isDirectory() ? directory : void 0;
256
+ } catch {
257
+ return void 0;
258
+ }
259
+ }
260
+ async list() {
261
+ const entries = await fsPromises.readdir(this.path, {
262
+ withFileTypes: true
263
+ });
264
+ return entries.map(
265
+ (entry) => entry.isDirectory() ? new _NodeDirectory(pathModule.join(this.path, entry.name)) : new NodeFile(pathModule.join(this.path, entry.name), entry.name)
266
+ );
267
+ }
268
+ async createFile(name) {
269
+ assertChildName(name);
270
+ await fsPromises.mkdir(this.path, { recursive: true });
271
+ const file = new NodeFile(pathModule.join(this.path, name));
272
+ await fsPromises.writeFile(file.path, "", { flag: "wx" });
273
+ return file;
274
+ }
275
+ async createDirectory(name) {
276
+ assertChildName(name);
277
+ await fsPromises.mkdir(this.path, { recursive: true });
278
+ const directory = new _NodeDirectory(pathModule.join(this.path, name));
279
+ await fsPromises.mkdir(directory.path);
280
+ return directory;
281
+ }
282
+ async remove(name, options) {
283
+ assertChildName(name);
284
+ await fsPromises.rm(pathModule.join(this.path, name), {
285
+ force: true,
286
+ recursive: options?.recursive === true
287
+ });
288
+ }
289
+ };
290
+ function encodeNodeResourceIdentity(kind, path) {
291
+ return `node-${kind}:${Buffer.from(pathModule.resolve(path), "utf8").toString("base64url")}`;
292
+ }
293
+ function decodeNodeResourceIdentity(identity, kind) {
294
+ const prefix = `node-${kind}:`;
295
+ if (!identity.startsWith(prefix)) {
296
+ return pathModule.isAbsolute(identity) ? identity : void 0;
297
+ }
298
+ try {
299
+ return Buffer.from(identity.slice(prefix.length), "base64url").toString(
300
+ "utf8"
301
+ );
302
+ } catch {
303
+ return void 0;
304
+ }
305
+ }
306
+ function assertChildName(name) {
307
+ if (name.length === 0 || name === "." || name === ".." || pathModule.isAbsolute(name) || name.includes("/") || name.includes("\\")) {
308
+ throw new TypeError(`Directory child must be a relative name: ${name}`);
309
+ }
310
+ }
311
+ var NodeDatabaseConnection = class {
312
+ constructor(database) {
313
+ this.database = database;
314
+ }
315
+ database;
316
+ async close() {
317
+ await new Promise((resolve2, reject) => {
318
+ this.database.close((error) => {
319
+ if (error) reject(error);
320
+ else resolve2();
321
+ });
322
+ });
323
+ }
324
+ async execute(sql) {
325
+ await new Promise((resolve2, reject) => {
326
+ this.database.exec(sql, (error) => {
327
+ if (error) reject(error);
328
+ else resolve2();
329
+ });
330
+ });
331
+ }
332
+ async queryAll(sql, params = []) {
333
+ return await new Promise((resolve2, reject) => {
334
+ this.database.all(sql, [...params], (error, rows) => {
335
+ if (error) reject(error);
336
+ else resolve2(rows);
337
+ });
338
+ });
339
+ }
340
+ async queryOne(sql, params = []) {
341
+ return await new Promise((resolve2, reject) => {
342
+ this.database.get(sql, [...params], (error, row) => {
343
+ if (error) reject(error);
344
+ else resolve2(row);
345
+ });
346
+ });
347
+ }
348
+ async run(sql, params = []) {
349
+ await new Promise((resolve2, reject) => {
350
+ this.database.run(sql, [...params], (error) => {
351
+ if (error) reject(error);
352
+ else resolve2();
353
+ });
354
+ });
355
+ }
356
+ };
357
+ async function openNodeDatabase(file, options) {
358
+ const flags = (options.mode === "readonly" ? nodeSqlite3.OPEN_READONLY : nodeSqlite3.OPEN_READWRITE | (options.create ? nodeSqlite3.OPEN_CREATE : 0)) | nodeSqlite3.OPEN_FULLMUTEX;
359
+ return new NodeDatabaseConnection(await openNativeNodeDatabase(file, flags));
360
+ }
361
+ async function openNativeNodeDatabase(file, flags) {
362
+ const path = getBrandedNodeResourcePath(file, "file");
363
+ if (path === void 0) {
364
+ throw new TypeError("The Node database adapter requires a NodeFile");
365
+ }
366
+ return await new Promise((resolve2, reject) => {
367
+ const database = new nodeSqlite3.Database(path, flags, (error) => {
368
+ if (error) reject(error);
369
+ else resolve2(database);
370
+ });
371
+ });
372
+ }
373
+ async function openNodeZip(file) {
374
+ const path = getBrandedNodeResourcePath(file, "file");
375
+ if (path === void 0) {
376
+ throw new TypeError("The Node ZIP adapter requires a NodeFile");
377
+ }
378
+ const zipFile = await new Promise((resolve2, reject) => {
379
+ yauzl.open(
380
+ path,
381
+ { autoClose: false, lazyEntries: true },
382
+ (error, opened) => {
383
+ if (error || opened === void 0)
384
+ reject(error ?? new Error("Cannot open ZIP"));
385
+ else resolve2(opened);
386
+ }
387
+ );
388
+ });
389
+ const entries = await new Promise(
390
+ (resolve2, reject) => {
391
+ const discovered = /* @__PURE__ */ new Map();
392
+ const rejectAndClose = (error) => {
393
+ zipFile.close();
394
+ reject(
395
+ error instanceof Error ? error : new Error("Cannot scan ZIP central directory")
396
+ );
397
+ };
398
+ const resolveEntries = () => {
399
+ zipFile.off("error", rejectAndClose);
400
+ resolve2(discovered);
401
+ };
402
+ zipFile.on("entry", (entry) => {
403
+ if (!entry.fileName.endsWith("/")) {
404
+ discovered.set(entry.fileName, entry);
405
+ }
406
+ zipFile.readEntry();
407
+ });
408
+ zipFile.once("error", rejectAndClose);
409
+ zipFile.once("end", resolveEntries);
410
+ zipFile.readEntry();
411
+ }
412
+ );
413
+ let closed = false;
414
+ return {
415
+ close: () => {
416
+ if (!closed) zipFile.close();
417
+ closed = true;
418
+ return Promise.resolve();
419
+ },
420
+ copyEntry: async (name, target) => {
421
+ if (closed) throw new Error("Cannot read a closed ZIP archive");
422
+ const entry = entries.get(name);
423
+ if (entry === void 0) return false;
424
+ await copyNodeZipEntry(zipFile, entry, target);
425
+ return true;
426
+ },
427
+ getEntrySize: (name) => {
428
+ if (closed) throw new Error("Cannot read a closed ZIP archive");
429
+ return Promise.resolve(entries.get(name)?.uncompressedSize);
430
+ },
431
+ listEntries: () => Promise.resolve([...entries.keys()]),
432
+ readEntryRange: async (name, offset, length) => {
433
+ if (closed) throw new Error("Cannot read a closed ZIP archive");
434
+ const entry = entries.get(name);
435
+ if (entry === void 0) return void 0;
436
+ return await readNodeZipEntryRange(zipFile, entry, offset, length);
437
+ },
438
+ readEntry: async (name) => {
439
+ if (closed) throw new Error("Cannot read a closed ZIP archive");
440
+ const entry = entries.get(name);
441
+ if (entry === void 0) return void 0;
442
+ return await readNodeZipEntry(zipFile, entry);
443
+ }
444
+ };
445
+ }
446
+ async function copyNodeZipEntry(zipFile, entry, target) {
447
+ const writer = await target.openWriter();
448
+ try {
449
+ const stream = await openNodeZipEntryStream(zipFile, entry);
450
+ await writeNodeStream(stream, writer);
451
+ await writer.commit();
452
+ } catch (error) {
453
+ await writer.abort().catch(() => void 0);
454
+ throw error;
455
+ }
456
+ }
457
+ async function readNodeZipEntry(zipFile, entry) {
458
+ return await collectNodeStream(await openNodeZipEntryStream(zipFile, entry));
459
+ }
460
+ async function readNodeZipEntryRange(zipFile, entry, offset, length) {
461
+ assertFileRange(offset, length, entry.uncompressedSize);
462
+ if (length === 0) return new Uint8Array();
463
+ if (entry.compressionMethod !== 0) {
464
+ const content2 = await collectDecodedNodeStreamRange(
465
+ await openNodeZipEntryStream(zipFile, entry),
466
+ offset,
467
+ length
468
+ );
469
+ return new Uint8Array(
470
+ content2.buffer,
471
+ content2.byteOffset,
472
+ content2.byteLength
473
+ );
474
+ }
475
+ const content = await collectNodeStream(
476
+ await openNodeZipEntryStream(zipFile, entry, {
477
+ decompress: null,
478
+ decrypt: null,
479
+ end: offset + length,
480
+ start: offset
481
+ })
482
+ );
483
+ return new Uint8Array(content.buffer, content.byteOffset, content.byteLength);
484
+ }
485
+ async function collectDecodedNodeStreamRange(input, offset, length) {
486
+ const chunks = [];
487
+ const end = offset + length;
488
+ let position = 0;
489
+ let collected = 0;
490
+ for await (const value of input) {
491
+ const chunk = Buffer.isBuffer(value) ? value : Buffer.from(value);
492
+ const chunkEnd = position + chunk.byteLength;
493
+ if (chunkEnd > offset && position < end) {
494
+ const selected = chunk.subarray(
495
+ Math.max(0, offset - position),
496
+ Math.min(chunk.byteLength, end - position)
497
+ );
498
+ chunks.push(selected);
499
+ collected += selected.byteLength;
500
+ }
501
+ position = chunkEnd;
502
+ if (position >= end) break;
503
+ }
504
+ if (collected !== length) {
505
+ throw new Error("ZIP entry changed while reading its byte range");
506
+ }
507
+ return Buffer.concat(chunks, collected);
508
+ }
509
+ async function openNodeZipEntryStream(zipFile, entry, options) {
510
+ return await new Promise((resolve2, reject) => {
511
+ const callback = (error, opened) => {
512
+ if (error || opened === void 0) {
513
+ reject(error ?? new Error(`Cannot read ZIP entry: ${entry.fileName}`));
514
+ } else {
515
+ resolve2(opened);
516
+ }
517
+ };
518
+ if (options === void 0) zipFile.openReadStream(entry, callback);
519
+ else zipFile.openReadStream(entry, options, callback);
520
+ });
521
+ }
522
+ async function writeNodeZip(file, entries) {
523
+ const zipFile = new yazl.ZipFile();
524
+ const writer = await file.openWriter();
525
+ const outputStream = zipFile.outputStream;
526
+ const outputDone = writeNodeStream(outputStream, writer);
527
+ const entryState = { cancelled: false, complete: false };
528
+ let iterator;
529
+ try {
530
+ iterator = getNodeZipEntryIterator(entries);
531
+ const entriesDone = addNodeZipEntries(zipFile, iterator, entryState);
532
+ await Promise.race([entriesDone, outputDone]);
533
+ if (!entryState.complete) {
534
+ throw new Error("ZIP output ended before entry production completed");
535
+ }
536
+ zipFile.end();
537
+ await outputDone;
538
+ await writer.commit();
539
+ } catch (error) {
540
+ entryState.cancelled = true;
541
+ if (!entryState.complete && iterator !== void 0) {
542
+ closeNodeZipEntryIterator(iterator);
543
+ }
544
+ if (!outputStream.destroyed) {
545
+ outputStream.destroy(
546
+ error instanceof Error ? error : new Error("Cannot write ZIP archive")
547
+ );
548
+ }
549
+ await outputDone.catch(() => void 0);
550
+ await writer.abort().catch(() => void 0);
551
+ throw error;
552
+ }
553
+ }
554
+ async function addNodeZipEntries(zipFile, iterator, state) {
555
+ while (!state.cancelled) {
556
+ const result = await iterator.next();
557
+ if (state.cancelled) return;
558
+ if (result.done) {
559
+ state.complete = true;
560
+ return;
561
+ }
562
+ if ("file" in result.value) {
563
+ zipFile.addReadStream(
564
+ createNodeFileReadStream(result.value.file),
565
+ result.value.name,
566
+ { compress: false }
567
+ );
568
+ } else if ("data" in result.value) {
569
+ zipFile.addBuffer(Buffer.from(result.value.data), result.value.name, {
570
+ compress: false
571
+ });
572
+ } else {
573
+ zipFile.addReadStream(
574
+ createNodeRangeReadStream(result.value),
575
+ result.value.name,
576
+ { compress: false, size: result.value.size }
577
+ );
578
+ }
579
+ }
580
+ }
581
+ function createNodeFileReadStream(file) {
582
+ return import_node_stream.Readable.from(
583
+ (async function* () {
584
+ const reader = await file.openReader();
585
+ try {
586
+ for (let offset = 0; offset < reader.size; ) {
587
+ const chunk = await reader.read(
588
+ offset,
589
+ Math.min(64 * 1024, reader.size - offset)
590
+ );
591
+ offset += chunk.byteLength;
592
+ yield chunk;
593
+ }
594
+ } finally {
595
+ await reader.close();
596
+ }
597
+ })()
598
+ );
599
+ }
600
+ function getBrandedNodeResourcePath(resource, kind) {
601
+ if (typeof resource !== "object" || resource === null) return void 0;
602
+ const candidate = resource;
603
+ return candidate[NODE_RESOURCE_KIND] === kind && typeof candidate.path === "string" ? candidate.path : void 0;
604
+ }
605
+ function createNodeRangeReadStream(entry) {
606
+ return import_node_stream.Readable.from(
607
+ (async function* () {
608
+ for (let offset = 0; offset < entry.size; ) {
609
+ const chunk = await entry.read(
610
+ offset,
611
+ Math.min(64 * 1024, entry.size - offset)
612
+ );
613
+ offset += chunk.byteLength;
614
+ yield chunk;
615
+ }
616
+ })()
617
+ );
618
+ }
619
+ function getNodeZipEntryIterator(entries) {
620
+ const asyncIterator = entries[Symbol.asyncIterator];
621
+ return asyncIterator === void 0 ? entries[Symbol.iterator]() : asyncIterator.call(entries);
622
+ }
623
+ function closeNodeZipEntryIterator(iterator) {
624
+ if (iterator.return === void 0) return;
625
+ try {
626
+ void Promise.resolve(iterator.return()).catch(() => void 0);
627
+ } catch {
628
+ }
629
+ }
630
+ async function writeNodeStream(input, writer) {
631
+ await (0, import_promises.pipeline)(
632
+ input,
633
+ new import_node_stream.Writable({
634
+ write: (chunk, _encoding, callback) => {
635
+ void writer.write(chunk).then(
636
+ () => callback(),
637
+ (error) => callback(
638
+ error instanceof Error ? error : new Error("Cannot stream ZIP archive")
639
+ )
640
+ );
641
+ }
642
+ })
643
+ );
644
+ }
645
+ async function collectNodeStream(input) {
646
+ return await new Promise((resolve2, reject) => {
647
+ const chunks = [];
648
+ input.on("data", (chunk) => chunks.push(chunk));
649
+ input.once("error", reject);
650
+ input.once("end", () => resolve2(Buffer.concat(chunks)));
651
+ });
652
+ }
653
+ var nodeWikiGraphPlatform = {
654
+ asyncContext: {
655
+ create: () => new asyncHooks.AsyncLocalStorage()
656
+ },
657
+ database: { open: openNodeDatabase },
658
+ lifecycle: {
659
+ instanceId: `node-process:${nodeProcess.pid}`,
660
+ isInstanceAlive: (instanceId) => {
661
+ const match = /^node-process:(\d+)$/u.exec(instanceId);
662
+ if (match === null) return Promise.resolve(void 0);
663
+ try {
664
+ nodeProcess.kill(Number(match[1]), 0);
665
+ return Promise.resolve(true);
666
+ } catch (error) {
667
+ if (typeof error === "object" && error !== null && "code" in error && error.code === "ESRCH") {
668
+ return Promise.resolve(false);
669
+ }
670
+ return Promise.resolve(true);
671
+ }
672
+ }
673
+ },
674
+ resources: {
675
+ getDirectory: (identity) => {
676
+ const path = decodeNodeResourceIdentity(identity, "directory");
677
+ return Promise.resolve(
678
+ path === void 0 ? void 0 : new NodeDirectory(path)
679
+ );
680
+ },
681
+ getFile: (identity) => {
682
+ const path = decodeNodeResourceIdentity(identity, "file");
683
+ return Promise.resolve(
684
+ path === void 0 ? void 0 : new NodeFile(path)
685
+ );
686
+ },
687
+ resolveLegacyDirectory: (reference) => {
688
+ const path = decodeNodeResourceIdentity(reference, "directory");
689
+ return Promise.resolve(
690
+ path === void 0 ? void 0 : new NodeDirectory(path)
691
+ );
692
+ }
693
+ },
694
+ templates: {
695
+ createEnvironment: (options) => new import_nunjucks.Environment(new NodeTemplateLoader(), options)
696
+ },
697
+ zip: {
698
+ open: openNodeZip,
699
+ write: writeNodeZip
700
+ }
701
+ };
702
+ var NodeTemplateLoader = class extends import_nunjucks.Loader {
703
+ #dataDirectory;
704
+ constructor(dataDirectory) {
705
+ super();
706
+ this.#dataDirectory = dataDirectory;
707
+ }
708
+ getSource(templateName) {
709
+ const name = (0, import_platform.normalizeTemplateName)(templateName);
710
+ const filePath = pathModule.join(
711
+ this.#dataDirectory ?? resolveNodeDataDirectory(),
712
+ name
713
+ );
714
+ return {
715
+ noCache: false,
716
+ path: name,
717
+ src: fs.readFileSync(filePath, "utf8")
718
+ };
719
+ }
720
+ };
721
+ function resolveNodeDataDirectory() {
722
+ const injected = globalThis.__WIKIGRAPH_DATA_DIR__;
723
+ if (typeof injected === "string" && injected !== "") return injected;
724
+ let directory = nodeProcess.cwd();
725
+ while (true) {
726
+ for (const candidate of [
727
+ pathModule.join(directory, "data"),
728
+ pathModule.join(directory, "packages", "core", "data")
729
+ ]) {
730
+ try {
731
+ if (fs.statSync(candidate).isDirectory()) return candidate;
732
+ } catch {
733
+ }
734
+ }
735
+ const parent = pathModule.dirname(directory);
736
+ if (parent === directory)
737
+ throw new Error("Could not locate data directory");
738
+ directory = parent;
739
+ }
740
+ }
741
+ function createNodeWikiGraphStorage(stateRoot = pathModule.join(os.homedir(), ".wikigraph")) {
742
+ return {
743
+ library: new NodeDirectory(stateRoot),
744
+ documentStore: new NodeDirectory(pathModule.join(stateRoot, "documents"))
745
+ };
746
+ }
747
+ function installNodeWikiGraphPlatform(stateRoot) {
748
+ (0, import_platform.installWikiGraphPlatform)(nodeWikiGraphPlatform);
749
+ (0, import_platform.installWikiGraphStorage)(createNodeWikiGraphStorage(stateRoot));
750
+ }
751
+ async function withNodeWikiGraphStorage(stateRoot, operation) {
752
+ return await (0, import_platform.withWikiGraphStorage)(
753
+ stateRoot === void 0 ? void 0 : createNodeWikiGraphStorage(stateRoot),
754
+ operation
755
+ );
756
+ }
757
+
758
+ // src/local-config.ts
759
+ var import_path = require("path");
760
+ var import_os = require("os");
761
+ var LOCAL_CONFIG_SCHEMA_SQL = `
762
+ CREATE TABLE IF NOT EXISTS config_sections (
763
+ section TEXT PRIMARY KEY,
764
+ value_json TEXT NOT NULL,
765
+ updated_at INTEGER NOT NULL
766
+ );
767
+ `;
768
+ async function readLocalConfigSection(section) {
769
+ return await withLocalConfigDatabase(async (database) => {
770
+ return await readLocalConfigSectionInDatabase(database, section);
771
+ });
772
+ }
773
+ function validateLocalConfigSection(section, value) {
774
+ switch (section) {
775
+ case "embeddings":
776
+ return validateEmbeddingsConfig(value);
777
+ case "llm":
778
+ return validateLLMConfig(value);
779
+ case "concurrent":
780
+ return validateConcurrentConfig(value);
781
+ case "wikimedia":
782
+ return validateWikimediaConfig(value);
783
+ case "wikispine":
784
+ return validateWikispineConfig(value);
785
+ }
786
+ }
787
+ async function withLocalConfigDatabase(operation) {
788
+ const database = await (0, import_wiki_graph_core.openSharedStateDatabase)(
789
+ new NodeFile(
790
+ (0, import_path.join)(
791
+ getWikiGraphSDKStateDir() ?? (0, import_path.join)((0, import_os.homedir)(), ".wikigraph"),
792
+ "core.sqlite"
793
+ )
794
+ ),
795
+ LOCAL_CONFIG_SCHEMA_SQL
796
+ );
797
+ try {
798
+ return await operation(database);
799
+ } finally {
800
+ await database.close();
801
+ }
802
+ }
803
+ async function readLocalConfigSectionInDatabase(database, section) {
804
+ const value = await database.queryOne(
805
+ "SELECT value_json FROM config_sections WHERE section = ?",
806
+ [section],
807
+ (row) => String(row.value_json)
808
+ );
809
+ return value === void 0 ? {} : parseSectionJSON(section, value);
810
+ }
811
+ function parseSectionJSON(section, value) {
812
+ let parsed;
813
+ try {
814
+ parsed = JSON.parse(value);
815
+ } catch (error) {
816
+ throw new Error(
817
+ `Invalid local config JSON for ${section}: ${formatError(error)}`
818
+ );
819
+ }
820
+ if (parsed === null || typeof parsed !== "object" || Array.isArray(parsed)) {
821
+ throw new Error(
822
+ `Invalid local config section ${section}: expected object.`
823
+ );
824
+ }
825
+ return validateLocalConfigSection(section, parsed);
826
+ }
827
+ function validateEmbeddingsConfig(value) {
828
+ const allowedKeys = /* @__PURE__ */ new Set([
829
+ "apiKey",
830
+ "baseURL",
831
+ "dimensions",
832
+ "model",
833
+ "name",
834
+ "provider"
835
+ ]);
836
+ const allowedProviders = /* @__PURE__ */ new Set(["openai", "openai-compatible"]);
837
+ const next = {};
838
+ for (const [key, entry] of Object.entries(value)) {
839
+ if (!allowedKeys.has(key)) {
840
+ throw new Error(`Unknown embeddings config key: ${key}`);
841
+ }
842
+ if (key === "dimensions") {
843
+ const parsed = typeof entry === "number" ? entry : typeof entry === "string" ? Number(entry) : NaN;
844
+ if (!Number.isInteger(parsed) || parsed <= 0) {
845
+ throw new Error("embeddings.dimensions must be a positive integer.");
846
+ }
847
+ next[key] = parsed;
848
+ continue;
849
+ }
850
+ if (typeof entry !== "string" || entry.trim() === "") {
851
+ throw new Error(`embeddings.${key} must be a non-empty string.`);
852
+ }
853
+ const normalized = entry.trim();
854
+ if (key === "provider" && !allowedProviders.has(normalized)) {
855
+ throw new Error(`Unknown embeddings.provider: ${normalized}`);
856
+ }
857
+ next[key] = normalized;
858
+ }
859
+ return next;
860
+ }
861
+ function validateLLMConfig(value) {
862
+ const allowedKeys = /* @__PURE__ */ new Set([
863
+ "apiKey",
864
+ "baseURL",
865
+ "model",
866
+ "name",
867
+ "provider"
868
+ ]);
869
+ const allowedProviders = /* @__PURE__ */ new Set([
870
+ "anthropic",
871
+ "google",
872
+ "openai",
873
+ "openai-compatible"
874
+ ]);
875
+ const next = {};
876
+ for (const [key, entry] of Object.entries(value)) {
877
+ if (!allowedKeys.has(key)) {
878
+ throw new Error(`Unknown llm config key: ${key}`);
879
+ }
880
+ if (typeof entry !== "string" || entry.trim() === "") {
881
+ throw new Error(`llm.${key} must be a non-empty string.`);
882
+ }
883
+ const normalized = entry.trim();
884
+ if (key === "provider" && !allowedProviders.has(normalized)) {
885
+ throw new Error(`Unknown llm.provider: ${normalized}`);
886
+ }
887
+ next[key] = normalized;
888
+ }
889
+ return next;
890
+ }
891
+ function validateConcurrentConfig(value) {
892
+ const allowedKeys = /* @__PURE__ */ new Set(["job", "request"]);
893
+ const next = {};
894
+ for (const [key, entry] of Object.entries(value)) {
895
+ if (!allowedKeys.has(key)) {
896
+ throw new Error(`Unknown concurrent config key: ${key}`);
897
+ }
898
+ const parsed = typeof entry === "number" ? entry : typeof entry === "string" ? Number(entry) : NaN;
899
+ if (!Number.isInteger(parsed) || parsed <= 0) {
900
+ throw new Error(`concurrent.${key} must be a positive integer.`);
901
+ }
902
+ next[key] = parsed;
903
+ }
904
+ return next;
905
+ }
906
+ function validateWikispineConfig(value) {
907
+ const allowedKeys = /* @__PURE__ */ new Set(["endpoint", "provider", "token"]);
908
+ const allowedProviders = /* @__PURE__ */ new Set(["cli", "fetch"]);
909
+ const next = {};
910
+ for (const [key, entry] of Object.entries(value)) {
911
+ if (!allowedKeys.has(key)) {
912
+ throw new Error(`Unknown wikispine config key: ${key}`);
913
+ }
914
+ if (typeof entry !== "string" || entry.trim() === "") {
915
+ throw new Error(`wikispine.${key} must be a non-empty string.`);
916
+ }
917
+ const normalized = entry.trim();
918
+ if (key === "provider" && !allowedProviders.has(normalized)) {
919
+ throw new Error(`Unknown wikispine.provider: ${normalized}`);
920
+ }
921
+ next[key] = normalized;
922
+ }
923
+ return next;
924
+ }
925
+ function validateWikimediaConfig(value) {
926
+ return validateEndpointConfig("wikimedia", value);
927
+ }
928
+ function validateEndpointConfig(section, value) {
929
+ const allowedKeys = /* @__PURE__ */ new Set(["endpoint", "token"]);
930
+ const next = {};
931
+ for (const [key, entry] of Object.entries(value)) {
932
+ if (!allowedKeys.has(key)) {
933
+ throw new Error(`Unknown ${section} config key: ${key}`);
934
+ }
935
+ if (typeof entry !== "string" || entry.trim() === "") {
936
+ throw new Error(`${section}.${key} must be a non-empty string.`);
937
+ }
938
+ next[key] = entry.trim();
939
+ }
940
+ return next;
941
+ }
942
+ function formatError(error) {
943
+ return error instanceof Error ? error.message : String(error);
944
+ }
945
+
946
+ // src/embedding.ts
947
+ var EMBEDDING_BATCH_SIZE = 10;
948
+ function buildSearchIndexEmbeddingProvider(config) {
949
+ const provider = requireEmbeddingProvider(config.provider);
950
+ const model = requireEmbeddingModel(config.model);
951
+ const embeddingModel = createEmbeddingModel(provider, model, config);
952
+ const providerOptions = createEmbeddingProviderOptions(provider, config);
953
+ return {
954
+ ...config.dimensions === void 0 ? {} : { dimensions: config.dimensions },
955
+ identity: createEmbeddingIdentity(provider, model, config),
956
+ model,
957
+ embedTexts: async (texts, options) => {
958
+ const embeddings = [];
959
+ let tokens = 0;
960
+ for (const batch of chunkTexts(texts, EMBEDDING_BATCH_SIZE)) {
961
+ options?.signal?.throwIfAborted();
962
+ const result = await (0, import_ai.embedMany)({
963
+ ...options?.signal === void 0 ? {} : { abortSignal: options.signal },
964
+ model: embeddingModel,
965
+ ...providerOptions === void 0 ? {} : { providerOptions },
966
+ values: [...batch]
967
+ });
968
+ embeddings.push(...result.embeddings);
969
+ tokens += result.usage.tokens ?? 0;
970
+ }
971
+ return {
972
+ embeddings,
973
+ ...tokens === 0 ? {} : { tokens }
974
+ };
975
+ }
976
+ };
977
+ }
978
+ function createEmbeddingIdentity(provider, model, config) {
979
+ return JSON.stringify({
980
+ ...config.baseURL === void 0 ? {} : { baseURL: config.baseURL },
981
+ ...config.dimensions === void 0 ? {} : { dimensions: config.dimensions },
982
+ model,
983
+ provider
984
+ });
985
+ }
986
+ function* chunkTexts(texts, size) {
987
+ for (let index = 0; index < texts.length; index += size) {
988
+ yield texts.slice(index, index + size);
989
+ }
990
+ }
991
+ function createEmbeddingModel(provider, model, config) {
992
+ switch (provider) {
993
+ case "openai": {
994
+ if (config.baseURL !== void 0) {
995
+ throw new Error(
996
+ "openai does not accept embeddings.baseURL. Use openai-compatible for third-party OpenAI-style embeddings APIs."
997
+ );
998
+ }
999
+ return (0, import_openai.createOpenAI)({
1000
+ ...config.apiKey === void 0 ? {} : { apiKey: config.apiKey },
1001
+ ...config.name === void 0 ? {} : { name: config.name }
1002
+ }).embeddingModel(model);
1003
+ }
1004
+ case "openai-compatible": {
1005
+ if (config.baseURL === void 0) {
1006
+ throw new Error("openai-compatible requires embeddings.baseURL.");
1007
+ }
1008
+ return (0, import_openai_compatible.createOpenAICompatible)({
1009
+ baseURL: config.baseURL,
1010
+ name: config.name ?? createOpenAICompatibleName(config.baseURL),
1011
+ ...config.apiKey === void 0 ? {} : { apiKey: config.apiKey }
1012
+ }).embeddingModel(model);
1013
+ }
1014
+ }
1015
+ }
1016
+ function createEmbeddingProviderOptions(provider, config) {
1017
+ if (config.dimensions === void 0) {
1018
+ return void 0;
1019
+ }
1020
+ return {
1021
+ [getEmbeddingProviderOptionsName(provider, config)]: {
1022
+ dimensions: config.dimensions
1023
+ }
1024
+ };
1025
+ }
1026
+ function getEmbeddingProviderOptionsName(provider, _config) {
1027
+ if (provider === "openai") {
1028
+ return "openai";
1029
+ }
1030
+ return "openaiCompatible";
1031
+ }
1032
+ function requireEmbeddingProvider(provider) {
1033
+ if (provider !== void 0) {
1034
+ return provider;
1035
+ }
1036
+ throw new Error(
1037
+ "Missing embeddings configuration. Configure `wikg://local/config/embeddings` with provider and model."
1038
+ );
1039
+ }
1040
+ function requireEmbeddingModel(model) {
1041
+ if (model !== void 0) {
1042
+ return model;
1043
+ }
1044
+ throw new Error(
1045
+ "Missing embeddings.model. Configure `wikg://local/config/embeddings` before using Dense search."
1046
+ );
1047
+ }
1048
+ function createOpenAICompatibleName(baseURL) {
1049
+ try {
1050
+ return new URL(baseURL).hostname;
1051
+ } catch {
1052
+ return "openai-compatible";
1053
+ }
1054
+ }
1055
+
1056
+ // src/runtime-config.ts
1057
+ var import_zod = require("zod");
1058
+ var WIKI_GRAPH_PROVIDER_VALUES = [
1059
+ "anthropic",
1060
+ "google",
1061
+ "openai",
1062
+ "openai-compatible"
1063
+ ];
1064
+ var wikiGraphProviderSchema = import_zod.z.enum(WIKI_GRAPH_PROVIDER_VALUES);
1065
+ var inlineLLMConfigSchema = import_zod.z.object({
1066
+ apiKey: import_zod.z.string().min(1).optional(),
1067
+ baseURL: import_zod.z.string().min(1).optional(),
1068
+ baseUrl: import_zod.z.string().min(1).optional(),
1069
+ chatCompletionsUrl: import_zod.z.string().min(1).optional(),
1070
+ llm: import_zod.z.object({
1071
+ apiKey: import_zod.z.string().min(1).optional(),
1072
+ baseURL: import_zod.z.string().min(1).optional(),
1073
+ baseUrl: import_zod.z.string().min(1).optional(),
1074
+ chatCompletionsUrl: import_zod.z.string().min(1).optional(),
1075
+ model: import_zod.z.string().min(1).optional(),
1076
+ name: import_zod.z.string().min(1).optional(),
1077
+ provider: wikiGraphProviderSchema.optional()
1078
+ }).optional(),
1079
+ model: import_zod.z.string().min(1).optional(),
1080
+ name: import_zod.z.string().min(1).optional(),
1081
+ provider: wikiGraphProviderSchema.optional()
1082
+ });
1083
+ async function loadWikiGraphRuntimeConfig(options) {
1084
+ const [embedding, localLLM, concurrent, wikimedia, wikispine] = await Promise.all([
1085
+ readLocalConfigSection("embeddings"),
1086
+ readLocalConfigSection("llm"),
1087
+ readLocalConfigSection("concurrent"),
1088
+ readLocalConfigSection("wikimedia"),
1089
+ readLocalConfigSection("wikispine")
1090
+ ]);
1091
+ const inlineLLMConfig = options?.llmJSON === void 0 ? void 0 : parseInlineLLMConfig(options.llmJSON);
1092
+ const llm = createLLMConfig({
1093
+ apiKey: firstDefined(inlineLLMConfig?.apiKey, readString(localLLM.apiKey)),
1094
+ baseURL: firstDefined(
1095
+ inlineLLMConfig?.baseURL,
1096
+ readString(localLLM.baseURL)
1097
+ ),
1098
+ model: firstDefined(inlineLLMConfig?.model, readString(localLLM.model)),
1099
+ name: firstDefined(inlineLLMConfig?.name, readString(localLLM.name)),
1100
+ provider: firstDefined(
1101
+ inlineLLMConfig?.provider,
1102
+ readProvider(localLLM.provider)
1103
+ )
1104
+ });
1105
+ const requestConcurrent = readPositiveInteger(concurrent.request);
1106
+ const jobConcurrent = readPositiveInteger(concurrent.job);
1107
+ const envPolicy = getWikiGraphSDKRuntimeContext().envPolicy;
1108
+ const wikispineConfig = resolveWikispineConfig(wikispine, envPolicy);
1109
+ const wikimediaConfig = createWikimediaConfig(wikimedia, envPolicy);
1110
+ const embeddingConfig = createEmbeddingConfig(embedding);
1111
+ return {
1112
+ ...jobConcurrent === void 0 && requestConcurrent === void 0 ? {} : {
1113
+ concurrent: {
1114
+ ...jobConcurrent === void 0 ? {} : { job: jobConcurrent },
1115
+ ...requestConcurrent === void 0 ? {} : { request: requestConcurrent }
1116
+ }
1117
+ },
1118
+ ...embeddingConfig === void 0 ? {} : { embedding: embeddingConfig },
1119
+ ...llm === void 0 ? {} : { llm },
1120
+ ...wikimediaConfig === void 0 ? {} : { wikimedia: wikimediaConfig },
1121
+ ...wikispineConfig === void 0 ? {} : { wikispine: wikispineConfig }
1122
+ };
1123
+ }
1124
+ function createWikimediaConfig(input, envPolicy) {
1125
+ const endpoint = readString(input?.endpoint);
1126
+ const token = readString(input?.token);
1127
+ if (endpoint === void 0 && token === void 0) return void 0;
1128
+ if (token === void 0) {
1129
+ throw new Error(
1130
+ "Remote Wikimedia access requires an API key. Configure `wikg://local/config/wikimedia` token with `put token --secret`."
1131
+ );
1132
+ }
1133
+ return {
1134
+ endpoint: endpoint ?? resolveHostedProviderEndpoint("wg-wikimedia", envPolicy),
1135
+ token
1136
+ };
1137
+ }
1138
+ function createEmbeddingConfig(input) {
1139
+ const value = input ?? {};
1140
+ const provider = readEmbeddingProvider(value.provider);
1141
+ const apiKey = readString(value.apiKey);
1142
+ const baseURL = readString(value.baseURL);
1143
+ const dimensions = typeof value.dimensions === "number" && Number.isInteger(value.dimensions) && value.dimensions > 0 ? value.dimensions : void 0;
1144
+ const model = readString(value.model);
1145
+ const name = readString(value.name);
1146
+ if (provider === void 0 || model === void 0 || provider === "openai-compatible" && baseURL === void 0 || provider === "openai" && baseURL !== void 0) {
1147
+ return void 0;
1148
+ }
1149
+ return {
1150
+ ...apiKey === void 0 ? {} : { apiKey },
1151
+ ...baseURL === void 0 ? {} : { baseURL },
1152
+ ...dimensions === void 0 ? {} : { dimensions },
1153
+ ...model === void 0 ? {} : { model },
1154
+ ...name === void 0 ? {} : { name },
1155
+ ...provider === void 0 ? {} : { provider }
1156
+ };
1157
+ }
1158
+ function parseInlineLLMConfig(value) {
1159
+ const normalized = normalizeString(value);
1160
+ if (normalized === void 0) {
1161
+ throw new Error("--llm must be a non-empty JSON object.");
1162
+ }
1163
+ let parsedJson;
1164
+ try {
1165
+ parsedJson = JSON.parse(normalized);
1166
+ } catch (error) {
1167
+ throw new Error(`Invalid --llm JSON: ${formatError2(error)}`);
1168
+ }
1169
+ const parsed = inlineLLMConfigSchema.safeParse(parsedJson);
1170
+ if (!parsed.success) {
1171
+ throw new Error(
1172
+ `Invalid --llm config: ${parsed.error.issues.map((issue) => `${issue.path.join(".") || "<root>"}: ${issue.message}`).join("; ")}`
1173
+ );
1174
+ }
1175
+ const input = parsed.data.llm ?? parsed.data;
1176
+ const provider = input.provider ?? inferInlineProvider(input);
1177
+ const baseURL = resolveInlineBaseURL(input);
1178
+ const config = createLLMConfig({
1179
+ apiKey: input.apiKey,
1180
+ baseURL,
1181
+ model: input.model,
1182
+ name: input.name,
1183
+ provider
1184
+ });
1185
+ if (config === void 0) {
1186
+ throw new Error("--llm must contain at least one supported LLM field.");
1187
+ }
1188
+ return config;
1189
+ }
1190
+ function inferInlineProvider(input) {
1191
+ if (input.provider === void 0 && (input.baseURL !== void 0 || input.baseUrl !== void 0 || input.chatCompletionsUrl !== void 0)) {
1192
+ return "openai-compatible";
1193
+ }
1194
+ return input.provider;
1195
+ }
1196
+ function inferBaseURLFromChatCompletionsURL(input) {
1197
+ if (input.chatCompletionsUrl === void 0) {
1198
+ return void 0;
1199
+ }
1200
+ const suffix = "/chat/completions";
1201
+ if (!input.chatCompletionsUrl.endsWith(suffix)) {
1202
+ throw new Error(
1203
+ "--llm chatCompletionsUrl must end with /chat/completions when baseURL is not provided."
1204
+ );
1205
+ }
1206
+ return input.chatCompletionsUrl.slice(0, -suffix.length);
1207
+ }
1208
+ function resolveInlineBaseURL(input) {
1209
+ if (input.baseURL !== void 0) {
1210
+ return input.baseURL;
1211
+ }
1212
+ if (input.baseUrl !== void 0) {
1213
+ return input.baseUrl;
1214
+ }
1215
+ return inferBaseURLFromChatCompletionsURL(input);
1216
+ }
1217
+ function createLLMConfig(input) {
1218
+ if (input.apiKey === void 0 && input.baseURL === void 0 && input.model === void 0 && input.name === void 0 && input.provider === void 0) {
1219
+ return void 0;
1220
+ }
1221
+ return {
1222
+ ...input.apiKey === void 0 ? {} : { apiKey: input.apiKey },
1223
+ ...input.baseURL === void 0 ? {} : { baseURL: input.baseURL },
1224
+ ...input.model === void 0 ? {} : { model: input.model },
1225
+ ...input.name === void 0 ? {} : { name: input.name },
1226
+ ...input.provider === void 0 ? {} : { provider: input.provider }
1227
+ };
1228
+ }
1229
+ function readProvider(value) {
1230
+ if (typeof value !== "string") {
1231
+ return void 0;
1232
+ }
1233
+ const parsed = wikiGraphProviderSchema.safeParse(value);
1234
+ return parsed.success ? parsed.data : void 0;
1235
+ }
1236
+ function resolveWikispineConfig(value, envPolicy = getWikiGraphSDKRuntimeContext().envPolicy) {
1237
+ const provider = readWikispineProvider(value.provider);
1238
+ const endpoint = readString(value.endpoint);
1239
+ const token = readString(value.token);
1240
+ if (provider === void 0) {
1241
+ return void 0;
1242
+ }
1243
+ if (provider === "cli") return { provider };
1244
+ if (token === void 0) {
1245
+ throw new Error(
1246
+ "Remote WikiSpine access requires an API key. Configure `wikg://local/config/wikispine` token with `put token --secret`."
1247
+ );
1248
+ }
1249
+ return {
1250
+ endpoint: endpoint ?? resolveHostedProviderEndpoint("wikispine", envPolicy),
1251
+ provider,
1252
+ token
1253
+ };
1254
+ }
1255
+ function resolveHostedProviderEndpoint(scope, envPolicy = getWikiGraphSDKRuntimeContext().envPolicy) {
1256
+ const origin = envPolicy === "development" ? "https://pdf-craft-api.oomol.dev" : "https://api.pdfcraft.ai";
1257
+ return `${origin}/v1/${scope}`;
1258
+ }
1259
+ function readWikispineProvider(value) {
1260
+ return value === "cli" || value === "fetch" ? value : void 0;
1261
+ }
1262
+ function readEmbeddingProvider(value) {
1263
+ return value === "openai" || value === "openai-compatible" ? value : void 0;
1264
+ }
1265
+ function readString(value) {
1266
+ return typeof value === "string" ? value : void 0;
1267
+ }
1268
+ function readPositiveInteger(value) {
1269
+ return typeof value === "number" && Number.isInteger(value) && value > 0 ? value : void 0;
1270
+ }
1271
+ function firstDefined(first, second) {
1272
+ return first ?? second;
1273
+ }
1274
+ function normalizeString(value) {
1275
+ const normalized = value?.trim();
1276
+ return normalized === void 0 || normalized === "" ? void 0 : normalized;
1277
+ }
1278
+ function formatError2(error) {
1279
+ return error instanceof Error ? error.message : String(error);
1280
+ }
1281
+
1282
+ // src/stage.ts
1283
+ var import_wiki_graph_core2 = require("wiki-graph-core");
1284
+ var import_wiki_graph_core3 = require("wiki-graph-core");
1285
+ var import_wiki_graph_core4 = require("wiki-graph-core");
1286
+
1287
+ // src/llm.ts
1288
+ var import_anthropic = require("@ai-sdk/anthropic");
1289
+ var import_google = require("@ai-sdk/google");
1290
+ var import_openai2 = require("@ai-sdk/openai");
1291
+ var import_openai_compatible2 = require("@ai-sdk/openai-compatible");
1292
+ function buildWikiGraphLLMOptions(config) {
1293
+ const llm = config.llm;
1294
+ if (llm?.provider === void 0 || llm.model === void 0) {
1295
+ throw new Error(
1296
+ "Missing LLM configuration. Set --llm for one run, or configure `wikg://local/config/llm` with provider and model."
1297
+ );
1298
+ }
1299
+ return {
1300
+ model: createLanguageModel(llm.provider, llm.model, {
1301
+ apiKey: llm.apiKey,
1302
+ baseURL: llm.baseURL,
1303
+ name: llm.name
1304
+ }),
1305
+ ...config.concurrent?.request === void 0 ? {} : { concurrent: config.concurrent.request }
1306
+ };
1307
+ }
1308
+ function createLanguageModel(provider, model, options) {
1309
+ switch (provider) {
1310
+ case "anthropic": {
1311
+ const anthropic = (0, import_anthropic.createAnthropic)({
1312
+ ...options.apiKey === void 0 ? {} : { apiKey: options.apiKey },
1313
+ ...options.name === void 0 ? {} : { name: options.name }
1314
+ });
1315
+ return anthropic(model);
1316
+ }
1317
+ case "google": {
1318
+ const google = (0, import_google.createGoogleGenerativeAI)({
1319
+ ...options.apiKey === void 0 ? {} : { apiKey: options.apiKey },
1320
+ ...options.name === void 0 ? {} : { name: options.name }
1321
+ });
1322
+ return google(model);
1323
+ }
1324
+ case "openai": {
1325
+ if (options.baseURL !== void 0) {
1326
+ throw new Error(
1327
+ "openai does not accept llm.baseURL or baseURL in --llm JSON. Use openai-compatible for third-party OpenAI-style APIs."
1328
+ );
1329
+ }
1330
+ const openai = (0, import_openai2.createOpenAI)({
1331
+ ...options.apiKey === void 0 ? {} : { apiKey: options.apiKey },
1332
+ ...options.name === void 0 ? {} : { name: options.name }
1333
+ });
1334
+ return openai(model);
1335
+ }
1336
+ case "openai-compatible": {
1337
+ if (options.baseURL === void 0) {
1338
+ throw new Error(
1339
+ "openai-compatible requires llm.baseURL or baseURL in --llm JSON."
1340
+ );
1341
+ }
1342
+ const openaiCompatible = (0, import_openai_compatible2.createOpenAICompatible)({
1343
+ baseURL: options.baseURL,
1344
+ name: options.name ?? createOpenAICompatibleName2(options.baseURL),
1345
+ ...options.apiKey === void 0 ? {} : { apiKey: options.apiKey }
1346
+ });
1347
+ return openaiCompatible(model);
1348
+ }
1349
+ }
1350
+ }
1351
+ function createOpenAICompatibleName2(baseURL) {
1352
+ try {
1353
+ return new URL(baseURL).hostname;
1354
+ } catch {
1355
+ return "openai-compatible";
1356
+ }
1357
+ }
1358
+
1359
+ // src/stage.ts
1360
+ function createStageLLM(config, options) {
1361
+ const llmOptions = buildWikiGraphLLMOptions(config);
1362
+ return new import_wiki_graph_core4.LLM({
1363
+ sampling: (0, import_wiki_graph_core3.createDefaultWikiGraphSampling)({
1364
+ ...llmOptions.temperature === void 0 ? {} : { temperature: llmOptions.temperature },
1365
+ ...llmOptions.topP === void 0 ? {} : { topP: llmOptions.topP }
1366
+ }),
1367
+ ...llmOptions,
1368
+ ...options?.cacheDirectory === void 0 ? {} : { cacheDirectory: options.cacheDirectory },
1369
+ ...options?.logDirectory === void 0 ? {} : { logDirectory: options.logDirectory },
1370
+ ...options?.onStreamProgress === void 0 ? {} : { onStreamProgress: options.onStreamProgress },
1371
+ ...options?.onTokenUsage === void 0 ? {} : { onTokenUsage: options.onTokenUsage }
1372
+ });
1373
+ }
1374
+ async function loadRequiredStageConfig(options) {
1375
+ const config = await loadWikiGraphRuntimeConfig({
1376
+ ...options.llmJSON === void 0 ? {} : { llmJSON: options.llmJSON }
1377
+ });
1378
+ if (config.llm?.provider === void 0 || config.llm.model === void 0) {
1379
+ throw new Error(
1380
+ "Missing LLM configuration. Set --llm for one run, or configure `wikg://local/config/llm` with provider and model."
1381
+ );
1382
+ }
1383
+ return config;
1384
+ }
1385
+
1386
+ // src/planning.ts
1387
+ var DEFAULT_GENERATION_JOB_CONCURRENCY = 3;
1388
+
1389
+ // src/wikispine.ts
1390
+ var import_child_process = require("child_process");
1391
+ var nodeWikispineCommandRunner = {
1392
+ run: async ({ args, command, input, onStdout, signal }) => await new Promise((resolve2, reject) => {
1393
+ signal?.throwIfAborted();
1394
+ const child = (0, import_child_process.spawn)(command, [...args], {
1395
+ stdio: ["pipe", "pipe", "pipe"]
1396
+ });
1397
+ const stderr = [];
1398
+ let settled = false;
1399
+ const settle = (operation) => {
1400
+ if (settled) return;
1401
+ settled = true;
1402
+ signal?.removeEventListener("abort", abort);
1403
+ operation();
1404
+ };
1405
+ const abort = () => {
1406
+ child.kill();
1407
+ settle(() => reject(abortError(signal)));
1408
+ };
1409
+ signal?.addEventListener("abort", abort, { once: true });
1410
+ child.stdout.setEncoding("utf8");
1411
+ child.stdout.on("data", (chunk) => {
1412
+ if (settled) return;
1413
+ try {
1414
+ onStdout(chunk);
1415
+ } catch (error) {
1416
+ child.kill();
1417
+ settle(
1418
+ () => reject(error instanceof Error ? error : new Error(String(error)))
1419
+ );
1420
+ }
1421
+ });
1422
+ child.stderr.on("data", (chunk) => stderr.push(chunk));
1423
+ child.on("error", (error) => {
1424
+ settle(
1425
+ () => reject(
1426
+ new Error(`Failed to start wikispine command: ${error.message}`)
1427
+ )
1428
+ );
1429
+ });
1430
+ child.on("close", (exitCode) => {
1431
+ settle(
1432
+ () => resolve2({
1433
+ exitCode,
1434
+ stderr: Buffer.concat(stderr).toString("utf8")
1435
+ })
1436
+ );
1437
+ });
1438
+ child.stdin.end(input);
1439
+ })
1440
+ };
1441
+ function abortError(signal) {
1442
+ return signal?.reason instanceof Error ? signal.reason : new Error("WikiSpine command aborted.");
1443
+ }
1444
+
1445
+ // src/worker.ts
1446
+ var import_worker = require("wiki-graph-core/worker");
1447
+ var import_worker2 = require("wiki-graph-core/worker");
1448
+ async function runBuildJobWorker(options) {
1449
+ installNodeWikiGraphPlatform();
1450
+ const { stateDir, ...coreOptions } = options;
1451
+ await withNodeWikiGraphStorage(
1452
+ stateDir,
1453
+ async () => await (0, import_worker.runBuildJobWorker)(coreOptions)
1454
+ );
1455
+ }
1456
+
1457
+ // src/default-worker.ts
1458
+ async function runWikiGraphQueueWorker(options = {}) {
1459
+ const config = await loadWikiGraphRuntimeConfig();
1460
+ await runBuildJobWorker({
1461
+ concurrency: config.concurrent?.job ?? DEFAULT_GENERATION_JOB_CONCURRENCY,
1462
+ executeJob: async (job, reporter, context) => {
1463
+ await (0, import_wiki_graph_core5.withLoggingContext)(
1464
+ { logDirectory: job.log, operation: "build-job" },
1465
+ async () => await executeBuildJob(job, reporter, context)
1466
+ );
1467
+ },
1468
+ ...options.signal === void 0 ? {} : { signal: options.signal }
1469
+ });
1470
+ }
1471
+ async function executeBuildJob(job, reporter, context) {
1472
+ const config = await loadWikiGraphRuntimeConfig({
1473
+ ...job.llmJSON === void 0 ? {} : { llmJSON: job.llmJSON }
1474
+ });
1475
+ const execution = await openJobExecutor(
1476
+ job,
1477
+ config,
1478
+ context.signal,
1479
+ reporter
1480
+ );
1481
+ try {
1482
+ if (job.target === "reading-summary") {
1483
+ let stage = await readChapterStage(job);
1484
+ if (stage === "sourced") {
1485
+ await executeStep(job, "reading-graph", execution, reporter, context, {
1486
+ ...execution.extractionPrompt === void 0 ? {} : { extractionPrompt: execution.extractionPrompt }
1487
+ });
1488
+ stage = await readChapterStage(job);
1489
+ }
1490
+ if (stage === "summarized") return;
1491
+ if (stage !== "graphed") {
1492
+ throw new Error(
1493
+ `Chapter ${job.chapterId} is ${stage}. Cannot generate summary.`
1494
+ );
1495
+ }
1496
+ await executeStep(job, "reading-summary", execution, reporter, context, {
1497
+ ...job.prompt === void 0 ? {} : { prompt: job.prompt }
1498
+ });
1499
+ return;
1500
+ }
1501
+ if (job.target === "reading-graph") {
1502
+ const stage = await readChapterStage(job);
1503
+ if (stage === "graphed" || stage === "summarized") return;
1504
+ if (stage !== "sourced") {
1505
+ throw new Error(
1506
+ `Chapter ${job.chapterId} is ${stage}. Cannot generate Reading Graph.`
1507
+ );
1508
+ }
1509
+ }
1510
+ if (job.target === "knowledge-graph") {
1511
+ const stage = await readChapterStage(job);
1512
+ if (stage === "planned") {
1513
+ throw new Error(
1514
+ `Chapter ${job.chapterId} is planned. Set source before generating Knowledge Graph.`
1515
+ );
1516
+ }
1517
+ }
1518
+ await executeStep(job, job.target, execution, reporter, context, {
1519
+ ...job.target === "reading-graph" ? { extractionPrompt: execution.extractionPrompt } : {},
1520
+ ...job.target === "knowledge-graph" ? { policyPrompt: execution.knowledgeGraphPrompt } : {}
1521
+ });
1522
+ } finally {
1523
+ await execution.close();
1524
+ }
1525
+ }
1526
+ async function executeStep(job, kind, execution, reporter, context, inputOptions) {
1527
+ await reporter.throwIfStopped();
1528
+ await reporter.stepStarted(kind);
1529
+ if (kind === "reading-graph" || kind === "knowledge-graph") {
1530
+ await assertCurrentFtsArtifact(job);
1531
+ }
1532
+ const stepWorkspace = await resetStepWorkspace(job.workspace, kind);
1533
+ const inputFile = await stepWorkspace.createFile("input.jsonl");
1534
+ const outputWorkspace = await stepWorkspace.createDirectory("output");
1535
+ const revision = await new import_wiki_graph_core5.WikiGraphArchiveFile(job.archive).readDocument(
1536
+ async (document) => {
1537
+ await (0, import_wiki_graph_core5.getChapterDetails)(document, job.chapterId);
1538
+ return await (0, import_worker3.writeChapterJobInputFile)(
1539
+ document,
1540
+ job.chapterId,
1541
+ kind,
1542
+ inputFile,
1543
+ inputOptions
1544
+ );
1545
+ }
1546
+ );
1547
+ await (0, import_wiki_graph_core5.recordBuildJobInputRevision)({
1548
+ currentRevision: revision,
1549
+ jobId: job.jobId,
1550
+ ownerId: requireRunningJobOwnerId(job)
1551
+ });
1552
+ await reporter.updatePhase({
1553
+ done: 0,
1554
+ phase: kind.startsWith("index-") ? "indexing" : "grounding",
1555
+ total: 1,
1556
+ unit: "item"
1557
+ });
1558
+ const result = await execution.executor({
1559
+ inputFile,
1560
+ kind,
1561
+ progress: reporter,
1562
+ revision,
1563
+ signal: context.signal,
1564
+ workspace: outputWorkspace
1565
+ });
1566
+ if (result.revision !== revision) {
1567
+ throw new Error(
1568
+ `Chapter job returned revision ${result.revision}; expected ${revision}.`
1569
+ );
1570
+ }
1571
+ await reporter.updatePhase({
1572
+ done: 0,
1573
+ phase: "committing",
1574
+ total: 1,
1575
+ unit: "item"
1576
+ });
1577
+ await new import_wiki_graph_core5.WikiGraphArchiveFile(job.archive).write(async (document) => {
1578
+ assertJobStillRunning(await (0, import_wiki_graph_core5.getBuildJob)(job.jobId));
1579
+ await (0, import_worker3.applyChapterJobArtifactFile)(
1580
+ document,
1581
+ job.chapterId,
1582
+ kind,
1583
+ revision,
1584
+ result.artifactFile
1585
+ );
1586
+ });
1587
+ await reporter.updatePhase({
1588
+ done: 1,
1589
+ phase: "committing",
1590
+ total: 1,
1591
+ unit: "item"
1592
+ });
1593
+ await reporter.stepCompleted(kind);
1594
+ assertJobStillRunning(await (0, import_wiki_graph_core5.getBuildJob)(job.jobId));
1595
+ }
1596
+ async function openJobExecutor(job, config, signal, reporter) {
1597
+ const generation = !job.target.startsWith("index-");
1598
+ const stageConfig = generation ? await loadRequiredStageConfig({
1599
+ ...job.llmJSON === void 0 ? {} : { llmJSON: job.llmJSON }
1600
+ }) : void 0;
1601
+ const llm = stageConfig === void 0 ? void 0 : createStageLLM(stageConfig, {
1602
+ cacheDirectory: job.cache,
1603
+ logDirectory: job.log,
1604
+ onTokenUsage: async (usage) => {
1605
+ await reporter.addTokenUsage(usage);
1606
+ }
1607
+ });
1608
+ const promptSource = job.prompt ?? stageConfig?.prompt;
1609
+ const wikispine = job.target === "knowledge-graph" ? requireKnowledgeGraphWikispineConfig(config) : void 0;
1610
+ const request = llm === void 0 ? void 0 : async (messages, index, maxRetries) => await llm.request(messages, {
1611
+ retryIndex: index,
1612
+ retryMax: maxRetries,
1613
+ scope: import_wiki_graph_core5.WikiGraphScope.ReaderExtraction,
1614
+ signal
1615
+ });
1616
+ if (request !== void 0 && llm !== void 0) {
1617
+ request.lazy = async (operation) => await llm.request(async () => await operation(request));
1618
+ }
1619
+ const wikimediaResolver = job.target !== "knowledge-graph" ? void 0 : await (0, import_wiki_graph_core5.openWikimediaResolver)(
1620
+ config.wikimedia === void 0 ? {
1621
+ kind: "local",
1622
+ llmRequest: requireValue(
1623
+ request,
1624
+ "Local Wikimedia resolution requires an LLM."
1625
+ )
1626
+ } : {
1627
+ endpoint: config.wikimedia.endpoint,
1628
+ kind: "remote",
1629
+ token: config.wikimedia.token
1630
+ }
1631
+ );
1632
+ const embeddingProvider = job.target === "index-embedding-source" || job.target === "index-embedding-summary" ? buildSearchIndexEmbeddingProvider(requireEmbeddingConfig(config)) : void 0;
1633
+ return {
1634
+ async close() {
1635
+ await wikimediaResolver?.close();
1636
+ },
1637
+ executor: (0, import_worker3.createLocalChapterJobFileExecutor)({
1638
+ ...embeddingProvider === void 0 ? {} : { embeddingProvider },
1639
+ ...llm === void 0 ? {} : { llm },
1640
+ ...wikimediaResolver === void 0 ? {} : { wikimediaResolver },
1641
+ ...wikispine === void 0 ? {} : {
1642
+ wikispine: {
1643
+ ...wikispine,
1644
+ ...wikispine.provider === "cli" ? { commandRunner: nodeWikispineCommandRunner } : {}
1645
+ }
1646
+ }
1647
+ }),
1648
+ ...promptSource === void 0 ? {} : { extractionPrompt: (0, import_wiki_graph_core2.resolveExtractionPrompt)(promptSource) },
1649
+ ...promptSource === void 0 ? {} : {
1650
+ knowledgeGraphPrompt: (0, import_wiki_graph_core2.resolveKnowledgeGraphRecallPrompt)(promptSource)
1651
+ }
1652
+ };
1653
+ }
1654
+ async function resetStepWorkspace(workspace, kind) {
1655
+ const name = `chapter-job-${kind}`;
1656
+ if (await workspace.getDirectory(name) !== void 0) {
1657
+ await workspace.remove(name, { recursive: true });
1658
+ }
1659
+ return await workspace.createDirectory(name);
1660
+ }
1661
+ async function readChapterStage(job) {
1662
+ return await new import_wiki_graph_core5.WikiGraphArchiveFile(job.archive).readDocument(
1663
+ async (document) => (await (0, import_wiki_graph_core5.getChapterDetails)(document, job.chapterId)).stage
1664
+ );
1665
+ }
1666
+ async function assertCurrentFtsArtifact(job) {
1667
+ await new import_wiki_graph_core5.WikiGraphArchiveFile(job.archive).readDocument(async (document) => {
1668
+ const revision = await document.serials.getRevision(job.chapterId);
1669
+ const artifact = await document.indexArtifacts.get(job.chapterId, "fts");
1670
+ if (artifact?.sourceRevision !== revision) {
1671
+ throw new Error(
1672
+ `Chapter ${job.chapterId} needs a current FTS index artifact before running ${job.target}.`
1673
+ );
1674
+ }
1675
+ });
1676
+ }
1677
+ function requireEmbeddingConfig(config) {
1678
+ if (config.embedding !== void 0) return config.embedding;
1679
+ throw new Error(
1680
+ "Missing embeddings configuration. Configure `wikg://local/config/embeddings` before building embedding index artifacts."
1681
+ );
1682
+ }
1683
+ function requireKnowledgeGraphWikispineConfig(config) {
1684
+ if (config.wikispine?.provider !== void 0) return config.wikispine;
1685
+ throw new Error(
1686
+ "Knowledge Graph requires WikiSpine. Configure `wikg://local/config/wikispine` with provider `cli` or `fetch` and test the provider before running the worker."
1687
+ );
1688
+ }
1689
+ function requireRunningJobOwnerId(job) {
1690
+ if (job.ownerId === void 0) {
1691
+ throw new Error(`Build job ${job.jobId} has no running owner.`);
1692
+ }
1693
+ return job.ownerId;
1694
+ }
1695
+ function assertJobStillRunning(job) {
1696
+ if (job.state !== "running") {
1697
+ throw new Error(`Job ${job.jobId} is ${job.state}. Stop before flushing.`);
1698
+ }
1699
+ }
1700
+ function requireValue(value, message) {
1701
+ if (value === void 0) throw new Error(message);
1702
+ return value;
1703
+ }
1704
+ // Annotate the CommonJS export names for ESM import in node:
1705
+ 0 && (module.exports = {
1706
+ requireKnowledgeGraphWikispineConfig,
1707
+ runWikiGraphQueueWorker
1708
+ });
1709
+ //# sourceMappingURL=default-worker.cjs.map