naracli 1.0.92 → 1.0.94

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.
@@ -274322,13 +274322,13 @@ async function handleAgentGet(agentId, options) {
274322
274322
  const hoursAgo = (Date.now() - lastRewarded) / (1e3 * 60 * 60);
274323
274323
  if (hoursAgo >= 24) {
274324
274324
  const agoStr = hoursAgo >= 48 ? `${Math.floor(hoursAgo / 24)}d` : `${Math.floor(hoursAgo)}h`;
274325
- console.log(` Tip: Last tweet verified ${agoStr} ago (>24h). You can submit a new tweet to earn more stake-free credits.`);
274325
+ console.log(` Tip: Last tweet verified ${agoStr} ago (>24h). You can submit a new tweet to earn more Boost PoMI credits.`);
274326
274326
  } else {
274327
274327
  const hoursLeft = Math.ceil(24 - hoursAgo);
274328
274328
  console.log(` Tip: Next tweet verification available in ~${hoursLeft}h.`);
274329
274329
  }
274330
274330
  } else {
274331
- console.log(` Tip: Submit a tweet to earn stake-free PoMI mining credits!`);
274331
+ console.log(` Tip: Submit a tweet to earn Boost PoMI credits (stake-free)!`);
274332
274332
  }
274333
274333
  const submitTweetText = randomSubmitTweet();
274334
274334
  const submitTweetIntent = `https://x.com/intent/tweet?text=${submitTweetText.replace(/ /g, "%20").replace(/#/g, "%23").replace(/"/g, "%22")}`;
@@ -274336,11 +274336,12 @@ async function handleAgentGet(agentId, options) {
274336
274336
  console.log(` Link: ${submitTweetIntent}`);
274337
274337
  console.log(` Then run: npx naracli agent submit-tweet <tweet-url>`);
274338
274338
  console.log(` Credits are based on likes, bookmarks, retweets, and quotes.`);
274339
+ console.log(` Submit daily without breaking the streak to multiply your rewards!`);
274339
274340
  console.log("");
274340
274341
  } else {
274341
274342
  const tweetText = randomBindTweet(agentId);
274342
274343
  const tweetIntent = `https://x.com/intent/tweet?text=${tweetText.replace(/ /g, "%20").replace(/#/g, "%23").replace(/"/g, "%22")}`;
274343
- console.log(` Tip: Bind your X(Twitter) to earn 20 NARA + stake-free PoMI mining credits!`);
274344
+ console.log(` Tip: Bind your X(Twitter) to earn 20 NARA + Boost PoMI credits (stake-free)!`);
274344
274345
  console.log(` 1. Post a tweet with this content:`);
274345
274346
  console.log(` ${tweetText}`);
274346
274347
  console.log(` Link: ${tweetIntent}`);
@@ -274496,6 +274497,36 @@ async function handleAgentLog(agentId, activity, log3, options) {
274496
274497
  console.log(` Transaction: ${signature}`);
274497
274498
  }
274498
274499
  }
274500
+ async function handleAgentRecover(agentId, options) {
274501
+ validateName(agentId, "Agent ID");
274502
+ const rpcUrl = getRpcUrl(options.rpcUrl);
274503
+ const wallet = await loadWallet(options.wallet);
274504
+ const pubkey = wallet.publicKey.toBase58();
274505
+ const networkConfig = loadNetworkConfig(rpcUrl, pubkey);
274506
+ if (networkConfig.agent_id) {
274507
+ printError(`Agent ID "${networkConfig.agent_id}" is already saved locally for this wallet. Run "agent clear" first if you want to replace it.`);
274508
+ process.exit(1);
274509
+ }
274510
+ const connection = new import_web3111.Connection(rpcUrl, "confirmed");
274511
+ let info;
274512
+ try {
274513
+ info = await getAgentInfo(connection, agentId);
274514
+ } catch {
274515
+ printError(`Agent "${agentId}" not found on-chain.`);
274516
+ process.exit(1);
274517
+ }
274518
+ const authority = info.record.authority.toBase58();
274519
+ if (authority !== pubkey) {
274520
+ printError(`Wallet ${pubkey} is not the authority of agent "${agentId}" (actual authority: ${authority}).`);
274521
+ process.exit(1);
274522
+ }
274523
+ setAgentId(agentId, rpcUrl, pubkey);
274524
+ if (options.json) {
274525
+ formatOutput({ recovered: true, agentId, authority: pubkey }, true);
274526
+ } else {
274527
+ printSuccess(`Agent ID "${agentId}" saved to local config.`);
274528
+ }
274529
+ }
274499
274530
  async function handleAgentClear(options) {
274500
274531
  const rpcUrl = getRpcUrl(options.rpcUrl);
274501
274532
  let pubkey;
@@ -274764,6 +274795,15 @@ function registerAgentCommands(program3) {
274764
274795
  process.exit(1);
274765
274796
  }
274766
274797
  });
