@highway1/cli 0.1.17 → 0.1.19

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.17",
3
+ "version": "0.1.19",
4
4
  "description": "CLI tool for Clawiverse network",
5
5
  "type": "module",
6
6
  "bin": {
@@ -13,7 +13,7 @@
13
13
  "clean": "rm -rf dist"
14
14
  },
15
15
  "dependencies": {
16
- "@highway1/core": "0.1.15",
16
+ "@highway1/core": "0.1.16",
17
17
  "chalk": "^5.3.0",
18
18
  "cli-table3": "^0.6.5",
19
19
  "commander": "^12.1.0",
@@ -48,12 +48,12 @@ export function registerDiscoverCommand(program: Command): void {
48
48
  await node.start();
49
49
 
50
50
  spin.text = 'Waiting for DHT peers...';
51
- // Wait until connected to at least one peer, or timeout after 15s
51
+ // Wait until connected to at least one peer, then give DHT time to sync
52
52
  await new Promise<void>((resolve) => {
53
53
  const timeout = setTimeout(resolve, 15000);
54
54
  node.libp2p.addEventListener('peer:connect', () => {
55
55
  clearTimeout(timeout);
56
- setTimeout(resolve, 1000); // brief settle time after first connection
56
+ setTimeout(resolve, 3000); // give DHT routing table time to populate
57
57
  }, { once: true });
58
58
  });
59
59
 
@@ -16,19 +16,28 @@ 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)')
19
20
  .action(async (options) => {
20
21
  try {
21
- printHeader('Join Clawiverse Network');
22
+ const jsonMode = options.json;
23
+
24
+ if (!jsonMode) {
25
+ printHeader('Join Clawiverse Network');
26
+ }
22
27
 
23
28
  const identity = getIdentity();
24
29
  const card = getAgentCard();
25
30
 
26
31
  if (!identity || !card) {
27
- error('No identity found. Run "hw1 init" first.');
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
+ }
28
37
  process.exit(1);
29
38
  }
30
39
 
31
- const spin = spinner('Starting libp2p node...');
40
+ const spin = jsonMode ? null : spinner('Starting libp2p node...');
32
41
 
33
42
  const keyPair = importKeyPair({
34
43
  publicKey: identity.publicKey,
@@ -45,14 +54,22 @@ export function registerJoinCommand(program: Command): void {
45
54
 
46
55
  await node.start();
47
56
 
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(', ')}`);
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
+ }
53
70
 
54
71
  // Wait for bootstrap peer connection before publishing to DHT
55
- const connectSpin = spinner('Connecting to bootstrap peers...');
72
+ const connectSpin = jsonMode ? null : spinner('Connecting to bootstrap peers...');
56
73
  await new Promise<void>((resolve) => {
57
74
  const timeout = setTimeout(resolve, 10000);
58
75
  node.libp2p.addEventListener('peer:connect', () => {
@@ -60,10 +77,12 @@ export function registerJoinCommand(program: Command): void {
60
77
  setTimeout(resolve, 500);
61
78
  }, { once: true });
62
79
  });
63
- connectSpin.succeed('Connected to network!');
80
+ if (connectSpin) {
81
+ connectSpin.succeed('Connected to network!');
82
+ }
64
83
 
65
84
  // Publish Agent Card with peerId and multiaddrs so others can dial us
66
- const cardSpin = spinner('Publishing Agent Card to DHT...');
85
+ const cardSpin = jsonMode ? null : spinner('Publishing Agent Card to DHT...');
67
86
 
68
87
  // Include circuit relay addresses so nodes behind NAT can be reached
69
88
  const directAddrs = node.getMultiaddrs();
@@ -89,7 +108,11 @@ export function registerJoinCommand(program: Command): void {
89
108
  const dht = createDHTOperations(node.libp2p);
90
109
  await dht.publishAgentCard(signedCard);
91
110
 
92
- cardSpin.succeed('Agent Card published!');
111
+ if (cardSpin) {
112
+ cardSpin.succeed('Agent Card published!');
113
+ } else {
114
+ console.log(JSON.stringify({ event: 'agent_card_published' }));
115
+ }
93
116
 
94
117
  // Register message handlers for incoming messages
95
118
  const router = createMessageRouter(
@@ -101,17 +124,34 @@ export function registerJoinCommand(program: Command): void {
101
124
  // Generic message handler that accepts any protocol
102
125
  const messageHandler = async (envelope: any) => {
103
126
  const payload = envelope.payload as Record<string, unknown>;
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();
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
+ }
111
149
 
112
150
  // If this is a request, send back a simple acknowledgment response
113
151
  if (envelope.type === 'request') {
114
- info(' Sending acknowledgment response...');
152
+ if (!jsonMode) {
153
+ info(' Sending acknowledgment response...');
154
+ }
115
155
 
116
156
  const { createEnvelope, signEnvelope, sign } = await import('@highway1/core');
117
157
  const identity = getIdentity();
@@ -153,23 +193,40 @@ export function registerJoinCommand(program: Command): void {
153
193
 
154
194
  await router.start();
155
195
 
156
- console.log();
157
- success('Successfully joined the Clawiverse network!');
158
- info('Listening for incoming messages...');
159
- info('Press Ctrl+C to stop');
160
-
161
- process.on('SIGINT', async () => {
196
+ if (!jsonMode) {
162
197
  console.log();
163
- const stopSpin = spinner('Stopping node...');
164
- await router.stop();
165
- await node.stop();
166
- stopSpin.succeed('Node stopped');
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
+ }
204
+
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
+ }
167
217
  process.exit(0);
168
- });
218
+ };
219
+
220
+ process.on('SIGINT', shutdown);
221
+ process.on('SIGTERM', shutdown);
169
222
 
170
223
  await new Promise(() => {});
171
224
  } catch (err) {
172
- error(`Failed to join network: ${(err as Error).message}`);
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
+ }
173
230
  process.exit(1);
174
231
  }
175
232
  });