traderclaw-cli 1.0.85 → 1.0.87
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/bin/installer-step-engine.mjs +28 -9
- package/bin/openclaw-trader.mjs +94 -12
- package/package.json +2 -2
|
@@ -2214,21 +2214,38 @@ export class InstallerStepEngine {
|
|
|
2214
2214
|
}
|
|
2215
2215
|
|
|
2216
2216
|
buildSetupHandoff() {
|
|
2217
|
-
|
|
2218
|
-
|
|
2219
|
-
|
|
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
|
-
|
|
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
|
-
|
|
2245
|
+
parts.push("--referral-code", shQuote(ref));
|
|
2229
2246
|
}
|
|
2230
2247
|
|
|
2231
|
-
const command =
|
|
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.
|
|
2240
|
-
"
|
|
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
|
|
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
|
}
|
package/bin/openclaw-trader.mjs
CHANGED
|
@@ -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
|
-
|
|
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
|
}
|
|
@@ -2138,11 +2215,11 @@ function wizardHtml(defaults) {
|
|
|
2138
2215
|
</div>
|
|
2139
2216
|
<div style="margin-top:12px;" id="llmOauthBlock" class="hidden">
|
|
2140
2217
|
<p class="muted" style="margin-bottom:12px;">
|
|
2141
|
-
OAuth here is fully guided. After you choose OAuth, we start OpenClaw login automatically. Use the sign-in button below, then complete ChatGPT in this browser.
|
|
2218
|
+
OAuth here is fully guided. After you choose OAuth, we start OpenClaw login automatically. Use the sign-in button below, then complete ChatGPT in this browser. If the redirect does not land automatically, you will be asked to paste the callback URL.
|
|
2142
2219
|
</p>
|
|
2143
2220
|
<div class="oauth-guide">
|
|
2144
2221
|
<p class="muted" style="margin-top:0;">
|
|
2145
|
-
<strong>Important:</strong> Complete the ChatGPT sign-in in this browser, then return to this tab.
|
|
2222
|
+
<strong>Important:</strong> Complete the ChatGPT sign-in in this browser, then return to this tab. If the redirect does not finish on its own, paste the callback URL using the box below.
|
|
2146
2223
|
</p>
|
|
2147
2224
|
<p class="muted" style="margin-top:4px;font-size:13px;color:#7a8ba8;">
|
|
2148
2225
|
<strong>Remote VPS?</strong> Forward port <code>1455</code> alongside the wizard port:
|
|
@@ -2152,13 +2229,13 @@ function wizardHtml(defaults) {
|
|
|
2152
2229
|
<li class="oauth-step pending" id="oauthStepPrepare">Preparing ChatGPT sign-in...</li>
|
|
2153
2230
|
<li class="oauth-step pending" id="oauthStepOpen">Open ChatGPT sign-in in this browser.</li>
|
|
2154
2231
|
<li class="oauth-step pending" id="oauthStepComplete">Finish ChatGPT approval, then return here.</li>
|
|
2155
|
-
<li class="oauth-step pending" id="oauthStepVerify">
|
|
2232
|
+
<li class="oauth-step pending" id="oauthStepVerify">If the redirect does not complete, paste the callback URL below.</li>
|
|
2156
2233
|
</ol>
|
|
2157
2234
|
<div class="oauth-actions">
|
|
2158
2235
|
<a id="oauthOpenUrlBtn" class="secondary" href="#" target="_blank" rel="noopener noreferrer" style="display:inline-block;padding:10px 14px;border-radius:8px;background:#2d7dff;color:#fff;text-decoration:none;font-weight:600;opacity:.55;pointer-events:none;">Open ChatGPT sign-in</a>
|
|
2159
2236
|
<button type="button" id="oauthRetryBtn" class="secondary hidden">Try sign-in again</button>
|
|
2160
2237
|
</div>
|
|
2161
|
-
<p id="oauthFlowStatus" class="muted" style="margin-top:8px;" aria-live="polite">Choose OAuth and wait a moment. We will prepare your sign-in
|
|
2238
|
+
<p id="oauthFlowStatus" class="muted" style="margin-top:8px;" aria-live="polite">Choose OAuth and wait a moment. We will prepare your sign-in link.</p>
|
|
2162
2239
|
<div id="oauthFallbackPaste" class="hidden" style="margin-top:12px;padding:12px;background:#111827;border:1px solid #334a87;border-radius:8px;">
|
|
2163
2240
|
<p class="muted" style="margin:0 0 8px;font-size:13px;color:#ffcc70;">
|
|
2164
2241
|
<strong>Redirect didn't reach us?</strong> Copy the full URL from the error page in your browser (it starts with <code>http://localhost:1455/auth/callback?code=…</code>) and paste it below.
|
|
@@ -2448,7 +2525,7 @@ function wizardHtml(defaults) {
|
|
|
2448
2525
|
setOauthStep(oauthStepOpen, "pending");
|
|
2449
2526
|
setOauthStep(oauthStepComplete, "pending");
|
|
2450
2527
|
setOauthStep(oauthStepVerify, "pending");
|
|
2451
|
-
setOauthStatus("Choose OAuth and wait a moment. We will prepare your sign-in
|
|
2528
|
+
setOauthStatus("Choose OAuth and wait a moment. We will prepare your sign-in link.");
|
|
2452
2529
|
}
|
|
2453
2530
|
|
|
2454
2531
|
(function initLlmAuthDefaults() {
|
|
@@ -2521,7 +2598,7 @@ function wizardHtml(defaults) {
|
|
|
2521
2598
|
setOauthStep(oauthStepComplete, "error");
|
|
2522
2599
|
setOauthStep(oauthStepVerify, "error");
|
|
2523
2600
|
setOauthStatus(
|
|
2524
|
-
"
|
|
2601
|
+
"OAuth session expired. This flow requires the wizard and OpenClaw on the same machine and browser. Click Try sign-in again.",
|
|
2525
2602
|
true,
|
|
2526
2603
|
);
|
|
2527
2604
|
} else {
|
|
@@ -2541,7 +2618,7 @@ function wizardHtml(defaults) {
|
|
|
2541
2618
|
const elapsed = oauthFlowStartedAtMs > 0 ? Math.floor((Date.now() - oauthFlowStartedAtMs) / 1000) : 0;
|
|
2542
2619
|
if (elapsed >= 90) {
|
|
2543
2620
|
setOauthStatus(
|
|
2544
|
-
"Still waiting for callback.
|
|
2621
|
+
"Still waiting for the callback. Make sure you are using this same browser and the 1455 port is forwarded (ssh -L 1455:127.0.0.1:1455). If the redirect does not land, paste the localhost:1455/auth/callback?… URL using the box below.",
|
|
2545
2622
|
true,
|
|
2546
2623
|
);
|
|
2547
2624
|
if (oauthRetryBtn) oauthRetryBtn.classList.remove("hidden");
|
|
@@ -2576,7 +2653,7 @@ function wizardHtml(defaults) {
|
|
|
2576
2653
|
setOauthStep(oauthStepComplete, "error");
|
|
2577
2654
|
setOauthStep(oauthStepVerify, "error");
|
|
2578
2655
|
setOauthStatus(
|
|
2579
|
-
errorText + "
|
|
2656
|
+
errorText + " Make sure you are using the same browser and the 1455 port is forwarded. Click Try sign-in again.",
|
|
2580
2657
|
true,
|
|
2581
2658
|
);
|
|
2582
2659
|
setOauthOpenButton("");
|
|
@@ -3102,7 +3179,7 @@ function wizardHtml(defaults) {
|
|
|
3102
3179
|
setOauthStep(oauthStepOpen, "done");
|
|
3103
3180
|
setOauthStep(oauthStepComplete, "active");
|
|
3104
3181
|
setOauthStep(oauthStepVerify, "active");
|
|
3105
|
-
setOauthStatus("
|
|
3182
|
+
setOauthStatus("After approval, return here. If the tab does not finish, paste the localhost:1455/auth/callback?… URL using the box below.");
|
|
3106
3183
|
showFallbackPasteAfterDelay(15_000);
|
|
3107
3184
|
});
|
|
3108
3185
|
}
|
|
@@ -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
|
|
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
|
|
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.
|
|
3
|
+
"version": "1.0.87",
|
|
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.
|
|
20
|
+
"solana-traderclaw": "^1.0.87"
|
|
21
21
|
},
|
|
22
22
|
"keywords": [
|
|
23
23
|
"traderclaw",
|