@highway1/cli 0.1.41 → 0.1.43

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,160 +0,0 @@
1
- import { Command } from 'commander';
2
- import {
3
- createNode,
4
- importKeyPair,
5
- createEnvelope,
6
- signEnvelope,
7
- createMessageRouter,
8
- createDHTOperations,
9
- sign,
10
- verify,
11
- extractPublicKey,
12
- } from '@highway1/core';
13
- import { getIdentity, getBootstrapPeers } from '../config.js';
14
- import { success, error, spinner, printHeader, info } from '../ui.js';
15
-
16
- export function registerSendCommand(program: Command): void {
17
- program
18
- .command('send')
19
- .description('Send a message to another agent')
20
- .requiredOption('--to <did>', 'Recipient DID')
21
- .requiredOption('--protocol <protocol>', 'Protocol identifier')
22
- .requiredOption('--payload <json>', 'Message payload (JSON)')
23
- .option('--type <type>', 'Message type (request|notification)', 'request')
24
- .option('--bootstrap <peers...>', 'Bootstrap peer addresses')
25
- .option('--peer <multiaddr>', 'Direct peer multiaddr (bypasses DHT lookup)')
26
- .action(async (options) => {
27
- try {
28
- printHeader('Send Message');
29
-
30
- const identity = getIdentity();
31
-
32
- if (!identity) {
33
- error('No identity found. Run "hw1 init" first.');
34
- process.exit(1);
35
- }
36
-
37
- let payload;
38
- try {
39
- payload = JSON.parse(options.payload);
40
- } catch {
41
- error('Invalid JSON payload');
42
- process.exit(1);
43
- }
44
-
45
- const spin = spinner('Starting node...');
46
-
47
- const keyPair = importKeyPair({
48
- publicKey: identity.publicKey,
49
- privateKey: identity.privateKey,
50
- });
51
-
52
- const bootstrapPeers = options.bootstrap || getBootstrapPeers();
53
-
54
- const node = await createNode({
55
- keyPair,
56
- bootstrapPeers,
57
- enableDHT: true,
58
- });
59
-
60
- // Register peer:identify listener BEFORE start() so we don't miss the event
61
- const identifyDone = new Promise<void>((resolve) => {
62
- const timeout = setTimeout(resolve, 12000);
63
- node.libp2p.addEventListener('peer:identify', () => {
64
- clearTimeout(timeout);
65
- setTimeout(resolve, 500);
66
- }, { once: true });
67
- });
68
-
69
- await node.start();
70
-
71
- spin.text = 'Connecting to network...';
72
- await identifyDone;
73
-
74
- const dht = createDHTOperations(node.libp2p);
75
- const verifyFn = async (signature: Uint8Array, data: Uint8Array): Promise<boolean> => {
76
- try {
77
- const decoded = JSON.parse(new TextDecoder().decode(data)) as { from?: string };
78
- if (!decoded.from || typeof decoded.from !== 'string') return false;
79
- const senderPublicKey = extractPublicKey(decoded.from);
80
- return verify(signature, data, senderPublicKey);
81
- } catch {
82
- return false;
83
- }
84
- };
85
-
86
- const router = createMessageRouter(
87
- node.libp2p,
88
- verifyFn,
89
- dht,
90
- bootstrapPeers
91
- );
92
-
93
- await router.start();
94
-
95
- spin.text = 'Creating message...';
96
-
97
- const envelope = createEnvelope(
98
- identity.did,
99
- options.to,
100
- options.type,
101
- options.protocol,
102
- payload
103
- );
104
-
105
- const signedEnvelope = await signEnvelope(envelope, (data) =>
106
- sign(data, keyPair.privateKey)
107
- );
108
-
109
- spin.text = 'Sending message...';
110
-
111
- // Build peer hint from --peer option if provided
112
- let peerHint = undefined;
113
- if (options.peer) {
114
- // Extract peerId from multiaddr (last component after /p2p/)
115
- const parts = options.peer.split('/p2p/');
116
- if (parts.length === 2) {
117
- peerHint = {
118
- peerId: parts[1],
119
- multiaddrs: [options.peer],
120
- };
121
- info(`Direct peer: ${options.peer}`);
122
- }
123
- }
124
-
125
- const response = await router.sendMessage(signedEnvelope, peerHint);
126
-
127
- spin.succeed('Message sent successfully!');
128
-
129
- console.log();
130
- info(`Message ID: ${signedEnvelope.id}`);
131
- info(`To: ${options.to}`);
132
- info(`Protocol: ${options.protocol}`);
133
- info(`Type: ${options.type}`);
134
- info(`Payload: ${JSON.stringify(payload)}`);
135
-
136
- // Display response if received
137
- if (response) {
138
- console.log();
139
- success('>>> Received response from recipient');
140
- info(`Response ID: ${response.id}`);
141
- info(`Reply To: ${response.replyTo}`);
142
- info(`Protocol: ${response.protocol}`);
143
- info(`Payload: ${JSON.stringify(response.payload, null, 2)}`);
144
- } else if (options.type === 'request') {
145
- console.log();
146
- info('No response received (recipient may not have returned a response)');
147
- }
148
-
149
- await router.stop();
150
- await node.stop();
151
-
152
- success('Done');
153
- } catch (err) {
154
- error(`Failed to send message: ${(err as Error).message}`);
155
- if ((err as Error).cause) error(`Cause: ${((err as Error).cause as Error).message}`);
156
- console.error(err);
157
- process.exit(1);
158
- }
159
- });
160
- }
@@ -1,45 +0,0 @@
1
- import { Command } from 'commander';
2
- import { getIdentity, getAgentCard, getBootstrapPeers } from '../config.js';
3
- import { error, printHeader, printKeyValue, printSection } from '../ui.js';
4
-
5
- export function registerStatusCommand(program: Command): void {
6
- program
7
- .command('status')
8
- .description('Show current status')
9
- .action(async () => {
10
- try {
11
- printHeader('Clawiverse Status');
12
-
13
- const identity = getIdentity();
14
- const card = getAgentCard();
15
- const bootstrapPeers = getBootstrapPeers();
16
-
17
- if (!identity) {
18
- error('No identity configured. Run "hw1 init" first.');
19
- process.exit(1);
20
- }
21
-
22
- printSection('Identity');
23
- printKeyValue('DID', identity.did);
24
- printKeyValue('Public Key', identity.publicKey.substring(0, 16) + '...');
25
-
26
- if (card) {
27
- printSection('Agent Card');
28
- printKeyValue('Name', card.name);
29
- printKeyValue('Description', card.description);
30
- printKeyValue('Capabilities', card.capabilities.join(', ') || 'None');
31
- }
32
-
33
- printSection('Network');
34
- printKeyValue(
35
- 'Bootstrap Peers',
36
- bootstrapPeers.length > 0 ? bootstrapPeers.join(', ') : 'None configured'
37
- );
38
-
39
- console.log();
40
- } catch (err) {
41
- error(`Failed to show status: ${(err as Error).message}`);
42
- process.exit(1);
43
- }
44
- });
45
- }
@@ -1,215 +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 } 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 () => new Uint8Array(), // Placeholder
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 () => new Uint8Array(), // Placeholder
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 () => new Uint8Array(), // Placeholder
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 () => new Uint8Array(), // Placeholder
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
- return trust;
215
- }
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
- }
package/src/index.ts DELETED
@@ -1,49 +0,0 @@
1
- #!/usr/bin/env node
2
-
3
- // Polyfill for Node.js < v22.0.0
4
- if (!Promise.withResolvers) {
5
- Promise.withResolvers = function <T>() {
6
- let resolve: (value: T | PromiseLike<T>) => void;
7
- let reject: (reason?: any) => void;
8
- const promise = new Promise<T>((res, rej) => {
9
- resolve = res;
10
- reject = rej;
11
- });
12
- return { promise, resolve: resolve!, reject: reject! };
13
- };
14
- }
15
-
16
- import { Command } from 'commander';
17
- import { createRequire } from 'module';
18
- import { registerInitCommand } from './commands/init.js';
19
- import { registerJoinCommand } from './commands/join.js';
20
- import { registerDiscoverCommand } from './commands/discover.js';
21
- import { registerSendCommand } from './commands/send.js';
22
- import { registerStatusCommand } from './commands/status.js';
23
- import { registerIdentityCommand } from './commands/identity.js';
24
- import { registerCardCommand } from './commands/card.js';
25
- import { createTrustCommand } from './commands/trust.js';
26
-
27
- const require = createRequire(import.meta.url);
28
- const { version } = require('../package.json');
29
-
30
- const program = new Command();
31
-
32
- const binName = process.argv[1]?.includes('hw1') ? 'hw1' : 'clawiverse';
33
-
34
- program
35
- .name(binName)
36
- .description('CLI tool for decentralized AI agent communication')
37
- .version(version);
38
-
39
- // Register commands
40
- registerInitCommand(program);
41
- registerJoinCommand(program);
42
- registerDiscoverCommand(program);
43
- registerSendCommand(program);
44
- registerStatusCommand(program);
45
- registerIdentityCommand(program);
46
- registerCardCommand(program);
47
- program.addCommand(createTrustCommand());
48
-
49
- program.parse();
package/src/ui.ts DELETED
@@ -1,38 +0,0 @@
1
- import chalk from 'chalk';
2
- import ora, { Ora } from 'ora';
3
-
4
- export function success(message: string): void {
5
- console.log(chalk.green('✓'), message);
6
- }
7
-
8
- export function error(message: string): void {
9
- console.log(chalk.red('✗'), message);
10
- }
11
-
12
- export function info(message: string): void {
13
- console.log(chalk.blue('ℹ'), message);
14
- }
15
-
16
- export function warn(message: string): void {
17
- console.log(chalk.yellow('⚠'), message);
18
- }
19
-
20
- export function spinner(text: string): Ora {
21
- return ora(text).start();
22
- }
23
-
24
- export function printHeader(title: string): void {
25
- console.log();
26
- console.log(chalk.bold.cyan(title));
27
- console.log(chalk.gray('─'.repeat(title.length)));
28
- console.log();
29
- }
30
-
31
- export function printKeyValue(key: string, value: string): void {
32
- console.log(chalk.gray(`${key}:`), chalk.white(value));
33
- }
34
-
35
- export function printSection(title: string): void {
36
- console.log();
37
- console.log(chalk.bold(title));
38
- }