@openher/cli 1.0.0 → 1.0.1
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/cli.mjs +45 -53
- package/package.json +1 -1
package/cli.mjs
CHANGED
|
@@ -84,11 +84,13 @@ function ask(question) {
|
|
|
84
84
|
}
|
|
85
85
|
|
|
86
86
|
function askSecret(question) {
|
|
87
|
+
// Non-TTY fallback: just use regular readline (shows input)
|
|
88
|
+
if (!process.stdin.isTTY) {
|
|
89
|
+
return ask(question);
|
|
90
|
+
}
|
|
87
91
|
return new Promise((resolve) => {
|
|
88
92
|
process.stdout.write(`${C.cyan}[openher]${C.reset} ${question}`);
|
|
89
|
-
|
|
90
|
-
// Mute echo
|
|
91
|
-
if (process.stdin.isTTY) process.stdin.setRawMode(true);
|
|
93
|
+
process.stdin.setRawMode(true);
|
|
92
94
|
let buf = "";
|
|
93
95
|
process.stdin.resume();
|
|
94
96
|
process.stdin.on("data", function handler(chunk) {
|
|
@@ -96,14 +98,13 @@ function askSecret(question) {
|
|
|
96
98
|
for (const ch of s) {
|
|
97
99
|
if (ch === "\n" || ch === "\r") {
|
|
98
100
|
process.stdin.removeListener("data", handler);
|
|
99
|
-
|
|
101
|
+
process.stdin.setRawMode(false);
|
|
100
102
|
process.stdin.pause();
|
|
101
103
|
process.stdout.write("\n");
|
|
102
|
-
rl.close();
|
|
103
104
|
resolve(buf);
|
|
104
105
|
return;
|
|
105
106
|
} else if (ch === "\u0003") {
|
|
106
|
-
|
|
107
|
+
process.stdin.setRawMode(false);
|
|
107
108
|
process.exit(1);
|
|
108
109
|
} else if (ch === "\x7f" || ch === "\b") {
|
|
109
110
|
buf = buf.slice(0, -1);
|
|
@@ -155,6 +156,15 @@ async function install() {
|
|
|
155
156
|
// ── Step 1: Check prerequisites ──
|
|
156
157
|
log("Checking prerequisites...");
|
|
157
158
|
|
|
159
|
+
// Node.js version (openclaw requires v22.12+)
|
|
160
|
+
const nodeVer = process.versions.node.split(".").map(Number);
|
|
161
|
+
if (nodeVer[0] < 22 || (nodeVer[0] === 22 && nodeVer[1] < 12)) {
|
|
162
|
+
error(`Node.js v22.12+ required (current: v${process.versions.node})`);
|
|
163
|
+
console.log(" Install via: https://nodejs.org/ or nvm install 22");
|
|
164
|
+
process.exit(1);
|
|
165
|
+
}
|
|
166
|
+
success(`Node.js v${process.versions.node}`);
|
|
167
|
+
|
|
158
168
|
if (!which("openclaw")) {
|
|
159
169
|
error("OpenClaw not found. Please install it first:");
|
|
160
170
|
console.log(" npm install -g openclaw");
|
|
@@ -356,35 +366,6 @@ async function install() {
|
|
|
356
366
|
env: { ...process.env, PORT: String(DEFAULT_PORT) },
|
|
357
367
|
});
|
|
358
368
|
|
|
359
|
-
// Wait for startup
|
|
360
|
-
let started = false;
|
|
361
|
-
const startTimeout = setTimeout(() => {
|
|
362
|
-
if (!started) {
|
|
363
|
-
warn("Backend is still starting. Check manually:");
|
|
364
|
-
console.log(` cd ${backendDir} && .venv/bin/python main.py`);
|
|
365
|
-
}
|
|
366
|
-
}, 15000);
|
|
367
|
-
|
|
368
|
-
child.stdout.on("data", (data) => {
|
|
369
|
-
const str = data.toString();
|
|
370
|
-
if (str.includes("Uvicorn running") || str.includes("Application startup")) {
|
|
371
|
-
started = true;
|
|
372
|
-
clearTimeout(startTimeout);
|
|
373
|
-
success(`Backend running on http://localhost:${DEFAULT_PORT}`);
|
|
374
|
-
finalize();
|
|
375
|
-
}
|
|
376
|
-
});
|
|
377
|
-
|
|
378
|
-
child.stderr.on("data", (data) => {
|
|
379
|
-
const str = data.toString();
|
|
380
|
-
if (str.includes("Uvicorn running") || str.includes("Application startup")) {
|
|
381
|
-
started = true;
|
|
382
|
-
clearTimeout(startTimeout);
|
|
383
|
-
success(`Backend running on http://localhost:${DEFAULT_PORT}`);
|
|
384
|
-
finalize();
|
|
385
|
-
}
|
|
386
|
-
});
|
|
387
|
-
|
|
388
369
|
child.unref();
|
|
389
370
|
|
|
390
371
|
// Write PID for later stop command
|
|
@@ -392,28 +373,39 @@ async function install() {
|
|
|
392
373
|
writeFileSync(join(openherDir, "backend.pid"), String(child.pid), "utf-8");
|
|
393
374
|
} catch {}
|
|
394
375
|
|
|
395
|
-
//
|
|
396
|
-
|
|
397
|
-
|
|
398
|
-
|
|
399
|
-
|
|
400
|
-
|
|
401
|
-
|
|
402
|
-
|
|
403
|
-
|
|
404
|
-
|
|
405
|
-
|
|
406
|
-
|
|
376
|
+
// Wait for startup signal from stdout/stderr
|
|
377
|
+
let started = false;
|
|
378
|
+
const onOutput = (data) => {
|
|
379
|
+
const str = data.toString();
|
|
380
|
+
if (!started && (str.includes("Uvicorn running") || str.includes("Application startup"))) {
|
|
381
|
+
started = true;
|
|
382
|
+
}
|
|
383
|
+
};
|
|
384
|
+
child.stdout.on("data", onOutput);
|
|
385
|
+
child.stderr.on("data", onOutput);
|
|
386
|
+
|
|
387
|
+
// Poll for up to 20s
|
|
388
|
+
await new Promise((resolve) => {
|
|
389
|
+
const check = setInterval(() => {
|
|
390
|
+
if (started) {
|
|
407
391
|
clearInterval(check);
|
|
408
392
|
resolve();
|
|
409
|
-
}
|
|
410
|
-
});
|
|
411
|
-
|
|
393
|
+
}
|
|
394
|
+
}, 500);
|
|
395
|
+
setTimeout(() => {
|
|
396
|
+
clearInterval(check);
|
|
397
|
+
resolve();
|
|
398
|
+
}, 20000);
|
|
399
|
+
});
|
|
412
400
|
|
|
413
|
-
if (
|
|
414
|
-
|
|
415
|
-
|
|
401
|
+
if (started) {
|
|
402
|
+
success(`Backend running on http://localhost:${DEFAULT_PORT}`);
|
|
403
|
+
} else {
|
|
404
|
+
warn("Backend may still be starting up. Check:");
|
|
405
|
+
console.log(` cd ${backendDir} && .venv/bin/python main.py`);
|
|
416
406
|
}
|
|
407
|
+
|
|
408
|
+
finalize();
|
|
417
409
|
}
|
|
418
410
|
|
|
419
411
|
function finalize() {
|