docdex 0.2.4 → 0.2.6
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 +1 -1
- package/lib/postinstall_setup.js +46 -10
- package/lib/uninstall.js +148 -23
- package/package.json +1 -1
package/CHANGELOG.md
CHANGED
package/lib/postinstall_setup.js
CHANGED
|
@@ -381,27 +381,53 @@ function hasInteractiveTty(stdin, stdout) {
|
|
|
381
381
|
return Boolean((stdin && stdin.isTTY) || (stdout && stdout.isTTY));
|
|
382
382
|
}
|
|
383
383
|
|
|
384
|
-
function
|
|
384
|
+
function canPromptWithTty(stdin, stdout) {
|
|
385
|
+
if (hasInteractiveTty(stdin, stdout)) return true;
|
|
386
|
+
const isWindows = process.platform === "win32";
|
|
387
|
+
const inputPath = isWindows ? "CONIN$" : "/dev/tty";
|
|
388
|
+
const outputPath = isWindows ? "CONOUT$" : "/dev/tty";
|
|
389
|
+
try {
|
|
390
|
+
const readFd = fs.openSync(inputPath, "r");
|
|
391
|
+
const writeFd = fs.openSync(outputPath, "w");
|
|
392
|
+
fs.closeSync(readFd);
|
|
393
|
+
fs.closeSync(writeFd);
|
|
394
|
+
return true;
|
|
395
|
+
} catch {
|
|
396
|
+
return false;
|
|
397
|
+
}
|
|
398
|
+
}
|
|
399
|
+
|
|
400
|
+
function resolveOllamaInstallMode({
|
|
401
|
+
env = process.env,
|
|
402
|
+
stdin = process.stdin,
|
|
403
|
+
stdout = process.stdout,
|
|
404
|
+
canPrompt = canPromptWithTty
|
|
405
|
+
} = {}) {
|
|
385
406
|
const override = parseEnvBool(env.DOCDEX_OLLAMA_INSTALL);
|
|
386
407
|
if (override === true) return { mode: "install", reason: "env", interactive: false };
|
|
387
408
|
if (override === false) return { mode: "skip", reason: "env", interactive: false };
|
|
388
|
-
if (!
|
|
409
|
+
if (!canPrompt(stdin, stdout)) {
|
|
410
|
+
if (env.CI) return { mode: "skip", reason: "ci", interactive: false };
|
|
389
411
|
return { mode: "skip", reason: "non_interactive", interactive: false };
|
|
390
412
|
}
|
|
391
|
-
if (env.CI) return { mode: "skip", reason: "ci", interactive: false };
|
|
392
413
|
return { mode: "prompt", reason: "interactive", interactive: true };
|
|
393
414
|
}
|
|
394
415
|
|
|
395
|
-
function resolveOllamaModelPromptMode({
|
|
416
|
+
function resolveOllamaModelPromptMode({
|
|
417
|
+
env = process.env,
|
|
418
|
+
stdin = process.stdin,
|
|
419
|
+
stdout = process.stdout,
|
|
420
|
+
canPrompt = canPromptWithTty
|
|
421
|
+
} = {}) {
|
|
396
422
|
const override = parseEnvBool(env.DOCDEX_OLLAMA_MODEL_PROMPT);
|
|
397
423
|
if (override === true) return { mode: "prompt", reason: "env", interactive: true };
|
|
398
424
|
if (override === false) return { mode: "skip", reason: "env", interactive: false };
|
|
399
425
|
const assumeYes = parseEnvBool(env.DOCDEX_OLLAMA_MODEL_ASSUME_Y);
|
|
400
426
|
if (assumeYes === true) return { mode: "auto", reason: "env", interactive: false };
|
|
401
|
-
if (!
|
|
427
|
+
if (!canPrompt(stdin, stdout)) {
|
|
428
|
+
if (env.CI) return { mode: "skip", reason: "ci", interactive: false };
|
|
402
429
|
return { mode: "skip", reason: "non_interactive", interactive: false };
|
|
403
430
|
}
|
|
404
|
-
if (env.CI) return { mode: "skip", reason: "ci", interactive: false };
|
|
405
431
|
return { mode: "prompt", reason: "interactive", interactive: true };
|
|
406
432
|
}
|
|
407
433
|
|
|
@@ -563,10 +589,19 @@ function resolvePromptStreams(stdin, stdout) {
|
|
|
563
589
|
return { input: stdin, output: stdout, close: null };
|
|
564
590
|
}
|
|
565
591
|
const isWindows = process.platform === "win32";
|
|
566
|
-
const
|
|
592
|
+
const inputPath = isWindows ? "CONIN$" : "/dev/tty";
|
|
593
|
+
const outputPath = isWindows ? "CONOUT$" : "/dev/tty";
|
|
567
594
|
try {
|
|
568
|
-
const input = fs.createReadStream(
|
|
569
|
-
|
|
595
|
+
const input = fs.createReadStream(inputPath, { autoClose: true });
|
|
596
|
+
const output = fs.createWriteStream(outputPath, { autoClose: true });
|
|
597
|
+
return {
|
|
598
|
+
input,
|
|
599
|
+
output,
|
|
600
|
+
close: () => {
|
|
601
|
+
input.close();
|
|
602
|
+
output.end();
|
|
603
|
+
}
|
|
604
|
+
};
|
|
570
605
|
} catch {
|
|
571
606
|
return { input: stdin, output: stdout, close: null };
|
|
572
607
|
}
|
|
@@ -1050,5 +1085,6 @@ module.exports = {
|
|
|
1050
1085
|
upsertLlmDefaultModel,
|
|
1051
1086
|
pullOllamaModel,
|
|
1052
1087
|
listOllamaModels,
|
|
1053
|
-
hasInteractiveTty
|
|
1088
|
+
hasInteractiveTty,
|
|
1089
|
+
canPromptWithTty
|
|
1054
1090
|
};
|
package/lib/uninstall.js
CHANGED
|
@@ -18,6 +18,8 @@ function stateDir() {
|
|
|
18
18
|
}
|
|
19
19
|
|
|
20
20
|
function daemonLockPath() {
|
|
21
|
+
const override = process.env.DOCDEX_DAEMON_LOCK_PATH;
|
|
22
|
+
if (override && override.trim()) return override.trim();
|
|
21
23
|
return path.join(os.homedir(), ".docdex", "daemon.lock");
|
|
22
24
|
}
|
|
23
25
|
|
|
@@ -28,21 +30,51 @@ function clientConfigPaths() {
|
|
|
28
30
|
switch (process.platform) {
|
|
29
31
|
case "win32":
|
|
30
32
|
return {
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
33
|
+
json: [
|
|
34
|
+
path.join(appData, "Claude", "claude_desktop_config.json"),
|
|
35
|
+
path.join(userProfile, ".cursor", "mcp.json"),
|
|
36
|
+
path.join(userProfile, ".cursor", "settings.json"),
|
|
37
|
+
path.join(userProfile, ".codeium", "windsurf", "mcp_config.json"),
|
|
38
|
+
path.join(appData, "Code", "User", "globalStorage", "saoudrizwan.claude-dev", "settings", "cline_mcp_settings.json"),
|
|
39
|
+
path.join(appData, "Code", "User", "globalStorage", "rooveterinaryinc.roo-cline", "settings", "mcp_settings.json"),
|
|
40
|
+
path.join(userProfile, ".continue", "config.json"),
|
|
41
|
+
path.join(userProfile, ".kiro", "settings", "mcp.json"),
|
|
42
|
+
path.join(appData, "Zed", "settings.json")
|
|
43
|
+
],
|
|
44
|
+
toml: [path.join(userProfile, ".codex", "config.toml")],
|
|
45
|
+
yaml: [path.join(appData, "Aider", "config.yml")]
|
|
34
46
|
};
|
|
35
47
|
case "darwin":
|
|
36
48
|
return {
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
49
|
+
json: [
|
|
50
|
+
path.join(home, "Library", "Application Support", "Claude", "claude_desktop_config.json"),
|
|
51
|
+
path.join(home, ".cursor", "mcp.json"),
|
|
52
|
+
path.join(home, ".cursor", "settings.json"),
|
|
53
|
+
path.join(home, ".codeium", "windsurf", "mcp_config.json"),
|
|
54
|
+
path.join(home, "Library", "Application Support", "Code", "User", "globalStorage", "saoudrizwan.claude-dev", "settings", "cline_mcp_settings.json"),
|
|
55
|
+
path.join(home, "Library", "Application Support", "Code", "User", "globalStorage", "rooveterinaryinc.roo-cline", "settings", "mcp_settings.json"),
|
|
56
|
+
path.join(home, ".continue", "config.json"),
|
|
57
|
+
path.join(home, ".kiro", "settings", "mcp.json"),
|
|
58
|
+
path.join(home, ".config", "zed", "settings.json")
|
|
59
|
+
],
|
|
60
|
+
toml: [path.join(home, ".codex", "config.toml")],
|
|
61
|
+
yaml: [path.join(home, ".config", "aider", "config.yml"), path.join(home, ".aider.conf.yml")]
|
|
40
62
|
};
|
|
41
63
|
default:
|
|
42
64
|
return {
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
65
|
+
json: [
|
|
66
|
+
path.join(home, ".config", "Claude", "claude_desktop_config.json"),
|
|
67
|
+
path.join(home, ".cursor", "mcp.json"),
|
|
68
|
+
path.join(home, ".cursor", "settings.json"),
|
|
69
|
+
path.join(home, ".codeium", "windsurf", "mcp_config.json"),
|
|
70
|
+
path.join(home, ".config", "Code", "User", "globalStorage", "saoudrizwan.claude-dev", "settings", "cline_mcp_settings.json"),
|
|
71
|
+
path.join(home, ".config", "Code", "User", "globalStorage", "rooveterinaryinc.roo-cline", "settings", "mcp_settings.json"),
|
|
72
|
+
path.join(home, ".continue", "config.json"),
|
|
73
|
+
path.join(home, ".kiro", "settings", "mcp.json"),
|
|
74
|
+
path.join(home, ".config", "zed", "settings.json")
|
|
75
|
+
],
|
|
76
|
+
toml: [path.join(home, ".codex", "config.toml")],
|
|
77
|
+
yaml: [path.join(home, ".config", "aider", "config.yml"), path.join(home, ".aider.conf.yml")]
|
|
46
78
|
};
|
|
47
79
|
}
|
|
48
80
|
}
|
|
@@ -67,12 +99,17 @@ function removeMcpServerJson(pathname, name = "docdex") {
|
|
|
67
99
|
const { value, exists } = readJson(pathname);
|
|
68
100
|
if (!exists || typeof value !== "object" || value == null || Array.isArray(value)) return false;
|
|
69
101
|
const root = value;
|
|
70
|
-
|
|
71
|
-
|
|
102
|
+
const keys = ["mcpServers", "mcp_servers"];
|
|
103
|
+
let changed = false;
|
|
104
|
+
for (const key of keys) {
|
|
105
|
+
const section = root[key];
|
|
106
|
+
if (!section || typeof section !== "object" || Array.isArray(section)) continue;
|
|
107
|
+
if (!Object.prototype.hasOwnProperty.call(section, name)) continue;
|
|
108
|
+
delete section[name];
|
|
109
|
+
changed = true;
|
|
110
|
+
if (Object.keys(section).length === 0) delete root[key];
|
|
72
111
|
}
|
|
73
|
-
if (!
|
|
74
|
-
delete root.mcpServers[name];
|
|
75
|
-
if (Object.keys(root.mcpServers).length === 0) delete root.mcpServers;
|
|
112
|
+
if (!changed) return false;
|
|
76
113
|
writeJson(pathname, root);
|
|
77
114
|
return true;
|
|
78
115
|
}
|
|
@@ -180,6 +217,71 @@ function removeCodexConfig(pathname, name = "docdex") {
|
|
|
180
217
|
return false;
|
|
181
218
|
}
|
|
182
219
|
|
|
220
|
+
function removeMcpServerYaml(pathname, name = "docdex") {
|
|
221
|
+
if (!fs.existsSync(pathname)) return false;
|
|
222
|
+
const original = fs.readFileSync(pathname, "utf8");
|
|
223
|
+
const lines = original.split(/\r?\n/);
|
|
224
|
+
const output = [];
|
|
225
|
+
let inSection = false;
|
|
226
|
+
let sectionIndent = null;
|
|
227
|
+
let skipIndent = null;
|
|
228
|
+
let changed = false;
|
|
229
|
+
|
|
230
|
+
const indentSize = (line) => (line.match(/^\s*/)?.[0].length ?? 0);
|
|
231
|
+
|
|
232
|
+
for (const line of lines) {
|
|
233
|
+
if (skipIndent != null) {
|
|
234
|
+
if (line.trim() && indentSize(line) <= skipIndent) {
|
|
235
|
+
skipIndent = null;
|
|
236
|
+
} else {
|
|
237
|
+
changed = true;
|
|
238
|
+
continue;
|
|
239
|
+
}
|
|
240
|
+
}
|
|
241
|
+
|
|
242
|
+
if (!inSection) {
|
|
243
|
+
if (/^\s*mcp_servers\s*:\s*$/.test(line)) {
|
|
244
|
+
inSection = true;
|
|
245
|
+
sectionIndent = indentSize(line);
|
|
246
|
+
}
|
|
247
|
+
output.push(line);
|
|
248
|
+
continue;
|
|
249
|
+
}
|
|
250
|
+
|
|
251
|
+
if (line.trim() && indentSize(line) <= sectionIndent) {
|
|
252
|
+
inSection = false;
|
|
253
|
+
output.push(line);
|
|
254
|
+
continue;
|
|
255
|
+
}
|
|
256
|
+
|
|
257
|
+
if (new RegExp(`^\\s*${name}\\s*:`).test(line)) {
|
|
258
|
+
changed = true;
|
|
259
|
+
skipIndent = indentSize(line);
|
|
260
|
+
continue;
|
|
261
|
+
}
|
|
262
|
+
|
|
263
|
+
const listName = line.match(/^\s*-\s*name\s*:\s*(.+)\s*$/);
|
|
264
|
+
if (listName && listName[1].replace(/["']/g, "").trim() === name) {
|
|
265
|
+
changed = true;
|
|
266
|
+
skipIndent = indentSize(line);
|
|
267
|
+
continue;
|
|
268
|
+
}
|
|
269
|
+
|
|
270
|
+
const listValue = line.match(/^\s*-\s*([^\s#]+)\s*$/);
|
|
271
|
+
if (listValue && listValue[1].replace(/["']/g, "").trim() === name) {
|
|
272
|
+
changed = true;
|
|
273
|
+
continue;
|
|
274
|
+
}
|
|
275
|
+
|
|
276
|
+
output.push(line);
|
|
277
|
+
}
|
|
278
|
+
|
|
279
|
+
if (changed) {
|
|
280
|
+
fs.writeFileSync(pathname, output.join("\n"));
|
|
281
|
+
}
|
|
282
|
+
return changed;
|
|
283
|
+
}
|
|
284
|
+
|
|
183
285
|
function killPid(pid) {
|
|
184
286
|
if (!pid) return false;
|
|
185
287
|
try {
|
|
@@ -209,6 +311,16 @@ function stopDaemonFromLock() {
|
|
|
209
311
|
}
|
|
210
312
|
}
|
|
211
313
|
|
|
314
|
+
function stopDaemonByName() {
|
|
315
|
+
if (process.platform === "win32") {
|
|
316
|
+
spawnSync("taskkill", ["/IM", "docdexd.exe", "/T", "/F"]);
|
|
317
|
+
return true;
|
|
318
|
+
}
|
|
319
|
+
spawnSync("pkill", ["-TERM", "-x", "docdexd"]);
|
|
320
|
+
spawnSync("pkill", ["-TERM", "-f", "docdexd daemon"]);
|
|
321
|
+
return true;
|
|
322
|
+
}
|
|
323
|
+
|
|
212
324
|
function unregisterStartup() {
|
|
213
325
|
if (process.platform === "darwin") {
|
|
214
326
|
const plistPath = path.join(os.homedir(), "Library", "LaunchAgents", "com.docdex.daemon.plist");
|
|
@@ -259,23 +371,34 @@ function clearStartupFailure() {
|
|
|
259
371
|
|
|
260
372
|
function removeDaemonRootNotice() {
|
|
261
373
|
const root = daemonRootPath();
|
|
262
|
-
const
|
|
263
|
-
|
|
264
|
-
|
|
265
|
-
|
|
266
|
-
|
|
374
|
+
const readmes = [path.join(root, "README.txt"), path.join(root, "README.md")];
|
|
375
|
+
for (const readme of readmes) {
|
|
376
|
+
if (fs.existsSync(readme)) {
|
|
377
|
+
try {
|
|
378
|
+
fs.unlinkSync(readme);
|
|
379
|
+
} catch {}
|
|
380
|
+
}
|
|
267
381
|
}
|
|
268
382
|
}
|
|
269
383
|
|
|
270
384
|
function removeClientConfigs() {
|
|
271
385
|
const paths = clientConfigPaths();
|
|
272
|
-
|
|
273
|
-
|
|
274
|
-
|
|
386
|
+
for (const pathname of paths.json || []) {
|
|
387
|
+
removeMcpServerJson(pathname);
|
|
388
|
+
}
|
|
389
|
+
for (const pathname of paths.toml || []) {
|
|
390
|
+
removeCodexConfig(pathname);
|
|
391
|
+
}
|
|
392
|
+
for (const pathname of paths.yaml || []) {
|
|
393
|
+
removeMcpServerYaml(pathname);
|
|
394
|
+
}
|
|
275
395
|
}
|
|
276
396
|
|
|
277
397
|
async function main() {
|
|
278
|
-
stopDaemonFromLock();
|
|
398
|
+
const stopped = stopDaemonFromLock();
|
|
399
|
+
if (!stopped) {
|
|
400
|
+
stopDaemonByName();
|
|
401
|
+
}
|
|
279
402
|
unregisterStartup();
|
|
280
403
|
removeClientConfigs();
|
|
281
404
|
clearStartupFailure();
|
|
@@ -289,7 +412,9 @@ if (require.main === module) {
|
|
|
289
412
|
module.exports = {
|
|
290
413
|
removeMcpServerJson,
|
|
291
414
|
removeCodexConfig,
|
|
415
|
+
removeMcpServerYaml,
|
|
292
416
|
stopDaemonFromLock,
|
|
417
|
+
stopDaemonByName,
|
|
293
418
|
unregisterStartup,
|
|
294
419
|
removeClientConfigs
|
|
295
420
|
};
|