docdex 0.2.6 → 0.2.8
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 +1 -1
- package/lib/postinstall_setup.js +98 -12
- package/package.json +2 -1
package/CHANGELOG.md
CHANGED
package/lib/postinstall_setup.js
CHANGED
|
@@ -6,6 +6,7 @@ const net = require("node:net");
|
|
|
6
6
|
const os = require("node:os");
|
|
7
7
|
const path = require("node:path");
|
|
8
8
|
const readline = require("node:readline");
|
|
9
|
+
const tty = require("node:tty");
|
|
9
10
|
const { spawn, spawnSync } = require("node:child_process");
|
|
10
11
|
|
|
11
12
|
const { detectPlatformKey, UnsupportedPlatformError } = require("./platform");
|
|
@@ -17,6 +18,7 @@ const STARTUP_FAILURE_MARKER = "startup_registration_failed.json";
|
|
|
17
18
|
const DEFAULT_OLLAMA_MODEL = "nomic-embed-text";
|
|
18
19
|
const DEFAULT_OLLAMA_CHAT_MODEL = "phi3.5:3.8b";
|
|
19
20
|
const DEFAULT_OLLAMA_CHAT_MODEL_SIZE_GIB = 2.2;
|
|
21
|
+
const SETUP_PENDING_MARKER = "setup_pending.json";
|
|
20
22
|
|
|
21
23
|
function defaultConfigPath() {
|
|
22
24
|
return path.join(os.homedir(), ".docdex", "config.toml");
|
|
@@ -30,6 +32,10 @@ function stateDir() {
|
|
|
30
32
|
return path.join(os.homedir(), ".docdex", "state");
|
|
31
33
|
}
|
|
32
34
|
|
|
35
|
+
function setupPendingPath() {
|
|
36
|
+
return path.join(stateDir(), SETUP_PENDING_MARKER);
|
|
37
|
+
}
|
|
38
|
+
|
|
33
39
|
function configUrlForPort(port) {
|
|
34
40
|
return `http://localhost:${port}/sse`;
|
|
35
41
|
}
|
|
@@ -389,9 +395,11 @@ function canPromptWithTty(stdin, stdout) {
|
|
|
389
395
|
try {
|
|
390
396
|
const readFd = fs.openSync(inputPath, "r");
|
|
391
397
|
const writeFd = fs.openSync(outputPath, "w");
|
|
398
|
+
const readable = tty.isatty(readFd);
|
|
399
|
+
const writable = tty.isatty(writeFd);
|
|
392
400
|
fs.closeSync(readFd);
|
|
393
401
|
fs.closeSync(writeFd);
|
|
394
|
-
return
|
|
402
|
+
return readable && writable;
|
|
395
403
|
} catch {
|
|
396
404
|
return false;
|
|
397
405
|
}
|
|
@@ -592,8 +600,15 @@ function resolvePromptStreams(stdin, stdout) {
|
|
|
592
600
|
const inputPath = isWindows ? "CONIN$" : "/dev/tty";
|
|
593
601
|
const outputPath = isWindows ? "CONOUT$" : "/dev/tty";
|
|
594
602
|
try {
|
|
595
|
-
const
|
|
596
|
-
const
|
|
603
|
+
const readFd = fs.openSync(inputPath, "r");
|
|
604
|
+
const writeFd = fs.openSync(outputPath, "w");
|
|
605
|
+
if (!tty.isatty(readFd) || !tty.isatty(writeFd)) {
|
|
606
|
+
fs.closeSync(readFd);
|
|
607
|
+
fs.closeSync(writeFd);
|
|
608
|
+
return { input: stdin, output: stdout, close: null };
|
|
609
|
+
}
|
|
610
|
+
const input = fs.createReadStream(inputPath, { fd: readFd, autoClose: true });
|
|
611
|
+
const output = fs.createWriteStream(outputPath, { fd: writeFd, autoClose: true });
|
|
597
612
|
return {
|
|
598
613
|
input,
|
|
599
614
|
output,
|
|
@@ -610,8 +625,11 @@ function resolvePromptStreams(stdin, stdout) {
|
|
|
610
625
|
function promptYesNo(question, { defaultYes = true, stdin = process.stdin, stdout = process.stdout } = {}) {
|
|
611
626
|
return new Promise((resolve) => {
|
|
612
627
|
const { input, output, close } = resolvePromptStreams(stdin, stdout);
|
|
613
|
-
const rl = readline.createInterface({ input, output });
|
|
614
|
-
|
|
628
|
+
const rl = readline.createInterface({ input, output, terminal: Boolean(output?.isTTY) });
|
|
629
|
+
if (output && typeof output.write === "function") {
|
|
630
|
+
output.write(`\n${question}`);
|
|
631
|
+
}
|
|
632
|
+
rl.question("", (answer) => {
|
|
615
633
|
rl.close();
|
|
616
634
|
if (typeof close === "function") close();
|
|
617
635
|
const normalized = String(answer || "").trim().toLowerCase();
|
|
@@ -624,8 +642,11 @@ function promptYesNo(question, { defaultYes = true, stdin = process.stdin, stdou
|
|
|
624
642
|
function promptInput(question, { stdin = process.stdin, stdout = process.stdout } = {}) {
|
|
625
643
|
return new Promise((resolve) => {
|
|
626
644
|
const { input, output, close } = resolvePromptStreams(stdin, stdout);
|
|
627
|
-
const rl = readline.createInterface({ input, output });
|
|
628
|
-
|
|
645
|
+
const rl = readline.createInterface({ input, output, terminal: Boolean(output?.isTTY) });
|
|
646
|
+
if (output && typeof output.write === "function") {
|
|
647
|
+
output.write(`\n${question}`);
|
|
648
|
+
}
|
|
649
|
+
rl.question("", (answer) => {
|
|
629
650
|
rl.close();
|
|
630
651
|
if (typeof close === "function") close();
|
|
631
652
|
resolve(String(answer || "").trim());
|
|
@@ -901,6 +922,11 @@ function registerStartup({ binaryPath, port, repoRoot, logger }) {
|
|
|
901
922
|
`<dict>\n` +
|
|
902
923
|
` <key>Label</key>\n` +
|
|
903
924
|
` <string>com.docdex.daemon</string>\n` +
|
|
925
|
+
` <key>EnvironmentVariables</key>\n` +
|
|
926
|
+
` <dict>\n` +
|
|
927
|
+
` <key>DOCDEX_BROWSER_AUTO_INSTALL</key>\n` +
|
|
928
|
+
` <string>0</string>\n` +
|
|
929
|
+
` </dict>\n` +
|
|
904
930
|
` <key>ProgramArguments</key>\n` +
|
|
905
931
|
` <array>\n` +
|
|
906
932
|
programArgs.map((arg) => ` <string>${arg}</string>\n`).join("") +
|
|
@@ -939,6 +965,7 @@ function registerStartup({ binaryPath, port, repoRoot, logger }) {
|
|
|
939
965
|
"",
|
|
940
966
|
"[Service]",
|
|
941
967
|
`ExecStart=${binaryPath} ${args.join(" ")}`,
|
|
968
|
+
"Environment=DOCDEX_BROWSER_AUTO_INSTALL=0",
|
|
942
969
|
"Restart=always",
|
|
943
970
|
"RestartSec=2",
|
|
944
971
|
"",
|
|
@@ -956,7 +983,9 @@ function registerStartup({ binaryPath, port, repoRoot, logger }) {
|
|
|
956
983
|
|
|
957
984
|
if (process.platform === "win32") {
|
|
958
985
|
const taskName = "Docdex Daemon";
|
|
959
|
-
const
|
|
986
|
+
const joinedArgs = args.map((arg) => `"${arg}"`).join(" ");
|
|
987
|
+
const taskArgs =
|
|
988
|
+
`"cmd.exe" /c "set DOCDEX_BROWSER_AUTO_INSTALL=0 && \"${binaryPath}\" ${joinedArgs}"`;
|
|
960
989
|
const create = spawnSync("schtasks", [
|
|
961
990
|
"/Create",
|
|
962
991
|
"/F",
|
|
@@ -996,7 +1025,14 @@ function startDaemonNow({ binaryPath, port, repoRoot }) {
|
|
|
996
1025
|
"warn",
|
|
997
1026
|
"--secure-mode=false"
|
|
998
1027
|
],
|
|
999
|
-
{
|
|
1028
|
+
{
|
|
1029
|
+
stdio: "ignore",
|
|
1030
|
+
detached: true,
|
|
1031
|
+
env: {
|
|
1032
|
+
...process.env,
|
|
1033
|
+
DOCDEX_BROWSER_AUTO_INSTALL: "0"
|
|
1034
|
+
}
|
|
1035
|
+
}
|
|
1000
1036
|
);
|
|
1001
1037
|
child.unref();
|
|
1002
1038
|
return true;
|
|
@@ -1008,6 +1044,12 @@ function recordStartupFailure(details) {
|
|
|
1008
1044
|
fs.writeFileSync(markerPath, JSON.stringify(details, null, 2));
|
|
1009
1045
|
}
|
|
1010
1046
|
|
|
1047
|
+
function recordSetupPending(details) {
|
|
1048
|
+
const markerPath = setupPendingPath();
|
|
1049
|
+
fs.mkdirSync(path.dirname(markerPath), { recursive: true });
|
|
1050
|
+
fs.writeFileSync(markerPath, JSON.stringify(details, null, 2));
|
|
1051
|
+
}
|
|
1052
|
+
|
|
1011
1053
|
function clearStartupFailure() {
|
|
1012
1054
|
const markerPath = path.join(stateDir(), STARTUP_FAILURE_MARKER);
|
|
1013
1055
|
if (fs.existsSync(markerPath)) fs.unlinkSync(markerPath);
|
|
@@ -1017,6 +1059,45 @@ function startupFailureReported() {
|
|
|
1017
1059
|
return fs.existsSync(path.join(stateDir(), STARTUP_FAILURE_MARKER));
|
|
1018
1060
|
}
|
|
1019
1061
|
|
|
1062
|
+
function shouldSkipSetup(env = process.env) {
|
|
1063
|
+
return parseEnvBool(env.DOCDEX_SETUP_SKIP) === true;
|
|
1064
|
+
}
|
|
1065
|
+
|
|
1066
|
+
function launchSetupWizard({
|
|
1067
|
+
binaryPath,
|
|
1068
|
+
logger,
|
|
1069
|
+
env = process.env,
|
|
1070
|
+
stdin = process.stdin,
|
|
1071
|
+
stdout = process.stdout,
|
|
1072
|
+
spawnFn = spawn,
|
|
1073
|
+
spawnSyncFn = spawnSync,
|
|
1074
|
+
platform = process.platform,
|
|
1075
|
+
canPrompt = canPromptWithTty
|
|
1076
|
+
}) {
|
|
1077
|
+
if (!binaryPath) return { ok: false, reason: "missing_binary" };
|
|
1078
|
+
if (shouldSkipSetup(env)) return { ok: false, reason: "skipped" };
|
|
1079
|
+
|
|
1080
|
+
const args = ["setup"];
|
|
1081
|
+
if (platform === "linux" || platform === "darwin") {
|
|
1082
|
+
if (!canPrompt(stdin, stdout)) {
|
|
1083
|
+
return { ok: false, reason: "non_interactive" };
|
|
1084
|
+
}
|
|
1085
|
+
const child = spawnFn(binaryPath, args, { stdio: "inherit" });
|
|
1086
|
+
if (child.pid) return { ok: true };
|
|
1087
|
+
return { ok: false, reason: "spawn_failed" };
|
|
1088
|
+
}
|
|
1089
|
+
|
|
1090
|
+
if (platform === "win32") {
|
|
1091
|
+
const quoted = `"${binaryPath}" ${args.map((arg) => `"${arg}"`).join(" ")}`;
|
|
1092
|
+
const result = spawnSyncFn("cmd", ["/c", "start", "", quoted]);
|
|
1093
|
+
if (result.status === 0) return { ok: true };
|
|
1094
|
+
logger?.warn?.(`[docdex] cmd start failed: ${result.stderr || "unknown error"}`);
|
|
1095
|
+
return { ok: false, reason: "terminal_launch_failed" };
|
|
1096
|
+
}
|
|
1097
|
+
|
|
1098
|
+
return { ok: false, reason: "unsupported_platform" };
|
|
1099
|
+
}
|
|
1100
|
+
|
|
1020
1101
|
async function runPostInstallSetup({ binaryPath, logger } = {}) {
|
|
1021
1102
|
const log = logger || console;
|
|
1022
1103
|
const configPath = defaultConfigPath();
|
|
@@ -1063,8 +1144,11 @@ async function runPostInstallSetup({ binaryPath, logger } = {}) {
|
|
|
1063
1144
|
}
|
|
1064
1145
|
|
|
1065
1146
|
startDaemonNow({ binaryPath: resolvedBinary, port, repoRoot: daemonRoot });
|
|
1066
|
-
|
|
1067
|
-
|
|
1147
|
+
const setupLaunch = launchSetupWizard({ binaryPath: resolvedBinary, logger: log });
|
|
1148
|
+
if (!setupLaunch.ok && setupLaunch.reason !== "skipped") {
|
|
1149
|
+
log.warn?.("[docdex] setup wizard did not launch. Run `docdex setup`.");
|
|
1150
|
+
recordSetupPending({ reason: setupLaunch.reason, port, repoRoot: daemonRoot });
|
|
1151
|
+
}
|
|
1068
1152
|
return { port, url, configPath };
|
|
1069
1153
|
}
|
|
1070
1154
|
|
|
@@ -1086,5 +1170,7 @@ module.exports = {
|
|
|
1086
1170
|
pullOllamaModel,
|
|
1087
1171
|
listOllamaModels,
|
|
1088
1172
|
hasInteractiveTty,
|
|
1089
|
-
canPromptWithTty
|
|
1173
|
+
canPromptWithTty,
|
|
1174
|
+
shouldSkipSetup,
|
|
1175
|
+
launchSetupWizard
|
|
1090
1176
|
};
|