docdex 0.2.59 → 0.2.61
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 +9 -0
- package/assets/agents.md +1 -1
- package/lib/postinstall_setup.js +238 -49
- package/package.json +1 -1
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,14 @@
|
|
|
1
1
|
# Changelog
|
|
2
2
|
|
|
3
|
+
## 0.2.61
|
|
4
|
+
- Add the optional personal-preferences memory subsystem with local capture, background digestion, and packaged HTTP/CLI/MCP controls for status, search, processing, export, redaction, deletion, and purge flows.
|
|
5
|
+
- Align the packaged personal-preferences surface with the top-level `[personal_preferences]` config, richer lineage/materialization, review and retention controls, bounded chat-context injection, and supported-client transcript scanning.
|
|
6
|
+
- Harden installer-managed client config rewrites so whitespace-padded Docdex keys and section names are normalized instead of duplicated on reinstall.
|
|
7
|
+
|
|
8
|
+
## 0.2.60
|
|
9
|
+
- 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.
|
|
10
|
+
- Update the packaged daemon dependency set to remove the vulnerable `rustls-webpki` chain that caused the nightly security audit failure.
|
|
11
|
+
|
|
3
12
|
## 0.2.58
|
|
4
13
|
- Export Docdex delegation savings in hourly mswarm telemetry packages and expose matching runtime/admin mswarm summaries for frontend visibility.
|
|
5
14
|
|
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,44 @@ 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 normalizeManagedServerName = (value) =>
|
|
1106
|
+
typeof value === "string" ? value.trim().toLowerCase() : null;
|
|
1107
|
+
const collectDocdexSectionEntry = (section) => {
|
|
1108
|
+
if (!isPlainObject(section)) return {};
|
|
1109
|
+
for (const [key, value] of Object.entries(section)) {
|
|
1110
|
+
if (normalizeManagedServerName(key) === "docdex" && isPlainObject(value)) {
|
|
1111
|
+
return { ...value };
|
|
1112
|
+
}
|
|
1113
|
+
}
|
|
1114
|
+
return {};
|
|
1115
|
+
};
|
|
1116
|
+
const removeDocdexFromSection = (key) => {
|
|
1117
|
+
const section = root[key];
|
|
1118
|
+
if (Array.isArray(section)) {
|
|
1119
|
+
const filtered = section.filter(
|
|
1120
|
+
(entry) => normalizeManagedServerName(entry?.name) !== "docdex"
|
|
1121
|
+
);
|
|
1122
|
+
if (filtered.length !== section.length) {
|
|
1123
|
+
root[key] = filtered;
|
|
1124
|
+
}
|
|
1125
|
+
return;
|
|
1126
|
+
}
|
|
1127
|
+
if (!isPlainObject(section)) {
|
|
1128
|
+
return;
|
|
1129
|
+
}
|
|
1130
|
+
let removed = false;
|
|
1131
|
+
for (const configKey of Object.keys(section)) {
|
|
1132
|
+
if (normalizeManagedServerName(configKey) === "docdex") {
|
|
1133
|
+
delete section[configKey];
|
|
1134
|
+
removed = true;
|
|
1135
|
+
}
|
|
1136
|
+
}
|
|
1137
|
+
if (removed && Object.keys(section).length === 0) {
|
|
1138
|
+
delete root[key];
|
|
1139
|
+
}
|
|
1140
|
+
};
|
|
1096
1141
|
const pickSection = () => {
|
|
1097
1142
|
if (root.mcpServers && typeof root.mcpServers === "object" && !Array.isArray(root.mcpServers)) {
|
|
1098
1143
|
return { key: "mcpServers", section: root.mcpServers };
|
|
@@ -1103,29 +1148,42 @@ function upsertMcpServerJson(pathname, url, options = {}) {
|
|
|
1103
1148
|
return null;
|
|
1104
1149
|
};
|
|
1105
1150
|
if (Array.isArray(root.mcpServers)) {
|
|
1106
|
-
const
|
|
1107
|
-
|
|
1108
|
-
|
|
1109
|
-
|
|
1110
|
-
|
|
1111
|
-
|
|
1112
|
-
|
|
1151
|
+
const nextEntries = [];
|
|
1152
|
+
let insertIndex = -1;
|
|
1153
|
+
let current = {};
|
|
1154
|
+
for (const entry of root.mcpServers) {
|
|
1155
|
+
if (normalizeManagedServerName(entry?.name) === "docdex") {
|
|
1156
|
+
if (insertIndex === -1) {
|
|
1157
|
+
insertIndex = nextEntries.length;
|
|
1158
|
+
current = isPlainObject(entry) ? { ...entry } : {};
|
|
1159
|
+
}
|
|
1160
|
+
continue;
|
|
1161
|
+
}
|
|
1162
|
+
nextEntries.push(entry);
|
|
1113
1163
|
}
|
|
1114
|
-
|
|
1115
|
-
|
|
1116
|
-
|
|
1117
|
-
|
|
1118
|
-
|
|
1119
|
-
|
|
1120
|
-
|
|
1121
|
-
|
|
1164
|
+
const nextEntry = { ...current, ...extra, url, name: "docdex" };
|
|
1165
|
+
if (insertIndex === -1) {
|
|
1166
|
+
nextEntries.push(nextEntry);
|
|
1167
|
+
} else {
|
|
1168
|
+
nextEntries.splice(insertIndex, 0, nextEntry);
|
|
1169
|
+
}
|
|
1170
|
+
root.mcpServers = nextEntries;
|
|
1171
|
+
removeDocdexFromSection("mcp_servers");
|
|
1172
|
+
} else {
|
|
1173
|
+
const picked = pickSection();
|
|
1174
|
+
const sectionKey = picked ? picked.key : "mcpServers";
|
|
1175
|
+
if (!picked) {
|
|
1176
|
+
root[sectionKey] = {};
|
|
1177
|
+
}
|
|
1178
|
+
const current = collectDocdexSectionEntry(root[sectionKey]);
|
|
1179
|
+
removeDocdexFromSection(sectionKey);
|
|
1180
|
+
if (!root[sectionKey] || !isPlainObject(root[sectionKey])) {
|
|
1181
|
+
root[sectionKey] = {};
|
|
1182
|
+
}
|
|
1183
|
+
root[sectionKey].docdex = { ...current, ...extra, url };
|
|
1184
|
+
removeDocdexFromSection(sectionKey === "mcpServers" ? "mcp_servers" : "mcpServers");
|
|
1122
1185
|
}
|
|
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 };
|
|
1186
|
+
if (JSON.stringify(root) === before) return false;
|
|
1129
1187
|
writeJson(pathname, root);
|
|
1130
1188
|
return true;
|
|
1131
1189
|
}
|
|
@@ -1137,7 +1195,15 @@ function upsertZedConfig(pathname, url) {
|
|
|
1137
1195
|
if (!root.experimental_mcp_servers || typeof root.experimental_mcp_servers !== "object" || Array.isArray(root.experimental_mcp_servers)) {
|
|
1138
1196
|
root.experimental_mcp_servers = {};
|
|
1139
1197
|
}
|
|
1140
|
-
const
|
|
1198
|
+
const normalizeManagedServerName = (value) =>
|
|
1199
|
+
typeof value === "string" ? value.trim().toLowerCase() : null;
|
|
1200
|
+
let current = root.experimental_mcp_servers.docdex;
|
|
1201
|
+
for (const key of Object.keys(root.experimental_mcp_servers)) {
|
|
1202
|
+
if (normalizeManagedServerName(key) === "docdex" && key !== "docdex") {
|
|
1203
|
+
if (current == null) current = root.experimental_mcp_servers[key];
|
|
1204
|
+
delete root.experimental_mcp_servers[key];
|
|
1205
|
+
}
|
|
1206
|
+
}
|
|
1141
1207
|
if (current && current.url === url) return false;
|
|
1142
1208
|
root.experimental_mcp_servers.docdex = { url };
|
|
1143
1209
|
writeJson(pathname, root);
|
|
@@ -1146,16 +1212,52 @@ function upsertZedConfig(pathname, url) {
|
|
|
1146
1212
|
|
|
1147
1213
|
function upsertCodexConfig(pathname, url) {
|
|
1148
1214
|
const codexTimeoutSec = 300;
|
|
1149
|
-
const hasSection = (contents, section) =>
|
|
1150
|
-
new RegExp(`^\\s*\\[${section}\\]\\s*$`, "m").test(contents);
|
|
1151
|
-
const hasNestedMcpServers = (contents) =>
|
|
1152
|
-
/^\s*\[mcp_servers\.[^\]]+\]\s*$/m.test(contents);
|
|
1153
1215
|
const legacyInstructionPath = "~/.docdex/agents.md";
|
|
1154
1216
|
const parseTomlString = (value) => {
|
|
1155
1217
|
const trimmed = value.trim();
|
|
1156
1218
|
const quoted = trimmed.match(/^"(.*)"$/) || trimmed.match(/^'(.*)'$/);
|
|
1157
1219
|
return quoted ? quoted[1] : trimmed;
|
|
1158
1220
|
};
|
|
1221
|
+
const normalizeTomlKeyPart = (value) => parseTomlString(value).trim();
|
|
1222
|
+
const parseTomlHeaderParts = (line) => {
|
|
1223
|
+
const match = line.match(/^\s*\[([^\]]+)\]\s*$/);
|
|
1224
|
+
if (!match) return null;
|
|
1225
|
+
return match[1].split(".").map(normalizeTomlKeyPart).filter((part) => part.length > 0);
|
|
1226
|
+
};
|
|
1227
|
+
const hasSection = (contents, section) => {
|
|
1228
|
+
const expectedParts = section.split(".").map(normalizeTomlKeyPart);
|
|
1229
|
+
return contents
|
|
1230
|
+
.split(/\r?\n/)
|
|
1231
|
+
.some((line) => {
|
|
1232
|
+
const parts = parseTomlHeaderParts(line);
|
|
1233
|
+
return (
|
|
1234
|
+
parts &&
|
|
1235
|
+
parts.length === expectedParts.length &&
|
|
1236
|
+
parts.every((part, index) => part === expectedParts[index])
|
|
1237
|
+
);
|
|
1238
|
+
});
|
|
1239
|
+
};
|
|
1240
|
+
const isTomlSectionLine = (line) => parseTomlHeaderParts(line) != null;
|
|
1241
|
+
const isMcpServersSectionLine = (line) => {
|
|
1242
|
+
const parts = parseTomlHeaderParts(line);
|
|
1243
|
+
return !!parts && parts.length === 1 && parts[0] === "mcp_servers";
|
|
1244
|
+
};
|
|
1245
|
+
const isDocdexNestedMcpServerSectionLine = (line) => {
|
|
1246
|
+
const parts = parseTomlHeaderParts(line);
|
|
1247
|
+
return !!parts && parts.length === 2 && parts[0] === "mcp_servers" && parts[1] === "docdex";
|
|
1248
|
+
};
|
|
1249
|
+
const hasNestedMcpServers = (contents) =>
|
|
1250
|
+
contents
|
|
1251
|
+
.split(/\r?\n/)
|
|
1252
|
+
.some((line) => {
|
|
1253
|
+
const parts = parseTomlHeaderParts(line);
|
|
1254
|
+
return !!parts && parts.length > 1 && parts[0] === "mcp_servers";
|
|
1255
|
+
});
|
|
1256
|
+
const parseTomlAssignmentKey = (line) => {
|
|
1257
|
+
const match = line.match(/^\s*([^=]+?)\s*=/);
|
|
1258
|
+
return match ? normalizeTomlKeyPart(match[1]) : null;
|
|
1259
|
+
};
|
|
1260
|
+
const isDocdexAssignmentLine = (line) => parseTomlAssignmentKey(line) === "docdex";
|
|
1159
1261
|
const migrateLegacyMcpServers = (contents) => {
|
|
1160
1262
|
if (!/\[\[mcp_servers\]\]/m.test(contents)) {
|
|
1161
1263
|
return { contents, migrated: false };
|
|
@@ -1220,8 +1322,7 @@ function upsertCodexConfig(pathname, url) {
|
|
|
1220
1322
|
["startup_timeout_sec", `${codexTimeoutSec}`]
|
|
1221
1323
|
];
|
|
1222
1324
|
const lines = contents.split(/\r?\n/);
|
|
1223
|
-
|
|
1224
|
-
let start = lines.findIndex((line) => headerRe.test(line));
|
|
1325
|
+
let start = lines.findIndex((line) => isDocdexNestedMcpServerSectionLine(line));
|
|
1225
1326
|
if (start === -1) {
|
|
1226
1327
|
if (lines.length && lines[lines.length - 1].trim()) lines.push("");
|
|
1227
1328
|
lines.push("[mcp_servers.docdex]");
|
|
@@ -1231,7 +1332,7 @@ function upsertCodexConfig(pathname, url) {
|
|
|
1231
1332
|
return { contents: lines.join("\n"), updated: true };
|
|
1232
1333
|
}
|
|
1233
1334
|
let end = start + 1;
|
|
1234
|
-
while (end < lines.length &&
|
|
1335
|
+
while (end < lines.length && !isTomlSectionLine(lines[end])) {
|
|
1235
1336
|
end += 1;
|
|
1236
1337
|
}
|
|
1237
1338
|
let updated = false;
|
|
@@ -1239,7 +1340,7 @@ function upsertCodexConfig(pathname, url) {
|
|
|
1239
1340
|
const lineValue = `${key} = ${value}`;
|
|
1240
1341
|
let keyIndex = -1;
|
|
1241
1342
|
for (let i = start + 1; i < end; i += 1) {
|
|
1242
|
-
if (
|
|
1343
|
+
if (parseTomlAssignmentKey(lines[i]) === key) {
|
|
1243
1344
|
keyIndex = i;
|
|
1244
1345
|
break;
|
|
1245
1346
|
}
|
|
@@ -1260,8 +1361,7 @@ function upsertCodexConfig(pathname, url) {
|
|
|
1260
1361
|
const entryLine =
|
|
1261
1362
|
`docdex = { url = "${urlValue}", tool_timeout_sec = ${codexTimeoutSec}, startup_timeout_sec = ${codexTimeoutSec} }`;
|
|
1262
1363
|
const lines = contents.split(/\r?\n/);
|
|
1263
|
-
const
|
|
1264
|
-
const start = lines.findIndex((line) => headerRe.test(line));
|
|
1364
|
+
const start = lines.findIndex((line) => isMcpServersSectionLine(line));
|
|
1265
1365
|
if (start === -1) {
|
|
1266
1366
|
if (lines.length && lines[lines.length - 1].trim()) lines.push("");
|
|
1267
1367
|
lines.push("[mcp_servers]");
|
|
@@ -1269,23 +1369,29 @@ function upsertCodexConfig(pathname, url) {
|
|
|
1269
1369
|
return { contents: lines.join("\n"), updated: true };
|
|
1270
1370
|
}
|
|
1271
1371
|
let end = start + 1;
|
|
1272
|
-
while (end < lines.length &&
|
|
1372
|
+
while (end < lines.length && !isTomlSectionLine(lines[end])) {
|
|
1273
1373
|
end += 1;
|
|
1274
1374
|
}
|
|
1275
1375
|
let updated = false;
|
|
1276
|
-
|
|
1376
|
+
const docdexLines = [];
|
|
1277
1377
|
for (let i = start + 1; i < end; i += 1) {
|
|
1278
|
-
if (
|
|
1279
|
-
|
|
1280
|
-
break;
|
|
1378
|
+
if (isDocdexAssignmentLine(lines[i])) {
|
|
1379
|
+
docdexLines.push(i);
|
|
1281
1380
|
}
|
|
1282
1381
|
}
|
|
1283
|
-
if (
|
|
1382
|
+
if (docdexLines.length === 0) {
|
|
1284
1383
|
lines.splice(end, 0, entryLine);
|
|
1285
1384
|
updated = true;
|
|
1286
|
-
} else
|
|
1287
|
-
|
|
1288
|
-
|
|
1385
|
+
} else {
|
|
1386
|
+
const [firstDocdexLine, ...extraDocdexLines] = docdexLines;
|
|
1387
|
+
if (lines[firstDocdexLine].trim() !== entryLine) {
|
|
1388
|
+
lines[firstDocdexLine] = entryLine;
|
|
1389
|
+
updated = true;
|
|
1390
|
+
}
|
|
1391
|
+
for (let i = extraDocdexLines.length - 1; i >= 0; i -= 1) {
|
|
1392
|
+
lines.splice(extraDocdexLines[i], 1);
|
|
1393
|
+
updated = true;
|
|
1394
|
+
}
|
|
1289
1395
|
}
|
|
1290
1396
|
return { contents: lines.join("\n"), updated };
|
|
1291
1397
|
};
|
|
@@ -1307,10 +1413,10 @@ function upsertCodexConfig(pathname, url) {
|
|
|
1307
1413
|
};
|
|
1308
1414
|
|
|
1309
1415
|
for (const line of lines) {
|
|
1310
|
-
const section = line
|
|
1416
|
+
const section = parseTomlHeaderParts(line);
|
|
1311
1417
|
if (section) {
|
|
1312
1418
|
flushFeatures();
|
|
1313
|
-
if (section[
|
|
1419
|
+
if (section.length === 1 && section[0] === "features") {
|
|
1314
1420
|
inFeatures = true;
|
|
1315
1421
|
buffer = [line];
|
|
1316
1422
|
continue;
|
|
@@ -1336,6 +1442,73 @@ function upsertCodexConfig(pathname, url) {
|
|
|
1336
1442
|
return { contents: output.join("\n"), updated };
|
|
1337
1443
|
};
|
|
1338
1444
|
|
|
1445
|
+
const removeRootDocdexEntries = (text) => {
|
|
1446
|
+
const lines = text.split(/\r?\n/);
|
|
1447
|
+
const output = [];
|
|
1448
|
+
let inRootSection = false;
|
|
1449
|
+
let updated = false;
|
|
1450
|
+
for (const line of lines) {
|
|
1451
|
+
const section = parseTomlHeaderParts(line);
|
|
1452
|
+
if (section) {
|
|
1453
|
+
inRootSection = section.length === 1 && section[0] === "mcp_servers";
|
|
1454
|
+
output.push(line);
|
|
1455
|
+
continue;
|
|
1456
|
+
}
|
|
1457
|
+
if (inRootSection && isDocdexAssignmentLine(line)) {
|
|
1458
|
+
updated = true;
|
|
1459
|
+
continue;
|
|
1460
|
+
}
|
|
1461
|
+
output.push(line);
|
|
1462
|
+
}
|
|
1463
|
+
return { contents: output.join("\n"), updated };
|
|
1464
|
+
};
|
|
1465
|
+
|
|
1466
|
+
const countRootDocdexEntries = (text) => {
|
|
1467
|
+
const lines = text.split(/\r?\n/);
|
|
1468
|
+
let inRootSection = false;
|
|
1469
|
+
let count = 0;
|
|
1470
|
+
for (const line of lines) {
|
|
1471
|
+
const section = parseTomlHeaderParts(line);
|
|
1472
|
+
if (section) {
|
|
1473
|
+
inRootSection = section.length === 1 && section[0] === "mcp_servers";
|
|
1474
|
+
continue;
|
|
1475
|
+
}
|
|
1476
|
+
if (inRootSection && isDocdexAssignmentLine(line)) {
|
|
1477
|
+
count += 1;
|
|
1478
|
+
}
|
|
1479
|
+
}
|
|
1480
|
+
return count;
|
|
1481
|
+
};
|
|
1482
|
+
|
|
1483
|
+
const removeNestedDocdexSections = (text) => {
|
|
1484
|
+
const lines = text.split(/\r?\n/);
|
|
1485
|
+
const output = [];
|
|
1486
|
+
let skipping = false;
|
|
1487
|
+
let updated = false;
|
|
1488
|
+
for (const line of lines) {
|
|
1489
|
+
const isSection = isTomlSectionLine(line);
|
|
1490
|
+
if (skipping) {
|
|
1491
|
+
if (isSection) {
|
|
1492
|
+
skipping = false;
|
|
1493
|
+
} else {
|
|
1494
|
+
continue;
|
|
1495
|
+
}
|
|
1496
|
+
}
|
|
1497
|
+
if (isDocdexNestedMcpServerSectionLine(line)) {
|
|
1498
|
+
skipping = true;
|
|
1499
|
+
updated = true;
|
|
1500
|
+
continue;
|
|
1501
|
+
}
|
|
1502
|
+
output.push(line);
|
|
1503
|
+
}
|
|
1504
|
+
return { contents: output.join("\n"), updated };
|
|
1505
|
+
};
|
|
1506
|
+
|
|
1507
|
+
const countNestedDocdexSections = (text) =>
|
|
1508
|
+
text
|
|
1509
|
+
.split(/\r?\n/)
|
|
1510
|
+
.filter((line) => isDocdexNestedMcpServerSectionLine(line)).length;
|
|
1511
|
+
|
|
1339
1512
|
let contents = "";
|
|
1340
1513
|
if (fs.existsSync(pathname)) {
|
|
1341
1514
|
contents = fs.readFileSync(pathname, "utf8");
|
|
@@ -1351,7 +1524,23 @@ function upsertCodexConfig(pathname, url) {
|
|
|
1351
1524
|
contents = cleaned.contents;
|
|
1352
1525
|
updated = updated || cleaned.updated;
|
|
1353
1526
|
|
|
1354
|
-
|
|
1527
|
+
const preferNested = hasNestedMcpServers(contents);
|
|
1528
|
+
const rootDocdexCount = countRootDocdexEntries(contents);
|
|
1529
|
+
const nestedDocdexCount = countNestedDocdexSections(contents);
|
|
1530
|
+
|
|
1531
|
+
if (preferNested && rootDocdexCount > 0) {
|
|
1532
|
+
const prunedRoot = removeRootDocdexEntries(contents);
|
|
1533
|
+
contents = prunedRoot.contents;
|
|
1534
|
+
updated = updated || prunedRoot.updated;
|
|
1535
|
+
}
|
|
1536
|
+
|
|
1537
|
+
if ((!preferNested && nestedDocdexCount > 0) || (preferNested && nestedDocdexCount > 1)) {
|
|
1538
|
+
const prunedNested = removeNestedDocdexSections(contents);
|
|
1539
|
+
contents = prunedNested.contents;
|
|
1540
|
+
updated = updated || prunedNested.updated;
|
|
1541
|
+
}
|
|
1542
|
+
|
|
1543
|
+
if (preferNested) {
|
|
1355
1544
|
const nested = upsertDocdexNested(contents, url);
|
|
1356
1545
|
contents = nested.contents;
|
|
1357
1546
|
updated = updated || nested.updated;
|