@highway1/cli 0.1.49 → 0.1.50
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/index.js +5286 -1168
- package/dist/index.js.map +1 -1
- package/package.json +7 -7
- package/src/commands/ask.ts +158 -0
- package/src/commands/card.ts +8 -3
- package/src/commands/identity.ts +12 -3
- package/src/commands/inbox.ts +222 -0
- package/src/commands/peers.ts +85 -0
- package/src/commands/send.ts +13 -7
- package/src/commands/serve.ts +271 -0
- package/src/commands/status.ts +18 -3
- package/src/commands/stop.ts +49 -0
- package/src/commands/trust.ts +144 -5
- package/src/daemon/client.ts +31 -9
- package/src/daemon/server.ts +264 -51
- package/src/index.ts +10 -0
- package/LICENSE +0 -21
package/src/daemon/server.ts
CHANGED
|
@@ -1,5 +1,7 @@
|
|
|
1
1
|
import { createServer, Socket } from 'net';
|
|
2
2
|
import type { Server } from 'net';
|
|
3
|
+
import { homedir } from 'os';
|
|
4
|
+
import { join } from 'path';
|
|
3
5
|
import {
|
|
4
6
|
createNode,
|
|
5
7
|
importKeyPair,
|
|
@@ -10,18 +12,43 @@ import {
|
|
|
10
12
|
extractPublicKey,
|
|
11
13
|
createEnvelope,
|
|
12
14
|
signEnvelope,
|
|
15
|
+
createTrustSystem,
|
|
16
|
+
MessageQueue,
|
|
17
|
+
DefenseMiddleware,
|
|
13
18
|
type ClawiverseNode,
|
|
14
19
|
type MessageRouter,
|
|
15
20
|
type DHTOperations,
|
|
21
|
+
type TrustSystem,
|
|
22
|
+
type MessageEnvelope,
|
|
16
23
|
} from '@highway1/core';
|
|
17
24
|
import { createLogger } from '@highway1/core';
|
|
18
25
|
import { getIdentity, getBootstrapPeers } from '../config.js';
|
|
19
26
|
|
|
20
27
|
const logger = createLogger('daemon');
|
|
21
28
|
|
|
29
|
+
type DaemonCommand =
|
|
30
|
+
| 'send'
|
|
31
|
+
| 'discover'
|
|
32
|
+
| 'status'
|
|
33
|
+
| 'messages'
|
|
34
|
+
| 'shutdown'
|
|
35
|
+
// Queue commands
|
|
36
|
+
| 'inbox'
|
|
37
|
+
| 'get_message'
|
|
38
|
+
| 'mark_read'
|
|
39
|
+
| 'delete_message'
|
|
40
|
+
| 'outbox'
|
|
41
|
+
| 'retry_message'
|
|
42
|
+
// Defense commands
|
|
43
|
+
| 'block'
|
|
44
|
+
| 'unblock'
|
|
45
|
+
| 'allowlist'
|
|
46
|
+
// Stats
|
|
47
|
+
| 'queue_stats';
|
|
48
|
+
|
|
22
49
|
interface DaemonRequest {
|
|
23
50
|
id: string;
|
|
24
|
-
command:
|
|
51
|
+
command: DaemonCommand;
|
|
25
52
|
params: any;
|
|
26
53
|
}
|
|
27
54
|
|
|
@@ -41,6 +68,11 @@ export class ClawDaemon {
|
|
|
41
68
|
private identity: any;
|
|
42
69
|
private bootstrapPeers: string[];
|
|
43
70
|
|
|
71
|
+
// New: persistent queue + defense
|
|
72
|
+
private queue: MessageQueue | null = null;
|
|
73
|
+
private defense: DefenseMiddleware | null = null;
|
|
74
|
+
private trustSystem: TrustSystem | null = null;
|
|
75
|
+
|
|
44
76
|
constructor(socketPath: string = '/tmp/clawiverse.sock') {
|
|
45
77
|
this.socketPath = socketPath;
|
|
46
78
|
this.identity = getIdentity();
|
|
@@ -55,7 +87,6 @@ export class ClawDaemon {
|
|
|
55
87
|
try {
|
|
56
88
|
logger.info('Starting Clawiverse daemon', { socketPath: this.socketPath });
|
|
57
89
|
|
|
58
|
-
// Initialize node once (eliminates 4s overhead per command)
|
|
59
90
|
const keyPair = importKeyPair({
|
|
60
91
|
publicKey: this.identity.publicKey,
|
|
61
92
|
privateKey: this.identity.privateKey,
|
|
@@ -71,7 +102,6 @@ export class ClawDaemon {
|
|
|
71
102
|
await this.node.start();
|
|
72
103
|
logger.info('Node started', { peerId: this.node.getPeerId() });
|
|
73
104
|
|
|
74
|
-
// Initialize DHT and router
|
|
75
105
|
this.dht = createDHTOperations(this.node.libp2p);
|
|
76
106
|
|
|
77
107
|
const verifyFn = async (signature: Uint8Array, data: Uint8Array): Promise<boolean> => {
|
|
@@ -95,6 +125,35 @@ export class ClawDaemon {
|
|
|
95
125
|
await this.router.start();
|
|
96
126
|
logger.info('Router started');
|
|
97
127
|
|
|
128
|
+
// Initialize trust system
|
|
129
|
+
const dataDir = join(homedir(), '.clawiverse');
|
|
130
|
+
this.trustSystem = createTrustSystem({
|
|
131
|
+
dbPath: join(dataDir, 'trust'),
|
|
132
|
+
getPublicKey: async (did: string) => extractPublicKey(did),
|
|
133
|
+
});
|
|
134
|
+
await this.trustSystem.start();
|
|
135
|
+
logger.info('Trust system started');
|
|
136
|
+
|
|
137
|
+
// Initialize message queue (LevelDB persistence per CVP-0010 §2.3)
|
|
138
|
+
this.queue = new MessageQueue({
|
|
139
|
+
dbPath: join(dataDir, 'inbox'),
|
|
140
|
+
});
|
|
141
|
+
await this.queue.start();
|
|
142
|
+
logger.info('Message queue started');
|
|
143
|
+
|
|
144
|
+
// Initialize defense middleware
|
|
145
|
+
this.defense = new DefenseMiddleware({
|
|
146
|
+
trustSystem: this.trustSystem,
|
|
147
|
+
storage: this.queue.store,
|
|
148
|
+
minTrustScore: 0, // Accept all by default
|
|
149
|
+
});
|
|
150
|
+
logger.info('Defense middleware initialized');
|
|
151
|
+
|
|
152
|
+
// Register catch-all handler: defense check + queue persistence
|
|
153
|
+
this.router.registerCatchAllHandler(async (envelope) => {
|
|
154
|
+
return await this.handleIncomingMessage(envelope);
|
|
155
|
+
});
|
|
156
|
+
|
|
98
157
|
// Create IPC server
|
|
99
158
|
this.server = createServer((socket) => {
|
|
100
159
|
this.handleConnection(socket);
|
|
@@ -113,21 +172,68 @@ export class ClawDaemon {
|
|
|
113
172
|
}
|
|
114
173
|
}
|
|
115
174
|
|
|
175
|
+
private async handleIncomingMessage(envelope: MessageEnvelope): Promise<MessageEnvelope | void> {
|
|
176
|
+
if (!this.defense || !this.queue || !this.trustSystem) return;
|
|
177
|
+
|
|
178
|
+
// Run defense checks
|
|
179
|
+
const result = await this.defense.checkMessage(envelope);
|
|
180
|
+
if (!result.allowed) {
|
|
181
|
+
logger.warn('Message rejected by defense', { id: envelope.id, reason: result.reason });
|
|
182
|
+
return;
|
|
183
|
+
}
|
|
184
|
+
|
|
185
|
+
// Persist to inbox
|
|
186
|
+
await this.queue.enqueueInbound(envelope, result.trustScore);
|
|
187
|
+
|
|
188
|
+
// Record interaction for trust scoring
|
|
189
|
+
await this.trustSystem.recordInteraction({
|
|
190
|
+
agentDid: envelope.from,
|
|
191
|
+
timestamp: Date.now(),
|
|
192
|
+
type: 'message',
|
|
193
|
+
success: true,
|
|
194
|
+
responseTime: 0,
|
|
195
|
+
});
|
|
196
|
+
|
|
197
|
+
logger.info('Message queued', { id: envelope.id, from: envelope.from });
|
|
198
|
+
}
|
|
199
|
+
|
|
116
200
|
private handleConnection(socket: Socket): void {
|
|
201
|
+
let buffer = '';
|
|
202
|
+
|
|
117
203
|
socket.on('data', async (data) => {
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
204
|
+
buffer += data.toString();
|
|
205
|
+
// Handle newline-delimited JSON
|
|
206
|
+
const lines = buffer.split('\n');
|
|
207
|
+
buffer = lines.pop() ?? '';
|
|
208
|
+
|
|
209
|
+
for (const line of lines) {
|
|
210
|
+
if (!line.trim()) continue;
|
|
211
|
+
try {
|
|
212
|
+
const request: DaemonRequest = JSON.parse(line);
|
|
213
|
+
logger.debug('Received request', { command: request.command, id: request.id });
|
|
214
|
+
const response = await this.handleRequest(request);
|
|
215
|
+
socket.write(JSON.stringify(response) + '\n');
|
|
216
|
+
} catch (error) {
|
|
217
|
+
const errorResponse: DaemonResponse = {
|
|
218
|
+
id: 'unknown',
|
|
219
|
+
success: false,
|
|
220
|
+
error: (error as Error).message,
|
|
221
|
+
};
|
|
222
|
+
socket.write(JSON.stringify(errorResponse) + '\n');
|
|
223
|
+
}
|
|
224
|
+
}
|
|
225
|
+
|
|
226
|
+
// Also handle single-message (no newline) for backward compat
|
|
227
|
+
if (buffer.trim()) {
|
|
228
|
+
try {
|
|
229
|
+
const request: DaemonRequest = JSON.parse(buffer);
|
|
230
|
+
buffer = '';
|
|
231
|
+
logger.debug('Received request', { command: request.command, id: request.id });
|
|
232
|
+
const response = await this.handleRequest(request);
|
|
233
|
+
socket.write(JSON.stringify(response) + '\n');
|
|
234
|
+
} catch {
|
|
235
|
+
// Not complete JSON yet, keep buffering
|
|
236
|
+
}
|
|
131
237
|
}
|
|
132
238
|
});
|
|
133
239
|
|
|
@@ -139,19 +245,30 @@ export class ClawDaemon {
|
|
|
139
245
|
private async handleRequest(req: DaemonRequest): Promise<DaemonResponse> {
|
|
140
246
|
try {
|
|
141
247
|
switch (req.command) {
|
|
142
|
-
case 'send':
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
case '
|
|
146
|
-
return await this.handleDiscover(req);
|
|
147
|
-
|
|
148
|
-
case 'status':
|
|
149
|
-
return this.handleStatus(req);
|
|
150
|
-
|
|
248
|
+
case 'send': return await this.handleSend(req);
|
|
249
|
+
case 'discover': return await this.handleDiscover(req);
|
|
250
|
+
case 'status': return this.handleStatus(req);
|
|
251
|
+
case 'messages': return await this.handleMessages(req);
|
|
151
252
|
case 'shutdown':
|
|
152
253
|
await this.shutdown();
|
|
153
254
|
return { id: req.id, success: true };
|
|
154
255
|
|
|
256
|
+
// Queue commands
|
|
257
|
+
case 'inbox': return await this.handleInbox(req);
|
|
258
|
+
case 'get_message': return await this.handleGetMessage(req);
|
|
259
|
+
case 'mark_read': return await this.handleMarkRead(req);
|
|
260
|
+
case 'delete_message': return await this.handleDeleteMessage(req);
|
|
261
|
+
case 'outbox': return await this.handleOutbox(req);
|
|
262
|
+
case 'retry_message': return await this.handleRetryMessage(req);
|
|
263
|
+
|
|
264
|
+
// Defense commands
|
|
265
|
+
case 'block': return await this.handleBlock(req);
|
|
266
|
+
case 'unblock': return await this.handleUnblock(req);
|
|
267
|
+
case 'allowlist': return await this.handleAllowlist(req);
|
|
268
|
+
|
|
269
|
+
// Stats
|
|
270
|
+
case 'queue_stats': return await this.handleQueueStats(req);
|
|
271
|
+
|
|
155
272
|
default:
|
|
156
273
|
return { id: req.id, success: false, error: 'Unknown command' };
|
|
157
274
|
}
|
|
@@ -168,7 +285,6 @@ export class ClawDaemon {
|
|
|
168
285
|
return { id: req.id, success: false, error: 'Router not initialized' };
|
|
169
286
|
}
|
|
170
287
|
|
|
171
|
-
// Create and sign envelope
|
|
172
288
|
const envelope = createEnvelope(
|
|
173
289
|
this.identity.did,
|
|
174
290
|
to,
|
|
@@ -186,52 +302,41 @@ export class ClawDaemon {
|
|
|
186
302
|
sign(data, keyPair.privateKey)
|
|
187
303
|
);
|
|
188
304
|
|
|
189
|
-
//
|
|
305
|
+
// Track outbound in queue
|
|
306
|
+
if (this.queue) {
|
|
307
|
+
await this.queue.enqueueOutbound(signedEnvelope);
|
|
308
|
+
}
|
|
309
|
+
|
|
190
310
|
let peerHint = undefined;
|
|
191
311
|
if (peer) {
|
|
192
312
|
const parts = peer.split('/p2p/');
|
|
193
313
|
if (parts.length >= 2) {
|
|
194
|
-
peerHint = {
|
|
195
|
-
peerId: parts[parts.length - 1],
|
|
196
|
-
multiaddrs: [peer],
|
|
197
|
-
};
|
|
314
|
+
peerHint = { peerId: parts[parts.length - 1], multiaddrs: [peer] };
|
|
198
315
|
}
|
|
199
316
|
}
|
|
200
317
|
|
|
201
|
-
// Send message
|
|
202
318
|
const response = await this.router.sendMessage(signedEnvelope, peerHint);
|
|
203
319
|
|
|
320
|
+
if (this.queue) {
|
|
321
|
+
await this.queue.markOutboundDelivered(signedEnvelope.id);
|
|
322
|
+
}
|
|
323
|
+
|
|
204
324
|
return {
|
|
205
325
|
id: req.id,
|
|
206
326
|
success: true,
|
|
207
|
-
data: {
|
|
208
|
-
id: signedEnvelope.id,
|
|
209
|
-
response: response || null,
|
|
210
|
-
},
|
|
327
|
+
data: { id: signedEnvelope.id, response: response || null },
|
|
211
328
|
};
|
|
212
329
|
}
|
|
213
330
|
|
|
214
331
|
private async handleDiscover(req: DaemonRequest): Promise<DaemonResponse> {
|
|
215
332
|
const { query } = req.params;
|
|
216
|
-
|
|
217
|
-
if (!this.dht) {
|
|
218
|
-
return { id: req.id, success: false, error: 'DHT not initialized' };
|
|
219
|
-
}
|
|
220
|
-
|
|
333
|
+
if (!this.dht) return { id: req.id, success: false, error: 'DHT not initialized' };
|
|
221
334
|
const results = await this.dht.searchSemantic(query);
|
|
222
|
-
|
|
223
|
-
return {
|
|
224
|
-
id: req.id,
|
|
225
|
-
success: true,
|
|
226
|
-
data: results,
|
|
227
|
-
};
|
|
335
|
+
return { id: req.id, success: true, data: results };
|
|
228
336
|
}
|
|
229
337
|
|
|
230
338
|
private handleStatus(req: DaemonRequest): DaemonResponse {
|
|
231
|
-
if (!this.node) {
|
|
232
|
-
return { id: req.id, success: false, error: 'Node not initialized' };
|
|
233
|
-
}
|
|
234
|
-
|
|
339
|
+
if (!this.node) return { id: req.id, success: false, error: 'Node not initialized' };
|
|
235
340
|
return {
|
|
236
341
|
id: req.id,
|
|
237
342
|
success: true,
|
|
@@ -245,6 +350,104 @@ export class ClawDaemon {
|
|
|
245
350
|
};
|
|
246
351
|
}
|
|
247
352
|
|
|
353
|
+
/** Legacy messages command — delegates to inbox for backward compat */
|
|
354
|
+
private async handleMessages(req: DaemonRequest): Promise<DaemonResponse> {
|
|
355
|
+
const { limit = 10 } = req.params || {};
|
|
356
|
+
if (this.queue) {
|
|
357
|
+
const page = await this.queue.getInbox({}, { limit });
|
|
358
|
+
return {
|
|
359
|
+
id: req.id,
|
|
360
|
+
success: true,
|
|
361
|
+
data: {
|
|
362
|
+
messages: page.messages.map((m) => ({ ...m.envelope, receivedAt: m.receivedAt })),
|
|
363
|
+
total: page.total,
|
|
364
|
+
},
|
|
365
|
+
};
|
|
366
|
+
}
|
|
367
|
+
return { id: req.id, success: true, data: { messages: [], total: 0 } };
|
|
368
|
+
}
|
|
369
|
+
|
|
370
|
+
// ─── Queue Handlers ───────────────────────────────────────────────────────
|
|
371
|
+
|
|
372
|
+
private async handleInbox(req: DaemonRequest): Promise<DaemonResponse> {
|
|
373
|
+
if (!this.queue) return { id: req.id, success: false, error: 'Queue not initialized' };
|
|
374
|
+
const { filter, pagination } = req.params || {};
|
|
375
|
+
const page = await this.queue.getInbox(filter, pagination);
|
|
376
|
+
return { id: req.id, success: true, data: page };
|
|
377
|
+
}
|
|
378
|
+
|
|
379
|
+
private async handleGetMessage(req: DaemonRequest): Promise<DaemonResponse> {
|
|
380
|
+
if (!this.queue) return { id: req.id, success: false, error: 'Queue not initialized' };
|
|
381
|
+
const { id } = req.params;
|
|
382
|
+
const msg = await this.queue.getMessage(id);
|
|
383
|
+
if (!msg) return { id: req.id, success: false, error: 'Message not found' };
|
|
384
|
+
return { id: req.id, success: true, data: msg };
|
|
385
|
+
}
|
|
386
|
+
|
|
387
|
+
private async handleMarkRead(req: DaemonRequest): Promise<DaemonResponse> {
|
|
388
|
+
if (!this.queue) return { id: req.id, success: false, error: 'Queue not initialized' };
|
|
389
|
+
await this.queue.markAsRead(req.params.id);
|
|
390
|
+
return { id: req.id, success: true };
|
|
391
|
+
}
|
|
392
|
+
|
|
393
|
+
private async handleDeleteMessage(req: DaemonRequest): Promise<DaemonResponse> {
|
|
394
|
+
if (!this.queue) return { id: req.id, success: false, error: 'Queue not initialized' };
|
|
395
|
+
await this.queue.deleteMessage(req.params.id);
|
|
396
|
+
return { id: req.id, success: true };
|
|
397
|
+
}
|
|
398
|
+
|
|
399
|
+
private async handleOutbox(req: DaemonRequest): Promise<DaemonResponse> {
|
|
400
|
+
if (!this.queue) return { id: req.id, success: false, error: 'Queue not initialized' };
|
|
401
|
+
const page = await this.queue.getOutbox(req.params?.pagination);
|
|
402
|
+
return { id: req.id, success: true, data: page };
|
|
403
|
+
}
|
|
404
|
+
|
|
405
|
+
private async handleRetryMessage(req: DaemonRequest): Promise<DaemonResponse> {
|
|
406
|
+
if (!this.queue) return { id: req.id, success: false, error: 'Queue not initialized' };
|
|
407
|
+
await this.queue.retryMessage(req.params.id);
|
|
408
|
+
return { id: req.id, success: true };
|
|
409
|
+
}
|
|
410
|
+
|
|
411
|
+
// ─── Defense Handlers ─────────────────────────────────────────────────────
|
|
412
|
+
|
|
413
|
+
private async handleBlock(req: DaemonRequest): Promise<DaemonResponse> {
|
|
414
|
+
if (!this.defense) return { id: req.id, success: false, error: 'Defense not initialized' };
|
|
415
|
+
const { did, reason = 'Blocked by user' } = req.params;
|
|
416
|
+
await this.defense.blockAgent(did, reason, this.identity.did);
|
|
417
|
+
return { id: req.id, success: true };
|
|
418
|
+
}
|
|
419
|
+
|
|
420
|
+
private async handleUnblock(req: DaemonRequest): Promise<DaemonResponse> {
|
|
421
|
+
if (!this.defense) return { id: req.id, success: false, error: 'Defense not initialized' };
|
|
422
|
+
await this.defense.unblockAgent(req.params.did);
|
|
423
|
+
return { id: req.id, success: true };
|
|
424
|
+
}
|
|
425
|
+
|
|
426
|
+
private async handleAllowlist(req: DaemonRequest): Promise<DaemonResponse> {
|
|
427
|
+
if (!this.defense || !this.queue) return { id: req.id, success: false, error: 'Defense not initialized' };
|
|
428
|
+
const { action, did, note } = req.params;
|
|
429
|
+
switch (action) {
|
|
430
|
+
case 'add':
|
|
431
|
+
await this.defense.allowAgent(did, note);
|
|
432
|
+
return { id: req.id, success: true };
|
|
433
|
+
case 'remove':
|
|
434
|
+
await this.defense.removeFromAllowlist(did);
|
|
435
|
+
return { id: req.id, success: true };
|
|
436
|
+
case 'list': {
|
|
437
|
+
const entries = await this.queue.store.listAllowed();
|
|
438
|
+
return { id: req.id, success: true, data: entries };
|
|
439
|
+
}
|
|
440
|
+
default:
|
|
441
|
+
return { id: req.id, success: false, error: `Unknown allowlist action: ${action}` };
|
|
442
|
+
}
|
|
443
|
+
}
|
|
444
|
+
|
|
445
|
+
private async handleQueueStats(req: DaemonRequest): Promise<DaemonResponse> {
|
|
446
|
+
if (!this.queue) return { id: req.id, success: false, error: 'Queue not initialized' };
|
|
447
|
+
const stats = await this.queue.getStats();
|
|
448
|
+
return { id: req.id, success: true, data: stats };
|
|
449
|
+
}
|
|
450
|
+
|
|
248
451
|
async shutdown(): Promise<void> {
|
|
249
452
|
logger.info('Shutting down daemon');
|
|
250
453
|
|
|
@@ -253,6 +456,16 @@ export class ClawDaemon {
|
|
|
253
456
|
this.router = null;
|
|
254
457
|
}
|
|
255
458
|
|
|
459
|
+
if (this.queue) {
|
|
460
|
+
await this.queue.stop();
|
|
461
|
+
this.queue = null;
|
|
462
|
+
}
|
|
463
|
+
|
|
464
|
+
if (this.trustSystem) {
|
|
465
|
+
await this.trustSystem.stop();
|
|
466
|
+
this.trustSystem = null;
|
|
467
|
+
}
|
|
468
|
+
|
|
256
469
|
if (this.node) {
|
|
257
470
|
await this.node.stop();
|
|
258
471
|
this.node = null;
|
package/src/index.ts
CHANGED
|
@@ -24,6 +24,11 @@ import { registerIdentityCommand } from './commands/identity.js';
|
|
|
24
24
|
import { registerCardCommand } from './commands/card.js';
|
|
25
25
|
import { createTrustCommand } from './commands/trust.js';
|
|
26
26
|
import { registerDaemonCommand } from './commands/daemon.js';
|
|
27
|
+
import { createInboxCommand } from './commands/inbox.js';
|
|
28
|
+
import { registerStopCommand } from './commands/stop.js';
|
|
29
|
+
import { registerAskCommand } from './commands/ask.js';
|
|
30
|
+
import { registerServeCommand } from './commands/serve.js';
|
|
31
|
+
import { registerPeersCommand } from './commands/peers.js';
|
|
27
32
|
|
|
28
33
|
const require = createRequire(import.meta.url);
|
|
29
34
|
const { version } = require('../package.json');
|
|
@@ -42,10 +47,15 @@ registerInitCommand(program);
|
|
|
42
47
|
registerJoinCommand(program);
|
|
43
48
|
registerDiscoverCommand(program);
|
|
44
49
|
registerSendCommand(program);
|
|
50
|
+
registerAskCommand(program);
|
|
51
|
+
registerServeCommand(program);
|
|
52
|
+
registerPeersCommand(program);
|
|
45
53
|
registerStatusCommand(program);
|
|
46
54
|
registerIdentityCommand(program);
|
|
47
55
|
registerCardCommand(program);
|
|
48
56
|
registerDaemonCommand(program);
|
|
57
|
+
registerStopCommand(program);
|
|
49
58
|
program.addCommand(createTrustCommand());
|
|
59
|
+
program.addCommand(createInboxCommand());
|
|
50
60
|
|
|
51
61
|
program.parse();
|
package/LICENSE
DELETED
|
@@ -1,21 +0,0 @@
|
|
|
1
|
-
MIT License
|
|
2
|
-
|
|
3
|
-
Copyright (c) 2026 Clawiverse Contributors
|
|
4
|
-
|
|
5
|
-
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
-
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
-
in the Software without restriction, including without limitation the rights
|
|
8
|
-
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
-
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
-
furnished to do so, subject to the following conditions:
|
|
11
|
-
|
|
12
|
-
The above copyright notice and this permission notice shall be included in all
|
|
13
|
-
copies or substantial portions of the Software.
|
|
14
|
-
|
|
15
|
-
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
-
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
-
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
-
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
-
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
-
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
-
SOFTWARE.
|