@character-foundry/character-foundry 0.1.3 → 0.1.5

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 (100) hide show
  1. package/README.md +70 -0
  2. package/dist/app-framework.cjs +1742 -0
  3. package/dist/app-framework.cjs.map +1 -0
  4. package/dist/app-framework.d.cts +881 -0
  5. package/dist/app-framework.d.ts +881 -2
  6. package/dist/app-framework.js +1718 -1
  7. package/dist/app-framework.js.map +1 -1
  8. package/dist/charx.cjs +917 -0
  9. package/dist/charx.cjs.map +1 -0
  10. package/dist/charx.d.cts +640 -0
  11. package/dist/charx.d.ts +640 -2
  12. package/dist/charx.js +893 -1
  13. package/dist/charx.js.map +1 -1
  14. package/dist/core.cjs +668 -0
  15. package/dist/core.cjs.map +1 -0
  16. package/dist/core.d.cts +363 -0
  17. package/dist/core.d.ts +363 -2
  18. package/dist/core.js +644 -1
  19. package/dist/core.js.map +1 -1
  20. package/dist/exporter.cjs +7539 -0
  21. package/dist/exporter.cjs.map +1 -0
  22. package/dist/exporter.d.cts +681 -0
  23. package/dist/exporter.d.ts +681 -2
  24. package/dist/exporter.js +7522 -1
  25. package/dist/exporter.js.map +1 -1
  26. package/dist/federation.cjs +3915 -0
  27. package/dist/federation.cjs.map +1 -0
  28. package/dist/federation.d.cts +2951 -0
  29. package/dist/federation.d.ts +2951 -2
  30. package/dist/federation.js +3891 -1
  31. package/dist/federation.js.map +1 -1
  32. package/dist/index.cjs +9109 -0
  33. package/dist/index.cjs.map +1 -0
  34. package/dist/index.d.cts +1119 -0
  35. package/dist/index.d.ts +1113 -20
  36. package/dist/index.js +9092 -26
  37. package/dist/index.js.map +1 -1
  38. package/dist/loader.cjs +8923 -0
  39. package/dist/loader.cjs.map +1 -0
  40. package/dist/loader.d.cts +1037 -0
  41. package/dist/loader.d.ts +1037 -2
  42. package/dist/loader.js +8906 -1
  43. package/dist/loader.js.map +1 -1
  44. package/dist/lorebook.cjs +865 -0
  45. package/dist/lorebook.cjs.map +1 -0
  46. package/dist/lorebook.d.cts +1008 -0
  47. package/dist/lorebook.d.ts +1008 -2
  48. package/dist/lorebook.js +841 -1
  49. package/dist/lorebook.js.map +1 -1
  50. package/dist/media.cjs +6660 -0
  51. package/dist/media.cjs.map +1 -0
  52. package/dist/media.d.cts +87 -0
  53. package/dist/media.d.ts +87 -2
  54. package/dist/media.js +6643 -1
  55. package/dist/media.js.map +1 -1
  56. package/dist/normalizer.cjs +502 -0
  57. package/dist/normalizer.cjs.map +1 -0
  58. package/dist/normalizer.d.cts +1216 -0
  59. package/dist/normalizer.d.ts +1216 -2
  60. package/dist/normalizer.js +478 -1
  61. package/dist/normalizer.js.map +1 -1
  62. package/dist/png.cjs +778 -0
  63. package/dist/png.cjs.map +1 -0
  64. package/dist/png.d.cts +786 -0
  65. package/dist/png.d.ts +786 -2
  66. package/dist/png.js +754 -1
  67. package/dist/png.js.map +1 -1
  68. package/dist/schemas.cjs +799 -0
  69. package/dist/schemas.cjs.map +1 -0
  70. package/dist/schemas.d.cts +2178 -0
  71. package/dist/schemas.d.ts +2178 -2
  72. package/dist/schemas.js +775 -1
  73. package/dist/schemas.js.map +1 -1
  74. package/dist/tokenizers.cjs +153 -0
  75. package/dist/tokenizers.cjs.map +1 -0
  76. package/dist/tokenizers.d.cts +155 -0
  77. package/dist/tokenizers.d.ts +155 -2
  78. package/dist/tokenizers.js +129 -1
  79. package/dist/tokenizers.js.map +1 -1
  80. package/dist/voxta.cjs +7995 -0
  81. package/dist/voxta.cjs.map +1 -0
  82. package/dist/voxta.d.cts +1349 -0
  83. package/dist/voxta.d.ts +1349 -2
  84. package/dist/voxta.js +7978 -1
  85. package/dist/voxta.js.map +1 -1
  86. package/package.json +177 -45
  87. package/dist/app-framework.d.ts.map +0 -1
  88. package/dist/charx.d.ts.map +0 -1
  89. package/dist/core.d.ts.map +0 -1
  90. package/dist/exporter.d.ts.map +0 -1
  91. package/dist/federation.d.ts.map +0 -1
  92. package/dist/index.d.ts.map +0 -1
  93. package/dist/loader.d.ts.map +0 -1
  94. package/dist/lorebook.d.ts.map +0 -1
  95. package/dist/media.d.ts.map +0 -1
  96. package/dist/normalizer.d.ts.map +0 -1
  97. package/dist/png.d.ts.map +0 -1
  98. package/dist/schemas.d.ts.map +0 -1
  99. package/dist/tokenizers.d.ts.map +0 -1
  100. package/dist/voxta.d.ts.map +0 -1
