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

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 +368 -207
  10. package/dist/charx.d.ts +368 -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 +368 -207
  16. package/dist/exporter.d.ts +368 -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 +368 -207
  22. package/dist/federation.d.ts +368 -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 +708 -423
  32. package/dist/index.d.ts +708 -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 +564 -318
  38. package/dist/loader.d.ts +564 -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 +674 -381
  44. package/dist/lorebook.d.ts +674 -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 +896 -560
  50. package/dist/normalizer.d.ts +896 -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 +512 -312
  56. package/dist/png.d.ts +512 -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 +1444 -896
  62. package/dist/schemas.d.ts +1444 -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 +564 -318
  68. package/dist/voxta.d.ts +564 -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.cjs CHANGED
@@ -134,7 +134,23 @@ function streamingUnzipSync(data, limits = DEFAULT_ZIP_LIMITS) {
134
134
  if (unsafePathHandling === "warn" && limits.onUnsafePath) {
135
135
  limits.onUnsafePath(file.name, reason);
136
136
  }
137
- file.ondata = () => {
137
+ file.ondata = (err, chunk, _final) => {
138
+ if (error) return;
139
+ if (err) {
140
+ error = err;
141
+ return;
142
+ }
143
+ if (chunk && chunk.length > 0) {
144
+ totalBytes += chunk.length;
145
+ if (totalBytes > limits.maxTotalSize) {
146
+ error = new ZipPreflightError(
147
+ `Total actual size ${totalBytes} exceeds limit ${limits.maxTotalSize}`,
148
+ totalBytes,
149
+ limits.maxTotalSize
150
+ );
151
+ file.terminate();
152
+ }
153
+ }
138
154
  };
139
155
  file.start();
140
156
  return;
@@ -471,22 +487,24 @@ var ExtractedAssetSchema = import_zod.z.object({
471
487
  mimeType: import_zod.z.string()
472
488
  });
473
489
  var CCv2LorebookEntrySchema = import_zod2.z.object({
474
- keys: import_zod2.z.array(import_zod2.z.string()),
490
+ keys: import_zod2.z.array(import_zod2.z.string()).optional(),
491
+ // Some tools use 'key' instead
475
492
  content: import_zod2.z.string(),
476
- enabled: import_zod2.z.boolean(),
477
- insertion_order: import_zod2.z.number().int(),
478
- // Optional fields
493
+ enabled: import_zod2.z.boolean().default(true),
494
+ // Default to enabled if missing
495
+ insertion_order: import_zod2.z.number().int().default(0),
496
+ // Optional fields - be lenient with nulls since wild data has them
479
497
  extensions: import_zod2.z.record(import_zod2.z.unknown()).optional(),
480
- case_sensitive: import_zod2.z.boolean().optional(),
498
+ case_sensitive: import_zod2.z.boolean().nullable().optional(),
481
499
  name: import_zod2.z.string().optional(),
482
500
  priority: import_zod2.z.number().int().optional(),
483
501
  id: import_zod2.z.number().int().optional(),
484
502
  comment: import_zod2.z.string().optional(),
485
- selective: import_zod2.z.boolean().optional(),
503
+ selective: import_zod2.z.boolean().nullable().optional(),
486
504
  secondary_keys: import_zod2.z.array(import_zod2.z.string()).optional(),
487
- constant: import_zod2.z.boolean().optional(),
488
- position: import_zod2.z.enum(["before_char", "after_char"]).optional()
489
- });
505
+ constant: import_zod2.z.boolean().nullable().optional(),
506
+ position: import_zod2.z.union([import_zod2.z.enum(["before_char", "after_char"]), import_zod2.z.number().int()]).nullable().optional()
507
+ }).passthrough();
490
508
  var CCv2CharacterBookSchema = import_zod2.z.object({
491
509
  name: import_zod2.z.string().optional(),
492
510
  description: import_zod2.z.string().optional(),
@@ -534,31 +552,34 @@ function getV2Data(card) {
534
552
  return card;
535
553
  }
536
554
  var CCv3LorebookEntrySchema = import_zod3.z.object({
537
- keys: import_zod3.z.array(import_zod3.z.string()),
555
+ keys: import_zod3.z.array(import_zod3.z.string()).optional(),
556
+ // Some tools use 'key' instead
538
557
  content: import_zod3.z.string(),
539
- enabled: import_zod3.z.boolean(),
540
- insertion_order: import_zod3.z.number().int(),
541
- // Optional fields
542
- case_sensitive: import_zod3.z.boolean().optional(),
558
+ enabled: import_zod3.z.boolean().default(true),
559
+ // Default to enabled if missing
560
+ insertion_order: import_zod3.z.number().int().default(0),
561
+ // Optional fields - be lenient with nulls since wild data has them
562
+ case_sensitive: import_zod3.z.boolean().nullable().optional(),
543
563
  name: import_zod3.z.string().optional(),
544
564
  priority: import_zod3.z.number().int().optional(),
545
565
  id: import_zod3.z.number().int().optional(),
546
566
  comment: import_zod3.z.string().optional(),
547
- selective: import_zod3.z.boolean().optional(),
567
+ selective: import_zod3.z.boolean().nullable().optional(),
548
568
  secondary_keys: import_zod3.z.array(import_zod3.z.string()).optional(),
549
- constant: import_zod3.z.boolean().optional(),
550
- position: import_zod3.z.enum(["before_char", "after_char"]).optional(),
569
+ constant: import_zod3.z.boolean().nullable().optional(),
570
+ position: import_zod3.z.union([import_zod3.z.enum(["before_char", "after_char"]), import_zod3.z.number().int()]).nullable().optional(),
551
571
  extensions: import_zod3.z.record(import_zod3.z.unknown()).optional(),
552
- // v3 specific
572
+ // v3 specific - also lenient with types since SillyTavern uses numbers for enums
553
573
  automation_id: import_zod3.z.string().optional(),
554
- role: import_zod3.z.enum(["system", "user", "assistant"]).optional(),
574
+ role: import_zod3.z.union([import_zod3.z.enum(["system", "user", "assistant"]), import_zod3.z.number().int()]).nullable().optional(),
555
575
  group: import_zod3.z.string().optional(),
556
576
  scan_frequency: import_zod3.z.number().int().nonnegative().optional(),
557
- probability: import_zod3.z.number().min(0).max(1).optional(),
577
+ probability: import_zod3.z.number().min(0).max(100).optional(),
578
+ // Some tools use 0-100 instead of 0-1
558
579
  use_regex: import_zod3.z.boolean().optional(),
559
580
  depth: import_zod3.z.number().int().nonnegative().optional(),
560
- selective_logic: import_zod3.z.enum(["AND", "NOT"]).optional()
561
- });
581
+ selective_logic: import_zod3.z.union([import_zod3.z.enum(["AND", "NOT"]), import_zod3.z.number().int()]).optional()
582
+ }).passthrough();
562
583
  var CCv3CharacterBookSchema = import_zod3.z.object({
563
584
  name: import_zod3.z.string().optional(),
564
585
  description: import_zod3.z.string().optional(),
@@ -7719,8 +7740,10 @@ function voxtaToCCv3(character, books) {
7719
7740
  };
7720
7741
  }
7721
7742
  }
