pi-cache-optimizer 2.6.9 → 2.6.10
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/index.ts +50 -15
- package/package.json +1 -1
package/index.ts
CHANGED
|
@@ -4833,6 +4833,19 @@ function composeMissingEntryInsertion(
|
|
|
4833
4833
|
modelId: string,
|
|
4834
4834
|
compatKeys: Record<string, unknown>,
|
|
4835
4835
|
): { modifiedText: string; placementLabel: string } {
|
|
4836
|
+
// Comments preserve length when stripped (`stripJsoncComments` replaces
|
|
4837
|
+
// comment bytes 1-for-1 with spaces), so offsets derived from the
|
|
4838
|
+
// comment-stripped text map cleanly back to the original. However,
|
|
4839
|
+
// `lastIndexOf("{", pos)` / `lastIndexOf("[", pos)` must NOT be run
|
|
4840
|
+
// against the raw original: a comment like `// add [more] here with a {
|
|
4841
|
+
// brace` would surface `[` / `{` bytes that have no structural meaning,
|
|
4842
|
+
// contaminating the `hasExisting`/`hasExistingElements` decision below
|
|
4843
|
+
// and producing a stray leading comma. Run the structural searches
|
|
4844
|
+
// against the comment-stripped version; keep the indentation lookups
|
|
4845
|
+
// (which only care about newlines + leading whitespace) on the
|
|
4846
|
+
// original since comments never contain forward-scan-relevant bytes.
|
|
4847
|
+
const cleanText = stripJsoncComments(originalText);
|
|
4848
|
+
|
|
4836
4849
|
// Resolve a sensible indentation step from an arbitrary byte offset in
|
|
4837
4850
|
// the original file.
|
|
4838
4851
|
const indentUnitAt = (offset: number): string => {
|
|
@@ -4867,9 +4880,11 @@ function composeMissingEntryInsertion(
|
|
|
4867
4880
|
const inner1 = inner0 + unit; // indent of compat keys inside the model
|
|
4868
4881
|
const inner2 = inner1 + unit; // indent of compat values
|
|
4869
4882
|
|
|
4870
|
-
// Determine whether the array is empty (need to skip the leading
|
|
4871
|
-
|
|
4872
|
-
|
|
4883
|
+
// Determine whether the array is empty (need to skip the leading comma).
|
|
4884
|
+
// Search for the models `[` on the comment-stripped text so a `[` inside
|
|
4885
|
+
// a comment cannot be mistaken for the array opener.
|
|
4886
|
+
const arrayInterior = cleanText.slice(
|
|
4887
|
+
cleanText.lastIndexOf("[", diagnosis.modelsEnd) + 1,
|
|
4873
4888
|
diagnosis.modelsEnd,
|
|
4874
4889
|
).trim();
|
|
4875
4890
|
const hasExistingElements = arrayInterior.length > 0;
|
|
@@ -4903,8 +4918,10 @@ function composeMissingEntryInsertion(
|
|
|
4903
4918
|
const inner3 = inner2 + unit;
|
|
4904
4919
|
|
|
4905
4920
|
const compatBlock = formatCompactCompat(inner3);
|
|
4906
|
-
|
|
4907
|
-
|
|
4921
|
+
// Search for the providers `{` on the comment-stripped text so a `{`
|
|
4922
|
+
// inside a comment cannot be mistaken for the providers object opener.
|
|
4923
|
+
const providersInterior = cleanText.slice(
|
|
4924
|
+
cleanText.lastIndexOf("{", diagnosis.providersEnd) + 1,
|
|
4908
4925
|
diagnosis.providersEnd,
|
|
4909
4926
|
).trim();
|
|
4910
4927
|
const hasExisting = providersInterior.length > 0;
|
|
@@ -5279,6 +5296,7 @@ function selfCheckFix(
|
|
|
5279
5296
|
providerLabel: string,
|
|
5280
5297
|
modelId: string,
|
|
5281
5298
|
compatKeys: Record<string, unknown>,
|
|
5299
|
+
placement: "provider" | "model" = "model",
|
|
5282
5300
|
): string | null {
|
|
5283
5301
|
try {
|
|
5284
5302
|
// Step 1: Parse both versions as JSONC (comments + trailing commas allowed).
|
|
@@ -5371,7 +5389,18 @@ function selfCheckFix(
|
|
|
5371
5389
|
} else {
|
|
5372
5390
|
const origCompat = origObj[key] as Record<string, unknown>;
|
|
5373
5391
|
const modCompat = modObj[key] as Record<string, unknown>;
|
|
5374
|
-
|
|
5392
|
+
// Only the compat object at the level ACTUALLY edited may have
|
|
5393
|
+
// its values repaired by this fix. The un-edited level must
|
|
5394
|
+
// remain byte/structure-equivalent, so its same-name keys stay
|
|
5395
|
+
// under full validation. Using a disjunction OR (provider ||
|
|
5396
|
+
// target) here would silently skip validation at the un-edited
|
|
5397
|
+
// level, masking corruption (e.g. a buggy editor accidentally
|
|
5398
|
+
// breaking provider.compat.sendSessionAffinityHeaders while
|
|
5399
|
+
// the fix was a model-level repair). Track placement — only
|
|
5400
|
+
// the placement-resolved object's own compat may be exempt.
|
|
5401
|
+
const mayRepairThisCompat =
|
|
5402
|
+
(placement === "provider" && origObj === origProvider) ||
|
|
5403
|
+
(placement === "model" && origObj === origTargetModelRecord);
|
|
5375
5404
|
for (const ck of Object.keys(origCompat)) {
|
|
5376
5405
|
if (!(ck in modCompat)) return false;
|
|
5377
5406
|
// The fix may repair an existing wrong compat value (for example
|
|
@@ -5393,12 +5422,15 @@ function selfCheckFix(
|
|
|
5393
5422
|
return "Modified file: original structure was altered (data loss detected)";
|
|
5394
5423
|
}
|
|
5395
5424
|
|
|
5396
|
-
//
|
|
5397
|
-
|
|
5398
|
-
|
|
5399
|
-
|
|
5425
|
+
// Note: we intentionally do NOT enforce `modified.length >= original.length`.
|
|
5426
|
+
// The surgical editor may replace an existing compat value with a shorter one
|
|
5427
|
+
// (e.g. `false` -> `true`), which legitimately shrinks the file by a byte.
|
|
5428
|
+
// Real data loss / truncation is already caught by Step 7's isSubset
|
|
5429
|
+
// (every original key still present) and Step 8's root-bracket integrity
|
|
5430
|
+
// check below — a surviving length heuristic would false-positive on every
|
|
5431
|
+
// such value repair. (Tracked: the mofas glm-5.2 self-check failure path.)
|
|
5400
5432
|
|
|
5401
|
-
// Step
|
|
5433
|
+
// Step 8: Validate root bracket integrity with the same string/comment-aware
|
|
5402
5434
|
// scanner used for edits. Do not count raw braces: comments or strings may
|
|
5403
5435
|
// legitimately contain unmatched `{` / `}` bytes.
|
|
5404
5436
|
const modifiedClean = stripJsoncComments(modified);
|
|
@@ -5673,6 +5705,9 @@ export const __internals_for_tests = {
|
|
|
5673
5705
|
locateModelInJsonc,
|
|
5674
5706
|
composeFixInsertion,
|
|
5675
5707
|
selfCheckFix,
|
|
5708
|
+
analyzeModelsJsonForMissingEntry,
|
|
5709
|
+
composeMissingEntryInsertion,
|
|
5710
|
+
selfCheckMissingEntryInsertion,
|
|
5676
5711
|
decideFixPlacement,
|
|
5677
5712
|
chooseFixPlacement,
|
|
5678
5713
|
findExistingCompatKeysInJsonc,
|
|
@@ -6692,7 +6727,7 @@ export default function (pi: ExtensionAPI) {
|
|
|
6692
6727
|
const modifiedText = composeFixInsertion(originalText, location, suggestion.compatKeys, decision.placement);
|
|
6693
6728
|
|
|
6694
6729
|
// Self-check
|
|
6695
|
-
const checkError = selfCheckFix(originalText, modifiedText, suggestion.providerLabel, suggestion.modelId, suggestion.compatKeys);
|
|
6730
|
+
const checkError = selfCheckFix(originalText, modifiedText, suggestion.providerLabel, suggestion.modelId, suggestion.compatKeys, decision.placement);
|
|
6696
6731
|
if (checkError !== null) {
|
|
6697
6732
|
cmdCtx.ui.notify(
|
|
6698
6733
|
`❌ Self-check failed before write: ${checkError}\n` +
|
|
@@ -6761,7 +6796,7 @@ export default function (pi: ExtensionAPI) {
|
|
|
6761
6796
|
|
|
6762
6797
|
// Post-write self-check (read back)
|
|
6763
6798
|
const writtenText = await readFile(MODELS_JSON_PATH, "utf8");
|
|
6764
|
-
const postCheckError = selfCheckFix(originalText, writtenText, suggestion.providerLabel, suggestion.modelId, suggestion.compatKeys);
|
|
6799
|
+
const postCheckError = selfCheckFix(originalText, writtenText, suggestion.providerLabel, suggestion.modelId, suggestion.compatKeys, decision.placement);
|
|
6765
6800
|
if (postCheckError !== null) {
|
|
6766
6801
|
// Restore from backup
|
|
6767
6802
|
await copyFile(backupPath, MODELS_JSON_PATH);
|
|
@@ -6890,7 +6925,7 @@ export default function (pi: ExtensionAPI) {
|
|
|
6890
6925
|
|
|
6891
6926
|
const menuDecision = chooseFixPlacement(originalText, location, suggestion.compatKeys, suggestion.providerLabel);
|
|
6892
6927
|
const modifiedText = composeFixInsertion(originalText, location, suggestion.compatKeys, menuDecision.placement);
|
|
6893
|
-
const checkError = selfCheckFix(originalText, modifiedText, suggestion.providerLabel, suggestion.modelId, suggestion.compatKeys);
|
|
6928
|
+
const checkError = selfCheckFix(originalText, modifiedText, suggestion.providerLabel, suggestion.modelId, suggestion.compatKeys, menuDecision.placement);
|
|
6894
6929
|
if (checkError !== null) {
|
|
6895
6930
|
cmdCtx.ui.notify(`❌ Self-check failed: ${checkError}\nNo changes made.`, "error");
|
|
6896
6931
|
return;
|
|
@@ -6936,7 +6971,7 @@ export default function (pi: ExtensionAPI) {
|
|
|
6936
6971
|
await rename(tempPath, MODELS_JSON_PATH);
|
|
6937
6972
|
|
|
6938
6973
|
const writtenText = await readFile(MODELS_JSON_PATH, "utf8");
|
|
6939
|
-
const postCheck = selfCheckFix(originalText, writtenText, suggestion.providerLabel, suggestion.modelId, suggestion.compatKeys);
|
|
6974
|
+
const postCheck = selfCheckFix(originalText, writtenText, suggestion.providerLabel, suggestion.modelId, suggestion.compatKeys, menuDecision.placement);
|
|
6940
6975
|
if (postCheck !== null) {
|
|
6941
6976
|
await copyFile(backupPath, MODELS_JSON_PATH);
|
|
6942
6977
|
cmdCtx.ui.notify(`❌ Post-write check failed: ${postCheck}\nBackup restored.`, "error");
|
package/package.json
CHANGED