@character-foundry/character-foundry 0.1.9 → 0.4.0-dev.1765938243

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 (71) hide show
  1. package/dist/app-framework.cjs +291 -95
  2. package/dist/app-framework.cjs.map +1 -1
  3. package/dist/app-framework.d.cts +1 -1
  4. package/dist/app-framework.d.ts +1 -1
  5. package/dist/app-framework.js +292 -96
  6. package/dist/app-framework.js.map +1 -1
  7. package/dist/charx.cjs +44 -23
  8. package/dist/charx.cjs.map +1 -1
  9. package/dist/charx.d.cts +377 -207
  10. package/dist/charx.d.ts +377 -207
  11. package/dist/charx.js +44 -23
  12. package/dist/charx.js.map +1 -1
  13. package/dist/exporter.cjs +27 -22
  14. package/dist/exporter.cjs.map +1 -1
  15. package/dist/exporter.d.cts +377 -207
  16. package/dist/exporter.d.ts +377 -207
  17. package/dist/exporter.js +27 -22
  18. package/dist/exporter.js.map +1 -1
  19. package/dist/federation.cjs +16 -4
  20. package/dist/federation.cjs.map +1 -1
  21. package/dist/federation.d.cts +377 -207
  22. package/dist/federation.d.ts +377 -207
  23. package/dist/federation.js +16 -4
  24. package/dist/federation.js.map +1 -1
  25. package/dist/image-utils.cjs.map +1 -1
  26. package/dist/image-utils.d.cts +12 -0
  27. package/dist/image-utils.d.ts +12 -0
  28. package/dist/image-utils.js.map +1 -1
  29. package/dist/index.cjs +106 -56
  30. package/dist/index.cjs.map +1 -1
  31. package/dist/index.d.cts +729 -423
  32. package/dist/index.d.ts +729 -423
  33. package/dist/index.js +106 -56
  34. package/dist/index.js.map +1 -1
  35. package/dist/loader.cjs +106 -56
  36. package/dist/loader.cjs.map +1 -1
  37. package/dist/loader.d.cts +578 -318
  38. package/dist/loader.d.ts +578 -318
  39. package/dist/loader.js +106 -56
  40. package/dist/loader.js.map +1 -1
  41. package/dist/lorebook.cjs +5 -5
  42. package/dist/lorebook.cjs.map +1 -1
  43. package/dist/lorebook.d.cts +691 -381
  44. package/dist/lorebook.d.ts +691 -381
  45. package/dist/lorebook.js +5 -5
  46. package/dist/lorebook.js.map +1 -1
  47. package/dist/normalizer.cjs +33 -23
  48. package/dist/normalizer.cjs.map +1 -1
  49. package/dist/normalizer.d.cts +926 -560
  50. package/dist/normalizer.d.ts +926 -560
  51. package/dist/normalizer.js +33 -23
  52. package/dist/normalizer.js.map +1 -1
  53. package/dist/png.cjs +27 -22
  54. package/dist/png.cjs.map +1 -1
  55. package/dist/png.d.cts +528 -312
  56. package/dist/png.d.ts +528 -312
  57. package/dist/png.js +27 -22
  58. package/dist/png.js.map +1 -1
  59. package/dist/schemas.cjs +41 -26
  60. package/dist/schemas.cjs.map +1 -1
  61. package/dist/schemas.d.cts +1492 -896
  62. package/dist/schemas.d.ts +1492 -896
  63. package/dist/schemas.js +41 -26
  64. package/dist/schemas.js.map +1 -1
  65. package/dist/voxta.cjs +48 -25
  66. package/dist/voxta.cjs.map +1 -1
  67. package/dist/voxta.d.cts +578 -318
  68. package/dist/voxta.d.ts +578 -318
  69. package/dist/voxta.js +48 -25
  70. package/dist/voxta.js.map +1 -1
  71. package/package.json +6 -6
