@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.
Files changed (2) hide show
  1. package/cli.mjs +45 -53
  2. 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
- const rl = createInterface({ input: process.stdin, terminal: false });
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
- if (process.stdin.isTTY) process.stdin.setRawMode(false);
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
- // Ctrl+C
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
- // If backend starts quickly, finalize is called above
396
- // Otherwise, wait for the timeout
397
- if (!started) {
398
- await new Promise((resolve) => {
399
- const check = setInterval(() => {
400
- if (started) {
401
- clearInterval(check);
402
- resolve();
403
- }
404
- }, 500);
405
- // Max wait 20s
406
- setTimeout(() => {
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
- }, 20000);
410
- });
411
- }
393
+ }
394
+ }, 500);
395
+ setTimeout(() => {
396
+ clearInterval(check);
397
+ resolve();
398
+ }, 20000);
399
+ });
412
400
 
413
- if (!started) {
414
- warn("Backend may still be starting up...");
415
- finalize();
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() {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@openher/cli",
3
- "version": "1.0.0",
3
+ "version": "1.0.1",
4
4
  "description": "One-click installer for OpenHer Persona Engine — AI Being plugin for OpenClaw",
5
5
  "type": "module",
6
6
  "bin": {