docdex 0.2.37 → 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/CHANGELOG.md +6 -0
- package/assets/agents.md +6 -5
- package/lib/install.js +11 -1
- package/lib/paths.js +10 -1
- package/lib/postinstall_setup.js +95 -20
- package/package.json +1 -1
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.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
|
|
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
|
|
|
@@ -305,9 +305,10 @@ When answering a complex coding query, follow this "Reasoning Trace":
|
|
|
305
305
|
Save more memories for both lobes during the task, not just at the end.
|
|
306
306
|
|
|
307
307
|
1. Repo memory: After each meaningful discovery or code change, save at least one durable fact (file location, behavior, config, gotcha) via `docdex_memory_save`.
|
|
308
|
-
2.
|
|
309
|
-
3.
|
|
310
|
-
4.
|
|
308
|
+
2. Memory overrides: When a new repo memory replaces older facts, include `metadata.supersedes` with the prior memory id(s). Docdex marks the superseded entries with `supersededBy`/`supersededAtMs`, down-ranks them during recall, and they can be removed via `docdex memory compact` (dry-run unless `--apply`).
|
|
309
|
+
3. Profile memory: When the user expresses a preference, constraint, or workflow correction, call `docdex_save_preference` immediately with the right category.
|
|
310
|
+
4. Keep it crisp: 1-3 short sentences, include file paths when relevant, avoid raw code blobs.
|
|
311
|
+
5. Safety: Never store secrets, tokens, or sensitive user data. Skip transient or speculative info.
|
|
311
312
|
|
|
312
313
|
### 3. Index Health + Diff-Aware Search (Mandatory)
|
|
313
314
|
|
package/lib/install.js
CHANGED
|
@@ -2286,6 +2286,14 @@ function printPostInstallBanner() {
|
|
|
2286
2286
|
return false;
|
|
2287
2287
|
}
|
|
2288
2288
|
};
|
|
2289
|
+
const writeStderr = (message) => {
|
|
2290
|
+
try {
|
|
2291
|
+
process.stderr.write(message);
|
|
2292
|
+
return true;
|
|
2293
|
+
} catch {
|
|
2294
|
+
return false;
|
|
2295
|
+
}
|
|
2296
|
+
};
|
|
2289
2297
|
let width = 0;
|
|
2290
2298
|
const content = [
|
|
2291
2299
|
"\x1b[31m _ _ \x1b[0m",
|
|
@@ -2320,7 +2328,9 @@ function printPostInstallBanner() {
|
|
|
2320
2328
|
lines.push(bottom);
|
|
2321
2329
|
const banner = `\r\x1b[2K${lines.join("\n")}\n`;
|
|
2322
2330
|
if (!writeDirect(banner)) {
|
|
2323
|
-
|
|
2331
|
+
if (!writeStderr(banner)) {
|
|
2332
|
+
console.log(banner);
|
|
2333
|
+
}
|
|
2324
2334
|
}
|
|
2325
2335
|
}
|
|
2326
2336
|
|
package/lib/paths.js
CHANGED
|
@@ -102,11 +102,20 @@ function resolveWindowsRunnerPath(options = {}) {
|
|
|
102
102
|
return pathModule.join(resolveDocdexDataDir({ ...options, pathModule }), "run-daemon.cmd");
|
|
103
103
|
}
|
|
104
104
|
|
|
105
|
+
function resolveWindowsSetupRunnerPath(options = {}) {
|
|
106
|
+
const pathModule = options.pathModule || path;
|
|
107
|
+
if (options.distBaseDir) {
|
|
108
|
+
return pathModule.join(pathModule.dirname(options.distBaseDir), "run-setup.cmd");
|
|
109
|
+
}
|
|
110
|
+
return pathModule.join(resolveDocdexDataDir({ ...options, pathModule }), "run-setup.cmd");
|
|
111
|
+
}
|
|
112
|
+
|
|
105
113
|
module.exports = {
|
|
106
114
|
resolveUserDataDir,
|
|
107
115
|
resolveDocdexDataDir,
|
|
108
116
|
resolveDistBaseCandidates,
|
|
109
117
|
resolveDistBaseDir,
|
|
110
118
|
resolveBinDir,
|
|
111
|
-
resolveWindowsRunnerPath
|
|
119
|
+
resolveWindowsRunnerPath,
|
|
120
|
+
resolveWindowsSetupRunnerPath
|
|
112
121
|
};
|
package/lib/postinstall_setup.js
CHANGED
|
@@ -15,7 +15,8 @@ const {
|
|
|
15
15
|
resolveDistBaseDir,
|
|
16
16
|
resolveDistBaseCandidates,
|
|
17
17
|
resolveBinDir,
|
|
18
|
-
resolveWindowsRunnerPath
|
|
18
|
+
resolveWindowsRunnerPath,
|
|
19
|
+
resolveWindowsSetupRunnerPath
|
|
19
20
|
} = require("./paths");
|
|
20
21
|
|
|
21
22
|
const DEFAULT_HOST = "127.0.0.1";
|
|
@@ -2261,9 +2262,32 @@ function writeWindowsRunner({ binaryPath, args, envPairs, workingDir, logger, di
|
|
|
2261
2262
|
}
|
|
2262
2263
|
}
|
|
2263
2264
|
|
|
2264
|
-
function
|
|
2265
|
+
function writeWindowsSetupRunner({ binaryPath, args, logger, distBaseDir } = {}) {
|
|
2266
|
+
if (!binaryPath) return null;
|
|
2267
|
+
const runnerPath = resolveWindowsSetupRunnerPath({ distBaseDir });
|
|
2268
|
+
const lines = [
|
|
2269
|
+
"@echo off",
|
|
2270
|
+
"setlocal",
|
|
2271
|
+
"set \"DOCDEX_SETUP_AUTO=1\"",
|
|
2272
|
+
"set \"DOCDEX_SETUP_MODE=auto\""
|
|
2273
|
+
];
|
|
2274
|
+
const argString = (args || []).map((arg) => escapeCmdArg(arg)).join(" ");
|
|
2275
|
+
lines.push(`${escapeCmdArg(binaryPath)} ${argString}`.trim());
|
|
2276
|
+
try {
|
|
2277
|
+
fs.mkdirSync(path.dirname(runnerPath), { recursive: true });
|
|
2278
|
+
fs.writeFileSync(runnerPath, `${lines.join("\r\n")}\r\n`);
|
|
2279
|
+
return runnerPath;
|
|
2280
|
+
} catch (err) {
|
|
2281
|
+
logger?.warn?.(`[docdex] failed to write Windows setup runner: ${err?.message || err}`);
|
|
2282
|
+
return null;
|
|
2283
|
+
}
|
|
2284
|
+
}
|
|
2285
|
+
|
|
2286
|
+
function registerStartup({ binaryPath, port, repoRoot, logger, distBaseDir, startNow = true }) {
|
|
2265
2287
|
if (!binaryPath) return { ok: false, reason: "missing_binary" };
|
|
2266
|
-
|
|
2288
|
+
if (startNow) {
|
|
2289
|
+
stopDaemonService({ logger });
|
|
2290
|
+
}
|
|
2267
2291
|
const envPairs = buildDaemonEnvPairs();
|
|
2268
2292
|
const workingDir = repoRoot ? path.resolve(repoRoot) : null;
|
|
2269
2293
|
const args = [
|
|
@@ -2315,6 +2339,7 @@ function registerStartup({ binaryPath, port, repoRoot, logger, distBaseDir }) {
|
|
|
2315
2339
|
`</plist>\n`;
|
|
2316
2340
|
fs.mkdirSync(path.dirname(plistPath), { recursive: true });
|
|
2317
2341
|
fs.writeFileSync(plistPath, plist);
|
|
2342
|
+
if (!startNow) return { ok: true };
|
|
2318
2343
|
const uid = typeof process.getuid === "function" ? process.getuid() : null;
|
|
2319
2344
|
const bootstrap = uid != null
|
|
2320
2345
|
? spawnSync("launchctl", ["bootstrap", `gui/${uid}`, plistPath])
|
|
@@ -2349,7 +2374,11 @@ function registerStartup({ binaryPath, port, repoRoot, logger, distBaseDir }) {
|
|
|
2349
2374
|
].filter(Boolean).join("\n");
|
|
2350
2375
|
fs.writeFileSync(unitPath, unit);
|
|
2351
2376
|
const reload = spawnSync("systemctl", ["--user", "daemon-reload"]);
|
|
2352
|
-
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 });
|
|
2353
2382
|
if (reload.status === 0 && enable.status === 0) return { ok: true };
|
|
2354
2383
|
logger?.warn?.(`[docdex] systemd failed: ${enable.stderr || reload.stderr || "unknown error"}`);
|
|
2355
2384
|
return { ok: false, reason: "systemd_failed" };
|
|
@@ -2380,7 +2409,9 @@ function registerStartup({ binaryPath, port, repoRoot, logger, distBaseDir }) {
|
|
|
2380
2409
|
taskArgs
|
|
2381
2410
|
]);
|
|
2382
2411
|
if (create.status === 0) {
|
|
2383
|
-
|
|
2412
|
+
if (startNow) {
|
|
2413
|
+
spawnSync("schtasks", ["/Run", "/TN", taskName]);
|
|
2414
|
+
}
|
|
2384
2415
|
return { ok: true };
|
|
2385
2416
|
}
|
|
2386
2417
|
logger?.warn?.(`[docdex] schtasks failed: ${create.stderr || "unknown error"}`);
|
|
@@ -2390,18 +2421,22 @@ function registerStartup({ binaryPath, port, repoRoot, logger, distBaseDir }) {
|
|
|
2390
2421
|
return { ok: false, reason: "unsupported_platform" };
|
|
2391
2422
|
}
|
|
2392
2423
|
|
|
2393
|
-
async function startDaemonWithHealthCheck({ binaryPath, port, host, logger, distBaseDir }) {
|
|
2424
|
+
async function startDaemonWithHealthCheck({ binaryPath, port, host, logger, distBaseDir, startNow = true }) {
|
|
2394
2425
|
const startup = registerStartup({
|
|
2395
2426
|
binaryPath,
|
|
2396
2427
|
port,
|
|
2397
2428
|
repoRoot: daemonRootPath(),
|
|
2398
2429
|
logger,
|
|
2399
|
-
distBaseDir
|
|
2430
|
+
distBaseDir,
|
|
2431
|
+
startNow
|
|
2400
2432
|
});
|
|
2401
2433
|
if (!startup.ok) {
|
|
2402
2434
|
logger?.warn?.(`[docdex] daemon service registration failed (${startup.reason || "unknown"}).`);
|
|
2403
2435
|
return { ok: false, reason: "startup_failed" };
|
|
2404
2436
|
}
|
|
2437
|
+
if (!startNow) {
|
|
2438
|
+
return { ok: true, reason: "registered" };
|
|
2439
|
+
}
|
|
2405
2440
|
startDaemonService({ logger });
|
|
2406
2441
|
const healthy = await waitForDaemonHealthy({ host, port });
|
|
2407
2442
|
if (healthy) {
|
|
@@ -2456,6 +2491,25 @@ function commandExists(cmd, spawnSyncFn) {
|
|
|
2456
2491
|
return true;
|
|
2457
2492
|
}
|
|
2458
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
|
+
|
|
2459
2513
|
function launchMacTerminal({ binaryPath, args, spawnSyncFn, logger }) {
|
|
2460
2514
|
const command = [
|
|
2461
2515
|
"DOCDEX_SETUP_AUTO=1",
|
|
@@ -2514,7 +2568,8 @@ function launchSetupWizard({
|
|
|
2514
2568
|
spawnFn = spawn,
|
|
2515
2569
|
spawnSyncFn = spawnSync,
|
|
2516
2570
|
platform = process.platform,
|
|
2517
|
-
canPrompt = canPromptWithTty
|
|
2571
|
+
canPrompt = canPromptWithTty,
|
|
2572
|
+
distBaseDir
|
|
2518
2573
|
}) {
|
|
2519
2574
|
if (!binaryPath) return { ok: false, reason: "missing_binary" };
|
|
2520
2575
|
if (shouldSkipSetup(env)) return { ok: false, reason: "skipped" };
|
|
@@ -2535,9 +2590,21 @@ function launchSetupWizard({
|
|
|
2535
2590
|
}
|
|
2536
2591
|
|
|
2537
2592
|
if (platform === "win32") {
|
|
2538
|
-
const
|
|
2539
|
-
|
|
2540
|
-
|
|
2593
|
+
const runnerPath = writeWindowsSetupRunner({
|
|
2594
|
+
binaryPath,
|
|
2595
|
+
args,
|
|
2596
|
+
logger,
|
|
2597
|
+
distBaseDir
|
|
2598
|
+
});
|
|
2599
|
+
if (!runnerPath) return { ok: false, reason: "runner_failed" };
|
|
2600
|
+
const result = spawnSyncFn("cmd", [
|
|
2601
|
+
"/c",
|
|
2602
|
+
"start",
|
|
2603
|
+
"",
|
|
2604
|
+
"cmd",
|
|
2605
|
+
"/c",
|
|
2606
|
+
escapeCmdArg(runnerPath)
|
|
2607
|
+
]);
|
|
2541
2608
|
if (result.status === 0) return { ok: true };
|
|
2542
2609
|
logger?.warn?.(`[docdex] cmd start failed: ${result.stderr || "unknown error"}`);
|
|
2543
2610
|
return { ok: false, reason: "terminal_launch_failed" };
|
|
@@ -2630,14 +2697,15 @@ async function runPostInstallSetup({ binaryPath, logger, env, skipDaemon, distBa
|
|
|
2630
2697
|
}
|
|
2631
2698
|
}
|
|
2632
2699
|
}
|
|
2633
|
-
let startupOk =
|
|
2634
|
-
if (allowDaemon
|
|
2700
|
+
let startupOk = false;
|
|
2701
|
+
if (allowDaemon) {
|
|
2635
2702
|
const result = await startDaemonWithHealthCheck({
|
|
2636
2703
|
binaryPath: startupBinaries.binaryPath,
|
|
2637
2704
|
port,
|
|
2638
2705
|
host: DEFAULT_HOST,
|
|
2639
2706
|
logger: log,
|
|
2640
|
-
distBaseDir: resolvedDistBaseDir
|
|
2707
|
+
distBaseDir: resolvedDistBaseDir,
|
|
2708
|
+
startNow: !reuseExisting
|
|
2641
2709
|
});
|
|
2642
2710
|
if (!result.ok) {
|
|
2643
2711
|
log.warn?.(`[docdex] daemon failed to start on ${DEFAULT_HOST}:${port}.`);
|
|
@@ -2681,13 +2749,20 @@ async function runPostInstallSetup({ binaryPath, logger, env, skipDaemon, distBa
|
|
|
2681
2749
|
if (startupOk) {
|
|
2682
2750
|
clearStartupFailure();
|
|
2683
2751
|
}
|
|
2684
|
-
const
|
|
2752
|
+
const skipExplicit = shouldSkipSetup(effectiveEnv);
|
|
2753
|
+
const skipWizard = isNpmLifecycle(effectiveEnv) || skipExplicit;
|
|
2685
2754
|
const setupLaunch = skipWizard
|
|
2686
|
-
? { ok: false, reason: "skipped" }
|
|
2687
|
-
: launchSetupWizard({
|
|
2688
|
-
|
|
2689
|
-
|
|
2690
|
-
|
|
2755
|
+
? { ok: false, reason: skipExplicit ? "skipped" : "npm_lifecycle" }
|
|
2756
|
+
: launchSetupWizard({
|
|
2757
|
+
binaryPath: startupBinaries.binaryPath,
|
|
2758
|
+
logger: log,
|
|
2759
|
+
distBaseDir: resolvedDistBaseDir
|
|
2760
|
+
});
|
|
2761
|
+
if (!setupLaunch.ok) {
|
|
2762
|
+
if (setupLaunch.reason !== "skipped") {
|
|
2763
|
+
log.warn?.("[docdex] setup wizard did not launch. Run `docdex setup`.");
|
|
2764
|
+
recordSetupPending({ reason: setupLaunch.reason, port, repoRoot: daemonRoot });
|
|
2765
|
+
}
|
|
2691
2766
|
}
|
|
2692
2767
|
return { port, url, configPath };
|
|
2693
2768
|
}
|