package/dist/loader.js CHANGED
@@ -104,7 +104,23 @@ function streamingUnzipSync(data, limits = DEFAULT_ZIP_LIMITS) {
104
104
  if (unsafePathHandling === "warn" && limits.onUnsafePath) {
105
105
  limits.onUnsafePath(file.name, reason);
106
106
  }
107
- file.ondata = () => {
107
+ file.ondata = (err, chunk, _final) => {
108
+ if (error) return;
109
+ if (err) {
110
+ error = err;
111
+ return;
112
+ }
113
+ if (chunk && chunk.length > 0) {
114
+ totalBytes += chunk.length;
115
+ if (totalBytes > limits.maxTotalSize) {
116
+ error = new ZipPreflightError(
117
+ `Total actual size ${totalBytes} exceeds limit ${limits.maxTotalSize}`,
118
+ totalBytes,
119
+ limits.maxTotalSize
120
+ );
121
+ file.terminate();
122
+ }
123
+ }
108
124
  };
109
125
  file.start();
110
126
  return;
@@ -441,22 +457,24 @@ var ExtractedAssetSchema = z.object({
441
457
  mimeType: z.string()
442
458
  });
443
459
  var CCv2LorebookEntrySchema = z2.object({
444
- keys: z2.array(z2.string()),
460
+ keys: z2.array(z2.string()).optional(),
461
+ // Some tools use 'key' instead
445
462
  content: z2.string(),
446
- enabled: z2.boolean(),
447
- insertion_order: z2.number().int(),
448
- // Optional fields
463
+ enabled: z2.boolean().default(true),
464
+ // Default to enabled if missing
465
+ insertion_order: z2.number().int().default(0),
466
+ // Optional fields - be lenient with nulls since wild data has them
449
467
  extensions: z2.record(z2.unknown()).optional(),
450
- case_sensitive: z2.boolean().optional(),
468
+ case_sensitive: z2.boolean().nullable().optional(),
451
469
  name: z2.string().optional(),
452
470
  priority: z2.number().int().optional(),
453
471
  id: z2.number().int().optional(),
454
472
  comment: z2.string().optional(),
455
- selective: z2.boolean().optional(),
473
+ selective: z2.boolean().nullable().optional(),
456
474
  secondary_keys: z2.array(z2.string()).optional(),
457
- constant: z2.boolean().optional(),
458
- position: z2.enum(["before_char", "after_char"]).optional()
459
- });
475
+ constant: z2.boolean().nullable().optional(),
476
+ position: z2.union([z2.enum(["before_char", "after_char"]), z2.number().int(), z2.literal("")]).nullable().optional()
477
+ }).passthrough();
460
478
  var CCv2CharacterBookSchema = z2.object({
461
479
  name: z2.string().optional(),
462
480
  description: z2.string().optional(),
@@ -504,31 +522,34 @@ function getV2Data(card) {
504
522
  return card;
505
523
  }
506
524
  var CCv3LorebookEntrySchema = z3.object({
507
- keys: z3.array(z3.string()),
525
+ keys: z3.array(z3.string()).optional(),
526
+ // Some tools use 'key' instead
508
527
  content: z3.string(),
509
- enabled: z3.boolean(),
510
- insertion_order: z3.number().int(),
511
- // Optional fields
512
- case_sensitive: z3.boolean().optional(),
528
+ enabled: z3.boolean().default(true),
529
+ // Default to enabled if missing
530
+ insertion_order: z3.number().int().default(0),
531
+ // Optional fields - be lenient with nulls since wild data has them
532
+ case_sensitive: z3.boolean().nullable().optional(),
513
533
  name: z3.string().optional(),
514
534
  priority: z3.number().int().optional(),
515
535
  id: z3.number().int().optional(),
516
536
  comment: z3.string().optional(),
517
- selective: z3.boolean().optional(),
537
+ selective: z3.boolean().nullable().optional(),
518
538
  secondary_keys: z3.array(z3.string()).optional(),
519
- constant: z3.boolean().optional(),
520
- position: z3.enum(["before_char", "after_char"]).optional(),
539
+ constant: z3.boolean().nullable().optional(),
540
+ position: z3.union([z3.enum(["before_char", "after_char"]), z3.number().int(), z3.literal("")]).nullable().optional(),
521
541
  extensions: z3.record(z3.unknown()).optional(),
522
- // v3 specific
542
+ // v3 specific - also lenient with types since SillyTavern uses numbers for enums
523
543
  automation_id: z3.string().optional(),
524
- role: z3.enum(["system", "user", "assistant"]).optional(),
544
+ role: z3.union([z3.enum(["system", "user", "assistant"]), z3.number().int()]).nullable().optional(),
525
545
  group: z3.string().optional(),
526
546
  scan_frequency: z3.number().int().nonnegative().optional(),
527
- probability: z3.number().min(0).max(1).optional(),
547
+ probability: z3.number().min(0).max(100).optional(),
548
+ // Some tools use 0-100 instead of 0-1
528
549
  use_regex: z3.boolean().optional(),
529
550
  depth: z3.number().int().nonnegative().optional(),
530
- selective_logic: z3.enum(["AND", "NOT"]).optional()
531
- });
551
+ selective_logic: z3.union([z3.enum(["AND", "NOT"]), z3.number().int()]).optional()
552
+ }).passthrough();
532
553
  var CCv3CharacterBookSchema = z3.object({
533
554
  name: z3.string().optional(),
534
555
  description: z3.string().optional(),
@@ -7689,8 +7710,10 @@ function voxtaToCCv3(character, books) {
7689
7710
  };
7690
7711
  }
7691
7712
  }