7722
- const creationDate = character.DateCreated ? Math.floor(new Date(character.DateCreated).getTime() / 1e3) : void 0;
7723
- const modificationDate = character.DateModified ? Math.floor(new Date(character.DateModified).getTime() / 1e3) : void 0;
7743
+ const rawCreationDate = character.DateCreated ? Math.floor(new Date(character.DateCreated).getTime() / 1e3) : void 0;
7744
+ const rawModificationDate = character.DateModified ? Math.floor(new Date(character.DateModified).getTime() / 1e3) : void 0;
7745
+ const creationDate = rawCreationDate !== void 0 && rawCreationDate >= 0 ? rawCreationDate : void 0;
7746
+ const modificationDate = rawModificationDate !== void 0 && rawModificationDate >= 0 ? rawModificationDate : void 0;
7724
7747
  const card = {
7725
7748
  spec: "chara_card_v3",
7726
7749
  spec_version: "3.0",
@@ -7755,6 +7778,11 @@ var DELTA_MAX_TOTAL_SIZE = 500 * 1024 * 1024;
7755
7778
  var DELTA_MAX_FILE_SIZE = 50 * 1024 * 1024;
7756
7779
 
7757
7780
  // ../normalizer/dist/index.js
7781
+ function normalizePosition(position) {
7782
+ if (position === void 0 || position === null) return "before_char";
7783
+ if (typeof position === "string") return position;
7784
+ return position;
7785
+ }
7758
7786
  function convertLorebookEntry(entry, index) {
7759
7787
  return {
7760
7788
  keys: entry.keys || [],
@@ -7770,7 +7798,7 @@ function convertLorebookEntry(entry, index) {
7770
7798
  selective: entry.selective ?? false,
7771
7799
  secondary_keys: entry.secondary_keys || [],
7772
7800
  constant: entry.constant ?? false,
7773
- position: entry.position || "before_char"
7801
+ position: normalizePosition(entry.position)
7774
7802
  };
7775
7803
  }
7776
7804
  function convertCharacterBook(book) {
@@ -8182,6 +8210,43 @@ var DEFAULT_OPTIONS3 = {
8182
8210
  maxTotalSize: 500 * 1024 * 1024,
8183
8211
  extractAssets: true
8184
8212
  };
8213
+ var ASSET_PREFIX_VARIANTS = [
8214
+ { prefix: "__asset:", format: "CCv3 (SillyTavern)" },
8215
+ { prefix: "asset:", format: "CCv2/CCv3 common" },
8216
+ { prefix: "pngchunk:", format: "Explicit PNG chunk" },
8217
+ { prefix: "chara-ext-asset_:", format: "RisuAI (with colon)" },
8218
+ { prefix: "chara-ext-asset_", format: "RisuAI" },
8219
+ { prefix: "__asset_", format: "Legacy underscore variant" }
8220
+ ];
8221
+ function isChunkReference(uri) {
8222
+ return ASSET_PREFIX_VARIANTS.some(({ prefix }) => uri.startsWith(prefix)) || !uri.includes(":");
8223
+ }
8224
+ function stripAssetPrefix(uri) {
8225
+ for (const { prefix } of ASSET_PREFIX_VARIANTS) {
8226
+ if (uri.startsWith(prefix)) {
8227
+ return uri.substring(prefix.length);
8228
+ }
8229
+ }
8230
+ return uri;
8231
+ }
8232
+ function generateChunkKeyCandidates(assetId, originalUri) {
8233
+ return [
8234
+ assetId,
8235
+ // Plain ID: "0"
8236
+ originalUri,
8237
+ // Original URI: "__asset:0"
8238
+ `asset:${assetId}`,
8239
+ // Common format
8240
+ `__asset:${assetId}`,
8241
+ // CCv3 format
8242
+ `__asset_${assetId}`,
8243
+ // Legacy underscore variant
8244
+ `chara-ext-asset_${assetId}`,
8245
+ // RisuAI format
8246
+ `chara-ext-asset_:${assetId}`
8247
+ // RisuAI format with colon
8248
+ ];
8249
+ }
8185
8250
  function estimateBase64DecodedSize(base64Length) {
8186
8251
  return Math.ceil(base64Length * 0.75);
8187
8252
  }
@@ -8249,39 +8314,22 @@ function parsePng(data, options) {
8249
8314
  if (extracted.extraChunks && options.extractAssets && card.data.assets) {
8250
8315
  const usedChunks = /* @__PURE__ */ new Set();
8251
8316
  const chunkMap = /* @__PURE__ */ new Map();
8317
+ const risuIndexPrefixes = ASSET_PREFIX_VARIANTS.filter((v) => v.prefix.startsWith("chara-ext-asset_"));
8252
8318
  for (const chunk of extracted.extraChunks) {
8253
8319
  chunkMap.set(chunk.keyword, chunk);
8254
- if (chunk.keyword.startsWith("chara-ext-asset_")) {
8255
- const suffix = chunk.keyword.replace("chara-ext-asset_", "");
8256
- chunkMap.set(suffix, chunk);
8257
- if (suffix.startsWith(":")) {
8258
- chunkMap.set(suffix.substring(1), chunk);
8320
+ for (const { prefix } of risuIndexPrefixes) {
8321
+ if (chunk.keyword.startsWith(prefix)) {
8322
+ const suffix = chunk.keyword.substring(prefix.length);
8323
+ chunkMap.set(suffix, chunk);
8324
+ break;
8259
8325
  }
8260
8326
  }
8261
8327
  }
8262
8328
  for (const descriptor of card.data.assets) {
8263
8329
  if (!descriptor.uri) continue;
8264
- if (descriptor.uri.startsWith("__asset:") || descriptor.uri.startsWith("asset:") || descriptor.uri.startsWith("pngchunk:") || !descriptor.uri.includes(":")) {
8265
- let assetId = descriptor.uri;
8266
- if (assetId.startsWith("__asset:")) assetId = assetId.substring(8);
8267
- else if (assetId.startsWith("asset:")) assetId = assetId.substring(6);
8268
- else if (assetId.startsWith("pngchunk:")) assetId = assetId.substring(9);
8269
- const candidates = [
8270
- assetId,
8271
- // "0"
8272
- descriptor.uri,
8273
- // "__asset:0"
8274
- `asset:${assetId}`,
8275
- // "asset:0"
8276
- `__asset:${assetId}`,
8277
- // "__asset:0"
8278
- `__asset_${assetId}`,
8279
- // "__asset_0"
8280
- `chara-ext-asset_${assetId}`,
8281
- // "chara-ext-asset_0"
8282
- `chara-ext-asset_:${assetId}`
8283
- // "chara-ext-asset_:0"
8284
- ];
8330
+ if (isChunkReference(descriptor.uri)) {
8331
+ const assetId = stripAssetPrefix(descriptor.uri);
8332
+ const candidates = generateChunkKeyCandidates(assetId, descriptor.uri);
8285
8333
  let chunk;
8286
8334
  for (const candidate of candidates) {
8287
8335
  chunk = chunkMap.get(candidate);
@@ -8328,13 +8376,15 @@ function parsePng(data, options) {
8328
8376
  }
8329
8377
  }
8330
8378
  }
8379
+ const risuPrefixes = ASSET_PREFIX_VARIANTS.filter((v) => v.prefix.startsWith("chara-ext-asset_"));
8331
8380
  for (const chunk of extracted.extraChunks) {
8332
8381
  if (!usedChunks.has(chunk.keyword)) {
8333
8382
  let assetId = null;
8334
- if (chunk.keyword.startsWith("chara-ext-asset_:")) {
8335
- assetId = chunk.keyword.substring("chara-ext-asset_:".length);
8336
- } else if (chunk.keyword.startsWith("chara-ext-asset_")) {
8337
- assetId = chunk.keyword.substring("chara-ext-asset_".length);
8383
+ for (const { prefix } of risuPrefixes) {
8384
+ if (chunk.keyword.startsWith(prefix)) {
8385
+ assetId = chunk.keyword.substring(prefix.length);
8386
+ break;
8387
+ }
8338
8388
  }
8339
8389
  if (assetId) {
8340
8390
  try {