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