docdex 0.2.39 → 0.2.40

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/assets/agents.md CHANGED
@@ -1,4 +1,4 @@
1
- ---- START OF DOCDEX INFO V0.2.39 ----
1
+ ---- START OF DOCDEX INFO V0.2.40 ----
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`).
@@ -177,7 +177,7 @@ This section is the authoritative source for how to call Docdex. Do not guess fi
177
177
 
178
178
  - Default HTTP base URL: http://127.0.0.1:28491 (override with DOCDEX_HTTP_BASE_URL).
179
179
  - Single-repo HTTP daemon: `docdexd serve --repo /abs/path`. /v1/initialize is NOT used. repo_id is optional, but must match the serving repo if provided.
180
- - Multi-repo HTTP daemon: `docdexd daemon`. You MUST call /v1/initialize before repo-scoped HTTP endpoints. When multiple repos are mounted, repo_id is required on every repo-scoped request.
180
+ - Multi-repo HTTP daemon: `docdexd daemon` (alias: `docdex start`). You MUST call /v1/initialize before repo-scoped HTTP endpoints. When multiple repos are mounted, repo_id is required on every repo-scoped request.
181
181
 
182
182
  ### 1) Initialize (HTTP) - exact request payload
183
183
 
@@ -2283,9 +2283,11 @@ function writeWindowsSetupRunner({ binaryPath, args, logger, distBaseDir } = {})
2283
2283
  }
2284
2284
  }
2285
2285
 
2286
- function registerStartup({ binaryPath, port, repoRoot, logger, distBaseDir }) {
2286
+ function registerStartup({ binaryPath, port, repoRoot, logger, distBaseDir, startNow = true }) {
2287
2287
  if (!binaryPath) return { ok: false, reason: "missing_binary" };
2288
- stopDaemonService({ logger });
2288
+ if (startNow) {
2289
+ stopDaemonService({ logger });
2290
+ }
2289
2291
  const envPairs = buildDaemonEnvPairs();
2290
2292
  const workingDir = repoRoot ? path.resolve(repoRoot) : null;
2291
2293
  const args = [
@@ -2337,6 +2339,7 @@ function registerStartup({ binaryPath, port, repoRoot, logger, distBaseDir }) {
2337
2339
  `</plist>\n`;
2338
2340
  fs.mkdirSync(path.dirname(plistPath), { recursive: true });
2339
2341
  fs.writeFileSync(plistPath, plist);
2342
+ if (!startNow) return { ok: true };
2340
2343
  const uid = typeof process.getuid === "function" ? process.getuid() : null;
2341
2344
  const bootstrap = uid != null
2342
2345
  ? spawnSync("launchctl", ["bootstrap", `gui/${uid}`, plistPath])
@@ -2371,7 +2374,11 @@ function registerStartup({ binaryPath, port, repoRoot, logger, distBaseDir }) {
2371
2374
  ].filter(Boolean).join("\n");
2372
2375
  fs.writeFileSync(unitPath, unit);
2373
2376
  const reload = spawnSync("systemctl", ["--user", "daemon-reload"]);
2374
- const enable = spawnSync("systemctl", ["--user", "enable", "--now", "docdexd.service"]);
2377
+ const enableArgs = startNow
2378
+ ? ["--user", "enable", "--now", "docdexd.service"]
2379
+ : ["--user", "enable", "docdexd.service"];
2380
+ const enable = spawnSync("systemctl", enableArgs);
2381
+ ensureSystemdUserLinger({ logger });
2375
2382
  if (reload.status === 0 && enable.status === 0) return { ok: true };
2376
2383
  logger?.warn?.(`[docdex] systemd failed: ${enable.stderr || reload.stderr || "unknown error"}`);
2377
2384
  return { ok: false, reason: "systemd_failed" };
@@ -2402,7 +2409,9 @@ function registerStartup({ binaryPath, port, repoRoot, logger, distBaseDir }) {
2402
2409
  taskArgs
2403
2410
  ]);
2404
2411
  if (create.status === 0) {
2405
- spawnSync("schtasks", ["/Run", "/TN", taskName]);
2412
+ if (startNow) {
2413
+ spawnSync("schtasks", ["/Run", "/TN", taskName]);
2414
+ }
2406
2415
  return { ok: true };
2407
2416
  }
2408
2417
  logger?.warn?.(`[docdex] schtasks failed: ${create.stderr || "unknown error"}`);
@@ -2412,18 +2421,22 @@ function registerStartup({ binaryPath, port, repoRoot, logger, distBaseDir }) {
2412
2421
  return { ok: false, reason: "unsupported_platform" };
2413
2422
  }
2414
2423
 
2415
- async function startDaemonWithHealthCheck({ binaryPath, port, host, logger, distBaseDir }) {
2424
+ async function startDaemonWithHealthCheck({ binaryPath, port, host, logger, distBaseDir, startNow = true }) {
2416
2425
  const startup = registerStartup({
2417
2426
  binaryPath,
2418
2427
  port,
2419
2428
  repoRoot: daemonRootPath(),
2420
2429
  logger,
2421
- distBaseDir
2430
+ distBaseDir,
2431
+ startNow
2422
2432
  });
2423
2433
  if (!startup.ok) {
2424
2434
  logger?.warn?.(`[docdex] daemon service registration failed (${startup.reason || "unknown"}).`);
2425
2435
  return { ok: false, reason: "startup_failed" };
2426
2436
  }
2437
+ if (!startNow) {
2438
+ return { ok: true, reason: "registered" };
2439
+ }
2427
2440
  startDaemonService({ logger });
2428
2441
  const healthy = await waitForDaemonHealthy({ host, port });
2429
2442
  if (healthy) {
@@ -2478,6 +2491,25 @@ function commandExists(cmd, spawnSyncFn) {
2478
2491
  return true;
2479
2492
  }
2480
2493
 
2494
+ function currentUsername() {
2495
+ try {
2496
+ const info = os.userInfo();
2497
+ if (info && info.username) return info.username;
2498
+ } catch {}
2499
+ return process.env.USER || process.env.LOGNAME || process.env.USERNAME || null;
2500
+ }
2501
+
2502
+ function ensureSystemdUserLinger({ logger } = {}) {
2503
+ if (process.platform !== "linux") return { ok: false, reason: "unsupported_platform" };
2504
+ if (!commandExists("loginctl", spawnSync)) return { ok: false, reason: "loginctl_missing" };
2505
+ const username = currentUsername();
2506
+ if (!username) return { ok: false, reason: "username_missing" };
2507
+ const result = spawnSync("loginctl", ["enable-linger", username]);
2508
+ if (result.status === 0) return { ok: true };
2509
+ logger?.warn?.(`[docdex] loginctl enable-linger failed: ${result.stderr || "unknown error"}`);
2510
+ return { ok: false, reason: "loginctl_failed" };
2511
+ }
2512
+
2481
2513
  function launchMacTerminal({ binaryPath, args, spawnSyncFn, logger }) {
2482
2514
  const command = [
2483
2515
  "DOCDEX_SETUP_AUTO=1",
@@ -2665,14 +2697,15 @@ async function runPostInstallSetup({ binaryPath, logger, env, skipDaemon, distBa
2665
2697
  }
2666
2698
  }
2667
2699
  }
2668
- let startupOk = reuseExisting;
2669
- if (allowDaemon && !reuseExisting) {
2700
+ let startupOk = false;
2701
+ if (allowDaemon) {
2670
2702
  const result = await startDaemonWithHealthCheck({
2671
2703
  binaryPath: startupBinaries.binaryPath,
2672
2704
  port,
2673
2705
  host: DEFAULT_HOST,
2674
2706
  logger: log,
2675
- distBaseDir: resolvedDistBaseDir
2707
+ distBaseDir: resolvedDistBaseDir,
2708
+ startNow: !reuseExisting
2676
2709
  });
2677
2710
  if (!result.ok) {
2678
2711
  log.warn?.(`[docdex] daemon failed to start on ${DEFAULT_HOST}:${port}.`);
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "docdex",
3
- "version": "0.2.39",
3
+ "version": "0.2.40",
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": {