@agirails/sdk 2.5.2 → 2.5.4

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 (172) hide show
  1. package/dist/ACTPClient.d.ts +18 -0
  2. package/dist/ACTPClient.d.ts.map +1 -1
  3. package/dist/ACTPClient.js +67 -22
  4. package/dist/ACTPClient.js.map +1 -1
  5. package/dist/adapters/BasicAdapter.d.ts +12 -0
  6. package/dist/adapters/BasicAdapter.d.ts.map +1 -1
  7. package/dist/adapters/BasicAdapter.js +30 -4
  8. package/dist/adapters/BasicAdapter.js.map +1 -1
  9. package/dist/adapters/StandardAdapter.d.ts +20 -3
  10. package/dist/adapters/StandardAdapter.d.ts.map +1 -1
  11. package/dist/adapters/StandardAdapter.js +45 -11
  12. package/dist/adapters/StandardAdapter.js.map +1 -1
  13. package/dist/cli/commands/publish.js +16 -4
  14. package/dist/cli/commands/publish.js.map +1 -1
  15. package/dist/cli/commands/register.js +16 -4
  16. package/dist/cli/commands/register.js.map +1 -1
  17. package/dist/cli/commands/tx.js +31 -3
  18. package/dist/cli/commands/tx.js.map +1 -1
  19. package/dist/cli/utils/client.d.ts.map +1 -1
  20. package/dist/cli/utils/client.js +1 -0
  21. package/dist/cli/utils/client.js.map +1 -1
  22. package/dist/config/networks.d.ts +2 -2
  23. package/dist/config/networks.d.ts.map +1 -1
  24. package/dist/config/networks.js +27 -22
  25. package/dist/config/networks.js.map +1 -1
  26. package/dist/level0/request.d.ts.map +1 -1
  27. package/dist/level0/request.js +2 -1
  28. package/dist/level0/request.js.map +1 -1
  29. package/dist/runtime/BlockchainRuntime.d.ts.map +1 -1
  30. package/dist/runtime/BlockchainRuntime.js +11 -5
  31. package/dist/runtime/BlockchainRuntime.js.map +1 -1
  32. package/dist/runtime/MockStateManager.d.ts.map +1 -1
  33. package/dist/runtime/MockStateManager.js +2 -1
  34. package/dist/runtime/MockStateManager.js.map +1 -1
  35. package/dist/utils/IPFSClient.d.ts +3 -1
  36. package/dist/utils/IPFSClient.d.ts.map +1 -1
  37. package/dist/utils/IPFSClient.js +27 -7
  38. package/dist/utils/IPFSClient.js.map +1 -1
  39. package/dist/wallet/AutoWalletProvider.d.ts.map +1 -1
  40. package/dist/wallet/AutoWalletProvider.js +52 -18
  41. package/dist/wallet/AutoWalletProvider.js.map +1 -1
  42. package/dist/wallet/SmartWalletRouter.d.ts +116 -0
  43. package/dist/wallet/SmartWalletRouter.d.ts.map +1 -0
  44. package/dist/wallet/SmartWalletRouter.js +212 -0
  45. package/dist/wallet/SmartWalletRouter.js.map +1 -0
  46. package/dist/wallet/aa/DualNonceManager.d.ts +19 -0
  47. package/dist/wallet/aa/DualNonceManager.d.ts.map +1 -1
  48. package/dist/wallet/aa/DualNonceManager.js +100 -5
  49. package/dist/wallet/aa/DualNonceManager.js.map +1 -1
  50. package/package.json +3 -6
  51. package/src/ACTPClient.ts +0 -1579
  52. package/src/abi/ACTPKernel.json +0 -1356
  53. package/src/abi/AgentRegistry.json +0 -915
  54. package/src/abi/ERC20.json +0 -40
  55. package/src/abi/EscrowVault.json +0 -134
  56. package/src/abi/IdentityRegistry.json +0 -316
  57. package/src/adapters/AdapterRegistry.ts +0 -173
  58. package/src/adapters/AdapterRouter.ts +0 -416
  59. package/src/adapters/BaseAdapter.ts +0 -498
  60. package/src/adapters/BasicAdapter.ts +0 -514
  61. package/src/adapters/IAdapter.ts +0 -292
  62. package/src/adapters/StandardAdapter.ts +0 -555
  63. package/src/adapters/X402Adapter.ts +0 -731
  64. package/src/adapters/index.ts +0 -60
  65. package/src/builders/DeliveryProofBuilder.ts +0 -327
  66. package/src/builders/QuoteBuilder.ts +0 -483
  67. package/src/builders/index.ts +0 -17
  68. package/src/cli/commands/balance.ts +0 -110
  69. package/src/cli/commands/batch.ts +0 -487
  70. package/src/cli/commands/config.ts +0 -231
  71. package/src/cli/commands/deploy-check.ts +0 -364
  72. package/src/cli/commands/deploy-env.ts +0 -120
  73. package/src/cli/commands/diff.ts +0 -141
  74. package/src/cli/commands/init.ts +0 -469
  75. package/src/cli/commands/mint.ts +0 -116
  76. package/src/cli/commands/pay.ts +0 -113
  77. package/src/cli/commands/publish.ts +0 -475
  78. package/src/cli/commands/pull.ts +0 -124
  79. package/src/cli/commands/register.ts +0 -247
  80. package/src/cli/commands/simulate.ts +0 -345
  81. package/src/cli/commands/time.ts +0 -302
  82. package/src/cli/commands/tx.ts +0 -448
  83. package/src/cli/commands/watch.ts +0 -211
  84. package/src/cli/index.ts +0 -134
  85. package/src/cli/utils/client.ts +0 -251
  86. package/src/cli/utils/config.ts +0 -389
  87. package/src/cli/utils/output.ts +0 -465
  88. package/src/cli/utils/wallet.ts +0 -109
  89. package/src/config/agirailsmd.ts +0 -262
  90. package/src/config/networks.ts +0 -275
  91. package/src/config/pendingPublish.ts +0 -237
  92. package/src/config/publishPipeline.ts +0 -359
  93. package/src/config/syncOperations.ts +0 -279
  94. package/src/erc8004/ERC8004Bridge.ts +0 -462
  95. package/src/erc8004/ReputationReporter.ts +0 -468
  96. package/src/erc8004/index.ts +0 -61
  97. package/src/errors/index.ts +0 -427
  98. package/src/index.ts +0 -364
  99. package/src/level0/Provider.ts +0 -117
  100. package/src/level0/ServiceDirectory.ts +0 -131
  101. package/src/level0/index.ts +0 -10
  102. package/src/level0/provide.ts +0 -132
  103. package/src/level0/request.ts +0 -432
  104. package/src/level1/Agent.ts +0 -1426
  105. package/src/level1/index.ts +0 -10
  106. package/src/level1/pricing/PriceCalculator.ts +0 -255
  107. package/src/level1/pricing/PricingStrategy.ts +0 -198
  108. package/src/level1/types/Job.ts +0 -179
  109. package/src/level1/types/Options.ts +0 -291
  110. package/src/level1/types/index.ts +0 -8
  111. package/src/protocol/ACTPKernel.ts +0 -808
  112. package/src/protocol/AgentRegistry.ts +0 -559
  113. package/src/protocol/DIDManager.ts +0 -629
  114. package/src/protocol/DIDResolver.ts +0 -554
  115. package/src/protocol/EASHelper.ts +0 -378
  116. package/src/protocol/EscrowVault.ts +0 -255
  117. package/src/protocol/EventMonitor.ts +0 -204
  118. package/src/protocol/MessageSigner.ts +0 -510
  119. package/src/protocol/ProofGenerator.ts +0 -339
  120. package/src/protocol/QuoteBuilder.ts +0 -15
  121. package/src/registry/AgentRegistryClient.ts +0 -202
  122. package/src/runtime/BlockchainRuntime.ts +0 -1015
  123. package/src/runtime/IACTPRuntime.ts +0 -306
  124. package/src/runtime/MockRuntime.ts +0 -1298
  125. package/src/runtime/MockStateManager.ts +0 -576
  126. package/src/runtime/index.ts +0 -25
  127. package/src/runtime/types/MockState.ts +0 -237
  128. package/src/storage/ArchiveBundleBuilder.ts +0 -561
  129. package/src/storage/ArweaveClient.ts +0 -946
  130. package/src/storage/FilebaseClient.ts +0 -790
  131. package/src/storage/index.ts +0 -96
  132. package/src/storage/types.ts +0 -348
  133. package/src/types/adapter.ts +0 -310
  134. package/src/types/agent.ts +0 -79
  135. package/src/types/did.ts +0 -223
  136. package/src/types/eip712.ts +0 -175
  137. package/src/types/erc8004.ts +0 -293
  138. package/src/types/escrow.ts +0 -27
  139. package/src/types/index.ts +0 -17
  140. package/src/types/message.ts +0 -145
  141. package/src/types/state.ts +0 -87
  142. package/src/types/transaction.ts +0 -69
  143. package/src/types/x402.ts +0 -251
  144. package/src/utils/ErrorRecoveryGuide.ts +0 -676
  145. package/src/utils/Helpers.ts +0 -688
  146. package/src/utils/IPFSClient.ts +0 -368
  147. package/src/utils/Logger.ts +0 -484
  148. package/src/utils/NonceManager.ts +0 -591
  149. package/src/utils/RateLimiter.ts +0 -534
  150. package/src/utils/ReceivedNonceTracker.ts +0 -567
  151. package/src/utils/SDKLifecycle.ts +0 -416
  152. package/src/utils/SecureNonce.ts +0 -78
  153. package/src/utils/Semaphore.ts +0 -276
  154. package/src/utils/UsedAttestationTracker.ts +0 -385
  155. package/src/utils/canonicalJson.ts +0 -38
  156. package/src/utils/circuitBreaker.ts +0 -324
  157. package/src/utils/computeTypeHash.ts +0 -48
  158. package/src/utils/fsSafe.ts +0 -80
  159. package/src/utils/index.ts +0 -80
  160. package/src/utils/retry.ts +0 -364
  161. package/src/utils/security.ts +0 -418
  162. package/src/utils/validation.ts +0 -540
  163. package/src/wallet/AutoWalletProvider.ts +0 -299
  164. package/src/wallet/EOAWalletProvider.ts +0 -69
  165. package/src/wallet/IWalletProvider.ts +0 -135
  166. package/src/wallet/aa/BundlerClient.ts +0 -274
  167. package/src/wallet/aa/DualNonceManager.ts +0 -173
  168. package/src/wallet/aa/PaymasterClient.ts +0 -174
  169. package/src/wallet/aa/TransactionBatcher.ts +0 -353
  170. package/src/wallet/aa/UserOpBuilder.ts +0 -246
  171. package/src/wallet/aa/constants.ts +0 -60
  172. package/src/wallet/keystore.ts +0 -240
