log-llm-config-staging 1.3.92 → 1.3.93
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.
|
@@ -25,6 +25,27 @@ function querySqlite(dbPath, key) {
|
|
|
25
25
|
stdio: ['pipe', 'pipe', 'pipe'],
|
|
26
26
|
}).trim();
|
|
27
27
|
}
|
|
28
|
+
/**
|
|
29
|
+
* Cursor keeps live agent settings (e.g. yoloCommandAllowlist) on nested composerState inside
|
|
30
|
+
* the reactive blob while the legacy ItemTable `composerState` row is often stale/partial.
|
|
31
|
+
* Merge nested fields so compliance/autofix match policy scans on uploaded reactive data.
|
|
32
|
+
*/
|
|
33
|
+
function mergeLegacyComposerStateWithReactiveNested(dbPath, reactiveKey, legacyComposerState) {
|
|
34
|
+
try {
|
|
35
|
+
const reactive = querySqlite(dbPath, reactiveKey);
|
|
36
|
+
if (!reactive)
|
|
37
|
+
return legacyComposerState;
|
|
38
|
+
const root = JSON.parse(reactive);
|
|
39
|
+
const nested = root.composerState;
|
|
40
|
+
if (nested === null || typeof nested !== 'object' || Array.isArray(nested)) {
|
|
41
|
+
return legacyComposerState;
|
|
42
|
+
}
|
|
43
|
+
return { ...legacyComposerState, ...nested };
|
|
44
|
+
}
|
|
45
|
+
catch {
|
|
46
|
+
return legacyComposerState;
|
|
47
|
+
}
|
|
48
|
+
}
|
|
28
49
|
/**
|
|
29
50
|
* Fallback if the API omits vscdb_composer_contract (older server): derive from vscdb_read_queries.
|
|
30
51
|
*/
|
|
@@ -113,6 +134,10 @@ export function readVscdbItemTableJson(dbPath, itemKey) {
|
|
|
113
134
|
}
|
|
114
135
|
const parsed = JSON.parse(raw);
|
|
115
136
|
if (parsed !== null && typeof parsed === 'object' && !Array.isArray(parsed)) {
|
|
137
|
+
if (itemKey === 'composerState' && reactiveKey) {
|
|
138
|
+
const merged = mergeLegacyComposerStateWithReactiveNested(dbPath, reactiveKey, parsed);
|
|
139
|
+
return { [itemKey]: merged };
|
|
140
|
+
}
|
|
116
141
|
return { [itemKey]: parsed };
|
|
117
142
|
}
|
|
118
143
|
// Bare JSON arrays (e.g. cursor/disabledMcpServers) — wrap under itemKey so ops-based
|
|
@@ -645,6 +645,35 @@ function mergeSqliteOpIntoJson(currentJson, sqliteOp) {
|
|
|
645
645
|
currentJson[key] = arr;
|
|
646
646
|
return;
|
|
647
647
|
}
|
|
648
|
+
if (sqliteOp.array_remove?.length) {
|
|
649
|
+
const jp = (sqliteOp.json_path ?? '').trim();
|
|
650
|
+
const removeSet = new Set(sqliteOp.array_remove.map((v) => String(v)));
|
|
651
|
+
if (!jp) {
|
|
652
|
+
const key = sqliteOp.target_key;
|
|
653
|
+
const existing = currentJson[key];
|
|
654
|
+
const arr = Array.isArray(existing) ? [...existing] : [];
|
|
655
|
+
currentJson[key] = arr.filter((x) => !removeSet.has(String(x)));
|
|
656
|
+
return;
|
|
657
|
+
}
|
|
658
|
+
const parts = jp.split('.').filter(Boolean);
|
|
659
|
+
if (parts.length === 0)
|
|
660
|
+
return;
|
|
661
|
+
let node = currentJson;
|
|
662
|
+
for (const p of parts.slice(0, -1)) {
|
|
663
|
+
if (node == null || typeof node !== 'object' || Array.isArray(node))
|
|
664
|
+
return;
|
|
665
|
+
node = node[p];
|
|
666
|
+
}
|
|
667
|
+
if (node == null || typeof node !== 'object' || Array.isArray(node))
|
|
668
|
+
return;
|
|
669
|
+
const container = node;
|
|
670
|
+
const arrayKey = parts[parts.length - 1];
|
|
671
|
+
const existing = container[arrayKey];
|
|
672
|
+
if (!Array.isArray(existing))
|
|
673
|
+
return;
|
|
674
|
+
container[arrayKey] = existing.filter((x) => !removeSet.has(String(x)));
|
|
675
|
+
return;
|
|
676
|
+
}
|
|
648
677
|
const where = sqliteOp.array_item_where;
|
|
649
678
|
const jp = sqliteOp.json_path ?? '';
|
|
650
679
|
if (where && typeof where === 'object' && Object.keys(where).length > 0 && jp) {
|