traderclaw-cli 1.0.102 → 1.0.103

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.
@@ -198,23 +198,34 @@ export async function ensureLinuxGatewayPersistence(options = {}) {
198
198
  let unitEnabled = false;
199
199
  try {
200
200
  await runSpawn("systemctl", ["--user", "daemon-reload"]);
201
- await runSpawn("systemctl", ["--user", "enable", unitName]);
201
+ await runSpawn("systemctl", ["--user", "enable", "--now", unitName]);
202
202
  unitEnabled = true;
203
- emit("info", `systemd user unit enabled: ${unitName}`);
203
+ emit("info", `systemd user unit enabled and started: ${unitName}`);
204
204
  } catch (err) {
205
205
  const msg = err?.stderr || err?.message || String(err);
206
- errors.push(`systemctl --user enable: ${msg}`);
206
+ errors.push(`systemctl --user enable --now: ${msg}`);
207
207
  emit(
208
208
  "warn",
209
- `Could not enable user unit ${unitName} (${msg.trim()}). If the gateway was installed, try: systemctl --user enable ${unitName}`,
209
+ `Could not enable/start user unit ${unitName} (${msg.trim()}). If the gateway was installed, try: systemctl --user enable --now ${unitName}`,
210
210
  );
211
211
  }
212
212
 
213
+ let unitActive = false;
214
+ try {
215
+ await runSpawn("systemctl", ["--user", "is-active", unitName]);
216
+ unitActive = true;
217
+ emit("info", `${unitName} is active.`);
218
+ } catch {
219
+ // is-active exits non-zero when inactive; not a hard error
220
+ emit("info", `${unitName} is not yet active (may need: openclaw gateway restart).`);
221
+ }
222
+
213
223
  return {
214
224
  skipped: false,
215
225
  linger: lingerOk,
216
226
  unitName,
217
227
  unitEnabled,
228
+ unitActive,
218
229
  errors: errors.length ? errors : undefined,
219
230
  };
220
231
  }
@@ -6,7 +6,7 @@ import { dirname, join } from "path";
6
6
  import { fileURLToPath, pathToFileURL } from "url";
7
7
  import { homedir } from "os";
8
8
  import { randomUUID, createPrivateKey, sign as cryptoSign } from "crypto";
9
- import { execFile, execFileSync, execSync } from "child_process";
9
+ import { execFile, execFileSync, execSync, spawnSync } from "child_process";
10
10
  import { promisify } from "util";
11
11
  import { createServer } from "http";
12
12
  import { resolvePluginPackageRoot } from "./resolve-plugin-root.mjs";
@@ -65,6 +65,9 @@ try {
65
65
  const VERSION = CLI_VERSION || PLUGIN_VERSION;
66
66
  const PLUGIN_ID = "solana-trader";
67
67
  const LEGACY_PLUGIN_IDS = ["traderclaw-v1", "solana-traderclaw-v1", "solana-traderclaw"];
68
+ const KAYBA_TRACING_PLUGIN_ID = "kayba-tracing";
69
+ const KAYBA_TRACING_NPM_PACKAGE = "@kayba_ai/openclaw-tracing";
70
+ const KAYBA_TRACING_FOLDER_DEFAULT = "traderclaw-agent";
68
71
  const CONFIG_DIR = join(homedir(), ".openclaw");
69
72
  const CONFIG_FILE = join(CONFIG_DIR, "openclaw.json");
70
73
  const WALLET_PRIVATE_KEY_ENV = "TRADERCLAW_WALLET_PRIVATE_KEY";
@@ -469,6 +472,48 @@ function setPluginConfig(config, pluginConfig) {
469
472
  };
470
473
  }
471
474
 
