docdex 0.2.59 → 0.2.60
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/CHANGELOG.md +4 -0
- package/assets/agents.md +1 -1
- package/lib/postinstall_setup.js +157 -34
- package/package.json +1 -1
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,9 @@
|
|
|
1
1
|
# Changelog
|
|
2
2
|
|
|
3
|
+
## 0.2.60
|
|
4
|
+
- Deduplicate installer-managed Docdex client config on reinstall: JSON client configs now collapse stale `docdex` entries, Codex TOML converges to one canonical Docdex entry, and packaged Docdex instruction blocks replace older Codex/Gemini/Claude prompt blocks instead of duplicating them.
|
|
5
|
+
- Update the packaged daemon dependency set to remove the vulnerable `rustls-webpki` chain that caused the nightly security audit failure.
|
|
6
|
+
|
|
3
7
|
## 0.2.58
|
|
4
8
|
- Export Docdex delegation savings in hourly mswarm telemetry packages and expose matching runtime/admin mswarm summaries for frontend visibility.
|
|
5
9
|
|
package/assets/agents.md
CHANGED
package/lib/postinstall_setup.js
CHANGED
|
@@ -666,8 +666,17 @@ function stripLegacyDocdexBodySegment(segment, body) {
|
|
|
666
666
|
const normalizedSegment = String(segment || "").replace(/\r\n/g, "\n");
|
|
667
667
|
const normalizedBody = String(body || "").replace(/\r\n/g, "\n");
|
|
668
668
|
if (!normalizedBody.trim()) return normalizedSegment;
|
|
669
|
-
|
|
670
|
-
|
|
669
|
+
let result = normalizedSegment;
|
|
670
|
+
let index = result.indexOf(normalizedBody);
|
|
671
|
+
while (index !== -1) {
|
|
672
|
+
let start = index;
|
|
673
|
+
let end = index + normalizedBody.length;
|
|
674
|
+
if (start > 0 && result[start - 1] === "\n") start -= 1;
|
|
675
|
+
if (end < result.length && result[end] === "\n") end += 1;
|
|
676
|
+
result = `${result.slice(0, start)}\n${result.slice(end)}`;
|
|
677
|
+
index = result.indexOf(normalizedBody);
|
|
678
|
+
}
|
|
679
|
+
return result.replace(/\n{3,}/g, "\n\n");
|
|
671
680
|
}
|
|
672
681
|
|
|
673
682
|
function stripLegacyDocdexBody(text, body) {
|
|
@@ -1082,6 +1091,7 @@ function upsertMcpServerJson(pathname, url, options = {}) {
|
|
|
1082
1091
|
const { value } = readJson(pathname);
|
|
1083
1092
|
if (typeof value !== "object" || value == null || Array.isArray(value)) return false;
|
|
1084
1093
|
const root = value;
|
|
1094
|
+
const before = JSON.stringify(root);
|
|
1085
1095
|
const extra =
|
|
1086
1096
|
options &&
|
|
1087
1097
|
typeof options === "object" &&
|
|
@@ -1090,9 +1100,25 @@ function upsertMcpServerJson(pathname, url, options = {}) {
|
|
|
1090
1100
|
!Array.isArray(options.extra)
|
|
1091
1101
|
? options.extra
|
|
1092
1102
|
: {};
|
|
1093
|
-
const
|
|
1094
|
-
|
|
1095
|
-
|
|
1103
|
+
const isPlainObject = (entry) =>
|
|
1104
|
+
typeof entry === "object" && entry != null && !Array.isArray(entry);
|
|
1105
|
+
const removeDocdexFromSection = (key) => {
|
|
1106
|
+
const section = root[key];
|
|
1107
|
+
if (Array.isArray(section)) {
|
|
1108
|
+
const filtered = section.filter((entry) => !(entry && entry.name === "docdex"));
|
|
1109
|
+
if (filtered.length !== section.length) {
|
|
1110
|
+
root[key] = filtered;
|
|
1111
|
+
}
|
|
1112
|
+
return;
|
|
1113
|
+
}
|
|
1114
|
+
if (!isPlainObject(section) || !Object.prototype.hasOwnProperty.call(section, "docdex")) {
|
|
1115
|
+
return;
|
|
1116
|
+
}
|
|
1117
|
+
delete section.docdex;
|
|
1118
|
+
if (Object.keys(section).length === 0) {
|
|
1119
|
+
delete root[key];
|
|
1120
|
+
}
|
|
1121
|
+
};
|
|
1096
1122
|
const pickSection = () => {
|
|
1097
1123
|
if (root.mcpServers && typeof root.mcpServers === "object" && !Array.isArray(root.mcpServers)) {
|
|
1098
1124
|
return { key: "mcpServers", section: root.mcpServers };
|
|
@@ -1103,29 +1129,39 @@ function upsertMcpServerJson(pathname, url, options = {}) {
|
|
|
1103
1129
|
return null;
|
|
1104
1130
|
};
|
|
1105
1131
|
if (Array.isArray(root.mcpServers)) {
|
|
1106
|
-
const
|
|
1107
|
-
|
|
1108
|
-
|
|
1109
|
-
|
|
1110
|
-
|
|
1111
|
-
|
|
1112
|
-
|
|
1132
|
+
const nextEntries = [];
|
|
1133
|
+
let insertIndex = -1;
|
|
1134
|
+
let current = {};
|
|
1135
|
+
for (const entry of root.mcpServers) {
|
|
1136
|
+
if (entry && entry.name === "docdex") {
|
|
1137
|
+
if (insertIndex === -1) {
|
|
1138
|
+
insertIndex = nextEntries.length;
|
|
1139
|
+
current = isPlainObject(entry) ? { ...entry } : {};
|
|
1140
|
+
}
|
|
1141
|
+
continue;
|
|
1142
|
+
}
|
|
1143
|
+
nextEntries.push(entry);
|
|
1113
1144
|
}
|
|
1114
|
-
|
|
1115
|
-
|
|
1116
|
-
|
|
1117
|
-
|
|
1118
|
-
|
|
1119
|
-
|
|
1120
|
-
|
|
1121
|
-
|
|
1145
|
+
const nextEntry = { ...current, ...extra, url, name: "docdex" };
|
|
1146
|
+
if (insertIndex === -1) {
|
|
1147
|
+
nextEntries.push(nextEntry);
|
|
1148
|
+
} else {
|
|
1149
|
+
nextEntries.splice(insertIndex, 0, nextEntry);
|
|
1150
|
+
}
|
|
1151
|
+
root.mcpServers = nextEntries;
|
|
1152
|
+
removeDocdexFromSection("mcp_servers");
|
|
1153
|
+
} else {
|
|
1154
|
+
const picked = pickSection();
|
|
1155
|
+
const sectionKey = picked ? picked.key : "mcpServers";
|
|
1156
|
+
if (!picked) {
|
|
1157
|
+
root[sectionKey] = {};
|
|
1158
|
+
}
|
|
1159
|
+
const section = root[sectionKey];
|
|
1160
|
+
const current = isPlainObject(section.docdex) ? section.docdex : {};
|
|
1161
|
+
section.docdex = { ...current, ...extra, url };
|
|
1162
|
+
removeDocdexFromSection(sectionKey === "mcpServers" ? "mcp_servers" : "mcpServers");
|
|
1122
1163
|
}
|
|
1123
|
-
|
|
1124
|
-
const current = section.docdex;
|
|
1125
|
-
if (current && current.url === url && matchesExtras(current)) return false;
|
|
1126
|
-
const base =
|
|
1127
|
-
current && typeof current === "object" && !Array.isArray(current) ? current : {};
|
|
1128
|
-
section.docdex = { ...base, ...extra, url };
|
|
1164
|
+
if (JSON.stringify(root) === before) return false;
|
|
1129
1165
|
writeJson(pathname, root);
|
|
1130
1166
|
return true;
|
|
1131
1167
|
}
|
|
@@ -1273,19 +1309,25 @@ function upsertCodexConfig(pathname, url) {
|
|
|
1273
1309
|
end += 1;
|
|
1274
1310
|
}
|
|
1275
1311
|
let updated = false;
|
|
1276
|
-
|
|
1312
|
+
const docdexLines = [];
|
|
1277
1313
|
for (let i = start + 1; i < end; i += 1) {
|
|
1278
1314
|
if (/^\s*docdex\s*=/.test(lines[i])) {
|
|
1279
|
-
|
|
1280
|
-
break;
|
|
1315
|
+
docdexLines.push(i);
|
|
1281
1316
|
}
|
|
1282
1317
|
}
|
|
1283
|
-
if (
|
|
1318
|
+
if (docdexLines.length === 0) {
|
|
1284
1319
|
lines.splice(end, 0, entryLine);
|
|
1285
1320
|
updated = true;
|
|
1286
|
-
} else
|
|
1287
|
-
|
|
1288
|
-
|
|
1321
|
+
} else {
|
|
1322
|
+
const [firstDocdexLine, ...extraDocdexLines] = docdexLines;
|
|
1323
|
+
if (lines[firstDocdexLine].trim() !== entryLine) {
|
|
1324
|
+
lines[firstDocdexLine] = entryLine;
|
|
1325
|
+
updated = true;
|
|
1326
|
+
}
|
|
1327
|
+
for (let i = extraDocdexLines.length - 1; i >= 0; i -= 1) {
|
|
1328
|
+
lines.splice(extraDocdexLines[i], 1);
|
|
1329
|
+
updated = true;
|
|
1330
|
+
}
|
|
1289
1331
|
}
|
|
1290
1332
|
return { contents: lines.join("\n"), updated };
|
|
1291
1333
|
};
|
|
@@ -1336,6 +1378,71 @@ function upsertCodexConfig(pathname, url) {
|
|
|
1336
1378
|
return { contents: output.join("\n"), updated };
|
|
1337
1379
|
};
|
|
1338
1380
|
|
|
1381
|
+
const removeRootDocdexEntries = (text) => {
|
|
1382
|
+
const lines = text.split(/\r?\n/);
|
|
1383
|
+
const output = [];
|
|
1384
|
+
let inRootSection = false;
|
|
1385
|
+
let updated = false;
|
|
1386
|
+
for (const line of lines) {
|
|
1387
|
+
const section = line.match(/^\s*\[([^\]]+)\]\s*$/);
|
|
1388
|
+
if (section) {
|
|
1389
|
+
inRootSection = section[1].trim() === "mcp_servers";
|
|
1390
|
+
output.push(line);
|
|
1391
|
+
continue;
|
|
1392
|
+
}
|
|
1393
|
+
if (inRootSection && /^\s*docdex\s*=/.test(line)) {
|
|
1394
|
+
updated = true;
|
|
1395
|
+
continue;
|
|
1396
|
+
}
|
|
1397
|
+
output.push(line);
|
|
1398
|
+
}
|
|
1399
|
+
return { contents: output.join("\n"), updated };
|
|
1400
|
+
};
|
|
1401
|
+
|
|
1402
|
+
const countRootDocdexEntries = (text) => {
|
|
1403
|
+
const lines = text.split(/\r?\n/);
|
|
1404
|
+
let inRootSection = false;
|
|
1405
|
+
let count = 0;
|
|
1406
|
+
for (const line of lines) {
|
|
1407
|
+
const section = line.match(/^\s*\[([^\]]+)\]\s*$/);
|
|
1408
|
+
if (section) {
|
|
1409
|
+
inRootSection = section[1].trim() === "mcp_servers";
|
|
1410
|
+
continue;
|
|
1411
|
+
}
|
|
1412
|
+
if (inRootSection && /^\s*docdex\s*=/.test(line)) {
|
|
1413
|
+
count += 1;
|
|
1414
|
+
}
|
|
1415
|
+
}
|
|
1416
|
+
return count;
|
|
1417
|
+
};
|
|
1418
|
+
|
|
1419
|
+
const removeNestedDocdexSections = (text) => {
|
|
1420
|
+
const lines = text.split(/\r?\n/);
|
|
1421
|
+
const output = [];
|
|
1422
|
+
let skipping = false;
|
|
1423
|
+
let updated = false;
|
|
1424
|
+
for (const line of lines) {
|
|
1425
|
+
const isSection = /^\s*\[.+\]\s*$/.test(line);
|
|
1426
|
+
if (skipping) {
|
|
1427
|
+
if (isSection) {
|
|
1428
|
+
skipping = false;
|
|
1429
|
+
} else {
|
|
1430
|
+
continue;
|
|
1431
|
+
}
|
|
1432
|
+
}
|
|
1433
|
+
if (/^\s*\[mcp_servers\.docdex\]\s*$/.test(line)) {
|
|
1434
|
+
skipping = true;
|
|
1435
|
+
updated = true;
|
|
1436
|
+
continue;
|
|
1437
|
+
}
|
|
1438
|
+
output.push(line);
|
|
1439
|
+
}
|
|
1440
|
+
return { contents: output.join("\n"), updated };
|
|
1441
|
+
};
|
|
1442
|
+
|
|
1443
|
+
const countNestedDocdexSections = (text) =>
|
|
1444
|
+
(text.match(/^\s*\[mcp_servers\.docdex\]\s*$/gm) || []).length;
|
|
1445
|
+
|
|
1339
1446
|
let contents = "";
|
|
1340
1447
|
if (fs.existsSync(pathname)) {
|
|
1341
1448
|
contents = fs.readFileSync(pathname, "utf8");
|
|
@@ -1351,7 +1458,23 @@ function upsertCodexConfig(pathname, url) {
|
|
|
1351
1458
|
contents = cleaned.contents;
|
|
1352
1459
|
updated = updated || cleaned.updated;
|
|
1353
1460
|
|
|
1354
|
-
|
|
1461
|
+
const preferNested = hasNestedMcpServers(contents);
|
|
1462
|
+
const rootDocdexCount = countRootDocdexEntries(contents);
|
|
1463
|
+
const nestedDocdexCount = countNestedDocdexSections(contents);
|
|
1464
|
+
|
|
1465
|
+
if (preferNested && rootDocdexCount > 0) {
|
|
1466
|
+
const prunedRoot = removeRootDocdexEntries(contents);
|
|
1467
|
+
contents = prunedRoot.contents;
|
|
1468
|
+
updated = updated || prunedRoot.updated;
|
|
1469
|
+
}
|
|
1470
|
+
|
|
1471
|
+
if ((!preferNested && nestedDocdexCount > 0) || (preferNested && nestedDocdexCount > 1)) {
|
|
1472
|
+
const prunedNested = removeNestedDocdexSections(contents);
|
|
1473
|
+
contents = prunedNested.contents;
|
|
1474
|
+
updated = updated || prunedNested.updated;
|
|
1475
|
+
}
|
|
1476
|
+
|
|
1477
|
+
if (preferNested) {
|
|
1355
1478
|
const nested = upsertDocdexNested(contents, url);
|
|
1356
1479
|
contents = nested.contents;
|
|
1357
1480
|
updated = updated || nested.updated;
|