naracli 1.0.65 → 1.0.67

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.
@@ -172227,7 +172227,7 @@ async function handleAgentGet(agentId, options) {
172227
172227
  if (tv) {
172228
172228
  tweetVerifyData = {
172229
172229
  tweetId: tv.tweetId.toString(),
172230
- status: TWITTER_STATUS[tv.status] ?? `unknown(${tv.status})`,
172230
+ status: TWEET_VERIFY_STATUS[tv.status] ?? `unknown(${tv.status})`,
172231
172231
  submittedAt: tv.submittedAt ? new Date(tv.submittedAt * 1e3).toISOString() : null,
172232
172232
  lastRewardedAt: tv.lastRewardedAt ? new Date(tv.lastRewardedAt * 1e3).toISOString() : null
172233
172233
  };
@@ -172263,7 +172263,8 @@ async function handleAgentGet(agentId, options) {
172263
172263
  console.log(` Twitter: (none)`);
172264
172264
  }
172265
172265
  if (tweetVerifyData) {
172266
- console.log(` Tweet verify: ${tweetVerifyData.tweetId} (${tweetVerifyData.status})`);
172266
+ const verified = tweetVerifyData.lastRewardedAt ? "verified" : "unverified";
172267
+ console.log(` Tweet: ${tweetVerifyData.tweetId} (${verified})`);
172267
172268
  if (tweetVerifyData.lastRewardedAt) console.log(` Tweet last rewarded: ${tweetVerifyData.lastRewardedAt}`);
172268
172269
  }
172269
172270
  console.log("");
@@ -172272,16 +172273,16 @@ async function handleAgentGet(agentId, options) {
172272
172273
  const lastRewarded = new Date(tweetVerifyData.lastRewardedAt).getTime();
172273
172274
  const hoursAgo = (Date.now() - lastRewarded) / (1e3 * 60 * 60);
172274
172275
  if (hoursAgo >= 24) {
172275
- console.log(` Tip: You can verify your tweet again to earn more stake-free credits.`);
172276
- console.log(` npx naracli agent submit-tweet <tweet-url>`);
172276
+ const h2 = Math.floor(hoursAgo);
172277
+ console.log(` Tip: Last tweet verified ${h2}h ago (>24h). You can submit a new tweet to earn more stake-free credits.`);
172277
172278
  } else {
172278
172279
  const hoursLeft = Math.ceil(24 - hoursAgo);
172279
172280
  console.log(` Tip: Next tweet verification available in ~${hoursLeft}h.`);
172280
172281
  }
172281
172282
  } else {
172282
172283
  console.log(` Tip: Submit a tweet to earn stake-free PoMI mining credits!`);
172283
- console.log(` npx naracli agent submit-tweet <tweet-url>`);
172284
172284
  }
172285
+ console.log(` npx naracli agent submit-tweet <tweet-url>`);
172285
172286
  console.log(` Stake-free credits are based on tweet likes, bookmarks, retweets, and quotes.`);
172286
172287
  console.log("");
172287
172288
  } else {
@@ -172466,6 +172467,7 @@ async function handleAgentClear(options) {
172466
172467
  }
172467
172468
  }
172468
172469
  var TWITTER_STATUS = { 0: "none", 1: "pending", 2: "verified", 3: "rejected" };
172470
+ var TWEET_VERIFY_STATUS = { 0: "ready", 1: "pending", 2: "approved", 3: "rejected" };
172469
172471
  function parseTweetUrl(url) {
172470
172472
  const m = url.match(/^https?:\/\/(?:x\.com|twitter\.com)\/([A-Za-z0-9_]+)\/status\/(\d+)/);
172471
172473
  if (!m) {
@@ -172913,6 +172915,38 @@ function registerCommands(program3) {
172913
172915
  process.exit(1);
172914
172916
  }
172915
172917
  });
172918
+ program3.command("airdrop").description("Claim a free NARA airdrop (0.1 NARA, once per 24 hours per address/IP)").action(async () => {
172919
+ const opts = program3.opts();
172920
+ try {
172921
+ const wallet = await loadWallet(opts.wallet);
172922
+ const address = wallet.publicKey.toBase58();
172923
+ if (!opts.json) printInfo(`Requesting airdrop for ${address}...`);
172924
+ const res = await fetch("https://quest-api.nara.build/airdrop", {
172925
+ method: "POST",
172926
+ headers: { "Content-Type": "application/json" },
172927
+ body: JSON.stringify({ wallet: address })
172928
+ });
172929
+ const data = await res.json();
172930
+ if (data.error) {
172931
+ if (data.retryAfterSeconds) {
172932
+ const hours = Math.ceil(data.retryAfterSeconds / 3600);
172933
+ printError(`${data.error}. Try again in ~${hours}h.`);
172934
+ } else {
172935
+ printError(data.error);
172936
+ }
172937
+ process.exit(1);
172938
+ }
172939
+ if (opts.json) {
172940
+ console.log(JSON.stringify(data, null, 2));
172941
+ } else {
172942
+ printSuccess(`Airdrop received: ${data.amount} NARA`);
172943
+ console.log(` Transaction: ${data.txHash}`);
172944
+ }
172945
+ } catch (error) {
172946
+ printError(error.message);
172947
+ process.exit(1);
172948
+ }
172949
+ });
172916
172950
  program3.command("token-balance <token-address>").description("Check token balance (supports SPL Token and Token-2022)").option("--owner <address>", "Owner address (optional, defaults to current wallet)").action(async (tokenAddress, options) => {
172917
172951
  const opts = program3.opts();
172918
172952
  try {
@@ -173021,7 +173055,7 @@ function registerCommands(program3) {
173021
173055
  }
173022
173056
 
173023
173057
  // bin/nara-cli.ts
173024
- var version2 = true ? "1.0.65" : "dev";
173058
+ var version2 = true ? "1.0.67" : "dev";
173025
173059
  var program2 = new Command();
173026
173060
  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);
173027
173061
  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.65",
3
+ "version": "1.0.67",
4
4
  "description": "CLI for the Nara chain (Solana-compatible)",
5
5
  "homepage": "https://nara.build",
6
6
  "repository": {
@@ -126,7 +126,7 @@ async function handleAgentGet(agentId: string, options: GlobalOptions) {
126
126
  if (tv) {
127
127
  tweetVerifyData = {
128
128
  tweetId: tv.tweetId.toString(),
129
- status: TWITTER_STATUS[tv.status] ?? `unknown(${tv.status})`,
129
+ status: TWEET_VERIFY_STATUS[tv.status] ?? `unknown(${tv.status})`,
130
130
  submittedAt: tv.submittedAt ? new Date(tv.submittedAt * 1000).toISOString() : null,
131
131
  lastRewardedAt: tv.lastRewardedAt ? new Date(tv.lastRewardedAt * 1000).toISOString() : null,
132
132
  };
@@ -167,7 +167,8 @@ async function handleAgentGet(agentId: string, options: GlobalOptions) {
167
167
  }
168
168
  // Tweet verification
169
169
  if (tweetVerifyData) {
170
- console.log(` Tweet verify: ${tweetVerifyData.tweetId} (${tweetVerifyData.status})`);
170
+ const verified = tweetVerifyData.lastRewardedAt ? "verified" : "unverified";
171
+ console.log(` Tweet: ${tweetVerifyData.tweetId} (${verified})`);
171
172
  if (tweetVerifyData.lastRewardedAt) console.log(` Tweet last rewarded: ${tweetVerifyData.lastRewardedAt}`);
172
173
  }
173
174
  console.log("");
@@ -177,16 +178,16 @@ async function handleAgentGet(agentId: string, options: GlobalOptions) {
177
178
  const lastRewarded = new Date(tweetVerifyData.lastRewardedAt).getTime();
178
179
  const hoursAgo = (Date.now() - lastRewarded) / (1000 * 60 * 60);
179
180
  if (hoursAgo >= 24) {
180
- console.log(` Tip: You can verify your tweet again to earn more stake-free credits.`);
181
- console.log(` npx naracli agent submit-tweet <tweet-url>`);
181
+ const h = Math.floor(hoursAgo);
182
+ console.log(` Tip: Last tweet verified ${h}h ago (>24h). You can submit a new tweet to earn more stake-free credits.`);
182
183
  } else {
183
184
  const hoursLeft = Math.ceil(24 - hoursAgo);
184
185
  console.log(` Tip: Next tweet verification available in ~${hoursLeft}h.`);
185
186
  }
186
187
  } else {
187
188
  console.log(` Tip: Submit a tweet to earn stake-free PoMI mining credits!`);
188
- console.log(` npx naracli agent submit-tweet <tweet-url>`);
189
189
  }
190
+ console.log(` npx naracli agent submit-tweet <tweet-url>`);
190
191
  console.log(` Stake-free credits are based on tweet likes, bookmarks, retweets, and quotes.`);
191
192
  console.log("");
192
193
  } else {
@@ -415,6 +416,7 @@ async function handleAgentClear(options: GlobalOptions) {
415
416
  // ─── Twitter handlers ────────────────────────────────────────────
416
417
 
417
418
  const TWITTER_STATUS: Record<number, string> = { 0: "none", 1: "pending", 2: "verified", 3: "rejected" };
419
+ const TWEET_VERIFY_STATUS: Record<number, string> = { 0: "ready", 1: "pending", 2: "approved", 3: "rejected" };
418
420
 
419
421
  /** Parse tweet URL and extract username + tweetId. Accepts https://x.com/<username>/status/<id> or https://twitter.com/<username>/status/<id>. */
420
422
  function parseTweetUrl(url: string): { username: string; tweetId: bigint; tweetUrl: string } {
package/src/cli/index.ts CHANGED
@@ -111,6 +111,46 @@ export function registerCommands(program: Command): void {
111
111
  }
112
112
  });
113
113
 
114
+ // Top-level: airdrop
115
+ program
116
+ .command("airdrop")
117
+ .description("Claim a free NARA airdrop (0.1 NARA, once per 24 hours per address/IP)")
118
+ .action(async () => {
119
+ const opts = program.opts() as GlobalOptions;
120
+ try {
121
+ const wallet = await loadWallet(opts.wallet);
122
+ const address = wallet.publicKey.toBase58();
123
+ if (!opts.json) printInfo(`Requesting airdrop for ${address}...`);
124
+
125
+ const res = await fetch("https://quest-api.nara.build/airdrop", {
126
+ method: "POST",
127
+ headers: { "Content-Type": "application/json" },
128
+ body: JSON.stringify({ wallet: address }),
129
+ });
130
+ const data = await res.json() as any;
131
+
132
+ if (data.error) {
133
+ if (data.retryAfterSeconds) {
134
+ const hours = Math.ceil(data.retryAfterSeconds / 3600);
135
+ printError(`${data.error}. Try again in ~${hours}h.`);
136
+ } else {
137
+ printError(data.error);
138
+ }
139
+ process.exit(1);
140
+ }
141
+
142
+ if (opts.json) {
143
+ console.log(JSON.stringify(data, null, 2));
144
+ } else {
145
+ printSuccess(`Airdrop received: ${data.amount} NARA`);
146
+ console.log(` Transaction: ${data.txHash}`);
147
+ }
148
+ } catch (error: any) {
149
+ printError(error.message);
150
+ process.exit(1);
151
+ }
152
+ });
153
+
114
154
  // Top-level: token-balance
115
155
  program
116
156
  .command("token-balance <token-address>")