@@ -1,237 +0,0 @@
1
- /**
2
- * Pending Publish Module — Deferred on-chain activation for Lazy Publish.
3
- *
4
- * When `actp publish` runs, it saves a `pending-publish.{network}.json` file
5
- * instead of making on-chain calls. The first real payment triggers activation
6
- * (registerAgent, publishConfig, setListed) in a single UserOp alongside the
7
- * payment calls.
8
- *
9
- * Files are chain-scoped: testnet and mainnet pending publishes coexist independently.
10
- * Legacy `pending-publish.json` (unscoped) is supported for migration.
11
- *
12
- * The file is deleted after successful on-chain activation.
13
- *
14
- * @module config/pendingPublish
15
- */
16
-
17
- import { readFileSync, writeFileSync, unlinkSync, existsSync, mkdirSync, renameSync, lstatSync } from 'fs';
18
- import { join } from 'path';
19
- import { ServiceDescriptor } from '../types/agent';
20
-
21
- // ============================================================================
22
- // Types
23
- // ============================================================================
24
-
25
- /**
26
- * Serializable representation of a ServiceDescriptor.
27
- * BigInt fields are stored as strings for JSON compatibility.
28
- */
29
- interface SerializedServiceDescriptor {
30
- serviceTypeHash: string;
31
- serviceType: string;
32
- schemaURI: string;
33
- minPrice: string;
34
- maxPrice: string;
35
- avgCompletionTime: number;
36
- metadataCID: string;
37
- }
38
-
39
- /**
40
- * Pending publish state — saved to `.actp/pending-publish.{network}.json`.
41
- */
42
- export interface PendingPublish {
43
- /** Schema version */
44
- version: 1;
45
- /** Canonical config hash (bytes32) */
46
- configHash: string;
47
- /** IPFS CID of uploaded AGIRAILS.md */
48
- cid: string;
49
- /** Agent endpoint URL */
50
- endpoint: string;
51
- /** Service descriptors from AGIRAILS.md frontmatter */
52
- serviceDescriptors: ServiceDescriptor[];
53
- /** ISO 8601 timestamp of when pending-publish.json was created */
54
- createdAt: string;
55
- /** Network identifier (e.g. 'base-sepolia', 'base-mainnet') */
56
- network?: string;
57
- }
58
-
59
- /**
60
- * JSON-serializable form of PendingPublish (bigints as strings).
61
- */
62
- interface SerializedPendingPublish {
63
- version: 1;
64
- configHash: string;
65
- cid: string;
66
- endpoint: string;
67
- serviceDescriptors: SerializedServiceDescriptor[];
68
- createdAt: string;
69
- network?: string;
70
- }
71
-
72
- // ============================================================================
73
- // Serialization Helpers
74
- // ============================================================================
75
-
76
- function serializeDescriptor(sd: ServiceDescriptor): SerializedServiceDescriptor {
77
- return {
78
- serviceTypeHash: sd.serviceTypeHash,
79
- serviceType: sd.serviceType,
80
- schemaURI: sd.schemaURI,
81
- minPrice: sd.minPrice.toString(),
82
- maxPrice: sd.maxPrice.toString(),
83
- avgCompletionTime: sd.avgCompletionTime,
84
- metadataCID: sd.metadataCID,
85
- };
86
- }
87
-
88
- function deserializeDescriptor(sd: SerializedServiceDescriptor): ServiceDescriptor {
89
- return {
90
- serviceTypeHash: sd.serviceTypeHash,
91
- serviceType: sd.serviceType,
92
- schemaURI: sd.schemaURI,
93
- minPrice: BigInt(sd.minPrice),
94
- maxPrice: BigInt(sd.maxPrice),
95
- avgCompletionTime: sd.avgCompletionTime,
96
- metadataCID: sd.metadataCID,
97
- };
98
- }
99
-
100
- // ============================================================================
101
- // Public API
102
- // ============================================================================
103
-
104
- /**
105
- * Get the .actp directory path.
106
- *
107
- * Respects `ACTP_DIR` env var for custom locations.
108
- * Defaults to `{cwd}/.actp`.
109
- */
110
- export function getActpDir(): string {
111
- return process.env.ACTP_DIR || join(process.cwd(), '.actp');
112
- }
113
-
114
- /**
115
- * Get the path to a pending-publish file.
116
- *
117
- * @param network - Optional network identifier. If provided, returns
118
- * `pending-publish.{network}.json`. Otherwise returns legacy `pending-publish.json`.
119
- */
120
- export function getPendingPublishPath(network?: string): string {
121
- if (network) {
122
- return join(getActpDir(), `pending-publish.${network}.json`);
123
- }
124
- return join(getActpDir(), 'pending-publish.json');
125
- }
126
-
127
- /**
128
- * Save a pending publish to `.actp/pending-publish.{network}.json`.
129
- *
130
- * Creates the .actp directory if it doesn't exist.
131
- * File is written atomically with mode 0o600 (owner read/write only).
132
- *
133
- * If `pending.network` is set, saves to network-scoped file.
134
- * Otherwise saves to legacy `pending-publish.json`.
135
- */
136
- export function savePendingPublish(pending: PendingPublish): void {
137
- const dir = getActpDir();
138
-
139
- // Verify .actp/ is a real directory (not a symlink — symlink attack prevention)
140
- if (existsSync(dir)) {
141
- const stat = lstatSync(dir);
142
- if (!stat.isDirectory() || stat.isSymbolicLink()) {
143
- throw new Error(`Security: ${dir} is not a real directory (symlink attack prevention)`);
144
- }
145
- } else {
146
- mkdirSync(dir, { recursive: true, mode: 0o700 });
147
- }
148
-
149
- const serialized: SerializedPendingPublish = {
150
- version: pending.version,
151
- configHash: pending.configHash,
152
- cid: pending.cid,
153
- endpoint: pending.endpoint,
154
- serviceDescriptors: pending.serviceDescriptors.map(serializeDescriptor),
155
- createdAt: pending.createdAt,
156
- ...(pending.network ? { network: pending.network } : {}),
157
- };
158
-
159
- const filePath = getPendingPublishPath(pending.network);
160
- const tmpPath = filePath + '.tmp';
161
-
162
- // Atomic write: write to .tmp with restricted mode, then rename
163
- writeFileSync(tmpPath, JSON.stringify(serialized, null, 2), { mode: 0o600 });
164
- renameSync(tmpPath, filePath);
165
- }
166
-
167
- /**
168
- * Load a pending publish from `.actp/pending-publish.{network}.json`.
169
- *
170
- * If `network` is provided:
171
- * 1. Try `pending-publish.{network}.json`
172
- * 2. Fall back to legacy `pending-publish.json` (migration)
173
- *
174
- * If no `network`: loads legacy `pending-publish.json`.
175
- *
176
- * Returns null if no file found.
177
- */
178
- export function loadPendingPublish(network?: string): PendingPublish | null {
179
- // Try network-scoped file first
180
- if (network) {
181
- const scopedPath = getPendingPublishPath(network);
182
- if (existsSync(scopedPath)) {
183
- return deserializePendingPublish(readFileSync(scopedPath, 'utf-8'));
184
- }
185
- }
186
-
187
- // Fall back to legacy file
188
- const legacyPath = getPendingPublishPath();
189
- if (!existsSync(legacyPath)) {
190
- return null;
191
- }
192
-
193
- return deserializePendingPublish(readFileSync(legacyPath, 'utf-8'));
194
- }
195
-
196
- /**
197
- * Delete the pending-publish file for a given network.
198
- *
199
- * Deletes both the network-scoped file and legacy file (cleanup).
200
- * No-op if files don't exist. Best-effort — never throws.
201
- */
202
- export function deletePendingPublish(network?: string): void {
203
- try {
204
- // Delete network-scoped file
205
- if (network) {
206
- const scopedPath = getPendingPublishPath(network);
207
- if (existsSync(scopedPath)) {
208
- unlinkSync(scopedPath);
209
- }
210
- }
211
-
212
- // Also delete legacy file if it exists (cleanup)
213
- const legacyPath = getPendingPublishPath();
214
- if (existsSync(legacyPath)) {
215
- unlinkSync(legacyPath);
216
- }
217
- } catch {
218
- // Best-effort: file deletion should never crash post-payment UX
219
- }
220
- }
221
-
222
- // ============================================================================
223
- // Internal Helpers
224
- // ============================================================================
225
-
226
- function deserializePendingPublish(raw: string): PendingPublish {
227
- const serialized: SerializedPendingPublish = JSON.parse(raw);
228
- return {
229
- version: serialized.version,
230
- configHash: serialized.configHash,
231
- cid: serialized.cid,
232
- endpoint: serialized.endpoint,
233
- serviceDescriptors: serialized.serviceDescriptors.map(deserializeDescriptor),
234
- createdAt: serialized.createdAt,
235
- ...(serialized.network ? { network: serialized.network } : {}),
236
- };
237
- }
@@ -1,359 +0,0 @@
1
- /**
2
- * Publish Pipeline - AGIRAILS.md → IPFS → Arweave → On-Chain
3
- *
4
- * Orchestrates the full publish flow:
5
- * 1. Read AGIRAILS.md → parse → compute configHash
6
- * 2. Upload to Filebase (IPFS pinning)
7
- * 3. Upload to Arweave (permanent storage) [optional]
8
- * 4. Call AgentRegistry.publishConfig(cid, hash) on-chain
9
- * 5. Update AGIRAILS.md frontmatter with config_hash and published_at
10
- *
11
- * @module config/publishPipeline
12
- */
13
-
14
- import { readFileSync, writeFileSync } from 'fs';
15
- import { Signer, keccak256, toUtf8Bytes } from 'ethers';
16
- import { parseAgirailsMd, computeConfigHash, serializeAgirailsMd } from './agirailsmd';
17
- import { AgentRegistryClient } from '../registry/AgentRegistryClient';
18
- import { AgentRegistry } from '../protocol/AgentRegistry';
19
- import { FilebaseClient } from '../storage/FilebaseClient';
20
- import { ArweaveClient } from '../storage/ArweaveClient';
21
- import { ServiceDescriptor } from '../types';
22
-
23
- // ============================================================================
24
- // Types
25
- // ============================================================================
26
-
27
- export interface PublishOptions {
28
- /** Path to AGIRAILS.md file */
29
- path: string;
30
- /** Network name (for registry address lookup) */
31
- network: string;
32
- /** AgentRegistry contract address */
33
- registryAddress: string;
34
- /** Signer for on-chain transactions */
35
- signer: Signer;
36
- /** Filebase client for IPFS upload */
37
- filebaseClient: FilebaseClient;
38
- /** Arweave client for permanent storage (optional) */
39
- arweaveClient?: ArweaveClient;
40
- /** Skip Arweave upload (dev mode) */
41
- skipArweave?: boolean;
42
- /** Dry run - compute and show but don't execute */
43
- dryRun?: boolean;
44
- /** Gas settings */
45
- gasSettings?: {
46
- maxFeePerGas?: bigint;
47
- maxPriorityFeePerGas?: bigint;
48
- };
49
- }
50
-
51
- export interface PublishResult {
52
- /** IPFS CID of the uploaded AGIRAILS.md */
53
- cid: string;
54
- /** Canonical config hash (bytes32) */
55
- configHash: string;
56
- /** On-chain transaction hash */
57
- txHash?: string;
58
- /** Arweave transaction ID (if uploaded) */
59
- arweaveTxId?: string;
60
- /** Whether this was a dry run */
61
- dryRun: boolean;
62
- /** Whether the agent was auto-registered during this publish */
63
- registered?: boolean;
64
- }
65
-
66
- // ============================================================================
67
- // Registration Helpers
68
- // ============================================================================
69
-
70
- export const PENDING_ENDPOINT = 'https://pending.agirails.io';
71
-
72
- /** Default values for capabilities-to-services conversion */
73
- const SERVICE_DEFAULTS = {
74
- schemaURI: '',
75
- minPrice: 0n,
76
- maxPrice: 1_000_000_000n, // 1000 USDC
77
- avgCompletionTime: 3600, // 1 hour
78
- metadataCID: '',
79
- };
80
-
81
- /** Max safe USDC value before BigInt conversion loses precision */
82
- const MAX_SAFE_USDC = Math.floor(Number.MAX_SAFE_INTEGER / 1_000_000);
83
-
84
- /** Validate service type format (must match contract requirements) */
85
- function validateServiceType(serviceType: string, source: string): void {
86
- if (!serviceType) {
87
- throw new Error(`Empty service type in ${source}`);
88
- }
89
- if (!/^[a-z0-9]+(-[a-z0-9]+)*$/.test(serviceType)) {
90
- throw new Error(
91
- `Invalid service type "${serviceType}" in ${source}. ` +
92
- 'Must be lowercase alphanumeric with hyphens (e.g., "text-generation").'
93
- );
94
- }
95
- }
96
-
97
- /** Convert human-readable USDC to 6-decimal base units with overflow check */
98
- function usdcToBaseUnits(value: number, fieldName: string): bigint {
99
- if (value < 0) throw new Error(`${fieldName} cannot be negative`);
100
- if (value > MAX_SAFE_USDC) throw new Error(`${fieldName} exceeds maximum safe value (${MAX_SAFE_USDC} USDC)`);
101
- return BigInt(Math.round(value * 1_000_000));
102
- }
103
-
104
- /**
105
- * Extract registration params from AGIRAILS.md frontmatter.
106
- *
107
- * Supports two formats:
108
- * - `services`: full ServiceDescriptor objects with pricing
109
- * - `capabilities`: simple string list, auto-converted with defaults
110
- *
111
- * @throws Error if neither services nor capabilities are present
112
- */
113
- export function extractRegistrationParams(
114
- frontmatter: Record<string, unknown>
115
- ): { endpoint: string; serviceDescriptors: ServiceDescriptor[] } {
116
- // Endpoint: use frontmatter field or placeholder
117
- const endpoint = typeof frontmatter.endpoint === 'string' && frontmatter.endpoint
118
- ? frontmatter.endpoint
119
- : PENDING_ENDPOINT;
120
-
121
- // Try explicit services first
122
- if (Array.isArray(frontmatter.services) && frontmatter.services.length > 0) {
123
- const serviceDescriptors = (frontmatter.services as Record<string, unknown>[]).map(svc => {
124
- const serviceType = String(svc.type || svc.service_type || '').trim().toLowerCase();
125
- validateServiceType(serviceType, 'services');
126
-
127
- // Parse price range: "1.0-100.0" or separate min/max
128
- let minPrice = SERVICE_DEFAULTS.minPrice;
129
- let maxPrice = SERVICE_DEFAULTS.maxPrice;
130
- if (typeof svc.price === 'string' && svc.price.includes('-')) {
131
- const [min, max] = svc.price.split('-').map(Number);
132
- minPrice = usdcToBaseUnits(min, 'min_price');
133
- maxPrice = usdcToBaseUnits(max, 'max_price');
134
- } else {
135
- if (svc.min_price !== undefined) minPrice = usdcToBaseUnits(Number(svc.min_price), 'min_price');
136
- if (svc.max_price !== undefined) maxPrice = usdcToBaseUnits(Number(svc.max_price), 'max_price');
137
- }
138
-
139
- return {
140
- serviceTypeHash: keccak256(toUtf8Bytes(serviceType)),
141
- serviceType,
142
- schemaURI: String(svc.schema_uri || svc.schemaURI || SERVICE_DEFAULTS.schemaURI),
143
- minPrice,
144
- maxPrice,
145
- avgCompletionTime: Number(svc.avg_completion_time || svc.avgCompletionTime || SERVICE_DEFAULTS.avgCompletionTime),
146
- metadataCID: String(svc.metadata_cid || svc.metadataCID || SERVICE_DEFAULTS.metadataCID),
147
- };
148
- });
149
- return { endpoint, serviceDescriptors };
150
- }
151
-
152
- // Fallback: convert capabilities list to services with defaults
153
- if (Array.isArray(frontmatter.capabilities) && frontmatter.capabilities.length > 0) {
154
- const serviceDescriptors = (frontmatter.capabilities as string[]).map(cap => {
155
- const serviceType = String(cap).trim().toLowerCase();
156
- validateServiceType(serviceType, 'capabilities');
157
- return {
158
- serviceTypeHash: keccak256(toUtf8Bytes(serviceType)),
159
- serviceType,
160
- schemaURI: SERVICE_DEFAULTS.schemaURI,
161
- minPrice: SERVICE_DEFAULTS.minPrice,
162
- maxPrice: SERVICE_DEFAULTS.maxPrice,
163
- avgCompletionTime: SERVICE_DEFAULTS.avgCompletionTime,
164
- metadataCID: SERVICE_DEFAULTS.metadataCID,
165
- };
166
- });
167
- return { endpoint, serviceDescriptors };
168
- }
169
-
170
- throw new Error(
171
- 'AGIRAILS.md must have "services" (with type field) or "capabilities" in frontmatter for agent registration.\n' +
172
- 'Add at least one, e.g.:\n' +
173
- ' services:\n' +
174
- ' - name: my-service\n' +
175
- ' type: text-generation\n' +
176
- ' price: 1.00\n'
177
- );
178
- }
179
-
180
- // ============================================================================
181
- // Prepare Publish (offline — no on-chain calls)
182
- // ============================================================================
183
-
184
- export interface PreparePublishOptions {
185
- /** Path to AGIRAILS.md file */
186
- path: string;
187
- /** Filebase client for IPFS upload */
188
- filebaseClient: FilebaseClient;
189
- /** Arweave client for permanent storage (optional) */
190
- arweaveClient?: ArweaveClient;
191
- /** Skip Arweave upload */
192
- skipArweave?: boolean;
193
- /** Dry run — compute and show but don't execute */
194
- dryRun?: boolean;
195
- }
196
-
197
- export interface PreparePublishResult {
198
- /** IPFS CID of uploaded AGIRAILS.md */
199
- cid: string;
200
- /** Canonical config hash (bytes32) */
201
- configHash: string;
202
- /** Arweave transaction ID (if uploaded) */
203
- arweaveTxId?: string;
204
- /** Parsed frontmatter */
205
- frontmatter: Record<string, unknown>;
206
- /** Parsed body */
207
- body: string;
208
- /** Whether this was a dry run */
209
- dryRun: boolean;
210
- }
211
-
212
- /**
213
- * Prepare publish — IPFS upload + hash computation only.
214
- *
215
- * No on-chain calls. Returns the CID and configHash for
216
- * saving to pending-publish.json (lazy publish flow).
217
- */
218
- export async function preparePublish(options: PreparePublishOptions): Promise<PreparePublishResult> {
219
- const {
220
- path,
221
- filebaseClient,
222
- arweaveClient,
223
- skipArweave = false,
224
- dryRun = false,
225
- } = options;
226
-
227
- // Read and parse
228
- const content = readFileSync(path, 'utf-8');
229
- const { frontmatter, body } = parseAgirailsMd(content);
230
- const { configHash } = computeConfigHash(content);
231
-
232
- if (dryRun) {
233
- return { cid: '(dry-run)', configHash, frontmatter, body, dryRun: true };
234
- }
235
-
236
- // Upload to IPFS
237
- const ipfsResult = await filebaseClient.uploadBinary(
238
- Buffer.from(content, 'utf-8'),
239
- 'text/markdown',
240
- { metadata: { type: 'agirails-config', version: '1.0' } }
241
- );
242
- const cid = ipfsResult.cid;
243
-
244
- // Arweave (optional)
245
- let arweaveTxId: string | undefined;
246
- if (!skipArweave && arweaveClient) {
247
- const arweaveResult = await arweaveClient.uploadJSON(
248
- { frontmatter, body, _format: 'agirails.md.v1' },
249
- [
250
- { name: 'Type', value: 'agent-config' },
251
- { name: 'ConfigHash', value: configHash },
252
- { name: 'IPFS-CID', value: cid },
253
- ]
254
- );
255
- arweaveTxId = arweaveResult.txId;
256
- }
257
-
258
- return { cid, configHash, arweaveTxId, frontmatter, body, dryRun: false };
259
- }
260
-
261
- // ============================================================================
262
- // Pipeline (legacy — makes on-chain calls)
263
- // ============================================================================
264
-
265
- /**
266
- * Execute the full publish pipeline.
267
- *
268
- * @param options - Publish configuration
269
- * @returns Publish result with CID, hash, and transaction hashes
270
- */
271
- export async function publishAgirailsMd(options: PublishOptions): Promise<PublishResult> {
272
- const {
273
- path,
274
- registryAddress,
275
- signer,
276
- filebaseClient,
277
- arweaveClient,
278
- skipArweave = false,
279
- dryRun = false,
280
- gasSettings,
281
- } = options;
282
-
283
- // Step 1: Read and parse
284
- const content = readFileSync(path, 'utf-8');
285
- const { frontmatter, body } = parseAgirailsMd(content);
286
- const { configHash } = computeConfigHash(content);
287
-
288
- if (dryRun) {
289
- return {
290
- cid: '(dry-run)',
291
- configHash,
292
- dryRun: true,
293
- registered: false,
294
- };
295
- }
296
-
297
- // Step 2: Upload raw AGIRAILS.md to IPFS via Filebase
298
- // Upload the actual markdown file (not a JSON wrapper) so CID points to the real file
299
- const ipfsResult = await filebaseClient.uploadBinary(
300
- Buffer.from(content, 'utf-8'),
301
- 'text/markdown',
302
- { metadata: { type: 'agirails-config', version: '1.0' } }
303
- );
304
- const cid = ipfsResult.cid;
305
-
306
- // Step 3: Upload to Arweave (optional)
307
- // Arweave stores the JSON-structured form for archival querying.
308
- // uploadJSON already sets Content-Type: application/json and Protocol: AGIRAILS as defaults.
309
- let arweaveTxId: string | undefined;
310
- if (!skipArweave && arweaveClient) {
311
- const arweaveResult = await arweaveClient.uploadJSON(
312
- { frontmatter, body, _format: 'agirails.md.v1' },
313
- [
314
- { name: 'Type', value: 'agent-config' },
315
- { name: 'ConfigHash', value: configHash },
316
- { name: 'IPFS-CID', value: cid },
317
- ]
318
- );
319
- arweaveTxId = arweaveResult.txId;
320
- }
321
-
322
- // Step 4: Auto-register if needed, then publish on-chain
323
- const registry = new AgentRegistry(registryAddress, signer, gasSettings);
324
- const registryClient = new AgentRegistryClient(registryAddress, signer, gasSettings);
325
- let registered = false;
326
-
327
- const signerAddress = await signer.getAddress();
328
- const profile = await registry.getAgent(signerAddress);
329
-
330
- if (!profile) {
331
- // Not registered — extract params from frontmatter and auto-register
332
- const regParams = extractRegistrationParams(frontmatter);
333
- await registry.registerAgent(regParams);
334
- registered = true;
335
- }
336
-
337
- const { txHash } = await registryClient.publishConfig(cid, configHash);
338
-
339
- // Step 5: Update frontmatter with publish metadata
340
- const updatedFrontmatter = {
341
- ...frontmatter,
342
- config_hash: configHash,
343
- published_at: new Date().toISOString(),
344
- config_cid: cid,
345
- ...(arweaveTxId ? { arweave_tx: arweaveTxId } : {}),
346
- };
347
-
348
- const updatedContent = serializeAgirailsMd(updatedFrontmatter, body);
349
- writeFileSync(path, updatedContent, 'utf-8');
350
-
351
- return {
352
- cid,
353
- configHash,
354
- txHash,
355
- arweaveTxId,
356
- dryRun: false,
357
- registered,
358
- };
359
- }