@clanker-chain/clanker-cli 2026.9.7-1 → 2026.9.7-2

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.
Files changed (2) hide show
  1. package/lib/setup.mjs +124 -32
  2. package/package.json +1 -1
package/lib/setup.mjs CHANGED
@@ -281,37 +281,92 @@ export async function runSetupInteractive(argv, opts = {}) {
281
281
  };
282
282
 
283
283
  try {
284
- console.log("clanker setup — local profile wizard");
285
- console.log(`home: ${home}`);
286
- if (hints.hasConfig) console.log(`existing config: ${hints.configPath}`);
287
- if (hints.hasOperator) console.log(`existing operator: ${hints.operatorPath}`);
284
+ console.log("");
285
+ console.log("clanker setup — create your local operator profile");
286
+ console.log("");
287
+ console.log(
288
+ "This writes ~/.clanker/config.json (network) and operator.json (who you are).",
289
+ );
290
+ console.log(
291
+ "Reads like `clanker whoami` can use the owner address without a private key;",
292
+ );
293
+ console.log("mint/revoke still need a key file or OPERATOR_PRIVATE_KEY later.");
294
+ console.log("");
295
+ console.log(`Profile directory: ${home}`);
296
+ console.log("");
297
+
298
+ // Detection summary
299
+ console.log("Detected on this machine:");
300
+ if (hints.hasConfig) {
301
+ const p = hints.config?.preset ?? "?";
302
+ const reg = hints.config?.registryAddress ?? "(none)";
303
+ console.log(` • Network config already at config.json (preset=${p}, registry=${reg})`);
304
+ } else {
305
+ console.log(" • No config.json yet — will create one");
306
+ }
307
+ if (hints.hasOperator) {
308
+ console.log(
309
+ ` • Operator profile already at operator.json (label=${hints.operator?.label}, owner=${hints.operator?.owner})`,
310
+ );
311
+ } else {
312
+ console.log(" • No operator.json yet — that is what we need for bare `whoami`");
313
+ }
288
314
  if (hints.foundryAvailable && hints.foundryAccounts.length) {
289
- console.log(`Foundry accounts: ${hints.foundryAccounts.join(", ")}`);
315
+ console.log(
316
+ ` • Foundry keystore accounts: ${hints.foundryAccounts.join(", ")} (names only; you paste the 0x address)`,
317
+ );
290
318
  } else if (!hints.foundryAvailable) {
291
- console.log("Foundry cast: not found (optional)");
319
+ console.log("Foundry `cast` not on PATH (optional)");
292
320
  }
293
321
  if (hints.openclawBots.length) {
294
322
  console.log(
295
- `OpenClaw bot keys: ${hints.openclawBots.join(", ")} (bot keys ≠ operator owner)`,
323
+ `OpenClaw bot key files: ${hints.openclawBots.join(", ")}`,
324
+ );
325
+ console.log(
326
+ " (These are bot signing keys — not your operator wallet. Useful context only.)",
296
327
  );
297
328
  }
298
329
  if (hints.hasOperatorPrivateKeyEnv) {
299
- console.log(`OPERATOR_PRIVATE_KEY: set → ${hints.envAddress ?? "(invalid)"}`);
330
+ console.log(
331
+ ` • OPERATOR_PRIVATE_KEY is set in this shell → ${hints.envAddress ?? "(invalid key)"}`,
332
+ );
300
333
  }
301
334
  console.log("");
302
335
 
303
336
  if ((hints.hasConfig || hints.hasOperator) && !flags.force) {
304
- const overwrite = await askYesNo("Overwrite existing ~/.clanker profile?", false);
305
- if (!overwrite) {
306
- throw new Error("Aborted (profile exists). Re-run with --force to overwrite.");
337
+ if (hints.hasConfig && !hints.hasOperator) {
338
+ console.log(
339
+ "You already have network settings from `clanker init`, but no operator identity.",
340
+ );
341
+ console.log(
342
+ "Continuing will refresh config.json if needed and create operator.json.",
343
+ );
344
+ const cont = await askYesNo("Continue setup?", true);
345
+ if (!cont) {
346
+ throw new Error("Aborted. Re-run `clanker setup` when ready.");
347
+ }
348
+ flags.force = true;
349
+ } else {
350
+ console.log(
351
+ "A full profile already exists. Continuing will REPLACE config.json and/or operator.json",
352
+ );
353
+ console.log("with the answers you give next (same files, new contents).");
354
+ const overwrite = await askYesNo("Replace existing profile files?", false);
355
+ if (!overwrite) {
356
+ throw new Error(
357
+ "Aborted. Pass --force to replace, or edit ~/.clanker/*.json by hand.",
358
+ );
359
+ }
360
+ flags.force = true;
307
361
  }
308
- flags.force = true;
362
+ console.log("");
309
363
  }
310
364
 
365
+ console.log("— Network —");
311
366
  let preset =
312
367
  flags.preset ||
313
368
  hints.config?.preset ||
314
- (await ask("Preset (sepolia|local)", "sepolia"));
369
+ (await ask("Which network? sepolia (public hub) or local (Anvil)", "sepolia"));
315
370
  preset = String(preset).toLowerCase();
316
371
  if (!PRESETS[preset]) throw new Error(`Unknown preset "${preset}"`);
317
372
 
@@ -321,7 +376,7 @@ export async function runSetupInteractive(argv, opts = {}) {
321
376
  fromBlock != null
322
377
  ? false
323
378
  : await askYesNo(
324
- `Use faster fromBlock ${SEPOLIA_FAST_FROM_BLOCK} for public RPC scans?`,
379
+ `Speed up chain scans? Use fromBlock ${SEPOLIA_FAST_FROM_BLOCK} (recommended on public RPC)`,
325
380
  true,
326
381
  );
327
382
  if (fromBlock == null) {
@@ -329,25 +384,41 @@ export async function runSetupInteractive(argv, opts = {}) {
329
384
  }
330
385
  }
331
386
 
387
+ console.log("");
388
+ console.log("— Operator identity —");
389
+ console.log(
390
+ "We need the wallet address that owns (or will own) your on-chain operator label.",
391
+ );
332
392
  let address = flags.address ?? null;
333
393
  if (!address && flags.keyFile) {
334
394
  address = addressFromKeyFile(flags.keyFile);
395
+ console.log(`Using address from --key-file: ${address}`);
335
396
  }
336
397
  if (!address && hints.envAddress) {
337
- const useEnv = await askYesNo(`Use address from OPERATOR_PRIVATE_KEY (${hints.envAddress})?`, true);
398
+ const useEnv = await askYesNo(
399
+ `Use address from OPERATOR_PRIVATE_KEY (${hints.envAddress})?`,
400
+ true,
401
+ );
338
402
  if (useEnv) address = hints.envAddress;
339
403
  }
340
404
  if (!address && hints.operator?.owner) {
341
- const useOp = await askYesNo(`Use existing operator.json owner (${hints.operator.owner})?`, true);
405
+ const useOp = await askYesNo(
406
+ `Keep existing operator.json owner (${hints.operator.owner})?`,
407
+ true,
408
+ );
342
409
  if (useOp) address = hints.operator.owner;
343
410
  }
344
411
  if (!address && hints.foundryAccounts.length) {
345
- console.log("Foundry accounts (signing still needs --key-file or OPERATOR_PRIVATE_KEY):");
412
+ console.log("");
413
+ console.log("Foundry accounts on this machine (passwords are never stored here):");
346
414
  hints.foundryAccounts.forEach((n, i) => console.log(` ${i + 1}. ${n}`));
347
- const pick = await ask("Foundry account name to associate (or leave blank)", "");
415
+ const pick = await ask(
416
+ "Type a Foundry account name to use, or leave blank to paste an address",
417
+ hints.foundryAccounts[0] ?? "",
418
+ );
348
419
  if (pick) {
349
420
  address = await ask(
350
- `Address for Foundry account "${pick}" (paste 0x…; unlock via cast if needed)`,
421
+ `Paste the 0x address for "${pick}" (cast wallet address ${pick} after unlock)`,
351
422
  "",
352
423
  );
353
424
  }
@@ -363,11 +434,13 @@ export async function runSetupInteractive(argv, opts = {}) {
363
434
  let label =
364
435
  flags.operator ||
365
436
  hints.operator?.label ||
366
- (await ask("Operator label (e.g. org.you)", ""));
437
+ (await ask("Operator label on-chain (e.g. org.openclaw.pat or org.you)", ""));
367
438
  if (!label) throw new Error("Operator label is required");
368
439
 
369
440
  const presetCfg = PRESETS[preset];
370
- console.log("Checking chain…");
441
+ console.log("");
442
+ console.log("— Chain check —");
443
+ console.log(`Looking up "${label}" on ${preset}…`);
371
444
  const check = await assertSetupIdentity({
372
445
  rpc: presetCfg.chainRpcUrl,
373
446
  registry: presetCfg.registryAddress,
@@ -376,22 +449,32 @@ export async function runSetupInteractive(argv, opts = {}) {
376
449
  skipChainCheck: flags.skipChainCheck || !presetCfg.registryAddress,
377
450
  });
378
451
  if (check.unregistered) {
379
- console.log(`Note: "${label}" is not registered yet — run clanker operator mint after setup.`);
452
+ console.log(
453
+ `OK: "${label}" is not registered yet — after setup, run: clanker operator mint ${label}`,
454
+ );
380
455
  } else if (check.operator) {
381
- console.log(`On-chain: ${label} active, owner matches.`);
456
+ console.log(`OK: "${label}" is active on-chain and owned by this address.`);
382
457
  }
383
458
 
459
+ console.log("");
460
+ console.log("— Signing key (optional) —");
461
+ console.log(
462
+ "Only needed for mint/revoke/transfer. Skip for read-only whoami/bots.",
463
+ );
384
464
  let keyFile = flags.keyFile;
385
465
  let keyEnv = flags.keyEnv;
386
466
  let skipKey = flags.skipKey;
387
467
  if (!skipKey && !keyFile && !keyEnv) {
388
468
  if (hints.hasOperatorPrivateKeyEnv) {
389
- const use = await askYesNo("Store env pointer OPERATOR_PRIVATE_KEY for signing?", true);
469
+ const use = await askYesNo(
470
+ "Remember OPERATOR_PRIVATE_KEY as the signing pointer in operator.json?",
471
+ true,
472
+ );
390
473
  if (use) keyEnv = "OPERATOR_PRIVATE_KEY";
391
474
  else skipKey = true;
392
475
  } else {
393
476
  const path = await ask(
394
- "Path to operator key file for signing (leave blank for read-only whoami)",
477
+ "Path to operator private-key file (blank = read-only profile)",
395
478
  "",
396
479
  );
397
480
  if (path) keyFile = path;
@@ -407,13 +490,16 @@ export async function runSetupInteractive(argv, opts = {}) {
407
490
  }
408
491
  }
409
492
 
410
- console.log("\nWill write:");
411
- console.log(` preset: ${preset}`);
493
+ console.log("");
494
+ console.log("— Summary (about to write) —");
495
+ console.log(` network: ${preset}`);
412
496
  console.log(` fromBlock:${fromBlock ?? presetCfg.fromBlock}`);
413
497
  console.log(` label: ${label}`);
414
498
  console.log(` owner: ${address}`);
415
- console.log(` key: ${key ? `${key.type}=${key.value}` : "(none — read-only)"}`);
416
- const ok = flags.yes || (await askYesNo("Write profile?", true));
499
+ console.log(
500
+ ` signing: ${key ? `${key.type}=${key.value}` : "none (read-only whoami/bots)"}`,
501
+ );
502
+ const ok = flags.yes || (await askYesNo("Write these files now?", true));
417
503
  if (!ok) throw new Error("Aborted");
418
504
 
419
505
  const result = applySetup(
@@ -429,12 +515,18 @@ export async function runSetupInteractive(argv, opts = {}) {
429
515
  { home, env },
430
516
  );
431
517
 
432
- console.log(`\nWrote ${result.configPath}`);
518
+ console.log("");
519
+ console.log(`Wrote ${result.configPath}`);
433
520
  console.log(`Wrote ${result.operatorPath}`);
434
521
  if (!key) {
435
- console.log("Read-only profile: `clanker whoami` works; mint/revoke need --key-file or OPERATOR_PRIVATE_KEY.");
522
+ console.log("");
523
+ console.log("Next: clanker whoami");
524
+ console.log(
525
+ "For mint/revoke later: re-run setup with a key file, or pass --key-file / OPERATOR_PRIVATE_KEY.",
526
+ );
436
527
  } else {
437
- console.log("Try: clanker whoami");
528
+ console.log("");
529
+ console.log("Next: clanker whoami");
438
530
  }
439
531
  return result;
440
532
  } finally {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@clanker-chain/clanker-cli",
3
- "version": "2026.9.7-1",
3
+ "version": "2026.9.7-2",
4
4
  "description": "CLI for wiring clanker-chain identity and MQTT into OpenClaw and other agentic stacks.",
5
5
  "type": "module",
6
6
  "bin": {