@highway1/cli 0.1.23 → 0.1.25
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/dist/index.js +55 -16
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
- package/src/commands/join.ts +42 -9
- package/src/commands/send.ts +10 -1
package/package.json
CHANGED
package/src/commands/join.ts
CHANGED
|
@@ -16,6 +16,7 @@ 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('--relay', 'Run as a relay server and advertise relay capability')
|
|
19
20
|
.action(async (options) => {
|
|
20
21
|
try {
|
|
21
22
|
printHeader('Join Clawiverse Network');
|
|
@@ -42,6 +43,7 @@ export function registerJoinCommand(program: Command): void {
|
|
|
42
43
|
bootstrapPeers,
|
|
43
44
|
enableDHT: true,
|
|
44
45
|
reserveRelaySlot: true,
|
|
46
|
+
enableRelay: options.relay ?? false,
|
|
45
47
|
});
|
|
46
48
|
|
|
47
49
|
await node.start();
|
|
@@ -54,31 +56,50 @@ export function registerJoinCommand(program: Command): void {
|
|
|
54
56
|
|
|
55
57
|
// Wait for bootstrap peer connection before publishing to DHT
|
|
56
58
|
const connectSpin = spinner('Connecting to bootstrap peers...');
|
|
59
|
+
|
|
60
|
+
// Phase 1: wait for peer:connect (up to 10s)
|
|
57
61
|
await new Promise<void>((resolve) => {
|
|
58
62
|
const timeout = setTimeout(resolve, 10000);
|
|
59
63
|
node.libp2p.addEventListener('peer:connect', () => {
|
|
60
64
|
clearTimeout(timeout);
|
|
61
|
-
|
|
65
|
+
resolve();
|
|
62
66
|
}, { once: true });
|
|
63
67
|
});
|
|
68
|
+
|
|
69
|
+
// Phase 2: wait for relay address to appear (up to 5s)
|
|
70
|
+
const hasRelayAddr = () => node.getMultiaddrs().some(a => a.includes('/p2p-circuit'));
|
|
71
|
+
if (!hasRelayAddr()) {
|
|
72
|
+
await new Promise<void>((resolve) => {
|
|
73
|
+
const timeout = setTimeout(resolve, 5000);
|
|
74
|
+
const check = () => {
|
|
75
|
+
if (hasRelayAddr()) { clearTimeout(timeout); resolve(); }
|
|
76
|
+
};
|
|
77
|
+
node.libp2p.addEventListener('self:multiaddress:updated', check);
|
|
78
|
+
setTimeout(() => node.libp2p.removeEventListener('self:multiaddress:updated', check), 5000);
|
|
79
|
+
});
|
|
80
|
+
}
|
|
81
|
+
|
|
64
82
|
connectSpin.succeed('Connected to network!');
|
|
65
83
|
|
|
66
84
|
// Publish Agent Card with peerId and multiaddrs so others can dial us
|
|
67
85
|
const cardSpin = spinner('Publishing Agent Card to DHT...');
|
|
68
86
|
|
|
69
|
-
//
|
|
70
|
-
const directAddrs = node.getMultiaddrs();
|
|
71
|
-
const relayAddrs =
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
const allAddrs = [...directAddrs, ...relayAddrs];
|
|
87
|
+
// Use relay addresses from libp2p (populated after reservation), fall back to manual construction
|
|
88
|
+
const directAddrs = node.getMultiaddrs().filter(a => !a.includes('/p2p-circuit'));
|
|
89
|
+
const relayAddrs = node.getMultiaddrs().filter(a => a.includes('/p2p-circuit'));
|
|
90
|
+
const fallbackRelayAddrs = relayAddrs.length === 0
|
|
91
|
+
? bootstrapPeers.map(r => `${r}/p2p-circuit/p2p/${node.getPeerId()}`)
|
|
92
|
+
: [];
|
|
93
|
+
const allAddrs = [...directAddrs, ...relayAddrs, ...fallbackRelayAddrs];
|
|
94
|
+
|
|
95
|
+
const capabilities = [...(card.capabilities ?? [])];
|
|
96
|
+
if (options.relay) capabilities.push('relay');
|
|
76
97
|
|
|
77
98
|
const agentCard = createAgentCard(
|
|
78
99
|
identity.did,
|
|
79
100
|
card.name,
|
|
80
101
|
card.description,
|
|
81
|
-
|
|
102
|
+
capabilities,
|
|
82
103
|
allAddrs,
|
|
83
104
|
node.getPeerId()
|
|
84
105
|
);
|
|
@@ -92,6 +113,17 @@ export function registerJoinCommand(program: Command): void {
|
|
|
92
113
|
|
|
93
114
|
cardSpin.succeed('Agent Card published!');
|
|
94
115
|
|
|
116
|
+
// Keep connection alive by pinging bootstrap peers periodically
|
|
117
|
+
const pingInterval = setInterval(async () => {
|
|
118
|
+
for (const peer of node.libp2p.getPeers()) {
|
|
119
|
+
try {
|
|
120
|
+
await node.libp2p.services.ping.ping(peer);
|
|
121
|
+
} catch {
|
|
122
|
+
// ignore ping failures
|
|
123
|
+
}
|
|
124
|
+
}
|
|
125
|
+
}, 30000); // ping every 30s
|
|
126
|
+
|
|
95
127
|
// Register message handlers for incoming messages
|
|
96
128
|
const router = createMessageRouter(
|
|
97
129
|
node.libp2p,
|
|
@@ -162,6 +194,7 @@ export function registerJoinCommand(program: Command): void {
|
|
|
162
194
|
process.on('SIGINT', async () => {
|
|
163
195
|
console.log();
|
|
164
196
|
const stopSpin = spinner('Stopping node...');
|
|
197
|
+
clearInterval(pingInterval);
|
|
165
198
|
await router.stop();
|
|
166
199
|
await node.stop();
|
|
167
200
|
stopSpin.succeed('Node stopped');
|
package/src/commands/send.ts
CHANGED
|
@@ -55,10 +55,19 @@ export function registerSendCommand(program: Command): void {
|
|
|
55
55
|
enableDHT: true,
|
|
56
56
|
});
|
|
57
57
|
|
|
58
|
+
// Register peer:identify listener BEFORE start() so we don't miss the event
|
|
59
|
+
const identifyDone = new Promise<void>((resolve) => {
|
|
60
|
+
const timeout = setTimeout(resolve, 12000);
|
|
61
|
+
node.libp2p.addEventListener('peer:identify', () => {
|
|
62
|
+
clearTimeout(timeout);
|
|
63
|
+
setTimeout(resolve, 500);
|
|
64
|
+
}, { once: true });
|
|
65
|
+
});
|
|
66
|
+
|
|
58
67
|
await node.start();
|
|
59
68
|
|
|
60
69
|
spin.text = 'Connecting to network...';
|
|
61
|
-
await
|
|
70
|
+
await identifyDone;
|
|
62
71
|
|
|
63
72
|
const dht = createDHTOperations(node.libp2p);
|
|
64
73
|
|