traderclaw-cli 1.0.84 → 1.0.86

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.
@@ -2214,21 +2214,38 @@ export class InstallerStepEngine {
2214
2214
  }
2215
2215
 
2216
2216
  buildSetupHandoff() {
2217
- const args = ["setup", "--url", this.options.orchestratorUrl || "https://api.traderclaw.ai"];
2218
- if (this.options.lane !== "event-driven") {
2219
- args.push("--skip-gateway-registration");
2217
+ // Shell-safe single-quote wrapper: wraps value in '…' and escapes any embedded single quotes.
2218
+ const shQuote = (v) => `'${String(v).replace(/'/g, "'\\''")}'`;
2219
+
2220
+ const cliName = this.modeConfig.cliName;
2221
+ const orchestratorUrl = this.options.orchestratorUrl || "https://api.traderclaw.ai";
2222
+ const apiKey = String(this.options.apiKey || "").trim();
2223
+
2224
+ // Build args in the user-facing convention:
2225
+ // traderclaw setup --api-key '…' --url '…' [--gateway-base-url '…'] [--skip-gateway-registration] [--referral-code '…']
2226
+ const parts = [cliName, "setup"];
2227
+
2228
+ if (apiKey) {
2229
+ parts.push("--api-key", shQuote(apiKey));
2220
2230
  }
2231
+
2232
+ parts.push("--url", shQuote(orchestratorUrl));
2233
+
2221
2234
  const gatewayBaseUrl = this.options.gatewayBaseUrl || this.state.detected.funnelUrl || "";
2222
2235
  if (this.options.lane === "event-driven" && gatewayBaseUrl) {
2223
- args.push("--gateway-base-url", gatewayBaseUrl);
2236
+ parts.push("--gateway-base-url", shQuote(gatewayBaseUrl));
2237
+ }
2238
+
2239
+ if (this.options.lane !== "event-driven") {
2240
+ parts.push("--skip-gateway-registration");
2224
2241
  }
2225
2242
 
2226
2243
  const ref = String(this.options.referralCode || "").trim();
2227
2244
  if (ref) {
2228
- args.push("--referral-code", ref);
2245
+ parts.push("--referral-code", shQuote(ref));
2229
2246
  }
2230
2247
 
2231
- const command = [this.modeConfig.cliName, ...args].join(" ");
2248
+ const command = parts.join(" ");
2232
2249
  const docs =
2233
2250
  "https://docs.traderclaw.ai/docs/installation#troubleshooting-session-expired-auth-errors-or-the-agent-logged-out";
2234
2251
  return {
@@ -2236,11 +2253,13 @@ export class InstallerStepEngine {
2236
2253
  command,
2237
2254
  title: "Ready to launch your agentic trading desk",
2238
2255
  message:
2239
- "Core install is complete. Final setup is intentionally handed off to your VPS shell so sensitive wallet prompts stay private. " +
2240
- "After setup, if the bot reports wallet proof / session errors: configure TRADERCLAW_WALLET_PRIVATE_KEY for the OpenClaw gateway service (systemd), not only in SSH see " +
2256
+ "Core install is complete. Run the command below in your VPS shell to complete authentication. " +
2257
+ "The wallet private key is intentionally omitted — if your account has a linked wallet, traderclaw setup will prompt for it securely in the terminal (hidden input, key is never saved or sent). " +
2258
+ "For automation or non-interactive environments use --wallet-private-key or the TRADERCLAW_WALLET_PRIVATE_KEY env var instead. " +
2259
+ "After setup, configure TRADERCLAW_WALLET_PRIVATE_KEY for the OpenClaw gateway service (systemd) so the bot can sign challenges at runtime — not only in your SSH session. See " +
2241
2260
  docs,
2242
2261
  hint:
2243
- "Run the command in terminal, answer setup prompts, then restart gateway. If Telegram startup checks all fail, open the troubleshooting link in the message above.",
2262
+ "Run the command in your terminal. If wallet proof is required, you will be prompted for the private key with hidden input. Then restart the gateway.",
2244
2263
  restartCommand: "openclaw gateway restart",
2245
2264
  };
2246
2265
  }
@@ -214,6 +214,79 @@ async function confirm(question) {
214
214
  return answer.toLowerCase() === "y" || answer.toLowerCase() === "yes";
215
215
  }
216
216
 
217
+ /**
218
+ * Prompt for the wallet private key with hidden input (no echo) when running in a TTY.
219
+ * Falls back to a visible prompt with a warning if raw mode is unavailable.
220
+ * Returns an empty string if the user presses Enter with no input.
221
+ */
222
+ async function promptWalletPrivateKeyHidden() {
223
+ const isTTY = process.stdin.isTTY && process.stdout.isTTY;
224
+ if (!isTTY) return "";
225
+
226
+ print(" Your trading wallet private key is required to prove ownership of the linked wallet.");
227
+ print(" It is used only to sign a one-time challenge locally — it is NEVER sent to any server");
228
+ print(" and is NEVER written to openclaw.json or any file.");
229
+ print(" For automation, use --wallet-private-key or the TRADERCLAW_WALLET_PRIVATE_KEY env var instead.\n");
230
+
231
+ return new Promise((resolve) => {
232
+ let input = "";
233
+ let rawEnabled = false;
234
+
235
+ const cleanup = () => {
236
+ try {
237
+ if (rawEnabled && process.stdin.isTTY) {
238
+ process.stdin.setRawMode(false);
239
+ }
240
+ } catch {
241
+ // ignore
242
+ }
243
+ process.stdin.pause();
244
+ process.stdin.removeAllListeners("data");
245
+ process.stdin.removeAllListeners("end");
246
+ };
247
+
248
+ try {
249
+ process.stdin.setRawMode(true);
250
+ rawEnabled = true;
251
+ } catch {
252
+ // raw mode unavailable — fall through to visible prompt
253
+ }
254
+
255
+ if (rawEnabled) {
256
+ process.stdout.write(" Wallet private key (hidden, press Enter when done): ");
257
+ process.stdin.resume();
258
+ process.stdin.setEncoding("utf8");
259
+
260
+ process.stdin.on("data", (ch) => {
261
+ if (ch === "\r" || ch === "\n") {
262
+ process.stdout.write("\n");
263
+ cleanup();
264
+ resolve(input.trim());
265
+ } else if (ch === "\u0003") {
266
+ // Ctrl-C
267
+ process.stdout.write("\n");
268
+ cleanup();
269
+ resolve("");
270
+ } else if (ch === "\u007f" || ch === "\b") {
271
+ // backspace
272
+ if (input.length > 0) input = input.slice(0, -1);
273
+ } else {
274
+ input += ch;
275
+ }
276
+ });
277
+
278
+ process.stdin.once("end", () => {
279
+ cleanup();
280
+ resolve(input.trim());
281
+ });
282
+ } else {
283
+ // Raw mode unavailable; warn and fall back to visible prompt.
284
+ printWarn(" Note: terminal does not support hidden input — key will be visible as you type.");
285
+ prompt(" Wallet private key", "").then((val) => resolve(val.trim()));
286
+ }
287
+ });
288
+ }
289
+
217
290
  async function httpRequest(url, opts = {}) {
218
291
  const controller = new AbortController();
219
292
  const timeoutId = setTimeout(() => controller.abort(), opts.timeout ?? 10000);
@@ -640,10 +713,14 @@ async function establishSession(orchestratorUrl, pluginConfig, walletPrivateKeyI
640
713
 
641
714
  if (challenge.walletProofRequired) {
642
715
  printWarn(" Wallet proof required — this account already has a wallet.");
643
- const walletPrivateKey = getRuntimeWalletPrivateKey(walletPrivateKeyInput);
716
+ let walletPrivateKey = getRuntimeWalletPrivateKey(walletPrivateKeyInput);
717
+ if (!walletPrivateKey) {
718
+ walletPrivateKey = await promptWalletPrivateKeyHidden();
719
+ }
644
720
  if (!walletPrivateKey) {
645
721
  printError(` Wallet private key not available. Cannot prove wallet ownership.`);
646
722
  printError(` Provide it via --wallet-private-key or env ${WALLET_PRIVATE_KEY_ENV} for local signing.`);
723
+ printError(` If running interactively (TTY), you will be prompted automatically when proof is required.`);
647
724
  printSessionTroubleshootingHint();
648
725
  throw new Error("Wallet proof required but no private key configured.");
649
726
  }
@@ -4091,7 +4168,11 @@ Setup options:
4091
4168
  --api-key, -k API key (skip interactive prompt)
4092
4169
  --url, -u Orchestrator URL (skip interactive prompt)
4093
4170
  --user-id External user ID for signup
4094
- --wallet-private-key Optional base58 private key for wallet proof flow (runtime only, never saved)
4171
+ --wallet-private-key Base58 private key for wallet proof (runtime only, never saved to disk).
4172
+ Optional: when omitted in a TTY session, traderclaw will prompt for it
4173
+ interactively with hidden input if the server requires wallet proof.
4174
+ Required when running non-interactively (scripts, CI) — use env
4175
+ TRADERCLAW_WALLET_PRIVATE_KEY for cleaner shell history.
4095
4176
  --gateway-base-url, -g Gateway public HTTPS URL for orchestrator callbacks
4096
4177
  --gateway-token, -t Gateway bearer token (defaults to API key)
4097
4178
  --telegram-recipient Telegram @username or chat id (aliases: --forward-telegram-chat-id, --telegram-chat-id)
@@ -4107,7 +4188,8 @@ Gateway subcommands:
4107
4188
  gateway ensure-persistent Linux: enable loginctl linger and systemd --user unit for OpenClaw gateway
4108
4189
 
4109
4190
  Login options:
4110
- --wallet-private-key <k> Base58 key for wallet proof when the server requires it (runtime only)
4191
+ --wallet-private-key <k> Base58 key for wallet proof (runtime only, never saved). Optional in a
4192
+ TTY session — traderclaw will prompt with hidden input if proof is needed.
4111
4193
  --force-reauth Clear refresh token and run full API challenge (use after logout or to rotate session)
4112
4194
 
4113
4195
  Config subcommands:
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "traderclaw-cli",
3
- "version": "1.0.84",
3
+ "version": "1.0.86",
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.84"
20
+ "solana-traderclaw": "^1.0.86"
21
21
  },
22
22
  "keywords": [
23
23
  "traderclaw",