traderclaw-cli 1.0.120 → 1.0.122

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.
@@ -11,7 +11,7 @@ const CONFIG_DIR = join(homedir(), ".openclaw");
11
11
  const CONFIG_FILE = join(CONFIG_DIR, "openclaw.json");
12
12
 
13
13
  /** Pinned openclaw platform version — bump deliberately after testing, never use "latest". */
14
- export const OPENCLAW_VERSION = "2026.4.29";
14
+ export const OPENCLAW_VERSION = "2026.5.4";
15
15
 
16
16
  /** Directory containing solana-traderclaw (openclaw.plugin.json) — works for plugin layout or traderclaw-cli + dependency. */
17
17
  const PLUGIN_PACKAGE_ROOT = resolvePluginPackageRoot(import.meta.url);
@@ -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,17 +633,61 @@ 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
+ "--prefer-offline",
658
+ "--loglevel",
659
+ "warn",
660
+ "--registry",
661
+ "https://registry.npmjs.org/",
662
+ `openclaw@${OPENCLAW_VERSION}`,
663
+ ],
664
+ {
665
+ onEvent,
666
+ cwd: npmCwd,
667
+ shell: false,
668
+ timeoutMs: effectiveTimeout,
669
+ heartbeatMs: 30_000,
670
+ heartbeatText:
671
+ "npm still installing OpenClaw (extract/link phase — this is normal silence). Check disk space and outbound HTTPS to registry.npmjs.org if this repeats many times",
672
+ env: {
673
+ ...process.env,
674
+ // Non-interactive / fewer slow npm side trips (fundraising prompts, audit).
675
+ ...(process.env.CI ? {} : { CI: "true" }),
676
+ npm_config_update_notifier: process.env.npm_config_update_notifier ?? "false",
677
+ },
678
+ },
679
+ );
680
+ if (typeof onEvent === "function") {
681
+ onEvent({ type: "stdout", text: "npm install -g openclaw completed. Verifying binary on PATH…\n", urls: [] });
682
+ }
582
683
  const available = commandExists("openclaw");
583
- let version = available ? getCommandOutput("openclaw --version", { timeoutMs: OPENCLAW_CLI_VERSION_TIMEOUT_MS }) : null;
684
+ // Version check is informational only cap it tightly so a blocking CLI startup never stalls the step.
685
+ const VERSION_TIMEOUT_MS = 8_000;
686
+ let version = available ? getCommandOutput("openclaw --version", { timeoutMs: VERSION_TIMEOUT_MS }) : null;
584
687
  if (available && !version && typeof onEvent === "function") {
585
688
  onEvent({
586
689
  type: "stderr",
587
- text: "openclaw is on PATH but --version timed out; treating install as successful.\n",
690
+ text: `openclaw is on PATH but --version did not respond within ${VERSION_TIMEOUT_MS}ms; treating install as successful.\n`,
588
691
  urls: [],
589
692
  });
590
693
  version = "(version check timed out)";
@@ -659,7 +762,7 @@ function isNpmFilesystemPackageSpec(spec) {
659
762
  * IMPORTANT: run with `{ shell: false }` — `spawn(..., { shell: true })` can drop argv on Unix and npm then mis-resolves the package name.
660
763
  */
661
764
  function npmGlobalInstallArgs(spec, { force = false } = {}) {
662
- const args = ["install", "-g", "--ignore-scripts"];
765
+ const args = ["install", "-g", "--ignore-scripts", "--no-audit", "--no-fund"];
663
766
  if (force) args.push("--force");
664
767
  if (!isNpmFilesystemPackageSpec(spec)) {
665
768
  args.push("--registry", "https://registry.npmjs.org/");
@@ -2646,7 +2749,7 @@ export class InstallerStepEngine {
2646
2749
  }
2647
2750
  this.emitLog("install_qmd", "info", "Installing @tobilu/qmd globally for vector search memory...");
2648
2751
  try {
2649
- await runCommandWithEvents("npm", ["install", "-g", "--ignore-scripts", "--registry", "https://registry.npmjs.org/", "@tobilu/qmd"], {
2752
+ await runCommandWithEvents("npm", ["install", "-g", "--ignore-scripts", "--no-audit", "--no-fund", "--registry", "https://registry.npmjs.org/", "@tobilu/qmd"], {
2650
2753
  onEvent: (evt) => this.emitLog("install_qmd", evt.type === "stderr" ? "warn" : "info", evt.text, evt.urls || []),
2651
2754
  });
2652
2755
  } 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.122",
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.122"
21
21
  },
22
22
  "keywords": [
23
23
  "traderclaw",