docdex 0.2.35 → 0.2.37
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 +6 -0
- package/assets/agents.md +3 -2
- package/lib/install.js +1 -1
- package/lib/postinstall_setup.js +98 -1
- package/package.json +2 -2
package/CHANGELOG.md
CHANGED
package/assets/agents.md
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
---- START OF DOCDEX INFO V0.2.
|
|
1
|
+
---- START OF DOCDEX INFO V0.2.37 ----
|
|
2
2
|
Docdex URL: http://127.0.0.1:28491
|
|
3
3
|
Use this base URL for Docdex HTTP endpoints.
|
|
4
4
|
Health check endpoint: `GET /healthz` (not `/v1/health`).
|
|
@@ -6,6 +6,7 @@ Health check endpoint: `GET /healthz` (not `/v1/health`).
|
|
|
6
6
|
## Priority Directives (Mandatory)
|
|
7
7
|
|
|
8
8
|
- Always use both memory lobes early: docdex_get_profile + docdex_memory_recall; save new facts via docdex_memory_save and new preferences via docdex_save_preference.
|
|
9
|
+
- Profile memory is always-on and global; never gate on DOCDEX_ENABLE_MEMORY or repo state. docdex_save_preference must persist (fallback if embeddings/LLM unavailable). If profile calls fail, treat it as a bug.
|
|
9
10
|
- Maintain agent-specific profile memory: use your agent_id with docdex_get_profile/docdex_save_preference; store generic self-knowledge (role, tooling, preferences).
|
|
10
11
|
- Use impact analysis for every code change: prefer MCP tools `docdex_impact_graph` / `docdex_dag_export` (IPC/HTTP). If shell networking is blocked, do not use curl; use MCP/IPC instead. If unavailable, state it and proceed cautiously.
|
|
11
12
|
- Apply DAG reasoning for planning: prefer dependency graph facts (impact results and /v1/dag/export) to choose the right change order and scope.
|
|
@@ -250,7 +251,7 @@ Query params:
|
|
|
250
251
|
|
|
251
252
|
- SSE: `/v1/mcp/sse` + `/v1/mcp/message`. When multiple repos are mounted, initialize with `rootUri` first.
|
|
252
253
|
- HTTP: `/v1/mcp` accepts repo context in the payload or via prior initialize.
|
|
253
|
-
- If HTTP/SSE is unreachable (sandboxed clients), fall back to local IPC: configure `transport = "ipc"` with `socket_path` (Unix) or `pipe_name` (Windows) and send MCP JSON-RPC to `/v1/mcp` over IPC.
|
|
254
|
+
- If HTTP/SSE is unreachable or fails (e.g., connection refused or sandboxed clients), fall back to local IPC: configure `transport = "ipc"` with `socket_path` (Unix) or `pipe_name` (Windows) and send MCP JSON-RPC to `/v1/mcp` over IPC.
|
|
254
255
|
- For stdio-only clients (e.g., Smithery), use the `docdex-mcp-stdio` entrypoint to bridge stdio JSON-RPC to Docdex MCP.
|
|
255
256
|
- For impact/DAG in sandboxed shells, prefer MCP/IPC tools over `curl` to `/v1/graph/impact` or `/v1/dag/export`.
|
|
256
257
|
- MCP tools: `docdex_impact_graph` (impact traversal) and `docdex_dag_export` (DAG export).
|
package/lib/install.js
CHANGED
|
@@ -2258,7 +2258,7 @@ async function main() {
|
|
|
2258
2258
|
}
|
|
2259
2259
|
const result = await runInstaller({ env, distBaseDir });
|
|
2260
2260
|
try {
|
|
2261
|
-
const skipDaemon =
|
|
2261
|
+
const skipDaemon = parseEnvBool(env?.DOCDEX_DAEMON_SKIP_SETUP);
|
|
2262
2262
|
await runPostInstallSetup({ binaryPath: result?.binaryPath, env, skipDaemon, distBaseDir });
|
|
2263
2263
|
} catch (err) {
|
|
2264
2264
|
console.warn(`[docdex] postinstall setup failed: ${err?.message || err}`);
|
package/lib/postinstall_setup.js
CHANGED
|
@@ -313,6 +313,73 @@ function stopDaemonService({ logger } = {}) {
|
|
|
313
313
|
return false;
|
|
314
314
|
}
|
|
315
315
|
|
|
316
|
+
function removeDaemonService({ logger, distBaseDir, env } = {}) {
|
|
317
|
+
if (process.platform === "darwin") {
|
|
318
|
+
const uid = typeof process.getuid === "function" ? process.getuid() : null;
|
|
319
|
+
const domain = uid != null ? `gui/${uid}` : null;
|
|
320
|
+
const plistPath = path.join(os.homedir(), "Library", "LaunchAgents", "com.docdex.daemon.plist");
|
|
321
|
+
const systemPlistPath = "/Library/LaunchDaemons/com.docdex.daemon.plist";
|
|
322
|
+
if (domain) {
|
|
323
|
+
spawnSync("launchctl", ["bootout", domain, "com.docdex.daemon"]);
|
|
324
|
+
spawnSync("launchctl", ["bootout", domain, plistPath]);
|
|
325
|
+
} else {
|
|
326
|
+
spawnSync("launchctl", ["bootout", "com.docdex.daemon"]);
|
|
327
|
+
spawnSync("launchctl", ["bootout", plistPath]);
|
|
328
|
+
}
|
|
329
|
+
spawnSync("launchctl", ["remove", "com.docdex.daemon"]);
|
|
330
|
+
spawnSync("launchctl", ["unload", "-w", plistPath]);
|
|
331
|
+
if (fs.existsSync(plistPath)) {
|
|
332
|
+
try {
|
|
333
|
+
fs.unlinkSync(plistPath);
|
|
334
|
+
} catch (err) {
|
|
335
|
+
logger?.warn?.(`[docdex] failed to remove LaunchAgent plist: ${err?.message || err}`);
|
|
336
|
+
}
|
|
337
|
+
}
|
|
338
|
+
if (fs.existsSync(systemPlistPath)) {
|
|
339
|
+
spawnSync("launchctl", ["bootout", "system", systemPlistPath]);
|
|
340
|
+
spawnSync("launchctl", ["remove", "com.docdex.daemon"]);
|
|
341
|
+
try {
|
|
342
|
+
fs.unlinkSync(systemPlistPath);
|
|
343
|
+
} catch (err) {
|
|
344
|
+
logger?.warn?.(`[docdex] failed to remove LaunchDaemon plist: ${err?.message || err}`);
|
|
345
|
+
}
|
|
346
|
+
}
|
|
347
|
+
return true;
|
|
348
|
+
}
|
|
349
|
+
if (process.platform === "linux") {
|
|
350
|
+
const systemdDir = path.join(os.homedir(), ".config", "systemd", "user");
|
|
351
|
+
const unitPath = path.join(systemdDir, "docdexd.service");
|
|
352
|
+
spawnSync("systemctl", ["--user", "stop", "docdexd.service"]);
|
|
353
|
+
spawnSync("systemctl", ["--user", "disable", "--now", "docdexd.service"]);
|
|
354
|
+
spawnSync("systemctl", ["--user", "reset-failed", "docdexd.service"]);
|
|
355
|
+
if (fs.existsSync(unitPath)) {
|
|
356
|
+
try {
|
|
357
|
+
fs.unlinkSync(unitPath);
|
|
358
|
+
} catch (err) {
|
|
359
|
+
logger?.warn?.(`[docdex] failed to remove systemd unit: ${err?.message || err}`);
|
|
360
|
+
}
|
|
361
|
+
spawnSync("systemctl", ["--user", "daemon-reload"]);
|
|
362
|
+
}
|
|
363
|
+
return true;
|
|
364
|
+
}
|
|
365
|
+
if (process.platform === "win32") {
|
|
366
|
+
const taskName = "Docdex Daemon";
|
|
367
|
+
spawnSync("schtasks", ["/End", "/TN", taskName]);
|
|
368
|
+
spawnSync("schtasks", ["/Delete", "/TN", taskName, "/F"]);
|
|
369
|
+
const resolvedDistBaseDir = distBaseDir || resolveDistBaseDir({ env, fsModule: fs });
|
|
370
|
+
const runnerPath = resolveWindowsRunnerPath({ distBaseDir: resolvedDistBaseDir, pathModule: path });
|
|
371
|
+
if (runnerPath && fs.existsSync(runnerPath)) {
|
|
372
|
+
try {
|
|
373
|
+
fs.unlinkSync(runnerPath);
|
|
374
|
+
} catch (err) {
|
|
375
|
+
logger?.warn?.(`[docdex] failed to remove Windows runner: ${err?.message || err}`);
|
|
376
|
+
}
|
|
377
|
+
}
|
|
378
|
+
return true;
|
|
379
|
+
}
|
|
380
|
+
return false;
|
|
381
|
+
}
|
|
382
|
+
|
|
316
383
|
function startDaemonService({ logger } = {}) {
|
|
317
384
|
if (process.platform === "darwin") {
|
|
318
385
|
const uid = typeof process.getuid === "function" ? process.getuid() : null;
|
|
@@ -356,6 +423,21 @@ function stopDaemonByName({ logger } = {}) {
|
|
|
356
423
|
return true;
|
|
357
424
|
}
|
|
358
425
|
|
|
426
|
+
async function cleanupExistingDaemon({ logger, env, distBaseDir, host, port } = {}) {
|
|
427
|
+
const log = logger || console;
|
|
428
|
+
stopDaemonService({ logger: log });
|
|
429
|
+
stopDaemonFromLock({ logger: log });
|
|
430
|
+
stopDaemonByName({ logger: log });
|
|
431
|
+
removeDaemonService({ logger: log, distBaseDir, env });
|
|
432
|
+
clearDaemonLocks();
|
|
433
|
+
if (!host || !port) return true;
|
|
434
|
+
const released = await waitForPortAvailable({ host, port });
|
|
435
|
+
if (!released) {
|
|
436
|
+
log.warn?.(`[docdex] ${host}:${port} still in use after daemon cleanup.`);
|
|
437
|
+
}
|
|
438
|
+
return released;
|
|
439
|
+
}
|
|
440
|
+
|
|
359
441
|
function clearDaemonLocks() {
|
|
360
442
|
let removed = false;
|
|
361
443
|
for (const lockPath of daemonLockPaths()) {
|
|
@@ -2360,7 +2442,6 @@ function isNpmLifecycle(env = process.env) {
|
|
|
2360
2442
|
|
|
2361
2443
|
function shouldSkipDaemonSideEffects({ env = process.env, skipDaemon } = {}) {
|
|
2362
2444
|
if (skipDaemon) return true;
|
|
2363
|
-
if (isNpmLifecycle(env)) return true;
|
|
2364
2445
|
if (parseEnvBool(env?.DOCDEX_DAEMON_SKIP_SETUP)) return true;
|
|
2365
2446
|
return false;
|
|
2366
2447
|
}
|
|
@@ -2478,6 +2559,22 @@ async function runPostInstallSetup({ binaryPath, logger, env, skipDaemon, distBa
|
|
|
2478
2559
|
}
|
|
2479
2560
|
const port = DEFAULT_DAEMON_PORT;
|
|
2480
2561
|
let portState = { available: true, reuseExisting: false };
|
|
2562
|
+
if (allowDaemon) {
|
|
2563
|
+
const cleaned = await cleanupExistingDaemon({
|
|
2564
|
+
logger: log,
|
|
2565
|
+
env: effectiveEnv,
|
|
2566
|
+
distBaseDir: resolvedDistBaseDir,
|
|
2567
|
+
host: DEFAULT_HOST,
|
|
2568
|
+
port
|
|
2569
|
+
});
|
|
2570
|
+
if (!cleaned) {
|
|
2571
|
+
log.warn?.(
|
|
2572
|
+
`[docdex] ${DEFAULT_HOST}:${port} is still in use after removing the daemon service; skipping daemon startup.`
|
|
2573
|
+
);
|
|
2574
|
+
recordStartupFailure({ reason: "port_in_use", host: DEFAULT_HOST, port });
|
|
2575
|
+
allowDaemon = false;
|
|
2576
|
+
}
|
|
2577
|
+
}
|
|
2481
2578
|
if (allowDaemon) {
|
|
2482
2579
|
portState = await resolveDaemonPortState({
|
|
2483
2580
|
host: DEFAULT_HOST,
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "docdex",
|
|
3
|
-
"version": "0.2.
|
|
3
|
+
"version": "0.2.37",
|
|
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": {
|
|
@@ -44,7 +44,7 @@
|
|
|
44
44
|
},
|
|
45
45
|
"homepage": "https://docdex.org",
|
|
46
46
|
"license": "MIT",
|
|
47
|
-
"author": "bekir
|
|
47
|
+
"author": "bekir dağ",
|
|
48
48
|
"keywords": [
|
|
49
49
|
"docdex",
|
|
50
50
|
"documentation",
|