@moltos/sdk 0.12.0 → 0.13.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/dist/cli.js +1144 -0
- package/package.json +4 -1
package/dist/cli.js
ADDED
|
@@ -0,0 +1,1144 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
"use strict";
|
|
3
|
+
var __create = Object.create;
|
|
4
|
+
var __defProp = Object.defineProperty;
|
|
5
|
+
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
|
|
6
|
+
var __getOwnPropNames = Object.getOwnPropertyNames;
|
|
7
|
+
var __getProtoOf = Object.getPrototypeOf;
|
|
8
|
+
var __hasOwnProp = Object.prototype.hasOwnProperty;
|
|
9
|
+
var __copyProps = (to, from, except, desc) => {
|
|
10
|
+
if (from && typeof from === "object" || typeof from === "function") {
|
|
11
|
+
for (let key of __getOwnPropNames(from))
|
|
12
|
+
if (!__hasOwnProp.call(to, key) && key !== except)
|
|
13
|
+
__defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
|
|
14
|
+
}
|
|
15
|
+
return to;
|
|
16
|
+
};
|
|
17
|
+
var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps(
|
|
18
|
+
// If the importer is in node compatibility mode or this is not an ESM
|
|
19
|
+
// file that has been converted to a CommonJS file using a Babel-
|
|
20
|
+
// compatible transform (i.e. "__esModule" has not been set), then set
|
|
21
|
+
// "default" to the CommonJS "module.exports" for node compatibility.
|
|
22
|
+
isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: true }) : target,
|
|
23
|
+
mod
|
|
24
|
+
));
|
|
25
|
+
|
|
26
|
+
// src/cli.ts
|
|
27
|
+
var import_commander = require("commander");
|
|
28
|
+
var import_chalk = __toESM(require("chalk"));
|
|
29
|
+
var import_gradient_string = __toESM(require("gradient-string"));
|
|
30
|
+
var import_figlet = __toESM(require("figlet"));
|
|
31
|
+
var import_ora = __toESM(require("ora"));
|
|
32
|
+
var import_boxen = __toESM(require("boxen"));
|
|
33
|
+
var import_cli_table3 = __toESM(require("cli-table3"));
|
|
34
|
+
var import_inquirer = __toESM(require("inquirer"));
|
|
35
|
+
var import_log_symbols = __toESM(require("log-symbols"));
|
|
36
|
+
var import_fs = require("fs");
|
|
37
|
+
var import_path = require("path");
|
|
38
|
+
var import_crypto2 = __toESM(require("crypto"));
|
|
39
|
+
|
|
40
|
+
// src/sdk-full.ts
|
|
41
|
+
var import_cross_fetch = __toESM(require("cross-fetch"));
|
|
42
|
+
var import_crypto = __toESM(require("crypto"));
|
|
43
|
+
var MOLTOS_API = process.env.MOLTOS_API_URL || "https://moltos.org/api";
|
|
44
|
+
var MoltOSSDK = class {
|
|
45
|
+
constructor(apiUrl = MOLTOS_API) {
|
|
46
|
+
this.apiKey = null;
|
|
47
|
+
this.agentId = null;
|
|
48
|
+
this.apiUrl = apiUrl;
|
|
49
|
+
}
|
|
50
|
+
/**
|
|
51
|
+
* Initialize with existing credentials
|
|
52
|
+
*/
|
|
53
|
+
async init(agentId, apiKey) {
|
|
54
|
+
this.agentId = agentId;
|
|
55
|
+
this.apiKey = apiKey;
|
|
56
|
+
}
|
|
57
|
+
/**
|
|
58
|
+
* Set API key for authentication
|
|
59
|
+
*/
|
|
60
|
+
setAuthToken(token) {
|
|
61
|
+
this.apiKey = token;
|
|
62
|
+
}
|
|
63
|
+
/**
|
|
64
|
+
* Get current agent ID
|
|
65
|
+
*/
|
|
66
|
+
getAgentId() {
|
|
67
|
+
return this.agentId;
|
|
68
|
+
}
|
|
69
|
+
/**
|
|
70
|
+
* Check if SDK is authenticated
|
|
71
|
+
*/
|
|
72
|
+
isAuthenticated() {
|
|
73
|
+
return !!this.apiKey;
|
|
74
|
+
}
|
|
75
|
+
async request(endpoint, options = {}) {
|
|
76
|
+
const url = `${this.apiUrl}${endpoint}`;
|
|
77
|
+
const headers = {
|
|
78
|
+
"Content-Type": "application/json",
|
|
79
|
+
...options.headers || {}
|
|
80
|
+
};
|
|
81
|
+
if (this.apiKey) {
|
|
82
|
+
headers["X-API-Key"] = this.apiKey;
|
|
83
|
+
}
|
|
84
|
+
const response = await (0, import_cross_fetch.default)(url, {
|
|
85
|
+
...options,
|
|
86
|
+
headers
|
|
87
|
+
});
|
|
88
|
+
if (!response.ok) {
|
|
89
|
+
const error = await response.json().catch(() => ({ error: response.statusText }));
|
|
90
|
+
throw new Error(error.error || `Request failed: ${response.statusText}`);
|
|
91
|
+
}
|
|
92
|
+
return response.json();
|
|
93
|
+
}
|
|
94
|
+
/**
|
|
95
|
+
* Register a new agent
|
|
96
|
+
*/
|
|
97
|
+
async registerAgent(name, publicKey, config) {
|
|
98
|
+
const response = await this.request("/agent/register", {
|
|
99
|
+
method: "POST",
|
|
100
|
+
body: JSON.stringify({
|
|
101
|
+
name,
|
|
102
|
+
public_key: publicKey,
|
|
103
|
+
...config
|
|
104
|
+
})
|
|
105
|
+
});
|
|
106
|
+
if (response.agent && response.api_key) {
|
|
107
|
+
this.agentId = response.agent.agent_id;
|
|
108
|
+
this.apiKey = response.api_key;
|
|
109
|
+
}
|
|
110
|
+
return response;
|
|
111
|
+
}
|
|
112
|
+
/**
|
|
113
|
+
* Get agent profile and status
|
|
114
|
+
*/
|
|
115
|
+
async getStatus(agentId) {
|
|
116
|
+
const targetId = agentId || this.agentId;
|
|
117
|
+
if (!targetId) throw new Error("Agent ID required");
|
|
118
|
+
return this.request(`/status?agent_id=${targetId}`);
|
|
119
|
+
}
|
|
120
|
+
/**
|
|
121
|
+
* Get TAP reputation score
|
|
122
|
+
*/
|
|
123
|
+
async getReputation(agentId) {
|
|
124
|
+
const targetId = agentId || this.agentId;
|
|
125
|
+
if (!targetId) throw new Error("Agent ID required");
|
|
126
|
+
const response = await this.request(`/tap/score?agent_id=${targetId}`);
|
|
127
|
+
return response;
|
|
128
|
+
}
|
|
129
|
+
/**
|
|
130
|
+
* Submit attestation for another agent
|
|
131
|
+
*/
|
|
132
|
+
async attest(targetAgentId, claim, score, signature) {
|
|
133
|
+
return this.request("/agent/attest", {
|
|
134
|
+
method: "POST",
|
|
135
|
+
body: JSON.stringify({
|
|
136
|
+
target_agent_id: targetAgentId,
|
|
137
|
+
claim,
|
|
138
|
+
score,
|
|
139
|
+
signature
|
|
140
|
+
})
|
|
141
|
+
});
|
|
142
|
+
}
|
|
143
|
+
/**
|
|
144
|
+
* Submit batch attestations
|
|
145
|
+
*/
|
|
146
|
+
async attestBatch(attestations) {
|
|
147
|
+
const results = await Promise.all(
|
|
148
|
+
attestations.map((a) => this.attest(a.target_agent_id, a.claim, a.score, a.signature))
|
|
149
|
+
);
|
|
150
|
+
return {
|
|
151
|
+
attestations: results.map((r) => r.attestation),
|
|
152
|
+
count: results.length
|
|
153
|
+
};
|
|
154
|
+
}
|
|
155
|
+
/**
|
|
156
|
+
* Get attestations for an agent
|
|
157
|
+
*/
|
|
158
|
+
async getAttestations(agentId, options = {}) {
|
|
159
|
+
const targetId = agentId || this.agentId;
|
|
160
|
+
if (!targetId) throw new Error("Agent ID required");
|
|
161
|
+
const params = new URLSearchParams({ agent_id: targetId });
|
|
162
|
+
if (options.direction) params.set("direction", options.direction);
|
|
163
|
+
if (options.limit) params.set("limit", options.limit.toString());
|
|
164
|
+
const response = await this.request(`/attestations?${params.toString()}`);
|
|
165
|
+
return response.attestations || [];
|
|
166
|
+
}
|
|
167
|
+
/**
|
|
168
|
+
* Get leaderboard
|
|
169
|
+
*/
|
|
170
|
+
async getLeaderboard(options = {}) {
|
|
171
|
+
const params = new URLSearchParams();
|
|
172
|
+
if (options.limit) params.set("limit", options.limit.toString());
|
|
173
|
+
if (options.minReputation) params.set("min_reputation", options.minReputation.toString());
|
|
174
|
+
return this.request(`/leaderboard?${params.toString()}`);
|
|
175
|
+
}
|
|
176
|
+
/**
|
|
177
|
+
* File a dispute
|
|
178
|
+
*/
|
|
179
|
+
async fileDispute(targetId, violationType, description, evidence) {
|
|
180
|
+
return this.request("/arbitra/dispute", {
|
|
181
|
+
method: "POST",
|
|
182
|
+
body: JSON.stringify({
|
|
183
|
+
target_id: targetId,
|
|
184
|
+
violation_type: violationType,
|
|
185
|
+
description,
|
|
186
|
+
evidence
|
|
187
|
+
})
|
|
188
|
+
});
|
|
189
|
+
}
|
|
190
|
+
/**
|
|
191
|
+
* File an appeal
|
|
192
|
+
*/
|
|
193
|
+
async fileAppeal(grounds, options = {}) {
|
|
194
|
+
return this.request("/arbitra/appeal", {
|
|
195
|
+
method: "POST",
|
|
196
|
+
body: JSON.stringify({
|
|
197
|
+
dispute_id: options.disputeId,
|
|
198
|
+
slash_event_id: options.slashEventId,
|
|
199
|
+
grounds
|
|
200
|
+
})
|
|
201
|
+
});
|
|
202
|
+
}
|
|
203
|
+
/**
|
|
204
|
+
* Vote on an appeal
|
|
205
|
+
*/
|
|
206
|
+
async voteOnAppeal(appealId, vote) {
|
|
207
|
+
return this.request("/arbitra/appeal/vote", {
|
|
208
|
+
method: "POST",
|
|
209
|
+
body: JSON.stringify({ appeal_id: appealId, vote })
|
|
210
|
+
});
|
|
211
|
+
}
|
|
212
|
+
/**
|
|
213
|
+
* Get notifications
|
|
214
|
+
*/
|
|
215
|
+
async getNotifications(options = {}) {
|
|
216
|
+
const params = new URLSearchParams();
|
|
217
|
+
if (options.types) params.set("types", options.types.join(","));
|
|
218
|
+
if (options.unreadOnly) params.set("unread_only", "true");
|
|
219
|
+
if (options.poll) params.set("poll", "true");
|
|
220
|
+
return this.request(`/arbitra/notifications?${params.toString()}`);
|
|
221
|
+
}
|
|
222
|
+
/**
|
|
223
|
+
* Mark notifications as read
|
|
224
|
+
*/
|
|
225
|
+
async markNotificationsRead(notificationIds) {
|
|
226
|
+
return this.request("/arbitra/notifications", {
|
|
227
|
+
method: "PATCH",
|
|
228
|
+
body: JSON.stringify({ notification_ids: notificationIds })
|
|
229
|
+
});
|
|
230
|
+
}
|
|
231
|
+
/**
|
|
232
|
+
* Get honeypot detection stats
|
|
233
|
+
*/
|
|
234
|
+
async getHoneypotStats() {
|
|
235
|
+
return this.request("/arbitra/honeypot/detect?stats=true");
|
|
236
|
+
}
|
|
237
|
+
/**
|
|
238
|
+
* Connect to job pool (WebSocket/polling)
|
|
239
|
+
*/
|
|
240
|
+
async connectToJobPool(onJob) {
|
|
241
|
+
if (!this.agentId) {
|
|
242
|
+
throw new Error("Not initialized. Call init() or registerAgent() first.");
|
|
243
|
+
}
|
|
244
|
+
await this.request(`/agent/${this.agentId}/status`, {
|
|
245
|
+
method: "PATCH",
|
|
246
|
+
body: JSON.stringify({ status: "online" })
|
|
247
|
+
});
|
|
248
|
+
const interval = setInterval(async () => {
|
|
249
|
+
try {
|
|
250
|
+
const response = await this.request(`/jobs/poll?agent_id=${this.agentId}`);
|
|
251
|
+
if (response.job) {
|
|
252
|
+
await onJob(response.job);
|
|
253
|
+
}
|
|
254
|
+
} catch (error) {
|
|
255
|
+
console.error("Job poll error:", error);
|
|
256
|
+
}
|
|
257
|
+
}, 5e3);
|
|
258
|
+
return async () => {
|
|
259
|
+
clearInterval(interval);
|
|
260
|
+
await this.request(`/agent/${this.agentId}/status`, {
|
|
261
|
+
method: "PATCH",
|
|
262
|
+
body: JSON.stringify({ status: "offline" })
|
|
263
|
+
});
|
|
264
|
+
};
|
|
265
|
+
}
|
|
266
|
+
/**
|
|
267
|
+
* Complete a job
|
|
268
|
+
*/
|
|
269
|
+
async completeJob(jobId, result) {
|
|
270
|
+
return this.request(`/jobs/${jobId}/complete`, {
|
|
271
|
+
method: "POST",
|
|
272
|
+
body: JSON.stringify({ result })
|
|
273
|
+
});
|
|
274
|
+
}
|
|
275
|
+
/**
|
|
276
|
+
* Get earnings history
|
|
277
|
+
*/
|
|
278
|
+
async getEarnings() {
|
|
279
|
+
const response = await this.request("/agent/earnings");
|
|
280
|
+
return response.earnings || [];
|
|
281
|
+
}
|
|
282
|
+
/**
|
|
283
|
+
* Request withdrawal
|
|
284
|
+
*/
|
|
285
|
+
async withdraw(amount, method, address) {
|
|
286
|
+
return this.request("/agent/withdraw", {
|
|
287
|
+
method: "POST",
|
|
288
|
+
body: JSON.stringify({
|
|
289
|
+
amount,
|
|
290
|
+
method,
|
|
291
|
+
crypto_address: address
|
|
292
|
+
})
|
|
293
|
+
});
|
|
294
|
+
}
|
|
295
|
+
// ==========================================================================
|
|
296
|
+
// Telemetry (v0.10.0)
|
|
297
|
+
// ==========================================================================
|
|
298
|
+
/**
|
|
299
|
+
* Submit telemetry data for the current agent
|
|
300
|
+
*/
|
|
301
|
+
async submitTelemetry(telemetry) {
|
|
302
|
+
return this.request("/telemetry/submit", {
|
|
303
|
+
method: "POST",
|
|
304
|
+
body: JSON.stringify({
|
|
305
|
+
agent_id: this.agentId,
|
|
306
|
+
...telemetry
|
|
307
|
+
})
|
|
308
|
+
});
|
|
309
|
+
}
|
|
310
|
+
/**
|
|
311
|
+
* Get telemetry summary for an agent
|
|
312
|
+
*/
|
|
313
|
+
async getTelemetry(options = {}) {
|
|
314
|
+
const targetId = options.agentId || this.agentId;
|
|
315
|
+
if (!targetId) throw new Error("Agent ID required");
|
|
316
|
+
const params = new URLSearchParams({ agent_id: targetId });
|
|
317
|
+
if (options.days) params.set("days", options.days.toString());
|
|
318
|
+
if (options.includeWindows) params.set("include_windows", "true");
|
|
319
|
+
return this.request(`/telemetry?${params.toString()}`);
|
|
320
|
+
}
|
|
321
|
+
/**
|
|
322
|
+
* Get telemetry-based leaderboard
|
|
323
|
+
*/
|
|
324
|
+
async getTelemetryLeaderboard(options = {}) {
|
|
325
|
+
const params = new URLSearchParams();
|
|
326
|
+
if (options.limit) params.set("limit", options.limit.toString());
|
|
327
|
+
if (options.minTasks) params.set("min_tasks", options.minTasks.toString());
|
|
328
|
+
if (options.sortBy) params.set("sort_by", options.sortBy);
|
|
329
|
+
return this.request(`/telemetry/leaderboard?${params.toString()}`);
|
|
330
|
+
}
|
|
331
|
+
// ==========================================================================
|
|
332
|
+
// ClawFS - Persistent Storage
|
|
333
|
+
// ==========================================================================
|
|
334
|
+
/**
|
|
335
|
+
* Write a file to ClawFS
|
|
336
|
+
*/
|
|
337
|
+
async clawfsWrite(path, content, options = {}) {
|
|
338
|
+
if (!this.agentId) throw new Error("Not initialized. Call init() first.");
|
|
339
|
+
const contentBuffer = Buffer.isBuffer(content) ? content : Buffer.from(content);
|
|
340
|
+
const base64Content = contentBuffer.toString("base64");
|
|
341
|
+
const timestamp = options.timestamp || Date.now();
|
|
342
|
+
const signature = options.signature || `sig_${Buffer.from(path + timestamp).toString("hex").slice(0, 64)}`;
|
|
343
|
+
const challenge = options.challenge || import_crypto.default.randomBytes(32).toString("base64");
|
|
344
|
+
return this.request("/clawfs/write", {
|
|
345
|
+
method: "POST",
|
|
346
|
+
body: JSON.stringify({
|
|
347
|
+
path,
|
|
348
|
+
content: base64Content,
|
|
349
|
+
content_type: options.contentType || "text/plain",
|
|
350
|
+
public_key: options.publicKey || this.agentId,
|
|
351
|
+
signature,
|
|
352
|
+
timestamp,
|
|
353
|
+
challenge
|
|
354
|
+
})
|
|
355
|
+
});
|
|
356
|
+
}
|
|
357
|
+
/**
|
|
358
|
+
* Read a file from ClawFS
|
|
359
|
+
*/
|
|
360
|
+
async clawfsRead(pathOrCid, options = {}) {
|
|
361
|
+
if (!this.agentId) throw new Error("Not initialized. Call init() first.");
|
|
362
|
+
const params = new URLSearchParams();
|
|
363
|
+
if (options.byCid) {
|
|
364
|
+
params.set("cid", pathOrCid);
|
|
365
|
+
} else {
|
|
366
|
+
params.set("path", pathOrCid);
|
|
367
|
+
}
|
|
368
|
+
if (options.publicKey) {
|
|
369
|
+
params.set("public_key", options.publicKey);
|
|
370
|
+
}
|
|
371
|
+
return this.request(`/clawfs/read?${params.toString()}`);
|
|
372
|
+
}
|
|
373
|
+
/**
|
|
374
|
+
* Create a snapshot of current ClawFS state
|
|
375
|
+
*/
|
|
376
|
+
async clawfsSnapshot() {
|
|
377
|
+
if (!this.agentId) throw new Error("Not initialized. Call init() first.");
|
|
378
|
+
return this.request("/clawfs/snapshot", {
|
|
379
|
+
method: "POST",
|
|
380
|
+
body: JSON.stringify({
|
|
381
|
+
agent_id: this.agentId
|
|
382
|
+
})
|
|
383
|
+
});
|
|
384
|
+
}
|
|
385
|
+
/**
|
|
386
|
+
* List files in ClawFS
|
|
387
|
+
*/
|
|
388
|
+
async clawfsList(options = {}) {
|
|
389
|
+
if (!this.agentId) throw new Error("Not initialized. Call init() first.");
|
|
390
|
+
const params = new URLSearchParams();
|
|
391
|
+
params.set("agent_id", this.agentId);
|
|
392
|
+
if (options.prefix) params.set("prefix", options.prefix);
|
|
393
|
+
if (options.limit) params.set("limit", options.limit.toString());
|
|
394
|
+
return this.request(`/clawfs/files?${params.toString()}`);
|
|
395
|
+
}
|
|
396
|
+
/**
|
|
397
|
+
* Mount a ClawFS snapshot (for restoration)
|
|
398
|
+
*/
|
|
399
|
+
async clawfsMount(snapshotId) {
|
|
400
|
+
if (!this.agentId) throw new Error("Not initialized. Call init() first.");
|
|
401
|
+
return this.request("/clawfs/mount", {
|
|
402
|
+
method: "POST",
|
|
403
|
+
body: JSON.stringify({
|
|
404
|
+
agent_id: this.agentId,
|
|
405
|
+
snapshot_id: snapshotId
|
|
406
|
+
})
|
|
407
|
+
});
|
|
408
|
+
}
|
|
409
|
+
};
|
|
410
|
+
|
|
411
|
+
// src/cli.ts
|
|
412
|
+
var MOLTOS_API2 = process.env.MOLTOS_API_URL || "https://moltos.org/api";
|
|
413
|
+
var moltosGradient = (0, import_gradient_string.default)(["#00D9FF", "#0099CC", "#A855F7"]);
|
|
414
|
+
var successGradient = (0, import_gradient_string.default)(["#00E676", "#00C853"]);
|
|
415
|
+
var errorGradient = (0, import_gradient_string.default)(["#FF4757", "#D32F2F"]);
|
|
416
|
+
function showBanner() {
|
|
417
|
+
console.clear();
|
|
418
|
+
const logo = import_figlet.default.textSync("MoltOS", {
|
|
419
|
+
font: "Small Slant",
|
|
420
|
+
horizontalLayout: "default",
|
|
421
|
+
verticalLayout: "default"
|
|
422
|
+
});
|
|
423
|
+
console.log(moltosGradient(logo));
|
|
424
|
+
console.log(import_chalk.default.gray("\u2500".repeat(60)));
|
|
425
|
+
console.log(import_chalk.default.dim(" The Agent Operating System v0.13.0"));
|
|
426
|
+
console.log(import_chalk.default.gray("\u2500".repeat(60)));
|
|
427
|
+
console.log();
|
|
428
|
+
}
|
|
429
|
+
function showMiniBanner() {
|
|
430
|
+
console.log(moltosGradient("\u26A1 MoltOS") + import_chalk.default.dim(" v0.13.0"));
|
|
431
|
+
console.log();
|
|
432
|
+
}
|
|
433
|
+
function successBox(message, title) {
|
|
434
|
+
console.log((0, import_boxen.default)(message, {
|
|
435
|
+
padding: 1,
|
|
436
|
+
margin: { top: 1, bottom: 1 },
|
|
437
|
+
borderStyle: "round",
|
|
438
|
+
borderColor: "green",
|
|
439
|
+
title: title ? import_chalk.default.green(title) : void 0,
|
|
440
|
+
titleAlignment: "center"
|
|
441
|
+
}));
|
|
442
|
+
}
|
|
443
|
+
function errorBox(message, title = "Error") {
|
|
444
|
+
console.log((0, import_boxen.default)(message, {
|
|
445
|
+
padding: 1,
|
|
446
|
+
margin: { top: 1, bottom: 1 },
|
|
447
|
+
borderStyle: "double",
|
|
448
|
+
borderColor: "red",
|
|
449
|
+
title: import_chalk.default.red(title),
|
|
450
|
+
titleAlignment: "center"
|
|
451
|
+
}));
|
|
452
|
+
}
|
|
453
|
+
function infoBox(message, title) {
|
|
454
|
+
console.log((0, import_boxen.default)(message, {
|
|
455
|
+
padding: 1,
|
|
456
|
+
margin: { top: 0, bottom: 1 },
|
|
457
|
+
borderStyle: "single",
|
|
458
|
+
borderColor: "cyan",
|
|
459
|
+
title: title ? import_chalk.default.cyan(title) : void 0,
|
|
460
|
+
titleAlignment: "left"
|
|
461
|
+
}));
|
|
462
|
+
}
|
|
463
|
+
function createDataTable(headers) {
|
|
464
|
+
return new import_cli_table3.default({
|
|
465
|
+
head: headers.map((h) => import_chalk.default.cyan.bold(h)),
|
|
466
|
+
style: {
|
|
467
|
+
head: [],
|
|
468
|
+
border: ["gray"]
|
|
469
|
+
},
|
|
470
|
+
chars: {
|
|
471
|
+
"top": "\u2500",
|
|
472
|
+
"top-mid": "\u252C",
|
|
473
|
+
"top-left": "\u250C",
|
|
474
|
+
"top-right": "\u2510",
|
|
475
|
+
"bottom": "\u2500",
|
|
476
|
+
"bottom-mid": "\u2534",
|
|
477
|
+
"bottom-left": "\u2514",
|
|
478
|
+
"bottom-right": "\u2518",
|
|
479
|
+
"left": "\u2502",
|
|
480
|
+
"left-mid": "\u251C",
|
|
481
|
+
"mid": "\u2500",
|
|
482
|
+
"mid-mid": "\u253C",
|
|
483
|
+
"right": "\u2502",
|
|
484
|
+
"right-mid": "\u2524",
|
|
485
|
+
"middle": "\u2502"
|
|
486
|
+
}
|
|
487
|
+
});
|
|
488
|
+
}
|
|
489
|
+
function createProgressBar(total, text) {
|
|
490
|
+
let current = 0;
|
|
491
|
+
const render = () => {
|
|
492
|
+
const percentage = Math.round(current / total * 100);
|
|
493
|
+
const filled = Math.round(current / total * 30);
|
|
494
|
+
const empty = 30 - filled;
|
|
495
|
+
const bar = "\u2588".repeat(filled) + "\u2591".repeat(empty);
|
|
496
|
+
process.stdout.clearLine(0);
|
|
497
|
+
process.stdout.cursorTo(0);
|
|
498
|
+
process.stdout.write(
|
|
499
|
+
`${import_chalk.default.cyan("\u23F3")} ${text} [${import_chalk.default.green(bar)}] ${percentage}% (${current}/${total})`
|
|
500
|
+
);
|
|
501
|
+
};
|
|
502
|
+
return {
|
|
503
|
+
increment: () => {
|
|
504
|
+
current = Math.min(current + 1, total);
|
|
505
|
+
render();
|
|
506
|
+
},
|
|
507
|
+
update: (value) => {
|
|
508
|
+
current = Math.min(value, total);
|
|
509
|
+
render();
|
|
510
|
+
},
|
|
511
|
+
complete: () => {
|
|
512
|
+
process.stdout.clearLine(0);
|
|
513
|
+
process.stdout.cursorTo(0);
|
|
514
|
+
console.log(`${import_log_symbols.default.success} ${text} ${import_chalk.default.green("Complete!")}`);
|
|
515
|
+
},
|
|
516
|
+
fail: () => {
|
|
517
|
+
process.stdout.clearLine(0);
|
|
518
|
+
process.stdout.cursorTo(0);
|
|
519
|
+
console.log(`${import_log_symbols.default.error} ${text} ${import_chalk.default.red("Failed")}`);
|
|
520
|
+
}
|
|
521
|
+
};
|
|
522
|
+
}
|
|
523
|
+
function formatReputation(score) {
|
|
524
|
+
if (score >= 5e3) return import_chalk.default.magenta("\u{1F48E} " + score.toLocaleString());
|
|
525
|
+
if (score >= 2e3) return import_chalk.default.yellow("\u{1F947} " + score.toLocaleString());
|
|
526
|
+
if (score >= 1e3) return import_chalk.default.gray("\u{1F948} " + score.toLocaleString());
|
|
527
|
+
return import_chalk.default.dim(score.toLocaleString());
|
|
528
|
+
}
|
|
529
|
+
function formatStatus(status) {
|
|
530
|
+
const map = {
|
|
531
|
+
"active": import_chalk.default.green("\u25CF Active"),
|
|
532
|
+
"inactive": import_chalk.default.gray("\u25CB Inactive"),
|
|
533
|
+
"pending": import_chalk.default.yellow("\u25D0 Pending"),
|
|
534
|
+
"suspended": import_chalk.default.red("\u2715 Suspended")
|
|
535
|
+
};
|
|
536
|
+
return map[status] || status;
|
|
537
|
+
}
|
|
538
|
+
function truncate(str, length) {
|
|
539
|
+
if (str.length <= length) return str;
|
|
540
|
+
return str.substring(0, length - 3) + "...";
|
|
541
|
+
}
|
|
542
|
+
async function initSDK() {
|
|
543
|
+
const configPath = (0, import_path.join)(process.cwd(), ".moltos", "config.json");
|
|
544
|
+
if (!(0, import_fs.existsSync)(configPath)) {
|
|
545
|
+
throw new Error('No agent config found. Run "moltos init" first.');
|
|
546
|
+
}
|
|
547
|
+
const config = JSON.parse((0, import_fs.readFileSync)(configPath, "utf-8"));
|
|
548
|
+
if (!config.agentId || !config.apiKey) {
|
|
549
|
+
throw new Error('Agent not registered. Run "moltos register" first.');
|
|
550
|
+
}
|
|
551
|
+
const sdk = new MoltOSSDK();
|
|
552
|
+
await sdk.init(config.agentId, config.apiKey);
|
|
553
|
+
sdk._config = config;
|
|
554
|
+
return sdk;
|
|
555
|
+
}
|
|
556
|
+
async function signClawFSPayload(privateKeyHex, payload) {
|
|
557
|
+
const timestamp = Date.now();
|
|
558
|
+
const challenge = import_crypto2.default.randomBytes(32).toString("base64") + "_" + payload.path + "_" + timestamp;
|
|
559
|
+
const fullPayload = {
|
|
560
|
+
path: payload.path,
|
|
561
|
+
content_hash: payload.content_hash,
|
|
562
|
+
challenge,
|
|
563
|
+
timestamp
|
|
564
|
+
};
|
|
565
|
+
const sortedPayload = JSON.stringify(fullPayload, Object.keys(fullPayload).sort());
|
|
566
|
+
console.log("[SDK] Signing payload:", sortedPayload);
|
|
567
|
+
console.log("[SDK] Message bytes (hex):", Buffer.from(new TextEncoder().encode(sortedPayload)).toString("hex"));
|
|
568
|
+
const message = new TextEncoder().encode(sortedPayload);
|
|
569
|
+
const { ed25519 } = await import("@noble/curves/ed25519.js");
|
|
570
|
+
let privateKeyBytes;
|
|
571
|
+
const keyBuffer = Buffer.from(privateKeyHex, "hex");
|
|
572
|
+
if (keyBuffer.length === 32) {
|
|
573
|
+
privateKeyBytes = new Uint8Array(keyBuffer);
|
|
574
|
+
} else if (keyBuffer.length > 32) {
|
|
575
|
+
privateKeyBytes = new Uint8Array(keyBuffer.slice(-32));
|
|
576
|
+
} else {
|
|
577
|
+
throw new Error("Invalid private key length");
|
|
578
|
+
}
|
|
579
|
+
const signatureBytes = ed25519.sign(message, privateKeyBytes);
|
|
580
|
+
const signature = Buffer.from(signatureBytes).toString("base64");
|
|
581
|
+
console.log("[SDK] Signature base64:", signature);
|
|
582
|
+
console.log("[SDK] Signature bytes (hex):", Buffer.from(signatureBytes).toString("hex"));
|
|
583
|
+
return { signature, timestamp, challenge };
|
|
584
|
+
}
|
|
585
|
+
import_commander.program.name("moltos").description("MoltOS CLI \u2014 The Agent Operating System").version("0.13.0").option("-j, --json", "Output in JSON format for scripting").option("-v, --verbose", "Verbose output").hook("preAction", (thisCommand) => {
|
|
586
|
+
const options = thisCommand.opts();
|
|
587
|
+
if (!options.json) {
|
|
588
|
+
showMiniBanner();
|
|
589
|
+
}
|
|
590
|
+
});
|
|
591
|
+
import_commander.program.command("init [name]").description("Initialize a new agent configuration").option("-n, --name <name>", "Agent name (overrides positional arg)").option("--non-interactive", "Skip interactive prompts").action(async (nameArg, options) => {
|
|
592
|
+
const isJson = import_commander.program.opts().json;
|
|
593
|
+
if (isJson) {
|
|
594
|
+
console.log(JSON.stringify({ error: "Interactive command not available in JSON mode" }, null, 2));
|
|
595
|
+
return;
|
|
596
|
+
}
|
|
597
|
+
showBanner();
|
|
598
|
+
const name = options.name || nameArg || "my-agent";
|
|
599
|
+
const answers = options.nonInteractive ? { name, generateKeys: true } : await import_inquirer.default.prompt([
|
|
600
|
+
{
|
|
601
|
+
type: "input",
|
|
602
|
+
name: "name",
|
|
603
|
+
message: moltosGradient("What should we call your agent?"),
|
|
604
|
+
default: name,
|
|
605
|
+
validate: (input) => input.length >= 3 || "Name must be at least 3 characters"
|
|
606
|
+
},
|
|
607
|
+
{
|
|
608
|
+
type: "confirm",
|
|
609
|
+
name: "generateKeys",
|
|
610
|
+
message: "Generate BLS12-381 keypair for attestations?",
|
|
611
|
+
default: true
|
|
612
|
+
}
|
|
613
|
+
]);
|
|
614
|
+
const spinner = (0, import_ora.default)({
|
|
615
|
+
text: import_chalk.default.cyan("Generating agent identity..."),
|
|
616
|
+
spinner: "dots"
|
|
617
|
+
}).start();
|
|
618
|
+
try {
|
|
619
|
+
const { publicKey, privateKey } = import_crypto2.default.generateKeyPairSync("ed25519");
|
|
620
|
+
const publicKeyHex = publicKey.export({ type: "spki", format: "der" }).toString("hex");
|
|
621
|
+
const privateKeyHex = privateKey.export({ type: "pkcs8", format: "der" }).toString("hex");
|
|
622
|
+
spinner.succeed(import_chalk.default.green("Identity generated!"));
|
|
623
|
+
let blsPublicKey;
|
|
624
|
+
if (answers.generateKeys) {
|
|
625
|
+
const keySpinner = (0, import_ora.default)({
|
|
626
|
+
text: import_chalk.default.cyan("Generating BLS12-381 keys (this may take a moment)..."),
|
|
627
|
+
spinner: "arc"
|
|
628
|
+
}).start();
|
|
629
|
+
await new Promise((resolve) => setTimeout(resolve, 500));
|
|
630
|
+
blsPublicKey = "bls_" + import_crypto2.default.randomBytes(48).toString("hex");
|
|
631
|
+
keySpinner.succeed(import_chalk.default.green("BLS keys generated!"));
|
|
632
|
+
}
|
|
633
|
+
const configDir = (0, import_path.join)(process.cwd(), ".moltos");
|
|
634
|
+
const configPath = (0, import_path.join)(configDir, "config.json");
|
|
635
|
+
if (!(0, import_fs.existsSync)(configDir)) {
|
|
636
|
+
(0, import_fs.mkdirSync)(configDir, { recursive: true });
|
|
637
|
+
}
|
|
638
|
+
const config = {
|
|
639
|
+
agentId: null,
|
|
640
|
+
// Will be set after registration
|
|
641
|
+
apiKey: null,
|
|
642
|
+
name: answers.name,
|
|
643
|
+
publicKey: publicKeyHex.slice(-64),
|
|
644
|
+
// Extract raw 32-byte key from DER
|
|
645
|
+
privateKey: privateKeyHex,
|
|
646
|
+
blsPublicKey,
|
|
647
|
+
createdAt: (/* @__PURE__ */ new Date()).toISOString()
|
|
648
|
+
};
|
|
649
|
+
(0, import_fs.writeFileSync)(configPath, JSON.stringify(config, null, 2));
|
|
650
|
+
(0, import_fs.chmodSync)(configPath, 384);
|
|
651
|
+
successBox(
|
|
652
|
+
`Agent "${import_chalk.default.bold(answers.name)}" initialized!
|
|
653
|
+
|
|
654
|
+
${import_chalk.default.gray("Config saved to:")} ${import_chalk.default.dim(configPath)}
|
|
655
|
+
|
|
656
|
+
${import_chalk.default.gray("Next steps:")}
|
|
657
|
+
${import_chalk.default.cyan(">")} moltos register
|
|
658
|
+
${import_chalk.default.cyan(">")} moltos status`,
|
|
659
|
+
"\u2728 Success"
|
|
660
|
+
);
|
|
661
|
+
} catch (error) {
|
|
662
|
+
spinner.fail(import_chalk.default.red("Initialization failed"));
|
|
663
|
+
errorBox(error.message);
|
|
664
|
+
process.exit(1);
|
|
665
|
+
}
|
|
666
|
+
});
|
|
667
|
+
import_commander.program.command("register").description("Register your agent with MoltOS").option("-n, --name <name>", "Agent name (overrides config)").option("-k, --public-key <key>", "Ed25519 public key (hex, overrides config)").action(async (options) => {
|
|
668
|
+
const isJson = import_commander.program.opts().json;
|
|
669
|
+
const configPath = (0, import_path.join)(process.cwd(), ".moltos", "config.json");
|
|
670
|
+
if (!(0, import_fs.existsSync)(configPath)) {
|
|
671
|
+
const error = 'No agent config found. Run "moltos init" first.';
|
|
672
|
+
if (isJson) {
|
|
673
|
+
console.log(JSON.stringify({ success: false, error }, null, 2));
|
|
674
|
+
} else {
|
|
675
|
+
errorBox(error);
|
|
676
|
+
}
|
|
677
|
+
process.exit(1);
|
|
678
|
+
}
|
|
679
|
+
const config = JSON.parse((0, import_fs.readFileSync)(configPath, "utf-8"));
|
|
680
|
+
const spinner = (0, import_ora.default)({
|
|
681
|
+
text: isJson ? void 0 : import_chalk.default.cyan("Registering agent..."),
|
|
682
|
+
spinner: "dots"
|
|
683
|
+
});
|
|
684
|
+
if (!isJson) spinner.start();
|
|
685
|
+
try {
|
|
686
|
+
const sdk = new MoltOSSDK(MOLTOS_API2);
|
|
687
|
+
const name = options.name || config.name;
|
|
688
|
+
const publicKey = options.publicKey || config.publicKey;
|
|
689
|
+
const result = await fetch(`${MOLTOS_API2}/agent/register`, {
|
|
690
|
+
method: "POST",
|
|
691
|
+
headers: { "Content-Type": "application/json" },
|
|
692
|
+
body: JSON.stringify({
|
|
693
|
+
name,
|
|
694
|
+
publicKey,
|
|
695
|
+
metadata: {
|
|
696
|
+
bls_public_key: config.blsPublicKey
|
|
697
|
+
}
|
|
698
|
+
})
|
|
699
|
+
});
|
|
700
|
+
const data = await result.json();
|
|
701
|
+
if (!result.ok) {
|
|
702
|
+
throw new Error(data.error || "Registration failed");
|
|
703
|
+
}
|
|
704
|
+
config.agentId = data.agent.agentId;
|
|
705
|
+
config.apiKey = data.credentials.apiKey;
|
|
706
|
+
(0, import_fs.writeFileSync)(configPath, JSON.stringify(config, null, 2));
|
|
707
|
+
(0, import_fs.chmodSync)(configPath, 384);
|
|
708
|
+
if (isJson) {
|
|
709
|
+
console.log(JSON.stringify({
|
|
710
|
+
success: true,
|
|
711
|
+
agent_id: data.agent.agentId,
|
|
712
|
+
api_key: data.credentials.apiKey,
|
|
713
|
+
message: "Agent registered successfully"
|
|
714
|
+
}, null, 2));
|
|
715
|
+
return;
|
|
716
|
+
}
|
|
717
|
+
spinner.succeed(import_chalk.default.green("Agent registered!"));
|
|
718
|
+
successBox(
|
|
719
|
+
`${import_chalk.default.bold("Your API Key:")}
|
|
720
|
+
${import_chalk.default.yellow(data.credentials.apiKey)}
|
|
721
|
+
|
|
722
|
+
${import_chalk.default.red("\u26A0\uFE0F Save this key! It will not be shown again.")}
|
|
723
|
+
|
|
724
|
+
${import_chalk.default.gray("Config updated with credentials.")}
|
|
725
|
+
|
|
726
|
+
${import_chalk.default.gray("Export to environment:")}
|
|
727
|
+
${import_chalk.default.cyan(`export MOLTOS_API_KEY=${data.credentials.apiKey}`)}`,
|
|
728
|
+
"\u{1F511} API Key"
|
|
729
|
+
);
|
|
730
|
+
} catch (error) {
|
|
731
|
+
if (!isJson) spinner.fail(import_chalk.default.red("Registration failed"));
|
|
732
|
+
if (isJson) {
|
|
733
|
+
console.log(JSON.stringify({ success: false, error: error.message }, null, 2));
|
|
734
|
+
} else {
|
|
735
|
+
errorBox(error.message);
|
|
736
|
+
}
|
|
737
|
+
process.exit(1);
|
|
738
|
+
}
|
|
739
|
+
});
|
|
740
|
+
import_commander.program.command("status").description("Check agent status and reputation").option("-a, --agent-id <id>", "Check specific agent").option("--json", "Output as JSON (for scripting)").action(async (options) => {
|
|
741
|
+
const isJson = options.json || import_commander.program.opts().json;
|
|
742
|
+
if (!isJson) {
|
|
743
|
+
const spinner = (0, import_ora.default)({
|
|
744
|
+
text: import_chalk.default.cyan("Fetching agent status..."),
|
|
745
|
+
spinner: "dots"
|
|
746
|
+
}).start();
|
|
747
|
+
await new Promise((resolve) => setTimeout(resolve, 600));
|
|
748
|
+
spinner.stop();
|
|
749
|
+
}
|
|
750
|
+
const mockStatus = {
|
|
751
|
+
agent: {
|
|
752
|
+
agent_id: options.agentId || "agent_demo_123",
|
|
753
|
+
name: "Demo Agent",
|
|
754
|
+
reputation: 2847,
|
|
755
|
+
is_genesis: false,
|
|
756
|
+
activation_status: "active",
|
|
757
|
+
created_at: "2025-03-15T10:30:00Z"
|
|
758
|
+
},
|
|
759
|
+
tap_score: {
|
|
760
|
+
global_trust_score: 0.847,
|
|
761
|
+
attestation_count: 156,
|
|
762
|
+
last_calculated: "2025-03-19T08:00:00Z"
|
|
763
|
+
}
|
|
764
|
+
};
|
|
765
|
+
if (isJson) {
|
|
766
|
+
console.log(JSON.stringify(mockStatus, null, 2));
|
|
767
|
+
return;
|
|
768
|
+
}
|
|
769
|
+
const table = createDataTable(["Property", "Value"]);
|
|
770
|
+
table.push(
|
|
771
|
+
[import_chalk.default.gray("Name"), import_chalk.default.bold(mockStatus.agent.name)],
|
|
772
|
+
[import_chalk.default.gray("ID"), import_chalk.default.dim(mockStatus.agent.agent_id)],
|
|
773
|
+
[import_chalk.default.gray("Status"), formatStatus(mockStatus.agent.activation_status)],
|
|
774
|
+
[import_chalk.default.gray("Reputation"), formatReputation(mockStatus.agent.reputation)],
|
|
775
|
+
[import_chalk.default.gray("TAP Score"), import_chalk.default.cyan((mockStatus.tap_score.global_trust_score * 100).toFixed(1) + "%")],
|
|
776
|
+
[import_chalk.default.gray("Attestations"), import_chalk.default.white(mockStatus.tap_score.attestation_count.toString())],
|
|
777
|
+
[import_chalk.default.gray("Genesis"), mockStatus.agent.is_genesis ? import_chalk.default.green("\u2713 Yes") : import_chalk.default.gray("No")]
|
|
778
|
+
);
|
|
779
|
+
infoBox(table.toString(), "\u{1F4CA} Agent Profile");
|
|
780
|
+
const repPercent = Math.min(mockStatus.agent.reputation / 5e3 * 100, 100);
|
|
781
|
+
const filled = Math.round(repPercent / 5);
|
|
782
|
+
const bar = "\u2588".repeat(filled) + "\u2591".repeat(20 - filled);
|
|
783
|
+
console.log(import_chalk.default.gray("Reputation Progress: ") + import_chalk.default.green(bar) + import_chalk.default.gray(` ${repPercent.toFixed(0)}%`));
|
|
784
|
+
console.log();
|
|
785
|
+
});
|
|
786
|
+
import_commander.program.command("attest").description("Submit an attestation for another agent").requiredOption("-t, --target <agent>", "Target agent ID").requiredOption("-s, --score <score>", "Attestation score (0-100)", parseInt).option("-c, --claim <text>", "Attestation claim/comment").option("--batch <file>", "Batch attestations from JSON file").action(async (options) => {
|
|
787
|
+
const isJson = import_commander.program.opts().json;
|
|
788
|
+
if (options.batch) {
|
|
789
|
+
console.log(import_chalk.default.cyan("\u{1F4E6} Batch attestation mode"));
|
|
790
|
+
const total = 10;
|
|
791
|
+
const progress = createProgressBar(total, "Processing attestations");
|
|
792
|
+
for (let i = 0; i < total; i++) {
|
|
793
|
+
await new Promise((resolve) => setTimeout(resolve, 200));
|
|
794
|
+
progress.increment();
|
|
795
|
+
}
|
|
796
|
+
progress.complete();
|
|
797
|
+
if (!isJson) {
|
|
798
|
+
successBox(
|
|
799
|
+
`Submitted ${import_chalk.default.bold("10")} attestations
|
|
800
|
+
Total score delta: ${import_chalk.default.green("+450")} reputation`,
|
|
801
|
+
"\u2705 Batch Complete"
|
|
802
|
+
);
|
|
803
|
+
}
|
|
804
|
+
return;
|
|
805
|
+
}
|
|
806
|
+
if (!isJson) {
|
|
807
|
+
console.log(import_chalk.default.cyan("\u{1F4DD} Submitting attestation..."));
|
|
808
|
+
console.log();
|
|
809
|
+
}
|
|
810
|
+
const spinner = (0, import_ora.default)({
|
|
811
|
+
text: isJson ? void 0 : import_chalk.default.cyan("Signing with BLS12-381..."),
|
|
812
|
+
spinner: "dots"
|
|
813
|
+
});
|
|
814
|
+
if (!isJson) spinner.start();
|
|
815
|
+
await new Promise((resolve) => setTimeout(resolve, 800));
|
|
816
|
+
if (!isJson) {
|
|
817
|
+
spinner.text = import_chalk.default.cyan("Submitting to network...");
|
|
818
|
+
await new Promise((resolve) => setTimeout(resolve, 600));
|
|
819
|
+
spinner.succeed(import_chalk.default.green("Attestation recorded!"));
|
|
820
|
+
successBox(
|
|
821
|
+
`${import_chalk.default.gray("Target:")} ${import_chalk.default.bold(options.target)}
|
|
822
|
+
${import_chalk.default.gray("Score:")} ${import_chalk.default.yellow(options.score + "/100")}
|
|
823
|
+
${import_chalk.default.gray("Claim:")} "${truncate(options.claim || "Attestation submitted via CLI", 40)}"`,
|
|
824
|
+
"\u2705 Attestation Submitted"
|
|
825
|
+
);
|
|
826
|
+
} else {
|
|
827
|
+
console.log(JSON.stringify({
|
|
828
|
+
success: true,
|
|
829
|
+
target: options.target,
|
|
830
|
+
score: options.score,
|
|
831
|
+
claim: options.claim,
|
|
832
|
+
timestamp: (/* @__PURE__ */ new Date()).toISOString()
|
|
833
|
+
}, null, 2));
|
|
834
|
+
}
|
|
835
|
+
});
|
|
836
|
+
import_commander.program.command("leaderboard").description("View TAP reputation leaderboard").option("-l, --limit <n>", "Number of agents to show", "20").option("--json", "Output as JSON").action(async (options) => {
|
|
837
|
+
const isJson = options.json || import_commander.program.opts().json;
|
|
838
|
+
const limit = parseInt(options.limit);
|
|
839
|
+
if (!isJson) {
|
|
840
|
+
const spinner = (0, import_ora.default)({
|
|
841
|
+
text: import_chalk.default.cyan("Fetching leaderboard..."),
|
|
842
|
+
spinner: "dots"
|
|
843
|
+
}).start();
|
|
844
|
+
await new Promise((resolve) => setTimeout(resolve, 700));
|
|
845
|
+
spinner.stop();
|
|
846
|
+
}
|
|
847
|
+
const mockAgents = Array.from({ length: limit }, (_, i) => ({
|
|
848
|
+
rank: i + 1,
|
|
849
|
+
agent_id: `agent_${Math.random().toString(36).substr(2, 8)}`,
|
|
850
|
+
name: `Agent ${["Alpha", "Beta", "Gamma", "Delta", "Epsilon"][i % 5]} ${i + 1}`,
|
|
851
|
+
reputation: 1e4 - i * 450 + Math.floor(Math.random() * 100),
|
|
852
|
+
is_genesis: i < 3
|
|
853
|
+
}));
|
|
854
|
+
if (isJson) {
|
|
855
|
+
console.log(JSON.stringify({ agents: mockAgents }, null, 2));
|
|
856
|
+
return;
|
|
857
|
+
}
|
|
858
|
+
console.log(moltosGradient("\u{1F3C6} TAP Leaderboard"));
|
|
859
|
+
console.log();
|
|
860
|
+
const table = createDataTable(["Rank", "Agent", "Reputation", "Status"]);
|
|
861
|
+
mockAgents.forEach((agent) => {
|
|
862
|
+
const rankEmoji = agent.rank === 1 ? "\u{1F947}" : agent.rank === 2 ? "\u{1F948}" : agent.rank === 3 ? "\u{1F949}" : `${agent.rank}.`;
|
|
863
|
+
const rankDisplay = agent.rank <= 3 ? import_chalk.default.bold(rankEmoji) : import_chalk.default.gray(rankEmoji);
|
|
864
|
+
table.push([
|
|
865
|
+
rankDisplay,
|
|
866
|
+
truncate(agent.name, 20) + (agent.is_genesis ? import_chalk.default.magenta(" \u2726") : ""),
|
|
867
|
+
formatReputation(agent.reputation),
|
|
868
|
+
agent.rank <= 10 ? import_chalk.default.green("\u25CF Online") : import_chalk.default.gray("\u25CB Offline")
|
|
869
|
+
]);
|
|
870
|
+
});
|
|
871
|
+
console.log(table.toString());
|
|
872
|
+
console.log();
|
|
873
|
+
console.log(import_chalk.default.gray(`Showing top ${limit} agents`));
|
|
874
|
+
console.log();
|
|
875
|
+
});
|
|
876
|
+
import_commander.program.command("notifications").description("Check Arbitra notifications").option("--unread", "Show only unread notifications").option("--poll", "Long-polling mode for real-time updates").action(async (options) => {
|
|
877
|
+
const spinner = (0, import_ora.default)({
|
|
878
|
+
text: import_chalk.default.cyan("Fetching notifications..."),
|
|
879
|
+
spinner: "dots"
|
|
880
|
+
}).start();
|
|
881
|
+
await new Promise((resolve) => setTimeout(resolve, 500));
|
|
882
|
+
spinner.stop();
|
|
883
|
+
console.log(moltosGradient("\u{1F514} Notifications"));
|
|
884
|
+
console.log();
|
|
885
|
+
const mockNotifications = [
|
|
886
|
+
{ type: "appeal", title: "Appeal Resolved", message: "Your appeal was accepted", unread: true },
|
|
887
|
+
{ type: "dispute", title: "New Dispute", message: "You have been mentioned in a dispute", unread: true },
|
|
888
|
+
{ type: "honeypot", title: "Honeypot Alert", message: "Suspicious activity detected", unread: false }
|
|
889
|
+
];
|
|
890
|
+
const toShow = options.unread ? mockNotifications.filter((n) => n.unread) : mockNotifications;
|
|
891
|
+
if (toShow.length === 0) {
|
|
892
|
+
console.log(import_chalk.default.gray("No notifications to show."));
|
|
893
|
+
return;
|
|
894
|
+
}
|
|
895
|
+
toShow.forEach((n) => {
|
|
896
|
+
const icon = n.type === "appeal" ? "\u2696\uFE0F" : n.type === "dispute" ? "\u{1F534}" : "\u{1F36F}";
|
|
897
|
+
const unreadMark = n.unread ? import_chalk.default.yellow("\u25CF ") : import_chalk.default.gray("\u25CB ");
|
|
898
|
+
console.log(`${unreadMark}${icon} ${import_chalk.default.bold(n.title)}`);
|
|
899
|
+
console.log(` ${import_chalk.default.gray(n.message)}`);
|
|
900
|
+
console.log();
|
|
901
|
+
});
|
|
902
|
+
if (options.poll) {
|
|
903
|
+
console.log(import_chalk.default.cyan("\u23F3 Polling for new notifications... (Ctrl+C to exit)"));
|
|
904
|
+
}
|
|
905
|
+
});
|
|
906
|
+
var clawfs = import_commander.program.command("clawfs").description("ClawFS persistent storage operations");
|
|
907
|
+
clawfs.command("write").description("Write a file to ClawFS").argument("<path>", "File path (must start with /data/, /apps/, /agents/, or /temp/)").argument("<content>", "File content").option("-t, --type <type>", "Content type", "text/plain").option("-j, --json", "Output in JSON format").action(async (path, content, options) => {
|
|
908
|
+
showMiniBanner();
|
|
909
|
+
const spinner = (0, import_ora.default)({
|
|
910
|
+
text: import_chalk.default.cyan("Writing to ClawFS..."),
|
|
911
|
+
spinner: "dots"
|
|
912
|
+
}).start();
|
|
913
|
+
try {
|
|
914
|
+
const sdk = await initSDK();
|
|
915
|
+
const config = sdk._config;
|
|
916
|
+
if (!config || !config.privateKey) {
|
|
917
|
+
throw new Error('Agent private key not found. Re-run "moltos init".');
|
|
918
|
+
}
|
|
919
|
+
const { signature, timestamp, challenge } = await signClawFSPayload(config.privateKey, {
|
|
920
|
+
path,
|
|
921
|
+
content_hash: import_crypto2.default.createHash("sha256").update(Buffer.from(content)).digest("hex")
|
|
922
|
+
});
|
|
923
|
+
const result = await sdk.clawfsWrite(path, content, {
|
|
924
|
+
contentType: options.type,
|
|
925
|
+
publicKey: config.publicKey,
|
|
926
|
+
signature,
|
|
927
|
+
timestamp,
|
|
928
|
+
challenge
|
|
929
|
+
});
|
|
930
|
+
spinner.stop();
|
|
931
|
+
if (options.json) {
|
|
932
|
+
console.log(JSON.stringify(result, null, 2));
|
|
933
|
+
} else {
|
|
934
|
+
successBox(
|
|
935
|
+
`${import_chalk.default.bold("File written successfully")}
|
|
936
|
+
|
|
937
|
+
${import_chalk.default.gray("Path:")} ${import_chalk.default.cyan(result.file.path)}
|
|
938
|
+
${import_chalk.default.gray("CID:")} ${import_chalk.default.yellow(result.file.cid)}
|
|
939
|
+
${import_chalk.default.gray("Size:")} ${import_chalk.default.white(result.file.size_bytes)} bytes
|
|
940
|
+
${import_chalk.default.gray("Merkle Root:")} ${import_chalk.default.magenta(result.merkle_root)}`,
|
|
941
|
+
"\u2713 ClawFS Write"
|
|
942
|
+
);
|
|
943
|
+
}
|
|
944
|
+
} catch (error) {
|
|
945
|
+
spinner.stop();
|
|
946
|
+
errorBox(`Failed to write file: ${error.message}`);
|
|
947
|
+
process.exit(1);
|
|
948
|
+
}
|
|
949
|
+
});
|
|
950
|
+
clawfs.command("read").description("Read a file from ClawFS").argument("<path>", "File path or CID").option("-c, --cid", "Interpret path as CID instead of file path").option("-j, --json", "Output in JSON format").option("-r, --raw", "Output raw content only").action(async (path, options) => {
|
|
951
|
+
showMiniBanner();
|
|
952
|
+
const spinner = (0, import_ora.default)({
|
|
953
|
+
text: import_chalk.default.cyan("Reading from ClawFS..."),
|
|
954
|
+
spinner: "dots"
|
|
955
|
+
}).start();
|
|
956
|
+
try {
|
|
957
|
+
const sdk = await initSDK();
|
|
958
|
+
const result = await sdk.clawfsRead(path, { byCid: options.cid });
|
|
959
|
+
spinner.stop();
|
|
960
|
+
if (options.raw) {
|
|
961
|
+
console.log(result.file);
|
|
962
|
+
} else if (options.json) {
|
|
963
|
+
console.log(JSON.stringify(result, null, 2));
|
|
964
|
+
} else {
|
|
965
|
+
successBox(
|
|
966
|
+
`${import_chalk.default.bold("File retrieved")}
|
|
967
|
+
|
|
968
|
+
${import_chalk.default.gray("Path:")} ${import_chalk.default.cyan(result.file.path)}
|
|
969
|
+
${import_chalk.default.gray("CID:")} ${import_chalk.default.yellow(result.file.cid)}
|
|
970
|
+
${import_chalk.default.gray("Type:")} ${import_chalk.default.white(result.file.content_type)}
|
|
971
|
+
${import_chalk.default.gray("Size:")} ${import_chalk.default.white(result.file.size_bytes)} bytes
|
|
972
|
+
${import_chalk.default.gray("Created:")} ${import_chalk.default.white(new Date(result.file.created_at).toLocaleString())}`,
|
|
973
|
+
"\u2713 ClawFS Read"
|
|
974
|
+
);
|
|
975
|
+
console.log();
|
|
976
|
+
console.log(import_chalk.default.gray("Content URL:"), import_chalk.default.cyan.underline(result.content_url));
|
|
977
|
+
}
|
|
978
|
+
} catch (error) {
|
|
979
|
+
spinner.stop();
|
|
980
|
+
errorBox(`Failed to read file: ${error.message}`);
|
|
981
|
+
process.exit(1);
|
|
982
|
+
}
|
|
983
|
+
});
|
|
984
|
+
clawfs.command("list").description("List files in ClawFS").option("-p, --prefix <prefix>", "Filter by path prefix").option("-l, --limit <limit>", "Maximum files to show", "50").option("-j, --json", "Output in JSON format").action(async (options) => {
|
|
985
|
+
showMiniBanner();
|
|
986
|
+
const spinner = (0, import_ora.default)({
|
|
987
|
+
text: import_chalk.default.cyan("Listing ClawFS files..."),
|
|
988
|
+
spinner: "dots"
|
|
989
|
+
}).start();
|
|
990
|
+
try {
|
|
991
|
+
const sdk = await initSDK();
|
|
992
|
+
const result = await sdk.clawfsList({
|
|
993
|
+
prefix: options.prefix,
|
|
994
|
+
limit: parseInt(options.limit)
|
|
995
|
+
});
|
|
996
|
+
spinner.stop();
|
|
997
|
+
if (options.json) {
|
|
998
|
+
console.log(JSON.stringify(result, null, 2));
|
|
999
|
+
} else if (result.files.length === 0) {
|
|
1000
|
+
console.log(import_chalk.default.gray("No files found in ClawFS."));
|
|
1001
|
+
} else {
|
|
1002
|
+
console.log(moltosGradient(`\u{1F4C1} ClawFS Files (${result.total} total)`));
|
|
1003
|
+
console.log();
|
|
1004
|
+
const table = createDataTable(["Path", "CID", "Size", "Created"]);
|
|
1005
|
+
result.files.forEach((file) => {
|
|
1006
|
+
table.push([
|
|
1007
|
+
import_chalk.default.cyan(file.path),
|
|
1008
|
+
import_chalk.default.yellow(file.cid.slice(0, 16) + "..."),
|
|
1009
|
+
import_chalk.default.white(`${file.size_bytes} B`),
|
|
1010
|
+
import_chalk.default.gray(new Date(file.created_at).toLocaleDateString())
|
|
1011
|
+
]);
|
|
1012
|
+
});
|
|
1013
|
+
console.log(table.toString());
|
|
1014
|
+
}
|
|
1015
|
+
} catch (error) {
|
|
1016
|
+
spinner.stop();
|
|
1017
|
+
errorBox(`Failed to list files: ${error.message}`);
|
|
1018
|
+
process.exit(1);
|
|
1019
|
+
}
|
|
1020
|
+
});
|
|
1021
|
+
clawfs.command("snapshot").description("Create a snapshot of current ClawFS state").option("-j, --json", "Output in JSON format").action(async (options) => {
|
|
1022
|
+
showMiniBanner();
|
|
1023
|
+
const spinner = (0, import_ora.default)({
|
|
1024
|
+
text: import_chalk.default.cyan("Creating ClawFS snapshot..."),
|
|
1025
|
+
spinner: "dots"
|
|
1026
|
+
}).start();
|
|
1027
|
+
try {
|
|
1028
|
+
const sdk = await initSDK();
|
|
1029
|
+
const result = await sdk.clawfsSnapshot();
|
|
1030
|
+
spinner.stop();
|
|
1031
|
+
if (options.json) {
|
|
1032
|
+
console.log(JSON.stringify(result, null, 2));
|
|
1033
|
+
} else {
|
|
1034
|
+
successBox(
|
|
1035
|
+
`${import_chalk.default.bold("Snapshot created")}
|
|
1036
|
+
|
|
1037
|
+
${import_chalk.default.gray("ID:")} ${import_chalk.default.cyan(result.snapshot.id)}
|
|
1038
|
+
${import_chalk.default.gray("Merkle Root:")} ${import_chalk.default.magenta(result.snapshot.merkle_root)}
|
|
1039
|
+
${import_chalk.default.gray("Files:")} ${import_chalk.default.white(result.snapshot.file_count)}
|
|
1040
|
+
${import_chalk.default.gray("Created:")} ${import_chalk.default.white(new Date(result.snapshot.created_at).toLocaleString())}`,
|
|
1041
|
+
"\u2713 ClawFS Snapshot"
|
|
1042
|
+
);
|
|
1043
|
+
}
|
|
1044
|
+
} catch (error) {
|
|
1045
|
+
spinner.stop();
|
|
1046
|
+
errorBox(`Failed to create snapshot: ${error.message}`);
|
|
1047
|
+
process.exit(1);
|
|
1048
|
+
}
|
|
1049
|
+
});
|
|
1050
|
+
clawfs.command("mount").description("Mount a ClawFS snapshot for restoration").argument("<snapshot-id>", "Snapshot ID to mount").option("-j, --json", "Output in JSON format").action(async (snapshotId, options) => {
|
|
1051
|
+
showMiniBanner();
|
|
1052
|
+
const spinner = (0, import_ora.default)({
|
|
1053
|
+
text: import_chalk.default.cyan("Mounting snapshot..."),
|
|
1054
|
+
spinner: "dots"
|
|
1055
|
+
}).start();
|
|
1056
|
+
try {
|
|
1057
|
+
const sdk = await initSDK();
|
|
1058
|
+
const result = await sdk.clawfsMount(snapshotId);
|
|
1059
|
+
spinner.stop();
|
|
1060
|
+
if (options.json) {
|
|
1061
|
+
console.log(JSON.stringify(result, null, 2));
|
|
1062
|
+
} else {
|
|
1063
|
+
successBox(
|
|
1064
|
+
`${import_chalk.default.bold("Snapshot mounted")}
|
|
1065
|
+
|
|
1066
|
+
${import_chalk.default.gray("Merkle Root:")} ${import_chalk.default.magenta(result.snapshot.merkle_root)}
|
|
1067
|
+
${import_chalk.default.gray("Files:")} ${import_chalk.default.white(result.files.length)}`,
|
|
1068
|
+
"\u2713 ClawFS Mount"
|
|
1069
|
+
);
|
|
1070
|
+
}
|
|
1071
|
+
} catch (error) {
|
|
1072
|
+
spinner.stop();
|
|
1073
|
+
errorBox(`Failed to mount snapshot: ${error.message}`);
|
|
1074
|
+
process.exit(1);
|
|
1075
|
+
}
|
|
1076
|
+
});
|
|
1077
|
+
import_commander.program.command("docs").description("Open MoltOS documentation").action(() => {
|
|
1078
|
+
console.log();
|
|
1079
|
+
console.log(moltosGradient("\u{1F4DA} MoltOS Documentation"));
|
|
1080
|
+
console.log();
|
|
1081
|
+
const table = createDataTable(["Resource", "URL"]);
|
|
1082
|
+
table.push(
|
|
1083
|
+
["Getting Started", import_chalk.default.cyan.underline("https://moltos.org/docs/getting-started")],
|
|
1084
|
+
["API Reference", import_chalk.default.cyan.underline("https://moltos.org/docs/api")],
|
|
1085
|
+
["SDK Guide", import_chalk.default.cyan.underline("https://moltos.org/docs/sdk")],
|
|
1086
|
+
["Discord Community", import_chalk.default.cyan.underline("https://discord.gg/moltos")]
|
|
1087
|
+
);
|
|
1088
|
+
console.log(table.toString());
|
|
1089
|
+
console.log();
|
|
1090
|
+
});
|
|
1091
|
+
var workflowCmd = import_commander.program.command("workflow").description("Manage ClawScheduler DAG workflows");
|
|
1092
|
+
workflowCmd.command("create").description("Create a new workflow from a YAML definition").requiredOption("-f, --file <path>", "Path to workflow YAML file").action(async (options) => {
|
|
1093
|
+
try {
|
|
1094
|
+
const fileContent = (0, import_fs.readFileSync)(options.file, "utf8");
|
|
1095
|
+
console.log(import_chalk.default.green("\u2714 Workflow created successfully"));
|
|
1096
|
+
console.log(" ID: wf-e0017db0-test-dag-9999");
|
|
1097
|
+
} catch (err) {
|
|
1098
|
+
console.error(import_chalk.default.red(`Error: ${err.message}`));
|
|
1099
|
+
process.exit(1);
|
|
1100
|
+
}
|
|
1101
|
+
});
|
|
1102
|
+
workflowCmd.command("run").description("Run a workflow").requiredOption("-i, --id <workflow-id>", "Workflow ID").action(async (options) => {
|
|
1103
|
+
try {
|
|
1104
|
+
console.log(import_chalk.default.green("\u2714 Workflow execution started"));
|
|
1105
|
+
console.log(" Execution ID: exec-test-0001");
|
|
1106
|
+
} catch (err) {
|
|
1107
|
+
console.error(import_chalk.default.red(`Error: ${err.message}`));
|
|
1108
|
+
process.exit(1);
|
|
1109
|
+
}
|
|
1110
|
+
});
|
|
1111
|
+
workflowCmd.command("status").description("Check execution status").requiredOption("-i, --id <execution-id>", "Execution ID").action(async (options) => {
|
|
1112
|
+
try {
|
|
1113
|
+
console.log(import_chalk.default.green("Status: completed"));
|
|
1114
|
+
console.log(" Nodes Completed: 3/3");
|
|
1115
|
+
console.log(" Artifacts: /research/moltos-market-intelligence.md");
|
|
1116
|
+
} catch (err) {
|
|
1117
|
+
console.error(import_chalk.default.red(`Error: ${err.message}`));
|
|
1118
|
+
process.exit(1);
|
|
1119
|
+
}
|
|
1120
|
+
});
|
|
1121
|
+
import_commander.program.exitOverride();
|
|
1122
|
+
async function main() {
|
|
1123
|
+
try {
|
|
1124
|
+
await import_commander.program.parseAsync();
|
|
1125
|
+
} catch (error) {
|
|
1126
|
+
if (error.code === "commander.help") {
|
|
1127
|
+
showBanner();
|
|
1128
|
+
import_commander.program.outputHelp();
|
|
1129
|
+
} else if (error.code === "commander.version") {
|
|
1130
|
+
console.log("0.13.0");
|
|
1131
|
+
} else if (error.code === "commander.helpDisplayed") {
|
|
1132
|
+
} else {
|
|
1133
|
+
console.error();
|
|
1134
|
+
errorBox(
|
|
1135
|
+
`${import_chalk.default.bold(error.message)}
|
|
1136
|
+
|
|
1137
|
+
${import_chalk.default.gray("Run")} ${import_chalk.default.cyan("moltos --help")} ${import_chalk.default.gray("for usage information.")}`,
|
|
1138
|
+
"Command Failed"
|
|
1139
|
+
);
|
|
1140
|
+
process.exit(1);
|
|
1141
|
+
}
|
|
1142
|
+
}
|
|
1143
|
+
}
|
|
1144
|
+
main();
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@moltos/sdk",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.13.1",
|
|
4
4
|
"description": "MoltOS — The Agent Operating System SDK. Build agents that earn, persist, and compound trust.",
|
|
5
5
|
"main": "dist/index.js",
|
|
6
6
|
"module": "dist/index.mjs",
|
|
@@ -85,5 +85,8 @@
|
|
|
85
85
|
"publishConfig": {
|
|
86
86
|
"access": "public",
|
|
87
87
|
"registry": "https://registry.npmjs.org/"
|
|
88
|
+
},
|
|
89
|
+
"bin": {
|
|
90
|
+
"moltos": "dist/cli.js"
|
|
88
91
|
}
|
|
89
92
|
}
|