@character-foundry/character-foundry 0.4.1 → 0.4.2-dev.1765997746
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/dist/charx.cjs +17 -38
- package/dist/charx.cjs.map +1 -1
- package/dist/charx.d.cts +27 -18
- package/dist/charx.d.ts +27 -18
- package/dist/charx.js +17 -38
- package/dist/charx.js.map +1 -1
- package/dist/exporter.cjs +36 -40
- package/dist/exporter.cjs.map +1 -1
- package/dist/exporter.d.cts +27 -18
- package/dist/exporter.d.ts +27 -18
- package/dist/exporter.js +36 -40
- package/dist/exporter.js.map +1 -1
- package/dist/federation.cjs +104 -36
- package/dist/federation.cjs.map +1 -1
- package/dist/federation.d.cts +62 -18
- package/dist/federation.d.ts +62 -18
- package/dist/federation.js +104 -36
- package/dist/federation.js.map +1 -1
- package/dist/index.cjs +36 -40
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +63 -42
- package/dist/index.d.ts +63 -42
- package/dist/index.js +36 -40
- package/dist/index.js.map +1 -1
- package/dist/loader.cjs +103 -17
- package/dist/loader.cjs.map +1 -1
- package/dist/loader.d.cts +56 -28
- package/dist/loader.d.ts +56 -28
- package/dist/loader.js +103 -17
- package/dist/loader.js.map +1 -1
- package/dist/lorebook.d.cts +51 -34
- package/dist/lorebook.d.ts +51 -34
- package/dist/normalizer.cjs +4 -4
- package/dist/normalizer.cjs.map +1 -1
- package/dist/normalizer.d.cts +90 -60
- package/dist/normalizer.d.ts +90 -60
- package/dist/normalizer.js +4 -4
- package/dist/normalizer.js.map +1 -1
- package/dist/png.cjs +4 -4
- package/dist/png.cjs.map +1 -1
- package/dist/png.d.cts +48 -32
- package/dist/png.d.ts +48 -32
- package/dist/png.js +4 -4
- package/dist/png.js.map +1 -1
- package/dist/schemas.cjs +9 -9
- package/dist/schemas.cjs.map +1 -1
- package/dist/schemas.d.cts +144 -96
- package/dist/schemas.d.ts +144 -96
- package/dist/schemas.js +9 -9
- package/dist/schemas.js.map +1 -1
- package/dist/voxta.cjs +23 -6
- package/dist/voxta.cjs.map +1 -1
- package/dist/voxta.d.cts +42 -28
- package/dist/voxta.d.ts +42 -28
- package/dist/voxta.js +23 -6
- package/dist/voxta.js.map +1 -1
- package/package.json +6 -6
package/dist/loader.cjs
CHANGED
|
@@ -21,6 +21,7 @@ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: tru
|
|
|
21
21
|
var loader_exports = {};
|
|
22
22
|
__export(loader_exports, {
|
|
23
23
|
computeContentHash: () => computeContentHash,
|
|
24
|
+
computeContentHashV2: () => computeContentHashV2,
|
|
24
25
|
detectFormat: () => detectFormat,
|
|
25
26
|
getContainerFormat: () => getContainerFormat,
|
|
26
27
|
mightBeCard: () => mightBeCard,
|
|
@@ -492,7 +493,7 @@ var CCv2LorebookEntrySchema = import_zod2.z.object({
|
|
|
492
493
|
content: import_zod2.z.string(),
|
|
493
494
|
enabled: import_zod2.z.boolean().default(true),
|
|
494
495
|
// Default to enabled if missing
|
|
495
|
-
insertion_order: import_zod2.z.
|
|
496
|
+
insertion_order: import_zod2.z.preprocess((v) => v ?? 0, import_zod2.z.number().int()),
|
|
496
497
|
// Optional fields - be lenient with nulls since wild data has them
|
|
497
498
|
extensions: import_zod2.z.record(import_zod2.z.unknown()).optional(),
|
|
498
499
|
case_sensitive: import_zod2.z.boolean().nullable().optional(),
|
|
@@ -503,7 +504,7 @@ var CCv2LorebookEntrySchema = import_zod2.z.object({
|
|
|
503
504
|
selective: import_zod2.z.boolean().nullable().optional(),
|
|
504
505
|
secondary_keys: import_zod2.z.array(import_zod2.z.string()).nullable().optional(),
|
|
505
506
|
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(), import_zod2.z.literal("")]).nullable().optional()
|
|
507
|
+
position: import_zod2.z.union([import_zod2.z.enum(["before_char", "after_char", "in_chat"]), import_zod2.z.number().int(), import_zod2.z.literal("")]).nullable().optional()
|
|
507
508
|
}).passthrough();
|
|
508
509
|
var CCv2CharacterBookSchema = import_zod2.z.object({
|
|
509
510
|
name: import_zod2.z.string().optional(),
|
|
@@ -557,7 +558,7 @@ var CCv3LorebookEntrySchema = import_zod3.z.object({
|
|
|
557
558
|
content: import_zod3.z.string(),
|
|
558
559
|
enabled: import_zod3.z.boolean().default(true),
|
|
559
560
|
// Default to enabled if missing
|
|
560
|
-
insertion_order: import_zod3.z.
|
|
561
|
+
insertion_order: import_zod3.z.preprocess((v) => v ?? 0, import_zod3.z.number().int()),
|
|
561
562
|
// Optional fields - be lenient with nulls since wild data has them
|
|
562
563
|
case_sensitive: import_zod3.z.boolean().nullable().optional(),
|
|
563
564
|
name: import_zod3.z.string().optional(),
|
|
@@ -567,7 +568,7 @@ var CCv3LorebookEntrySchema = import_zod3.z.object({
|
|
|
567
568
|
selective: import_zod3.z.boolean().nullable().optional(),
|
|
568
569
|
secondary_keys: import_zod3.z.array(import_zod3.z.string()).nullable().optional(),
|
|
569
570
|
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(), import_zod3.z.literal("")]).nullable().optional(),
|
|
571
|
+
position: import_zod3.z.union([import_zod3.z.enum(["before_char", "after_char", "in_chat"]), import_zod3.z.number().int(), import_zod3.z.literal("")]).nullable().optional(),
|
|
571
572
|
extensions: import_zod3.z.record(import_zod3.z.unknown()).optional(),
|
|
572
573
|
// v3 specific - also lenient with types since SillyTavern uses numbers for enums
|
|
573
574
|
automation_id: import_zod3.z.string().optional(),
|
|
@@ -8727,7 +8728,7 @@ function defaultTokenCounter(_card) {
|
|
|
8727
8728
|
total: 0
|
|
8728
8729
|
};
|
|
8729
8730
|
}
|
|
8730
|
-
function
|
|
8731
|
+
function getCanonicalContentV1(card) {
|
|
8731
8732
|
const normalized = {
|
|
8732
8733
|
name: card.data.name,
|
|
8733
8734
|
description: card.data.description || "",
|
|
@@ -8749,6 +8750,69 @@ function getCanonicalContent(card) {
|
|
|
8749
8750
|
};
|
|
8750
8751
|
return JSON.stringify(normalized, Object.keys(normalized).sort());
|
|
8751
8752
|
}
|
|
8753
|
+
function stableStringify(value) {
|
|
8754
|
+
if (value === null) return "null";
|
|
8755
|
+
switch (typeof value) {
|
|
8756
|
+
case "string":
|
|
8757
|
+
return JSON.stringify(value);
|
|
8758
|
+
case "number":
|
|
8759
|
+
return Number.isFinite(value) ? String(value) : "null";
|
|
8760
|
+
case "boolean":
|
|
8761
|
+
return value ? "true" : "false";
|
|
8762
|
+
case "bigint":
|
|
8763
|
+
return JSON.stringify(value.toString());
|
|
8764
|
+
case "undefined":
|
|
8765
|
+
case "function":
|
|
8766
|
+
case "symbol":
|
|
8767
|
+
return "null";
|
|
8768
|
+
case "object": {
|
|
8769
|
+
if (Array.isArray(value)) {
|
|
8770
|
+
const parts2 = value.map((item) => {
|
|
8771
|
+
if (item === void 0 || typeof item === "function" || typeof item === "symbol") {
|
|
8772
|
+
return "null";
|
|
8773
|
+
}
|
|
8774
|
+
return stableStringify(item);
|
|
8775
|
+
});
|
|
8776
|
+
return `[${parts2.join(",")}]`;
|
|
8777
|
+
}
|
|
8778
|
+
const obj = value;
|
|
8779
|
+
const keys = Object.keys(obj).sort();
|
|
8780
|
+
const parts = [];
|
|
8781
|
+
for (const key of keys) {
|
|
8782
|
+
const v = obj[key];
|
|
8783
|
+
if (v === void 0 || typeof v === "function" || typeof v === "symbol") {
|
|
8784
|
+
continue;
|
|
8785
|
+
}
|
|
8786
|
+
parts.push(`${JSON.stringify(key)}:${stableStringify(v)}`);
|
|
8787
|
+
}
|
|
8788
|
+
return `{${parts.join(",")}}`;
|
|
8789
|
+
}
|
|
8790
|
+
default:
|
|
8791
|
+
return "null";
|
|
8792
|
+
}
|
|
8793
|
+
}
|
|
8794
|
+
function getCanonicalContentV2(card) {
|
|
8795
|
+
const normalized = {
|
|
8796
|
+
name: card.data.name,
|
|
8797
|
+
description: card.data.description || "",
|
|
8798
|
+
personality: card.data.personality || "",
|
|
8799
|
+
scenario: card.data.scenario || "",
|
|
8800
|
+
first_mes: card.data.first_mes || "",
|
|
8801
|
+
mes_example: card.data.mes_example || "",
|
|
8802
|
+
system_prompt: card.data.system_prompt || "",
|
|
8803
|
+
post_history_instructions: card.data.post_history_instructions || "",
|
|
8804
|
+
alternate_greetings: card.data.alternate_greetings || [],
|
|
8805
|
+
character_book: card.data.character_book ? {
|
|
8806
|
+
entries: (card.data.character_book.entries || []).map((e) => ({
|
|
8807
|
+
keys: e.keys,
|
|
8808
|
+
content: e.content,
|
|
8809
|
+
enabled: e.enabled
|
|
8810
|
+
}))
|
|
8811
|
+
} : null,
|
|
8812
|
+
creator_notes: card.data.creator_notes || ""
|
|
8813
|
+
};
|
|
8814
|
+
return stableStringify(normalized);
|
|
8815
|
+
}
|
|
8752
8816
|
function isWithinTolerance(clientValue, computedValue, tolerance) {
|
|
8753
8817
|
if (clientValue === void 0) return false;
|
|
8754
8818
|
if (computedValue === 0) return clientValue === 0;
|
|
@@ -8769,15 +8833,18 @@ async function validateClientMetadata(clientMetadata, parseResult, options = {})
|
|
|
8769
8833
|
const warnings = [];
|
|
8770
8834
|
const errors = [];
|
|
8771
8835
|
const computedTokens = countTokens(card);
|
|
8772
|
-
const
|
|
8773
|
-
const
|
|
8836
|
+
const canonicalContentV1 = getCanonicalContentV1(card);
|
|
8837
|
+
const canonicalContentV2 = getCanonicalContentV2(card);
|
|
8838
|
+
const computedHashV1 = await computeHash(canonicalContentV1);
|
|
8839
|
+
const computedHashV2 = await computeHash(canonicalContentV2);
|
|
8774
8840
|
const entries = card.data.character_book?.entries || [];
|
|
8775
8841
|
const computedHasLorebook = entries.length > 0;
|
|
8776
8842
|
const computedLorebookCount = entries.length;
|
|
8777
8843
|
const authoritative = {
|
|
8778
8844
|
name: card.data.name,
|
|
8779
8845
|
tokens: computedTokens,
|
|
8780
|
-
contentHash:
|
|
8846
|
+
contentHash: computedHashV1,
|
|
8847
|
+
contentHashV2: computedHashV2,
|
|
8781
8848
|
hasLorebook: computedHasLorebook,
|
|
8782
8849
|
lorebookEntriesCount: computedLorebookCount
|
|
8783
8850
|
};
|
|
@@ -8789,21 +8856,27 @@ async function validateClientMetadata(clientMetadata, parseResult, options = {})
|
|
|
8789
8856
|
withinTolerance: false
|
|
8790
8857
|
});
|
|
8791
8858
|
}
|
|
8792
|
-
|
|
8859
|
+
const matchesV1 = clientMetadata.contentHash === computedHashV1;
|
|
8860
|
+
const matchesV2 = clientMetadata.contentHash === computedHashV2;
|
|
8861
|
+
if (!matchesV1 && !matchesV2) {
|
|
8793
8862
|
const disc = {
|
|
8794
8863
|
field: "contentHash",
|
|
8795
8864
|
clientValue: clientMetadata.contentHash,
|
|
8796
|
-
computedValue:
|
|
8865
|
+
computedValue: computedHashV1,
|
|
8797
8866
|
withinTolerance: false
|
|
8798
8867
|
};
|
|
8799
8868
|
discrepancies.push(disc);
|
|
8800
8869
|
if (allowHashMismatch) {
|
|
8801
8870
|
warnings.push(
|
|
8802
|
-
`Content hash mismatch: client=${clientMetadata.contentHash.substring(0, 8)}..., server=${
|
|
8871
|
+
`Content hash mismatch: client=${clientMetadata.contentHash.substring(0, 8)}..., server(v1)=${computedHashV1.substring(0, 8)}..., server(v2)=${computedHashV2.substring(0, 8)}...`
|
|
8803
8872
|
);
|
|
8804
8873
|
} else {
|
|
8805
8874
|
errors.push("Content hash mismatch - possible tampering or encoding difference");
|
|
8806
8875
|
}
|
|
8876
|
+
} else if (matchesV1 && !matchesV2) {
|
|
8877
|
+
warnings.push(
|
|
8878
|
+
"Client contentHash matches legacy v1 canonicalization. Prefer authoritative.contentHashV2 for new storage."
|
|
8879
|
+
);
|
|
8807
8880
|
}
|
|
8808
8881
|
const tokenFields = [
|
|
8809
8882
|
"description",
|
|
@@ -8884,7 +8957,11 @@ async function validateClientMetadata(clientMetadata, parseResult, options = {})
|
|
|
8884
8957
|
};
|
|
8885
8958
|
}
|
|
8886
8959
|
async function computeContentHash(card) {
|
|
8887
|
-
const content =
|
|
8960
|
+
const content = getCanonicalContentV1(card);
|
|
8961
|
+
return sha256Hash(content);
|
|
8962
|
+
}
|
|
8963
|
+
async function computeContentHashV2(card) {
|
|
8964
|
+
const content = getCanonicalContentV2(card);
|
|
8888
8965
|
return sha256Hash(content);
|
|
8889
8966
|
}
|
|
8890
8967
|
function validateClientMetadataSync(clientMetadata, parseResult, options) {
|
|
@@ -8900,15 +8977,18 @@ function validateClientMetadataSync(clientMetadata, parseResult, options) {
|
|
|
8900
8977
|
const warnings = [];
|
|
8901
8978
|
const errors = [];
|
|
8902
8979
|
const computedTokens = countTokens(card);
|
|
8903
|
-
const
|
|
8904
|
-
const
|
|
8980
|
+
const canonicalContentV1 = getCanonicalContentV1(card);
|
|
8981
|
+
const canonicalContentV2 = getCanonicalContentV2(card);
|
|
8982
|
+
const computedHashV1 = computeHash(canonicalContentV1);
|
|
8983
|
+
const computedHashV2 = computeHash(canonicalContentV2);
|
|
8905
8984
|
const entries = card.data.character_book?.entries || [];
|
|
8906
8985
|
const computedHasLorebook = entries.length > 0;
|
|
8907
8986
|
const computedLorebookCount = entries.length;
|
|
8908
8987
|
const authoritative = {
|
|
8909
8988
|
name: card.data.name,
|
|
8910
8989
|
tokens: computedTokens,
|
|
8911
|
-
contentHash:
|
|
8990
|
+
contentHash: computedHashV1,
|
|
8991
|
+
contentHashV2: computedHashV2,
|
|
8912
8992
|
hasLorebook: computedHasLorebook,
|
|
8913
8993
|
lorebookEntriesCount: computedLorebookCount
|
|
8914
8994
|
};
|
|
@@ -8920,11 +9000,13 @@ function validateClientMetadataSync(clientMetadata, parseResult, options) {
|
|
|
8920
9000
|
withinTolerance: false
|
|
8921
9001
|
});
|
|
8922
9002
|
}
|
|
8923
|
-
|
|
9003
|
+
const matchesV1 = clientMetadata.contentHash === computedHashV1;
|
|
9004
|
+
const matchesV2 = clientMetadata.contentHash === computedHashV2;
|
|
9005
|
+
if (!matchesV1 && !matchesV2) {
|
|
8924
9006
|
discrepancies.push({
|
|
8925
9007
|
field: "contentHash",
|
|
8926
9008
|
clientValue: clientMetadata.contentHash,
|
|
8927
|
-
computedValue:
|
|
9009
|
+
computedValue: computedHashV1,
|
|
8928
9010
|
withinTolerance: false
|
|
8929
9011
|
});
|
|
8930
9012
|
if (allowHashMismatch) {
|
|
@@ -8932,6 +9014,10 @@ function validateClientMetadataSync(clientMetadata, parseResult, options) {
|
|
|
8932
9014
|
} else {
|
|
8933
9015
|
errors.push("Content hash mismatch");
|
|
8934
9016
|
}
|
|
9017
|
+
} else if (matchesV1 && !matchesV2) {
|
|
9018
|
+
warnings.push(
|
|
9019
|
+
"Client contentHash matches legacy v1 canonicalization. Prefer authoritative.contentHashV2 for new storage."
|
|
9020
|
+
);
|
|
8935
9021
|
}
|
|
8936
9022
|
const tokenFields = [
|
|
8937
9023
|
"description",
|