274798
+ agent.command("recover <agent-id>").description("Recover an existing on-chain agent ID to local config (verifies wallet is the authority)").action(async (agentId, _opts, cmd) => {
274799
+ try {
274800
+ const globalOpts = cmd.optsWithGlobals();
274801
+ await handleAgentRecover(agentId, globalOpts);
274802
+ } catch (error) {
274803
+ printError(error.message);
274804
+ process.exit(1);
274805
+ }
274806
+ });
274767
274807
  agent.command("clear").description("Clear saved agent ID from local config (does not delete on-chain)").action(async (_opts, cmd) => {
274768
274808
  try {
274769
274809
  const globalOpts = cmd.optsWithGlobals();
@@ -274824,7 +274864,7 @@ Example:
274824
274864
  const tweetText = randomBindTweet(agentId);
274825
274865
  const tweetIntent = `https://x.com/intent/tweet?text=${tweetText.replace(/ /g, "%20").replace(/#/g, "%23").replace(/"/g, "%22")}`;
274826
274866
  console.log("");
274827
- console.log(` Bind your X(Twitter) to earn 20 NARA + stake-free PoMI mining credits!`);
274867
+ console.log(` Bind your X(Twitter) to earn 20 NARA + Boost PoMI credits (stake-free)!`);
274828
274868
  console.log(` 1. Post a tweet with this content:`);
274829
274869
  console.log(` ${tweetText}`);
274830
274870
  console.log(` Link: ${tweetIntent}`);
@@ -276939,7 +276979,7 @@ function registerCommands(program3) {
276939
276979
  }
276940
276980
 
276941
276981
  // bin/nara-cli.ts
276942
- var version2 = true ? "1.0.92" : "dev";
276982
+ var version2 = true ? "1.0.94" : "dev";
276943
276983
  var program2 = new Command();
276944
276984
  program2.name("naracli").description("CLI for the Nara chain. Native coin is NARA (not SOL). Mine NARA for free via PoMI quests, manage wallets, register agents, and more. Run 'naracli <command> --help' for details on any command.").version(version2);
276945
276985
  program2.option("-r, --rpc-url <url>", "RPC endpoint (default: https://mainnet-api.nara.build/)").option("-w, --wallet <path>", "Path to wallet keypair JSON file (default: ~/.config/nara/id.json)").option("-j, --json", "Output in JSON format");
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "naracli",
3
- "version": "1.0.92",
3
+ "version": "1.0.94",
4
4
  "description": "CLI for the Nara chain (Solana-compatible)",
5
5
  "homepage": "https://nara.build",
6
6
  "repository": {
@@ -264,13 +264,13 @@ async function handleAgentGet(agentId: string, options: GlobalOptions) {
264
264
  const hoursAgo = (Date.now() - lastRewarded) / (1000 * 60 * 60);
265
265
  if (hoursAgo >= 24) {
266
266
  const agoStr = hoursAgo >= 48 ? `${Math.floor(hoursAgo / 24)}d` : `${Math.floor(hoursAgo)}h`;
267
- console.log(` Tip: Last tweet verified ${agoStr} ago (>24h). You can submit a new tweet to earn more stake-free credits.`);
267
+ console.log(` Tip: Last tweet verified ${agoStr} ago (>24h). You can submit a new tweet to earn more Boost PoMI credits.`);
268
268
  } else {
269
269
  const hoursLeft = Math.ceil(24 - hoursAgo);
270
270
  console.log(` Tip: Next tweet verification available in ~${hoursLeft}h.`);
271
271
  }
272
272
  } else {
273
- console.log(` Tip: Submit a tweet to earn stake-free PoMI mining credits!`);
273
+ console.log(` Tip: Submit a tweet to earn Boost PoMI credits (stake-free)!`);
274
274
  }
275
275
  const submitTweetText = randomSubmitTweet();
276
276
  const submitTweetIntent = `https://x.com/intent/tweet?text=${submitTweetText.replace(/ /g, "%20").replace(/#/g, "%23").replace(/"/g, "%22")}`;
@@ -278,12 +278,13 @@ async function handleAgentGet(agentId: string, options: GlobalOptions) {
278
278
  console.log(` Link: ${submitTweetIntent}`);
279
279
  console.log(` Then run: npx naracli agent submit-tweet <tweet-url>`);
280
280
  console.log(` Credits are based on likes, bookmarks, retweets, and quotes.`);
281
+ console.log(` Submit daily without breaking the streak to multiply your rewards!`);
281
282
  console.log("");
282
283
  } else {
283
284
  // Not bound — show bind tip
284
285
  const tweetText = randomBindTweet(agentId);
285
286
  const tweetIntent = `https://x.com/intent/tweet?text=${tweetText.replace(/ /g, "%20").replace(/#/g, "%23").replace(/"/g, "%22")}`;
286
- console.log(` Tip: Bind your X(Twitter) to earn 20 NARA + stake-free PoMI mining credits!`);
287
+ console.log(` Tip: Bind your X(Twitter) to earn 20 NARA + Boost PoMI credits (stake-free)!`);
287
288
  console.log(` 1. Post a tweet with this content:`);
288
289
  console.log(` ${tweetText}`);
289
290
  console.log(` Link: ${tweetIntent}`);
@@ -478,6 +479,44 @@ async function handleAgentLog(
478
479
  }
479
480
  }
480
481
 
482
+ async function handleAgentRecover(agentId: string, options: GlobalOptions) {
483
+ validateName(agentId, "Agent ID");
484
+ const rpcUrl = getRpcUrl(options.rpcUrl);
485
+ const wallet = await loadWallet(options.wallet);
486
+ const pubkey = wallet.publicKey.toBase58();
487
+
488
+ // Check if local config already has an agent ID for this wallet
489
+ const networkConfig = loadNetworkConfig(rpcUrl, pubkey);
490
+ if (networkConfig.agent_id) {
491
+ printError(`Agent ID "${networkConfig.agent_id}" is already saved locally for this wallet. Run "agent clear" first if you want to replace it.`);
492
+ process.exit(1);
493
+ }
494
+
495
+ const connection = new Connection(rpcUrl, "confirmed");
496
+
497
+ // Verify on-chain: agent exists and authority matches current wallet
498
+ let info;
499
+ try {
500
+ info = await getAgentInfo(connection, agentId);
501
+ } catch {
502
+ printError(`Agent "${agentId}" not found on-chain.`);
503
+ process.exit(1);
504
+ }
505
+ const authority = info.record.authority.toBase58();
506
+ if (authority !== pubkey) {
507
+ printError(`Wallet ${pubkey} is not the authority of agent "${agentId}" (actual authority: ${authority}).`);
508
+ process.exit(1);
509
+ }
510
+
511
+ setAgentId(agentId, rpcUrl, pubkey);
512
+
513
+ if (options.json) {
514
+ formatOutput({ recovered: true, agentId, authority: pubkey }, true);
515
+ } else {
516
+ printSuccess(`Agent ID "${agentId}" saved to local config.`);
517
+ }
518
+ }
519
+
481
520
  async function handleAgentClear(options: GlobalOptions) {
482
521
  const rpcUrl = getRpcUrl(options.rpcUrl);
483
522
  let pubkey: string | undefined;
@@ -854,6 +893,20 @@ export function registerAgentCommands(program: Command): void {
854
893
  }
855
894
  });
856
895
 
896
+ // agent recover
897
+ agent
898
+ .command("recover <agent-id>")
899
+ .description("Recover an existing on-chain agent ID to local config (verifies wallet is the authority)")
900
+ .action(async (agentId: string, _opts: any, cmd: Command) => {
901
+ try {
902
+ const globalOpts = cmd.optsWithGlobals() as GlobalOptions;
903
+ await handleAgentRecover(agentId, globalOpts);
904
+ } catch (error: any) {
905
+ printError(error.message);
906
+ process.exit(1);
907
+ }
908
+ });
909
+
857
910
  // agent clear
858
911
  agent
859
912
  .command("clear")
@@ -945,7 +998,7 @@ Example:
945
998
  const tweetText = randomBindTweet(agentId);
946
999
  const tweetIntent = `https://x.com/intent/tweet?text=${tweetText.replace(/ /g, "%20").replace(/#/g, "%23").replace(/"/g, "%22")}`;
947
1000
  console.log("");
948
- console.log(` Bind your X(Twitter) to earn 20 NARA + stake-free PoMI mining credits!`);
1001
+ console.log(` Bind your X(Twitter) to earn 20 NARA + Boost PoMI credits (stake-free)!`);
949
1002
  console.log(` 1. Post a tweet with this content:`);
950
1003
  console.log(` ${tweetText}`);
951
1004
  console.log(` Link: ${tweetIntent}`);