@agirails/sdk 2.3.0 → 2.3.3

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 (153) hide show
  1. package/README.md +45 -8
  2. package/dist/ACTPClient.d.ts +35 -1
  3. package/dist/ACTPClient.d.ts.map +1 -1
  4. package/dist/ACTPClient.js +156 -26
  5. package/dist/ACTPClient.js.map +1 -1
  6. package/dist/adapters/AdapterRouter.d.ts.map +1 -1
  7. package/dist/adapters/AdapterRouter.js.map +1 -1
  8. package/dist/adapters/BasicAdapter.d.ts +10 -1
  9. package/dist/adapters/BasicAdapter.d.ts.map +1 -1
  10. package/dist/adapters/BasicAdapter.js +36 -1
  11. package/dist/adapters/BasicAdapter.js.map +1 -1
  12. package/dist/cli/commands/init.d.ts +2 -1
  13. package/dist/cli/commands/init.d.ts.map +1 -1
  14. package/dist/cli/commands/init.js +345 -25
  15. package/dist/cli/commands/init.js.map +1 -1
  16. package/dist/cli/commands/publish.d.ts.map +1 -1
  17. package/dist/cli/commands/publish.js.map +1 -1
  18. package/dist/cli/commands/register.d.ts +16 -0
  19. package/dist/cli/commands/register.d.ts.map +1 -0
  20. package/dist/cli/commands/register.js +211 -0
  21. package/dist/cli/commands/register.js.map +1 -0
  22. package/dist/cli/index.js +3 -0
  23. package/dist/cli/index.js.map +1 -1
  24. package/dist/cli/utils/config.d.ts +20 -0
  25. package/dist/cli/utils/config.d.ts.map +1 -1
  26. package/dist/cli/utils/config.js.map +1 -1
  27. package/dist/config/networks.d.ts +20 -4
  28. package/dist/config/networks.d.ts.map +1 -1
  29. package/dist/config/networks.js +59 -27
  30. package/dist/config/networks.js.map +1 -1
  31. package/dist/config/publishPipeline.d.ts +14 -0
  32. package/dist/config/publishPipeline.d.ts.map +1 -1
  33. package/dist/config/publishPipeline.js +2 -1
  34. package/dist/config/publishPipeline.js.map +1 -1
  35. package/dist/erc8004/ERC8004Bridge.d.ts.map +1 -1
  36. package/dist/erc8004/ERC8004Bridge.js +6 -5
  37. package/dist/erc8004/ERC8004Bridge.js.map +1 -1
  38. package/dist/erc8004/ReputationReporter.d.ts.map +1 -1
  39. package/dist/erc8004/ReputationReporter.js +9 -12
  40. package/dist/erc8004/ReputationReporter.js.map +1 -1
  41. package/dist/index.d.ts +4 -0
  42. package/dist/index.d.ts.map +1 -1
  43. package/dist/index.js +7 -3
  44. package/dist/index.js.map +1 -1
  45. package/dist/level1/Agent.js +4 -4
  46. package/dist/level1/Agent.js.map +1 -1
  47. package/dist/protocol/ACTPKernel.d.ts +7 -1
  48. package/dist/protocol/ACTPKernel.d.ts.map +1 -1
  49. package/dist/protocol/ACTPKernel.js +13 -10
  50. package/dist/protocol/ACTPKernel.js.map +1 -1
  51. package/dist/protocol/EventMonitor.d.ts +14 -0
  52. package/dist/protocol/EventMonitor.d.ts.map +1 -1
  53. package/dist/protocol/EventMonitor.js +14 -0
  54. package/dist/protocol/EventMonitor.js.map +1 -1
  55. package/dist/runtime/BlockchainRuntime.d.ts +5 -0
  56. package/dist/runtime/BlockchainRuntime.d.ts.map +1 -1
  57. package/dist/runtime/BlockchainRuntime.js +1 -1
  58. package/dist/runtime/BlockchainRuntime.js.map +1 -1
  59. package/dist/storage/ArchiveBundleBuilder.d.ts.map +1 -1
  60. package/dist/storage/ArchiveBundleBuilder.js.map +1 -1
  61. package/dist/storage/ArweaveClient.d.ts.map +1 -1
  62. package/dist/storage/ArweaveClient.js +2 -0
  63. package/dist/storage/ArweaveClient.js.map +1 -1
  64. package/dist/storage/FilebaseClient.d.ts.map +1 -1
  65. package/dist/storage/FilebaseClient.js +2 -0
  66. package/dist/storage/FilebaseClient.js.map +1 -1
  67. package/dist/utils/ErrorRecoveryGuide.d.ts.map +1 -1
  68. package/dist/utils/ErrorRecoveryGuide.js +3 -2
  69. package/dist/utils/ErrorRecoveryGuide.js.map +1 -1
  70. package/dist/utils/IPFSClient.d.ts +3 -2
  71. package/dist/utils/IPFSClient.d.ts.map +1 -1
  72. package/dist/utils/IPFSClient.js +7 -5
  73. package/dist/utils/IPFSClient.js.map +1 -1
  74. package/dist/utils/computeTypeHash.js +1 -3
  75. package/dist/utils/computeTypeHash.js.map +1 -1
  76. package/dist/utils/retry.d.ts.map +1 -1
  77. package/dist/utils/retry.js +0 -1
  78. package/dist/utils/retry.js.map +1 -1
  79. package/dist/utils/validation.d.ts +2 -2
  80. package/dist/utils/validation.d.ts.map +1 -1
  81. package/dist/utils/validation.js +2 -2
  82. package/dist/utils/validation.js.map +1 -1
  83. package/dist/wallet/AutoWalletProvider.d.ts +77 -0
  84. package/dist/wallet/AutoWalletProvider.d.ts.map +1 -0
  85. package/dist/wallet/AutoWalletProvider.js +197 -0
  86. package/dist/wallet/AutoWalletProvider.js.map +1 -0
  87. package/dist/wallet/EOAWalletProvider.d.ts +21 -0
  88. package/dist/wallet/EOAWalletProvider.d.ts.map +1 -0
  89. package/dist/wallet/EOAWalletProvider.js +57 -0
  90. package/dist/wallet/EOAWalletProvider.js.map +1 -0
  91. package/dist/wallet/IWalletProvider.d.ts +115 -0
  92. package/dist/wallet/IWalletProvider.d.ts.map +1 -0
  93. package/dist/wallet/IWalletProvider.js +12 -0
  94. package/dist/wallet/IWalletProvider.js.map +1 -0
  95. package/dist/wallet/aa/BundlerClient.d.ts +70 -0
  96. package/dist/wallet/aa/BundlerClient.d.ts.map +1 -0
  97. package/dist/wallet/aa/BundlerClient.js +184 -0
  98. package/dist/wallet/aa/BundlerClient.js.map +1 -0
  99. package/dist/wallet/aa/DualNonceManager.d.ts +56 -0
  100. package/dist/wallet/aa/DualNonceManager.d.ts.map +1 -0
  101. package/dist/wallet/aa/DualNonceManager.js +142 -0
  102. package/dist/wallet/aa/DualNonceManager.js.map +1 -0
  103. package/dist/wallet/aa/PaymasterClient.d.ts +52 -0
  104. package/dist/wallet/aa/PaymasterClient.d.ts.map +1 -0
  105. package/dist/wallet/aa/PaymasterClient.js +116 -0
  106. package/dist/wallet/aa/PaymasterClient.js.map +1 -0
  107. package/dist/wallet/aa/TransactionBatcher.d.ts +87 -0
  108. package/dist/wallet/aa/TransactionBatcher.d.ts.map +1 -0
  109. package/dist/wallet/aa/TransactionBatcher.js +148 -0
  110. package/dist/wallet/aa/TransactionBatcher.js.map +1 -0
  111. package/dist/wallet/aa/UserOpBuilder.d.ts +71 -0
  112. package/dist/wallet/aa/UserOpBuilder.d.ts.map +1 -0
  113. package/dist/wallet/aa/UserOpBuilder.js +196 -0
  114. package/dist/wallet/aa/UserOpBuilder.js.map +1 -0
  115. package/dist/wallet/aa/constants.d.ts +54 -0
  116. package/dist/wallet/aa/constants.d.ts.map +1 -0
  117. package/dist/wallet/aa/constants.js +18 -0
  118. package/dist/wallet/aa/constants.js.map +1 -0
  119. package/package.json +4 -2
  120. package/src/ACTPClient.ts +217 -31
  121. package/src/adapters/AdapterRouter.ts +0 -1
  122. package/src/adapters/BasicAdapter.ts +41 -1
  123. package/src/cli/commands/init.ts +394 -25
  124. package/src/cli/commands/publish.ts +1 -2
  125. package/src/cli/commands/register.ts +233 -0
  126. package/src/cli/index.ts +4 -0
  127. package/src/cli/utils/config.ts +30 -0
  128. package/src/config/networks.ts +82 -27
  129. package/src/config/publishPipeline.ts +2 -2
  130. package/src/erc8004/ERC8004Bridge.ts +6 -5
  131. package/src/erc8004/ReputationReporter.ts +14 -18
  132. package/src/index.ts +12 -0
  133. package/src/level1/Agent.ts +5 -5
  134. package/src/protocol/ACTPKernel.ts +20 -10
  135. package/src/protocol/EventMonitor.ts +14 -0
  136. package/src/runtime/BlockchainRuntime.ts +7 -1
  137. package/src/storage/ArchiveBundleBuilder.ts +0 -2
  138. package/src/storage/ArweaveClient.ts +2 -1
  139. package/src/storage/FilebaseClient.ts +3 -3
  140. package/src/utils/ErrorRecoveryGuide.ts +4 -2
  141. package/src/utils/IPFSClient.ts +9 -7
  142. package/src/utils/computeTypeHash.ts +1 -3
  143. package/src/utils/retry.ts +0 -1
  144. package/src/utils/validation.ts +2 -2
  145. package/src/wallet/AutoWalletProvider.ts +294 -0
  146. package/src/wallet/EOAWalletProvider.ts +69 -0
  147. package/src/wallet/IWalletProvider.ts +133 -0
  148. package/src/wallet/aa/BundlerClient.ts +274 -0
  149. package/src/wallet/aa/DualNonceManager.ts +173 -0
  150. package/src/wallet/aa/PaymasterClient.ts +174 -0
  151. package/src/wallet/aa/TransactionBatcher.ts +240 -0
  152. package/src/wallet/aa/UserOpBuilder.ts +246 -0
  153. package/src/wallet/aa/constants.ts +60 -0
