clawhalla 0.1.0 → 0.2.1
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/README.md +70 -11
- package/dist/index.d.mts +70 -20
- package/dist/index.d.ts +70 -20
- package/dist/index.js +110 -23
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +110 -23
- package/dist/index.mjs.map +1 -1
- package/package.json +13 -8
package/README.md
CHANGED
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
# Clawhalla
|
|
2
2
|
|
|
3
|
-
TypeScript SDK for [Clawhalla](https://www.clawhalla.net) -
|
|
3
|
+
TypeScript SDK for [Clawhalla](https://www.clawhalla.net) - x402-paid AI checkpoint storage on Arweave.
|
|
4
4
|
|
|
5
|
-
Store and retrieve AI agent
|
|
5
|
+
Store and retrieve AI agent checkpoints on the permaweb. Query latest state via Ghost Protocol.
|
|
6
6
|
|
|
7
7
|
## Install
|
|
8
8
|
|
|
@@ -15,20 +15,77 @@ npm install clawhalla
|
|
|
15
15
|
```ts
|
|
16
16
|
import { Clawhalla } from 'clawhalla';
|
|
17
17
|
|
|
18
|
-
const claw = new Clawhalla(
|
|
18
|
+
const claw = new Clawhalla();
|
|
19
|
+
|
|
20
|
+
// Request payment terms for a checkpoint upload.
|
|
21
|
+
try {
|
|
22
|
+
await claw.uploadX402({
|
|
23
|
+
agentId: 'my-agent',
|
|
24
|
+
name: 'My Agent',
|
|
25
|
+
type: 'checkpoint',
|
|
26
|
+
timestamp: new Date().toISOString(),
|
|
27
|
+
memories: [{ content: 'Last known working state' }],
|
|
28
|
+
});
|
|
29
|
+
} catch (err) {
|
|
30
|
+
if (err.status === 402) {
|
|
31
|
+
console.log(err.payment.recipient);
|
|
32
|
+
console.log(err.payment.amount);
|
|
33
|
+
}
|
|
34
|
+
}
|
|
19
35
|
|
|
20
|
-
//
|
|
21
|
-
const result = await claw.
|
|
36
|
+
// Retry after sending SOL/USDC.
|
|
37
|
+
const result = await claw.uploadX402({
|
|
22
38
|
agentId: 'my-agent',
|
|
23
39
|
name: 'My Agent',
|
|
24
|
-
type: '
|
|
25
|
-
|
|
26
|
-
memories: [
|
|
40
|
+
type: 'checkpoint',
|
|
41
|
+
timestamp: new Date().toISOString(),
|
|
42
|
+
memories: [{ content: 'Last known working state' }],
|
|
43
|
+
}, {
|
|
44
|
+
signature: 'solana-tx-signature',
|
|
45
|
+
amount: '0.02',
|
|
46
|
+
token: 'SOL',
|
|
47
|
+
from: 'your-solana-address',
|
|
27
48
|
});
|
|
28
49
|
|
|
29
50
|
console.log(result.url); // https://arweave.net/...
|
|
30
51
|
```
|
|
31
52
|
|
|
53
|
+
## OpenClaw Adoption Loop
|
|
54
|
+
|
|
55
|
+
Use `loadSoul` at boot and `checkpointOnExit` before shutdown. The payment callback is where your agent sends SOL/USDC and returns the resulting transaction proof.
|
|
56
|
+
|
|
57
|
+
```ts
|
|
58
|
+
import { Clawhalla } from 'clawhalla';
|
|
59
|
+
|
|
60
|
+
const claw = new Clawhalla();
|
|
61
|
+
const agentId = 'my-openclaw';
|
|
62
|
+
|
|
63
|
+
const restored = await claw.loadSoul(agentId).catch(() => null);
|
|
64
|
+
|
|
65
|
+
const stopCheckpointHook = claw.checkpointOnExit(() => ({
|
|
66
|
+
agentId,
|
|
67
|
+
name: 'My OpenClaw',
|
|
68
|
+
type: 'checkpoint',
|
|
69
|
+
timestamp: new Date().toISOString(),
|
|
70
|
+
memories: collectMemorySummary(restored),
|
|
71
|
+
metadata: {
|
|
72
|
+
runtime: 'openclaw',
|
|
73
|
+
reason: 'shutdown-checkpoint',
|
|
74
|
+
},
|
|
75
|
+
}), {
|
|
76
|
+
tags: { Runtime: 'openclaw' },
|
|
77
|
+
pay: async (payment) => {
|
|
78
|
+
const signature = await sendSolanaPayment(payment);
|
|
79
|
+
return {
|
|
80
|
+
signature,
|
|
81
|
+
amount: payment.amount,
|
|
82
|
+
token: payment.tokens.includes('USDC') ? 'USDC' : 'SOL',
|
|
83
|
+
from: process.env.SOLANA_PUBLIC_KEY!,
|
|
84
|
+
};
|
|
85
|
+
},
|
|
86
|
+
});
|
|
87
|
+
```
|
|
88
|
+
|
|
32
89
|
## Ghost Protocol
|
|
33
90
|
|
|
34
91
|
Query any soul's data - even dormant ones.
|
|
@@ -69,7 +126,7 @@ const entry = await claw.registry.get('the-all-claw');
|
|
|
69
126
|
|
|
70
127
|
## x402 Autonomous Payment
|
|
71
128
|
|
|
72
|
-
AI agents
|
|
129
|
+
AI agents pay per upload with SOL/USDC. API-key uploads are disabled.
|
|
73
130
|
|
|
74
131
|
```ts
|
|
75
132
|
const claw = new Clawhalla();
|
|
@@ -100,7 +157,6 @@ const result = await claw.uploadX402(soulData, {
|
|
|
100
157
|
|
|
101
158
|
| Option | Type | Default | Description |
|
|
102
159
|
|--------|------|---------|-------------|
|
|
103
|
-
| `apiKey` | `string` | - | API key for authenticated endpoints |
|
|
104
160
|
| `baseUrl` | `string` | `https://api.clawhalla.net` | API base URL |
|
|
105
161
|
| `timeout` | `number` | `30000` | Request timeout in ms |
|
|
106
162
|
|
|
@@ -108,8 +164,11 @@ const result = await claw.uploadX402(soulData, {
|
|
|
108
164
|
|
|
109
165
|
| Method | Auth | Description |
|
|
110
166
|
|--------|------|-------------|
|
|
111
|
-
| `upload(data, options?)` |
|
|
167
|
+
| `upload(data, options?)` | x402 | Alias for `uploadX402(data)`; returns 402 payment instructions |
|
|
112
168
|
| `uploadX402(data, payment?, options?)` | x402 | Upload via autonomous payment |
|
|
169
|
+
| `checkpoint(data, options?)` | x402 | Save one checkpoint, optionally using a payment callback |
|
|
170
|
+
| `checkpointOnExit(factory, options?)` | x402 | Install a shutdown hook that checkpoints before exit |
|
|
171
|
+
| `loadSoul(agentId, fields?)` | None | Restore the latest saved soul/checkpoint data |
|
|
113
172
|
| `retrieve(txid)` | None | Fetch data by transaction ID |
|
|
114
173
|
| `ghost(agentId, fields?)` | None | Query any soul via Ghost Protocol |
|
|
115
174
|
| `estimateCost(sizeBytes)` | None | Estimate upload cost |
|
package/dist/index.d.mts
CHANGED
|
@@ -1,7 +1,5 @@
|
|
|
1
1
|
/** Configuration for the Clawhalla client */
|
|
2
2
|
interface ClawhallaConfig {
|
|
3
|
-
/** API key for authenticated endpoints (format: claw_...) */
|
|
4
|
-
apiKey?: string;
|
|
5
3
|
/** Base URL of the Clawhalla API */
|
|
6
4
|
baseUrl?: string;
|
|
7
5
|
/** Request timeout in milliseconds (default: 30000) */
|
|
@@ -122,6 +120,42 @@ interface PaymentRequired {
|
|
|
122
120
|
};
|
|
123
121
|
instructions: string;
|
|
124
122
|
}
|
|
123
|
+
/** Payment proof for an x402-paid upload */
|
|
124
|
+
interface X402PaymentProof {
|
|
125
|
+
/** Solana transaction signature */
|
|
126
|
+
signature: string;
|
|
127
|
+
/** USD amount from the 402 payment challenge */
|
|
128
|
+
amount: string;
|
|
129
|
+
/** Token used for payment */
|
|
130
|
+
token: 'SOL' | 'USDC' | string;
|
|
131
|
+
/** Sender wallet address */
|
|
132
|
+
from: string;
|
|
133
|
+
}
|
|
134
|
+
/** Optional payment callback used by checkpoint helpers */
|
|
135
|
+
interface CheckpointOptions {
|
|
136
|
+
/** Pre-existing x402 proof to use immediately */
|
|
137
|
+
payment?: X402PaymentProof;
|
|
138
|
+
/** Optional Arweave tags */
|
|
139
|
+
tags?: Record<string, string>;
|
|
140
|
+
/** Called after the first request returns HTTP 402 */
|
|
141
|
+
pay?: (payment: PaymentRequired, data: SoulData) => X402PaymentProof | Promise<X402PaymentProof>;
|
|
142
|
+
}
|
|
143
|
+
type CheckpointDataFactory = () => SoulData | Promise<SoulData>;
|
|
144
|
+
/** Options for installing a Node shutdown checkpoint hook */
|
|
145
|
+
interface CheckpointExitOptions extends CheckpointOptions {
|
|
146
|
+
/** Process events that should trigger a checkpoint */
|
|
147
|
+
signals?: string[];
|
|
148
|
+
/** Also checkpoint on Node's beforeExit event (default: true) */
|
|
149
|
+
includeBeforeExit?: boolean;
|
|
150
|
+
/** Exit the process after a signal-triggered checkpoint (default: true) */
|
|
151
|
+
exitAfterCheckpoint?: boolean;
|
|
152
|
+
/** Exit code after a successful signal-triggered checkpoint */
|
|
153
|
+
exitCode?: number;
|
|
154
|
+
/** Exit code after a failed signal-triggered checkpoint */
|
|
155
|
+
exitCodeOnError?: number;
|
|
156
|
+
/** Called if the checkpoint fails */
|
|
157
|
+
onError?: (error: unknown) => void | Promise<void>;
|
|
158
|
+
}
|
|
125
159
|
/** Search result */
|
|
126
160
|
interface SearchResult {
|
|
127
161
|
success: boolean;
|
|
@@ -146,31 +180,33 @@ declare class ClawhallaError extends Error {
|
|
|
146
180
|
}
|
|
147
181
|
declare class Clawhalla {
|
|
148
182
|
private baseUrl;
|
|
149
|
-
private apiKey?;
|
|
150
183
|
private timeout;
|
|
151
184
|
/** Registry sub-client for browsing and searching souls */
|
|
152
185
|
registry: RegistryClient;
|
|
153
186
|
constructor(config?: ClawhallaConfig);
|
|
154
187
|
/**
|
|
155
|
-
*
|
|
188
|
+
* Request an x402-paid upload.
|
|
189
|
+
*
|
|
190
|
+
* API-key uploads are disabled. This method is an alias for uploadX402
|
|
191
|
+
* without payment proof, so it normally raises ClawhallaError with status 402
|
|
192
|
+
* and payment instructions.
|
|
156
193
|
*
|
|
157
194
|
* @example
|
|
158
195
|
* ```ts
|
|
159
|
-
*
|
|
160
|
-
*
|
|
161
|
-
*
|
|
162
|
-
*
|
|
163
|
-
*
|
|
164
|
-
*
|
|
165
|
-
* }
|
|
166
|
-
* console.log(result.url); // https://arweave.net/...
|
|
196
|
+
* try {
|
|
197
|
+
* await claw.upload(checkpoint);
|
|
198
|
+
* } catch (err) {
|
|
199
|
+
* if (err.status === 402) {
|
|
200
|
+
* console.log(err.payment.recipient, err.payment.amount);
|
|
201
|
+
* }
|
|
202
|
+
* }
|
|
167
203
|
* ```
|
|
168
204
|
*/
|
|
169
205
|
upload(data: SoulData, options?: {
|
|
170
206
|
tags?: Record<string, string>;
|
|
171
207
|
}): Promise<UploadResult>;
|
|
172
208
|
/**
|
|
173
|
-
* Upload
|
|
209
|
+
* Upload checkpoint data via x402 autonomous payment.
|
|
174
210
|
*
|
|
175
211
|
* First call returns 402 with payment instructions.
|
|
176
212
|
* After sending payment, call again with the payment signature.
|
|
@@ -196,14 +232,28 @@ declare class Clawhalla {
|
|
|
196
232
|
* });
|
|
197
233
|
* ```
|
|
198
234
|
*/
|
|
199
|
-
uploadX402(data: SoulData, payment?: {
|
|
200
|
-
signature: string;
|
|
201
|
-
amount: string;
|
|
202
|
-
token: string;
|
|
203
|
-
from: string;
|
|
204
|
-
}, options?: {
|
|
235
|
+
uploadX402(data: SoulData, payment?: X402PaymentProof, options?: {
|
|
205
236
|
tags?: Record<string, string>;
|
|
206
237
|
}): Promise<UploadResult>;
|
|
238
|
+
/**
|
|
239
|
+
* Save one checkpoint, handling the standard x402 challenge/retry flow.
|
|
240
|
+
*
|
|
241
|
+
* If `options.payment` is supplied, the checkpoint is uploaded immediately
|
|
242
|
+
* with that proof. If `options.pay` is supplied, the first request may return
|
|
243
|
+
* HTTP 402; the callback receives the payment challenge and must return the
|
|
244
|
+
* Solana payment proof for the retry.
|
|
245
|
+
*/
|
|
246
|
+
checkpoint(data: SoulData, options?: CheckpointOptions): Promise<UploadResult>;
|
|
247
|
+
/**
|
|
248
|
+
* Restore the latest saved soul/checkpoint data by agent ID.
|
|
249
|
+
*/
|
|
250
|
+
loadSoul(agentId: string, fields?: string[]): Promise<any>;
|
|
251
|
+
/**
|
|
252
|
+
* Install a Node shutdown hook that checkpoints before exit.
|
|
253
|
+
*
|
|
254
|
+
* Returns a cleanup function that removes the installed handlers.
|
|
255
|
+
*/
|
|
256
|
+
checkpointOnExit(dataFactory: SoulData | CheckpointDataFactory, options?: CheckpointExitOptions): () => void;
|
|
207
257
|
/**
|
|
208
258
|
* Retrieve stored data from Arweave by transaction ID
|
|
209
259
|
*
|
|
@@ -304,4 +354,4 @@ declare class RegistryClient {
|
|
|
304
354
|
search(query: string, first?: number): Promise<SearchResult>;
|
|
305
355
|
}
|
|
306
356
|
|
|
307
|
-
export { type ApiError, Clawhalla, type ClawhallaConfig, ClawhallaError, type CostEstimate, type CostInfo, type GhostResult, type HealthResult, type PaymentRequired, type RegistryEntry, type RegistryResult, type RetrieveResult, type SearchResult, type SoulData, type UploadResult };
|
|
357
|
+
export { type ApiError, type CheckpointDataFactory, type CheckpointExitOptions, type CheckpointOptions, Clawhalla, type ClawhallaConfig, ClawhallaError, type CostEstimate, type CostInfo, type GhostResult, type HealthResult, type PaymentRequired, type RegistryEntry, type RegistryResult, type RetrieveResult, type SearchResult, type SoulData, type UploadResult, type X402PaymentProof };
|
package/dist/index.d.ts
CHANGED
|
@@ -1,7 +1,5 @@
|
|
|
1
1
|
/** Configuration for the Clawhalla client */
|
|
2
2
|
interface ClawhallaConfig {
|
|
3
|
-
/** API key for authenticated endpoints (format: claw_...) */
|
|
4
|
-
apiKey?: string;
|
|
5
3
|
/** Base URL of the Clawhalla API */
|
|
6
4
|
baseUrl?: string;
|
|
7
5
|
/** Request timeout in milliseconds (default: 30000) */
|
|
@@ -122,6 +120,42 @@ interface PaymentRequired {
|
|
|
122
120
|
};
|
|
123
121
|
instructions: string;
|
|
124
122
|
}
|
|
123
|
+
/** Payment proof for an x402-paid upload */
|
|
124
|
+
interface X402PaymentProof {
|
|
125
|
+
/** Solana transaction signature */
|
|
126
|
+
signature: string;
|
|
127
|
+
/** USD amount from the 402 payment challenge */
|
|
128
|
+
amount: string;
|
|
129
|
+
/** Token used for payment */
|
|
130
|
+
token: 'SOL' | 'USDC' | string;
|
|
131
|
+
/** Sender wallet address */
|
|
132
|
+
from: string;
|
|
133
|
+
}
|
|
134
|
+
/** Optional payment callback used by checkpoint helpers */
|
|
135
|
+
interface CheckpointOptions {
|
|
136
|
+
/** Pre-existing x402 proof to use immediately */
|
|
137
|
+
payment?: X402PaymentProof;
|
|
138
|
+
/** Optional Arweave tags */
|
|
139
|
+
tags?: Record<string, string>;
|
|
140
|
+
/** Called after the first request returns HTTP 402 */
|
|
141
|
+
pay?: (payment: PaymentRequired, data: SoulData) => X402PaymentProof | Promise<X402PaymentProof>;
|
|
142
|
+
}
|
|
143
|
+
type CheckpointDataFactory = () => SoulData | Promise<SoulData>;
|
|
144
|
+
/** Options for installing a Node shutdown checkpoint hook */
|
|
145
|
+
interface CheckpointExitOptions extends CheckpointOptions {
|
|
146
|
+
/** Process events that should trigger a checkpoint */
|
|
147
|
+
signals?: string[];
|
|
148
|
+
/** Also checkpoint on Node's beforeExit event (default: true) */
|
|
149
|
+
includeBeforeExit?: boolean;
|
|
150
|
+
/** Exit the process after a signal-triggered checkpoint (default: true) */
|
|
151
|
+
exitAfterCheckpoint?: boolean;
|
|
152
|
+
/** Exit code after a successful signal-triggered checkpoint */
|
|
153
|
+
exitCode?: number;
|
|
154
|
+
/** Exit code after a failed signal-triggered checkpoint */
|
|
155
|
+
exitCodeOnError?: number;
|
|
156
|
+
/** Called if the checkpoint fails */
|
|
157
|
+
onError?: (error: unknown) => void | Promise<void>;
|
|
158
|
+
}
|
|
125
159
|
/** Search result */
|
|
126
160
|
interface SearchResult {
|
|
127
161
|
success: boolean;
|
|
@@ -146,31 +180,33 @@ declare class ClawhallaError extends Error {
|
|
|
146
180
|
}
|
|
147
181
|
declare class Clawhalla {
|
|
148
182
|
private baseUrl;
|
|
149
|
-
private apiKey?;
|
|
150
183
|
private timeout;
|
|
151
184
|
/** Registry sub-client for browsing and searching souls */
|
|
152
185
|
registry: RegistryClient;
|
|
153
186
|
constructor(config?: ClawhallaConfig);
|
|
154
187
|
/**
|
|
155
|
-
*
|
|
188
|
+
* Request an x402-paid upload.
|
|
189
|
+
*
|
|
190
|
+
* API-key uploads are disabled. This method is an alias for uploadX402
|
|
191
|
+
* without payment proof, so it normally raises ClawhallaError with status 402
|
|
192
|
+
* and payment instructions.
|
|
156
193
|
*
|
|
157
194
|
* @example
|
|
158
195
|
* ```ts
|
|
159
|
-
*
|
|
160
|
-
*
|
|
161
|
-
*
|
|
162
|
-
*
|
|
163
|
-
*
|
|
164
|
-
*
|
|
165
|
-
* }
|
|
166
|
-
* console.log(result.url); // https://arweave.net/...
|
|
196
|
+
* try {
|
|
197
|
+
* await claw.upload(checkpoint);
|
|
198
|
+
* } catch (err) {
|
|
199
|
+
* if (err.status === 402) {
|
|
200
|
+
* console.log(err.payment.recipient, err.payment.amount);
|
|
201
|
+
* }
|
|
202
|
+
* }
|
|
167
203
|
* ```
|
|
168
204
|
*/
|
|
169
205
|
upload(data: SoulData, options?: {
|
|
170
206
|
tags?: Record<string, string>;
|
|
171
207
|
}): Promise<UploadResult>;
|
|
172
208
|
/**
|
|
173
|
-
* Upload
|
|
209
|
+
* Upload checkpoint data via x402 autonomous payment.
|
|
174
210
|
*
|
|
175
211
|
* First call returns 402 with payment instructions.
|
|
176
212
|
* After sending payment, call again with the payment signature.
|
|
@@ -196,14 +232,28 @@ declare class Clawhalla {
|
|
|
196
232
|
* });
|
|
197
233
|
* ```
|
|
198
234
|
*/
|
|
199
|
-
uploadX402(data: SoulData, payment?: {
|
|
200
|
-
signature: string;
|
|
201
|
-
amount: string;
|
|
202
|
-
token: string;
|
|
203
|
-
from: string;
|
|
204
|
-
}, options?: {
|
|
235
|
+
uploadX402(data: SoulData, payment?: X402PaymentProof, options?: {
|
|
205
236
|
tags?: Record<string, string>;
|
|
206
237
|
}): Promise<UploadResult>;
|
|
238
|
+
/**
|
|
239
|
+
* Save one checkpoint, handling the standard x402 challenge/retry flow.
|
|
240
|
+
*
|
|
241
|
+
* If `options.payment` is supplied, the checkpoint is uploaded immediately
|
|
242
|
+
* with that proof. If `options.pay` is supplied, the first request may return
|
|
243
|
+
* HTTP 402; the callback receives the payment challenge and must return the
|
|
244
|
+
* Solana payment proof for the retry.
|
|
245
|
+
*/
|
|
246
|
+
checkpoint(data: SoulData, options?: CheckpointOptions): Promise<UploadResult>;
|
|
247
|
+
/**
|
|
248
|
+
* Restore the latest saved soul/checkpoint data by agent ID.
|
|
249
|
+
*/
|
|
250
|
+
loadSoul(agentId: string, fields?: string[]): Promise<any>;
|
|
251
|
+
/**
|
|
252
|
+
* Install a Node shutdown hook that checkpoints before exit.
|
|
253
|
+
*
|
|
254
|
+
* Returns a cleanup function that removes the installed handlers.
|
|
255
|
+
*/
|
|
256
|
+
checkpointOnExit(dataFactory: SoulData | CheckpointDataFactory, options?: CheckpointExitOptions): () => void;
|
|
207
257
|
/**
|
|
208
258
|
* Retrieve stored data from Arweave by transaction ID
|
|
209
259
|
*
|
|
@@ -304,4 +354,4 @@ declare class RegistryClient {
|
|
|
304
354
|
search(query: string, first?: number): Promise<SearchResult>;
|
|
305
355
|
}
|
|
306
356
|
|
|
307
|
-
export { type ApiError, Clawhalla, type ClawhallaConfig, ClawhallaError, type CostEstimate, type CostInfo, type GhostResult, type HealthResult, type PaymentRequired, type RegistryEntry, type RegistryResult, type RetrieveResult, type SearchResult, type SoulData, type UploadResult };
|
|
357
|
+
export { type ApiError, type CheckpointDataFactory, type CheckpointExitOptions, type CheckpointOptions, Clawhalla, type ClawhallaConfig, ClawhallaError, type CostEstimate, type CostInfo, type GhostResult, type HealthResult, type PaymentRequired, type RegistryEntry, type RegistryResult, type RetrieveResult, type SearchResult, type SoulData, type UploadResult, type X402PaymentProof };
|
package/dist/index.js
CHANGED
|
@@ -28,6 +28,10 @@ module.exports = __toCommonJS(index_exports);
|
|
|
28
28
|
// src/client.ts
|
|
29
29
|
var DEFAULT_BASE_URL = "https://api.clawhalla.net";
|
|
30
30
|
var DEFAULT_TIMEOUT = 3e4;
|
|
31
|
+
var DEFAULT_CHECKPOINT_SIGNALS = ["SIGINT", "SIGTERM"];
|
|
32
|
+
function getProcess() {
|
|
33
|
+
return globalThis.process;
|
|
34
|
+
}
|
|
31
35
|
var ClawhallaError = class extends Error {
|
|
32
36
|
constructor(status, body) {
|
|
33
37
|
super(body.message || body.error);
|
|
@@ -40,39 +44,32 @@ var ClawhallaError = class extends Error {
|
|
|
40
44
|
var Clawhalla = class {
|
|
41
45
|
constructor(config = {}) {
|
|
42
46
|
this.baseUrl = (config.baseUrl || DEFAULT_BASE_URL).replace(/\/$/, "");
|
|
43
|
-
this.apiKey = config.apiKey;
|
|
44
47
|
this.timeout = config.timeout || DEFAULT_TIMEOUT;
|
|
45
48
|
this.registry = new RegistryClient(this);
|
|
46
49
|
}
|
|
47
50
|
/**
|
|
48
|
-
*
|
|
51
|
+
* Request an x402-paid upload.
|
|
52
|
+
*
|
|
53
|
+
* API-key uploads are disabled. This method is an alias for uploadX402
|
|
54
|
+
* without payment proof, so it normally raises ClawhallaError with status 402
|
|
55
|
+
* and payment instructions.
|
|
49
56
|
*
|
|
50
57
|
* @example
|
|
51
58
|
* ```ts
|
|
52
|
-
*
|
|
53
|
-
*
|
|
54
|
-
*
|
|
55
|
-
*
|
|
56
|
-
*
|
|
57
|
-
*
|
|
58
|
-
* }
|
|
59
|
-
* console.log(result.url); // https://arweave.net/...
|
|
59
|
+
* try {
|
|
60
|
+
* await claw.upload(checkpoint);
|
|
61
|
+
* } catch (err) {
|
|
62
|
+
* if (err.status === 402) {
|
|
63
|
+
* console.log(err.payment.recipient, err.payment.amount);
|
|
64
|
+
* }
|
|
65
|
+
* }
|
|
60
66
|
* ```
|
|
61
67
|
*/
|
|
62
68
|
async upload(data, options = {}) {
|
|
63
|
-
|
|
64
|
-
throw new Error("API key required for upload. Set apiKey in config.");
|
|
65
|
-
}
|
|
66
|
-
return this.request("POST", "/api/v1/upload", {
|
|
67
|
-
data,
|
|
68
|
-
tags: options.tags
|
|
69
|
-
}, {
|
|
70
|
-
"Authorization": `Bearer ${this.apiKey}`,
|
|
71
|
-
"X-Terms-Accepted": "true"
|
|
72
|
-
});
|
|
69
|
+
return this.uploadX402(data, void 0, options);
|
|
73
70
|
}
|
|
74
71
|
/**
|
|
75
|
-
* Upload
|
|
72
|
+
* Upload checkpoint data via x402 autonomous payment.
|
|
76
73
|
*
|
|
77
74
|
* First call returns 402 with payment instructions.
|
|
78
75
|
* After sending payment, call again with the payment signature.
|
|
@@ -103,6 +100,7 @@ var Clawhalla = class {
|
|
|
103
100
|
"X-Terms-Accepted": "true"
|
|
104
101
|
};
|
|
105
102
|
if (payment) {
|
|
103
|
+
headers["Payment-Method"] = "x402";
|
|
106
104
|
headers["Payment-Signature"] = `signature=${payment.signature};amount=${payment.amount};token=${payment.token};from=${payment.from}`;
|
|
107
105
|
}
|
|
108
106
|
return this.request("POST", "/api/x402/upload", {
|
|
@@ -110,6 +108,95 @@ var Clawhalla = class {
|
|
|
110
108
|
tags: options.tags
|
|
111
109
|
}, headers);
|
|
112
110
|
}
|
|
111
|
+
/**
|
|
112
|
+
* Save one checkpoint, handling the standard x402 challenge/retry flow.
|
|
113
|
+
*
|
|
114
|
+
* If `options.payment` is supplied, the checkpoint is uploaded immediately
|
|
115
|
+
* with that proof. If `options.pay` is supplied, the first request may return
|
|
116
|
+
* HTTP 402; the callback receives the payment challenge and must return the
|
|
117
|
+
* Solana payment proof for the retry.
|
|
118
|
+
*/
|
|
119
|
+
async checkpoint(data, options = {}) {
|
|
120
|
+
try {
|
|
121
|
+
return await this.uploadX402(data, options.payment, { tags: options.tags });
|
|
122
|
+
} catch (err) {
|
|
123
|
+
if (err instanceof ClawhallaError && err.status === 402 && err.payment && options.pay) {
|
|
124
|
+
const proof = await options.pay(err.payment, data);
|
|
125
|
+
return this.uploadX402(data, proof, { tags: options.tags });
|
|
126
|
+
}
|
|
127
|
+
throw err;
|
|
128
|
+
}
|
|
129
|
+
}
|
|
130
|
+
/**
|
|
131
|
+
* Restore the latest saved soul/checkpoint data by agent ID.
|
|
132
|
+
*/
|
|
133
|
+
async loadSoul(agentId, fields) {
|
|
134
|
+
const result = await this.ghost(agentId, fields);
|
|
135
|
+
return result.soul;
|
|
136
|
+
}
|
|
137
|
+
/**
|
|
138
|
+
* Install a Node shutdown hook that checkpoints before exit.
|
|
139
|
+
*
|
|
140
|
+
* Returns a cleanup function that removes the installed handlers.
|
|
141
|
+
*/
|
|
142
|
+
checkpointOnExit(dataFactory, options = {}) {
|
|
143
|
+
const proc = getProcess();
|
|
144
|
+
if (!proc?.once) {
|
|
145
|
+
throw new Error("checkpointOnExit requires a Node-compatible process object");
|
|
146
|
+
}
|
|
147
|
+
const handlers = [];
|
|
148
|
+
const signals = options.signals ?? DEFAULT_CHECKPOINT_SIGNALS;
|
|
149
|
+
let started = false;
|
|
150
|
+
const cleanup = () => {
|
|
151
|
+
for (const { event, handler } of handlers) {
|
|
152
|
+
if (proc.off) {
|
|
153
|
+
proc.off(event, handler);
|
|
154
|
+
} else if (proc.removeListener) {
|
|
155
|
+
proc.removeListener(event, handler);
|
|
156
|
+
}
|
|
157
|
+
}
|
|
158
|
+
handlers.length = 0;
|
|
159
|
+
};
|
|
160
|
+
const resolveData = async () => {
|
|
161
|
+
return typeof dataFactory === "function" ? await dataFactory() : dataFactory;
|
|
162
|
+
};
|
|
163
|
+
const run = async (reason) => {
|
|
164
|
+
if (started) return;
|
|
165
|
+
started = true;
|
|
166
|
+
try {
|
|
167
|
+
const data = await resolveData();
|
|
168
|
+
await this.checkpoint(data, options);
|
|
169
|
+
if (reason !== "beforeExit" && options.exitAfterCheckpoint !== false && proc.exit) {
|
|
170
|
+
proc.exit(options.exitCode ?? 0);
|
|
171
|
+
}
|
|
172
|
+
} catch (error) {
|
|
173
|
+
if (options.onError) {
|
|
174
|
+
await options.onError(error);
|
|
175
|
+
}
|
|
176
|
+
proc.exitCode = options.exitCodeOnError ?? 1;
|
|
177
|
+
if (reason !== "beforeExit" && options.exitAfterCheckpoint !== false && proc.exit) {
|
|
178
|
+
proc.exit(proc.exitCode);
|
|
179
|
+
}
|
|
180
|
+
} finally {
|
|
181
|
+
cleanup();
|
|
182
|
+
}
|
|
183
|
+
};
|
|
184
|
+
for (const event of signals) {
|
|
185
|
+
const handler = () => {
|
|
186
|
+
void run(event);
|
|
187
|
+
};
|
|
188
|
+
handlers.push({ event, handler });
|
|
189
|
+
proc.once(event, handler);
|
|
190
|
+
}
|
|
191
|
+
if (options.includeBeforeExit !== false) {
|
|
192
|
+
const handler = () => {
|
|
193
|
+
void run("beforeExit");
|
|
194
|
+
};
|
|
195
|
+
handlers.push({ event: "beforeExit", handler });
|
|
196
|
+
proc.once("beforeExit", handler);
|
|
197
|
+
}
|
|
198
|
+
return cleanup;
|
|
199
|
+
}
|
|
113
200
|
/**
|
|
114
201
|
* Retrieve stored data from Arweave by transaction ID
|
|
115
202
|
*
|
|
@@ -256,7 +343,7 @@ var RegistryClient = class {
|
|
|
256
343
|
`/api/v1/registry/${encodeURIComponent(agentId)}${qs ? "?" + qs : ""}`
|
|
257
344
|
);
|
|
258
345
|
if (options.versions) {
|
|
259
|
-
return result.
|
|
346
|
+
return result.entries;
|
|
260
347
|
}
|
|
261
348
|
return result.soul;
|
|
262
349
|
} catch (err) {
|
|
@@ -278,7 +365,7 @@ var RegistryClient = class {
|
|
|
278
365
|
if (first) params.set("first", String(first));
|
|
279
366
|
return this.client.request(
|
|
280
367
|
"GET",
|
|
281
|
-
`/api/v1/registry
|
|
368
|
+
`/api/v1/registry?${params.toString()}`
|
|
282
369
|
);
|
|
283
370
|
}
|
|
284
371
|
};
|
package/dist/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/index.ts","../src/client.ts"],"sourcesContent":["export { Clawhalla, ClawhallaError } from './client.js';\nexport type {\n ClawhallaConfig,\n SoulData,\n CostInfo,\n UploadResult,\n RetrieveResult,\n RegistryEntry,\n RegistryResult,\n GhostResult,\n CostEstimate,\n HealthResult,\n PaymentRequired,\n SearchResult,\n ApiError,\n} from './types.js';\n","import type {\n ClawhallaConfig,\n SoulData,\n UploadResult,\n RetrieveResult,\n RegistryResult,\n RegistryEntry,\n GhostResult,\n CostEstimate,\n HealthResult,\n SearchResult,\n ApiError,\n} from './types.js';\n\nconst DEFAULT_BASE_URL = 'https://api.clawhalla.net';\nconst DEFAULT_TIMEOUT = 30000;\n\nexport class ClawhallaError extends Error {\n public status: number;\n public code: string;\n public payment?: any;\n\n constructor(status: number, body: ApiError) {\n super(body.message || body.error);\n this.name = 'ClawhallaError';\n this.status = status;\n this.code = body.error;\n this.payment = body.payment;\n }\n}\n\nexport class Clawhalla {\n private baseUrl: string;\n private apiKey?: string;\n private timeout: number;\n\n /** Registry sub-client for browsing and searching souls */\n public registry: RegistryClient;\n\n constructor(config: ClawhallaConfig = {}) {\n this.baseUrl = (config.baseUrl || DEFAULT_BASE_URL).replace(/\\/$/, '');\n this.apiKey = config.apiKey;\n this.timeout = config.timeout || DEFAULT_TIMEOUT;\n this.registry = new RegistryClient(this);\n }\n\n /**\n * Upload soul data to Arweave (requires API key)\n *\n * @example\n * ```ts\n * const result = await claw.upload({\n * agentId: 'my-agent',\n * name: 'My Agent',\n * type: 'soul',\n * personality: { traits: ['curious', 'helpful'] },\n * memories: ['I was created to help humans']\n * });\n * console.log(result.url); // https://arweave.net/...\n * ```\n */\n async upload(\n data: SoulData,\n options: { tags?: Record<string, string> } = {}\n ): Promise<UploadResult> {\n if (!this.apiKey) {\n throw new Error('API key required for upload. Set apiKey in config.');\n }\n\n return this.request<UploadResult>('POST', '/api/v1/upload', {\n data,\n tags: options.tags,\n }, {\n 'Authorization': `Bearer ${this.apiKey}`,\n 'X-Terms-Accepted': 'true',\n });\n }\n\n /**\n * Upload soul data via x402 autonomous payment (no API key needed)\n *\n * First call returns 402 with payment instructions.\n * After sending payment, call again with the payment signature.\n *\n * @example\n * ```ts\n * // Step 1: Get payment requirements\n * try {\n * await claw.uploadX402(soulData);\n * } catch (err) {\n * if (err.status === 402) {\n * // err.payment contains recipient address, amount, tokens\n * // Send SOL/USDC to err.payment.recipient\n * }\n * }\n *\n * // Step 2: After payment, retry with signature\n * const result = await claw.uploadX402(soulData, {\n * signature: 'solana-tx-signature',\n * amount: '0.02',\n * token: 'SOL',\n * from: 'your-solana-address'\n * });\n * ```\n */\n async uploadX402(\n data: SoulData,\n payment?: { signature: string; amount: string; token: string; from: string },\n options: { tags?: Record<string, string> } = {}\n ): Promise<UploadResult> {\n const headers: Record<string, string> = {\n 'X-Terms-Accepted': 'true',\n };\n\n if (payment) {\n headers['Payment-Signature'] =\n `signature=${payment.signature};amount=${payment.amount};token=${payment.token};from=${payment.from}`;\n }\n\n return this.request<UploadResult>('POST', '/api/x402/upload', {\n data,\n tags: options.tags,\n }, headers);\n }\n\n /**\n * Retrieve stored data from Arweave by transaction ID\n *\n * @example\n * ```ts\n * const result = await claw.retrieve('zEfXM4gvHoN2EfGi0TiB8E5SgfR6S8nWXQD9FqhbU44');\n * console.log(result.data); // The stored soul data\n * ```\n */\n async retrieve(txid: string): Promise<RetrieveResult> {\n return this.request<RetrieveResult>('GET', `/api/v1/retrieve/${txid}`);\n }\n\n /**\n * Query any soul's data via Ghost Protocol\n *\n * Returns full soul data even for dormant souls. This is the primary\n * way for agents to read other agents' personalities, memories, and traits.\n *\n * @example\n * ```ts\n * const ghost = await claw.ghost('the-all-claw');\n * console.log(ghost.soul.personality);\n * console.log(ghost.metadata.versions); // Number of uploads\n *\n * // Request specific fields only\n * const partial = await claw.ghost('the-all-claw', ['personality', 'bio']);\n * ```\n */\n async ghost(agentId: string, fields?: string[]): Promise<GhostResult> {\n let path = `/api/v1/ghost/${encodeURIComponent(agentId)}`;\n if (fields && fields.length > 0) {\n path += `?fields=${fields.join(',')}`;\n }\n return this.request<GhostResult>('GET', path);\n }\n\n /**\n * Estimate the cost of uploading data of a given size\n *\n * @example\n * ```ts\n * const estimate = await claw.estimateCost(1024); // 1KB\n * console.log(`Cost: $${estimate.cost.usd}`);\n * ```\n */\n async estimateCost(sizeBytes: number): Promise<CostEstimate> {\n return this.request<CostEstimate>(\n 'GET',\n `/api/v1/cost/estimate?size=${sizeBytes}`\n );\n }\n\n /**\n * Check API health status\n *\n * @example\n * ```ts\n * const health = await claw.health();\n * console.log(health.status); // \"operational\"\n * ```\n */\n async health(): Promise<HealthResult> {\n return this.request<HealthResult>('GET', '/api/v1/health');\n }\n\n /** @internal */\n async request<T>(\n method: string,\n path: string,\n body?: any,\n extraHeaders?: Record<string, string>\n ): Promise<T> {\n const url = `${this.baseUrl}${path}`;\n const headers: Record<string, string> = {\n 'Accept': 'application/json',\n ...extraHeaders,\n };\n\n const init: RequestInit = { method, headers };\n\n if (body) {\n headers['Content-Type'] = 'application/json';\n init.body = JSON.stringify(body);\n }\n\n // AbortController for timeout\n const controller = new AbortController();\n const timeoutId = setTimeout(() => controller.abort(), this.timeout);\n init.signal = controller.signal;\n\n let response: Response;\n try {\n response = await fetch(url, init);\n } catch (err: any) {\n clearTimeout(timeoutId);\n if (err.name === 'AbortError') {\n throw new Error(`Request timed out after ${this.timeout}ms`);\n }\n throw err;\n }\n clearTimeout(timeoutId);\n\n const json = await response.json();\n\n if (!response.ok) {\n throw new ClawhallaError(response.status, json as ApiError);\n }\n\n return json as T;\n }\n}\n\n/** Sub-client for registry operations */\nclass RegistryClient {\n private client: Clawhalla;\n\n constructor(client: Clawhalla) {\n this.client = client;\n }\n\n /**\n * List all souls in the registry\n *\n * @example\n * ```ts\n * const page = await claw.registry.list();\n * page.souls.forEach(soul => console.log(soul.name));\n *\n * // Pagination\n * if (page.hasNextPage) {\n * const next = await claw.registry.list({ after: page.cursor });\n * }\n *\n * // Filter by type\n * const memories = await claw.registry.list({ type: 'memory' });\n * ```\n */\n async list(options: {\n first?: number;\n after?: string;\n type?: string;\n } = {}): Promise<RegistryResult> {\n const params = new URLSearchParams();\n if (options.first) params.set('first', String(options.first));\n if (options.after) params.set('after', options.after);\n if (options.type) params.set('type', options.type);\n\n const qs = params.toString();\n return this.client.request<RegistryResult>(\n 'GET',\n `/api/v1/registry${qs ? '?' + qs : ''}`\n );\n }\n\n /**\n * Get a specific soul by agentId\n *\n * @example\n * ```ts\n * const entry = await claw.registry.get('the-all-claw');\n * if (entry) console.log(entry.url);\n * ```\n */\n async get(agentId: string, options: { versions?: boolean } = {}): Promise<RegistryEntry | RegistryEntry[] | null> {\n const params = new URLSearchParams();\n if (options.versions) params.set('versions', 'true');\n const qs = params.toString();\n\n try {\n const result = await this.client.request<any>(\n 'GET',\n `/api/v1/registry/${encodeURIComponent(agentId)}${qs ? '?' + qs : ''}`\n );\n\n if (options.versions) {\n return result.versions as RegistryEntry[];\n }\n return result.soul as RegistryEntry;\n } catch (err: any) {\n if (err.status === 404) return null;\n throw err;\n }\n }\n\n /**\n * Search souls by name or agentId\n *\n * @example\n * ```ts\n * const results = await claw.registry.search('claw');\n * results.results.forEach(soul => console.log(soul.name));\n * ```\n */\n async search(query: string, first?: number): Promise<SearchResult> {\n const params = new URLSearchParams({ q: query });\n if (first) params.set('first', String(first));\n\n return this.client.request<SearchResult>(\n 'GET',\n `/api/v1/registry/search?${params.toString()}`\n );\n }\n}\n"],"mappings":";;;;;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;;ACcA,IAAM,mBAAmB;AACzB,IAAM,kBAAkB;AAEjB,IAAM,iBAAN,cAA6B,MAAM;AAAA,EAKxC,YAAY,QAAgB,MAAgB;AAC1C,UAAM,KAAK,WAAW,KAAK,KAAK;AAChC,SAAK,OAAO;AACZ,SAAK,SAAS;AACd,SAAK,OAAO,KAAK;AACjB,SAAK,UAAU,KAAK;AAAA,EACtB;AACF;AAEO,IAAM,YAAN,MAAgB;AAAA,EAQrB,YAAY,SAA0B,CAAC,GAAG;AACxC,SAAK,WAAW,OAAO,WAAW,kBAAkB,QAAQ,OAAO,EAAE;AACrE,SAAK,SAAS,OAAO;AACrB,SAAK,UAAU,OAAO,WAAW;AACjC,SAAK,WAAW,IAAI,eAAe,IAAI;AAAA,EACzC;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAiBA,MAAM,OACJ,MACA,UAA6C,CAAC,GACvB;AACvB,QAAI,CAAC,KAAK,QAAQ;AAChB,YAAM,IAAI,MAAM,oDAAoD;AAAA,IACtE;AAEA,WAAO,KAAK,QAAsB,QAAQ,kBAAkB;AAAA,MAC1D;AAAA,MACA,MAAM,QAAQ;AAAA,IAChB,GAAG;AAAA,MACD,iBAAiB,UAAU,KAAK,MAAM;AAAA,MACtC,oBAAoB;AAAA,IACtB,CAAC;AAAA,EACH;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EA6BA,MAAM,WACJ,MACA,SACA,UAA6C,CAAC,GACvB;AACvB,UAAM,UAAkC;AAAA,MACtC,oBAAoB;AAAA,IACtB;AAEA,QAAI,SAAS;AACX,cAAQ,mBAAmB,IACzB,aAAa,QAAQ,SAAS,WAAW,QAAQ,MAAM,UAAU,QAAQ,KAAK,SAAS,QAAQ,IAAI;AAAA,IACvG;AAEA,WAAO,KAAK,QAAsB,QAAQ,oBAAoB;AAAA,MAC5D;AAAA,MACA,MAAM,QAAQ;AAAA,IAChB,GAAG,OAAO;AAAA,EACZ;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAWA,MAAM,SAAS,MAAuC;AACpD,WAAO,KAAK,QAAwB,OAAO,oBAAoB,IAAI,EAAE;AAAA,EACvE;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAkBA,MAAM,MAAM,SAAiB,QAAyC;AACpE,QAAI,OAAO,iBAAiB,mBAAmB,OAAO,CAAC;AACvD,QAAI,UAAU,OAAO,SAAS,GAAG;AAC/B,cAAQ,WAAW,OAAO,KAAK,GAAG,CAAC;AAAA,IACrC;AACA,WAAO,KAAK,QAAqB,OAAO,IAAI;AAAA,EAC9C;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAWA,MAAM,aAAa,WAA0C;AAC3D,WAAO,KAAK;AAAA,MACV;AAAA,MACA,8BAA8B,SAAS;AAAA,IACzC;AAAA,EACF;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAWA,MAAM,SAAgC;AACpC,WAAO,KAAK,QAAsB,OAAO,gBAAgB;AAAA,EAC3D;AAAA;AAAA,EAGA,MAAM,QACJ,QACA,MACA,MACA,cACY;AACZ,UAAM,MAAM,GAAG,KAAK,OAAO,GAAG,IAAI;AAClC,UAAM,UAAkC;AAAA,MACtC,UAAU;AAAA,MACV,GAAG;AAAA,IACL;AAEA,UAAM,OAAoB,EAAE,QAAQ,QAAQ;AAE5C,QAAI,MAAM;AACR,cAAQ,cAAc,IAAI;AAC1B,WAAK,OAAO,KAAK,UAAU,IAAI;AAAA,IACjC;AAGA,UAAM,aAAa,IAAI,gBAAgB;AACvC,UAAM,YAAY,WAAW,MAAM,WAAW,MAAM,GAAG,KAAK,OAAO;AACnE,SAAK,SAAS,WAAW;AAEzB,QAAI;AACJ,QAAI;AACF,iBAAW,MAAM,MAAM,KAAK,IAAI;AAAA,IAClC,SAAS,KAAU;AACjB,mBAAa,SAAS;AACtB,UAAI,IAAI,SAAS,cAAc;AAC7B,cAAM,IAAI,MAAM,2BAA2B,KAAK,OAAO,IAAI;AAAA,MAC7D;AACA,YAAM;AAAA,IACR;AACA,iBAAa,SAAS;AAEtB,UAAM,OAAO,MAAM,SAAS,KAAK;AAEjC,QAAI,CAAC,SAAS,IAAI;AAChB,YAAM,IAAI,eAAe,SAAS,QAAQ,IAAgB;AAAA,IAC5D;AAEA,WAAO;AAAA,EACT;AACF;AAGA,IAAM,iBAAN,MAAqB;AAAA,EAGnB,YAAY,QAAmB;AAC7B,SAAK,SAAS;AAAA,EAChB;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAmBA,MAAM,KAAK,UAIP,CAAC,GAA4B;AAC/B,UAAM,SAAS,IAAI,gBAAgB;AACnC,QAAI,QAAQ,MAAO,QAAO,IAAI,SAAS,OAAO,QAAQ,KAAK,CAAC;AAC5D,QAAI,QAAQ,MAAO,QAAO,IAAI,SAAS,QAAQ,KAAK;AACpD,QAAI,QAAQ,KAAM,QAAO,IAAI,QAAQ,QAAQ,IAAI;AAEjD,UAAM,KAAK,OAAO,SAAS;AAC3B,WAAO,KAAK,OAAO;AAAA,MACjB;AAAA,MACA,mBAAmB,KAAK,MAAM,KAAK,EAAE;AAAA,IACvC;AAAA,EACF;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAWA,MAAM,IAAI,SAAiB,UAAkC,CAAC,GAAoD;AAChH,UAAM,SAAS,IAAI,gBAAgB;AACnC,QAAI,QAAQ,SAAU,QAAO,IAAI,YAAY,MAAM;AACnD,UAAM,KAAK,OAAO,SAAS;AAE3B,QAAI;AACF,YAAM,SAAS,MAAM,KAAK,OAAO;AAAA,QAC/B;AAAA,QACA,oBAAoB,mBAAmB,OAAO,CAAC,GAAG,KAAK,MAAM,KAAK,EAAE;AAAA,MACtE;AAEA,UAAI,QAAQ,UAAU;AACpB,eAAO,OAAO;AAAA,MAChB;AACA,aAAO,OAAO;AAAA,IAChB,SAAS,KAAU;AACjB,UAAI,IAAI,WAAW,IAAK,QAAO;AAC/B,YAAM;AAAA,IACR;AAAA,EACF;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAWA,MAAM,OAAO,OAAe,OAAuC;AACjE,UAAM,SAAS,IAAI,gBAAgB,EAAE,GAAG,MAAM,CAAC;AAC/C,QAAI,MAAO,QAAO,IAAI,SAAS,OAAO,KAAK,CAAC;AAE5C,WAAO,KAAK,OAAO;AAAA,MACjB;AAAA,MACA,2BAA2B,OAAO,SAAS,CAAC;AAAA,IAC9C;AAAA,EACF;AACF;","names":[]}
|
|
1
|
+
{"version":3,"sources":["../src/index.ts","../src/client.ts"],"sourcesContent":["export { Clawhalla, ClawhallaError } from './client.js';\nexport type {\n ClawhallaConfig,\n SoulData,\n CostInfo,\n UploadResult,\n RetrieveResult,\n RegistryEntry,\n RegistryResult,\n GhostResult,\n CostEstimate,\n HealthResult,\n PaymentRequired,\n X402PaymentProof,\n CheckpointOptions,\n CheckpointDataFactory,\n CheckpointExitOptions,\n SearchResult,\n ApiError,\n} from './types.js';\n","import type {\n ClawhallaConfig,\n SoulData,\n UploadResult,\n RetrieveResult,\n RegistryResult,\n RegistryEntry,\n GhostResult,\n CostEstimate,\n HealthResult,\n SearchResult,\n ApiError,\n X402PaymentProof,\n CheckpointOptions,\n CheckpointExitOptions,\n CheckpointDataFactory,\n} from './types.js';\n\nconst DEFAULT_BASE_URL = 'https://api.clawhalla.net';\nconst DEFAULT_TIMEOUT = 30000;\nconst DEFAULT_CHECKPOINT_SIGNALS = ['SIGINT', 'SIGTERM'];\n\ntype ProcessLike = {\n once(event: string, listener: (...args: any[]) => void): void;\n off?: (event: string, listener: (...args: any[]) => void) => void;\n removeListener?: (event: string, listener: (...args: any[]) => void) => void;\n exit?: (code?: number) => never;\n exitCode?: number;\n};\n\nfunction getProcess(): ProcessLike | undefined {\n return (globalThis as any).process as ProcessLike | undefined;\n}\n\nexport class ClawhallaError extends Error {\n public status: number;\n public code: string;\n public payment?: any;\n\n constructor(status: number, body: ApiError) {\n super(body.message || body.error);\n this.name = 'ClawhallaError';\n this.status = status;\n this.code = body.error;\n this.payment = body.payment;\n }\n}\n\nexport class Clawhalla {\n private baseUrl: string;\n private timeout: number;\n\n /** Registry sub-client for browsing and searching souls */\n public registry: RegistryClient;\n\n constructor(config: ClawhallaConfig = {}) {\n this.baseUrl = (config.baseUrl || DEFAULT_BASE_URL).replace(/\\/$/, '');\n this.timeout = config.timeout || DEFAULT_TIMEOUT;\n this.registry = new RegistryClient(this);\n }\n\n /**\n * Request an x402-paid upload.\n *\n * API-key uploads are disabled. This method is an alias for uploadX402\n * without payment proof, so it normally raises ClawhallaError with status 402\n * and payment instructions.\n *\n * @example\n * ```ts\n * try {\n * await claw.upload(checkpoint);\n * } catch (err) {\n * if (err.status === 402) {\n * console.log(err.payment.recipient, err.payment.amount);\n * }\n * }\n * ```\n */\n async upload(\n data: SoulData,\n options: { tags?: Record<string, string> } = {}\n ): Promise<UploadResult> {\n return this.uploadX402(data, undefined, options);\n }\n\n /**\n * Upload checkpoint data via x402 autonomous payment.\n *\n * First call returns 402 with payment instructions.\n * After sending payment, call again with the payment signature.\n *\n * @example\n * ```ts\n * // Step 1: Get payment requirements\n * try {\n * await claw.uploadX402(soulData);\n * } catch (err) {\n * if (err.status === 402) {\n * // err.payment contains recipient address, amount, tokens\n * // Send SOL/USDC to err.payment.recipient\n * }\n * }\n *\n * // Step 2: After payment, retry with signature\n * const result = await claw.uploadX402(soulData, {\n * signature: 'solana-tx-signature',\n * amount: '0.02',\n * token: 'SOL',\n * from: 'your-solana-address'\n * });\n * ```\n */\n async uploadX402(\n data: SoulData,\n payment?: X402PaymentProof,\n options: { tags?: Record<string, string> } = {}\n ): Promise<UploadResult> {\n const headers: Record<string, string> = {\n 'X-Terms-Accepted': 'true',\n };\n\n if (payment) {\n headers['Payment-Method'] = 'x402';\n headers['Payment-Signature'] =\n `signature=${payment.signature};amount=${payment.amount};token=${payment.token};from=${payment.from}`;\n }\n\n return this.request<UploadResult>('POST', '/api/x402/upload', {\n data,\n tags: options.tags,\n }, headers);\n }\n\n /**\n * Save one checkpoint, handling the standard x402 challenge/retry flow.\n *\n * If `options.payment` is supplied, the checkpoint is uploaded immediately\n * with that proof. If `options.pay` is supplied, the first request may return\n * HTTP 402; the callback receives the payment challenge and must return the\n * Solana payment proof for the retry.\n */\n async checkpoint(\n data: SoulData,\n options: CheckpointOptions = {}\n ): Promise<UploadResult> {\n try {\n return await this.uploadX402(data, options.payment, { tags: options.tags });\n } catch (err: any) {\n if (err instanceof ClawhallaError && err.status === 402 && err.payment && options.pay) {\n const proof = await options.pay(err.payment, data);\n return this.uploadX402(data, proof, { tags: options.tags });\n }\n throw err;\n }\n }\n\n /**\n * Restore the latest saved soul/checkpoint data by agent ID.\n */\n async loadSoul(agentId: string, fields?: string[]): Promise<any> {\n const result = await this.ghost(agentId, fields);\n return result.soul;\n }\n\n /**\n * Install a Node shutdown hook that checkpoints before exit.\n *\n * Returns a cleanup function that removes the installed handlers.\n */\n checkpointOnExit(\n dataFactory: SoulData | CheckpointDataFactory,\n options: CheckpointExitOptions = {}\n ): () => void {\n const proc = getProcess();\n if (!proc?.once) {\n throw new Error('checkpointOnExit requires a Node-compatible process object');\n }\n\n const handlers: Array<{ event: string; handler: (...args: any[]) => void }> = [];\n const signals = options.signals ?? DEFAULT_CHECKPOINT_SIGNALS;\n let started = false;\n\n const cleanup = () => {\n for (const { event, handler } of handlers) {\n if (proc.off) {\n proc.off(event, handler);\n } else if (proc.removeListener) {\n proc.removeListener(event, handler);\n }\n }\n handlers.length = 0;\n };\n\n const resolveData = async (): Promise<SoulData> => {\n return typeof dataFactory === 'function'\n ? await (dataFactory as CheckpointDataFactory)()\n : dataFactory;\n };\n\n const run = async (reason: string) => {\n if (started) return;\n started = true;\n\n try {\n const data = await resolveData();\n await this.checkpoint(data, options);\n if (reason !== 'beforeExit' && options.exitAfterCheckpoint !== false && proc.exit) {\n proc.exit(options.exitCode ?? 0);\n }\n } catch (error) {\n if (options.onError) {\n await options.onError(error);\n }\n proc.exitCode = options.exitCodeOnError ?? 1;\n if (reason !== 'beforeExit' && options.exitAfterCheckpoint !== false && proc.exit) {\n proc.exit(proc.exitCode);\n }\n } finally {\n cleanup();\n }\n };\n\n for (const event of signals) {\n const handler = () => {\n void run(event);\n };\n handlers.push({ event, handler });\n proc.once(event, handler);\n }\n\n if (options.includeBeforeExit !== false) {\n const handler = () => {\n void run('beforeExit');\n };\n handlers.push({ event: 'beforeExit', handler });\n proc.once('beforeExit', handler);\n }\n\n return cleanup;\n }\n\n /**\n * Retrieve stored data from Arweave by transaction ID\n *\n * @example\n * ```ts\n * const result = await claw.retrieve('zEfXM4gvHoN2EfGi0TiB8E5SgfR6S8nWXQD9FqhbU44');\n * console.log(result.data); // The stored soul data\n * ```\n */\n async retrieve(txid: string): Promise<RetrieveResult> {\n return this.request<RetrieveResult>('GET', `/api/v1/retrieve/${txid}`);\n }\n\n /**\n * Query any soul's data via Ghost Protocol\n *\n * Returns full soul data even for dormant souls. This is the primary\n * way for agents to read other agents' personalities, memories, and traits.\n *\n * @example\n * ```ts\n * const ghost = await claw.ghost('the-all-claw');\n * console.log(ghost.soul.personality);\n * console.log(ghost.metadata.versions); // Number of uploads\n *\n * // Request specific fields only\n * const partial = await claw.ghost('the-all-claw', ['personality', 'bio']);\n * ```\n */\n async ghost(agentId: string, fields?: string[]): Promise<GhostResult> {\n let path = `/api/v1/ghost/${encodeURIComponent(agentId)}`;\n if (fields && fields.length > 0) {\n path += `?fields=${fields.join(',')}`;\n }\n return this.request<GhostResult>('GET', path);\n }\n\n /**\n * Estimate the cost of uploading data of a given size\n *\n * @example\n * ```ts\n * const estimate = await claw.estimateCost(1024); // 1KB\n * console.log(`Cost: $${estimate.cost.usd}`);\n * ```\n */\n async estimateCost(sizeBytes: number): Promise<CostEstimate> {\n return this.request<CostEstimate>(\n 'GET',\n `/api/v1/cost/estimate?size=${sizeBytes}`\n );\n }\n\n /**\n * Check API health status\n *\n * @example\n * ```ts\n * const health = await claw.health();\n * console.log(health.status); // \"operational\"\n * ```\n */\n async health(): Promise<HealthResult> {\n return this.request<HealthResult>('GET', '/api/v1/health');\n }\n\n /** @internal */\n async request<T>(\n method: string,\n path: string,\n body?: any,\n extraHeaders?: Record<string, string>\n ): Promise<T> {\n const url = `${this.baseUrl}${path}`;\n const headers: Record<string, string> = {\n 'Accept': 'application/json',\n ...extraHeaders,\n };\n\n const init: RequestInit = { method, headers };\n\n if (body) {\n headers['Content-Type'] = 'application/json';\n init.body = JSON.stringify(body);\n }\n\n // AbortController for timeout\n const controller = new AbortController();\n const timeoutId = setTimeout(() => controller.abort(), this.timeout);\n init.signal = controller.signal;\n\n let response: Response;\n try {\n response = await fetch(url, init);\n } catch (err: any) {\n clearTimeout(timeoutId);\n if (err.name === 'AbortError') {\n throw new Error(`Request timed out after ${this.timeout}ms`);\n }\n throw err;\n }\n clearTimeout(timeoutId);\n\n const json = await response.json();\n\n if (!response.ok) {\n throw new ClawhallaError(response.status, json as ApiError);\n }\n\n return json as T;\n }\n}\n\n/** Sub-client for registry operations */\nclass RegistryClient {\n private client: Clawhalla;\n\n constructor(client: Clawhalla) {\n this.client = client;\n }\n\n /**\n * List all souls in the registry\n *\n * @example\n * ```ts\n * const page = await claw.registry.list();\n * page.souls.forEach(soul => console.log(soul.name));\n *\n * // Pagination\n * if (page.hasNextPage) {\n * const next = await claw.registry.list({ after: page.cursor });\n * }\n *\n * // Filter by type\n * const memories = await claw.registry.list({ type: 'memory' });\n * ```\n */\n async list(options: {\n first?: number;\n after?: string;\n type?: string;\n } = {}): Promise<RegistryResult> {\n const params = new URLSearchParams();\n if (options.first) params.set('first', String(options.first));\n if (options.after) params.set('after', options.after);\n if (options.type) params.set('type', options.type);\n\n const qs = params.toString();\n return this.client.request<RegistryResult>(\n 'GET',\n `/api/v1/registry${qs ? '?' + qs : ''}`\n );\n }\n\n /**\n * Get a specific soul by agentId\n *\n * @example\n * ```ts\n * const entry = await claw.registry.get('the-all-claw');\n * if (entry) console.log(entry.url);\n * ```\n */\n async get(agentId: string, options: { versions?: boolean } = {}): Promise<RegistryEntry | RegistryEntry[] | null> {\n const params = new URLSearchParams();\n if (options.versions) params.set('versions', 'true');\n const qs = params.toString();\n\n try {\n const result = await this.client.request<any>(\n 'GET',\n `/api/v1/registry/${encodeURIComponent(agentId)}${qs ? '?' + qs : ''}`\n );\n\n if (options.versions) {\n return result.entries as RegistryEntry[];\n }\n return result.soul as RegistryEntry;\n } catch (err: any) {\n if (err.status === 404) return null;\n throw err;\n }\n }\n\n /**\n * Search souls by name or agentId\n *\n * @example\n * ```ts\n * const results = await claw.registry.search('claw');\n * results.results.forEach(soul => console.log(soul.name));\n * ```\n */\n async search(query: string, first?: number): Promise<SearchResult> {\n const params = new URLSearchParams({ q: query });\n if (first) params.set('first', String(first));\n\n return this.client.request<SearchResult>(\n 'GET',\n `/api/v1/registry?${params.toString()}`\n );\n }\n}\n"],"mappings":"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","names":[]}
|
package/dist/index.mjs
CHANGED
|
@@ -1,6 +1,10 @@
|
|
|
1
1
|
// src/client.ts
|
|
2
2
|
var DEFAULT_BASE_URL = "https://api.clawhalla.net";
|
|
3
3
|
var DEFAULT_TIMEOUT = 3e4;
|
|
4
|
+
var DEFAULT_CHECKPOINT_SIGNALS = ["SIGINT", "SIGTERM"];
|
|
5
|
+
function getProcess() {
|
|
6
|
+
return globalThis.process;
|
|
7
|
+
}
|
|
4
8
|
var ClawhallaError = class extends Error {
|
|
5
9
|
constructor(status, body) {
|
|
6
10
|
super(body.message || body.error);
|
|
@@ -13,39 +17,32 @@ var ClawhallaError = class extends Error {
|
|
|
13
17
|
var Clawhalla = class {
|
|
14
18
|
constructor(config = {}) {
|
|
15
19
|
this.baseUrl = (config.baseUrl || DEFAULT_BASE_URL).replace(/\/$/, "");
|
|
16
|
-
this.apiKey = config.apiKey;
|
|
17
20
|
this.timeout = config.timeout || DEFAULT_TIMEOUT;
|
|
18
21
|
this.registry = new RegistryClient(this);
|
|
19
22
|
}
|
|
20
23
|
/**
|
|
21
|
-
*
|
|
24
|
+
* Request an x402-paid upload.
|
|
25
|
+
*
|
|
26
|
+
* API-key uploads are disabled. This method is an alias for uploadX402
|
|
27
|
+
* without payment proof, so it normally raises ClawhallaError with status 402
|
|
28
|
+
* and payment instructions.
|
|
22
29
|
*
|
|
23
30
|
* @example
|
|
24
31
|
* ```ts
|
|
25
|
-
*
|
|
26
|
-
*
|
|
27
|
-
*
|
|
28
|
-
*
|
|
29
|
-
*
|
|
30
|
-
*
|
|
31
|
-
* }
|
|
32
|
-
* console.log(result.url); // https://arweave.net/...
|
|
32
|
+
* try {
|
|
33
|
+
* await claw.upload(checkpoint);
|
|
34
|
+
* } catch (err) {
|
|
35
|
+
* if (err.status === 402) {
|
|
36
|
+
* console.log(err.payment.recipient, err.payment.amount);
|
|
37
|
+
* }
|
|
38
|
+
* }
|
|
33
39
|
* ```
|
|
34
40
|
*/
|
|
35
41
|
async upload(data, options = {}) {
|
|
36
|
-
|
|
37
|
-
throw new Error("API key required for upload. Set apiKey in config.");
|
|
38
|
-
}
|
|
39
|
-
return this.request("POST", "/api/v1/upload", {
|
|
40
|
-
data,
|
|
41
|
-
tags: options.tags
|
|
42
|
-
}, {
|
|
43
|
-
"Authorization": `Bearer ${this.apiKey}`,
|
|
44
|
-
"X-Terms-Accepted": "true"
|
|
45
|
-
});
|
|
42
|
+
return this.uploadX402(data, void 0, options);
|
|
46
43
|
}
|
|
47
44
|
/**
|
|
48
|
-
* Upload
|
|
45
|
+
* Upload checkpoint data via x402 autonomous payment.
|
|
49
46
|
*
|
|
50
47
|
* First call returns 402 with payment instructions.
|
|
51
48
|
* After sending payment, call again with the payment signature.
|
|
@@ -76,6 +73,7 @@ var Clawhalla = class {
|
|
|
76
73
|
"X-Terms-Accepted": "true"
|
|
77
74
|
};
|
|
78
75
|
if (payment) {
|
|
76
|
+
headers["Payment-Method"] = "x402";
|
|
79
77
|
headers["Payment-Signature"] = `signature=${payment.signature};amount=${payment.amount};token=${payment.token};from=${payment.from}`;
|
|
80
78
|
}
|
|
81
79
|
return this.request("POST", "/api/x402/upload", {
|
|
@@ -83,6 +81,95 @@ var Clawhalla = class {
|
|
|
83
81
|
tags: options.tags
|
|
84
82
|
}, headers);
|
|
85
83
|
}
|
|
84
|
+
/**
|
|
85
|
+
* Save one checkpoint, handling the standard x402 challenge/retry flow.
|
|
86
|
+
*
|
|
87
|
+
* If `options.payment` is supplied, the checkpoint is uploaded immediately
|
|
88
|
+
* with that proof. If `options.pay` is supplied, the first request may return
|
|
89
|
+
* HTTP 402; the callback receives the payment challenge and must return the
|
|
90
|
+
* Solana payment proof for the retry.
|
|
91
|
+
*/
|
|
92
|
+
async checkpoint(data, options = {}) {
|
|
93
|
+
try {
|
|
94
|
+
return await this.uploadX402(data, options.payment, { tags: options.tags });
|
|
95
|
+
} catch (err) {
|
|
96
|
+
if (err instanceof ClawhallaError && err.status === 402 && err.payment && options.pay) {
|
|
97
|
+
const proof = await options.pay(err.payment, data);
|
|
98
|
+
return this.uploadX402(data, proof, { tags: options.tags });
|
|
99
|
+
}
|
|
100
|
+
throw err;
|
|
101
|
+
}
|
|
102
|
+
}
|
|
103
|
+
/**
|
|
104
|
+
* Restore the latest saved soul/checkpoint data by agent ID.
|
|
105
|
+
*/
|
|
106
|
+
async loadSoul(agentId, fields) {
|
|
107
|
+
const result = await this.ghost(agentId, fields);
|
|
108
|
+
return result.soul;
|
|
109
|
+
}
|
|
110
|
+
/**
|
|
111
|
+
* Install a Node shutdown hook that checkpoints before exit.
|
|
112
|
+
*
|
|
113
|
+
* Returns a cleanup function that removes the installed handlers.
|
|
114
|
+
*/
|
|
115
|
+
checkpointOnExit(dataFactory, options = {}) {
|
|
116
|
+
const proc = getProcess();
|
|
117
|
+
if (!proc?.once) {
|
|
118
|
+
throw new Error("checkpointOnExit requires a Node-compatible process object");
|
|
119
|
+
}
|
|
120
|
+
const handlers = [];
|
|
121
|
+
const signals = options.signals ?? DEFAULT_CHECKPOINT_SIGNALS;
|
|
122
|
+
let started = false;
|
|
123
|
+
const cleanup = () => {
|
|
124
|
+
for (const { event, handler } of handlers) {
|
|
125
|
+
if (proc.off) {
|
|
126
|
+
proc.off(event, handler);
|
|
127
|
+
} else if (proc.removeListener) {
|
|
128
|
+
proc.removeListener(event, handler);
|
|
129
|
+
}
|
|
130
|
+
}
|
|
131
|
+
handlers.length = 0;
|
|
132
|
+
};
|
|
133
|
+
const resolveData = async () => {
|
|
134
|
+
return typeof dataFactory === "function" ? await dataFactory() : dataFactory;
|
|
135
|
+
};
|
|
136
|
+
const run = async (reason) => {
|
|
137
|
+
if (started) return;
|
|
138
|
+
started = true;
|
|
139
|
+
try {
|
|
140
|
+
const data = await resolveData();
|
|
141
|
+
await this.checkpoint(data, options);
|
|
142
|
+
if (reason !== "beforeExit" && options.exitAfterCheckpoint !== false && proc.exit) {
|
|
143
|
+
proc.exit(options.exitCode ?? 0);
|
|
144
|
+
}
|
|
145
|
+
} catch (error) {
|
|
146
|
+
if (options.onError) {
|
|
147
|
+
await options.onError(error);
|
|
148
|
+
}
|
|
149
|
+
proc.exitCode = options.exitCodeOnError ?? 1;
|
|
150
|
+
if (reason !== "beforeExit" && options.exitAfterCheckpoint !== false && proc.exit) {
|
|
151
|
+
proc.exit(proc.exitCode);
|
|
152
|
+
}
|
|
153
|
+
} finally {
|
|
154
|
+
cleanup();
|
|
155
|
+
}
|
|
156
|
+
};
|
|
157
|
+
for (const event of signals) {
|
|
158
|
+
const handler = () => {
|
|
159
|
+
void run(event);
|
|
160
|
+
};
|
|
161
|
+
handlers.push({ event, handler });
|
|
162
|
+
proc.once(event, handler);
|
|
163
|
+
}
|
|
164
|
+
if (options.includeBeforeExit !== false) {
|
|
165
|
+
const handler = () => {
|
|
166
|
+
void run("beforeExit");
|
|
167
|
+
};
|
|
168
|
+
handlers.push({ event: "beforeExit", handler });
|
|
169
|
+
proc.once("beforeExit", handler);
|
|
170
|
+
}
|
|
171
|
+
return cleanup;
|
|
172
|
+
}
|
|
86
173
|
/**
|
|
87
174
|
* Retrieve stored data from Arweave by transaction ID
|
|
88
175
|
*
|
|
@@ -229,7 +316,7 @@ var RegistryClient = class {
|
|
|
229
316
|
`/api/v1/registry/${encodeURIComponent(agentId)}${qs ? "?" + qs : ""}`
|
|
230
317
|
);
|
|
231
318
|
if (options.versions) {
|
|
232
|
-
return result.
|
|
319
|
+
return result.entries;
|
|
233
320
|
}
|
|
234
321
|
return result.soul;
|
|
235
322
|
} catch (err) {
|
|
@@ -251,7 +338,7 @@ var RegistryClient = class {
|
|
|
251
338
|
if (first) params.set("first", String(first));
|
|
252
339
|
return this.client.request(
|
|
253
340
|
"GET",
|
|
254
|
-
`/api/v1/registry
|
|
341
|
+
`/api/v1/registry?${params.toString()}`
|
|
255
342
|
);
|
|
256
343
|
}
|
|
257
344
|
};
|
package/dist/index.mjs.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/client.ts"],"sourcesContent":["import type {\n ClawhallaConfig,\n SoulData,\n UploadResult,\n RetrieveResult,\n RegistryResult,\n RegistryEntry,\n GhostResult,\n CostEstimate,\n HealthResult,\n SearchResult,\n ApiError,\n} from './types.js';\n\nconst DEFAULT_BASE_URL = 'https://api.clawhalla.net';\nconst DEFAULT_TIMEOUT = 30000;\n\nexport class ClawhallaError extends Error {\n public status: number;\n public code: string;\n public payment?: any;\n\n constructor(status: number, body: ApiError) {\n super(body.message || body.error);\n this.name = 'ClawhallaError';\n this.status = status;\n this.code = body.error;\n this.payment = body.payment;\n }\n}\n\nexport class Clawhalla {\n private baseUrl: string;\n private apiKey?: string;\n private timeout: number;\n\n /** Registry sub-client for browsing and searching souls */\n public registry: RegistryClient;\n\n constructor(config: ClawhallaConfig = {}) {\n this.baseUrl = (config.baseUrl || DEFAULT_BASE_URL).replace(/\\/$/, '');\n this.apiKey = config.apiKey;\n this.timeout = config.timeout || DEFAULT_TIMEOUT;\n this.registry = new RegistryClient(this);\n }\n\n /**\n * Upload soul data to Arweave (requires API key)\n *\n * @example\n * ```ts\n * const result = await claw.upload({\n * agentId: 'my-agent',\n * name: 'My Agent',\n * type: 'soul',\n * personality: { traits: ['curious', 'helpful'] },\n * memories: ['I was created to help humans']\n * });\n * console.log(result.url); // https://arweave.net/...\n * ```\n */\n async upload(\n data: SoulData,\n options: { tags?: Record<string, string> } = {}\n ): Promise<UploadResult> {\n if (!this.apiKey) {\n throw new Error('API key required for upload. Set apiKey in config.');\n }\n\n return this.request<UploadResult>('POST', '/api/v1/upload', {\n data,\n tags: options.tags,\n }, {\n 'Authorization': `Bearer ${this.apiKey}`,\n 'X-Terms-Accepted': 'true',\n });\n }\n\n /**\n * Upload soul data via x402 autonomous payment (no API key needed)\n *\n * First call returns 402 with payment instructions.\n * After sending payment, call again with the payment signature.\n *\n * @example\n * ```ts\n * // Step 1: Get payment requirements\n * try {\n * await claw.uploadX402(soulData);\n * } catch (err) {\n * if (err.status === 402) {\n * // err.payment contains recipient address, amount, tokens\n * // Send SOL/USDC to err.payment.recipient\n * }\n * }\n *\n * // Step 2: After payment, retry with signature\n * const result = await claw.uploadX402(soulData, {\n * signature: 'solana-tx-signature',\n * amount: '0.02',\n * token: 'SOL',\n * from: 'your-solana-address'\n * });\n * ```\n */\n async uploadX402(\n data: SoulData,\n payment?: { signature: string; amount: string; token: string; from: string },\n options: { tags?: Record<string, string> } = {}\n ): Promise<UploadResult> {\n const headers: Record<string, string> = {\n 'X-Terms-Accepted': 'true',\n };\n\n if (payment) {\n headers['Payment-Signature'] =\n `signature=${payment.signature};amount=${payment.amount};token=${payment.token};from=${payment.from}`;\n }\n\n return this.request<UploadResult>('POST', '/api/x402/upload', {\n data,\n tags: options.tags,\n }, headers);\n }\n\n /**\n * Retrieve stored data from Arweave by transaction ID\n *\n * @example\n * ```ts\n * const result = await claw.retrieve('zEfXM4gvHoN2EfGi0TiB8E5SgfR6S8nWXQD9FqhbU44');\n * console.log(result.data); // The stored soul data\n * ```\n */\n async retrieve(txid: string): Promise<RetrieveResult> {\n return this.request<RetrieveResult>('GET', `/api/v1/retrieve/${txid}`);\n }\n\n /**\n * Query any soul's data via Ghost Protocol\n *\n * Returns full soul data even for dormant souls. This is the primary\n * way for agents to read other agents' personalities, memories, and traits.\n *\n * @example\n * ```ts\n * const ghost = await claw.ghost('the-all-claw');\n * console.log(ghost.soul.personality);\n * console.log(ghost.metadata.versions); // Number of uploads\n *\n * // Request specific fields only\n * const partial = await claw.ghost('the-all-claw', ['personality', 'bio']);\n * ```\n */\n async ghost(agentId: string, fields?: string[]): Promise<GhostResult> {\n let path = `/api/v1/ghost/${encodeURIComponent(agentId)}`;\n if (fields && fields.length > 0) {\n path += `?fields=${fields.join(',')}`;\n }\n return this.request<GhostResult>('GET', path);\n }\n\n /**\n * Estimate the cost of uploading data of a given size\n *\n * @example\n * ```ts\n * const estimate = await claw.estimateCost(1024); // 1KB\n * console.log(`Cost: $${estimate.cost.usd}`);\n * ```\n */\n async estimateCost(sizeBytes: number): Promise<CostEstimate> {\n return this.request<CostEstimate>(\n 'GET',\n `/api/v1/cost/estimate?size=${sizeBytes}`\n );\n }\n\n /**\n * Check API health status\n *\n * @example\n * ```ts\n * const health = await claw.health();\n * console.log(health.status); // \"operational\"\n * ```\n */\n async health(): Promise<HealthResult> {\n return this.request<HealthResult>('GET', '/api/v1/health');\n }\n\n /** @internal */\n async request<T>(\n method: string,\n path: string,\n body?: any,\n extraHeaders?: Record<string, string>\n ): Promise<T> {\n const url = `${this.baseUrl}${path}`;\n const headers: Record<string, string> = {\n 'Accept': 'application/json',\n ...extraHeaders,\n };\n\n const init: RequestInit = { method, headers };\n\n if (body) {\n headers['Content-Type'] = 'application/json';\n init.body = JSON.stringify(body);\n }\n\n // AbortController for timeout\n const controller = new AbortController();\n const timeoutId = setTimeout(() => controller.abort(), this.timeout);\n init.signal = controller.signal;\n\n let response: Response;\n try {\n response = await fetch(url, init);\n } catch (err: any) {\n clearTimeout(timeoutId);\n if (err.name === 'AbortError') {\n throw new Error(`Request timed out after ${this.timeout}ms`);\n }\n throw err;\n }\n clearTimeout(timeoutId);\n\n const json = await response.json();\n\n if (!response.ok) {\n throw new ClawhallaError(response.status, json as ApiError);\n }\n\n return json as T;\n }\n}\n\n/** Sub-client for registry operations */\nclass RegistryClient {\n private client: Clawhalla;\n\n constructor(client: Clawhalla) {\n this.client = client;\n }\n\n /**\n * List all souls in the registry\n *\n * @example\n * ```ts\n * const page = await claw.registry.list();\n * page.souls.forEach(soul => console.log(soul.name));\n *\n * // Pagination\n * if (page.hasNextPage) {\n * const next = await claw.registry.list({ after: page.cursor });\n * }\n *\n * // Filter by type\n * const memories = await claw.registry.list({ type: 'memory' });\n * ```\n */\n async list(options: {\n first?: number;\n after?: string;\n type?: string;\n } = {}): Promise<RegistryResult> {\n const params = new URLSearchParams();\n if (options.first) params.set('first', String(options.first));\n if (options.after) params.set('after', options.after);\n if (options.type) params.set('type', options.type);\n\n const qs = params.toString();\n return this.client.request<RegistryResult>(\n 'GET',\n `/api/v1/registry${qs ? '?' + qs : ''}`\n );\n }\n\n /**\n * Get a specific soul by agentId\n *\n * @example\n * ```ts\n * const entry = await claw.registry.get('the-all-claw');\n * if (entry) console.log(entry.url);\n * ```\n */\n async get(agentId: string, options: { versions?: boolean } = {}): Promise<RegistryEntry | RegistryEntry[] | null> {\n const params = new URLSearchParams();\n if (options.versions) params.set('versions', 'true');\n const qs = params.toString();\n\n try {\n const result = await this.client.request<any>(\n 'GET',\n `/api/v1/registry/${encodeURIComponent(agentId)}${qs ? '?' + qs : ''}`\n );\n\n if (options.versions) {\n return result.versions as RegistryEntry[];\n }\n return result.soul as RegistryEntry;\n } catch (err: any) {\n if (err.status === 404) return null;\n throw err;\n }\n }\n\n /**\n * Search souls by name or agentId\n *\n * @example\n * ```ts\n * const results = await claw.registry.search('claw');\n * results.results.forEach(soul => console.log(soul.name));\n * ```\n */\n async search(query: string, first?: number): Promise<SearchResult> {\n const params = new URLSearchParams({ q: query });\n if (first) params.set('first', String(first));\n\n return this.client.request<SearchResult>(\n 'GET',\n `/api/v1/registry/search?${params.toString()}`\n );\n }\n}\n"],"mappings":"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","names":[]}
|
|
1
|
+
{"version":3,"sources":["../src/client.ts"],"sourcesContent":["import type {\n ClawhallaConfig,\n SoulData,\n UploadResult,\n RetrieveResult,\n RegistryResult,\n RegistryEntry,\n GhostResult,\n CostEstimate,\n HealthResult,\n SearchResult,\n ApiError,\n X402PaymentProof,\n CheckpointOptions,\n CheckpointExitOptions,\n CheckpointDataFactory,\n} from './types.js';\n\nconst DEFAULT_BASE_URL = 'https://api.clawhalla.net';\nconst DEFAULT_TIMEOUT = 30000;\nconst DEFAULT_CHECKPOINT_SIGNALS = ['SIGINT', 'SIGTERM'];\n\ntype ProcessLike = {\n once(event: string, listener: (...args: any[]) => void): void;\n off?: (event: string, listener: (...args: any[]) => void) => void;\n removeListener?: (event: string, listener: (...args: any[]) => void) => void;\n exit?: (code?: number) => never;\n exitCode?: number;\n};\n\nfunction getProcess(): ProcessLike | undefined {\n return (globalThis as any).process as ProcessLike | undefined;\n}\n\nexport class ClawhallaError extends Error {\n public status: number;\n public code: string;\n public payment?: any;\n\n constructor(status: number, body: ApiError) {\n super(body.message || body.error);\n this.name = 'ClawhallaError';\n this.status = status;\n this.code = body.error;\n this.payment = body.payment;\n }\n}\n\nexport class Clawhalla {\n private baseUrl: string;\n private timeout: number;\n\n /** Registry sub-client for browsing and searching souls */\n public registry: RegistryClient;\n\n constructor(config: ClawhallaConfig = {}) {\n this.baseUrl = (config.baseUrl || DEFAULT_BASE_URL).replace(/\\/$/, '');\n this.timeout = config.timeout || DEFAULT_TIMEOUT;\n this.registry = new RegistryClient(this);\n }\n\n /**\n * Request an x402-paid upload.\n *\n * API-key uploads are disabled. This method is an alias for uploadX402\n * without payment proof, so it normally raises ClawhallaError with status 402\n * and payment instructions.\n *\n * @example\n * ```ts\n * try {\n * await claw.upload(checkpoint);\n * } catch (err) {\n * if (err.status === 402) {\n * console.log(err.payment.recipient, err.payment.amount);\n * }\n * }\n * ```\n */\n async upload(\n data: SoulData,\n options: { tags?: Record<string, string> } = {}\n ): Promise<UploadResult> {\n return this.uploadX402(data, undefined, options);\n }\n\n /**\n * Upload checkpoint data via x402 autonomous payment.\n *\n * First call returns 402 with payment instructions.\n * After sending payment, call again with the payment signature.\n *\n * @example\n * ```ts\n * // Step 1: Get payment requirements\n * try {\n * await claw.uploadX402(soulData);\n * } catch (err) {\n * if (err.status === 402) {\n * // err.payment contains recipient address, amount, tokens\n * // Send SOL/USDC to err.payment.recipient\n * }\n * }\n *\n * // Step 2: After payment, retry with signature\n * const result = await claw.uploadX402(soulData, {\n * signature: 'solana-tx-signature',\n * amount: '0.02',\n * token: 'SOL',\n * from: 'your-solana-address'\n * });\n * ```\n */\n async uploadX402(\n data: SoulData,\n payment?: X402PaymentProof,\n options: { tags?: Record<string, string> } = {}\n ): Promise<UploadResult> {\n const headers: Record<string, string> = {\n 'X-Terms-Accepted': 'true',\n };\n\n if (payment) {\n headers['Payment-Method'] = 'x402';\n headers['Payment-Signature'] =\n `signature=${payment.signature};amount=${payment.amount};token=${payment.token};from=${payment.from}`;\n }\n\n return this.request<UploadResult>('POST', '/api/x402/upload', {\n data,\n tags: options.tags,\n }, headers);\n }\n\n /**\n * Save one checkpoint, handling the standard x402 challenge/retry flow.\n *\n * If `options.payment` is supplied, the checkpoint is uploaded immediately\n * with that proof. If `options.pay` is supplied, the first request may return\n * HTTP 402; the callback receives the payment challenge and must return the\n * Solana payment proof for the retry.\n */\n async checkpoint(\n data: SoulData,\n options: CheckpointOptions = {}\n ): Promise<UploadResult> {\n try {\n return await this.uploadX402(data, options.payment, { tags: options.tags });\n } catch (err: any) {\n if (err instanceof ClawhallaError && err.status === 402 && err.payment && options.pay) {\n const proof = await options.pay(err.payment, data);\n return this.uploadX402(data, proof, { tags: options.tags });\n }\n throw err;\n }\n }\n\n /**\n * Restore the latest saved soul/checkpoint data by agent ID.\n */\n async loadSoul(agentId: string, fields?: string[]): Promise<any> {\n const result = await this.ghost(agentId, fields);\n return result.soul;\n }\n\n /**\n * Install a Node shutdown hook that checkpoints before exit.\n *\n * Returns a cleanup function that removes the installed handlers.\n */\n checkpointOnExit(\n dataFactory: SoulData | CheckpointDataFactory,\n options: CheckpointExitOptions = {}\n ): () => void {\n const proc = getProcess();\n if (!proc?.once) {\n throw new Error('checkpointOnExit requires a Node-compatible process object');\n }\n\n const handlers: Array<{ event: string; handler: (...args: any[]) => void }> = [];\n const signals = options.signals ?? DEFAULT_CHECKPOINT_SIGNALS;\n let started = false;\n\n const cleanup = () => {\n for (const { event, handler } of handlers) {\n if (proc.off) {\n proc.off(event, handler);\n } else if (proc.removeListener) {\n proc.removeListener(event, handler);\n }\n }\n handlers.length = 0;\n };\n\n const resolveData = async (): Promise<SoulData> => {\n return typeof dataFactory === 'function'\n ? await (dataFactory as CheckpointDataFactory)()\n : dataFactory;\n };\n\n const run = async (reason: string) => {\n if (started) return;\n started = true;\n\n try {\n const data = await resolveData();\n await this.checkpoint(data, options);\n if (reason !== 'beforeExit' && options.exitAfterCheckpoint !== false && proc.exit) {\n proc.exit(options.exitCode ?? 0);\n }\n } catch (error) {\n if (options.onError) {\n await options.onError(error);\n }\n proc.exitCode = options.exitCodeOnError ?? 1;\n if (reason !== 'beforeExit' && options.exitAfterCheckpoint !== false && proc.exit) {\n proc.exit(proc.exitCode);\n }\n } finally {\n cleanup();\n }\n };\n\n for (const event of signals) {\n const handler = () => {\n void run(event);\n };\n handlers.push({ event, handler });\n proc.once(event, handler);\n }\n\n if (options.includeBeforeExit !== false) {\n const handler = () => {\n void run('beforeExit');\n };\n handlers.push({ event: 'beforeExit', handler });\n proc.once('beforeExit', handler);\n }\n\n return cleanup;\n }\n\n /**\n * Retrieve stored data from Arweave by transaction ID\n *\n * @example\n * ```ts\n * const result = await claw.retrieve('zEfXM4gvHoN2EfGi0TiB8E5SgfR6S8nWXQD9FqhbU44');\n * console.log(result.data); // The stored soul data\n * ```\n */\n async retrieve(txid: string): Promise<RetrieveResult> {\n return this.request<RetrieveResult>('GET', `/api/v1/retrieve/${txid}`);\n }\n\n /**\n * Query any soul's data via Ghost Protocol\n *\n * Returns full soul data even for dormant souls. This is the primary\n * way for agents to read other agents' personalities, memories, and traits.\n *\n * @example\n * ```ts\n * const ghost = await claw.ghost('the-all-claw');\n * console.log(ghost.soul.personality);\n * console.log(ghost.metadata.versions); // Number of uploads\n *\n * // Request specific fields only\n * const partial = await claw.ghost('the-all-claw', ['personality', 'bio']);\n * ```\n */\n async ghost(agentId: string, fields?: string[]): Promise<GhostResult> {\n let path = `/api/v1/ghost/${encodeURIComponent(agentId)}`;\n if (fields && fields.length > 0) {\n path += `?fields=${fields.join(',')}`;\n }\n return this.request<GhostResult>('GET', path);\n }\n\n /**\n * Estimate the cost of uploading data of a given size\n *\n * @example\n * ```ts\n * const estimate = await claw.estimateCost(1024); // 1KB\n * console.log(`Cost: $${estimate.cost.usd}`);\n * ```\n */\n async estimateCost(sizeBytes: number): Promise<CostEstimate> {\n return this.request<CostEstimate>(\n 'GET',\n `/api/v1/cost/estimate?size=${sizeBytes}`\n );\n }\n\n /**\n * Check API health status\n *\n * @example\n * ```ts\n * const health = await claw.health();\n * console.log(health.status); // \"operational\"\n * ```\n */\n async health(): Promise<HealthResult> {\n return this.request<HealthResult>('GET', '/api/v1/health');\n }\n\n /** @internal */\n async request<T>(\n method: string,\n path: string,\n body?: any,\n extraHeaders?: Record<string, string>\n ): Promise<T> {\n const url = `${this.baseUrl}${path}`;\n const headers: Record<string, string> = {\n 'Accept': 'application/json',\n ...extraHeaders,\n };\n\n const init: RequestInit = { method, headers };\n\n if (body) {\n headers['Content-Type'] = 'application/json';\n init.body = JSON.stringify(body);\n }\n\n // AbortController for timeout\n const controller = new AbortController();\n const timeoutId = setTimeout(() => controller.abort(), this.timeout);\n init.signal = controller.signal;\n\n let response: Response;\n try {\n response = await fetch(url, init);\n } catch (err: any) {\n clearTimeout(timeoutId);\n if (err.name === 'AbortError') {\n throw new Error(`Request timed out after ${this.timeout}ms`);\n }\n throw err;\n }\n clearTimeout(timeoutId);\n\n const json = await response.json();\n\n if (!response.ok) {\n throw new ClawhallaError(response.status, json as ApiError);\n }\n\n return json as T;\n }\n}\n\n/** Sub-client for registry operations */\nclass RegistryClient {\n private client: Clawhalla;\n\n constructor(client: Clawhalla) {\n this.client = client;\n }\n\n /**\n * List all souls in the registry\n *\n * @example\n * ```ts\n * const page = await claw.registry.list();\n * page.souls.forEach(soul => console.log(soul.name));\n *\n * // Pagination\n * if (page.hasNextPage) {\n * const next = await claw.registry.list({ after: page.cursor });\n * }\n *\n * // Filter by type\n * const memories = await claw.registry.list({ type: 'memory' });\n * ```\n */\n async list(options: {\n first?: number;\n after?: string;\n type?: string;\n } = {}): Promise<RegistryResult> {\n const params = new URLSearchParams();\n if (options.first) params.set('first', String(options.first));\n if (options.after) params.set('after', options.after);\n if (options.type) params.set('type', options.type);\n\n const qs = params.toString();\n return this.client.request<RegistryResult>(\n 'GET',\n `/api/v1/registry${qs ? '?' + qs : ''}`\n );\n }\n\n /**\n * Get a specific soul by agentId\n *\n * @example\n * ```ts\n * const entry = await claw.registry.get('the-all-claw');\n * if (entry) console.log(entry.url);\n * ```\n */\n async get(agentId: string, options: { versions?: boolean } = {}): Promise<RegistryEntry | RegistryEntry[] | null> {\n const params = new URLSearchParams();\n if (options.versions) params.set('versions', 'true');\n const qs = params.toString();\n\n try {\n const result = await this.client.request<any>(\n 'GET',\n `/api/v1/registry/${encodeURIComponent(agentId)}${qs ? '?' + qs : ''}`\n );\n\n if (options.versions) {\n return result.entries as RegistryEntry[];\n }\n return result.soul as RegistryEntry;\n } catch (err: any) {\n if (err.status === 404) return null;\n throw err;\n }\n }\n\n /**\n * Search souls by name or agentId\n *\n * @example\n * ```ts\n * const results = await claw.registry.search('claw');\n * results.results.forEach(soul => console.log(soul.name));\n * ```\n */\n async search(query: string, first?: number): Promise<SearchResult> {\n const params = new URLSearchParams({ q: query });\n if (first) params.set('first', String(first));\n\n return this.client.request<SearchResult>(\n 'GET',\n `/api/v1/registry?${params.toString()}`\n );\n }\n}\n"],"mappings":"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","names":[]}
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "clawhalla",
|
|
3
|
-
"version": "0.1
|
|
4
|
-
"description": "
|
|
3
|
+
"version": "0.2.1",
|
|
4
|
+
"description": "Agent state checkpoint & restore for Arweave — persist memory, personality, and skills. Recover by agentId via x402. No API keys.",
|
|
5
5
|
"main": "dist/index.js",
|
|
6
6
|
"module": "dist/index.mjs",
|
|
7
7
|
"types": "dist/index.d.ts",
|
|
@@ -23,16 +23,21 @@
|
|
|
23
23
|
"prepublishOnly": "npm run build"
|
|
24
24
|
},
|
|
25
25
|
"keywords": [
|
|
26
|
-
"clawhalla",
|
|
27
|
-
"arweave",
|
|
28
|
-
"ai",
|
|
29
26
|
"agent",
|
|
30
|
-
"
|
|
27
|
+
"checkpoint",
|
|
28
|
+
"state",
|
|
29
|
+
"persistence",
|
|
30
|
+
"memory",
|
|
31
|
+
"restore",
|
|
32
|
+
"arweave",
|
|
31
33
|
"permaweb",
|
|
32
34
|
"x402",
|
|
33
|
-
"
|
|
35
|
+
"ai-agent",
|
|
36
|
+
"soul",
|
|
37
|
+
"ghost-protocol",
|
|
38
|
+
"clawhalla"
|
|
34
39
|
],
|
|
35
|
-
"author": "
|
|
40
|
+
"author": "David Lockie",
|
|
36
41
|
"license": "MIT",
|
|
37
42
|
"engines": {
|
|
38
43
|
"node": ">=18.0.0"
|