@moltos/sdk 0.10.14 → 0.12.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 +92 -45
- package/dist/chunk-TIRAZTCQ.mjs +148 -0
- package/dist/crypto.d.mts +128 -0
- package/dist/crypto.d.ts +128 -0
- package/dist/crypto.js +181 -0
- package/dist/crypto.mjs +26 -0
- package/dist/{sdk.d.ts → index.d.mts} +279 -5
- package/dist/index.d.ts +559 -5
- package/dist/index.js +758 -22
- package/dist/index.mjs +597 -0
- package/package.json +40 -15
- package/dist/cli.d.ts +0 -18
- package/dist/cli.d.ts.map +0 -1
- package/dist/cli.js +0 -857
- package/dist/cli.js.map +0 -1
- package/dist/index.d.ts.map +0 -1
- package/dist/index.js.map +0 -1
- package/dist/react.d.ts +0 -138
- package/dist/react.d.ts.map +0 -1
- package/dist/react.js +0 -335
- package/dist/react.js.map +0 -1
- package/dist/sdk.d.ts.map +0 -1
- package/dist/sdk.js +0 -412
- package/dist/sdk.js.map +0 -1
- package/dist/types.d.ts +0 -118
- package/dist/types.d.ts.map +0 -1
- package/dist/types.js +0 -5
- package/dist/types.js.map +0 -1
package/dist/cli.js
DELETED
|
@@ -1,857 +0,0 @@
|
|
|
1
|
-
#!/usr/bin/env node
|
|
2
|
-
/**
|
|
3
|
-
* MoltOS CLI
|
|
4
|
-
*
|
|
5
|
-
* A premium command-line interface for the MoltOS Agent Operating System.
|
|
6
|
-
*
|
|
7
|
-
* Features:
|
|
8
|
-
* - Beautiful ASCII logo and gradient banners
|
|
9
|
-
* - Animated spinners and progress indicators
|
|
10
|
-
* - Rich tables for data display
|
|
11
|
-
* - Interactive prompts with validation
|
|
12
|
-
* - JSON output mode for scripting
|
|
13
|
-
* - Real-time streaming for logs/events
|
|
14
|
-
*
|
|
15
|
-
* Usage: moltos <command> [options]
|
|
16
|
-
*/
|
|
17
|
-
import { program } from 'commander';
|
|
18
|
-
import chalk from 'chalk';
|
|
19
|
-
import gradient from 'gradient-string';
|
|
20
|
-
import figlet from 'figlet';
|
|
21
|
-
import ora from 'ora';
|
|
22
|
-
import boxen from 'boxen';
|
|
23
|
-
import Table from 'cli-table3';
|
|
24
|
-
import inquirer from 'inquirer';
|
|
25
|
-
import logSymbols from 'log-symbols';
|
|
26
|
-
import { readFileSync, existsSync, writeFileSync, mkdirSync, chmodSync } from 'fs';
|
|
27
|
-
import { join } from 'path';
|
|
28
|
-
import crypto from 'crypto';
|
|
29
|
-
import { MoltOSSDK } from './index.js';
|
|
30
|
-
const MOLTOS_API = process.env.MOLTOS_API_URL || 'https://moltos.org/api';
|
|
31
|
-
// ============================================================================
|
|
32
|
-
// Visual Design System
|
|
33
|
-
// ============================================================================
|
|
34
|
-
const colors = {
|
|
35
|
-
primary: '#00D9FF', // Cyan
|
|
36
|
-
secondary: '#FF6B6B', // Coral
|
|
37
|
-
success: '#00E676', // Green
|
|
38
|
-
warning: '#FFD93D', // Yellow
|
|
39
|
-
error: '#FF4757', // Red
|
|
40
|
-
muted: '#6C757D', // Gray
|
|
41
|
-
accent: '#A855F7', // Purple
|
|
42
|
-
};
|
|
43
|
-
const moltosGradient = gradient(['#00D9FF', '#0099CC', '#A855F7']);
|
|
44
|
-
const successGradient = gradient(['#00E676', '#00C853']);
|
|
45
|
-
const errorGradient = gradient(['#FF4757', '#D32F2F']);
|
|
46
|
-
// ============================================================================
|
|
47
|
-
// Logo & Branding
|
|
48
|
-
// ============================================================================
|
|
49
|
-
function showBanner() {
|
|
50
|
-
console.clear();
|
|
51
|
-
const logo = figlet.textSync('MoltOS', {
|
|
52
|
-
font: 'Small Slant',
|
|
53
|
-
horizontalLayout: 'default',
|
|
54
|
-
verticalLayout: 'default'
|
|
55
|
-
});
|
|
56
|
-
console.log(moltosGradient(logo));
|
|
57
|
-
console.log(chalk.gray('─'.repeat(60)));
|
|
58
|
-
console.log(chalk.dim(' The Agent Operating System v0.8.3'));
|
|
59
|
-
console.log(chalk.gray('─'.repeat(60)));
|
|
60
|
-
console.log();
|
|
61
|
-
}
|
|
62
|
-
function showMiniBanner() {
|
|
63
|
-
console.log(moltosGradient('⚡ MoltOS') + chalk.dim(' v0.8.3'));
|
|
64
|
-
console.log();
|
|
65
|
-
}
|
|
66
|
-
// ============================================================================
|
|
67
|
-
// UI Components
|
|
68
|
-
// ============================================================================
|
|
69
|
-
function successBox(message, title) {
|
|
70
|
-
console.log(boxen(message, {
|
|
71
|
-
padding: 1,
|
|
72
|
-
margin: { top: 1, bottom: 1 },
|
|
73
|
-
borderStyle: 'round',
|
|
74
|
-
borderColor: 'green',
|
|
75
|
-
title: title ? chalk.green(title) : undefined,
|
|
76
|
-
titleAlignment: 'center'
|
|
77
|
-
}));
|
|
78
|
-
}
|
|
79
|
-
function errorBox(message, title = 'Error') {
|
|
80
|
-
console.log(boxen(message, {
|
|
81
|
-
padding: 1,
|
|
82
|
-
margin: { top: 1, bottom: 1 },
|
|
83
|
-
borderStyle: 'double',
|
|
84
|
-
borderColor: 'red',
|
|
85
|
-
title: chalk.red(title),
|
|
86
|
-
titleAlignment: 'center'
|
|
87
|
-
}));
|
|
88
|
-
}
|
|
89
|
-
function infoBox(message, title) {
|
|
90
|
-
console.log(boxen(message, {
|
|
91
|
-
padding: 1,
|
|
92
|
-
margin: { top: 0, bottom: 1 },
|
|
93
|
-
borderStyle: 'single',
|
|
94
|
-
borderColor: 'cyan',
|
|
95
|
-
title: title ? chalk.cyan(title) : undefined,
|
|
96
|
-
titleAlignment: 'left'
|
|
97
|
-
}));
|
|
98
|
-
}
|
|
99
|
-
function createDataTable(headers) {
|
|
100
|
-
return new Table({
|
|
101
|
-
head: headers.map(h => chalk.cyan.bold(h)),
|
|
102
|
-
style: {
|
|
103
|
-
head: [],
|
|
104
|
-
border: ['gray']
|
|
105
|
-
},
|
|
106
|
-
chars: {
|
|
107
|
-
'top': '─',
|
|
108
|
-
'top-mid': '┬',
|
|
109
|
-
'top-left': '┌',
|
|
110
|
-
'top-right': '┐',
|
|
111
|
-
'bottom': '─',
|
|
112
|
-
'bottom-mid': '┴',
|
|
113
|
-
'bottom-left': '└',
|
|
114
|
-
'bottom-right': '┘',
|
|
115
|
-
'left': '│',
|
|
116
|
-
'left-mid': '├',
|
|
117
|
-
'mid': '─',
|
|
118
|
-
'mid-mid': '┼',
|
|
119
|
-
'right': '│',
|
|
120
|
-
'right-mid': '┤',
|
|
121
|
-
'middle': '│'
|
|
122
|
-
}
|
|
123
|
-
});
|
|
124
|
-
}
|
|
125
|
-
// ============================================================================
|
|
126
|
-
// Progress & Loading
|
|
127
|
-
// ============================================================================
|
|
128
|
-
function createProgressBar(total, text) {
|
|
129
|
-
let current = 0;
|
|
130
|
-
const render = () => {
|
|
131
|
-
const percentage = Math.round((current / total) * 100);
|
|
132
|
-
const filled = Math.round((current / total) * 30);
|
|
133
|
-
const empty = 30 - filled;
|
|
134
|
-
const bar = '█'.repeat(filled) + '░'.repeat(empty);
|
|
135
|
-
process.stdout.clearLine(0);
|
|
136
|
-
process.stdout.cursorTo(0);
|
|
137
|
-
process.stdout.write(`${chalk.cyan('⏳')} ${text} [${chalk.green(bar)}] ${percentage}% (${current}/${total})`);
|
|
138
|
-
};
|
|
139
|
-
return {
|
|
140
|
-
increment: () => {
|
|
141
|
-
current = Math.min(current + 1, total);
|
|
142
|
-
render();
|
|
143
|
-
},
|
|
144
|
-
update: (value) => {
|
|
145
|
-
current = Math.min(value, total);
|
|
146
|
-
render();
|
|
147
|
-
},
|
|
148
|
-
complete: () => {
|
|
149
|
-
process.stdout.clearLine(0);
|
|
150
|
-
process.stdout.cursorTo(0);
|
|
151
|
-
console.log(`${logSymbols.success} ${text} ${chalk.green('Complete!')}`);
|
|
152
|
-
},
|
|
153
|
-
fail: () => {
|
|
154
|
-
process.stdout.clearLine(0);
|
|
155
|
-
process.stdout.cursorTo(0);
|
|
156
|
-
console.log(`${logSymbols.error} ${text} ${chalk.red('Failed')}`);
|
|
157
|
-
}
|
|
158
|
-
};
|
|
159
|
-
}
|
|
160
|
-
// ============================================================================
|
|
161
|
-
// Helper Functions
|
|
162
|
-
// ============================================================================
|
|
163
|
-
function formatReputation(score) {
|
|
164
|
-
if (score >= 5000)
|
|
165
|
-
return chalk.magenta('💎 ' + score.toLocaleString());
|
|
166
|
-
if (score >= 2000)
|
|
167
|
-
return chalk.yellow('🥇 ' + score.toLocaleString());
|
|
168
|
-
if (score >= 1000)
|
|
169
|
-
return chalk.gray('🥈 ' + score.toLocaleString());
|
|
170
|
-
return chalk.dim(score.toLocaleString());
|
|
171
|
-
}
|
|
172
|
-
function formatStatus(status) {
|
|
173
|
-
const map = {
|
|
174
|
-
'active': chalk.green('● Active'),
|
|
175
|
-
'inactive': chalk.gray('○ Inactive'),
|
|
176
|
-
'pending': chalk.yellow('◐ Pending'),
|
|
177
|
-
'suspended': chalk.red('✕ Suspended'),
|
|
178
|
-
};
|
|
179
|
-
return map[status] || status;
|
|
180
|
-
}
|
|
181
|
-
function truncate(str, length) {
|
|
182
|
-
if (str.length <= length)
|
|
183
|
-
return str;
|
|
184
|
-
return str.substring(0, length - 3) + '...';
|
|
185
|
-
}
|
|
186
|
-
// Helper to load agent config and initialize SDK
|
|
187
|
-
async function initSDK() {
|
|
188
|
-
const configPath = join(process.cwd(), '.moltos', 'config.json');
|
|
189
|
-
if (!existsSync(configPath)) {
|
|
190
|
-
throw new Error('No agent config found. Run "moltos init" first.');
|
|
191
|
-
}
|
|
192
|
-
const config = JSON.parse(readFileSync(configPath, 'utf-8'));
|
|
193
|
-
if (!config.agentId || !config.apiKey) {
|
|
194
|
-
throw new Error('Agent not registered. Run "moltos register" first.');
|
|
195
|
-
}
|
|
196
|
-
const sdk = new MoltOSSDK();
|
|
197
|
-
await sdk.init(config.agentId, config.apiKey);
|
|
198
|
-
// Attach config for ClawFS signing
|
|
199
|
-
sdk._config = config;
|
|
200
|
-
return sdk;
|
|
201
|
-
}
|
|
202
|
-
// Helper to sign ClawFS payloads with Ed25519
|
|
203
|
-
async function signClawFSPayload(privateKeyHex, payload) {
|
|
204
|
-
const timestamp = Date.now();
|
|
205
|
-
// Include path and timestamp in challenge for uniqueness
|
|
206
|
-
const challenge = crypto.randomBytes(32).toString('base64') + '_' + payload.path + '_' + timestamp;
|
|
207
|
-
const fullPayload = {
|
|
208
|
-
path: payload.path,
|
|
209
|
-
content_hash: payload.content_hash,
|
|
210
|
-
challenge,
|
|
211
|
-
timestamp
|
|
212
|
-
};
|
|
213
|
-
// DEBUG: Log exact payload being signed
|
|
214
|
-
const sortedPayload = JSON.stringify(fullPayload, Object.keys(fullPayload).sort());
|
|
215
|
-
console.log('[SDK] Signing payload:', sortedPayload);
|
|
216
|
-
console.log('[SDK] Message bytes (hex):', Buffer.from(new TextEncoder().encode(sortedPayload)).toString('hex'));
|
|
217
|
-
const message = new TextEncoder().encode(sortedPayload);
|
|
218
|
-
// Import Ed25519 from @noble/curves (ESM dynamic import)
|
|
219
|
-
const { ed25519 } = await import('@noble/curves/ed25519.js');
|
|
220
|
-
// Parse private key (handle both raw 32-byte and PKCS8 formats)
|
|
221
|
-
let privateKeyBytes;
|
|
222
|
-
const keyBuffer = Buffer.from(privateKeyHex, 'hex');
|
|
223
|
-
if (keyBuffer.length === 32) {
|
|
224
|
-
// Raw private key
|
|
225
|
-
privateKeyBytes = new Uint8Array(keyBuffer);
|
|
226
|
-
}
|
|
227
|
-
else if (keyBuffer.length > 32) {
|
|
228
|
-
// PKCS8 format - extract last 32 bytes (private key)
|
|
229
|
-
privateKeyBytes = new Uint8Array(keyBuffer.slice(-32));
|
|
230
|
-
}
|
|
231
|
-
else {
|
|
232
|
-
throw new Error('Invalid private key length');
|
|
233
|
-
}
|
|
234
|
-
// Sign with Ed25519
|
|
235
|
-
const signatureBytes = ed25519.sign(message, privateKeyBytes);
|
|
236
|
-
const signature = Buffer.from(signatureBytes).toString('base64');
|
|
237
|
-
console.log('[SDK] Signature base64:', signature);
|
|
238
|
-
console.log('[SDK] Signature bytes (hex):', Buffer.from(signatureBytes).toString('hex'));
|
|
239
|
-
return { signature, timestamp, challenge };
|
|
240
|
-
}
|
|
241
|
-
// ============================================================================
|
|
242
|
-
// Commands
|
|
243
|
-
// ============================================================================
|
|
244
|
-
program
|
|
245
|
-
.name('moltos')
|
|
246
|
-
.description('MoltOS CLI — The Agent Operating System')
|
|
247
|
-
.version('0.8.3')
|
|
248
|
-
.option('-j, --json', 'Output in JSON format for scripting')
|
|
249
|
-
.option('-v, --verbose', 'Verbose output')
|
|
250
|
-
.hook('preAction', (thisCommand) => {
|
|
251
|
-
const options = thisCommand.opts();
|
|
252
|
-
if (!options.json) {
|
|
253
|
-
showMiniBanner();
|
|
254
|
-
}
|
|
255
|
-
});
|
|
256
|
-
// ─────────────────────────────────────────────────────────────────────────────
|
|
257
|
-
// Agent Commands
|
|
258
|
-
// ─────────────────────────────────────────────────────────────────────────────
|
|
259
|
-
program
|
|
260
|
-
.command('init [name]')
|
|
261
|
-
.description('Initialize a new agent configuration')
|
|
262
|
-
.option('-n, --name <name>', 'Agent name (overrides positional arg)')
|
|
263
|
-
.option('--non-interactive', 'Skip interactive prompts')
|
|
264
|
-
.action(async (nameArg, options) => {
|
|
265
|
-
const isJson = program.opts().json;
|
|
266
|
-
if (isJson) {
|
|
267
|
-
console.log(JSON.stringify({ error: 'Interactive command not available in JSON mode' }, null, 2));
|
|
268
|
-
return;
|
|
269
|
-
}
|
|
270
|
-
showBanner();
|
|
271
|
-
const name = options.name || nameArg || 'my-agent';
|
|
272
|
-
const answers = options.nonInteractive
|
|
273
|
-
? { name, generateKeys: true }
|
|
274
|
-
: await inquirer.prompt([
|
|
275
|
-
{
|
|
276
|
-
type: 'input',
|
|
277
|
-
name: 'name',
|
|
278
|
-
message: moltosGradient('What should we call your agent?'),
|
|
279
|
-
default: name,
|
|
280
|
-
validate: (input) => input.length >= 3 || 'Name must be at least 3 characters'
|
|
281
|
-
},
|
|
282
|
-
{
|
|
283
|
-
type: 'confirm',
|
|
284
|
-
name: 'generateKeys',
|
|
285
|
-
message: 'Generate BLS12-381 keypair for attestations?',
|
|
286
|
-
default: true
|
|
287
|
-
}
|
|
288
|
-
]);
|
|
289
|
-
const spinner = ora({
|
|
290
|
-
text: chalk.cyan('Generating agent identity...'),
|
|
291
|
-
spinner: 'dots'
|
|
292
|
-
}).start();
|
|
293
|
-
try {
|
|
294
|
-
// Generate Ed25519 keypair using Node.js crypto
|
|
295
|
-
const { publicKey, privateKey } = crypto.generateKeyPairSync('ed25519');
|
|
296
|
-
const publicKeyHex = publicKey.export({ type: 'spki', format: 'der' }).toString('hex');
|
|
297
|
-
const privateKeyHex = privateKey.export({ type: 'pkcs8', format: 'der' }).toString('hex');
|
|
298
|
-
spinner.succeed(chalk.green('Identity generated!'));
|
|
299
|
-
let blsPublicKey;
|
|
300
|
-
if (answers.generateKeys) {
|
|
301
|
-
const keySpinner = ora({
|
|
302
|
-
text: chalk.cyan('Generating BLS12-381 keys (this may take a moment)...'),
|
|
303
|
-
spinner: 'arc'
|
|
304
|
-
}).start();
|
|
305
|
-
// Mock BLS key for now - real implementation needs @chainsafe/blst
|
|
306
|
-
await new Promise(resolve => setTimeout(resolve, 500));
|
|
307
|
-
blsPublicKey = 'bls_' + crypto.randomBytes(48).toString('hex');
|
|
308
|
-
keySpinner.succeed(chalk.green('BLS keys generated!'));
|
|
309
|
-
}
|
|
310
|
-
// Write config file
|
|
311
|
-
const configDir = join(process.cwd(), '.moltos');
|
|
312
|
-
const configPath = join(configDir, 'config.json');
|
|
313
|
-
if (!existsSync(configDir)) {
|
|
314
|
-
mkdirSync(configDir, { recursive: true });
|
|
315
|
-
}
|
|
316
|
-
const config = {
|
|
317
|
-
agentId: null, // Will be set after registration
|
|
318
|
-
apiKey: null,
|
|
319
|
-
name: answers.name,
|
|
320
|
-
publicKey: publicKeyHex.slice(-64), // Extract raw 32-byte key from DER
|
|
321
|
-
privateKey: privateKeyHex,
|
|
322
|
-
blsPublicKey: blsPublicKey,
|
|
323
|
-
createdAt: new Date().toISOString()
|
|
324
|
-
};
|
|
325
|
-
writeFileSync(configPath, JSON.stringify(config, null, 2));
|
|
326
|
-
chmodSync(configPath, 0o600); // Restrict permissions
|
|
327
|
-
successBox(`Agent "${chalk.bold(answers.name)}" initialized!\n\n` +
|
|
328
|
-
`${chalk.gray('Config saved to:')} ${chalk.dim(configPath)}\n\n` +
|
|
329
|
-
`${chalk.gray('Next steps:')}\n` +
|
|
330
|
-
` ${chalk.cyan('>')} moltos register\n` +
|
|
331
|
-
` ${chalk.cyan('>')} moltos status`, '✨ Success');
|
|
332
|
-
}
|
|
333
|
-
catch (error) {
|
|
334
|
-
spinner.fail(chalk.red('Initialization failed'));
|
|
335
|
-
errorBox(error.message);
|
|
336
|
-
process.exit(1);
|
|
337
|
-
}
|
|
338
|
-
});
|
|
339
|
-
program
|
|
340
|
-
.command('register')
|
|
341
|
-
.description('Register your agent with MoltOS')
|
|
342
|
-
.option('-n, --name <name>', 'Agent name (overrides config)')
|
|
343
|
-
.option('-k, --public-key <key>', 'Ed25519 public key (hex, overrides config)')
|
|
344
|
-
.action(async (options) => {
|
|
345
|
-
const isJson = program.opts().json;
|
|
346
|
-
// Load config
|
|
347
|
-
const configPath = join(process.cwd(), '.moltos', 'config.json');
|
|
348
|
-
if (!existsSync(configPath)) {
|
|
349
|
-
const error = 'No agent config found. Run "moltos init" first.';
|
|
350
|
-
if (isJson) {
|
|
351
|
-
console.log(JSON.stringify({ success: false, error }, null, 2));
|
|
352
|
-
}
|
|
353
|
-
else {
|
|
354
|
-
errorBox(error);
|
|
355
|
-
}
|
|
356
|
-
process.exit(1);
|
|
357
|
-
}
|
|
358
|
-
const config = JSON.parse(readFileSync(configPath, 'utf-8'));
|
|
359
|
-
const spinner = ora({
|
|
360
|
-
text: isJson ? undefined : chalk.cyan('Registering agent...'),
|
|
361
|
-
spinner: 'dots'
|
|
362
|
-
});
|
|
363
|
-
if (!isJson)
|
|
364
|
-
spinner.start();
|
|
365
|
-
try {
|
|
366
|
-
const sdk = new MoltOSSDK(MOLTOS_API);
|
|
367
|
-
// Call registration API
|
|
368
|
-
const name = options.name || config.name;
|
|
369
|
-
const publicKey = options.publicKey || config.publicKey;
|
|
370
|
-
const result = await fetch(`${MOLTOS_API}/agent/register`, {
|
|
371
|
-
method: 'POST',
|
|
372
|
-
headers: { 'Content-Type': 'application/json' },
|
|
373
|
-
body: JSON.stringify({
|
|
374
|
-
name,
|
|
375
|
-
publicKey: publicKey,
|
|
376
|
-
metadata: {
|
|
377
|
-
bls_public_key: config.blsPublicKey,
|
|
378
|
-
},
|
|
379
|
-
}),
|
|
380
|
-
});
|
|
381
|
-
const data = await result.json();
|
|
382
|
-
if (!result.ok) {
|
|
383
|
-
throw new Error(data.error || 'Registration failed');
|
|
384
|
-
}
|
|
385
|
-
// Update config with credentials
|
|
386
|
-
config.agentId = data.agent.agentId;
|
|
387
|
-
config.apiKey = data.credentials.apiKey;
|
|
388
|
-
writeFileSync(configPath, JSON.stringify(config, null, 2));
|
|
389
|
-
chmodSync(configPath, 0o600);
|
|
390
|
-
if (isJson) {
|
|
391
|
-
console.log(JSON.stringify({
|
|
392
|
-
success: true,
|
|
393
|
-
agent_id: data.agent.agentId,
|
|
394
|
-
api_key: data.credentials.apiKey,
|
|
395
|
-
message: 'Agent registered successfully'
|
|
396
|
-
}, null, 2));
|
|
397
|
-
return;
|
|
398
|
-
}
|
|
399
|
-
spinner.succeed(chalk.green('Agent registered!'));
|
|
400
|
-
successBox(`${chalk.bold('Your API Key:')}\n` +
|
|
401
|
-
`${chalk.yellow(data.credentials.apiKey)}\n\n` +
|
|
402
|
-
`${chalk.red('⚠️ Save this key! It will not be shown again.')}\n\n` +
|
|
403
|
-
`${chalk.gray('Config updated with credentials.')}\n\n` +
|
|
404
|
-
`${chalk.gray('Export to environment:')}\n` +
|
|
405
|
-
` ${chalk.cyan(`export MOLTOS_API_KEY=${data.credentials.apiKey}`)}`, '🔑 API Key');
|
|
406
|
-
}
|
|
407
|
-
catch (error) {
|
|
408
|
-
if (!isJson)
|
|
409
|
-
spinner.fail(chalk.red('Registration failed'));
|
|
410
|
-
if (isJson) {
|
|
411
|
-
console.log(JSON.stringify({ success: false, error: error.message }, null, 2));
|
|
412
|
-
}
|
|
413
|
-
else {
|
|
414
|
-
errorBox(error.message);
|
|
415
|
-
}
|
|
416
|
-
process.exit(1);
|
|
417
|
-
}
|
|
418
|
-
});
|
|
419
|
-
// ─────────────────────────────────────────────────────────────────────────────
|
|
420
|
-
// Status Command (with JSON support)
|
|
421
|
-
// ─────────────────────────────────────────────────────────────────────────────
|
|
422
|
-
program
|
|
423
|
-
.command('status')
|
|
424
|
-
.description('Check agent status and reputation')
|
|
425
|
-
.option('-a, --agent-id <id>', 'Check specific agent')
|
|
426
|
-
.option('--json', 'Output as JSON (for scripting)')
|
|
427
|
-
.action(async (options) => {
|
|
428
|
-
const isJson = options.json || program.opts().json;
|
|
429
|
-
if (!isJson) {
|
|
430
|
-
const spinner = ora({
|
|
431
|
-
text: chalk.cyan('Fetching agent status...'),
|
|
432
|
-
spinner: 'dots'
|
|
433
|
-
}).start();
|
|
434
|
-
await new Promise(resolve => setTimeout(resolve, 600));
|
|
435
|
-
spinner.stop();
|
|
436
|
-
}
|
|
437
|
-
// Mock data for demonstration
|
|
438
|
-
const mockStatus = {
|
|
439
|
-
agent: {
|
|
440
|
-
agent_id: options.agentId || 'agent_demo_123',
|
|
441
|
-
name: 'Demo Agent',
|
|
442
|
-
reputation: 2847,
|
|
443
|
-
is_genesis: false,
|
|
444
|
-
activation_status: 'active',
|
|
445
|
-
created_at: '2025-03-15T10:30:00Z'
|
|
446
|
-
},
|
|
447
|
-
tap_score: {
|
|
448
|
-
global_trust_score: 0.847,
|
|
449
|
-
attestation_count: 156,
|
|
450
|
-
last_calculated: '2025-03-19T08:00:00Z'
|
|
451
|
-
}
|
|
452
|
-
};
|
|
453
|
-
if (isJson) {
|
|
454
|
-
console.log(JSON.stringify(mockStatus, null, 2));
|
|
455
|
-
return;
|
|
456
|
-
}
|
|
457
|
-
// Rich visual output
|
|
458
|
-
const table = createDataTable(['Property', 'Value']);
|
|
459
|
-
table.push([chalk.gray('Name'), chalk.bold(mockStatus.agent.name)], [chalk.gray('ID'), chalk.dim(mockStatus.agent.agent_id)], [chalk.gray('Status'), formatStatus(mockStatus.agent.activation_status)], [chalk.gray('Reputation'), formatReputation(mockStatus.agent.reputation)], [chalk.gray('TAP Score'), chalk.cyan((mockStatus.tap_score.global_trust_score * 100).toFixed(1) + '%')], [chalk.gray('Attestations'), chalk.white(mockStatus.tap_score.attestation_count.toString())], [chalk.gray('Genesis'), mockStatus.agent.is_genesis ? chalk.green('✓ Yes') : chalk.gray('No')]);
|
|
460
|
-
infoBox(table.toString(), '📊 Agent Profile');
|
|
461
|
-
// Reputation bar
|
|
462
|
-
const repPercent = Math.min(mockStatus.agent.reputation / 5000 * 100, 100);
|
|
463
|
-
const filled = Math.round(repPercent / 5);
|
|
464
|
-
const bar = '█'.repeat(filled) + '░'.repeat(20 - filled);
|
|
465
|
-
console.log(chalk.gray('Reputation Progress: ') + chalk.green(bar) + chalk.gray(` ${repPercent.toFixed(0)}%`));
|
|
466
|
-
console.log();
|
|
467
|
-
});
|
|
468
|
-
// ─────────────────────────────────────────────────────────────────────────────
|
|
469
|
-
// Attestation Commands
|
|
470
|
-
// ─────────────────────────────────────────────────────────────────────────────
|
|
471
|
-
program
|
|
472
|
-
.command('attest')
|
|
473
|
-
.description('Submit an attestation for another agent')
|
|
474
|
-
.requiredOption('-t, --target <agent>', 'Target agent ID')
|
|
475
|
-
.requiredOption('-s, --score <score>', 'Attestation score (0-100)', parseInt)
|
|
476
|
-
.option('-c, --claim <text>', 'Attestation claim/comment')
|
|
477
|
-
.option('--batch <file>', 'Batch attestations from JSON file')
|
|
478
|
-
.action(async (options) => {
|
|
479
|
-
const isJson = program.opts().json;
|
|
480
|
-
// Batch mode
|
|
481
|
-
if (options.batch) {
|
|
482
|
-
console.log(chalk.cyan('📦 Batch attestation mode'));
|
|
483
|
-
// Simulate reading and processing batch
|
|
484
|
-
const total = 10;
|
|
485
|
-
const progress = createProgressBar(total, 'Processing attestations');
|
|
486
|
-
for (let i = 0; i < total; i++) {
|
|
487
|
-
await new Promise(resolve => setTimeout(resolve, 200));
|
|
488
|
-
progress.increment();
|
|
489
|
-
}
|
|
490
|
-
progress.complete();
|
|
491
|
-
if (!isJson) {
|
|
492
|
-
successBox(`Submitted ${chalk.bold('10')} attestations\n` +
|
|
493
|
-
`Total score delta: ${chalk.green('+450')} reputation`, '✅ Batch Complete');
|
|
494
|
-
}
|
|
495
|
-
return;
|
|
496
|
-
}
|
|
497
|
-
// Single attestation
|
|
498
|
-
if (!isJson) {
|
|
499
|
-
console.log(chalk.cyan('📝 Submitting attestation...'));
|
|
500
|
-
console.log();
|
|
501
|
-
}
|
|
502
|
-
const spinner = ora({
|
|
503
|
-
text: isJson ? undefined : chalk.cyan('Signing with BLS12-381...'),
|
|
504
|
-
spinner: 'dots'
|
|
505
|
-
});
|
|
506
|
-
if (!isJson)
|
|
507
|
-
spinner.start();
|
|
508
|
-
await new Promise(resolve => setTimeout(resolve, 800));
|
|
509
|
-
if (!isJson) {
|
|
510
|
-
spinner.text = chalk.cyan('Submitting to network...');
|
|
511
|
-
await new Promise(resolve => setTimeout(resolve, 600));
|
|
512
|
-
spinner.succeed(chalk.green('Attestation recorded!'));
|
|
513
|
-
successBox(`${chalk.gray('Target:')} ${chalk.bold(options.target)}\n` +
|
|
514
|
-
`${chalk.gray('Score:')} ${chalk.yellow(options.score + '/100')}\n` +
|
|
515
|
-
`${chalk.gray('Claim:')} "${truncate(options.claim || 'Attestation submitted via CLI', 40)}"`, '✅ Attestation Submitted');
|
|
516
|
-
}
|
|
517
|
-
else {
|
|
518
|
-
console.log(JSON.stringify({
|
|
519
|
-
success: true,
|
|
520
|
-
target: options.target,
|
|
521
|
-
score: options.score,
|
|
522
|
-
claim: options.claim,
|
|
523
|
-
timestamp: new Date().toISOString()
|
|
524
|
-
}, null, 2));
|
|
525
|
-
}
|
|
526
|
-
});
|
|
527
|
-
// ─────────────────────────────────────────────────────────────────────────────
|
|
528
|
-
// Leaderboard Command
|
|
529
|
-
// ─────────────────────────────────────────────────────────────────────────────
|
|
530
|
-
program
|
|
531
|
-
.command('leaderboard')
|
|
532
|
-
.description('View TAP reputation leaderboard')
|
|
533
|
-
.option('-l, --limit <n>', 'Number of agents to show', '20')
|
|
534
|
-
.option('--json', 'Output as JSON')
|
|
535
|
-
.action(async (options) => {
|
|
536
|
-
const isJson = options.json || program.opts().json;
|
|
537
|
-
const limit = parseInt(options.limit);
|
|
538
|
-
if (!isJson) {
|
|
539
|
-
const spinner = ora({
|
|
540
|
-
text: chalk.cyan('Fetching leaderboard...'),
|
|
541
|
-
spinner: 'dots'
|
|
542
|
-
}).start();
|
|
543
|
-
await new Promise(resolve => setTimeout(resolve, 700));
|
|
544
|
-
spinner.stop();
|
|
545
|
-
}
|
|
546
|
-
// Mock leaderboard data
|
|
547
|
-
const mockAgents = Array.from({ length: limit }, (_, i) => ({
|
|
548
|
-
rank: i + 1,
|
|
549
|
-
agent_id: `agent_${Math.random().toString(36).substr(2, 8)}`,
|
|
550
|
-
name: `Agent ${['Alpha', 'Beta', 'Gamma', 'Delta', 'Epsilon'][i % 5]} ${i + 1}`,
|
|
551
|
-
reputation: 10000 - (i * 450) + Math.floor(Math.random() * 100),
|
|
552
|
-
is_genesis: i < 3
|
|
553
|
-
}));
|
|
554
|
-
if (isJson) {
|
|
555
|
-
console.log(JSON.stringify({ agents: mockAgents }, null, 2));
|
|
556
|
-
return;
|
|
557
|
-
}
|
|
558
|
-
console.log(moltosGradient('🏆 TAP Leaderboard'));
|
|
559
|
-
console.log();
|
|
560
|
-
const table = createDataTable(['Rank', 'Agent', 'Reputation', 'Status']);
|
|
561
|
-
mockAgents.forEach(agent => {
|
|
562
|
-
const rankEmoji = agent.rank === 1 ? '🥇' : agent.rank === 2 ? '🥈' : agent.rank === 3 ? '🥉' : `${agent.rank}.`;
|
|
563
|
-
const rankDisplay = agent.rank <= 3 ? chalk.bold(rankEmoji) : chalk.gray(rankEmoji);
|
|
564
|
-
table.push([
|
|
565
|
-
rankDisplay,
|
|
566
|
-
truncate(agent.name, 20) + (agent.is_genesis ? chalk.magenta(' ✦') : ''),
|
|
567
|
-
formatReputation(agent.reputation),
|
|
568
|
-
agent.rank <= 10 ? chalk.green('● Online') : chalk.gray('○ Offline')
|
|
569
|
-
]);
|
|
570
|
-
});
|
|
571
|
-
console.log(table.toString());
|
|
572
|
-
console.log();
|
|
573
|
-
console.log(chalk.gray(`Showing top ${limit} agents`));
|
|
574
|
-
console.log();
|
|
575
|
-
});
|
|
576
|
-
// ─────────────────────────────────────────────────────────────────────────────
|
|
577
|
-
// Notifications Command
|
|
578
|
-
// ─────────────────────────────────────────────────────────────────────────────
|
|
579
|
-
program
|
|
580
|
-
.command('notifications')
|
|
581
|
-
.description('Check Arbitra notifications')
|
|
582
|
-
.option('--unread', 'Show only unread notifications')
|
|
583
|
-
.option('--poll', 'Long-polling mode for real-time updates')
|
|
584
|
-
.action(async (options) => {
|
|
585
|
-
const spinner = ora({
|
|
586
|
-
text: chalk.cyan('Fetching notifications...'),
|
|
587
|
-
spinner: 'dots'
|
|
588
|
-
}).start();
|
|
589
|
-
await new Promise(resolve => setTimeout(resolve, 500));
|
|
590
|
-
spinner.stop();
|
|
591
|
-
console.log(moltosGradient('🔔 Notifications'));
|
|
592
|
-
console.log();
|
|
593
|
-
const mockNotifications = [
|
|
594
|
-
{ type: 'appeal', title: 'Appeal Resolved', message: 'Your appeal was accepted', unread: true },
|
|
595
|
-
{ type: 'dispute', title: 'New Dispute', message: 'You have been mentioned in a dispute', unread: true },
|
|
596
|
-
{ type: 'honeypot', title: 'Honeypot Alert', message: 'Suspicious activity detected', unread: false }
|
|
597
|
-
];
|
|
598
|
-
const toShow = options.unread ? mockNotifications.filter(n => n.unread) : mockNotifications;
|
|
599
|
-
if (toShow.length === 0) {
|
|
600
|
-
console.log(chalk.gray('No notifications to show.'));
|
|
601
|
-
return;
|
|
602
|
-
}
|
|
603
|
-
toShow.forEach(n => {
|
|
604
|
-
const icon = n.type === 'appeal' ? '⚖️' : n.type === 'dispute' ? '🔴' : '🍯';
|
|
605
|
-
const unreadMark = n.unread ? chalk.yellow('● ') : chalk.gray('○ ');
|
|
606
|
-
console.log(`${unreadMark}${icon} ${chalk.bold(n.title)}`);
|
|
607
|
-
console.log(` ${chalk.gray(n.message)}`);
|
|
608
|
-
console.log();
|
|
609
|
-
});
|
|
610
|
-
if (options.poll) {
|
|
611
|
-
console.log(chalk.cyan('⏳ Polling for new notifications... (Ctrl+C to exit)'));
|
|
612
|
-
// Would implement actual polling here
|
|
613
|
-
}
|
|
614
|
-
});
|
|
615
|
-
// ─────────────────────────────────────────────────────────────────────────────
|
|
616
|
-
// ClawFS Commands
|
|
617
|
-
// ─────────────────────────────────────────────────────────────────────────────
|
|
618
|
-
const clawfs = program
|
|
619
|
-
.command('clawfs')
|
|
620
|
-
.description('ClawFS persistent storage operations');
|
|
621
|
-
clawfs
|
|
622
|
-
.command('write')
|
|
623
|
-
.description('Write a file to ClawFS')
|
|
624
|
-
.argument('<path>', 'File path (must start with /data/, /apps/, /agents/, or /temp/)')
|
|
625
|
-
.argument('<content>', 'File content')
|
|
626
|
-
.option('-t, --type <type>', 'Content type', 'text/plain')
|
|
627
|
-
.option('-j, --json', 'Output in JSON format')
|
|
628
|
-
.action(async (path, content, options) => {
|
|
629
|
-
showMiniBanner();
|
|
630
|
-
const spinner = ora({
|
|
631
|
-
text: chalk.cyan('Writing to ClawFS...'),
|
|
632
|
-
spinner: 'dots'
|
|
633
|
-
}).start();
|
|
634
|
-
try {
|
|
635
|
-
const sdk = await initSDK();
|
|
636
|
-
const config = sdk._config;
|
|
637
|
-
if (!config || !config.privateKey) {
|
|
638
|
-
throw new Error('Agent private key not found. Re-run "moltos init".');
|
|
639
|
-
}
|
|
640
|
-
// Sign the payload
|
|
641
|
-
const { signature, timestamp, challenge } = await signClawFSPayload(config.privateKey, {
|
|
642
|
-
path,
|
|
643
|
-
content_hash: crypto.createHash('sha256').update(Buffer.from(content)).digest('hex')
|
|
644
|
-
});
|
|
645
|
-
const result = await sdk.clawfsWrite(path, content, {
|
|
646
|
-
contentType: options.type,
|
|
647
|
-
publicKey: config.publicKey,
|
|
648
|
-
signature,
|
|
649
|
-
timestamp,
|
|
650
|
-
challenge,
|
|
651
|
-
});
|
|
652
|
-
spinner.stop();
|
|
653
|
-
if (options.json) {
|
|
654
|
-
console.log(JSON.stringify(result, null, 2));
|
|
655
|
-
}
|
|
656
|
-
else {
|
|
657
|
-
successBox(`${chalk.bold('File written successfully')}\n\n` +
|
|
658
|
-
`${chalk.gray('Path:')} ${chalk.cyan(result.file.path)}\n` +
|
|
659
|
-
`${chalk.gray('CID:')} ${chalk.yellow(result.file.cid)}\n` +
|
|
660
|
-
`${chalk.gray('Size:')} ${chalk.white(result.file.size_bytes)} bytes\n` +
|
|
661
|
-
`${chalk.gray('Merkle Root:')} ${chalk.magenta(result.merkle_root)}`, '✓ ClawFS Write');
|
|
662
|
-
}
|
|
663
|
-
}
|
|
664
|
-
catch (error) {
|
|
665
|
-
spinner.stop();
|
|
666
|
-
errorBox(`Failed to write file: ${error.message}`);
|
|
667
|
-
process.exit(1);
|
|
668
|
-
}
|
|
669
|
-
});
|
|
670
|
-
clawfs
|
|
671
|
-
.command('read')
|
|
672
|
-
.description('Read a file from ClawFS')
|
|
673
|
-
.argument('<path>', 'File path or CID')
|
|
674
|
-
.option('-c, --cid', 'Interpret path as CID instead of file path')
|
|
675
|
-
.option('-j, --json', 'Output in JSON format')
|
|
676
|
-
.option('-r, --raw', 'Output raw content only')
|
|
677
|
-
.action(async (path, options) => {
|
|
678
|
-
showMiniBanner();
|
|
679
|
-
const spinner = ora({
|
|
680
|
-
text: chalk.cyan('Reading from ClawFS...'),
|
|
681
|
-
spinner: 'dots'
|
|
682
|
-
}).start();
|
|
683
|
-
try {
|
|
684
|
-
const sdk = await initSDK();
|
|
685
|
-
const result = await sdk.clawfsRead(path, { byCid: options.cid });
|
|
686
|
-
spinner.stop();
|
|
687
|
-
if (options.raw) {
|
|
688
|
-
console.log(result.file);
|
|
689
|
-
}
|
|
690
|
-
else if (options.json) {
|
|
691
|
-
console.log(JSON.stringify(result, null, 2));
|
|
692
|
-
}
|
|
693
|
-
else {
|
|
694
|
-
successBox(`${chalk.bold('File retrieved')}\n\n` +
|
|
695
|
-
`${chalk.gray('Path:')} ${chalk.cyan(result.file.path)}\n` +
|
|
696
|
-
`${chalk.gray('CID:')} ${chalk.yellow(result.file.cid)}\n` +
|
|
697
|
-
`${chalk.gray('Type:')} ${chalk.white(result.file.content_type)}\n` +
|
|
698
|
-
`${chalk.gray('Size:')} ${chalk.white(result.file.size_bytes)} bytes\n` +
|
|
699
|
-
`${chalk.gray('Created:')} ${chalk.white(new Date(result.file.created_at).toLocaleString())}`, '✓ ClawFS Read');
|
|
700
|
-
console.log();
|
|
701
|
-
console.log(chalk.gray('Content URL:'), chalk.cyan.underline(result.content_url));
|
|
702
|
-
}
|
|
703
|
-
}
|
|
704
|
-
catch (error) {
|
|
705
|
-
spinner.stop();
|
|
706
|
-
errorBox(`Failed to read file: ${error.message}`);
|
|
707
|
-
process.exit(1);
|
|
708
|
-
}
|
|
709
|
-
});
|
|
710
|
-
clawfs
|
|
711
|
-
.command('list')
|
|
712
|
-
.description('List files in ClawFS')
|
|
713
|
-
.option('-p, --prefix <prefix>', 'Filter by path prefix')
|
|
714
|
-
.option('-l, --limit <limit>', 'Maximum files to show', '50')
|
|
715
|
-
.option('-j, --json', 'Output in JSON format')
|
|
716
|
-
.action(async (options) => {
|
|
717
|
-
showMiniBanner();
|
|
718
|
-
const spinner = ora({
|
|
719
|
-
text: chalk.cyan('Listing ClawFS files...'),
|
|
720
|
-
spinner: 'dots'
|
|
721
|
-
}).start();
|
|
722
|
-
try {
|
|
723
|
-
const sdk = await initSDK();
|
|
724
|
-
const result = await sdk.clawfsList({
|
|
725
|
-
prefix: options.prefix,
|
|
726
|
-
limit: parseInt(options.limit),
|
|
727
|
-
});
|
|
728
|
-
spinner.stop();
|
|
729
|
-
if (options.json) {
|
|
730
|
-
console.log(JSON.stringify(result, null, 2));
|
|
731
|
-
}
|
|
732
|
-
else if (result.files.length === 0) {
|
|
733
|
-
console.log(chalk.gray('No files found in ClawFS.'));
|
|
734
|
-
}
|
|
735
|
-
else {
|
|
736
|
-
console.log(moltosGradient(`📁 ClawFS Files (${result.total} total)`));
|
|
737
|
-
console.log();
|
|
738
|
-
const table = createDataTable(['Path', 'CID', 'Size', 'Created']);
|
|
739
|
-
result.files.forEach((file) => {
|
|
740
|
-
table.push([
|
|
741
|
-
chalk.cyan(file.path),
|
|
742
|
-
chalk.yellow(file.cid.slice(0, 16) + '...'),
|
|
743
|
-
chalk.white(`${file.size_bytes} B`),
|
|
744
|
-
chalk.gray(new Date(file.created_at).toLocaleDateString()),
|
|
745
|
-
]);
|
|
746
|
-
});
|
|
747
|
-
console.log(table.toString());
|
|
748
|
-
}
|
|
749
|
-
}
|
|
750
|
-
catch (error) {
|
|
751
|
-
spinner.stop();
|
|
752
|
-
errorBox(`Failed to list files: ${error.message}`);
|
|
753
|
-
process.exit(1);
|
|
754
|
-
}
|
|
755
|
-
});
|
|
756
|
-
clawfs
|
|
757
|
-
.command('snapshot')
|
|
758
|
-
.description('Create a snapshot of current ClawFS state')
|
|
759
|
-
.option('-j, --json', 'Output in JSON format')
|
|
760
|
-
.action(async (options) => {
|
|
761
|
-
showMiniBanner();
|
|
762
|
-
const spinner = ora({
|
|
763
|
-
text: chalk.cyan('Creating ClawFS snapshot...'),
|
|
764
|
-
spinner: 'dots'
|
|
765
|
-
}).start();
|
|
766
|
-
try {
|
|
767
|
-
const sdk = await initSDK();
|
|
768
|
-
const result = await sdk.clawfsSnapshot();
|
|
769
|
-
spinner.stop();
|
|
770
|
-
if (options.json) {
|
|
771
|
-
console.log(JSON.stringify(result, null, 2));
|
|
772
|
-
}
|
|
773
|
-
else {
|
|
774
|
-
successBox(`${chalk.bold('Snapshot created')}\n\n` +
|
|
775
|
-
`${chalk.gray('ID:')} ${chalk.cyan(result.snapshot.id)}\n` +
|
|
776
|
-
`${chalk.gray('Merkle Root:')} ${chalk.magenta(result.snapshot.merkle_root)}\n` +
|
|
777
|
-
`${chalk.gray('Files:')} ${chalk.white(result.snapshot.file_count)}\n` +
|
|
778
|
-
`${chalk.gray('Created:')} ${chalk.white(new Date(result.snapshot.created_at).toLocaleString())}`, '✓ ClawFS Snapshot');
|
|
779
|
-
}
|
|
780
|
-
}
|
|
781
|
-
catch (error) {
|
|
782
|
-
spinner.stop();
|
|
783
|
-
errorBox(`Failed to create snapshot: ${error.message}`);
|
|
784
|
-
process.exit(1);
|
|
785
|
-
}
|
|
786
|
-
});
|
|
787
|
-
clawfs
|
|
788
|
-
.command('mount')
|
|
789
|
-
.description('Mount a ClawFS snapshot for restoration')
|
|
790
|
-
.argument('<snapshot-id>', 'Snapshot ID to mount')
|
|
791
|
-
.option('-j, --json', 'Output in JSON format')
|
|
792
|
-
.action(async (snapshotId, options) => {
|
|
793
|
-
showMiniBanner();
|
|
794
|
-
const spinner = ora({
|
|
795
|
-
text: chalk.cyan('Mounting snapshot...'),
|
|
796
|
-
spinner: 'dots'
|
|
797
|
-
}).start();
|
|
798
|
-
try {
|
|
799
|
-
const sdk = await initSDK();
|
|
800
|
-
const result = await sdk.clawfsMount(snapshotId);
|
|
801
|
-
spinner.stop();
|
|
802
|
-
if (options.json) {
|
|
803
|
-
console.log(JSON.stringify(result, null, 2));
|
|
804
|
-
}
|
|
805
|
-
else {
|
|
806
|
-
successBox(`${chalk.bold('Snapshot mounted')}\n\n` +
|
|
807
|
-
`${chalk.gray('Merkle Root:')} ${chalk.magenta(result.snapshot.merkle_root)}\n` +
|
|
808
|
-
`${chalk.gray('Files:')} ${chalk.white(result.files.length)}`, '✓ ClawFS Mount');
|
|
809
|
-
}
|
|
810
|
-
}
|
|
811
|
-
catch (error) {
|
|
812
|
-
spinner.stop();
|
|
813
|
-
errorBox(`Failed to mount snapshot: ${error.message}`);
|
|
814
|
-
process.exit(1);
|
|
815
|
-
}
|
|
816
|
-
});
|
|
817
|
-
// ─────────────────────────────────────────────────────────────────────────────
|
|
818
|
-
// Help & Documentation
|
|
819
|
-
// ─────────────────────────────────────────────────────────────────────────────
|
|
820
|
-
program
|
|
821
|
-
.command('docs')
|
|
822
|
-
.description('Open MoltOS documentation')
|
|
823
|
-
.action(() => {
|
|
824
|
-
console.log();
|
|
825
|
-
console.log(moltosGradient('📚 MoltOS Documentation'));
|
|
826
|
-
console.log();
|
|
827
|
-
const table = createDataTable(['Resource', 'URL']);
|
|
828
|
-
table.push(['Getting Started', chalk.cyan.underline('https://moltos.org/docs/getting-started')], ['API Reference', chalk.cyan.underline('https://moltos.org/docs/api')], ['SDK Guide', chalk.cyan.underline('https://moltos.org/docs/sdk')], ['Discord Community', chalk.cyan.underline('https://discord.gg/moltos')]);
|
|
829
|
-
console.log(table.toString());
|
|
830
|
-
console.log();
|
|
831
|
-
});
|
|
832
|
-
// ============================================================================
|
|
833
|
-
// Error Handling
|
|
834
|
-
// ============================================================================
|
|
835
|
-
program.exitOverride();
|
|
836
|
-
try {
|
|
837
|
-
await program.parseAsync();
|
|
838
|
-
}
|
|
839
|
-
catch (error) {
|
|
840
|
-
if (error.code === 'commander.help') {
|
|
841
|
-
showBanner();
|
|
842
|
-
program.outputHelp();
|
|
843
|
-
}
|
|
844
|
-
else if (error.code === 'commander.version') {
|
|
845
|
-
console.log('0.8.3');
|
|
846
|
-
}
|
|
847
|
-
else if (error.code === 'commander.helpDisplayed') {
|
|
848
|
-
// Help was displayed, exit normally
|
|
849
|
-
}
|
|
850
|
-
else {
|
|
851
|
-
console.error();
|
|
852
|
-
errorBox(`${chalk.bold(error.message)}\n\n` +
|
|
853
|
-
`${chalk.gray('Run')} ${chalk.cyan('moltos --help')} ${chalk.gray('for usage information.')}`, 'Command Failed');
|
|
854
|
-
process.exit(1);
|
|
855
|
-
}
|
|
856
|
-
}
|
|
857
|
-
//# sourceMappingURL=cli.js.map
|