@agirails/sdk 2.5.3 → 2.5.5

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 (169) hide show
  1. package/dist/ACTPClient.d.ts +18 -0
  2. package/dist/ACTPClient.d.ts.map +1 -1
  3. package/dist/ACTPClient.js +72 -23
  4. package/dist/ACTPClient.js.map +1 -1
  5. package/dist/adapters/BasicAdapter.d.ts +15 -0
  6. package/dist/adapters/BasicAdapter.d.ts.map +1 -1
  7. package/dist/adapters/BasicAdapter.js +33 -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 +90 -12
  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/config/networks.d.ts +10 -2
  20. package/dist/config/networks.d.ts.map +1 -1
  21. package/dist/config/networks.js +31 -22
  22. package/dist/config/networks.js.map +1 -1
  23. package/dist/level0/request.d.ts.map +1 -1
  24. package/dist/level0/request.js +2 -1
  25. package/dist/level0/request.js.map +1 -1
  26. package/dist/runtime/BlockchainRuntime.d.ts.map +1 -1
  27. package/dist/runtime/BlockchainRuntime.js +11 -5
  28. package/dist/runtime/BlockchainRuntime.js.map +1 -1
  29. package/dist/utils/IPFSClient.d.ts +3 -1
  30. package/dist/utils/IPFSClient.d.ts.map +1 -1
  31. package/dist/utils/IPFSClient.js +27 -7
  32. package/dist/utils/IPFSClient.js.map +1 -1
  33. package/dist/wallet/AutoWalletProvider.d.ts +11 -1
  34. package/dist/wallet/AutoWalletProvider.d.ts.map +1 -1
  35. package/dist/wallet/AutoWalletProvider.js +84 -19
  36. package/dist/wallet/AutoWalletProvider.js.map +1 -1
  37. package/dist/wallet/IWalletProvider.d.ts +34 -0
  38. package/dist/wallet/IWalletProvider.d.ts.map +1 -1
  39. package/dist/wallet/SmartWalletRouter.d.ts +128 -0
  40. package/dist/wallet/SmartWalletRouter.d.ts.map +1 -0
  41. package/dist/wallet/SmartWalletRouter.js +248 -0
  42. package/dist/wallet/SmartWalletRouter.js.map +1 -0
  43. package/dist/wallet/aa/DualNonceManager.d.ts +26 -1
  44. package/dist/wallet/aa/DualNonceManager.d.ts.map +1 -1
  45. package/dist/wallet/aa/DualNonceManager.js +140 -6
  46. package/dist/wallet/aa/DualNonceManager.js.map +1 -1
  47. package/package.json +3 -6
  48. package/src/ACTPClient.ts +0 -1579
  49. package/src/abi/ACTPKernel.json +0 -1356
  50. package/src/abi/AgentRegistry.json +0 -915
  51. package/src/abi/ERC20.json +0 -40
  52. package/src/abi/EscrowVault.json +0 -134
  53. package/src/abi/IdentityRegistry.json +0 -316
  54. package/src/adapters/AdapterRegistry.ts +0 -173
  55. package/src/adapters/AdapterRouter.ts +0 -416
  56. package/src/adapters/BaseAdapter.ts +0 -498
  57. package/src/adapters/BasicAdapter.ts +0 -514
  58. package/src/adapters/IAdapter.ts +0 -292
  59. package/src/adapters/StandardAdapter.ts +0 -555
  60. package/src/adapters/X402Adapter.ts +0 -731
  61. package/src/adapters/index.ts +0 -60
  62. package/src/builders/DeliveryProofBuilder.ts +0 -327
  63. package/src/builders/QuoteBuilder.ts +0 -483
  64. package/src/builders/index.ts +0 -17
  65. package/src/cli/commands/balance.ts +0 -110
  66. package/src/cli/commands/batch.ts +0 -487
  67. package/src/cli/commands/config.ts +0 -231
  68. package/src/cli/commands/deploy-check.ts +0 -364
  69. package/src/cli/commands/deploy-env.ts +0 -120
  70. package/src/cli/commands/diff.ts +0 -141
  71. package/src/cli/commands/init.ts +0 -469
  72. package/src/cli/commands/mint.ts +0 -116
  73. package/src/cli/commands/pay.ts +0 -113
  74. package/src/cli/commands/publish.ts +0 -475
  75. package/src/cli/commands/pull.ts +0 -124
  76. package/src/cli/commands/register.ts +0 -247
  77. package/src/cli/commands/simulate.ts +0 -345
  78. package/src/cli/commands/time.ts +0 -302
  79. package/src/cli/commands/tx.ts +0 -448
  80. package/src/cli/commands/watch.ts +0 -211
  81. package/src/cli/index.ts +0 -134
  82. package/src/cli/utils/client.ts +0 -252
  83. package/src/cli/utils/config.ts +0 -389
  84. package/src/cli/utils/output.ts +0 -465
  85. package/src/cli/utils/wallet.ts +0 -109
  86. package/src/config/agirailsmd.ts +0 -262
  87. package/src/config/networks.ts +0 -275
  88. package/src/config/pendingPublish.ts +0 -237
  89. package/src/config/publishPipeline.ts +0 -359
  90. package/src/config/syncOperations.ts +0 -279
  91. package/src/erc8004/ERC8004Bridge.ts +0 -462
  92. package/src/erc8004/ReputationReporter.ts +0 -468
  93. package/src/erc8004/index.ts +0 -61
  94. package/src/errors/index.ts +0 -427
  95. package/src/index.ts +0 -364
  96. package/src/level0/Provider.ts +0 -117
  97. package/src/level0/ServiceDirectory.ts +0 -131
  98. package/src/level0/index.ts +0 -10
  99. package/src/level0/provide.ts +0 -132
  100. package/src/level0/request.ts +0 -432
  101. package/src/level1/Agent.ts +0 -1426
  102. package/src/level1/index.ts +0 -10
  103. package/src/level1/pricing/PriceCalculator.ts +0 -255
  104. package/src/level1/pricing/PricingStrategy.ts +0 -198
  105. package/src/level1/types/Job.ts +0 -179
  106. package/src/level1/types/Options.ts +0 -291
  107. package/src/level1/types/index.ts +0 -8
  108. package/src/protocol/ACTPKernel.ts +0 -808
  109. package/src/protocol/AgentRegistry.ts +0 -559
  110. package/src/protocol/DIDManager.ts +0 -629
  111. package/src/protocol/DIDResolver.ts +0 -554
  112. package/src/protocol/EASHelper.ts +0 -378
  113. package/src/protocol/EscrowVault.ts +0 -255
  114. package/src/protocol/EventMonitor.ts +0 -204
  115. package/src/protocol/MessageSigner.ts +0 -510
  116. package/src/protocol/ProofGenerator.ts +0 -339
  117. package/src/protocol/QuoteBuilder.ts +0 -15
  118. package/src/registry/AgentRegistryClient.ts +0 -202
  119. package/src/runtime/BlockchainRuntime.ts +0 -1015
  120. package/src/runtime/IACTPRuntime.ts +0 -306
  121. package/src/runtime/MockRuntime.ts +0 -1298
  122. package/src/runtime/MockStateManager.ts +0 -577
  123. package/src/runtime/index.ts +0 -25
  124. package/src/runtime/types/MockState.ts +0 -237
  125. package/src/storage/ArchiveBundleBuilder.ts +0 -561
  126. package/src/storage/ArweaveClient.ts +0 -946
  127. package/src/storage/FilebaseClient.ts +0 -790
  128. package/src/storage/index.ts +0 -96
  129. package/src/storage/types.ts +0 -348
  130. package/src/types/adapter.ts +0 -310
  131. package/src/types/agent.ts +0 -79
  132. package/src/types/did.ts +0 -223
  133. package/src/types/eip712.ts +0 -175
  134. package/src/types/erc8004.ts +0 -293
  135. package/src/types/escrow.ts +0 -27
  136. package/src/types/index.ts +0 -17
  137. package/src/types/message.ts +0 -145
  138. package/src/types/state.ts +0 -87
  139. package/src/types/transaction.ts +0 -69
  140. package/src/types/x402.ts +0 -251
  141. package/src/utils/ErrorRecoveryGuide.ts +0 -676
  142. package/src/utils/Helpers.ts +0 -688
  143. package/src/utils/IPFSClient.ts +0 -368
  144. package/src/utils/Logger.ts +0 -484
  145. package/src/utils/NonceManager.ts +0 -591
  146. package/src/utils/RateLimiter.ts +0 -534
  147. package/src/utils/ReceivedNonceTracker.ts +0 -567
  148. package/src/utils/SDKLifecycle.ts +0 -416
  149. package/src/utils/SecureNonce.ts +0 -78
  150. package/src/utils/Semaphore.ts +0 -276
  151. package/src/utils/UsedAttestationTracker.ts +0 -385
  152. package/src/utils/canonicalJson.ts +0 -38
  153. package/src/utils/circuitBreaker.ts +0 -324
  154. package/src/utils/computeTypeHash.ts +0 -48
  155. package/src/utils/fsSafe.ts +0 -80
  156. package/src/utils/index.ts +0 -80
  157. package/src/utils/retry.ts +0 -364
  158. package/src/utils/security.ts +0 -418
  159. package/src/utils/validation.ts +0 -540
  160. package/src/wallet/AutoWalletProvider.ts +0 -299
  161. package/src/wallet/EOAWalletProvider.ts +0 -69
  162. package/src/wallet/IWalletProvider.ts +0 -135
  163. package/src/wallet/aa/BundlerClient.ts +0 -274
  164. package/src/wallet/aa/DualNonceManager.ts +0 -173
  165. package/src/wallet/aa/PaymasterClient.ts +0 -174
  166. package/src/wallet/aa/TransactionBatcher.ts +0 -353
  167. package/src/wallet/aa/UserOpBuilder.ts +0 -246
  168. package/src/wallet/aa/constants.ts +0 -60
  169. 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
- }