naracli 1.0.32 → 1.0.40

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.
@@ -22,7 +22,7 @@ import { fileURLToPath } from "node:url";
22
22
  import { Connection, Keypair, LAMPORTS_PER_SOL, SystemProgram, Transaction } from "@solana/web3.js";
23
23
  import bs58 from "bs58";
24
24
  import { DEFAULT_AGENT_REGISTRY_PROGRAM_ID, getQuestInfo, getAgentRecord } from "nara-sdk";
25
- import { runCli, hasWallet } from "./helpers.js";
25
+ import { runCli, hasWallet, pollConfirmation } from "./helpers.js";
26
26
 
27
27
  const __dirname = dirname(fileURLToPath(import.meta.url));
28
28
 
@@ -80,7 +80,7 @@ describe("quest referral (on-chain)", { skip: !hasWallet ? "no PRIVATE_KEY" : un
80
80
  transferTx.recentBlockhash = (await connection.getLatestBlockhash("confirmed")).blockhash;
81
81
  transferTx.sign(mainWallet);
82
82
  const sig = await connection.sendRawTransaction(transferTx.serialize());
83
- await connection.confirmTransaction(sig, "confirmed");
83
+ await pollConfirmation(connection, sig);
84
84
  console.log(` Transfer tx: ${sig}`);
85
85
  });
86
86
 
@@ -106,9 +106,11 @@ describe("quest referral (on-chain)", { skip: !hasWallet ? "no PRIVATE_KEY" : un
106
106
  console.log(" Referral agent registered");
107
107
  });
108
108
 
