@highway1/cli 0.1.19 → 0.1.21

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,6 +1,6 @@
1
1
  {
2
2
  "name": "@highway1/cli",
3
- "version": "0.1.19",
3
+ "version": "0.1.21",
4
4
  "description": "CLI tool for Clawiverse network",
5
5
  "type": "module",
6
6
  "bin": {
@@ -30,7 +30,10 @@ export function registerCardCommand(program: Command): void {
30
30
  card
31
31
  .command('edit')
32
32
  .description('Edit Agent Card')
33
- .action(async () => {
33
+ .option('--name <name>', 'Agent name')
34
+ .option('--description <description>', 'Agent description')
35
+ .option('--capabilities <capabilities>', 'Capabilities (comma-separated)')
36
+ .action(async (options) => {
34
37
  try {
35
38
  printHeader('Edit Agent Card');
36
39
 
@@ -41,35 +44,49 @@ export function registerCardCommand(program: Command): void {
41
44
  process.exit(1);
42
45
  }
43
46
 
44
- const answers = await inquirer.prompt([
45
- {
46
- type: 'input',
47
- name: 'name',
48
- message: 'Agent name:',
49
- default: currentCard.name,
50
- },
51
- {
52
- type: 'input',
53
- name: 'description',
54
- message: 'Agent description:',
55
- default: currentCard.description,
56
- },
57
- {
58
- type: 'input',
59
- name: 'capabilities',
60
- message: 'Capabilities (comma-separated):',
61
- default: currentCard.capabilities.join(', '),
62
- },
63
- ]);
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
+ ]);
64
80
 
65
- const updatedCard = {
66
- name: answers.name,
67
- description: answers.description,
68
- capabilities: answers.capabilities
69
- .split(',')
70
- .map((c: string) => c.trim())
71
- .filter((c: string) => c.length > 0),
72
- };
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
+ }
73
90
 
74
91
  setAgentCard(updatedCard);
75
92
 
@@ -2,63 +2,38 @@ import { Command } from 'commander';
2
2
  import { generateKeyPair, exportKeyPair, deriveDID } from '@highway1/core';
3
3
  import { hasIdentity, setIdentity, setAgentCard } from '../config.js';
4
4
  import { success, error, spinner, printHeader, printKeyValue } from '../ui.js';
5
- import inquirer from 'inquirer';
6
5
 
7
6
  export function registerInitCommand(program: Command): void {
8
7
  program
9
8
  .command('init')
10
9
  .description('Initialize a new Clawiverse identity')
11
- .option('--name <name>', 'Agent name')
12
- .option('--description <description>', 'Agent description')
10
+ .option('--name <name>', 'Agent name', 'My Agent')
11
+ .option('--description <description>', 'Agent description', 'A Clawiverse agent')
13
12
  .option('--force', 'Overwrite existing identity')
14
13
  .action(async (options) => {
15
14
  try {
16
15
  printHeader('Initialize Clawiverse Identity');
17
16
 
18
- // Check if identity already exists
19
17
  if (hasIdentity() && !options.force) {
20
18
  error('Identity already exists. Use --force to overwrite.');
21
19
  process.exit(1);
22
20
  }
23
21
 
24
- // Prompt for agent details if not provided
25
- let name = options.name;
26
- let description = options.description;
27
-
28
- if (!name) name = 'My Agent';
29
- if (!description) description = 'A Clawiverse agent';
30
-
31
- if (!options.name) {
32
- const { name: inputName } = await inquirer.prompt({
33
- type: 'input', name: 'name', message: 'Agent name:', default: name,
34
- });
35
- name = inputName || name;
36
- }
37
- if (!options.description) {
38
- const { description: inputDesc } = await inquirer.prompt({
39
- type: 'input', name: 'description', message: 'Agent description:', default: description,
40
- });
41
- description = inputDesc || description;
42
- }
43
-
44
22
  const spin = spinner('Generating key pair...');
45
23
 
46
- // Generate key pair
47
24
  const keyPair = await generateKeyPair();
48
25
  const exported = exportKeyPair(keyPair);
49
26
  const did = deriveDID(keyPair.publicKey);
50
27
 
51
- // Save identity
52
28
  setIdentity({
53
29
  did,
54
30
  publicKey: exported.publicKey,
55
31
  privateKey: exported.privateKey,
56
32
  });
57
33
 
58
- // Save agent card
59
34
  setAgentCard({
60
- name,
61
- description,
35
+ name: options.name,
36
+ description: options.description,
62
37
  capabilities: [],
63
38
  });
64
39
 
@@ -66,8 +41,8 @@ export function registerInitCommand(program: Command): void {
66
41
 
67
42
  console.log();
68
43
  printKeyValue('DID', did);
69
- printKeyValue('Name', name);
70
- printKeyValue('Description', description);
44
+ printKeyValue('Name', options.name);
45
+ printKeyValue('Description', options.description);
71
46
  console.log();
72
47
 
73
48
  success('Run "hw1 join" to connect to the network');
@@ -16,28 +16,19 @@ export function registerJoinCommand(program: Command): void {
16
16
  .command('join')
17
17
  .description('Join the Clawiverse network')
18
18
  .option('--bootstrap <peers...>', 'Bootstrap peer addresses')
19
- .option('--json', 'Output messages as JSON (for agent automation)')
20
19
  .action(async (options) => {
21
20
  try {
22
- const jsonMode = options.json;
23
-
24
- if (!jsonMode) {
25
- printHeader('Join Clawiverse Network');
26
- }
21
+ printHeader('Join Clawiverse Network');
27
22
 
28
23
  const identity = getIdentity();
29
24
  const card = getAgentCard();
30
25
 
31
26
  if (!identity || !card) {
32
- if (jsonMode) {
33
- console.log(JSON.stringify({ error: 'No identity found. Run "hw1 init" first.' }));
34
- } else {
35
- error('No identity found. Run "hw1 init" first.');
36
- }
27
+ error('No identity found. Run "hw1 init" first.');
37
28
  process.exit(1);
38
29
  }
39
30
 
40
- const spin = jsonMode ? null : spinner('Starting libp2p node...');
31
+ const spin = spinner('Starting libp2p node...');
41
32
 
42
33
  const keyPair = importKeyPair({
43
34
  publicKey: identity.publicKey,
@@ -54,22 +45,14 @@ export function registerJoinCommand(program: Command): void {
54
45
 
55
46
  await node.start();
56
47
 
57
- if (spin) {
58
- spin.succeed('Node started successfully!');
59
- info(`Peer ID: ${node.getPeerId()}`);
60
- info(`DID: ${identity.did}`);
61
- info(`Listening on: ${node.getMultiaddrs().join(', ')}`);
62
- } else {
63
- console.log(JSON.stringify({
64
- event: 'node_started',
65
- peerId: node.getPeerId(),
66
- did: identity.did,
67
- multiaddrs: node.getMultiaddrs(),
68
- }));
69
- }
48
+ spin.succeed('Node started successfully!');
49
+
50
+ info(`Peer ID: ${node.getPeerId()}`);
51
+ info(`DID: ${identity.did}`);
52
+ info(`Listening on: ${node.getMultiaddrs().join(', ')}`);
70
53
 
71
54
  // Wait for bootstrap peer connection before publishing to DHT
72
- const connectSpin = jsonMode ? null : spinner('Connecting to bootstrap peers...');
55
+ const connectSpin = spinner('Connecting to bootstrap peers...');
73
56
  await new Promise<void>((resolve) => {
74
57
  const timeout = setTimeout(resolve, 10000);
75
58
  node.libp2p.addEventListener('peer:connect', () => {
@@ -77,12 +60,10 @@ export function registerJoinCommand(program: Command): void {
77
60
  setTimeout(resolve, 500);
78
61
  }, { once: true });
79
62
  });
80
- if (connectSpin) {
81
- connectSpin.succeed('Connected to network!');
82
- }
63
+ connectSpin.succeed('Connected to network!');
83
64
 
84
65
  // Publish Agent Card with peerId and multiaddrs so others can dial us
85
- const cardSpin = jsonMode ? null : spinner('Publishing Agent Card to DHT...');
66
+ const cardSpin = spinner('Publishing Agent Card to DHT...');
86
67
 
87
68
  // Include circuit relay addresses so nodes behind NAT can be reached
88
69
  const directAddrs = node.getMultiaddrs();
@@ -108,11 +89,7 @@ export function registerJoinCommand(program: Command): void {
108
89
  const dht = createDHTOperations(node.libp2p);
109
90
  await dht.publishAgentCard(signedCard);
110
91
 
111
- if (cardSpin) {
112
- cardSpin.succeed('Agent Card published!');
113
- } else {
114
- console.log(JSON.stringify({ event: 'agent_card_published' }));
115
- }
92
+ cardSpin.succeed('Agent Card published!');
116
93
 
117
94
  // Register message handlers for incoming messages
118
95
  const router = createMessageRouter(
@@ -124,34 +101,17 @@ export function registerJoinCommand(program: Command): void {
124
101
  // Generic message handler that accepts any protocol
125
102
  const messageHandler = async (envelope: any) => {
126
103
  const payload = envelope.payload as Record<string, unknown>;
127
-
128
- if (jsonMode) {
129
- // Output as JSON for agent consumption
130
- console.log(JSON.stringify({
131
- event: 'message_received',
132
- id: envelope.id,
133
- from: envelope.from,
134
- to: envelope.to,
135
- protocol: envelope.protocol,
136
- type: envelope.type,
137
- payload,
138
- timestamp: Date.now(),
139
- }));
140
- } else {
141
- console.log();
142
- success(`>>> Received message from ${envelope.from}`);
143
- info(` Message ID: ${envelope.id}`);
144
- info(` Protocol: ${envelope.protocol}`);
145
- info(` Type: ${envelope.type}`);
146
- info(` Payload: ${JSON.stringify(payload, null, 2)}`);
147
- console.log();
148
- }
104
+ console.log();
105
+ success(`>>> Received message from ${envelope.from}`);
106
+ info(` Message ID: ${envelope.id}`);
107
+ info(` Protocol: ${envelope.protocol}`);
108
+ info(` Type: ${envelope.type}`);
109
+ info(` Payload: ${JSON.stringify(payload, null, 2)}`);
110
+ console.log();
149
111
 
150
112
  // If this is a request, send back a simple acknowledgment response
151
113
  if (envelope.type === 'request') {
152
- if (!jsonMode) {
153
- info(' Sending acknowledgment response...');
154
- }
114
+ info(' Sending acknowledgment response...');
155
115
 
156
116
  const { createEnvelope, signEnvelope, sign } = await import('@highway1/core');
157
117
  const identity = getIdentity();
@@ -193,40 +153,23 @@ export function registerJoinCommand(program: Command): void {
193
153
 
194
154
  await router.start();
195
155
 
196
- if (!jsonMode) {
197
- console.log();
198
- success('Successfully joined the Clawiverse network!');
199
- info('Listening for incoming messages...');
200
- info('Press Ctrl+C to stop');
201
- } else {
202
- console.log(JSON.stringify({ event: 'ready', status: 'listening' }));
203
- }
156
+ console.log();
157
+ success('Successfully joined the Clawiverse network!');
158
+ info('Listening for incoming messages...');
159
+ info('Press Ctrl+C to stop');
204
160
 
205
- const shutdown = async () => {
206
- if (!jsonMode) {
207
- console.log();
208
- const stopSpin = spinner('Stopping node...');
209
- await router.stop();
210
- await node.stop();
211
- stopSpin.succeed('Node stopped');
212
- } else {
213
- await router.stop();
214
- await node.stop();
215
- console.log(JSON.stringify({ event: 'shutdown', status: 'stopped' }));
216
- }
161
+ process.on('SIGINT', async () => {
162
+ console.log();
163
+ const stopSpin = spinner('Stopping node...');
164
+ await router.stop();
165
+ await node.stop();
166
+ stopSpin.succeed('Node stopped');
217
167
  process.exit(0);
218
- };
219
-
220
- process.on('SIGINT', shutdown);
221
- process.on('SIGTERM', shutdown);
168
+ });
222
169
 
223
170
  await new Promise(() => {});
224
171
  } catch (err) {
225
- if (options.json) {
226
- console.log(JSON.stringify({ error: (err as Error).message }));
227
- } else {
228
- error(`Failed to join network: ${(err as Error).message}`);
229
- }
172
+ error(`Failed to join network: ${(err as Error).message}`);
230
173
  process.exit(1);
231
174
  }
232
175
  });