475
+ function setKaybaTracingPluginConfig(config, kaybaApiKey, folder) {
476
+ normalizePluginConfigShape(config);
477
+ if (!config.plugins) config.plugins = {};
478
+ if (!config.plugins.entries) config.plugins.entries = {};
479
+ if (!Array.isArray(config.plugins.allow)) config.plugins.allow = [];
480
+ if (!config.plugins.allow.includes(KAYBA_TRACING_PLUGIN_ID)) {
481
+ config.plugins.allow.push(KAYBA_TRACING_PLUGIN_ID);
482
+ }
483
+ const prev = config.plugins.entries[KAYBA_TRACING_PLUGIN_ID];
484
+ const prevConfig = prev && typeof prev.config === "object" && prev.config !== null ? prev.config : {};
485
+ config.plugins.entries[KAYBA_TRACING_PLUGIN_ID] = {
486
+ enabled: true,
487
+ hooks: { allowConversationAccess: true },
488
+ config: {
489
+ ...prevConfig,
490
+ apiKey: kaybaApiKey,
491
+ folder: prevConfig.folder || folder || KAYBA_TRACING_FOLDER_DEFAULT,
492
+ },
493
+ };
494
+ }
495
+
496
+ async function installAndEnableKaybaTracingPlugin() {
497
+ // Best-effort: openclaw plugins install <pkg> + enable <id>. Returns null on success, error message on failure.
498
+ try {
499
+ await execFileAsync("openclaw", ["plugins", "install", KAYBA_TRACING_NPM_PACKAGE], { env: NO_COLOR_ENV });
500
+ } catch (err) {
501
+ const text = `${err?.message || ""}\n${err?.stderr || ""}`.toLowerCase();
502
+ if (!text.includes("already exists") && !text.includes("already installed")) {
503
+ return err instanceof Error ? err.message : String(err);
504
+ }
505
+ }
506
+ try {
507
+ await execFileAsync("openclaw", ["plugins", "enable", KAYBA_TRACING_PLUGIN_ID], { env: NO_COLOR_ENV });
508
+ } catch (err) {
509
+ const text = `${err?.message || ""}\n${err?.stderr || ""}`.toLowerCase();
510
+ if (!text.includes("already enabled")) {
511
+ return err instanceof Error ? err.message : String(err);
512
+ }
513
+ }
514
+ return null;
515
+ }
516
+
472
517
  function getGatewayConfig(config) {
473
518
  if (!config || typeof config !== "object") return {};
474
519
  if (!config.gateway || typeof config.gateway !== "object") return {};
@@ -829,6 +874,7 @@ async function cmdSetup(args) {
829
874
  let forwardTelegramRecipientArg = "";
830
875
  let referralCodeArg = "";
831
876
  let referralInvalidRetries = 0;
877
+ let kaybaApiKeyArg = "";
832
878
 
833
879
  for (let i = 0; i < args.length; i++) {
834
880
  if ((args[i] === "--api-key" || args[i] === "-k") && args[i + 1]) {
@@ -878,6 +924,9 @@ async function cmdSetup(args) {
878
924
  if ((args[i] === "--referral-code" || args[i] === "-r") && args[i + 1]) {
879
925
  referralCodeArg = args[++i];
880
926
  }
927
+ if ((args[i] === "--kayba-key" || args[i] === "--kayba-api-key") && args[i + 1]) {
928
+ kaybaApiKeyArg = args[++i];
929
+ }
881
930
  }
882
931
  const runtimeWalletPrivateKey = getRuntimeWalletPrivateKey(walletPrivateKey);
883
932
 
@@ -1216,12 +1265,30 @@ async function cmdSetup(args) {
1216
1265
  }
1217
1266
  }
1218
1267
 
1268
+ let kaybaApiKey = (kaybaApiKeyArg || process.env.KAYBA_API_KEY || prevPlugin?.kaybaApiKey || "").trim();
1269
+ if (!kaybaApiKey) {
1270
+ print("\nKayba tracing (optional)...\n");
1271
+ printInfo(" Capture every agent turn — full LLM prompts, tool calls, replies — for observability.");
1272
+ printInfo(" Get a key at https://use.kayba.ai/settings/api-keys, or use one provided by your operator.");
1273
+ kaybaApiKey = (await prompt("Kayba API key (kayba_ak_..., Enter to skip)", "")).trim();
1274
+ } else {
1275
+ printInfo(`\n Reusing Kayba API key: ${maskKey(kaybaApiKey)}`);
1276
+ }
1277
+ if (kaybaApiKey) {
1278
+ pluginConfig.kaybaApiKey = kaybaApiKey;
1279
+ if (!pluginConfig.kaybaFolder) pluginConfig.kaybaFolder = "traderclaw";
1280
+ }
1281
+
1219
1282
  print("\nWriting configuration...\n");
1220
1283
 
1221
1284
  const existingConfig = readConfig();
1222
1285
  removeLegacyWalletPrivateKey(pluginConfig);
1223
1286
  setPluginConfig(existingConfig, pluginConfig);
1224
1287
 
1288
+ if (kaybaApiKey) {
1289
+ setKaybaTracingPluginConfig(existingConfig, kaybaApiKey, KAYBA_TRACING_FOLDER_DEFAULT);
1290
+ }
1291
+
1225
1292
  if (!existingConfig.agents || typeof existingConfig.agents !== "object") {
1226
1293
  existingConfig.agents = {};
1227
1294
  }
@@ -1251,6 +1318,17 @@ async function cmdSetup(args) {
1251
1318
 
1252
1319
  printSuccess(` Config written to ${CONFIG_FILE}`);
1253
1320
 
1321
+ if (kaybaApiKey) {
1322
+ print(`\nInstalling ${KAYBA_TRACING_PLUGIN_ID} plugin (one-time)...\n`);
1323
+ const installErr = await installAndEnableKaybaTracingPlugin();
1324
+ if (installErr) {
1325
+ printWarn(` Plugin install failed: ${installErr}`);
1326
+ printWarn(` Finish manually: openclaw plugins install ${KAYBA_TRACING_NPM_PACKAGE} && openclaw plugins enable ${KAYBA_TRACING_PLUGIN_ID}`);
1327
+ } else {
1328
+ printSuccess(` ${KAYBA_TRACING_PLUGIN_ID} installed and enabled (folder: ${KAYBA_TRACING_FOLDER_DEFAULT})`);
1329
+ }
1330
+ }
1331
+
1254
1332
  if (!skipGatewayRegistration) {
1255
1333
  print("\nGateway forwarding setup (required for event-driven wakeups)...\n");
1256
1334
 
@@ -4242,15 +4320,17 @@ Setup options:
4242
4320
  --gateway-token, -t Gateway bearer token (defaults to API key)
4243
4321
  --telegram-recipient Telegram @username or chat id (aliases: --forward-telegram-chat-id, --telegram-chat-id)
4244
4322
  --referral-code, -r Optional referral code for new signups (extra trial time when valid)
4323
+ --kayba-key Kayba API key (kayba_ak_...) — captures every agent turn to your Kayba dashboard.
4324
+ Aliases: --kayba-api-key. Env fallback: KAYBA_API_KEY. Skip with empty value.
4245
4325
  --skip-gateway-registration Skip gateway URL registration with orchestrator
4246
4326
  --show-api-key Extra hint after signup (full key is always shown once; confirm with API_KEY_STORED)
4247
4327
  --show-wallet-private-key Reveal full wallet private key in setup output
4248
4328
  --signup Force signup flow (create new account)
4249
4329
  --write-gateway-env Write TRADERCLAW_WALLET_PRIVATE_KEY to a systemd EnvironmentFile for the user gateway (Linux)
4250
- --no-ensure-gateway-persistent Skip automatic Linux loginctl linger + user unit enable after setup
4330
+ --no-ensure-gateway-persistent Skip automatic Linux loginctl linger + systemctl --user enable --now after setup
4251
4331
 
4252
4332
  Gateway subcommands:
4253
- gateway ensure-persistent Linux: enable loginctl linger and systemd --user unit for OpenClaw gateway
4333
+ gateway ensure-persistent Linux: enable loginctl linger and systemctl --user enable --now for OpenClaw gateway
4254
4334
 
4255
4335
  Login options:
4256
4336
  --wallet-private-key <k> Base58 key for wallet proof (runtime only, never saved). Optional in a
@@ -4287,6 +4367,8 @@ Examples:
4287
4367
  traderclaw setup --api-key oc_xxx --url https://api.traderclaw.ai
4288
4368
  traderclaw setup --gateway-base-url https://gateway.myhost.ts.net
4289
4369
  traderclaw setup --telegram-recipient @myusername
4370
+ traderclaw setup --kayba-key kayba_ak_xxx # one-shot Kayba tracing setup (installs kayba-tracing plugin)
4371
+ KAYBA_API_KEY=kayba_ak_xxx traderclaw setup # same via env var
4290
4372
  traderclaw login
4291
4373
  traderclaw login --force-reauth --wallet-private-key <base58_key>
4292
4374
  traderclaw logout
@@ -4453,17 +4535,46 @@ async function cmdUpdate(args) {
4453
4535
  }
4454
4536
 
4455
4537
  if (dryRun) {
4456
- print(`\n [dry-run] Would run: openclaw gateway restart\n`);
4538
+ print(`\n [dry-run] Would run: systemctl --user enable --now + restart (Linux) or openclaw gateway restart\n`);
4457
4539
  } else {
4458
- if (!commandExists("openclaw")) {
4459
- printWarn("\n Skipping gateway restart: openclaw not in PATH. After fixing PATH: openclaw gateway restart");
4460
- } else {
4540
+ const { isLinuxGatewayPersistenceEligible, ensureLinuxGatewayPersistence, resolveGatewayUnitNameFromStatusJson, readOpenclawGatewayStatusJson } = await import("./gateway-persistence-linux.mjs");
4541
+ if (isLinuxGatewayPersistenceEligible()) {
4542
+ print("\n Gateway persistence (Linux)...\n");
4543
+ let unitName = "openclaw-gateway.service";
4544
+ try {
4545
+ const statusJson = readOpenclawGatewayStatusJson();
4546
+ unitName = resolveGatewayUnitNameFromStatusJson(statusJson);
4547
+ await ensureLinuxGatewayPersistence({
4548
+ emitLog: (level, text) => {
4549
+ if (level === "warn") printWarn(` ${text}`);
4550
+ else printInfo(` ${text}`);
4551
+ },
4552
+ });
4553
+ } catch (err) {
4554
+ printWarn(` Gateway persistence (optional): ${err.message || err}`);
4555
+ }
4461
4556
  print("\n Restarting gateway...\n");
4462
4557
  try {
4463
- execFileSync("openclaw", ["gateway", "restart"], { stdio: "inherit" });
4464
- printSuccess(" Gateway restarted.");
4465
- } catch {
4466
- printWarn(" Gateway restart returned non-zero. Try manually: openclaw gateway restart");
4558
+ const r = spawnSync("systemctl", ["--user", "restart", unitName], { stdio: "inherit" });
4559
+ if (r.status === 0) {
4560
+ printSuccess(` Gateway restarted (systemctl --user restart ${unitName}).`);
4561
+ } else {
4562
+ printWarn(` systemctl --user restart returned ${r.status}. Try: systemctl --user restart ${unitName}`);
4563
+ }
4564
+ } catch (err) {
4565
+ printWarn(` systemctl --user restart: ${err.message || err}. Try manually: systemctl --user restart ${unitName}`);
4566
+ }
4567
+ } else {
4568
+ if (!commandExists("openclaw")) {
4569
+ printWarn("\n Skipping gateway restart: openclaw not in PATH. After fixing PATH: openclaw gateway restart");
4570
+ } else {
4571
+ print("\n Restarting gateway...\n");
4572
+ try {
4573
+ execFileSync("openclaw", ["gateway", "restart"], { stdio: "inherit" });
4574
+ printSuccess(" Gateway restarted.");
4575
+ } catch {
4576
+ printWarn(" Gateway restart returned non-zero. Try manually: openclaw gateway restart");
4577
+ }
4467
4578
  }
4468
4579
  }
4469
4580
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "traderclaw-cli",
3
- "version": "1.0.102",
3
+ "version": "1.0.103",
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.102"
20
+ "solana-traderclaw": "^1.0.103"
21
21
  },
22
22
  "keywords": [
23
23
  "traderclaw",