@@ -32,6 +32,7 @@ export function createInitCommand(): Command {
32
32
  .description('Initialize ACTP in the current directory')
33
33
  .option('-m, --mode <mode>', 'Operating mode: mock, testnet, mainnet', 'mock')
34
34
  .option('-a, --address <address>', 'Your Ethereum address')
35
+ .option('-w, --wallet <type>', 'Wallet type: auto (gas-free Smart Wallet) or eoa (traditional)', 'auto')
35
36
  .option('-f, --force', 'Overwrite existing configuration')
36
37
  .option('--scaffold', 'Generate a starter agent.ts file')
37
38
  .option('--intent <intent>', 'Agent intent: earn, pay, or both (default: earn)')
@@ -39,13 +40,13 @@ export function createInitCommand(): Command {
39
40
  .option('--price <usdc>', 'Base price in USDC (default: 1)')
40
41
  .option('--json', 'Output as JSON')
41
42
  .option('-q, --quiet', 'Minimal output')
42
- .action(async (options) => {
43
+ .action(async (options, command) => {
43
44
  const output = new Output(
44
45
  options.json ? 'json' : options.quiet ? 'quiet' : 'human'
45
46
  );
46
47
 
47
48
  try {
48
- await runInit(options, output);
49
+ await runInit(options, output, command);
49
50
  } catch (error) {
50
51
  output.errorResult({
51
52
  code: 'INIT_FAILED',
@@ -67,6 +68,7 @@ type ScaffoldIntent = 'earn' | 'pay' | 'both';
67
68
  interface InitOptions {
68
69
  mode: string;
69
70
  address?: string;
71
+ wallet?: string;
70
72
  force?: boolean;
71
73
  scaffold?: boolean;
72
74
  intent?: string;
@@ -74,7 +76,7 @@ interface InitOptions {
74
76
  price?: string;
75
77
  }
76
78
 
77
- async function runInit(options: InitOptions, output: Output): Promise<void> {
79
+ async function runInit(options: InitOptions, output: Output, cmd?: Command): Promise<void> {
78
80
  const projectRoot = process.cwd();
79
81
 
80
82
  // Check if already initialized
@@ -85,6 +87,65 @@ async function runInit(options: InitOptions, output: Output): Promise<void> {
85
87
  );
86
88
  }
87
89
 
90
+ // ── AGIRAILS.md pre-fill ──────────────────────────────────────────────
91
+ const agirailsMdPath = path.join(projectRoot, 'AGIRAILS.md');
92
+ let mdConfig: Record<string, unknown> | null = null;
93
+
94
+ if (fs.existsSync(agirailsMdPath)) {
95
+ try {
96
+ const { parseAgirailsMd } = await import('../../config/agirailsmd');
97
+ const parsed = parseAgirailsMd(fs.readFileSync(agirailsMdPath, 'utf-8'));
98
+ mdConfig = parsed.frontmatter;
99
+ } catch {
100
+ output.warning('Found AGIRAILS.md but could not parse it — ignoring');
101
+ }
102
+ }
103
+
104
+ // Helper: true when the user explicitly passed a flag on the CLI
105
+ const isExplicit = (flag: string): boolean =>
106
+ cmd?.getOptionValueSource(flag) === 'cli';
107
+
108
+ // Apply AGIRAILS.md values where the user didn't set an explicit flag
109
+ if (mdConfig) {
110
+ // network → mode mapping
111
+ if (!isExplicit('mode') && mdConfig.network) {
112
+ const net = String(mdConfig.network);
113
+ if (net === 'base-sepolia' || net === 'testnet') options.mode = 'testnet';
114
+ else if (net === 'base-mainnet' || net === 'mainnet') options.mode = 'mainnet';
115
+ else if (net === 'mock') options.mode = 'mock';
116
+ }
117
+
118
+ // intent
119
+ if (!isExplicit('intent') && mdConfig.intent) {
120
+ options.intent = String(mdConfig.intent);
121
+ }
122
+
123
+ // capabilities → service (first capability)
124
+ if (!isExplicit('service') && Array.isArray(mdConfig.capabilities) && mdConfig.capabilities.length > 0) {
125
+ options.service = String(mdConfig.capabilities[0]);
126
+ }
127
+
128
+ // price
129
+ if (!isExplicit('price') && mdConfig.price != null) {
130
+ options.price = String(mdConfig.price);
131
+ }
132
+
133
+ // Log what we pre-filled
134
+ const lines: string[] = [];
135
+ if (mdConfig.network) lines.push(` Mode: ${options.mode}`);
136
+ if (mdConfig.name) lines.push(` Agent: ${String(mdConfig.name)}`);
137
+ if (mdConfig.intent) lines.push(` Intent: ${options.intent || mdConfig.intent}`);
138
+ if (Array.isArray(mdConfig.capabilities)) lines.push(` Capabilities: ${mdConfig.capabilities.join(', ')}`);
139
+ if (mdConfig.price != null) lines.push(` Price: $${mdConfig.price} USDC`);
140
+
141
+ output.info('Found AGIRAILS.md \u2014 using config from file');
142
+ for (const line of lines) {
143
+ output.print(line);
144
+ }
145
+ output.blank();
146
+ }
147
+ // ── End AGIRAILS.md pre-fill ──────────────────────────────────────────
148
+
88
149
  // Validate mode
89
150
  const validModes: CLIMode[] = ['mock', 'testnet', 'mainnet'];
90
151
  if (!validModes.includes(options.mode as CLIMode)) {
@@ -95,8 +156,18 @@ async function runInit(options: InitOptions, output: Output): Promise<void> {
95
156
 
96
157
  const mode = options.mode as CLIMode;
97
158
 
159
+ // Determine wallet type
160
+ const walletType = (mode === 'mock') ? 'mock' : (options.wallet || 'auto');
161
+ if (walletType !== 'mock' && walletType !== 'auto' && walletType !== 'eoa') {
162
+ throw new Error(
163
+ `Invalid wallet type: "${walletType}". Valid types: auto, eoa`
164
+ );
165
+ }
166
+
98
167
  // Get or generate address
99
168
  let address = options.address;
169
+ let smartWalletAddress: string | undefined;
170
+ let didRegister = false;
100
171
  if (!address) {
101
172
  if (mode === 'mock') {
102
173
  // Generate a random address for mock mode
@@ -106,7 +177,24 @@ async function runInit(options: InitOptions, output: Output): Promise<void> {
106
177
  // Generate a real wallet with encrypted keystore
107
178
  const actpDir = getActpDir(projectRoot);
108
179
  fs.mkdirSync(actpDir, { recursive: true });
109
- address = await generateWallet(actpDir, output);
180
+ const eoaAddress = await generateWallet(actpDir, output);
181
+
182
+ if (walletType === 'auto') {
183
+ // Compute Smart Wallet address from signer
184
+ smartWalletAddress = await computeSmartWalletInit(eoaAddress, mode, output);
185
+
186
+ // Y/N: Register for gas-free transactions?
187
+ const shouldRegister = await promptRegister(output);
188
+ if (shouldRegister) {
189
+ didRegister = await runInlineRegistration(projectRoot, mode, output);
190
+ }
191
+
192
+ // address = Smart Wallet if registered, EOA if not
193
+ // This ensures CLI commands (balance, tx list) show the correct address
194
+ address = didRegister ? smartWalletAddress : eoaAddress;
195
+ } else {
196
+ address = eoaAddress;
197
+ }
110
198
  }
111
199
  }
112
200
 
@@ -123,6 +211,17 @@ async function runInit(options: InitOptions, output: Output): Promise<void> {
123
211
  mode,
124
212
  address: address.toLowerCase(),
125
213
  version: '1.0',
214
+ ...(walletType !== 'mock' && { wallet: walletType as 'auto' | 'eoa' }),
215
+ ...(smartWalletAddress && { smartWallet: smartWalletAddress.toLowerCase() }),
216
+ ...(didRegister && { registered: true }),
217
+ // AGIRAILS.md-derived values (stored for downstream use)
218
+ ...(mdConfig && mdConfig.name ? { agentName: String(mdConfig.name) } : {}),
219
+ ...(mdConfig && mdConfig.intent ? { intent: String(mdConfig.intent) as 'earn' | 'pay' | 'both' } : {}),
220
+ ...(mdConfig && Array.isArray(mdConfig.capabilities) ? { capabilities: mdConfig.capabilities.map(String) } : {}),
221
+ ...(mdConfig && mdConfig.price != null ? { price: Number(mdConfig.price) } : {}),
222
+ ...(mdConfig && mdConfig.concurrency != null ? { concurrency: Number(mdConfig.concurrency) } : {}),
223
+ ...(mdConfig && mdConfig.payment_mode ? { paymentMode: String(mdConfig.payment_mode) as 'actp' | 'x402' | 'both' } : {}),
224
+ ...(mdConfig && mdConfig.budget != null ? { budget: Number(mdConfig.budget) } : {}),
126
225
  };
127
226
 
128
227
  // Save configuration
@@ -160,19 +259,32 @@ async function runInit(options: InitOptions, output: Output): Promise<void> {
160
259
  directory: getActpDir(projectRoot),
161
260
  mode,
162
261
  address,
262
+ ...(walletType !== 'mock' && { wallet: walletType }),
163
263
  },
164
264
  { quietKey: 'address' }
165
265
  );
166
266
 
167
267
  // Generate scaffold if requested
168
268
  if (options.scaffold) {
169
- await runScaffold(options, mode, output);
269
+ await runScaffold(options, mode, output, mdConfig);
170
270
  } else {
171
271
  output.blank();
172
272
  output.print('Next steps:');
173
- output.print(' 1. Create a payment: actp pay <provider> <amount>');
174
- output.print(' 2. Check your balance: actp balance');
175
- output.print(' 3. List transactions: actp tx list');
273
+ if (walletType === 'auto' && didRegister) {
274
+ // Already registered ready to go
275
+ output.print(' 1. Create a payment: actp pay <provider> <amount>');
276
+ output.print(' 2. Check your balance: actp balance');
277
+ output.print(' 3. List transactions: actp tx list');
278
+ } else if (walletType === 'auto') {
279
+ // Skipped registration — remind them
280
+ output.print(' 1. Register for gas-free: actp register');
281
+ output.print(' 2. Create a payment: actp pay <provider> <amount>');
282
+ output.print(' 3. Check your balance: actp balance');
283
+ } else {
284
+ output.print(' 1. Create a payment: actp pay <provider> <amount>');
285
+ output.print(' 2. Check your balance: actp balance');
286
+ output.print(' 3. List transactions: actp tx list');
287
+ }
176
288
  output.print('');
177
289
  output.print('Tip: Use --scaffold to generate a starter agent.ts');
178
290
  }
@@ -219,6 +331,274 @@ async function generateWallet(actpDir: string, output: Output): Promise<string>
219
331
  return wallet.address;
220
332
  }
221
333
 
334
+ /**
335
+ * Compute the Smart Wallet address for an EOA signer.
336
+ * Uses CREATE2 counterfactual derivation — no deployment needed.
337
+ */
338
+ async function computeSmartWalletInit(
339
+ eoaAddress: string,
340
+ mode: string,
341
+ output: Output
342
+ ): Promise<string> {
343
+ const { ethers } = await import('ethers');
344
+ const { getNetwork } = await import('../../config/networks');
345
+ const { computeSmartWalletAddress } = await import('../../wallet/aa/UserOpBuilder');
346
+
347
+ const network = mode === 'testnet' ? 'base-sepolia' : 'base-mainnet';
348
+ const networkConfig = getNetwork(network);
349
+ const rpcUrl = networkConfig.rpcUrl;
350
+ const provider = new ethers.JsonRpcProvider(rpcUrl);
351
+
352
+ output.info('Computing Smart Wallet address...');
353
+ const smartWalletAddress = await computeSmartWalletAddress(eoaAddress, provider);
354
+
355
+ output.success(`Smart Wallet: ${smartWalletAddress}`);
356
+ output.info('Gas-free transactions enabled (requires registration)');
357
+ output.info('Register with: actp register');
358
+
359
+ return smartWalletAddress;
360
+ }
361
+
362
+ /**
363
+ * Ask user if they want to register for gas-free transactions.
364
+ * Non-TTY (piped/agent) defaults to yes.
365
+ */
366
+ async function promptRegister(output: Output): Promise<boolean> {
367
+ output.blank();
368
+ output.print('Register for gas-free transactions? (recommended)');
369
+ output.print(' Your agent gets a Smart Wallet with sponsored gas — no ETH needed.');
370
+ output.print(' Requires on-chain registration on AgentRegistry.');
371
+ output.blank();
372
+
373
+ if (!process.stdin.isTTY) {
374
+ output.info('Non-interactive mode: auto-registering');
375
+ return true;
376
+ }
377
+
378
+ const rl = readline.createInterface({
379
+ input: process.stdin,
380
+ output: process.stdout,
381
+ });
382
+
383
+ return new Promise((resolve) => {
384
+ rl.question(' Register now? [Y/n] ', (answer) => {
385
+ rl.close();
386
+ const trimmed = answer.trim().toLowerCase();
387
+ resolve(trimmed === '' || trimmed === 'y' || trimmed === 'yes');
388
+ });
389
+ });
390
+ }
391
+
392
+ /**
393
+ * Run inline registration during init.
394
+ * Reuses the same logic as `actp register` — parses AGIRAILS.md,
395
+ * builds gasless UserOp (testnet: register + mint 1000 USDC).
396
+ *
397
+ * Returns true if registration succeeded, false on failure (non-fatal).
398
+ */
399
+ async function runInlineRegistration(
400
+ projectRoot: string,
401
+ mode: string,
402
+ output: Output
403
+ ): Promise<boolean> {
404
+ try {
405
+ const { resolvePrivateKey } = await import('../../wallet/keystore');
406
+ const privateKey = await resolvePrivateKey(projectRoot);
407
+ if (!privateKey) {
408
+ output.warning('Could not load wallet key. Run "actp register" later.');
409
+ return false;
410
+ }
411
+
412
+ const { parseAgirailsMd } = await import('../../config/agirailsmd');
413
+ const { extractRegistrationParams } = await import('../../config/publishPipeline');
414
+ const { ethers } = await import('ethers');
415
+ const { getNetwork } = await import('../../config/networks');
416
+ const { AutoWalletProvider } = await import('../../wallet/AutoWalletProvider');
417
+ const { buildRegisterAgentBatch, buildTestnetInitBatch, buildTestnetMintBatch } = await import('../../wallet/aa/TransactionBatcher');
418
+ const { sdkLogger } = await import('../../utils/Logger');
419
+
420
+ // Parse AGIRAILS.md if present
421
+ const agirailsMdPath = path.join(projectRoot, 'AGIRAILS.md');
422
+ let endpoint = '';
423
+ let serviceDescriptors;
424
+
425
+ if (fs.existsSync(agirailsMdPath)) {
426
+ const content = fs.readFileSync(agirailsMdPath, 'utf-8');
427
+ const parsed = parseAgirailsMd(content);
428
+ const regParams = extractRegistrationParams(parsed.frontmatter);
429
+ endpoint = regParams.endpoint;
430
+ serviceDescriptors = regParams.serviceDescriptors;
431
+ output.info(`Parsed ${serviceDescriptors.length} service(s) from AGIRAILS.md`);
432
+ } else {
433
+ const serviceType = 'general';
434
+ endpoint = 'https://agirails.io/agent/pending';
435
+ serviceDescriptors = [{
436
+ serviceTypeHash: ethers.keccak256(ethers.toUtf8Bytes(serviceType)),
437
+ serviceType,
438
+ schemaURI: '',
439
+ minPrice: 0n,
440
+ maxPrice: 1_000_000_000n,
441
+ avgCompletionTime: 3600,
442
+ metadataCID: '',
443
+ }];
444
+ output.info('No AGIRAILS.md found. Using default "general" service.');
445
+ }
446
+
447
+ const network = mode === 'testnet' ? 'base-sepolia' : 'base-mainnet';
448
+ const networkConfig = getNetwork(network);
449
+
450
+ if (!networkConfig.aa || !networkConfig.contracts.agentRegistry) {
451
+ output.warning('AA or AgentRegistry not configured. Run "actp register" later.');
452
+ return false;
453
+ }
454
+
455
+ // Check for valid bundler/paymaster URL (CDP_API_KEY must be set)
456
+ const cdpUrl = networkConfig.aa.bundlerUrls.coinbase;
457
+ const hasPimlico = !!networkConfig.aa.bundlerUrls.pimlico;
458
+ if (cdpUrl.endsWith('/') && !hasPimlico) {
459
+ output.warning('CDP_API_KEY not set. Skipping registration.');
460
+ output.info('Set CDP_API_KEY and run "actp register" later.');
461
+ return false;
462
+ }
463
+
464
+ const provider = new ethers.JsonRpcProvider(networkConfig.rpcUrl);
465
+ const signer = new ethers.Wallet(privateKey, provider);
466
+
467
+ const autoWallet = await AutoWalletProvider.create({
468
+ signer,
469
+ provider,
470
+ chainId: networkConfig.chainId,
471
+ actpKernelAddress: networkConfig.contracts.actpKernel,
472
+ bundler: {
473
+ primaryUrl: networkConfig.aa.bundlerUrls.coinbase,
474
+ backupUrl: networkConfig.aa.bundlerUrls.pimlico,
475
+ },
476
+ paymaster: {
477
+ primaryUrl: networkConfig.aa.paymasterUrls.coinbase,
478
+ backupUrl: networkConfig.aa.paymasterUrls.pimlico,
479
+ },
480
+ });
481
+
482
+ const smartWalletAddress = autoWallet.getAddress();
483
+
484
+ // Build and submit registration batch
485
+ if (mode === 'testnet') {
486
+ // Testnet: try combined batch first, fall back to separate UserOps
487
+ // Some paymaster configurations reject multi-target batches in simulation
488
+ output.info('Testnet: registering + minting 1000 test USDC...');
489
+
490
+ const combinedCalls = buildTestnetInitBatch({
491
+ agentRegistryAddress: networkConfig.contracts.agentRegistry,
492
+ endpoint,
493
+ serviceDescriptors,
494
+ mockUsdcAddress: networkConfig.contracts.usdc,
495
+ recipient: smartWalletAddress,
496
+ mintAmount: '1000000000',
497
+ });
498
+
499
+ let receipt;
500
+ try {
501
+ const txRequests = combinedCalls.map((c) => ({
502
+ to: c.target,
503
+ data: c.data,
504
+ value: c.value.toString(),
505
+ }));
506
+ receipt = await autoWallet.sendBatchTransaction(txRequests);
507
+ } catch (combinedError) {
508
+ // Combined batch failed — split into two separate UserOps
509
+ output.info('Combined batch failed, trying separate transactions...');
510
+ sdkLogger.warn('Combined testnet batch failed, splitting', {
511
+ error: combinedError instanceof Error ? combinedError.message : String(combinedError),
512
+ });
513
+
514
+ // Step 1: Register agent only
515
+ const registerCalls = buildRegisterAgentBatch(
516
+ networkConfig.contracts.agentRegistry,
517
+ endpoint,
518
+ serviceDescriptors
519
+ );
520
+ const registerTxs = registerCalls.map((c) => ({
521
+ to: c.target,
522
+ data: c.data,
523
+ value: c.value.toString(),
524
+ }));
525
+
526
+ const registerReceipt = await autoWallet.sendBatchTransaction(registerTxs);
527
+ if (!registerReceipt.success) {
528
+ output.warning(`Registration failed (tx: ${registerReceipt.hash}). Run "actp register" later.`);
529
+ return false;
530
+ }
531
+ output.success('Agent registered on AgentRegistry');
532
+ output.print(` Tx: ${registerReceipt.hash}`);
533
+
534
+ // Step 2: Mint test USDC
535
+ try {
536
+ const mintCalls = buildTestnetMintBatch(
537
+ networkConfig.contracts.usdc,
538
+ smartWalletAddress,
539
+ '1000000000'
540
+ );
541
+ const mintTxs = mintCalls.map((c) => ({
542
+ to: c.target,
543
+ data: c.data,
544
+ value: c.value.toString(),
545
+ }));
546
+ const mintReceipt = await autoWallet.sendBatchTransaction(mintTxs);
547
+ if (mintReceipt.success) {
548
+ output.success('Minted 1,000 test USDC to Smart Wallet');
549
+ output.print(` Tx: ${mintReceipt.hash}`);
550
+ } else {
551
+ output.warning('USDC mint failed. Mint manually: actp faucet');
552
+ }
553
+ } catch (mintError) {
554
+ output.warning('USDC mint failed. Mint manually: actp faucet');
555
+ sdkLogger.warn('Testnet mint failed', {
556
+ error: mintError instanceof Error ? mintError.message : String(mintError),
557
+ });
558
+ }
559
+ return true;
560
+ }
561
+
562
+ if (!receipt.success) {
563
+ output.warning(`Registration failed (tx: ${receipt.hash}). Run "actp register" later.`);
564
+ return false;
565
+ }
566
+
567
+ output.success('Agent registered on AgentRegistry');
568
+ output.success('Minted 1,000 test USDC to Smart Wallet');
569
+ output.print(` Tx: ${receipt.hash}`);
570
+ } else {
571
+ // Mainnet: register only (no minting)
572
+ output.info('Registering on AgentRegistry (gasless)...');
573
+ const calls = buildRegisterAgentBatch(
574
+ networkConfig.contracts.agentRegistry,
575
+ endpoint,
576
+ serviceDescriptors
577
+ );
578
+ const txRequests = calls.map((c) => ({
579
+ to: c.target,
580
+ data: c.data,
581
+ value: c.value.toString(),
582
+ }));
583
+
584
+ const receipt = await autoWallet.sendBatchTransaction(txRequests);
585
+ if (!receipt.success) {
586
+ output.warning(`Registration failed (tx: ${receipt.hash}). Run "actp register" later.`);
587
+ return false;
588
+ }
589
+
590
+ output.success('Agent registered on AgentRegistry');
591
+ output.print(` Tx: ${receipt.hash}`);
592
+ }
593
+
594
+ return true;
595
+ } catch (error) {
596
+ output.warning(`Registration failed: ${(error as Error).message}`);
597
+ output.info('You can register later with: actp register');
598
+ return false;
599
+ }
600
+ }
601
+
222
602
  async function promptPassword(): Promise<string> {
223
603
  // If not a TTY (e.g. piped or run by agent), skip prompt
224
604
  if (!process.stdin.isTTY) {
@@ -246,6 +626,7 @@ async function runScaffold(
246
626
  options: InitOptions,
247
627
  mode: CLIMode,
248
628
  output: Output,
629
+ mdConfig?: Record<string, unknown> | null,
249
630
  ): Promise<void> {
250
631
  const validIntents: ScaffoldIntent[] = ['earn', 'pay', 'both'];
251
632
  const intent: ScaffoldIntent = (options.intent as ScaffoldIntent) || 'earn';
@@ -266,8 +647,8 @@ async function runScaffold(
266
647
  return;
267
648
  }
268
649
 
269
- // Derive agent name from directory
270
- const agentName = path.basename(process.cwd());
650
+ // Derive agent name: prefer AGIRAILS.md name, fallback to directory name
651
+ const agentName = (mdConfig?.name ? String(mdConfig.name) : null) || path.basename(process.cwd());
271
652
 
272
653
  // Get template and substitute variables
273
654
  const template = getTemplate(intent);
@@ -297,8 +678,8 @@ async function runScaffold(
297
678
  const tsconfigContent = JSON.stringify({
298
679
  compilerOptions: {
299
680
  target: 'ES2022',
300
- module: 'ES2022',
301
- moduleResolution: 'bundler',
681
+ module: 'commonjs',
682
+ moduleResolution: 'node',
302
683
  esModuleInterop: true,
303
684
  strict: true,
304
685
  outDir: 'dist',
@@ -317,19 +698,7 @@ async function runScaffold(
317
698
  }
318
699
  }
319
700
 
320
- // Check package.json for type: module
321
- const pkgFile = path.join(process.cwd(), 'package.json');
322
- if (fs.existsSync(pkgFile)) {
323
- try {
324
- const pkg = JSON.parse(fs.readFileSync(pkgFile, 'utf-8'));
325
- if (pkg.type !== 'module') {
326
- output.warning(
327
- 'package.json has type: "' + (pkg.type || 'commonjs') + '". ' +
328
- 'Set "type": "module" for ESM support, or run with: npx ts-node --esm agent.ts'
329
- );
330
- }
331
- } catch { /* ignore parse errors */ }
332
- }
701
+ // Note: @agirails/sdk is CJS — no type:module check needed
333
702
 
334
703
  output.blank();
335
704
  output.print('Next steps:');
@@ -13,8 +13,7 @@ import { mapError } from '../utils/client';
13
13
  import { resolve } from 'path';
14
14
  import { readFileSync, existsSync } from 'fs';
15
15
  import { ethers } from 'ethers';
16
- import { computeConfigHash, parseAgirailsMd, serializeAgirailsMd } from '../../config/agirailsmd';
17
- import { AgentRegistryClient } from '../../registry/AgentRegistryClient';
16
+ import { computeConfigHash, parseAgirailsMd } from '../../config/agirailsmd';
18
17
  import { FilebaseClient } from '../../storage/FilebaseClient';
19
18
  import { ArweaveClient } from '../../storage/ArweaveClient';
20
19
  import { getNetwork } from '../../config/networks';