@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.
- package/lib/setup.mjs +124 -32
- 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("
|
|
285
|
-
console.log(
|
|
286
|
-
|
|
287
|
-
|
|
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(
|
|
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
|
|
319
|
+
console.log(" • Foundry `cast` not on PATH (optional)");
|
|
292
320
|
}
|
|
293
321
|
if (hints.openclawBots.length) {
|
|
294
322
|
console.log(
|
|
295
|
-
`OpenClaw bot
|
|
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(
|
|
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
|
-
|
|
305
|
-
|
|
306
|
-
|
|
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
|
-
|
|
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("
|
|
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
|
|
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(
|
|
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(
|
|
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("
|
|
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(
|
|
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
|
-
`
|
|
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("
|
|
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(
|
|
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(`
|
|
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(
|
|
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
|
|
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("
|
|
411
|
-
console.log(
|
|
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(
|
|
416
|
-
|
|
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(
|
|
518
|
+
console.log("");
|
|
519
|
+
console.log(`Wrote ${result.configPath}`);
|
|
433
520
|
console.log(`Wrote ${result.operatorPath}`);
|
|
434
521
|
if (!key) {
|
|
435
|
-
console.log("
|
|
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("
|
|
528
|
+
console.log("");
|
|
529
|
+
console.log("Next: clanker whoami");
|
|
438
530
|
}
|
|
439
531
|
return result;
|
|
440
532
|
} finally {
|