traderclaw-cli 1.0.120 → 1.0.121

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.
@@ -451,7 +451,25 @@ function isOpenClawConfigSchemaFailure(text) {
451
451
 
452
452
  function runCommandWithEvents(cmd, args = [], opts = {}) {
453
453
  return new Promise((resolve, reject) => {
454
- const { onEvent, ...spawnOpts } = opts;
454
+ const {
455
+ onEvent,
456
+ timeoutMs = 0,
457
+ heartbeatMs = 0,
458
+ heartbeatText = "command still running…",
459
+ ...spawnOpts
460
+ } = opts;
461
+
462
+ let settled = false;
463
+ let timeoutId;
464
+ let heartbeatId;
465
+ const finish = (fn, arg) => {
466
+ if (settled) return;
467
+ settled = true;
468
+ if (timeoutId) clearTimeout(timeoutId);
469
+ if (heartbeatId) clearInterval(heartbeatId);
470
+ fn(arg);
471
+ };
472
+
455
473
  const isNpm = /(?:^|[\\/])npm(?:\.cmd)?$/.test(cmd) || cmd === "npm";
456
474
  if (isNpm && !spawnOpts.env?.NODE_OPTIONS?.includes("max-old-space-size")) {
457
475
  spawnOpts.env = {
@@ -471,6 +489,44 @@ function runCommandWithEvents(cmd, args = [], opts = {}) {
471
489
  const emitFn = typeof onEvent === "function" ? onEvent : null;
472
490
  const emit = (event) => emitFn && emitFn(event);
473
491
 
492
+ if (typeof timeoutMs === "number" && timeoutMs > 0) {
493
+ timeoutId = setTimeout(() => {
494
+ try {
495
+ child.kill("SIGTERM");
496
+ } catch {
497
+ /* ignore */
498
+ }
499
+ setTimeout(() => {
500
+ try {
501
+ child.kill("SIGKILL");
502
+ } catch {
503
+ /* ignore */
504
+ }
505
+ }, 12_000);
506
+ const tail = `${stdout}\n${stderr}`.trim().slice(-6000);
507
+ const err = new Error(
508
+ `Timed out after ${timeoutMs}ms: ${cmd} ${args.join(" ")}\n`
509
+ + `Last output:\n${tail || "(no output yet — possible npm registry or network stall; try again or run the same npm command in a terminal)"}`,
510
+ );
511
+ err.timedOut = true;
512
+ err.stdout = stdout;
513
+ err.stderr = stderr;
514
+ finish(reject, err);
515
+ }, timeoutMs);
516
+ }
517
+
518
+ if (typeof heartbeatMs === "number" && heartbeatMs > 0 && emitFn) {
519
+ const start = Date.now();
520
+ heartbeatId = setInterval(() => {
521
+ const sec = Math.floor((Date.now() - start) / 1000);
522
+ emitFn({
523
+ type: "stdout",
524
+ text: `[installer] ${heartbeatText} (${sec}s elapsed).\n`,
525
+ urls: [],
526
+ });
527
+ }, heartbeatMs);
528
+ }
529
+
474
530
  child.stdout?.on("data", (d) => {
475
531
  const text = d.toString();
476
532
  stdout += text;
@@ -484,8 +540,9 @@ function runCommandWithEvents(cmd, args = [], opts = {}) {
484
540
  });
485
541
 
486
542
  child.on("close", (code) => {
543
+ if (settled) return;
487
544
  const urls = [...new Set([...extractUrls(stdout), ...extractUrls(stderr)])];
488
- if (code === 0) resolve({ stdout, stderr, code, urls });
545
+ if (code === 0) finish(resolve, { stdout, stderr, code, urls });
489
546
  else {
490
547
  const isOom = code === 137 || (stderr || stdout || "").includes("Killed");
491
548
  const raw = (stderr || "").trim();
@@ -500,10 +557,10 @@ function runCommandWithEvents(cmd, args = [], opts = {}) {
500
557
  err.stderr = stderr;
501
558
  err.urls = urls;
502
559
  err.oom = isOom;
503
- reject(err);
560
+ finish(reject, err);
504
561
  }
505
562
  });
506
- child.on("error", reject);
563
+ child.on("error", (e) => finish(reject, e));
507
564
  });
508
565
  }
509
566
 
@@ -535,7 +592,7 @@ export async function ensureOpenClawGlobalPackageDependencies() {
535
592
  return { skipped: true, reason: "global_openclaw_dir_not_found" };
536
593
  }
537
594
  const registry = "https://registry.npmjs.org/";
538
- const installFlags = ["install", "--omit=dev", "--ignore-scripts", "--registry", registry];
595
+ const installFlags = ["install", "--omit=dev", "--ignore-scripts", "--no-audit", "--no-fund", "--registry", registry];
539
596
  await runCommandWithEvents("npm", installFlags, { cwd: dir, shell: false });
540
597
  await runCommandWithEvents(
541
598
  "npm",
@@ -544,6 +601,8 @@ export async function ensureOpenClawGlobalPackageDependencies() {
544
601
  "--omit=dev",
545
602
  "--no-save",
546
603
  "--ignore-scripts",
604
+ "--no-audit",
605
+ "--no-fund",
547
606
  "--registry",
548
607
  registry,
549
608
  "grammy",
@@ -574,11 +633,49 @@ async function installOpenClawPlatform(onEvent) {
574
633
  });
575
634
  }
576
635
  const npmCwd = getNpmGlobalInstallCwd();
577
- await runCommandWithEvents("npm", ["install", "-g", "--ignore-scripts", "--registry", "https://registry.npmjs.org/", `openclaw@${OPENCLAW_VERSION}`], {
578
- onEvent,
579
- cwd: npmCwd,
580
- shell: false,
581
- });
636
+ const npmTimeoutMs = Number.parseInt(String(process.env.TRADERCLAW_OPENCLAW_NPM_TIMEOUT_MS || "").trim(), 10);
637
+ const effectiveTimeout = Number.isFinite(npmTimeoutMs) && npmTimeoutMs > 0 ? npmTimeoutMs : 1_800_000;
638
+ if (typeof onEvent === "function") {
639
+ onEvent({
640
+ type: "stdout",
641
+ text:
642
+ `Running: npm install -g openclaw@${OPENCLAW_VERSION} (cwd=${npmCwd}, --no-audit --no-fund). `
643
+ + "First-time or upgrade installs can take several minutes; live npm lines and heartbeats appear below. "
644
+ + `Also watch the terminal where you started \`traderclaw install --wizard\`. `
645
+ + `Override stall limit: TRADERCLAW_OPENCLAW_NPM_TIMEOUT_MS (ms), default ${effectiveTimeout}.\n`,
646
+ urls: [],
647
+ });
648
+ }
649
+ await runCommandWithEvents(
650
+ "npm",
651
+ [
652
+ "install",
653
+ "-g",
654
+ "--ignore-scripts",
655
+ "--no-audit",
656
+ "--no-fund",
657
+ "--loglevel",
658
+ "info",
659
+ "--registry",
660
+ "https://registry.npmjs.org/",
661
+ `openclaw@${OPENCLAW_VERSION}`,
662
+ ],
663
+ {
664
+ onEvent,
665
+ cwd: npmCwd,
666
+ shell: false,
667
+ timeoutMs: effectiveTimeout,
668
+ heartbeatMs: 60_000,
669
+ heartbeatText:
670
+ "npm still installing OpenClaw — if this repeats for a long time, check disk space, DNS, and outbound HTTPS to registry.npmjs.org",
671
+ env: {
672
+ ...process.env,
673
+ // Non-interactive / fewer slow npm side trips (fundraising prompts, audit).
674
+ ...(process.env.CI ? {} : { CI: "true" }),
675
+ npm_config_update_notifier: process.env.npm_config_update_notifier ?? "false",
676
+ },
677
+ },
678
+ );
582
679
  const available = commandExists("openclaw");
583
680
  let version = available ? getCommandOutput("openclaw --version", { timeoutMs: OPENCLAW_CLI_VERSION_TIMEOUT_MS }) : null;
584
681
  if (available && !version && typeof onEvent === "function") {
@@ -659,7 +756,7 @@ function isNpmFilesystemPackageSpec(spec) {
659
756
  * IMPORTANT: run with `{ shell: false }` — `spawn(..., { shell: true })` can drop argv on Unix and npm then mis-resolves the package name.
660
757
  */
661
758
  function npmGlobalInstallArgs(spec, { force = false } = {}) {
662
- const args = ["install", "-g", "--ignore-scripts"];
759
+ const args = ["install", "-g", "--ignore-scripts", "--no-audit", "--no-fund"];
663
760
  if (force) args.push("--force");
664
761
  if (!isNpmFilesystemPackageSpec(spec)) {
665
762
  args.push("--registry", "https://registry.npmjs.org/");
@@ -2646,7 +2743,7 @@ export class InstallerStepEngine {
2646
2743
  }
2647
2744
  this.emitLog("install_qmd", "info", "Installing @tobilu/qmd globally for vector search memory...");
2648
2745
  try {
2649
- await runCommandWithEvents("npm", ["install", "-g", "--ignore-scripts", "--registry", "https://registry.npmjs.org/", "@tobilu/qmd"], {
2746
+ await runCommandWithEvents("npm", ["install", "-g", "--ignore-scripts", "--no-audit", "--no-fund", "--registry", "https://registry.npmjs.org/", "@tobilu/qmd"], {
2650
2747
  onEvent: (evt) => this.emitLog("install_qmd", evt.type === "stderr" ? "warn" : "info", evt.text, evt.urls || []),
2651
2748
  });
2652
2749
  } catch (err) {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "traderclaw-cli",
3
- "version": "1.0.120",
3
+ "version": "1.0.121",
4
4
  "description": "Global TraderClaw CLI (install --wizard, setup, precheck). Installs solana-traderclaw as a dependency for OpenClaw plugin files.",
5
5
  "type": "module",
6
6
  "bin": {
@@ -17,7 +17,7 @@
17
17
  "node": ">=22"
18
18
  },
19
19
  "dependencies": {
20
- "solana-traderclaw": "^1.0.120"
20
+ "solana-traderclaw": "^1.0.121"
21
21
  },
22
22
  "keywords": [
23
23
  "traderclaw",