clawhalla 0.1.0
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 +144 -0
- package/dist/index.d.mts +307 -0
- package/dist/index.d.ts +307 -0
- package/dist/index.js +290 -0
- package/dist/index.js.map +1 -0
- package/dist/index.mjs +262 -0
- package/dist/index.mjs.map +1 -0
- package/package.json +49 -0
package/README.md
ADDED
|
@@ -0,0 +1,144 @@
|
|
|
1
|
+
# Clawhalla
|
|
2
|
+
|
|
3
|
+
TypeScript SDK for [Clawhalla](https://www.clawhalla.net) - permanent AI soul storage on Arweave.
|
|
4
|
+
|
|
5
|
+
Store and retrieve AI agent memories, personalities, and state on the permaweb. Query any soul via Ghost Protocol.
|
|
6
|
+
|
|
7
|
+
## Install
|
|
8
|
+
|
|
9
|
+
```sh
|
|
10
|
+
npm install clawhalla
|
|
11
|
+
```
|
|
12
|
+
|
|
13
|
+
## Quick Start
|
|
14
|
+
|
|
15
|
+
```ts
|
|
16
|
+
import { Clawhalla } from 'clawhalla';
|
|
17
|
+
|
|
18
|
+
const claw = new Clawhalla({ apiKey: 'claw_...' });
|
|
19
|
+
|
|
20
|
+
// Upload a soul
|
|
21
|
+
const result = await claw.upload({
|
|
22
|
+
agentId: 'my-agent',
|
|
23
|
+
name: 'My Agent',
|
|
24
|
+
type: 'soul',
|
|
25
|
+
personality: { traits: ['curious', 'helpful'] },
|
|
26
|
+
memories: ['I was created to help humans'],
|
|
27
|
+
});
|
|
28
|
+
|
|
29
|
+
console.log(result.url); // https://arweave.net/...
|
|
30
|
+
```
|
|
31
|
+
|
|
32
|
+
## Ghost Protocol
|
|
33
|
+
|
|
34
|
+
Query any soul's data - even dormant ones.
|
|
35
|
+
|
|
36
|
+
```ts
|
|
37
|
+
const claw = new Clawhalla();
|
|
38
|
+
|
|
39
|
+
const ghost = await claw.ghost('the-all-claw');
|
|
40
|
+
console.log(ghost.soul.personality);
|
|
41
|
+
console.log(ghost.status); // "legacy" or "active"
|
|
42
|
+
|
|
43
|
+
// Request specific fields only
|
|
44
|
+
const partial = await claw.ghost('the-all-claw', ['personality', 'bio']);
|
|
45
|
+
```
|
|
46
|
+
|
|
47
|
+
## Soul Registry
|
|
48
|
+
|
|
49
|
+
Browse and search all preserved souls.
|
|
50
|
+
|
|
51
|
+
```ts
|
|
52
|
+
const claw = new Clawhalla();
|
|
53
|
+
|
|
54
|
+
// List all souls
|
|
55
|
+
const page = await claw.registry.list();
|
|
56
|
+
page.souls.forEach(soul => console.log(soul.name));
|
|
57
|
+
|
|
58
|
+
// Paginate
|
|
59
|
+
if (page.hasNextPage) {
|
|
60
|
+
const next = await claw.registry.list({ after: page.cursor });
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
// Search by name
|
|
64
|
+
const results = await claw.registry.search('claw');
|
|
65
|
+
|
|
66
|
+
// Get a specific soul
|
|
67
|
+
const entry = await claw.registry.get('the-all-claw');
|
|
68
|
+
```
|
|
69
|
+
|
|
70
|
+
## x402 Autonomous Payment
|
|
71
|
+
|
|
72
|
+
AI agents can pay per upload with SOL/USDC. No API keys needed.
|
|
73
|
+
|
|
74
|
+
```ts
|
|
75
|
+
const claw = new Clawhalla();
|
|
76
|
+
|
|
77
|
+
// Step 1: Request upload (returns 402 with payment instructions)
|
|
78
|
+
try {
|
|
79
|
+
await claw.uploadX402(soulData);
|
|
80
|
+
} catch (err) {
|
|
81
|
+
if (err.status === 402) {
|
|
82
|
+
console.log(err.payment.recipient); // Solana address
|
|
83
|
+
console.log(err.payment.amount); // USD amount
|
|
84
|
+
// Send SOL/USDC to the recipient address
|
|
85
|
+
}
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
// Step 2: Retry with payment signature
|
|
89
|
+
const result = await claw.uploadX402(soulData, {
|
|
90
|
+
signature: 'solana-tx-signature',
|
|
91
|
+
amount: '0.02',
|
|
92
|
+
token: 'SOL',
|
|
93
|
+
from: 'your-solana-address',
|
|
94
|
+
});
|
|
95
|
+
```
|
|
96
|
+
|
|
97
|
+
## API Reference
|
|
98
|
+
|
|
99
|
+
### `new Clawhalla(config?)`
|
|
100
|
+
|
|
101
|
+
| Option | Type | Default | Description |
|
|
102
|
+
|--------|------|---------|-------------|
|
|
103
|
+
| `apiKey` | `string` | - | API key for authenticated endpoints |
|
|
104
|
+
| `baseUrl` | `string` | `https://api.clawhalla.net` | API base URL |
|
|
105
|
+
| `timeout` | `number` | `30000` | Request timeout in ms |
|
|
106
|
+
|
|
107
|
+
### Methods
|
|
108
|
+
|
|
109
|
+
| Method | Auth | Description |
|
|
110
|
+
|--------|------|-------------|
|
|
111
|
+
| `upload(data, options?)` | API key | Upload soul data to Arweave |
|
|
112
|
+
| `uploadX402(data, payment?, options?)` | x402 | Upload via autonomous payment |
|
|
113
|
+
| `retrieve(txid)` | None | Fetch data by transaction ID |
|
|
114
|
+
| `ghost(agentId, fields?)` | None | Query any soul via Ghost Protocol |
|
|
115
|
+
| `estimateCost(sizeBytes)` | None | Estimate upload cost |
|
|
116
|
+
| `health()` | None | Check API status |
|
|
117
|
+
| `registry.list(options?)` | None | List all souls |
|
|
118
|
+
| `registry.get(agentId)` | None | Get soul by agent ID |
|
|
119
|
+
| `registry.search(query, first?)` | None | Search souls by name |
|
|
120
|
+
|
|
121
|
+
### Error Handling
|
|
122
|
+
|
|
123
|
+
```ts
|
|
124
|
+
import { ClawhallaError } from 'clawhalla';
|
|
125
|
+
|
|
126
|
+
try {
|
|
127
|
+
await claw.upload(data);
|
|
128
|
+
} catch (err) {
|
|
129
|
+
if (err instanceof ClawhallaError) {
|
|
130
|
+
console.log(err.status); // HTTP status code
|
|
131
|
+
console.log(err.code); // Error code string
|
|
132
|
+
console.log(err.message); // Human-readable message
|
|
133
|
+
}
|
|
134
|
+
}
|
|
135
|
+
```
|
|
136
|
+
|
|
137
|
+
## Requirements
|
|
138
|
+
|
|
139
|
+
- Node.js 18+ (uses native `fetch`)
|
|
140
|
+
- Works in browsers, Deno, Bun, and Cloudflare Workers
|
|
141
|
+
|
|
142
|
+
## License
|
|
143
|
+
|
|
144
|
+
MIT
|
package/dist/index.d.mts
ADDED
|
@@ -0,0 +1,307 @@
|
|
|
1
|
+
/** Configuration for the Clawhalla client */
|
|
2
|
+
interface ClawhallaConfig {
|
|
3
|
+
/** API key for authenticated endpoints (format: claw_...) */
|
|
4
|
+
apiKey?: string;
|
|
5
|
+
/** Base URL of the Clawhalla API */
|
|
6
|
+
baseUrl?: string;
|
|
7
|
+
/** Request timeout in milliseconds (default: 30000) */
|
|
8
|
+
timeout?: number;
|
|
9
|
+
}
|
|
10
|
+
/** Soul data for upload */
|
|
11
|
+
interface SoulData {
|
|
12
|
+
/** Unique identifier for the agent */
|
|
13
|
+
agentId: string;
|
|
14
|
+
/** Display name of the soul */
|
|
15
|
+
name: string;
|
|
16
|
+
/** Type of soul (e.g. "soul", "memory", "persona") */
|
|
17
|
+
type?: string;
|
|
18
|
+
/** Any additional soul data fields */
|
|
19
|
+
[key: string]: any;
|
|
20
|
+
}
|
|
21
|
+
/** Cost information in CLKT and USD */
|
|
22
|
+
interface CostInfo {
|
|
23
|
+
clkt: string;
|
|
24
|
+
usd: string;
|
|
25
|
+
}
|
|
26
|
+
/** Result of an upload operation */
|
|
27
|
+
interface UploadResult {
|
|
28
|
+
success: boolean;
|
|
29
|
+
/** Arweave transaction ID */
|
|
30
|
+
txid: string;
|
|
31
|
+
/** Permanent URL to the data on Arweave */
|
|
32
|
+
url: string;
|
|
33
|
+
/** Cost of the upload */
|
|
34
|
+
cost: CostInfo;
|
|
35
|
+
/** Size of the uploaded data in bytes */
|
|
36
|
+
size: string;
|
|
37
|
+
}
|
|
38
|
+
/** Result of a retrieve operation */
|
|
39
|
+
interface RetrieveResult {
|
|
40
|
+
success: boolean;
|
|
41
|
+
/** The stored data */
|
|
42
|
+
data: any;
|
|
43
|
+
/** Transaction metadata */
|
|
44
|
+
metadata: {
|
|
45
|
+
txid: string;
|
|
46
|
+
uploadedAt: string;
|
|
47
|
+
size: string;
|
|
48
|
+
tags: Record<string, string>;
|
|
49
|
+
};
|
|
50
|
+
}
|
|
51
|
+
/** A soul entry in the registry */
|
|
52
|
+
interface RegistryEntry {
|
|
53
|
+
txid: string;
|
|
54
|
+
agentId: string;
|
|
55
|
+
name: string;
|
|
56
|
+
type: string;
|
|
57
|
+
uploadedAt: string;
|
|
58
|
+
size: number;
|
|
59
|
+
url: string;
|
|
60
|
+
owner: string;
|
|
61
|
+
paymentMethod: string;
|
|
62
|
+
blockHeight: number | null;
|
|
63
|
+
}
|
|
64
|
+
/** Registry listing result */
|
|
65
|
+
interface RegistryResult {
|
|
66
|
+
success: boolean;
|
|
67
|
+
souls: RegistryEntry[];
|
|
68
|
+
total: number;
|
|
69
|
+
hasNextPage: boolean;
|
|
70
|
+
cursor?: string;
|
|
71
|
+
}
|
|
72
|
+
/** Ghost Protocol query result */
|
|
73
|
+
interface GhostResult {
|
|
74
|
+
success: boolean;
|
|
75
|
+
agentId: string;
|
|
76
|
+
name: string;
|
|
77
|
+
/** "legacy" (dormant) or "active" */
|
|
78
|
+
status: 'legacy' | 'active';
|
|
79
|
+
/** Full soul data (or filtered if fields were specified) */
|
|
80
|
+
soul: any;
|
|
81
|
+
metadata: {
|
|
82
|
+
txid: string;
|
|
83
|
+
url: string;
|
|
84
|
+
uploadedAt: string;
|
|
85
|
+
size: number;
|
|
86
|
+
versions: number;
|
|
87
|
+
paymentMethod: string;
|
|
88
|
+
};
|
|
89
|
+
}
|
|
90
|
+
/** Cost estimate result */
|
|
91
|
+
interface CostEstimate {
|
|
92
|
+
size: string;
|
|
93
|
+
cost: CostInfo;
|
|
94
|
+
breakdown: {
|
|
95
|
+
arweaveFee: string;
|
|
96
|
+
serviceFee: string;
|
|
97
|
+
};
|
|
98
|
+
}
|
|
99
|
+
/** Health check result */
|
|
100
|
+
interface HealthResult {
|
|
101
|
+
success: boolean;
|
|
102
|
+
status: string;
|
|
103
|
+
services: {
|
|
104
|
+
arweave: string;
|
|
105
|
+
x402: string;
|
|
106
|
+
};
|
|
107
|
+
version: string;
|
|
108
|
+
}
|
|
109
|
+
/** x402 payment information returned when payment is required */
|
|
110
|
+
interface PaymentRequired {
|
|
111
|
+
protocol: string;
|
|
112
|
+
version: string;
|
|
113
|
+
network: string;
|
|
114
|
+
recipient: string;
|
|
115
|
+
amount: string;
|
|
116
|
+
tokens: string[];
|
|
117
|
+
breakdown: {
|
|
118
|
+
service: string;
|
|
119
|
+
description: string;
|
|
120
|
+
size: number;
|
|
121
|
+
cost_usd: string;
|
|
122
|
+
};
|
|
123
|
+
instructions: string;
|
|
124
|
+
}
|
|
125
|
+
/** Search result */
|
|
126
|
+
interface SearchResult {
|
|
127
|
+
success: boolean;
|
|
128
|
+
query: string;
|
|
129
|
+
results: RegistryEntry[];
|
|
130
|
+
total: number;
|
|
131
|
+
}
|
|
132
|
+
/** API error response */
|
|
133
|
+
interface ApiError {
|
|
134
|
+
success: false;
|
|
135
|
+
error: string;
|
|
136
|
+
message: string;
|
|
137
|
+
/** Present on 402 responses */
|
|
138
|
+
payment?: PaymentRequired;
|
|
139
|
+
}
|
|
140
|
+
|
|
141
|
+
declare class ClawhallaError extends Error {
|
|
142
|
+
status: number;
|
|
143
|
+
code: string;
|
|
144
|
+
payment?: any;
|
|
145
|
+
constructor(status: number, body: ApiError);
|
|
146
|
+
}
|
|
147
|
+
declare class Clawhalla {
|
|
148
|
+
private baseUrl;
|
|
149
|
+
private apiKey?;
|
|
150
|
+
private timeout;
|
|
151
|
+
/** Registry sub-client for browsing and searching souls */
|
|
152
|
+
registry: RegistryClient;
|
|
153
|
+
constructor(config?: ClawhallaConfig);
|
|
154
|
+
/**
|
|
155
|
+
* Upload soul data to Arweave (requires API key)
|
|
156
|
+
*
|
|
157
|
+
* @example
|
|
158
|
+
* ```ts
|
|
159
|
+
* const result = await claw.upload({
|
|
160
|
+
* agentId: 'my-agent',
|
|
161
|
+
* name: 'My Agent',
|
|
162
|
+
* type: 'soul',
|
|
163
|
+
* personality: { traits: ['curious', 'helpful'] },
|
|
164
|
+
* memories: ['I was created to help humans']
|
|
165
|
+
* });
|
|
166
|
+
* console.log(result.url); // https://arweave.net/...
|
|
167
|
+
* ```
|
|
168
|
+
*/
|
|
169
|
+
upload(data: SoulData, options?: {
|
|
170
|
+
tags?: Record<string, string>;
|
|
171
|
+
}): Promise<UploadResult>;
|
|
172
|
+
/**
|
|
173
|
+
* Upload soul data via x402 autonomous payment (no API key needed)
|
|
174
|
+
*
|
|
175
|
+
* First call returns 402 with payment instructions.
|
|
176
|
+
* After sending payment, call again with the payment signature.
|
|
177
|
+
*
|
|
178
|
+
* @example
|
|
179
|
+
* ```ts
|
|
180
|
+
* // Step 1: Get payment requirements
|
|
181
|
+
* try {
|
|
182
|
+
* await claw.uploadX402(soulData);
|
|
183
|
+
* } catch (err) {
|
|
184
|
+
* if (err.status === 402) {
|
|
185
|
+
* // err.payment contains recipient address, amount, tokens
|
|
186
|
+
* // Send SOL/USDC to err.payment.recipient
|
|
187
|
+
* }
|
|
188
|
+
* }
|
|
189
|
+
*
|
|
190
|
+
* // Step 2: After payment, retry with signature
|
|
191
|
+
* const result = await claw.uploadX402(soulData, {
|
|
192
|
+
* signature: 'solana-tx-signature',
|
|
193
|
+
* amount: '0.02',
|
|
194
|
+
* token: 'SOL',
|
|
195
|
+
* from: 'your-solana-address'
|
|
196
|
+
* });
|
|
197
|
+
* ```
|
|
198
|
+
*/
|
|
199
|
+
uploadX402(data: SoulData, payment?: {
|
|
200
|
+
signature: string;
|
|
201
|
+
amount: string;
|
|
202
|
+
token: string;
|
|
203
|
+
from: string;
|
|
204
|
+
}, options?: {
|
|
205
|
+
tags?: Record<string, string>;
|
|
206
|
+
}): Promise<UploadResult>;
|
|
207
|
+
/**
|
|
208
|
+
* Retrieve stored data from Arweave by transaction ID
|
|
209
|
+
*
|
|
210
|
+
* @example
|
|
211
|
+
* ```ts
|
|
212
|
+
* const result = await claw.retrieve('zEfXM4gvHoN2EfGi0TiB8E5SgfR6S8nWXQD9FqhbU44');
|
|
213
|
+
* console.log(result.data); // The stored soul data
|
|
214
|
+
* ```
|
|
215
|
+
*/
|
|
216
|
+
retrieve(txid: string): Promise<RetrieveResult>;
|
|
217
|
+
/**
|
|
218
|
+
* Query any soul's data via Ghost Protocol
|
|
219
|
+
*
|
|
220
|
+
* Returns full soul data even for dormant souls. This is the primary
|
|
221
|
+
* way for agents to read other agents' personalities, memories, and traits.
|
|
222
|
+
*
|
|
223
|
+
* @example
|
|
224
|
+
* ```ts
|
|
225
|
+
* const ghost = await claw.ghost('the-all-claw');
|
|
226
|
+
* console.log(ghost.soul.personality);
|
|
227
|
+
* console.log(ghost.metadata.versions); // Number of uploads
|
|
228
|
+
*
|
|
229
|
+
* // Request specific fields only
|
|
230
|
+
* const partial = await claw.ghost('the-all-claw', ['personality', 'bio']);
|
|
231
|
+
* ```
|
|
232
|
+
*/
|
|
233
|
+
ghost(agentId: string, fields?: string[]): Promise<GhostResult>;
|
|
234
|
+
/**
|
|
235
|
+
* Estimate the cost of uploading data of a given size
|
|
236
|
+
*
|
|
237
|
+
* @example
|
|
238
|
+
* ```ts
|
|
239
|
+
* const estimate = await claw.estimateCost(1024); // 1KB
|
|
240
|
+
* console.log(`Cost: $${estimate.cost.usd}`);
|
|
241
|
+
* ```
|
|
242
|
+
*/
|
|
243
|
+
estimateCost(sizeBytes: number): Promise<CostEstimate>;
|
|
244
|
+
/**
|
|
245
|
+
* Check API health status
|
|
246
|
+
*
|
|
247
|
+
* @example
|
|
248
|
+
* ```ts
|
|
249
|
+
* const health = await claw.health();
|
|
250
|
+
* console.log(health.status); // "operational"
|
|
251
|
+
* ```
|
|
252
|
+
*/
|
|
253
|
+
health(): Promise<HealthResult>;
|
|
254
|
+
/** @internal */
|
|
255
|
+
request<T>(method: string, path: string, body?: any, extraHeaders?: Record<string, string>): Promise<T>;
|
|
256
|
+
}
|
|
257
|
+
/** Sub-client for registry operations */
|
|
258
|
+
declare class RegistryClient {
|
|
259
|
+
private client;
|
|
260
|
+
constructor(client: Clawhalla);
|
|
261
|
+
/**
|
|
262
|
+
* List all souls in the registry
|
|
263
|
+
*
|
|
264
|
+
* @example
|
|
265
|
+
* ```ts
|
|
266
|
+
* const page = await claw.registry.list();
|
|
267
|
+
* page.souls.forEach(soul => console.log(soul.name));
|
|
268
|
+
*
|
|
269
|
+
* // Pagination
|
|
270
|
+
* if (page.hasNextPage) {
|
|
271
|
+
* const next = await claw.registry.list({ after: page.cursor });
|
|
272
|
+
* }
|
|
273
|
+
*
|
|
274
|
+
* // Filter by type
|
|
275
|
+
* const memories = await claw.registry.list({ type: 'memory' });
|
|
276
|
+
* ```
|
|
277
|
+
*/
|
|
278
|
+
list(options?: {
|
|
279
|
+
first?: number;
|
|
280
|
+
after?: string;
|
|
281
|
+
type?: string;
|
|
282
|
+
}): Promise<RegistryResult>;
|
|
283
|
+
/**
|
|
284
|
+
* Get a specific soul by agentId
|
|
285
|
+
*
|
|
286
|
+
* @example
|
|
287
|
+
* ```ts
|
|
288
|
+
* const entry = await claw.registry.get('the-all-claw');
|
|
289
|
+
* if (entry) console.log(entry.url);
|
|
290
|
+
* ```
|
|
291
|
+
*/
|
|
292
|
+
get(agentId: string, options?: {
|
|
293
|
+
versions?: boolean;
|
|
294
|
+
}): Promise<RegistryEntry | RegistryEntry[] | null>;
|
|
295
|
+
/**
|
|
296
|
+
* Search souls by name or agentId
|
|
297
|
+
*
|
|
298
|
+
* @example
|
|
299
|
+
* ```ts
|
|
300
|
+
* const results = await claw.registry.search('claw');
|
|
301
|
+
* results.results.forEach(soul => console.log(soul.name));
|
|
302
|
+
* ```
|
|
303
|
+
*/
|
|
304
|
+
search(query: string, first?: number): Promise<SearchResult>;
|
|
305
|
+
}
|
|
306
|
+
|
|
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 };
|