7692
- const creationDate = character.DateCreated ? Math.floor(new Date(character.DateCreated).getTime() / 1e3) : void 0;
7693
- const modificationDate = character.DateModified ? Math.floor(new Date(character.DateModified).getTime() / 1e3) : void 0;
7713
+ const rawCreationDate = character.DateCreated ? Math.floor(new Date(character.DateCreated).getTime() / 1e3) : void 0;
7714
+ const rawModificationDate = character.DateModified ? Math.floor(new Date(character.DateModified).getTime() / 1e3) : void 0;
7715
+ const creationDate = rawCreationDate !== void 0 && rawCreationDate >= 0 ? rawCreationDate : void 0;
7716
+ const modificationDate = rawModificationDate !== void 0 && rawModificationDate >= 0 ? rawModificationDate : void 0;
7694
7717
  const card = {
7695
7718
  spec: "chara_card_v3",
7696
7719
  spec_version: "3.0",
@@ -7725,6 +7748,11 @@ var DELTA_MAX_TOTAL_SIZE = 500 * 1024 * 1024;
7725
7748
  var DELTA_MAX_FILE_SIZE = 50 * 1024 * 1024;
7726
7749
 
7727
7750
  // ../normalizer/dist/index.js
7751
+ function normalizePosition(position) {
7752
+ if (position === void 0 || position === null || position === "") return "before_char";
7753
+ if (typeof position === "string") return position;
7754
+ return position;
7755
+ }
7728
7756
  function convertLorebookEntry(entry, index) {
7729
7757
  return {
7730
7758
  keys: entry.keys || [],
@@ -7740,7 +7768,7 @@ function convertLorebookEntry(entry, index) {
7740
7768
  selective: entry.selective ?? false,
7741
7769
  secondary_keys: entry.secondary_keys || [],
7742
7770
  constant: entry.constant ?? false,
7743
- position: entry.position || "before_char"
7771
+ position: normalizePosition(entry.position)
7744
7772
  };
7745
7773
  }
7746
7774
  function convertCharacterBook(book) {
@@ -8152,6 +8180,43 @@ var DEFAULT_OPTIONS3 = {
8152
8180
  maxTotalSize: 500 * 1024 * 1024,
8153
8181
  extractAssets: true
8154
8182
  };
8183
+ var ASSET_PREFIX_VARIANTS = [
8184
+ { prefix: "__asset:", format: "CCv3 (SillyTavern)" },
8185
+ { prefix: "asset:", format: "CCv2/CCv3 common" },
8186
+ { prefix: "pngchunk:", format: "Explicit PNG chunk" },
8187
+ { prefix: "chara-ext-asset_:", format: "RisuAI (with colon)" },
8188
+ { prefix: "chara-ext-asset_", format: "RisuAI" },
8189
+ { prefix: "__asset_", format: "Legacy underscore variant" }
8190
+ ];
8191
+ function isChunkReference(uri) {
8192
+ return ASSET_PREFIX_VARIANTS.some(({ prefix }) => uri.startsWith(prefix)) || !uri.includes(":");
8193
+ }
8194
+ function stripAssetPrefix(uri) {
8195
+ for (const { prefix } of ASSET_PREFIX_VARIANTS) {
8196
+ if (uri.startsWith(prefix)) {
8197
+ return uri.substring(prefix.length);
8198
+ }
8199
+ }
8200
+ return uri;
8201
+ }
8202
+ function generateChunkKeyCandidates(assetId, originalUri) {
8203
+ return [
8204
+ assetId,
8205
+ // Plain ID: "0"
8206
+ originalUri,
8207
+ // Original URI: "__asset:0"
8208
+ `asset:${assetId}`,
8209
+ // Common format
8210
+ `__asset:${assetId}`,
8211
+ // CCv3 format
8212
+ `__asset_${assetId}`,
8213
+ // Legacy underscore variant
8214
+ `chara-ext-asset_${assetId}`,
8215
+ // RisuAI format
8216
+ `chara-ext-asset_:${assetId}`
8217
+ // RisuAI format with colon
8218
+ ];
8219
+ }
8155
8220
  function estimateBase64DecodedSize(base64Length) {
8156
8221
  return Math.ceil(base64Length * 0.75);
8157
8222
  }
@@ -8219,39 +8284,22 @@ function parsePng(data, options) {
8219
8284
  if (extracted.extraChunks && options.extractAssets && card.data.assets) {
8220
8285
  const usedChunks = /* @__PURE__ */ new Set();
8221
8286
  const chunkMap = /* @__PURE__ */ new Map();
8287
+ const risuIndexPrefixes = ASSET_PREFIX_VARIANTS.filter((v) => v.prefix.startsWith("chara-ext-asset_"));
8222
8288
  for (const chunk of extracted.extraChunks) {
8223
8289
  chunkMap.set(chunk.keyword, chunk);
8224
- if (chunk.keyword.startsWith("chara-ext-asset_")) {
8225
- const suffix = chunk.keyword.replace("chara-ext-asset_", "");
8226
- chunkMap.set(suffix, chunk);
8227
- if (suffix.startsWith(":")) {
8228
- chunkMap.set(suffix.substring(1), chunk);
8290
+ for (const { prefix } of risuIndexPrefixes) {
8291
+ if (chunk.keyword.startsWith(prefix)) {
8292
+ const suffix = chunk.keyword.substring(prefix.length);
8293
+ chunkMap.set(suffix, chunk);
8294
+ break;
8229
8295
  }
8230
8296
  }
8231
8297
  }
8232
8298
  for (const descriptor of card.data.assets) {
8233
8299
  if (!descriptor.uri) continue;
8234
- if (descriptor.uri.startsWith("__asset:") || descriptor.uri.startsWith("asset:") || descriptor.uri.startsWith("pngchunk:") || !descriptor.uri.includes(":")) {
8235
- let assetId = descriptor.uri;
8236
- if (assetId.startsWith("__asset:")) assetId = assetId.substring(8);
8237
- else if (assetId.startsWith("asset:")) assetId = assetId.substring(6);
8238
- else if (assetId.startsWith("pngchunk:")) assetId = assetId.substring(9);
8239
- const candidates = [
8240
- assetId,
8241
- // "0"
8242
- descriptor.uri,
8243
- // "__asset:0"
8244
- `asset:${assetId}`,
8245
- // "asset:0"
8246
- `__asset:${assetId}`,
8247
- // "__asset:0"
8248
- `__asset_${assetId}`,
8249
- // "__asset_0"
8250
- `chara-ext-asset_${assetId}`,
8251
- // "chara-ext-asset_0"
8252
- `chara-ext-asset_:${assetId}`
8253
- // "chara-ext-asset_:0"
8254
- ];
8300
+ if (isChunkReference(descriptor.uri)) {
8301
+ const assetId = stripAssetPrefix(descriptor.uri);
8302
+ const candidates = generateChunkKeyCandidates(assetId, descriptor.uri);
8255
8303
  let chunk;
8256
8304
  for (const candidate of candidates) {
8257
8305
  chunk = chunkMap.get(candidate);
@@ -8298,13 +8346,15 @@ function parsePng(data, options) {
8298
8346
  }
8299
8347
  }
8300
8348
  }
8349
+ const risuPrefixes = ASSET_PREFIX_VARIANTS.filter((v) => v.prefix.startsWith("chara-ext-asset_"));
8301
8350
  for (const chunk of extracted.extraChunks) {
8302
8351
  if (!usedChunks.has(chunk.keyword)) {
8303
8352
  let assetId = null;
8304
- if (chunk.keyword.startsWith("chara-ext-asset_:")) {
8305
- assetId = chunk.keyword.substring("chara-ext-asset_:".length);
8306
- } else if (chunk.keyword.startsWith("chara-ext-asset_")) {
8307
- assetId = chunk.keyword.substring("chara-ext-asset_".length);
8353
+ for (const { prefix } of risuPrefixes) {
8354
+ if (chunk.keyword.startsWith(prefix)) {
8355
+ assetId = chunk.keyword.substring(prefix.length);
8356
+ break;
8357
+ }
8308
8358
  }
8309
8359
  if (assetId) {
8310
8360
  try {