@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.
- package/README.md +70 -0
- package/dist/app-framework.cjs +1742 -0
- package/dist/app-framework.cjs.map +1 -0
- package/dist/app-framework.d.cts +881 -0
- package/dist/app-framework.d.ts +881 -2
- package/dist/app-framework.js +1718 -1
- package/dist/app-framework.js.map +1 -1
- package/dist/charx.cjs +917 -0
- package/dist/charx.cjs.map +1 -0
- package/dist/charx.d.cts +640 -0
- package/dist/charx.d.ts +640 -2
- package/dist/charx.js +893 -1
- package/dist/charx.js.map +1 -1
- package/dist/core.cjs +668 -0
- package/dist/core.cjs.map +1 -0
- package/dist/core.d.cts +363 -0
- package/dist/core.d.ts +363 -2
- package/dist/core.js +644 -1
- package/dist/core.js.map +1 -1
- package/dist/exporter.cjs +7539 -0
- package/dist/exporter.cjs.map +1 -0
- package/dist/exporter.d.cts +681 -0
- package/dist/exporter.d.ts +681 -2
- package/dist/exporter.js +7522 -1
- package/dist/exporter.js.map +1 -1
- package/dist/federation.cjs +3915 -0
- package/dist/federation.cjs.map +1 -0
- package/dist/federation.d.cts +2951 -0
- package/dist/federation.d.ts +2951 -2
- package/dist/federation.js +3891 -1
- package/dist/federation.js.map +1 -1
- package/dist/index.cjs +9109 -0
- package/dist/index.cjs.map +1 -0
- package/dist/index.d.cts +1119 -0
- package/dist/index.d.ts +1113 -20
- package/dist/index.js +9092 -26
- package/dist/index.js.map +1 -1
- package/dist/loader.cjs +8923 -0
- package/dist/loader.cjs.map +1 -0
- package/dist/loader.d.cts +1037 -0
- package/dist/loader.d.ts +1037 -2
- package/dist/loader.js +8906 -1
- package/dist/loader.js.map +1 -1
- package/dist/lorebook.cjs +865 -0
- package/dist/lorebook.cjs.map +1 -0
- package/dist/lorebook.d.cts +1008 -0
- package/dist/lorebook.d.ts +1008 -2
- package/dist/lorebook.js +841 -1
- package/dist/lorebook.js.map +1 -1
- package/dist/media.cjs +6660 -0
- package/dist/media.cjs.map +1 -0
- package/dist/media.d.cts +87 -0
- package/dist/media.d.ts +87 -2
- package/dist/media.js +6643 -1
- package/dist/media.js.map +1 -1
- package/dist/normalizer.cjs +502 -0
- package/dist/normalizer.cjs.map +1 -0
- package/dist/normalizer.d.cts +1216 -0
- package/dist/normalizer.d.ts +1216 -2
- package/dist/normalizer.js +478 -1
- package/dist/normalizer.js.map +1 -1
- package/dist/png.cjs +778 -0
- package/dist/png.cjs.map +1 -0
- package/dist/png.d.cts +786 -0
- package/dist/png.d.ts +786 -2
- package/dist/png.js +754 -1
- package/dist/png.js.map +1 -1
- package/dist/schemas.cjs +799 -0
- package/dist/schemas.cjs.map +1 -0
- package/dist/schemas.d.cts +2178 -0
- package/dist/schemas.d.ts +2178 -2
- package/dist/schemas.js +775 -1
- package/dist/schemas.js.map +1 -1
- package/dist/tokenizers.cjs +153 -0
- package/dist/tokenizers.cjs.map +1 -0
- package/dist/tokenizers.d.cts +155 -0
- package/dist/tokenizers.d.ts +155 -2
- package/dist/tokenizers.js +129 -1
- package/dist/tokenizers.js.map +1 -1
- package/dist/voxta.cjs +7995 -0
- package/dist/voxta.cjs.map +1 -0
- package/dist/voxta.d.cts +1349 -0
- package/dist/voxta.d.ts +1349 -2
- package/dist/voxta.js +7978 -1
- package/dist/voxta.js.map +1 -1
- package/package.json +177 -45
- package/dist/app-framework.d.ts.map +0 -1
- package/dist/charx.d.ts.map +0 -1
- package/dist/core.d.ts.map +0 -1
- package/dist/exporter.d.ts.map +0 -1
- package/dist/federation.d.ts.map +0 -1
- package/dist/index.d.ts.map +0 -1
- package/dist/loader.d.ts.map +0 -1
- package/dist/lorebook.d.ts.map +0 -1
- package/dist/media.d.ts.map +0 -1
- package/dist/normalizer.d.ts.map +0 -1
- package/dist/png.d.ts.map +0 -1
- package/dist/schemas.d.ts.map +0 -1
- package/dist/tokenizers.d.ts.map +0 -1
- package/dist/voxta.d.ts.map +0 -1
package/dist/lorebook.js
CHANGED
|
@@ -1,2 +1,842 @@
|
|
|
1
|
-
|
|
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
|