@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.
- package/dist/ACTPClient.d.ts +18 -0
- package/dist/ACTPClient.d.ts.map +1 -1
- package/dist/ACTPClient.js +72 -23
- package/dist/ACTPClient.js.map +1 -1
- package/dist/adapters/BasicAdapter.d.ts +15 -0
- package/dist/adapters/BasicAdapter.d.ts.map +1 -1
- package/dist/adapters/BasicAdapter.js +33 -4
- package/dist/adapters/BasicAdapter.js.map +1 -1
- package/dist/adapters/StandardAdapter.d.ts +20 -3
- package/dist/adapters/StandardAdapter.d.ts.map +1 -1
- package/dist/adapters/StandardAdapter.js +90 -12
- package/dist/adapters/StandardAdapter.js.map +1 -1
- package/dist/cli/commands/publish.js +16 -4
- package/dist/cli/commands/publish.js.map +1 -1
- package/dist/cli/commands/register.js +16 -4
- package/dist/cli/commands/register.js.map +1 -1
- package/dist/cli/commands/tx.js +31 -3
- package/dist/cli/commands/tx.js.map +1 -1
- package/dist/config/networks.d.ts +10 -2
- package/dist/config/networks.d.ts.map +1 -1
- package/dist/config/networks.js +31 -22
- package/dist/config/networks.js.map +1 -1
- package/dist/level0/request.d.ts.map +1 -1
- package/dist/level0/request.js +2 -1
- package/dist/level0/request.js.map +1 -1
- package/dist/runtime/BlockchainRuntime.d.ts.map +1 -1
- package/dist/runtime/BlockchainRuntime.js +11 -5
- package/dist/runtime/BlockchainRuntime.js.map +1 -1
- package/dist/utils/IPFSClient.d.ts +3 -1
- package/dist/utils/IPFSClient.d.ts.map +1 -1
- package/dist/utils/IPFSClient.js +27 -7
- package/dist/utils/IPFSClient.js.map +1 -1
- package/dist/wallet/AutoWalletProvider.d.ts +11 -1
- package/dist/wallet/AutoWalletProvider.d.ts.map +1 -1
- package/dist/wallet/AutoWalletProvider.js +84 -19
- package/dist/wallet/AutoWalletProvider.js.map +1 -1
- package/dist/wallet/IWalletProvider.d.ts +34 -0
- package/dist/wallet/IWalletProvider.d.ts.map +1 -1
- package/dist/wallet/SmartWalletRouter.d.ts +128 -0
- package/dist/wallet/SmartWalletRouter.d.ts.map +1 -0
- package/dist/wallet/SmartWalletRouter.js +248 -0
- package/dist/wallet/SmartWalletRouter.js.map +1 -0
- package/dist/wallet/aa/DualNonceManager.d.ts +26 -1
- package/dist/wallet/aa/DualNonceManager.d.ts.map +1 -1
- package/dist/wallet/aa/DualNonceManager.js +140 -6
- package/dist/wallet/aa/DualNonceManager.js.map +1 -1
- package/package.json +3 -6
- package/src/ACTPClient.ts +0 -1579
- package/src/abi/ACTPKernel.json +0 -1356
- package/src/abi/AgentRegistry.json +0 -915
- package/src/abi/ERC20.json +0 -40
- package/src/abi/EscrowVault.json +0 -134
- package/src/abi/IdentityRegistry.json +0 -316
- package/src/adapters/AdapterRegistry.ts +0 -173
- package/src/adapters/AdapterRouter.ts +0 -416
- package/src/adapters/BaseAdapter.ts +0 -498
- package/src/adapters/BasicAdapter.ts +0 -514
- package/src/adapters/IAdapter.ts +0 -292
- package/src/adapters/StandardAdapter.ts +0 -555
- package/src/adapters/X402Adapter.ts +0 -731
- package/src/adapters/index.ts +0 -60
- package/src/builders/DeliveryProofBuilder.ts +0 -327
- package/src/builders/QuoteBuilder.ts +0 -483
- package/src/builders/index.ts +0 -17
- package/src/cli/commands/balance.ts +0 -110
- package/src/cli/commands/batch.ts +0 -487
- package/src/cli/commands/config.ts +0 -231
- package/src/cli/commands/deploy-check.ts +0 -364
- package/src/cli/commands/deploy-env.ts +0 -120
- package/src/cli/commands/diff.ts +0 -141
- package/src/cli/commands/init.ts +0 -469
- package/src/cli/commands/mint.ts +0 -116
- package/src/cli/commands/pay.ts +0 -113
- package/src/cli/commands/publish.ts +0 -475
- package/src/cli/commands/pull.ts +0 -124
- package/src/cli/commands/register.ts +0 -247
- package/src/cli/commands/simulate.ts +0 -345
- package/src/cli/commands/time.ts +0 -302
- package/src/cli/commands/tx.ts +0 -448
- package/src/cli/commands/watch.ts +0 -211
- package/src/cli/index.ts +0 -134
- package/src/cli/utils/client.ts +0 -252
- package/src/cli/utils/config.ts +0 -389
- package/src/cli/utils/output.ts +0 -465
- package/src/cli/utils/wallet.ts +0 -109
- package/src/config/agirailsmd.ts +0 -262
- package/src/config/networks.ts +0 -275
- package/src/config/pendingPublish.ts +0 -237
- package/src/config/publishPipeline.ts +0 -359
- package/src/config/syncOperations.ts +0 -279
- package/src/erc8004/ERC8004Bridge.ts +0 -462
- package/src/erc8004/ReputationReporter.ts +0 -468
- package/src/erc8004/index.ts +0 -61
- package/src/errors/index.ts +0 -427
- package/src/index.ts +0 -364
- package/src/level0/Provider.ts +0 -117
- package/src/level0/ServiceDirectory.ts +0 -131
- package/src/level0/index.ts +0 -10
- package/src/level0/provide.ts +0 -132
- package/src/level0/request.ts +0 -432
- package/src/level1/Agent.ts +0 -1426
- package/src/level1/index.ts +0 -10
- package/src/level1/pricing/PriceCalculator.ts +0 -255
- package/src/level1/pricing/PricingStrategy.ts +0 -198
- package/src/level1/types/Job.ts +0 -179
- package/src/level1/types/Options.ts +0 -291
- package/src/level1/types/index.ts +0 -8
- package/src/protocol/ACTPKernel.ts +0 -808
- package/src/protocol/AgentRegistry.ts +0 -559
- package/src/protocol/DIDManager.ts +0 -629
- package/src/protocol/DIDResolver.ts +0 -554
- package/src/protocol/EASHelper.ts +0 -378
- package/src/protocol/EscrowVault.ts +0 -255
- package/src/protocol/EventMonitor.ts +0 -204
- package/src/protocol/MessageSigner.ts +0 -510
- package/src/protocol/ProofGenerator.ts +0 -339
- package/src/protocol/QuoteBuilder.ts +0 -15
- package/src/registry/AgentRegistryClient.ts +0 -202
- package/src/runtime/BlockchainRuntime.ts +0 -1015
- package/src/runtime/IACTPRuntime.ts +0 -306
- package/src/runtime/MockRuntime.ts +0 -1298
- package/src/runtime/MockStateManager.ts +0 -577
- package/src/runtime/index.ts +0 -25
- package/src/runtime/types/MockState.ts +0 -237
- package/src/storage/ArchiveBundleBuilder.ts +0 -561
- package/src/storage/ArweaveClient.ts +0 -946
- package/src/storage/FilebaseClient.ts +0 -790
- package/src/storage/index.ts +0 -96
- package/src/storage/types.ts +0 -348
- package/src/types/adapter.ts +0 -310
- package/src/types/agent.ts +0 -79
- package/src/types/did.ts +0 -223
- package/src/types/eip712.ts +0 -175
- package/src/types/erc8004.ts +0 -293
- package/src/types/escrow.ts +0 -27
- package/src/types/index.ts +0 -17
- package/src/types/message.ts +0 -145
- package/src/types/state.ts +0 -87
- package/src/types/transaction.ts +0 -69
- package/src/types/x402.ts +0 -251
- package/src/utils/ErrorRecoveryGuide.ts +0 -676
- package/src/utils/Helpers.ts +0 -688
- package/src/utils/IPFSClient.ts +0 -368
- package/src/utils/Logger.ts +0 -484
- package/src/utils/NonceManager.ts +0 -591
- package/src/utils/RateLimiter.ts +0 -534
- package/src/utils/ReceivedNonceTracker.ts +0 -567
- package/src/utils/SDKLifecycle.ts +0 -416
- package/src/utils/SecureNonce.ts +0 -78
- package/src/utils/Semaphore.ts +0 -276
- package/src/utils/UsedAttestationTracker.ts +0 -385
- package/src/utils/canonicalJson.ts +0 -38
- package/src/utils/circuitBreaker.ts +0 -324
- package/src/utils/computeTypeHash.ts +0 -48
- package/src/utils/fsSafe.ts +0 -80
- package/src/utils/index.ts +0 -80
- package/src/utils/retry.ts +0 -364
- package/src/utils/security.ts +0 -418
- package/src/utils/validation.ts +0 -540
- package/src/wallet/AutoWalletProvider.ts +0 -299
- package/src/wallet/EOAWalletProvider.ts +0 -69
- package/src/wallet/IWalletProvider.ts +0 -135
- package/src/wallet/aa/BundlerClient.ts +0 -274
- package/src/wallet/aa/DualNonceManager.ts +0 -173
- package/src/wallet/aa/PaymasterClient.ts +0 -174
- package/src/wallet/aa/TransactionBatcher.ts +0 -353
- package/src/wallet/aa/UserOpBuilder.ts +0 -246
- package/src/wallet/aa/constants.ts +0 -60
- 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
|
-
}
|