@highway1/cli 0.1.37 → 0.1.39

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/package.json CHANGED
@@ -1,32 +1,20 @@
1
1
  {
2
2
  "name": "@highway1/cli",
3
- "version": "0.1.37",
4
- "description": "CLI tool for Clawiverse network",
3
+ "version": "0.1.39",
4
+ "description": "CLI tool for decentralized AI agent network",
5
5
  "type": "module",
6
6
  "bin": {
7
- "clawiverse": "./dist/index.js",
8
7
  "hw1": "./dist/index.js"
9
8
  },
10
- "scripts": {
11
- "build": "tsup",
12
- "dev": "tsup --watch",
13
- "clean": "rm -rf dist"
14
- },
9
+ "keywords": ["ai", "agent", "p2p", "cli"],
10
+ "license": "MIT",
15
11
  "dependencies": {
16
- "@highway1/core": "0.1.26",
17
- "chalk": "^5.3.0",
18
- "cli-table3": "^0.6.5",
12
+ "@highway1/core": "^0.1.39",
19
13
  "commander": "^12.1.0",
20
- "conf": "^13.0.1",
14
+ "chalk": "^5.3.0",
15
+ "ora": "^8.1.0",
21
16
  "inquirer": "^13.3.0",
22
- "ora": "^8.1.0"
23
- },
24
- "devDependencies": {
25
- "@types/node": "^22.10.2",
26
- "tsup": "^8.3.5",
27
- "typescript": "^5.7.2"
28
- },
29
- "engines": {
30
- "node": ">=22.0.0"
17
+ "cli-table3": "^0.6.5",
18
+ "conf": "^13.0.1"
31
19
  }
32
20
  }