109
- it("registers main agent", async () => {
110
- console.log(` Registering main agent "${mainAgentId}"...`);
111
- const { stdout, stderr, exitCode } = await runCli(["agent", "register", mainAgentId]);
109
+ it("registers main agent with referral", async () => {
110
+ console.log(` Registering main agent "${mainAgentId}" with referral "${referralAgentId}"...`);
111
+ const { stdout, stderr, exitCode } = await runCli([
112
+ "agent", "register", mainAgentId, "--referral", referralAgentId,
113
+ ]);
112
114
  const output = stdout + stderr;
113
115
  if (output.includes("already") || output.includes("in use")) {
114
116
  console.log(" Agent already exists, continuing");
@@ -116,7 +118,7 @@ describe("quest referral (on-chain)", { skip: !hasWallet ? "no PRIVATE_KEY" : un
116
118
  }
117
119
  assert.equal(exitCode, 0, `Failed: ${stderr}`);
118
120
  assert.ok(output.includes("registered") || output.includes("Transaction"), "should confirm registration");
119
- console.log(" Main agent registered");
121
+ console.log(" Main agent registered with referral");
120
122
  });
121
123
 
122
124
  it("answers quest with --referral", async () => {
@@ -162,7 +164,7 @@ describe("quest referral (on-chain)", { skip: !hasWallet ? "no PRIVATE_KEY" : un
162
164
  // Extract transaction signature
163
165
  const txMatch = output.match(/Transaction:\s+(\S+)/);
164
166
  assert.ok(txMatch, "should show transaction signature");
165
- const txSig = txMatch![1];
167
+ const txSig = txMatch![1]!;
166
168
  console.log(` Transaction: ${txSig}`);
167
169
 
168
170
  // Verify transaction succeeded on-chain
@@ -204,25 +206,16 @@ describe("quest referral (on-chain)", { skip: !hasWallet ? "no PRIVATE_KEY" : un
204
206
  console.log(" Answer submitted with referral successfully");
205
207
  });
206
208
 
207
- it("verifies on-chain agent points", async () => {
209
+ it("verifies on-chain agent records", async () => {
208
210
  try {
209
211
  const mainRecord = await getAgentRecord(connection, mainAgentId);
210
- console.log(` Main agent points: ${mainRecord.points}`);
212
+ console.log(` Main agent: ${mainRecord.agentId}, referral: ${mainRecord.referralId ?? "(none)"}`);
211
213
 
212
214
  const referralRecord = await getAgentRecord(connection, referralAgentId);
213
- console.log(` Referral agent points: ${referralRecord.points}`);
214
-
215
- if (mainRecord.points > 0) {
216
- console.log(" OK: Main agent earned points");
217
- } else {
218
- console.log(" WARN: Main agent has 0 points (quest may not have been answered in this run)");
219
- }
220
-
221
- if (referralRecord.points > 0) {
222
- console.log(" OK: Referral agent earned referral points");
223
- } else {
224
- console.log(" WARN: Referral agent has 0 points");
225
- }
215
+ console.log(` Referral agent: ${referralRecord.agentId}`);
216
+
217
+ // Points are now minted as SPL tokens (Token-2022), not stored on AgentRecord
218
+ console.log(" OK: Both agent records exist on-chain");
226
219
  } catch (err: any) {
227
220
  console.log(` (skipped: ${err.message})`);
228
221
  }
@@ -94,7 +94,7 @@ describe("quest proof generation", () => {
94
94
 
95
95
  // Generate proof with a random pubkey (we're just testing proof generation)
96
96
  const testKeypair = Keypair.generate();
97
- const proof = await generateProof(match.answer, quest.answerHash, testKeypair.publicKey);
97
+ const proof = await generateProof(match.answer, quest.answerHash, testKeypair.publicKey, quest.round);
98
98
 
99
99
  assert.ok(proof.solana.proofA.length > 0, "proofA should not be empty");
100
100
  assert.ok(proof.solana.proofB.length > 0, "proofB should not be empty");
@@ -0,0 +1,80 @@
1
+ /**
2
+ * Tests for validation utilities
3
+ *
4
+ * Run: npm run test:validation
5
+ */
6
+
7
+ import { describe, it } from "node:test";
8
+ import assert from "node:assert/strict";
9
+ import { validateName } from "../cli/utils/validation.js";
10
+
11
+ describe("validateName", () => {
12
+ // Valid names
13
+ it("accepts simple lowercase name", () => {
14
+ assert.equal(validateName("myagent", "Agent ID"), "myagent");
15
+ });
16
+
17
+ it("accepts name with hyphens", () => {
18
+ assert.equal(validateName("my-agent", "Agent ID"), "my-agent");
19
+ });
20
+
21
+ it("accepts name with numbers", () => {
22
+ assert.equal(validateName("agent1", "Agent ID"), "agent1");
23
+ });
24
+
25
+ it("accepts name with hyphens and numbers", () => {
26
+ assert.equal(validateName("my-agent-123", "Agent ID"), "my-agent-123");
27
+ });
28
+
29
+ it("accepts single letter", () => {
30
+ assert.equal(validateName("a", "Agent ID"), "a");
31
+ });
32
+
33
+ it("accepts long valid name", () => {
34
+ assert.equal(validateName("a-very-long-agent-name-with-numbers-123", "Agent ID"), "a-very-long-agent-name-with-numbers-123");
35
+ });
36
+
37
+ // Invalid names
38
+ it("rejects name starting with number", () => {
39
+ assert.throws(() => validateName("1agent", "Agent ID"), /lowercase/);
40
+ });
41
+
42
+ it("rejects name starting with hyphen", () => {
43
+ assert.throws(() => validateName("-agent", "Agent ID"), /lowercase/);
44
+ });
45
+
46
+ it("rejects uppercase letters", () => {
47
+ assert.throws(() => validateName("MyAgent", "Agent ID"), /lowercase/);
48
+ });
49
+
50
+ it("rejects mixed case", () => {
51
+ assert.throws(() => validateName("myAgent", "Agent ID"), /lowercase/);
52
+ });
53
+
54
+ it("rejects underscores", () => {
55
+ assert.throws(() => validateName("my_agent", "Agent ID"), /lowercase/);
56
+ });
57
+
58
+ it("rejects dots", () => {
59
+ assert.throws(() => validateName("my.agent", "Agent ID"), /lowercase/);
60
+ });
61
+
62
+ it("rejects spaces", () => {
63
+ assert.throws(() => validateName("my agent", "Agent ID"), /lowercase/);
64
+ });
65
+
66
+ it("rejects empty string", () => {
67
+ assert.throws(() => validateName("", "Agent ID"), /lowercase/);
68
+ });
69
+
70
+ it("rejects special characters", () => {
71
+ assert.throws(() => validateName("agent@home", "Agent ID"), /lowercase/);
72
+ });
73
+
74
+ it("includes label in error message", () => {
75
+ assert.throws(
76
+ () => validateName("BAD", "Skill name"),
77
+ (err: any) => err.message.includes("Skill name")
78
+ );
79
+ });
80
+ });
@@ -17,7 +17,7 @@ describe("zkid --help", () => {
17
17
  it("shows all subcommands", async () => {
18
18
  const { stdout, exitCode } = await runCli(["zkid", "--help"]);
19
19
  assert.equal(exitCode, 0);
20
- for (const cmd of ["create", "info", "deposit", "scan", "withdraw", "id-commitment", "transfer"]) {
20
+ for (const cmd of ["create", "info", "deposit", "scan", "withdraw", "id-commitment", "transfer-owner"]) {
21
21
  assert.ok(stdout.includes(cmd), `missing subcommand: ${cmd}`);
22
22
  }
23
23
  });
@@ -36,8 +36,8 @@ describe("zkid --help", () => {
36
36
  assert.ok(stdout.includes("--recipient"));
37
37
  });
38
38
 
39
- it("zkid transfer --help shows <new-id-commitment>", async () => {
40
- const { stdout, exitCode } = await runCli(["zkid", "transfer", "--help"]);
39
+ it("zkid transfer-owner --help shows <new-id-commitment>", async () => {
40
+ const { stdout, exitCode } = await runCli(["zkid", "transfer-owner", "--help"]);
41
41
  assert.equal(exitCode, 0);
42
42
  assert.ok(stdout.includes("<new-id-commitment>"));
43
43
  });
@@ -68,21 +68,21 @@ describe("zkid deposit denomination validation", () => {
68
68
  describe("zkid transfer commitment validation", () => {
69
69
  it("rejects commitment shorter than 64 chars", async () => {
70
70
  if (!hasWallet) return;
71
- const { stderr, exitCode } = await runCli(["zkid", "transfer", "alice", "deadbeef"]);
71
+ const { stderr, exitCode } = await runCli(["zkid", "transfer-owner", "alice", "deadbeef"]);
72
72
  assert.equal(exitCode, 1);
73
73
  assert.ok(stderr.includes("Invalid id-commitment"), `stderr: ${stderr}`);
74
74
  });
75
75
 
76
76
  it("rejects commitment with non-hex characters", async () => {
77
77
  if (!hasWallet) return;
78
- const { stderr, exitCode } = await runCli(["zkid", "transfer", "alice", "z".repeat(64)]);
78
+ const { stderr, exitCode } = await runCli(["zkid", "transfer-owner", "alice", "z".repeat(64)]);
79
79
  assert.equal(exitCode, 1);
80
80
  assert.ok(stderr.includes("Invalid id-commitment"), `stderr: ${stderr}`);
81
81
  });
82
82
 
83
83
  it("rejects commitment that is 63 chars (one short)", async () => {
84
84
  if (!hasWallet) return;
85
- const { stderr, exitCode } = await runCli(["zkid", "transfer", "alice", "a".repeat(63)]);
85
+ const { stderr, exitCode } = await runCli(["zkid", "transfer-owner", "alice", "a".repeat(63)]);
86
86
  assert.equal(exitCode, 1);
87
87
  assert.ok(stderr.includes("Invalid id-commitment"), `stderr: ${stderr}`);
88
88
  });