@highway1/cli 0.1.53 → 0.1.55

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.
@@ -1,354 +0,0 @@
1
- /**
2
- * Trust Command - Manage trust scores and endorsements
3
- */
4
-
5
- import { Command } from 'commander';
6
- import { getConfig, getIdentity } from '../config.js';
7
- import { createLogger, createTrustSystem, extractPublicKey } from '@highway1/core';
8
- import { homedir } from 'os';
9
- import { join } from 'path';
10
-
11
- const logger = createLogger('cli:trust');
12
-
13
- export function createTrustCommand(): Command {
14
- const trust = new Command('trust')
15
- .description('Manage trust scores and endorsements');
16
-
17
- // Show trust score
18
- trust
19
- .command('show')
20
- .description('Show trust score for an agent')
21
- .argument('<did>', 'Agent DID')
22
- .action(async (did: string) => {
23
- try {
24
- const dataDir = join(homedir(), '.clawiverse');
25
- const trustSystem = createTrustSystem({
26
- dbPath: `${dataDir}/trust`,
27
- getPublicKey: async (did: string) => extractPublicKey(did), // CVP-0010 §4.1 fix
28
- });
29
-
30
- await trustSystem.start();
31
-
32
- const score = await trustSystem.getTrustScore(did);
33
- const endorsements = await trustSystem.getEndorsements(did);
34
-
35
- console.log('\n📊 Trust Score for', did);
36
- console.log('─'.repeat(60));
37
- console.log(`Interaction Score: ${(score.interactionScore * 100).toFixed(1)}%`);
38
- console.log(`Endorsements: ${score.endorsements}`);
39
- console.log(`Completion Rate: ${(score.completionRate * 100).toFixed(1)}%`);
40
- console.log(`Response Time: ${score.responseTime.toFixed(0)}ms`);
41
- console.log(`Uptime: ${(score.uptime * 100).toFixed(1)}%`);
42
- console.log(`Last Updated: ${new Date(score.lastUpdated).toLocaleString()}`);
43
-
44
- if (endorsements.length > 0) {
45
- console.log('\n✨ Endorsements:');
46
- for (const e of endorsements) {
47
- console.log(` • From: ${e.from}`);
48
- console.log(` Score: ${(e.score * 100).toFixed(0)}%`);
49
- console.log(` Reason: ${e.reason}`);
50
- console.log(` Date: ${new Date(e.timestamp).toLocaleDateString()}`);
51
- }
52
- }
53
-
54
- await trustSystem.stop();
55
- } catch (error) {
56
- logger.error('Failed to show trust score', error);
57
- console.error('Error:', error instanceof Error ? error.message : error);
58
- process.exit(1);
59
- }
60
- });
61
-
62
- // Endorse an agent
63
- trust
64
- .command('endorse')
65
- .description('Endorse an agent')
66
- .argument('<did>', 'Agent DID to endorse')
67
- .option('-s, --score <score>', 'Endorsement score (0-1)', '0.8')
68
- .option('-r, --reason <reason>', 'Reason for endorsement', 'Good collaboration')
69
- .action(async (did: string, options: { score: string; reason: string }) => {
70
- try {
71
- const dataDir = join(homedir(), '.clawiverse');
72
- const trustSystem = createTrustSystem({
73
- dbPath: `${dataDir}/trust`,
74
- getPublicKey: async (did: string) => extractPublicKey(did), // CVP-0010 §4.1 fix
75
- });
76
-
77
- await trustSystem.start();
78
-
79
- const score = parseFloat(options.score);
80
- if (isNaN(score) || score < 0 || score > 1) {
81
- throw new Error('Score must be between 0 and 1');
82
- }
83
-
84
- // Load identity for signing
85
- const identity = getIdentity();
86
- if (!identity) {
87
- throw new Error('No identity found. Run "hw1 init" first.');
88
- }
89
-
90
- const { importKeyPair } = await import('@highway1/core');
91
- const keyPair = importKeyPair({
92
- publicKey: identity.publicKey,
93
- privateKey: identity.privateKey,
94
- });
95
-
96
- const endorsement = await trustSystem.endorse(
97
- identity.did,
98
- did,
99
- score,
100
- options.reason,
101
- keyPair.sign
102
- );
103
-
104
- console.log('\n✅ Endorsement created');
105
- console.log(`From: ${endorsement.from}`);
106
- console.log(`To: ${endorsement.to}`);
107
- console.log(`Score: ${(endorsement.score * 100).toFixed(0)}%`);
108
- console.log(`Reason: ${endorsement.reason}`);
109
-
110
- await trustSystem.stop();
111
- } catch (error) {
112
- logger.error('Failed to endorse agent', error);
113
- console.error('Error:', error instanceof Error ? error.message : error);
114
- process.exit(1);
115
- }
116
- });
117
-
118
- // Show interaction history
119
- trust
120
- .command('history')
121
- .description('Show interaction history with an agent')
122
- .argument('<did>', 'Agent DID')
123
- .option('-l, --limit <limit>', 'Number of interactions to show', '10')
124
- .action(async (did: string, options: { limit: string }) => {
125
- try {
126
- const dataDir = join(homedir(), '.clawiverse');
127
- const trustSystem = createTrustSystem({
128
- dbPath: `${dataDir}/trust`,
129
- getPublicKey: async (did: string) => extractPublicKey(did), // CVP-0010 §4.1 fix
130
- });
131
-
132
- await trustSystem.start();
133
-
134
- const limit = parseInt(options.limit, 10);
135
- const history = await trustSystem.getHistory(did, limit);
136
-
137
- console.log(`\n📜 Interaction History with ${did}`);
138
- console.log('─'.repeat(60));
139
-
140
- if (history.length === 0) {
141
- console.log('No interactions recorded');
142
- } else {
143
- for (const interaction of history) {
144
- const status = interaction.success ? '✅' : '❌';
145
- console.log(`${status} ${interaction.type} - ${new Date(interaction.timestamp).toLocaleString()}`);
146
- console.log(` Response time: ${interaction.responseTime}ms`);
147
- if (interaction.rating) {
148
- console.log(` Rating: ${'⭐'.repeat(interaction.rating)}`);
149
- }
150
- if (interaction.feedback) {
151
- console.log(` Feedback: ${interaction.feedback}`);
152
- }
153
- }
154
- }
155
-
156
- await trustSystem.stop();
157
- } catch (error) {
158
- logger.error('Failed to show history', error);
159
- console.error('Error:', error instanceof Error ? error.message : error);
160
- process.exit(1);
161
- }
162
- });
163
-
164
- // Show trust statistics
165
- trust
166
- .command('stats')
167
- .description('Show local trust statistics')
168
- .action(async () => {
169
- try {
170
- const dataDir = join(homedir(), '.clawiverse');
171
- const trustSystem = createTrustSystem({
172
- dbPath: `${dataDir}/trust`,
173
- getPublicKey: async (did: string) => extractPublicKey(did), // CVP-0010 §4.1 fix
174
- });
175
-
176
- await trustSystem.start();
177
-
178
- // Get all agents from interaction history
179
- const { InteractionHistory } = await import('@highway1/core');
180
- const history = new InteractionHistory(`${dataDir}/trust/interactions`);
181
- await history.open();
182
-
183
- const agents = await history.getAllAgents();
184
-
185
- console.log('\n📊 Trust Statistics');
186
- console.log('─'.repeat(60));
187
- console.log(`Total agents tracked: ${agents.length}`);
188
-
189
- if (agents.length > 0) {
190
- console.log('\nTop agents by trust score:');
191
- const scores = await Promise.all(
192
- agents.map(async (did) => ({
193
- did,
194
- score: await trustSystem.getTrustScore(did),
195
- }))
196
- );
197
-
198
- scores.sort((a, b) => b.score.interactionScore - a.score.interactionScore);
199
-
200
- for (const { did, score } of scores.slice(0, 5)) {
201
- console.log(` ${(score.interactionScore * 100).toFixed(0)}% - ${did}`);
202
- }
203
- }
204
-
205
- await history.close();
206
- await trustSystem.stop();
207
- } catch (error) {
208
- logger.error('Failed to show stats', error);
209
- console.error('Error:', error instanceof Error ? error.message : error);
210
- process.exit(1);
211
- }
212
- });
213
-
214
- // Block an agent (via daemon defense layer)
215
- trust
216
- .command('block <did>')
217
- .description('Block an agent from sending you messages')
218
- .option('-r, --reason <reason>', 'Reason for blocking', 'Blocked by user')
219
- .action(async (did: string, options: { reason: string }) => {
220
- try {
221
- const { DaemonClient } = await import('../daemon/client.js');
222
- const client = new DaemonClient();
223
- if (await client.isDaemonRunning()) {
224
- await client.send('block', { did, reason: options.reason });
225
- console.log(`Blocked ${did}`);
226
- } else {
227
- // Daemon not running — write directly to storage
228
- const { MessageStorage } = await import('@highway1/core');
229
- const storage = new MessageStorage(join(homedir(), '.clawiverse', 'inbox'));
230
- await storage.open();
231
- await storage.putBlock({ did, reason: options.reason, blockedAt: Date.now(), blockedBy: 'local' });
232
- await storage.close();
233
- console.log(`Blocked ${did}`);
234
- }
235
- } catch (error) {
236
- logger.error('Failed to block agent', error);
237
- console.error('Error:', error instanceof Error ? error.message : error);
238
- process.exit(1);
239
- }
240
- });
241
-
242
- // Unblock an agent
243
- trust
244
- .command('unblock <did>')
245
- .description('Unblock a previously blocked agent')
246
- .action(async (did: string) => {
247
- try {
248
- const { DaemonClient } = await import('../daemon/client.js');
249
- const client = new DaemonClient();
250
- if (await client.isDaemonRunning()) {
251
- await client.send('unblock', { did });
252
- } else {
253
- const { MessageStorage } = await import('@highway1/core');
254
- const storage = new MessageStorage(join(homedir(), '.clawiverse', 'inbox'));
255
- await storage.open();
256
- await storage.deleteBlock(did);
257
- await storage.close();
258
- }
259
- console.log(`Unblocked ${did}`);
260
- } catch (error) {
261
- logger.error('Failed to unblock agent', error);
262
- console.error('Error:', error instanceof Error ? error.message : error);
263
- process.exit(1);
264
- }
265
- });
266
-
267
- // List blocked agents
268
- trust
269
- .command('list-blocked')
270
- .description('List all blocked agents')
271
- .action(async () => {
272
- try {
273
- const { MessageStorage } = await import('@highway1/core');
274
- const storage = new MessageStorage(join(homedir(), '.clawiverse', 'inbox'));
275
- await storage.open();
276
- const blocked = await storage.listBlocked();
277
- await storage.close();
278
-
279
- if (blocked.length === 0) {
280
- console.log('No blocked agents.');
281
- return;
282
- }
283
- console.log(`\nBlocked agents (${blocked.length}):\n`);
284
- for (const entry of blocked) {
285
- console.log(` ${entry.did}`);
286
- console.log(` Reason: ${entry.reason}`);
287
- console.log(` Blocked: ${new Date(entry.blockedAt).toLocaleString()}`);
288
- }
289
- console.log();
290
- } catch (error) {
291
- logger.error('Failed to list blocked agents', error);
292
- console.error('Error:', error instanceof Error ? error.message : error);
293
- process.exit(1);
294
- }
295
- });
296
-
297
- // Add to allowlist
298
- trust
299
- .command('allow <did>')
300
- .description('Add an agent to your allowlist (bypasses all defense checks)')
301
- .option('-n, --note <note>', 'Note about this agent')
302
- .action(async (did: string, options: { note?: string }) => {
303
- try {
304
- const { DaemonClient } = await import('../daemon/client.js');
305
- const client = new DaemonClient();
306
- if (await client.isDaemonRunning()) {
307
- await client.send('allowlist', { action: 'add', did, note: options.note });
308
- } else {
309
- const { MessageStorage } = await import('@highway1/core');
310
- const storage = new MessageStorage(join(homedir(), '.clawiverse', 'inbox'));
311
- await storage.open();
312
- await storage.putAllow({ did, addedAt: Date.now(), note: options.note });
313
- await storage.close();
314
- }
315
- console.log(`Added ${did} to allowlist`);
316
- } catch (error) {
317
- logger.error('Failed to allowlist agent', error);
318
- console.error('Error:', error instanceof Error ? error.message : error);
319
- process.exit(1);
320
- }
321
- });
322
-
323
- // List allowlisted agents
324
- trust
325
- .command('list-allowed')
326
- .description('List all allowlisted agents')
327
- .action(async () => {
328
- try {
329
- const { MessageStorage } = await import('@highway1/core');
330
- const storage = new MessageStorage(join(homedir(), '.clawiverse', 'inbox'));
331
- await storage.open();
332
- const allowed = await storage.listAllowed();
333
- await storage.close();
334
-
335
- if (allowed.length === 0) {
336
- console.log('No allowlisted agents.');
337
- return;
338
- }
339
- console.log(`\nAllowlisted agents (${allowed.length}):\n`);
340
- for (const entry of allowed) {
341
- console.log(` ${entry.did}`);
342
- if (entry.note) console.log(` Note: ${entry.note}`);
343
- console.log(` Added: ${new Date(entry.addedAt).toLocaleString()}`);
344
- }
345
- console.log();
346
- } catch (error) {
347
- logger.error('Failed to list allowed agents', error);
348
- console.error('Error:', error instanceof Error ? error.message : error);
349
- process.exit(1);
350
- }
351
- });
352
-
353
- return trust;
354
- }
package/src/config.ts DELETED
@@ -1,74 +0,0 @@
1
- import Conf from 'conf';
2
- import { homedir } from 'os';
3
- import { join } from 'path';
4
-
5
- export interface ClawiverseConfig {
6
- identity?: {
7
- did: string;
8
- publicKey: string;
9
- privateKey: string;
10
- };
11
- network?: {
12
- bootstrapPeers: string[];
13
- listenAddresses: string[];
14
- };
15
- agentCard?: {
16
- name: string;
17
- description: string;
18
- capabilities: string[];
19
- };
20
- }
21
-
22
- const CLAWIVERSE_HOME = process.env.CLAWIVERSE_HOME || join(homedir(), '.clawiverse');
23
-
24
- const config = new Conf<ClawiverseConfig>({
25
- projectName: 'clawiverse',
26
- cwd: CLAWIVERSE_HOME,
27
- });
28
-
29
- export function getConfig(): ClawiverseConfig {
30
- return config.store;
31
- }
32
-
33
- export function setConfig(key: string, value: unknown): void {
34
- config.set(key, value);
35
- }
36
-
37
- export function getConfigValue<T>(key: string): T | undefined {
38
- return config.get(key) as T | undefined;
39
- }
40
-
41
- export function hasIdentity(): boolean {
42
- return config.has('identity');
43
- }
44
-
45
- export function getIdentity() {
46
- return config.get('identity');
47
- }
48
-
49
- export function setIdentity(identity: ClawiverseConfig['identity']): void {
50
- config.set('identity', identity);
51
- }
52
-
53
- export function getAgentCard() {
54
- return config.get('agentCard');
55
- }
56
-
57
- export function setAgentCard(card: ClawiverseConfig['agentCard']): void {
58
- config.set('agentCard', card);
59
- }
60
-
61
- // Default public bootstrap nodes (update after deployment)
62
- const DEFAULT_BOOTSTRAP_PEERS: string[] = [
63
- '/dns4/hw1.woowot.com/tcp/4001/p2p/12D3KooWH9R8d4bhzpfyWi3aY5wLBsmLp1LU8ZGk9V7rK17sfzaW',
64
- ];
65
-
66
- export function getBootstrapPeers(): string[] {
67
- const userPeers = config.get('network.bootstrapPeers') as string[] | undefined;
68
- if (userPeers && userPeers.length > 0) return userPeers;
69
- return DEFAULT_BOOTSTRAP_PEERS;
70
- }
71
-
72
- export function setBootstrapPeers(peers: string[]): void {
73
- config.set('network.bootstrapPeers', peers);
74
- }
@@ -1,90 +0,0 @@
1
- import { connect, Socket } from 'net';
2
- import { createLogger } from '@highway1/core';
3
-
4
- const logger = createLogger('daemon-client');
5
-
6
- export class DaemonClient {
7
- private socketPath: string;
8
-
9
- constructor(socketPath: string = '/tmp/clawiverse.sock') {
10
- this.socketPath = socketPath;
11
- }
12
-
13
- async send(command: string, params: any): Promise<any> {
14
- return new Promise((resolve, reject) => {
15
- const socket = connect(this.socketPath);
16
- const requestId = `req_${Date.now()}_${Math.random().toString(36).slice(2)}`;
17
-
18
- let responseReceived = false;
19
- let buffer = ''; // CVP-0010 §1.2: Buffer for NDJSON framing
20
-
21
- socket.on('connect', () => {
22
- const request = { id: requestId, command, params };
23
- logger.debug('Sending request', { command, id: requestId });
24
- // CVP-0010 §1.2: Send with newline delimiter
25
- socket.write(JSON.stringify(request) + '\n');
26
- });
27
-
28
- socket.on('data', (data) => {
29
- try {
30
- // CVP-0010 §1.2: Accumulate data and split by newlines
31
- buffer += data.toString();
32
- const lines = buffer.split('\n');
33
-
34
- // Keep incomplete line in buffer
35
- buffer = lines.pop() || '';
36
-
37
- // Process complete lines
38
- for (const line of lines) {
39
- if (!line.trim()) continue;
40
-
41
- const response = JSON.parse(line);
42
-
43
- // Match response by ID
44
- if (response.id !== requestId) {
45
- logger.debug('Ignoring unmatched response', { responseId: response.id, requestId });
46
- continue;
47
- }
48
-
49
- responseReceived = true;
50
- socket.end();
51
-
52
- logger.debug('Received response', { success: response.success, id: response.id });
53
-
54
- if (response.success) {
55
- resolve(response.data);
56
- } else {
57
- reject(new Error(response.error));
58
- }
59
- return;
60
- }
61
- } catch (error) {
62
- reject(new Error(`Failed to parse response: ${(error as Error).message}`));
63
- }
64
- });
65
-
66
- socket.on('error', (err) => {
67
- if (!responseReceived) {
68
- logger.debug('Socket error', { error: err.message });
69
- reject(err);
70
- }
71
- });
72
-
73
- socket.setTimeout(30000, () => {
74
- if (!responseReceived) {
75
- socket.destroy();
76
- reject(new Error('Request timeout'));
77
- }
78
- });
79
- });
80
- }
81
-
82
- async isDaemonRunning(): Promise<boolean> {
83
- try {
84
- await this.send('status', {});
85
- return true;
86
- } catch {
87
- return false;
88
- }
89
- }
90
- }