docdex 0.2.39 → 0.2.41
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 +5 -0
- package/assets/agents.md +5 -3
- package/lib/install.js +10 -0
- package/lib/postinstall_setup.js +53 -11
- package/package.json +1 -1
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,10 @@
|
|
|
1
1
|
# Changelog
|
|
2
2
|
|
|
3
|
+
## 0.2.41
|
|
4
|
+
- Improve Windows npm postinstall UX with a plain setup hint, npm lifecycle non-interactive detection, and no empty cmd window from immediate daemon start.
|
|
5
|
+
- Fix setup TUI menu selection highlighting on Windows terminals.
|
|
6
|
+
- Propagate DAG session IDs in docs so `docdex_dag_export` is called with the `dag_session_id` from search results.
|
|
7
|
+
|
|
3
8
|
## 0.2.39
|
|
4
9
|
- Bump release metadata to 0.2.39.
|
|
5
10
|
|
package/assets/agents.md
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
---- START OF DOCDEX INFO V0.2.
|
|
1
|
+
---- START OF DOCDEX INFO V0.2.41 ----
|
|
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
|
|
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
|
|
|
@@ -246,6 +246,8 @@ Query params:
|
|
|
246
246
|
- `format` (optional: json/text/dot; default json)
|
|
247
247
|
- `max_nodes` (optional)
|
|
248
248
|
- `repo_id` (required when multiple repos are mounted)
|
|
249
|
+
Notes:
|
|
250
|
+
- Use the `dag_session_id` from `/search` responses (or MCP `docdex_search`/`docdex_web_research`) as the `session_id`. `dag_session_id` is accepted as an alias.
|
|
249
251
|
|
|
250
252
|
### 7) MCP over HTTP/SSE
|
|
251
253
|
|
|
@@ -270,7 +272,7 @@ Do not guess fields; use these canonical shapes.
|
|
|
270
272
|
- `docdex_ast`: `{ project_root, path, max_nodes? }`
|
|
271
273
|
- `docdex_impact_diagnostics`: `{ project_root, file? }`
|
|
272
274
|
- `docdex_impact_graph`: `{ project_root, file, max_edges?, max_depth?, edge_types? }`
|
|
273
|
-
- `docdex_dag_export`: `{ project_root, session_id, format?, max_nodes? }`
|
|
275
|
+
- `docdex_dag_export`: `{ project_root, session_id|dag_session_id, format?, max_nodes? }`
|
|
274
276
|
- `docdex_memory_save`: `{ project_root, text }`
|
|
275
277
|
- `docdex_memory_recall`: `{ project_root, query, top_k? }`
|
|
276
278
|
- `docdex_get_profile`: `{ agent_id }`
|
package/lib/install.js
CHANGED
|
@@ -2294,6 +2294,16 @@ function printPostInstallBanner() {
|
|
|
2294
2294
|
return false;
|
|
2295
2295
|
}
|
|
2296
2296
|
};
|
|
2297
|
+
if (process.platform === "win32") {
|
|
2298
|
+
const plain = [
|
|
2299
|
+
"[docdex] Docdex installed successfully.",
|
|
2300
|
+
"[docdex] Next step: run `docdex setup` to complete the installation.",
|
|
2301
|
+
"[docdex] Setup configures Ollama/models + browser."
|
|
2302
|
+
].join("\r\n") + "\r\n";
|
|
2303
|
+
if (!writeDirect(plain)) {
|
|
2304
|
+
writeStderr(plain);
|
|
2305
|
+
}
|
|
2306
|
+
}
|
|
2297
2307
|
let width = 0;
|
|
2298
2308
|
const content = [
|
|
2299
2309
|
"\x1b[31m _ _ \x1b[0m",
|
package/lib/postinstall_setup.js
CHANGED
|
@@ -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
|
-
|
|
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
|
|
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
|
-
|
|
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) {
|
|
@@ -2459,7 +2472,11 @@ function startupFailureReported() {
|
|
|
2459
2472
|
}
|
|
2460
2473
|
|
|
2461
2474
|
function isNpmLifecycle(env = process.env) {
|
|
2462
|
-
|
|
2475
|
+
if (env?.npm_lifecycle_event) return true;
|
|
2476
|
+
const userAgent = String(env?.npm_config_user_agent || "");
|
|
2477
|
+
if (userAgent.includes("npm/")) return true;
|
|
2478
|
+
if (env?.npm_execpath) return true;
|
|
2479
|
+
return false;
|
|
2463
2480
|
}
|
|
2464
2481
|
|
|
2465
2482
|
function shouldSkipDaemonSideEffects({ env = process.env, skipDaemon } = {}) {
|
|
@@ -2478,6 +2495,25 @@ function commandExists(cmd, spawnSyncFn) {
|
|
|
2478
2495
|
return true;
|
|
2479
2496
|
}
|
|
2480
2497
|
|
|
2498
|
+
function currentUsername() {
|
|
2499
|
+
try {
|
|
2500
|
+
const info = os.userInfo();
|
|
2501
|
+
if (info && info.username) return info.username;
|
|
2502
|
+
} catch {}
|
|
2503
|
+
return process.env.USER || process.env.LOGNAME || process.env.USERNAME || null;
|
|
2504
|
+
}
|
|
2505
|
+
|
|
2506
|
+
function ensureSystemdUserLinger({ logger } = {}) {
|
|
2507
|
+
if (process.platform !== "linux") return { ok: false, reason: "unsupported_platform" };
|
|
2508
|
+
if (!commandExists("loginctl", spawnSync)) return { ok: false, reason: "loginctl_missing" };
|
|
2509
|
+
const username = currentUsername();
|
|
2510
|
+
if (!username) return { ok: false, reason: "username_missing" };
|
|
2511
|
+
const result = spawnSync("loginctl", ["enable-linger", username]);
|
|
2512
|
+
if (result.status === 0) return { ok: true };
|
|
2513
|
+
logger?.warn?.(`[docdex] loginctl enable-linger failed: ${result.stderr || "unknown error"}`);
|
|
2514
|
+
return { ok: false, reason: "loginctl_failed" };
|
|
2515
|
+
}
|
|
2516
|
+
|
|
2481
2517
|
function launchMacTerminal({ binaryPath, args, spawnSyncFn, logger }) {
|
|
2482
2518
|
const command = [
|
|
2483
2519
|
"DOCDEX_SETUP_AUTO=1",
|
|
@@ -2558,6 +2594,9 @@ function launchSetupWizard({
|
|
|
2558
2594
|
}
|
|
2559
2595
|
|
|
2560
2596
|
if (platform === "win32") {
|
|
2597
|
+
if (!canPrompt(stdin, stdout)) {
|
|
2598
|
+
return { ok: false, reason: "non_interactive" };
|
|
2599
|
+
}
|
|
2561
2600
|
const runnerPath = writeWindowsSetupRunner({
|
|
2562
2601
|
binaryPath,
|
|
2563
2602
|
args,
|
|
@@ -2584,6 +2623,7 @@ function launchSetupWizard({
|
|
|
2584
2623
|
async function runPostInstallSetup({ binaryPath, logger, env, skipDaemon, distBaseDir } = {}) {
|
|
2585
2624
|
const log = logger || console;
|
|
2586
2625
|
const effectiveEnv = env || process.env;
|
|
2626
|
+
const isNpm = isNpmLifecycle(effectiveEnv);
|
|
2587
2627
|
const distCandidates = resolveDistBaseCandidates({ env: effectiveEnv });
|
|
2588
2628
|
const resolvedDistBaseDir = distBaseDir || resolveDistBaseDir({ env: effectiveEnv, fsModule: fs });
|
|
2589
2629
|
let allowDaemon = !shouldSkipDaemonSideEffects({ env: effectiveEnv, skipDaemon });
|
|
@@ -2665,14 +2705,16 @@ async function runPostInstallSetup({ binaryPath, logger, env, skipDaemon, distBa
|
|
|
2665
2705
|
}
|
|
2666
2706
|
}
|
|
2667
2707
|
}
|
|
2668
|
-
let startupOk =
|
|
2669
|
-
if (allowDaemon
|
|
2708
|
+
let startupOk = false;
|
|
2709
|
+
if (allowDaemon) {
|
|
2710
|
+
const allowStartNow = !(process.platform === "win32" && isNpm);
|
|
2670
2711
|
const result = await startDaemonWithHealthCheck({
|
|
2671
2712
|
binaryPath: startupBinaries.binaryPath,
|
|
2672
2713
|
port,
|
|
2673
2714
|
host: DEFAULT_HOST,
|
|
2674
2715
|
logger: log,
|
|
2675
|
-
distBaseDir: resolvedDistBaseDir
|
|
2716
|
+
distBaseDir: resolvedDistBaseDir,
|
|
2717
|
+
startNow: !reuseExisting && allowStartNow
|
|
2676
2718
|
});
|
|
2677
2719
|
if (!result.ok) {
|
|
2678
2720
|
log.warn?.(`[docdex] daemon failed to start on ${DEFAULT_HOST}:${port}.`);
|
|
@@ -2717,7 +2759,7 @@ async function runPostInstallSetup({ binaryPath, logger, env, skipDaemon, distBa
|
|
|
2717
2759
|
clearStartupFailure();
|
|
2718
2760
|
}
|
|
2719
2761
|
const skipExplicit = shouldSkipSetup(effectiveEnv);
|
|
2720
|
-
const skipWizard =
|
|
2762
|
+
const skipWizard = isNpm || skipExplicit;
|
|
2721
2763
|
const setupLaunch = skipWizard
|
|
2722
2764
|
? { ok: false, reason: skipExplicit ? "skipped" : "npm_lifecycle" }
|
|
2723
2765
|
: launchSetupWizard({
|