package/dist/lorebook.js CHANGED
@@ -1,2 +1,842 @@
1
- export * from '@character-foundry/lorebook';
1
+ // ../core/dist/index.js
2
+ function toString(data) {
3
+ return new TextDecoder().decode(data);
4
+ }
5
+ var isNode = typeof process !== "undefined" && process.versions != null && process.versions.node != null;
6
+ var ENCODE_CHUNK_SIZE = 64 * 1024;
7
+ var FOUNDRY_ERROR_MARKER = /* @__PURE__ */ Symbol.for("@character-foundry/core:FoundryError");
8
+ var FoundryError = class extends Error {
9
+ constructor(message, code) {
10
+ super(message);
11
+ this.code = code;
12
+ this.name = "FoundryError";
13
+ if (Error.captureStackTrace) {
14
+ Error.captureStackTrace(this, this.constructor);
15
+ }
16
+ }
17
+ /** @internal Marker for cross-module identification */
18
+ [FOUNDRY_ERROR_MARKER] = true;
19
+ };
20
+ var ParseError = class extends FoundryError {
21
+ constructor(message, format) {
22
+ super(message, "PARSE_ERROR");
23
+ this.format = format;
24
+ this.name = "ParseError";
25
+ }
26
+ };
27
+
28
+ // ../lorebook/dist/index.js
29
+ function parseLorebook(data) {
30
+ let json;
31
+ try {
32
+ const text = toString(data);
33
+ json = JSON.parse(text);
34
+ } catch (err) {
35
+ throw new ParseError(
36
+ `Failed to parse lorebook JSON: ${err instanceof Error ? err.message : String(err)}`,
37
+ "lorebook"
38
+ );
39
+ }
40
+ const format = detectLorebookFormat(json);
41
+ const book = normalizeToCC3(json, format);
42
+ return {
43
+ book,
44
+ originalFormat: format,
45
+ originalShape: json
46
+ };
47
+ }
48
+ function detectLorebookFormat(data) {
49
+ if (!data || typeof data !== "object") {
50
+ return "unknown";
51
+ }
52
+ const obj = data;
53
+ if (Array.isArray(obj.entries)) {
54
+ const firstEntry = obj.entries[0];
55
+ if (firstEntry && Array.isArray(firstEntry.keys) && "content" in firstEntry) {
56
+ return "ccv3";
57
+ }
58
+ }
59
+ if (obj.entries && typeof obj.entries === "object" && !Array.isArray(obj.entries)) {
60
+ const entries = obj.entries;
61
+ const firstKey = Object.keys(entries)[0];
62
+ if (firstKey) {
63
+ const firstEntry = entries[firstKey];
64
+ if ("uid" in firstEntry && "key" in firstEntry && "content" in firstEntry) {
65
+ return "sillytavern";
66
+ }
67
+ }
68
+ }
69
+ if (obj.kind === "memory" && Array.isArray(obj.entries)) {
70
+ const firstEntry = obj.entries[0];
71
+ if (firstEntry && "keywords" in firstEntry && "entry" in firstEntry) {
72
+ return "agnai";
73
+ }
74
+ }
75
+ if (obj.type === "risu" || obj.ripiVersion !== void 0) {
76
+ return "risu";
77
+ }
78
+ if (obj.format === "wyvern" || obj.wyvern !== void 0) {
79
+ return "wyvern";
80
+ }
81
+ return "unknown";
82
+ }
83
+ function normalizeToCC3(data, format) {
84
+ switch (format) {
85
+ case "ccv3":
86
+ return normalizeCCv3(data);
87
+ case "sillytavern":
88
+ return normalizeSillyTavern(data);
89
+ case "agnai":
90
+ return normalizeAgnai(data);
91
+ case "risu":
92
+ return normalizeRisu(data);
93
+ case "wyvern":
94
+ return normalizeWyvern(data);
95
+ case "unknown":
96
+ default:
97
+ return attemptGenericNormalize(data);
98
+ }
99
+ }
100
+ function normalizeCCv3(data) {
101
+ const obj = data;
102
+ return {
103
+ name: typeof obj.name === "string" ? obj.name : void 0,
104
+ description: typeof obj.description === "string" ? obj.description : void 0,
105
+ entries: Array.isArray(obj.entries) ? obj.entries.map((e, i) => normalizeEntry(e, i)) : [],
106
+ extensions: typeof obj.extensions === "object" ? obj.extensions : void 0
107
+ };
108
+ }
109
+ function normalizeSillyTavern(data) {
110
+ const entries = [];
111
+ if (data.entries && typeof data.entries === "object") {
112
+ const entryList = Object.values(data.entries);
113
+ entryList.sort((a, b) => (a.order ?? 0) - (b.order ?? 0));
114
+ for (let i = 0; i < entryList.length; i++) {
115
+ const e = entryList[i];
116
+ entries.push({
117
+ keys: Array.isArray(e.key) ? e.key : [],
118
+ secondary_keys: Array.isArray(e.keysecondary) ? e.keysecondary : [],
119
+ content: e.content || "",
120
+ enabled: e.disable !== true,
121
+ insertion_order: e.order ?? i,
122
+ id: e.uid ?? i,
123
+ name: e.comment || `Entry ${e.uid ?? i}`,
124
+ comment: e.comment || "",
125
+ priority: e.order ?? 10,
126
+ selective: e.selective ?? false,
127
+ constant: e.constant ?? false,
128
+ position: mapSTPosition(e.position),
129
+ extensions: {
130
+ sillytavern: {
131
+ uid: e.uid,
132
+ selectiveLogic: e.selectiveLogic,
133
+ excludeRecursion: e.excludeRecursion,
134
+ probability: e.probability,
135
+ useProbability: e.useProbability,
136
+ depth: e.depth,
137
+ group: e.group,
138
+ scanDepth: e.scanDepth,
139
+ caseSensitive: e.caseSensitive,
140
+ matchWholeWords: e.matchWholeWords,
141
+ automationId: e.automationId,
142
+ role: e.role,
143
+ vectorized: e.vectorized,
144
+ groupOverride: e.groupOverride,
145
+ groupWeight: e.groupWeight,
146
+ sticky: e.sticky,
147
+ cooldown: e.cooldown,
148
+ delay: e.delay
149
+ }
150
+ }
151
+ });
152
+ }
153
+ }
154
+ return {
155
+ name: data.name,
156
+ description: data.description,
157
+ entries
158
+ };
159
+ }
160
+ function mapSTPosition(pos) {
161
+ switch (pos) {
162
+ case 0:
163
+ return "before_char";
164
+ case 1:
165
+ return "after_char";
166
+ case 2:
167
+ return "before_char";
168
+ // Top of AN
169
+ case 3:
170
+ return "after_char";
171
+ // Bottom of AN
172
+ case 4:
173
+ return "before_char";
174
+ // @ D
175
+ default:
176
+ return "before_char";
177
+ }
178
+ }
179
+ function normalizeAgnai(data) {
180
+ const entries = [];
181
+ if (Array.isArray(data.entries)) {
182
+ for (let i = 0; i < data.entries.length; i++) {
183
+ const e = data.entries[i];
184
+ entries.push({
185
+ keys: Array.isArray(e.keywords) ? e.keywords : [],
186
+ secondary_keys: [],
187
+ content: e.entry || "",
188
+ enabled: e.enabled !== false,
189
+ insertion_order: i,
190
+ id: i,
191
+ name: e.name || `Entry ${i}`,
192
+ comment: "",
193
+ priority: e.priority ?? 10,
194
+ selective: false,
195
+ constant: false,
196
+ position: "before_char",
197
+ extensions: {
198
+ agnai: {
199
+ weight: e.weight
200
+ }
201
+ }
202
+ });
203
+ }
204
+ }
205
+ return {
206
+ name: data.name,
207
+ description: data.description,
208
+ entries
209
+ };
210
+ }
211
+ function normalizeRisu(data) {
212
+ const obj = data;
213
+ return {
214
+ name: typeof obj.name === "string" ? obj.name : "Risu Lorebook",
215
+ entries: [],
216
+ extensions: { risu: obj }
217
+ };
218
+ }
219
+ function normalizeWyvern(data) {
220
+ const obj = data;
221
+ return {
222
+ name: typeof obj.name === "string" ? obj.name : "Wyvern Lorebook",
223
+ entries: [],
224
+ extensions: { wyvern: obj }
225
+ };
226
+ }
227
+ function attemptGenericNormalize(data) {
228
+ const obj = data;
229
+ const entries = [];
230
+ const possibleEntries = obj.entries || obj.items || obj.lore || obj.data;
231
+ if (Array.isArray(possibleEntries)) {
232
+ for (let i = 0; i < possibleEntries.length; i++) {
233
+ const e = possibleEntries[i];
234
+ entries.push(normalizeEntry(e, i));
235
+ }
236
+ }
237
+ return {
238
+ name: typeof obj.name === "string" ? obj.name : "Unknown Lorebook",
239
+ description: typeof obj.description === "string" ? obj.description : void 0,
240
+ entries,
241
+ extensions: { original: obj }
242
+ };
243
+ }
244
+ function normalizeEntry(entry, index) {
245
+ const e = entry;
246
+ let keys = [];
247
+ if (Array.isArray(e.keys)) keys = e.keys;
248
+ else if (Array.isArray(e.key)) keys = e.key;
249
+ else if (Array.isArray(e.keywords)) keys = e.keywords;
250
+ else if (typeof e.keys === "string") keys = [e.keys];
251
+ else if (typeof e.key === "string") keys = e.key.split(",").map((k) => k.trim());
252
+ let content = "";
253
+ if (typeof e.content === "string") content = e.content;
254
+ else if (typeof e.entry === "string") content = e.entry;
255
+ else if (typeof e.text === "string") content = e.text;
256
+ else if (typeof e.value === "string") content = e.value;
257
+ return {
258
+ keys,
259
+ secondary_keys: Array.isArray(e.secondary_keys) ? e.secondary_keys : [],
260
+ content,
261
+ enabled: e.enabled !== false && e.disable !== true,
262
+ insertion_order: typeof e.insertion_order === "number" ? e.insertion_order : index,
263
+ id: typeof e.id === "number" ? e.id : index,
264
+ name: typeof e.name === "string" ? e.name : `Entry ${index}`,
265
+ comment: typeof e.comment === "string" ? e.comment : "",
266
+ priority: typeof e.priority === "number" ? e.priority : 10,
267
+ selective: e.selective === true,
268
+ constant: e.constant === true,
269
+ position: "before_char"
270
+ };
271
+ }
272
+ function extractLorebookRefs(card) {
273
+ const refs = [];
274
+ const extensions = card.data.extensions;
275
+ if (!extensions) return refs;
276
+ if (extensions.chub && typeof extensions.chub === "object") {
277
+ const chub = extensions.chub;
278
+ if (Array.isArray(chub.linked_lorebooks)) {
279
+ for (const item of chub.linked_lorebooks) {
280
+ if (typeof item === "string") {
281
+ refs.push(parseLorebookUrl(item, "chub"));
282
+ } else if (typeof item === "object" && item !== null) {
283
+ const obj = item;
284
+ refs.push({
285
+ url: String(obj.url || obj.uri || ""),
286
+ platform: "chub",
287
+ id: obj.id ? String(obj.id) : void 0,
288
+ name: obj.name ? String(obj.name) : void 0
289
+ });
290
+ }
291
+ }
292
+ }
293
+ }
294
+ if (Array.isArray(extensions.world_infos)) {
295
+ for (const item of extensions.world_infos) {
296
+ if (typeof item === "string") {
297
+ refs.push(parseLorebookUrl(item, "unknown"));
298
+ } else if (typeof item === "object" && item !== null) {
299
+ const obj = item;
300
+ refs.push({
301
+ url: String(obj.url || obj.uri || ""),
302
+ platform: detectPlatformFromUrl(String(obj.url || obj.uri || "")),
303
+ id: obj.id ? String(obj.id) : void 0,
304
+ name: obj.name ? String(obj.name) : void 0
305
+ });
306
+ }
307
+ }
308
+ }
309
+ if (Array.isArray(extensions.linked_lorebooks)) {
310
+ for (const item of extensions.linked_lorebooks) {
311
+ if (typeof item === "string") {
312
+ refs.push(parseLorebookUrl(item, "unknown"));
313
+ } else if (typeof item === "object" && item !== null) {
314
+ const obj = item;
315
+ refs.push({
316
+ url: String(obj.url || obj.uri || ""),
317
+ platform: obj.platform ? String(obj.platform) : detectPlatformFromUrl(String(obj.url || "")),
318
+ id: obj.id ? String(obj.id) : void 0,
319
+ name: obj.name ? String(obj.name) : void 0
320
+ });
321
+ }
322
+ }
323
+ }
324
+ if (Array.isArray(extensions.ripiLinkedLorebooks)) {
325
+ for (const item of extensions.ripiLinkedLorebooks) {
326
+ if (typeof item === "object" && item !== null) {
327
+ const obj = item;
328
+ refs.push({
329
+ url: String(obj.url || ""),
330
+ platform: "risu",
331
+ id: obj.id ? String(obj.id) : void 0,
332
+ name: obj.name ? String(obj.name) : void 0
333
+ });
334
+ }
335
+ }
336
+ }
337
+ return refs.filter((r) => r.url.length > 0);
338
+ }
339
+ function parseLorebookUrl(url, defaultPlatform) {
340
+ const platform = detectPlatformFromUrl(url) || defaultPlatform;
341
+ const id = extractIdFromUrl(url, platform);
342
+ return { url, platform, id };
343
+ }
344
+ function detectPlatformFromUrl(url) {
345
+ if (url.includes("chub.ai") || url.includes("characterhub.org")) return "chub";
346
+ if (url.includes("risu.io") || url.includes("risuai")) return "risu";
347
+ if (url.includes("janitorai")) return "janitor";
348
+ if (url.includes("pygmalion")) return "pygmalion";
349
+ return "unknown";
350
+ }
351
+ function extractIdFromUrl(url, platform) {
352
+ try {
353
+ const parsed = new URL(url);
354
+ switch (platform) {
355
+ case "chub": {
356
+ const match = parsed.pathname.match(/\/lorebooks\/([^/]+\/[^/]+)/);
357
+ return match ? match[1] : void 0;
358
+ }
359
+ case "risu": {
360
+ const match = parsed.pathname.match(/\/lorebook\/([^/]+)/);
361
+ return match ? match[1] : void 0;
362
+ }
363
+ default:
364
+ return void 0;
365
+ }
366
+ } catch {
367
+ return void 0;
368
+ }
369
+ }
370
+ function extractLinkedEntries(book) {
371
+ const embeddedEntries = [];
372
+ const linkedBySource = /* @__PURE__ */ new Map();
373
+ for (const entry of book.entries || []) {
374
+ const source = getEntrySource(entry);
375
+ if (source) {
376
+ const existing = linkedBySource.get(source.linkedFrom) || [];
377
+ existing.push(entry);
378
+ linkedBySource.set(source.linkedFrom, existing);
379
+ } else {
380
+ embeddedEntries.push(entry);
381
+ }
382
+ }
383
+ const embedded = {
384
+ ...book,
385
+ entries: embeddedEntries
386
+ };
387
+ const linked = /* @__PURE__ */ new Map();
388
+ for (const [source, entries] of linkedBySource) {
389
+ const firstSource = getEntrySource(entries[0]);
390
+ linked.set(source, {
391
+ name: firstSource?.lorebookName || `Linked from ${source}`,
392
+ entries
393
+ });
394
+ }
395
+ return { embedded, linked };
396
+ }
397
+ function getEntrySource(entry) {
398
+ const ext = entry.extensions;
399
+ if (!ext?.lorebookSource) return void 0;
400
+ const source = ext.lorebookSource;
401
+ return {
402
+ linkedFrom: String(source.linkedFrom || ""),
403
+ platform: String(source.platform || "unknown"),
404
+ fetchedAt: String(source.fetchedAt || ""),
405
+ originalEntryId: source.originalEntryId ? String(source.originalEntryId) : void 0,
406
+ lorebookName: source.lorebookName ? String(source.lorebookName) : void 0
407
+ };
408
+ }
409
+ function getLorebookCollection(card) {
410
+ const embedded = [];
411
+ const linked = [];
412
+ if (card.data.character_book) {
413
+ const { embedded: embeddedBook, linked: linkedBooks } = extractLinkedEntries(
414
+ card.data.character_book
415
+ );
416
+ if (embeddedBook.entries.length > 0) {
417
+ embedded.push(embeddedBook);
418
+ }
419
+ for (const [source, book] of linkedBooks) {
420
+ const firstEntry = book.entries[0];
421
+ const sourceMeta = getEntrySource(firstEntry);
422
+ linked.push({
423
+ source,
424
+ platform: sourceMeta?.platform || "unknown",
425
+ fetchedAt: sourceMeta?.fetchedAt || "",
426
+ name: book.name,
427
+ book
428
+ });
429
+ }
430
+ }
431
+ const extensions = card.data.extensions;
432
+ if (extensions?.additional_lorebooks && Array.isArray(extensions.additional_lorebooks)) {
433
+ for (const additionalBook of extensions.additional_lorebooks) {
434
+ if (additionalBook && typeof additionalBook === "object") {
435
+ const book = additionalBook;
436
+ if (book.entries && book.entries.length > 0) {
437
+ embedded.push(book);
438
+ }
439
+ }
440
+ }
441
+ }
442
+ return { embedded, linked };
443
+ }
444
+ function stampEntriesWithSource(book, source) {
445
+ const stampedEntries = book.entries.map((entry) => stampEntry(entry, source));
446
+ return {
447
+ ...book,
448
+ entries: stampedEntries
449
+ };
450
+ }
451
+ function stampEntry(entry, source) {
452
+ const sourceMeta = {
453
+ ...source,
454
+ originalEntryId: entry.name || String(entry.id)
455
+ };
456
+ return {
457
+ ...entry,
458
+ extensions: {
459
+ ...entry.extensions,
460
+ lorebookSource: sourceMeta
461
+ }
462
+ };
463
+ }
464
+ function createLinkedLorebook(book, sourceUrl, platform, sourceId) {
465
+ const fetchedAt = (/* @__PURE__ */ new Date()).toISOString();
466
+ const stampedBook = stampEntriesWithSource(book, {
467
+ linkedFrom: sourceUrl,
468
+ platform,
469
+ fetchedAt,
470
+ lorebookName: book.name
471
+ });
472
+ return {
473
+ source: sourceUrl,
474
+ platform,
475
+ sourceId,
476
+ fetchedAt,
477
+ name: book.name,
478
+ book: stampedBook
479
+ };
480
+ }
481
+ function addLinkedLorebookToCard(card, linkedBook) {
482
+ const extensions = card.data.extensions || {};
483
+ const additionalLorebooks = extensions.additional_lorebooks || [];
484
+ return {
485
+ ...card,
486
+ data: {
487
+ ...card.data,
488
+ extensions: {
489
+ ...extensions,
490
+ additional_lorebooks: [...additionalLorebooks, linkedBook.book]
491
+ }
492
+ }
493
+ };
494
+ }
495
+ function addEmbeddedLorebookToCard(card, book) {
496
+ if (!card.data.character_book || card.data.character_book.entries.length === 0) {
497
+ return {
498
+ ...card,
499
+ data: {
500
+ ...card.data,
501
+ character_book: book
502
+ }
503
+ };
504
+ }
505
+ const extensions = card.data.extensions || {};
506
+ const additionalLorebooks = extensions.additional_lorebooks || [];
507
+ return {
508
+ ...card,
509
+ data: {
510
+ ...card.data,
511
+ extensions: {
512
+ ...extensions,
513
+ additional_lorebooks: [...additionalLorebooks, book]
514
+ }
515
+ }
516
+ };
517
+ }
518
+ function removeLorebookFromCard(card, lorebookName) {
519
+ let updatedCard = { ...card, data: { ...card.data } };
520
+ if (card.data.character_book?.name === lorebookName) {
521
+ updatedCard.data.character_book = void 0;
522
+ }
523
+ const extensions = card.data.extensions || {};
524
+ if (Array.isArray(extensions.additional_lorebooks)) {
525
+ const filtered = extensions.additional_lorebooks.filter(
526
+ (book) => book.name !== lorebookName
527
+ );
528
+ updatedCard.data.extensions = {
529
+ ...extensions,
530
+ additional_lorebooks: filtered.length > 0 ? filtered : void 0
531
+ };
532
+ }
533
+ return updatedCard;
534
+ }
535
+ function removeLinkedEntriesBySource(card, sourceUrl) {
536
+ let updatedCard = { ...card, data: { ...card.data } };
537
+ if (card.data.character_book) {
538
+ updatedCard.data.character_book = removeSourceEntriesFromBook(
539
+ card.data.character_book,
540
+ sourceUrl
541
+ );
542
+ }
543
+ const extensions = card.data.extensions || {};
544
+ if (Array.isArray(extensions.additional_lorebooks)) {
545
+ const cleaned = extensions.additional_lorebooks.map((book) => removeSourceEntriesFromBook(book, sourceUrl)).filter((book) => book.entries.length > 0);
546
+ updatedCard.data.extensions = {
547
+ ...extensions,
548
+ additional_lorebooks: cleaned.length > 0 ? cleaned : void 0
549
+ };
550
+ }
551
+ return updatedCard;
552
+ }
553
+ function removeSourceEntriesFromBook(book, sourceUrl) {
554
+ const filteredEntries = book.entries.filter((entry) => {
555
+ const ext = entry.extensions;
556
+ if (!ext?.lorebookSource) return true;
557
+ const source = ext.lorebookSource;
558
+ return source.linkedFrom !== sourceUrl;
559
+ });
560
+ return {
561
+ ...book,
562
+ entries: filteredEntries
563
+ };
564
+ }
565
+ function replaceLorebookInCard(card, updatedBook) {
566
+ let updatedCard = { ...card, data: { ...card.data } };
567
+ if (card.data.character_book?.name === updatedBook.name) {
568
+ updatedCard.data.character_book = updatedBook;
569
+ return updatedCard;
570
+ }
571
+ const extensions = card.data.extensions || {};
572
+ if (Array.isArray(extensions.additional_lorebooks)) {
573
+ const updated = extensions.additional_lorebooks.map(
574
+ (book) => book.name === updatedBook.name ? updatedBook : book
575
+ );
576
+ updatedCard.data.extensions = {
577
+ ...extensions,
578
+ additional_lorebooks: updated
579
+ };
580
+ }
581
+ return updatedCard;
582
+ }
583
+ function setLorebookCollection(card, collection) {
584
+ const [mainBook, ...additionalEmbedded] = collection.embedded;
585
+ const linkedBooks = collection.linked.map((l) => l.book);
586
+ const additionalBooks = [...additionalEmbedded, ...linkedBooks];
587
+ const extensions = card.data.extensions || {};
588
+ return {
589
+ ...card,
590
+ data: {
591
+ ...card.data,
592
+ character_book: mainBook,
593
+ extensions: {
594
+ ...extensions,
595
+ additional_lorebooks: additionalBooks.length > 0 ? additionalBooks : void 0
596
+ }
597
+ }
598
+ };
599
+ }
600
+ function convertLorebook(book, targetFormat, originalShape) {
601
+ switch (targetFormat) {
602
+ case "ccv3":
603
+ return book;
604
+ case "sillytavern":
605
+ return toSillyTavern(book, originalShape);
606
+ case "agnai":
607
+ return toAgnai(book, originalShape);
608
+ case "risu":
609
+ return toRisu(book, originalShape);
610
+ case "wyvern":
611
+ return toWyvern(book, originalShape);
612
+ default:
613
+ return book;
614
+ }
615
+ }
616
+ function toSillyTavern(book, original) {
617
+ const entries = {};
618
+ for (let i = 0; i < book.entries.length; i++) {
619
+ const entry = book.entries[i];
620
+ const uid = entry.id ?? i;
621
+ const stExt = entry.extensions?.sillytavern || {};
622
+ entries[String(uid)] = {
623
+ uid,
624
+ key: entry.keys,
625
+ keysecondary: entry.secondary_keys,
626
+ comment: entry.comment || entry.name,
627
+ content: entry.content,
628
+ constant: entry.constant,
629
+ selective: entry.selective,
630
+ selectiveLogic: stExt.selectiveLogic,
631
+ order: entry.insertion_order,
632
+ position: mapCCv3Position(entry.position),
633
+ disable: !entry.enabled,
634
+ excludeRecursion: stExt.excludeRecursion,
635
+ probability: stExt.probability,
636
+ useProbability: stExt.useProbability,
637
+ depth: stExt.depth,
638
+ group: stExt.group,
639
+ scanDepth: stExt.scanDepth,
640
+ caseSensitive: stExt.caseSensitive,
641
+ matchWholeWords: stExt.matchWholeWords,
642
+ automationId: stExt.automationId,
643
+ role: stExt.role,
644
+ vectorized: stExt.vectorized,
645
+ groupOverride: stExt.groupOverride,
646
+ groupWeight: stExt.groupWeight,
647
+ sticky: stExt.sticky,
648
+ cooldown: stExt.cooldown,
649
+ delay: stExt.delay
650
+ };
651
+ }
652
+ return {
653
+ entries,
654
+ name: book.name,
655
+ description: book.description
656
+ };
657
+ }
658
+ function mapCCv3Position(position) {
659
+ switch (position) {
660
+ case "before_char":
661
+ return 0;
662
+ case "after_char":
663
+ return 1;
664
+ default:
665
+ return 0;
666
+ }
667
+ }
668
+ function toAgnai(book, original) {
669
+ const entries = book.entries.map((entry, i) => {
670
+ const agnaiExt = entry.extensions?.agnai || {};
671
+ return {
672
+ name: entry.name || `Entry ${i}`,
673
+ entry: entry.content,
674
+ keywords: entry.keys,
675
+ priority: entry.priority ?? 10,
676
+ weight: agnaiExt.weight ?? 1,
677
+ enabled: entry.enabled !== false
678
+ };
679
+ });
680
+ return {
681
+ kind: "memory",
682
+ name: book.name || "Lorebook",
683
+ description: book.description,
684
+ entries
685
+ };
686
+ }
687
+ function toRisu(book, original) {
688
+ if (original && typeof original === "object") {
689
+ const obj = original;
690
+ return {
691
+ ...obj,
692
+ // Update with CCv3 data
693
+ name: book.name,
694
+ entries: book.entries
695
+ };
696
+ }
697
+ return {
698
+ type: "risu",
699
+ name: book.name,
700
+ entries: book.entries
701
+ };
702
+ }
703
+ function toWyvern(book, original) {
704
+ if (original && typeof original === "object") {
705
+ const obj = original;
706
+ return {
707
+ ...obj,
708
+ // Update with CCv3 data
709
+ name: book.name,
710
+ entries: book.entries
711
+ };
712
+ }
713
+ return {
714
+ format: "wyvern",
715
+ name: book.name,
716
+ entries: book.entries
717
+ };
718
+ }
719
+ function serializeLorebook(book, format = "ccv3", originalShape, pretty = true) {
720
+ const converted = convertLorebook(book, format, originalShape);
721
+ return pretty ? JSON.stringify(converted, null, 2) : JSON.stringify(converted);
722
+ }
723
+ function serializeParsedLorebook(parsed, pretty = true) {
724
+ return serializeLorebook(
725
+ parsed.book,
726
+ parsed.originalFormat,
727
+ parsed.originalShape,
728
+ pretty
729
+ );
730
+ }
731
+ function mergeLorebooks(bookA, bookB, name) {
732
+ const maxIdA = Math.max(0, ...bookA.entries.map((e) => e.id ?? 0));
733
+ const renumberedB = bookB.entries.map((entry, i) => ({
734
+ ...entry,
735
+ id: maxIdA + 1 + i,
736
+ insertion_order: bookA.entries.length + i
737
+ }));
738
+ return {
739
+ name: name || bookA.name || bookB.name,
740
+ description: bookA.description || bookB.description,
741
+ entries: [...bookA.entries, ...renumberedB],
742
+ extensions: {
743
+ ...bookA.extensions,
744
+ ...bookB.extensions
745
+ }
746
+ };
747
+ }
748
+ function findEntriesByKeys(book, searchKeys, options = {}) {
749
+ const { caseSensitive = false, matchAll = false } = options;
750
+ const normalizeKey = (k) => caseSensitive ? k : k.toLowerCase();
751
+ const normalizedSearch = searchKeys.map(normalizeKey);
752
+ return book.entries.filter((entry) => {
753
+ const entryKeys = entry.keys.map(normalizeKey);
754
+ if (matchAll) {
755
+ return normalizedSearch.every((sk) => entryKeys.some((ek) => ek.includes(sk)));
756
+ } else {
757
+ return normalizedSearch.some((sk) => entryKeys.some((ek) => ek.includes(sk)));
758
+ }
759
+ });
760
+ }
761
+ function findEntryByNameOrId(book, nameOrId) {
762
+ if (typeof nameOrId === "number") {
763
+ return book.entries.find((e) => e.id === nameOrId);
764
+ }
765
+ return book.entries.find(
766
+ (e) => e.name === nameOrId || String(e.id) === nameOrId
767
+ );
768
+ }
769
+ function updateEntry(book, entryId, updates) {
770
+ const entries = book.entries.map((entry) => {
771
+ const matches = entry.id === entryId || entry.name === entryId || String(entry.id) === entryId;
772
+ if (matches) {
773
+ return { ...entry, ...updates };
774
+ }
775
+ return entry;
776
+ });
777
+ return { ...book, entries };
778
+ }
779
+ function addEntry(book, entry) {
780
+ const maxId = Math.max(0, ...book.entries.map((e) => e.id ?? 0));
781
+ const newEntry = {
782
+ ...entry,
783
+ id: maxId + 1,
784
+ insertion_order: book.entries.length
785
+ };
786
+ return {
787
+ ...book,
788
+ entries: [...book.entries, newEntry]
789
+ };
790
+ }
791
+ function removeEntry(book, entryId) {
792
+ const entries = book.entries.filter((entry) => {
793
+ const matches = entry.id === entryId || entry.name === entryId || String(entry.id) === entryId;
794
+ return !matches;
795
+ });
796
+ return { ...book, entries };
797
+ }
798
+ function reorderEntries(book, entryIds) {
799
+ const entryMap = new Map(
800
+ book.entries.map((e) => [e.id ?? e.name, e])
801
+ );
802
+ const reordered = [];
803
+ for (let i = 0; i < entryIds.length; i++) {
804
+ const id = entryIds[i];
805
+ const entry = entryMap.get(id) || book.entries.find((e) => e.name === id);
806
+ if (entry) {
807
+ reordered.push({ ...entry, insertion_order: i });
808
+ entryMap.delete(entry.id ?? entry.name);
809
+ }
810
+ }
811
+ for (const entry of entryMap.values()) {
812
+ reordered.push({ ...entry, insertion_order: reordered.length });
813
+ }
814
+ return { ...book, entries: reordered };
815
+ }
816
+ export {
817
+ addEmbeddedLorebookToCard,
818
+ addEntry,
819
+ addLinkedLorebookToCard,
820
+ convertLorebook,
821
+ createLinkedLorebook,
822
+ detectLorebookFormat,
823
+ extractLinkedEntries,
824
+ extractLorebookRefs,
825
+ findEntriesByKeys,
826
+ findEntryByNameOrId,
827
+ getLorebookCollection,
828
+ mergeLorebooks,
829
+ normalizeToCC3,
830
+ parseLorebook,
831
+ removeEntry,
832
+ removeLinkedEntriesBySource,
833
+ removeLorebookFromCard,
834
+ reorderEntries,
835
+ replaceLorebookInCard,
836
+ serializeLorebook,
837
+ serializeParsedLorebook,
838
+ setLorebookCollection,
839
+ stampEntriesWithSource,
840
+ updateEntry
841
+ };
2
842
  //# sourceMappingURL=lorebook.js.map