docdex 0.2.30 → 0.2.32
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/cli_entry.js +242 -0
- package/lib/install.js +116 -7
- package/lib/mcp_stdio_cli.js +15 -0
- package/package.json +4 -4
package/CHANGELOG.md
CHANGED
|
@@ -2,6 +2,10 @@
|
|
|
2
2
|
|
|
3
3
|
## Unreleased
|
|
4
4
|
- Remove legacy stdio MCP (`docdexd mcp` / `docdex-mcp-server`); MCP is served only over HTTP/SSE.
|
|
5
|
+
- Ensure npm tarballs include CLI wrapper entrypoints and restore missing wrappers during postinstall.
|
|
6
|
+
- Retry Windows file operations during install to reduce EPERM/EACCES failures.
|
|
7
|
+
- Nightly HTTP soak waits for index readiness before load testing.
|
|
8
|
+
- Windows CLI shims now target stable `lib/` entrypoints to avoid missing `bin/docdex.js`.
|
|
5
9
|
|
|
6
10
|
## 0.2.23
|
|
7
11
|
- Add Smithery session config schema metadata (titles/descriptions, defaults, example config) for local MCP sessions.
|
package/assets/agents.md
CHANGED
package/lib/cli_entry.js
ADDED
|
@@ -0,0 +1,242 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
"use strict";
|
|
3
|
+
|
|
4
|
+
const fs = require("node:fs");
|
|
5
|
+
const path = require("node:path");
|
|
6
|
+
const { spawn } = require("node:child_process");
|
|
7
|
+
|
|
8
|
+
const pkg = require("../package.json");
|
|
9
|
+
const { resolveDistBaseDir, resolveDistBaseCandidates } = require("./paths");
|
|
10
|
+
const {
|
|
11
|
+
artifactName,
|
|
12
|
+
detectLibcFromRuntime,
|
|
13
|
+
detectPlatformKey,
|
|
14
|
+
targetTripleForPlatformKey,
|
|
15
|
+
assetPatternForPlatformKey,
|
|
16
|
+
UnsupportedPlatformError
|
|
17
|
+
} = require("./platform");
|
|
18
|
+
const { checkForUpdateOnce } = require("./update_check");
|
|
19
|
+
|
|
20
|
+
function isDoctorCommand(argv) {
|
|
21
|
+
const sub = argv[0];
|
|
22
|
+
return sub === "doctor" || sub === "diagnostics";
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
function printLines(lines, { stderr } = {}) {
|
|
26
|
+
for (const line of lines) {
|
|
27
|
+
if (!line) continue;
|
|
28
|
+
if (stderr) console.error(line);
|
|
29
|
+
else console.log(line);
|
|
30
|
+
}
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
function envBool(value) {
|
|
34
|
+
if (!value) return false;
|
|
35
|
+
const normalized = String(value).trim().toLowerCase();
|
|
36
|
+
return ["1", "true", "t", "yes", "y", "on"].includes(normalized);
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
function readInstallMetadata({ fsModule, pathModule, basePath }) {
|
|
40
|
+
if (!fsModule || typeof fsModule.readFileSync !== "function") return null;
|
|
41
|
+
const metadataPath = pathModule.join(basePath, "docdexd-install.json");
|
|
42
|
+
try {
|
|
43
|
+
const raw = fsModule.readFileSync(metadataPath, "utf8");
|
|
44
|
+
return JSON.parse(raw);
|
|
45
|
+
} catch {
|
|
46
|
+
return null;
|
|
47
|
+
}
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
function formatInstallSource(meta) {
|
|
51
|
+
const source = meta?.archive?.source;
|
|
52
|
+
if (!source || typeof source !== "string") return "unknown";
|
|
53
|
+
if (source === "local") return "local binary";
|
|
54
|
+
return `release (${source})`;
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
function resolveInstallPaths(platformKey) {
|
|
58
|
+
const binaryName = process.platform === "win32" ? "docdexd.exe" : "docdexd";
|
|
59
|
+
const candidates = [];
|
|
60
|
+
for (const distBase of resolveDistBaseCandidates({ env: process.env })) {
|
|
61
|
+
candidates.push(path.join(distBase, platformKey));
|
|
62
|
+
}
|
|
63
|
+
candidates.push(path.join(__dirname, "..", "dist", platformKey));
|
|
64
|
+
const seen = new Set();
|
|
65
|
+
const unique = candidates.filter((candidate) => {
|
|
66
|
+
if (!candidate || seen.has(candidate)) return false;
|
|
67
|
+
seen.add(candidate);
|
|
68
|
+
return true;
|
|
69
|
+
});
|
|
70
|
+
for (const basePath of unique) {
|
|
71
|
+
const binaryPath = path.join(basePath, binaryName);
|
|
72
|
+
if (fs.existsSync(binaryPath)) {
|
|
73
|
+
return { basePath, binaryPath };
|
|
74
|
+
}
|
|
75
|
+
}
|
|
76
|
+
const fallbackBase =
|
|
77
|
+
unique[0] || path.join(resolveDistBaseDir({ env: process.env, fsModule: fs }), platformKey);
|
|
78
|
+
return { basePath: fallbackBase, binaryPath: path.join(fallbackBase, binaryName) };
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
function runDoctor() {
|
|
82
|
+
const platform = process.platform;
|
|
83
|
+
const arch = process.arch;
|
|
84
|
+
|
|
85
|
+
let libc = null;
|
|
86
|
+
if (platform === "linux") {
|
|
87
|
+
try {
|
|
88
|
+
libc = detectLibcFromRuntime();
|
|
89
|
+
} catch (err) {
|
|
90
|
+
printLines(
|
|
91
|
+
[
|
|
92
|
+
"[docdex] doctor failed: could not detect libc",
|
|
93
|
+
`[docdex] Detected platform: ${platform}/${arch}`,
|
|
94
|
+
`[docdex] Error: ${err?.message || String(err)}`
|
|
95
|
+
],
|
|
96
|
+
{ stderr: true }
|
|
97
|
+
);
|
|
98
|
+
process.exit(1);
|
|
99
|
+
return;
|
|
100
|
+
}
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
let report;
|
|
104
|
+
try {
|
|
105
|
+
const platformKey = detectPlatformKey();
|
|
106
|
+
const targetTriple = targetTripleForPlatformKey(platformKey);
|
|
107
|
+
const expectedAssetName = artifactName(platformKey);
|
|
108
|
+
const expectedAssetPattern = assetPatternForPlatformKey(platformKey, { exampleAssetName: expectedAssetName });
|
|
109
|
+
const distCandidates = resolveDistBaseCandidates({ env: process.env });
|
|
110
|
+
const distBase =
|
|
111
|
+
distCandidates[0] || resolveDistBaseDir({ env: process.env, fsModule: null });
|
|
112
|
+
const basePath = path.join(distBase, platformKey);
|
|
113
|
+
const installMeta = readInstallMetadata({ fsModule: fs, pathModule: path, basePath });
|
|
114
|
+
const installSource = formatInstallSource(installMeta);
|
|
115
|
+
|
|
116
|
+
report = {
|
|
117
|
+
exitCode: 0,
|
|
118
|
+
stderr: false,
|
|
119
|
+
lines: [
|
|
120
|
+
"[docdex] doctor",
|
|
121
|
+
`[docdex] Detected platform: ${platform}/${arch}${libc ? `/${libc}` : ""}`,
|
|
122
|
+
"[docdex] Supported: yes",
|
|
123
|
+
`[docdex] Platform key: ${platformKey}`,
|
|
124
|
+
`[docdex] Expected target triple: ${targetTriple}`,
|
|
125
|
+
`[docdex] Expected release asset: ${expectedAssetName}`,
|
|
126
|
+
`[docdex] Asset naming pattern: ${expectedAssetPattern}`,
|
|
127
|
+
`[docdex] Install source: ${installSource}`
|
|
128
|
+
]
|
|
129
|
+
};
|
|
130
|
+
} catch (err) {
|
|
131
|
+
if (err instanceof UnsupportedPlatformError) {
|
|
132
|
+
const detected = `${err.details?.platform ?? platform}/${err.details?.arch ?? arch}`;
|
|
133
|
+
const libcSuffix = err.details?.libc ? `/${err.details.libc}` : "";
|
|
134
|
+
const candidatePlatformKey =
|
|
135
|
+
typeof err.details?.candidatePlatformKey === "string" ? err.details.candidatePlatformKey : null;
|
|
136
|
+
const candidateTargetTriple =
|
|
137
|
+
typeof err.details?.candidateTargetTriple === "string" ? err.details.candidateTargetTriple : null;
|
|
138
|
+
const supportedKeys = Array.isArray(err.details?.supportedPlatformKeys) ? err.details.supportedPlatformKeys : [];
|
|
139
|
+
|
|
140
|
+
const candidateAssetName = candidatePlatformKey ? artifactName(candidatePlatformKey) : null;
|
|
141
|
+
const candidateAssetPattern = candidatePlatformKey
|
|
142
|
+
? assetPatternForPlatformKey(candidatePlatformKey, { exampleAssetName: candidateAssetName })
|
|
143
|
+
: null;
|
|
144
|
+
|
|
145
|
+
report = {
|
|
146
|
+
exitCode: err.exitCode || 3,
|
|
147
|
+
stderr: true,
|
|
148
|
+
lines: [
|
|
149
|
+
"[docdex] doctor",
|
|
150
|
+
`[docdex] Detected platform: ${detected}${libcSuffix}`,
|
|
151
|
+
"[docdex] Supported: no",
|
|
152
|
+
`[docdex] error code: ${err.code}`,
|
|
153
|
+
"[docdex] No download/install is attempted for this platform.",
|
|
154
|
+
candidatePlatformKey ? `[docdex] Platform key: ${candidatePlatformKey}` : null,
|
|
155
|
+
candidateTargetTriple ? `[docdex] Target triple: ${candidateTargetTriple}` : null,
|
|
156
|
+
candidateAssetPattern ? `[docdex] Asset naming pattern: ${candidateAssetPattern}` : null,
|
|
157
|
+
supportedKeys.length ? `[docdex] Supported platforms: ${supportedKeys.join(", ")}` : null,
|
|
158
|
+
"[docdex] Next steps: use a supported platform or build from source (Rust)."
|
|
159
|
+
]
|
|
160
|
+
};
|
|
161
|
+
} else {
|
|
162
|
+
report = {
|
|
163
|
+
exitCode: 1,
|
|
164
|
+
stderr: true,
|
|
165
|
+
lines: [
|
|
166
|
+
"[docdex] doctor failed: unexpected error",
|
|
167
|
+
`[docdex] Detected platform: ${platform}/${arch}${libc ? `/${libc}` : ""}`,
|
|
168
|
+
`[docdex] Error: ${err?.message || String(err)}`
|
|
169
|
+
]
|
|
170
|
+
};
|
|
171
|
+
}
|
|
172
|
+
}
|
|
173
|
+
|
|
174
|
+
printLines(report.lines, { stderr: report.stderr });
|
|
175
|
+
process.exit(report.exitCode);
|
|
176
|
+
}
|
|
177
|
+
|
|
178
|
+
async function run() {
|
|
179
|
+
const argv = process.argv.slice(2);
|
|
180
|
+
if (isDoctorCommand(argv)) {
|
|
181
|
+
runDoctor();
|
|
182
|
+
return;
|
|
183
|
+
}
|
|
184
|
+
|
|
185
|
+
let platformKey;
|
|
186
|
+
try {
|
|
187
|
+
platformKey = detectPlatformKey();
|
|
188
|
+
} catch (err) {
|
|
189
|
+
if (err instanceof UnsupportedPlatformError) {
|
|
190
|
+
const detected = `${err.details?.platform ?? process.platform}/${err.details?.arch ?? process.arch}`;
|
|
191
|
+
const libc = err.details?.libc ? `/${err.details.libc}` : "";
|
|
192
|
+
console.error(`[docdex] unsupported platform (${detected}${libc})`);
|
|
193
|
+
console.error(`[docdex] error code: ${err.code}`);
|
|
194
|
+
console.error("[docdex] No download/run was attempted for this platform.");
|
|
195
|
+
if (Array.isArray(err.details?.supportedPlatformKeys) && err.details.supportedPlatformKeys.length) {
|
|
196
|
+
console.error(`[docdex] Supported platforms: ${err.details.supportedPlatformKeys.join(", ")}`);
|
|
197
|
+
}
|
|
198
|
+
if (typeof err.details?.candidatePlatformKey === "string") {
|
|
199
|
+
console.error(`[docdex] Asset naming pattern: ${assetPatternForPlatformKey(err.details.candidatePlatformKey)}`);
|
|
200
|
+
}
|
|
201
|
+
console.error("[docdex] Next steps: use a supported platform or build from source (Rust).");
|
|
202
|
+
process.exit(err.exitCode || 3);
|
|
203
|
+
return;
|
|
204
|
+
}
|
|
205
|
+
console.error(`[docdex] failed to detect platform: ${err?.message || String(err)}`);
|
|
206
|
+
process.exit(1);
|
|
207
|
+
return;
|
|
208
|
+
}
|
|
209
|
+
|
|
210
|
+
const { binaryPath } = resolveInstallPaths(platformKey);
|
|
211
|
+
|
|
212
|
+
if (!fs.existsSync(binaryPath)) {
|
|
213
|
+
console.error(`[docdex] Missing binary for ${platformKey}. Try reinstalling or set DOCDEX_DOWNLOAD_REPO to a repo with release assets.`);
|
|
214
|
+
try {
|
|
215
|
+
console.error(`[docdex] Expected target triple: ${targetTripleForPlatformKey(platformKey)}`);
|
|
216
|
+
console.error(`[docdex] Asset naming pattern: ${assetPatternForPlatformKey(platformKey)}`);
|
|
217
|
+
} catch {}
|
|
218
|
+
process.exit(1);
|
|
219
|
+
return;
|
|
220
|
+
}
|
|
221
|
+
|
|
222
|
+
await checkForUpdateOnce({
|
|
223
|
+
currentVersion: pkg.version,
|
|
224
|
+
env: process.env,
|
|
225
|
+
stdout: process.stdout,
|
|
226
|
+
stderr: process.stderr,
|
|
227
|
+
logger: console
|
|
228
|
+
});
|
|
229
|
+
|
|
230
|
+
const env = { ...process.env };
|
|
231
|
+
const child = spawn(binaryPath, process.argv.slice(2), { stdio: "inherit", env });
|
|
232
|
+
child.on("exit", (code) => process.exit(code ?? 1));
|
|
233
|
+
child.on("error", (err) => {
|
|
234
|
+
console.error(`[docdex] failed to launch binary: ${err.message}`);
|
|
235
|
+
process.exit(1);
|
|
236
|
+
});
|
|
237
|
+
}
|
|
238
|
+
|
|
239
|
+
run().catch((err) => {
|
|
240
|
+
console.error(`[docdex] unexpected error: ${err?.message || String(err)}`);
|
|
241
|
+
process.exit(1);
|
|
242
|
+
});
|
package/lib/install.js
CHANGED
|
@@ -42,6 +42,31 @@ const DEFAULT_INTEGRITY_CONFIG = Object.freeze({
|
|
|
42
42
|
const LOCAL_FALLBACK_ENV = "DOCDEX_LOCAL_FALLBACK";
|
|
43
43
|
const LOCAL_BINARY_ENV = "DOCDEX_LOCAL_BINARY";
|
|
44
44
|
const AGENTS_DOC_FILENAME = "agents.md";
|
|
45
|
+
const CLI_WRAPPER_SCRIPT = [
|
|
46
|
+
"#!/usr/bin/env node",
|
|
47
|
+
"\"use strict\";",
|
|
48
|
+
"",
|
|
49
|
+
"require(\"../lib/cli_entry\");",
|
|
50
|
+
""
|
|
51
|
+
].join("\n");
|
|
52
|
+
const MCP_STDIO_WRAPPER_SCRIPT = [
|
|
53
|
+
"#!/usr/bin/env node",
|
|
54
|
+
"\"use strict\";",
|
|
55
|
+
"",
|
|
56
|
+
"const { runBridge } = require(\"../lib/mcp_stdio_bridge\");",
|
|
57
|
+
"",
|
|
58
|
+
"async function main() {",
|
|
59
|
+
" try {",
|
|
60
|
+
" await runBridge({ stdin: process.stdin, stdout: process.stdout, stderr: process.stderr });",
|
|
61
|
+
" } catch (err) {",
|
|
62
|
+
" process.stderr.write(`[docdex-mcp-stdio] fatal: ${err}\\n`);",
|
|
63
|
+
" process.exit(1);",
|
|
64
|
+
" }",
|
|
65
|
+
"}",
|
|
66
|
+
"",
|
|
67
|
+
"main();",
|
|
68
|
+
""
|
|
69
|
+
].join("\n");
|
|
45
70
|
|
|
46
71
|
const EXIT_CODE_BY_ERROR_CODE = Object.freeze({
|
|
47
72
|
DOCDEX_INSTALLER_CONFIG: 2,
|
|
@@ -231,6 +256,53 @@ function writeAgentInstructions() {
|
|
|
231
256
|
}
|
|
232
257
|
}
|
|
233
258
|
|
|
259
|
+
function shouldWriteWrapper(fsModule, filePath) {
|
|
260
|
+
if (!fsModule?.existsSync) return true;
|
|
261
|
+
if (!fsModule.existsSync(filePath)) return true;
|
|
262
|
+
try {
|
|
263
|
+
const stat = fsModule.statSync(filePath);
|
|
264
|
+
if (!stat.isFile()) return true;
|
|
265
|
+
return stat.size < 8;
|
|
266
|
+
} catch {
|
|
267
|
+
return true;
|
|
268
|
+
}
|
|
269
|
+
}
|
|
270
|
+
|
|
271
|
+
function ensureCliWrappers({ fsModule = fs, pathModule = path, logger } = {}) {
|
|
272
|
+
const log = logger || console;
|
|
273
|
+
const binDir = pathModule.join(__dirname, "..", "bin");
|
|
274
|
+
const wrappers = [
|
|
275
|
+
{ path: pathModule.join(binDir, "docdex.js"), contents: CLI_WRAPPER_SCRIPT },
|
|
276
|
+
{ path: pathModule.join(binDir, "docdex-mcp-stdio.js"), contents: MCP_STDIO_WRAPPER_SCRIPT }
|
|
277
|
+
];
|
|
278
|
+
|
|
279
|
+
try {
|
|
280
|
+
fsModule.mkdirSync(binDir, { recursive: true });
|
|
281
|
+
} catch (err) {
|
|
282
|
+
log?.warn?.(`[docdex] unable to ensure CLI wrappers (mkdir failed): ${err?.message || err}`);
|
|
283
|
+
return false;
|
|
284
|
+
}
|
|
285
|
+
|
|
286
|
+
let repaired = 0;
|
|
287
|
+
for (const wrapper of wrappers) {
|
|
288
|
+
if (!shouldWriteWrapper(fsModule, wrapper.path)) continue;
|
|
289
|
+
try {
|
|
290
|
+
fsModule.writeFileSync(wrapper.path, wrapper.contents, "utf8");
|
|
291
|
+
if (process.platform !== "win32" && fsModule.chmodSync) {
|
|
292
|
+
fsModule.chmodSync(wrapper.path, 0o755);
|
|
293
|
+
}
|
|
294
|
+
repaired += 1;
|
|
295
|
+
} catch (err) {
|
|
296
|
+
log?.warn?.(`[docdex] unable to write CLI wrapper at ${wrapper.path}: ${err?.message || err}`);
|
|
297
|
+
}
|
|
298
|
+
}
|
|
299
|
+
|
|
300
|
+
if (repaired > 0) {
|
|
301
|
+
log?.warn?.(`[docdex] restored ${repaired} CLI wrapper(s) under ${binDir}`);
|
|
302
|
+
}
|
|
303
|
+
return repaired > 0;
|
|
304
|
+
}
|
|
305
|
+
|
|
234
306
|
function selectHttpClient(url) {
|
|
235
307
|
try {
|
|
236
308
|
const protocol = new URL(url).protocol;
|
|
@@ -421,6 +493,38 @@ function nowIso() {
|
|
|
421
493
|
return new Date().toISOString();
|
|
422
494
|
}
|
|
423
495
|
|
|
496
|
+
function sleep(ms) {
|
|
497
|
+
return new Promise((resolve) => setTimeout(resolve, ms));
|
|
498
|
+
}
|
|
499
|
+
|
|
500
|
+
function isRetryableFsError(err) {
|
|
501
|
+
if (!err || typeof err !== "object") return false;
|
|
502
|
+
const code = err.code;
|
|
503
|
+
return code === "EPERM" || code === "EACCES" || code === "EBUSY" || code === "ENOTEMPTY";
|
|
504
|
+
}
|
|
505
|
+
|
|
506
|
+
async function withWindowsRetry(fn, { attempts = 6, delayMs = 50 } = {}) {
|
|
507
|
+
if (process.platform !== "win32") {
|
|
508
|
+
return fn();
|
|
509
|
+
}
|
|
510
|
+
let lastErr = null;
|
|
511
|
+
for (let attempt = 0; attempt < attempts; attempt += 1) {
|
|
512
|
+
try {
|
|
513
|
+
return await fn();
|
|
514
|
+
} catch (err) {
|
|
515
|
+
lastErr = err;
|
|
516
|
+
if (!isRetryableFsError(err)) throw err;
|
|
517
|
+
const waitMs = delayMs * Math.pow(2, attempt);
|
|
518
|
+
await sleep(waitMs);
|
|
519
|
+
}
|
|
520
|
+
}
|
|
521
|
+
throw lastErr;
|
|
522
|
+
}
|
|
523
|
+
|
|
524
|
+
async function renameWithRetry(fsModule, fromPath, toPath) {
|
|
525
|
+
return withWindowsRetry(() => fsModule.promises.rename(fromPath, toPath));
|
|
526
|
+
}
|
|
527
|
+
|
|
424
528
|
async function readJsonFileIfPossible({ fsModule, filePath }) {
|
|
425
529
|
if (!fsModule?.promises?.readFile) {
|
|
426
530
|
return { value: null, error: "readFile_unavailable", errorCode: "READFILE_UNAVAILABLE" };
|
|
@@ -447,7 +551,7 @@ async function writeJsonFileAtomic({ fsModule, pathModule, filePath, value }) {
|
|
|
447
551
|
const tmp = `${filePath}.${process.pid}.${Date.now()}.tmp`;
|
|
448
552
|
const payload = `${JSON.stringify(value, null, 2)}\n`;
|
|
449
553
|
await fsModule.promises.writeFile(tmp, payload, "utf8");
|
|
450
|
-
await fsModule
|
|
554
|
+
await renameWithRetry(fsModule, tmp, filePath);
|
|
451
555
|
}
|
|
452
556
|
|
|
453
557
|
function isValidInstallMetadata(meta) {
|
|
@@ -605,7 +709,7 @@ async function installFromLocalBinary({
|
|
|
605
709
|
writeJsonFileAtomicFn,
|
|
606
710
|
logger
|
|
607
711
|
}) {
|
|
608
|
-
await fsModule.promises.rm(distDir, { recursive: true, force: true });
|
|
712
|
+
await withWindowsRetry(() => fsModule.promises.rm(distDir, { recursive: true, force: true }));
|
|
609
713
|
await fsModule.promises.mkdir(distDir, { recursive: true });
|
|
610
714
|
const filename = isWin32 ? "docdexd.exe" : "docdexd";
|
|
611
715
|
const destPath = pathModule.join(distDir, filename);
|
|
@@ -723,7 +827,7 @@ function failedDirName({ distDir, nonce }) {
|
|
|
723
827
|
async function removeDirSafe(fsModule, dirPath) {
|
|
724
828
|
if (!dirPath) return false;
|
|
725
829
|
try {
|
|
726
|
-
await fsModule.promises.rm(dirPath, { recursive: true, force: true });
|
|
830
|
+
await withWindowsRetry(() => fsModule.promises.rm(dirPath, { recursive: true, force: true }));
|
|
727
831
|
return true;
|
|
728
832
|
} catch {
|
|
729
833
|
return false;
|
|
@@ -865,7 +969,7 @@ async function recoverInterruptedInstall({ fsModule, pathModule, distDir, isWin3
|
|
|
865
969
|
const candidate = await selectLatestCandidate(fsModule, backups);
|
|
866
970
|
if (candidate) {
|
|
867
971
|
try {
|
|
868
|
-
await fsModule
|
|
972
|
+
await renameWithRetry(fsModule, candidate.path, distDir);
|
|
869
973
|
recoveredFrom = candidate.path;
|
|
870
974
|
action = "recovered";
|
|
871
975
|
} catch (err) {
|
|
@@ -2002,11 +2106,11 @@ async function runInstaller(options) {
|
|
|
2002
2106
|
|
|
2003
2107
|
if (existsSync && existsSync(distDir)) {
|
|
2004
2108
|
await fsModule.promises.rm(backupDir, { recursive: true, force: true }).catch(() => {});
|
|
2005
|
-
await fsModule
|
|
2109
|
+
await renameWithRetry(fsModule, distDir, backupDir);
|
|
2006
2110
|
backupMoved = true;
|
|
2007
2111
|
}
|
|
2008
2112
|
|
|
2009
|
-
await fsModule
|
|
2113
|
+
await renameWithRetry(fsModule, stagingDir, distDir);
|
|
2010
2114
|
promoted = true;
|
|
2011
2115
|
|
|
2012
2116
|
if (typeof restartFn === "function") {
|
|
@@ -2076,7 +2180,7 @@ async function runInstaller(options) {
|
|
|
2076
2180
|
if (existsSync(distDir)) {
|
|
2077
2181
|
await fsModule.promises.rm(distDir, { recursive: true, force: true });
|
|
2078
2182
|
}
|
|
2079
|
-
await fsModule
|
|
2183
|
+
await renameWithRetry(fsModule, backupDir, distDir);
|
|
2080
2184
|
rollbackStatus = "restored previous installation";
|
|
2081
2185
|
rollbackSucceeded = true;
|
|
2082
2186
|
} else if (promoted && !backupMoved) {
|
|
@@ -2137,6 +2241,11 @@ async function main() {
|
|
|
2137
2241
|
const env = process.env;
|
|
2138
2242
|
const distBaseCandidates = resolveDistBaseCandidates({ env });
|
|
2139
2243
|
const distBaseDir = resolveDistBaseDir({ env, fsModule: fs });
|
|
2244
|
+
try {
|
|
2245
|
+
ensureCliWrappers({ logger: console });
|
|
2246
|
+
} catch (err) {
|
|
2247
|
+
console.warn(`[docdex] CLI wrapper check failed: ${err?.message || err}`);
|
|
2248
|
+
}
|
|
2140
2249
|
if (
|
|
2141
2250
|
process.platform === "win32" &&
|
|
2142
2251
|
!env?.DOCDEX_DIST_DIR &&
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
"use strict";
|
|
3
|
+
|
|
4
|
+
const { runBridge } = require("./mcp_stdio_bridge");
|
|
5
|
+
|
|
6
|
+
async function main() {
|
|
7
|
+
try {
|
|
8
|
+
await runBridge({ stdin: process.stdin, stdout: process.stdout, stderr: process.stderr });
|
|
9
|
+
} catch (err) {
|
|
10
|
+
process.stderr.write(`[docdex-mcp-stdio] fatal: ${err}\n`);
|
|
11
|
+
process.exit(1);
|
|
12
|
+
}
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
main();
|
package/package.json
CHANGED
|
@@ -1,12 +1,12 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "docdex",
|
|
3
|
-
"version": "0.2.
|
|
3
|
+
"version": "0.2.32",
|
|
4
4
|
"mcpName": "io.github.bekirdag/docdex",
|
|
5
5
|
"description": "Local-first documentation and code indexer with HTTP/MCP search, AST, and agent memory.",
|
|
6
6
|
"bin": {
|
|
7
|
-
"docdex": "
|
|
8
|
-
"docdexd": "
|
|
9
|
-
"docdex-mcp-stdio": "
|
|
7
|
+
"docdex": "lib/cli_entry.js",
|
|
8
|
+
"docdexd": "lib/cli_entry.js",
|
|
9
|
+
"docdex-mcp-stdio": "lib/mcp_stdio_cli.js"
|
|
10
10
|
},
|
|
11
11
|
"files": [
|
|
12
12
|
"bin",
|