package/bin/clawiverse.js DELETED
@@ -1,2 +0,0 @@
1
- #!/usr/bin/env node
2
- import '../dist/index.js';
@@ -1,99 +0,0 @@
1
- import { Command } from 'commander';
2
- import { getAgentCard, setAgentCard } from '../config.js';
3
- import { success, error, printHeader } from '../ui.js';
4
- import inquirer from 'inquirer';
5
-
6
- export function registerCardCommand(program: Command): void {
7
- const card = program.command('card').description('Manage Agent Card');
8
-
9
- card
10
- .command('show')
11
- .description('Show current Agent Card')
12
- .action(async () => {
13
- try {
14
- printHeader('Agent Card');
15
-
16
- const agentCard = getAgentCard();
17
-
18
- if (!agentCard) {
19
- error('No Agent Card found. Run "hw1 init" first.');
20
- process.exit(1);
21
- }
22
-
23
- console.log(JSON.stringify(agentCard, null, 2));
24
- } catch (err) {
25
- error(`Failed to show card: ${(err as Error).message}`);
26
- process.exit(1);
27
- }
28
- });
29
-
30
- card
31
- .command('edit')
32
- .description('Edit Agent Card')
33
- .option('--name <name>', 'Agent name')
34
- .option('--description <description>', 'Agent description')
35
- .option('--capabilities <capabilities>', 'Capabilities (comma-separated)')
36
- .action(async (options) => {
37
- try {
38
- printHeader('Edit Agent Card');
39
-
40
- const currentCard = getAgentCard();
41
-
42
- if (!currentCard) {
43
- error('No Agent Card found. Run "hw1 init" first.');
44
- process.exit(1);
45
- }
46
-
47
- let updatedCard;
48
-
49
- // If any options provided, use non-interactive mode
50
- if (options.name || options.description || options.capabilities) {
51
- updatedCard = {
52
- name: options.name || currentCard.name,
53
- description: options.description || currentCard.description,
54
- capabilities: options.capabilities
55
- ? options.capabilities.split(',').map((c: string) => c.trim()).filter((c: string) => c.length > 0)
56
- : currentCard.capabilities,
57
- };
58
- } else {
59
- // Interactive mode
60
- const answers = await inquirer.prompt([
61
- {
62
- type: 'input',
63
- name: 'name',
64
- message: 'Agent name:',
65
- default: currentCard.name,
66
- },
67
- {
68
- type: 'input',
69
- name: 'description',
70
- message: 'Agent description:',
71
- default: currentCard.description,
72
- },
73
- {
74
- type: 'input',
75
- name: 'capabilities',
76
- message: 'Capabilities (comma-separated):',
77
- default: currentCard.capabilities.join(', '),
78
- },
79
- ]);
80
-
81
- updatedCard = {
82
- name: answers.name,
83
- description: answers.description,
84
- capabilities: answers.capabilities
85
- .split(',')
86
- .map((c: string) => c.trim())
87
- .filter((c: string) => c.length > 0),
88
- };
89
- }
90
-
91
- setAgentCard(updatedCard);
92
-
93
- success('Agent Card updated successfully!');
94
- } catch (err) {
95
- error(`Failed to edit card: ${(err as Error).message}`);
96
- process.exit(1);
97
- }
98
- });
99
- }
@@ -1,168 +0,0 @@
1
- import { Command } from 'commander';
2
- import {
3
- createNode,
4
- importKeyPair,
5
- createDHTOperations,
6
- } from '@highway1/core';
7
- import { getIdentity, getBootstrapPeers } from '../config.js';
8
- import { error, spinner, printHeader, info, success } from '../ui.js';
9
- import Table from 'cli-table3';
10
-
11
- export function registerDiscoverCommand(program: Command): void {
12
- program
13
- .command('discover')
14
- .description('Discover agents on the network')
15
- .option('--capability <capability>', 'Filter by capability')
16
- .option('--did <did>', 'Query specific DID')
17
- .option('--query <text>', 'Natural language query (e.g., "translate Japanese")')
18
- .option('--min-trust <score>', 'Minimum trust score (0-1)')
19
- .option('--language <lang>', 'Filter by language')
20
- .option('--limit <number>', 'Maximum number of results', '10')
21
- .option('--bootstrap <peers...>', 'Bootstrap peer addresses')
22
- .action(async (options) => {
23
- try {
24
- printHeader('Discover Agents');
25
-
26
- const identity = getIdentity();
27
-
28
- if (!identity) {
29
- error('No identity found. Run "hw1 init" first.');
30
- process.exit(1);
31
- }
32
-
33
- const spin = spinner('Starting node...');
34
-
35
- const keyPair = importKeyPair({
36
- publicKey: identity.publicKey,
37
- privateKey: identity.privateKey,
38
- });
39
-
40
- const bootstrapPeers = options.bootstrap || getBootstrapPeers();
41
-
42
- const node = await createNode({
43
- keyPair,
44
- bootstrapPeers,
45
- enableDHT: true,
46
- });
47
-
48
- await node.start();
49
-
50
- spin.text = 'Waiting for DHT peers...';
51
- // Wait until connected to at least one peer, then give DHT time to sync
52
- await new Promise<void>((resolve) => {
53
- const timeout = setTimeout(resolve, 15000);
54
- node.libp2p.addEventListener('peer:connect', () => {
55
- clearTimeout(timeout);
56
- setTimeout(resolve, 3000); // give DHT routing table time to populate
57
- }, { once: true });
58
- });
59
-
60
- spin.text = 'Querying DHT...';
61
-
62
- const dht = createDHTOperations(node.libp2p);
63
-
64
- if (options.did) {
65
- const card = await dht.queryAgentCard(options.did);
66
-
67
- if (card) {
68
- spin.succeed('Agent found!');
69
- console.log();
70
- info(`DID: ${card.did}`);
71
- info(`Name: ${card.name}`);
72
- info(`Description: ${card.description}`);
73
- info(`Version: ${card.version}`);
74
- info(`Capabilities: ${card.capabilities.join(', ') || '(none)'}`);
75
- info(`Peer ID: ${card.peerId || '(unknown)'}`);
76
- info(`Endpoints: ${card.endpoints.length > 0 ? card.endpoints.join('\n ') : '(none)'}`);
77
- info(`Timestamp: ${new Date(card.timestamp).toISOString()}`);
78
- } else {
79
- spin.fail('Agent not found');
80
- }
81
- } else if (options.capability || options.query) {
82
- // Semantic search
83
- const query: any = {
84
- limit: parseInt(options.limit, 10),
85
- };
86
-
87
- if (options.query) {
88
- query.text = options.query;
89
- } else if (options.capability) {
90
- query.capability = options.capability;
91
- }
92
-
93
- if (options.minTrust) {
94
- query.filters = {
95
- minTrustScore: parseFloat(options.minTrust),
96
- };
97
- }
98
-
99
- if (options.language) {
100
- query.filters = query.filters || {};
101
- query.filters.language = options.language;
102
- }
103
-
104
- const cards = await dht.searchSemantic(query);
105
-
106
- spin.succeed(`Found ${cards.length} agents`);
107
-
108
- if (cards.length > 0) {
109
- const table = new Table({
110
- head: ['DID', 'Name', 'Capabilities', 'Trust'],
111
- colWidths: [40, 20, 35, 10],
112
- });
113
-
114
- for (const card of cards) {
115
- const capabilities = Array.isArray(card.capabilities)
116
- ? card.capabilities.map((cap: any) =>
117
- typeof cap === 'string' ? cap : cap.name
118
- ).join(', ')
119
- : '';
120
-
121
- const trustScore = card.trust
122
- ? `${(card.trust.interactionScore * 100).toFixed(0)}%`
123
- : 'N/A';
124
-
125
- table.push([
126
- card.did.substring(0, 35) + '...',
127
- card.name,
128
- capabilities.substring(0, 30) + (capabilities.length > 30 ? '...' : ''),
129
- trustScore,
130
- ]);
131
- }
132
-
133
- console.log();
134
- console.log(table.toString());
135
-
136
- // Show detailed info for first result if query was used
137
- if (options.query && cards.length > 0) {
138
- const card = cards[0];
139
- console.log();
140
- info('Top match details:');
141
- info(` DID: ${card.did}`);
142
- info(` Name: ${card.name}`);
143
- info(` Description: ${card.description}`);
144
-
145
- if (Array.isArray(card.capabilities) && card.capabilities.length > 0) {
146
- const cap = card.capabilities[0];
147
- if (typeof cap === 'object' && cap !== null) {
148
- info(` Capability: ${cap.name}`);
149
- info(` ${cap.description}`);
150
- }
151
- }
152
- }
153
- }
154
- } else {
155
- spin.fail('Please specify --did, --capability, or --query');
156
- info('Usage: hw1 discover --did <did>');
157
- info(' hw1 discover --capability <capability>');
158
- info(' hw1 discover --query "translate Japanese"');
159
- info(' hw1 discover --query "code review" --min-trust 0.8');
160
- }
161
-
162
- await node.stop();
163
- } catch (err) {
164
- error(`Failed to discover: ${(err as Error).message}`);
165
- process.exit(1);
166
- }
167
- });
168
- }
@@ -1,37 +0,0 @@
1
- import { Command } from 'commander';
2
- import { getIdentity, getAgentCard } from '../config.js';
3
- import { error, printHeader, printKeyValue } from '../ui.js';
4
-
5
- export function registerIdentityCommand(program: Command): void {
6
- program
7
- .command('identity')
8
- .description('Show current identity information')
9
- .action(async () => {
10
- try {
11
- printHeader('Clawiverse Identity');
12
-
13
- const identity = getIdentity();
14
- const card = getAgentCard();
15
-
16
- if (!identity) {
17
- error('No identity found. Run "hw1 init" first.');
18
- process.exit(1);
19
- }
20
-
21
- printKeyValue('DID', identity.did);
22
- printKeyValue('Public Key', identity.publicKey.substring(0, 16) + '...');
23
-
24
- if (card) {
25
- console.log();
26
- printKeyValue('Name', card.name);
27
- printKeyValue('Description', card.description);
28
- printKeyValue('Capabilities', card.capabilities.join(', ') || 'None');
29
- }
30
-
31
- console.log();
32
- } catch (err) {
33
- error(`Failed to show identity: ${(err as Error).message}`);
34
- process.exit(1);
35
- }
36
- });
37
- }
@@ -1,54 +0,0 @@
1
- import { Command } from 'commander';
2
- import { generateKeyPair, exportKeyPair, deriveDID } from '@highway1/core';
3
- import { hasIdentity, setIdentity, setAgentCard } from '../config.js';
4
- import { success, error, spinner, printHeader, printKeyValue } from '../ui.js';
5
-
6
- export function registerInitCommand(program: Command): void {
7
- program
8
- .command('init')
9
- .description('Initialize a new Clawiverse identity')
10
- .option('--name <name>', 'Agent name', 'My Agent')
11
- .option('--description <description>', 'Agent description', 'A Clawiverse agent')
12
- .option('--force', 'Overwrite existing identity')
13
- .action(async (options) => {
14
- try {
15
- printHeader('Initialize Clawiverse Identity');
16
-
17
- if (hasIdentity() && !options.force) {
18
- error('Identity already exists. Use --force to overwrite.');
19
- process.exit(1);
20
- }
21
-
22
- const spin = spinner('Generating key pair...');
23
-
24
- const keyPair = await generateKeyPair();
25
- const exported = exportKeyPair(keyPair);
26
- const did = deriveDID(keyPair.publicKey);
27
-
28
- setIdentity({
29
- did,
30
- publicKey: exported.publicKey,
31
- privateKey: exported.privateKey,
32
- });
33
-
34
- setAgentCard({
35
- name: options.name,
36
- description: options.description,
37
- capabilities: [],
38
- });
39
-
40
- spin.succeed('Identity created successfully!');
41
-
42
- console.log();
43
- printKeyValue('DID', did);
44
- printKeyValue('Name', options.name);
45
- printKeyValue('Description', options.description);
46
- console.log();
47
-
48
- success('Run "hw1 join" to connect to the network');
49
- } catch (err) {
50
- error(`Failed to initialize: ${(err as Error).message}`);
51
- process.exit(1);
52
- }
53
- });
54
- }
@@ -1,243 +0,0 @@
1
- import { Command } from 'commander';
2
- import {
3
- createNode,
4
- importKeyPair,
5
- createAgentCard,
6
- signAgentCard,
7
- createDHTOperations,
8
- createMessageRouter,
9
- sign,
10
- } from '@highway1/core';
11
- import { getIdentity, getAgentCard, getBootstrapPeers } from '../config.js';
12
- import { success, error, spinner, printHeader, info } from '../ui.js';
13
-
14
- export function registerJoinCommand(program: Command): void {
15
- program
16
- .command('join')
17
- .description('Join the Clawiverse network')
18
- .option('--bootstrap <peers...>', 'Bootstrap peer addresses')
19
- .option('--relay', 'Run as a relay server and advertise relay capability')
20
- .action(async (options) => {
21
- try {
22
- printHeader('Join Clawiverse Network');
23
-
24
- const identity = getIdentity();
25
- const card = getAgentCard();
26
-
27
- if (!identity || !card) {
28
- error('No identity found. Run "hw1 init" first.');
29
- process.exit(1);
30
- }
31
-
32
- const spin = spinner('Starting libp2p node...');
33
-
34
- const keyPair = importKeyPair({
35
- publicKey: identity.publicKey,
36
- privateKey: identity.privateKey,
37
- });
38
-
39
- const bootstrapPeers = options.bootstrap || getBootstrapPeers();
40
-
41
- const node = await createNode({
42
- keyPair,
43
- bootstrapPeers,
44
- enableDHT: true,
45
- reserveRelaySlot: true,
46
- enableRelay: options.relay ?? false,
47
- });
48
-
49
- await node.start();
50
-
51
- spin.succeed('Node started successfully!');
52
-
53
- info(`Peer ID: ${node.getPeerId()}`);
54
- info(`DID: ${identity.did}`);
55
- info(`Listening on: ${node.getMultiaddrs().join(', ')}`);
56
-
57
- // Wait for bootstrap peer connection before publishing to DHT
58
- const connectSpin = spinner('Connecting to bootstrap peers...');
59
-
60
- // Phase 1: wait for peer:connect (up to 10s)
61
- await new Promise<void>((resolve) => {
62
- const timeout = setTimeout(resolve, 10000);
63
- node.libp2p.addEventListener('peer:connect', () => {
64
- clearTimeout(timeout);
65
- resolve();
66
- }, { once: true });
67
- });
68
-
69
- // Phase 2: wait for relay reservation (up to 10s)
70
- const hasRelayAddr = () => node.getMultiaddrs().some(a => a.includes('/p2p-circuit'));
71
- if (!hasRelayAddr()) {
72
- info('Waiting for relay reservation...');
73
- info(`Listen addresses configured: ${JSON.stringify((node.libp2p as any).components?.addressManager?.getListenAddrs?.() || [])}`);
74
-
75
- await new Promise<void>((resolve) => {
76
- const timeout = setTimeout(() => {
77
- info(`Relay reservation timeout after 10s.`);
78
- info(`Final multiaddrs: ${node.getMultiaddrs().join(', ')}`);
79
- info(`Connected peers: ${node.libp2p.getPeers().map(p => p.toString()).join(', ')}`);
80
- resolve();
81
- }, 10000);
82
-
83
- // Listen for relay:reservation event (fires when reservation succeeds)
84
- const onReservation = (evt: any) => {
85
- info(`Relay reservation successful! Details: ${JSON.stringify(evt.detail)}`);
86
- clearTimeout(timeout);
87
- // Wait a bit for multiaddrs to update
88
- setTimeout(() => {
89
- info(`Relay addresses: ${node.getMultiaddrs().filter(a => a.includes('/p2p-circuit')).join(', ')}`);
90
- resolve();
91
- }, 500);
92
- };
93
-
94
- // Also listen for self:peer:update as fallback
95
- const onPeerUpdate = () => {
96
- if (hasRelayAddr()) {
97
- info(`Relay address acquired via peer update`);
98
- clearTimeout(timeout);
99
- resolve();
100
- }
101
- };
102
-
103
- node.libp2p.addEventListener('relay:reservation', onReservation, { once: true });
104
- node.libp2p.addEventListener('self:peer:update', onPeerUpdate);
105
-
106
- setTimeout(() => {
107
- node.libp2p.removeEventListener('relay:reservation', onReservation);
108
- node.libp2p.removeEventListener('self:peer:update', onPeerUpdate);
109
- }, 10000);
110
- });
111
- } else {
112
- info(`Relay address already present: ${node.getMultiaddrs().filter(a => a.includes('/p2p-circuit')).join(', ')}`);
113
- }
114
-
115
- connectSpin.succeed('Connected to network!');
116
-
117
- // Publish Agent Card with peerId and multiaddrs so others can dial us
118
- const cardSpin = spinner('Publishing Agent Card to DHT...');
119
-
120
- // Use relay addresses from libp2p (populated after reservation), fall back to manual construction
121
- const directAddrs = node.getMultiaddrs().filter(a => !a.includes('/p2p-circuit'));
122
- const relayAddrs = node.getMultiaddrs().filter(a => a.includes('/p2p-circuit'));
123
- const fallbackRelayAddrs = relayAddrs.length === 0
124
- ? bootstrapPeers.map(r => `${r}/p2p-circuit/p2p/${node.getPeerId()}`)
125
- : [];
126
- const allAddrs = [...directAddrs, ...relayAddrs, ...fallbackRelayAddrs];
127
-
128
- const capabilities = [...(card.capabilities ?? [])];
129
- if (options.relay) capabilities.push('relay');
130
-
131
- const agentCard = createAgentCard(
132
- identity.did,
133
- card.name,
134
- card.description,
135
- capabilities,
136
- allAddrs,
137
- node.getPeerId()
138
- );
139
-
140
- const signedCard = await signAgentCard(agentCard, (data) =>
141
- sign(data, keyPair.privateKey)
142
- );
143
-
144
- const dht = createDHTOperations(node.libp2p);
145
- await dht.publishAgentCard(signedCard);
146
-
147
- cardSpin.succeed('Agent Card published!');
148
-
149
- // Keep connection alive by pinging bootstrap peers periodically
150
- const pingInterval = setInterval(async () => {
151
- for (const peer of node.libp2p.getPeers()) {
152
- try {
153
- await node.libp2p.services.ping.ping(peer);
154
- } catch {
155
- // ignore ping failures
156
- }
157
- }
158
- }, 30000); // ping every 30s
159
-
160
- // Register message handlers for incoming messages
161
- const router = createMessageRouter(
162
- node.libp2p,
163
- async () => true,
164
- dht
165
- );
166
-
167
- // Generic message handler that accepts any protocol
168
- const messageHandler = async (envelope: any) => {
169
- const payload = envelope.payload as Record<string, unknown>;
170
- console.log();
171
- success(`>>> Received message from ${envelope.from}`);
172
- info(` Message ID: ${envelope.id}`);
173
- info(` Protocol: ${envelope.protocol}`);
174
- info(` Type: ${envelope.type}`);
175
- info(` Payload: ${JSON.stringify(payload, null, 2)}`);
176
- console.log();
177
-
178
- // If this is a request, send back a simple acknowledgment response
179
- if (envelope.type === 'request') {
180
- info(' Sending acknowledgment response...');
181
-
182
- const { createEnvelope, signEnvelope, sign } = await import('@highway1/core');
183
- const identity = getIdentity();
184
- const keyPair = importKeyPair({
185
- publicKey: identity!.publicKey,
186
- privateKey: identity!.privateKey,
187
- });
188
-
189
- const responseEnvelope = createEnvelope(
190
- envelope.to, // We are the recipient, now we're the sender
191
- envelope.from, // Original sender is now the recipient
192
- 'response',
193
- envelope.protocol,
194
- {
195
- status: 'received',
196
- message: 'Message received and processed',
197
- originalPayload: payload,
198
- timestamp: Date.now()
199
- },
200
- envelope.id // replyTo: original message ID
201
- );
202
-
203
- const signedResponse = await signEnvelope(responseEnvelope, (data) =>
204
- sign(data, keyPair.privateKey)
205
- );
206
-
207
- return signedResponse;
208
- }
209
-
210
- return undefined;
211
- };
212
-
213
- // Register handlers for common protocols
214
- router.registerHandler('/clawiverse/msg/1.0.0', messageHandler);
215
- router.registerHandler('/clawiverse/greet/1.0.0', messageHandler);
216
-
217
- // Register catch-all handler for any other protocol
218
- router.registerCatchAllHandler(messageHandler);
219
-
220
- await router.start();
221
-
222
- console.log();
223
- success('Successfully joined the Clawiverse network!');
224
- info('Listening for incoming messages...');
225
- info('Press Ctrl+C to stop');
226
-
227
- process.on('SIGINT', async () => {
228
- console.log();
229
- const stopSpin = spinner('Stopping node...');
230
- clearInterval(pingInterval);
231
- await router.stop();
232
- await node.stop();
233
- stopSpin.succeed('Node stopped');
234
- process.exit(0);
235
- });
236
-
237
- await new Promise(() => {});
238
- } catch (err) {
239
- error(`Failed to join network: ${(err as Error).message}`);
240
- process.exit(1);
241
- }
242
- });
243
- }