@astroanywhere/agent 0.1.35 → 0.1.36
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/cli.js +8 -11
- package/dist/cli.js.map +1 -1
- package/dist/commands/start.d.ts.map +1 -1
- package/dist/commands/start.js +71 -51
- package/dist/commands/start.js.map +1 -1
- package/dist/lib/display.d.ts +24 -0
- package/dist/lib/display.d.ts.map +1 -0
- package/dist/lib/display.js +202 -0
- package/dist/lib/display.js.map +1 -0
- package/dist/lib/openclaw-bridge.d.ts +73 -0
- package/dist/lib/openclaw-bridge.d.ts.map +1 -0
- package/dist/lib/openclaw-bridge.js +457 -0
- package/dist/lib/openclaw-bridge.js.map +1 -0
- package/dist/lib/providers.d.ts.map +1 -1
- package/dist/lib/providers.js +46 -53
- package/dist/lib/providers.js.map +1 -1
- package/dist/lib/ssh-installer.d.ts +19 -10
- package/dist/lib/ssh-installer.d.ts.map +1 -1
- package/dist/lib/ssh-installer.js +18 -12
- package/dist/lib/ssh-installer.js.map +1 -1
- package/dist/lib/task-executor.d.ts +8 -1
- package/dist/lib/task-executor.d.ts.map +1 -1
- package/dist/lib/task-executor.js +77 -4
- package/dist/lib/task-executor.js.map +1 -1
- package/dist/lib/websocket-client.d.ts +5 -0
- package/dist/lib/websocket-client.d.ts.map +1 -1
- package/dist/lib/websocket-client.js +159 -0
- package/dist/lib/websocket-client.js.map +1 -1
- package/dist/mcp/tools.d.ts +1 -1
- package/dist/providers/claude-sdk-adapter.d.ts +4 -1
- package/dist/providers/claude-sdk-adapter.d.ts.map +1 -1
- package/dist/providers/claude-sdk-adapter.js +16 -5
- package/dist/providers/claude-sdk-adapter.js.map +1 -1
- package/dist/providers/openclaw-adapter.d.ts +46 -29
- package/dist/providers/openclaw-adapter.d.ts.map +1 -1
- package/dist/providers/openclaw-adapter.js +603 -215
- package/dist/providers/openclaw-adapter.js.map +1 -1
- package/dist/providers/opencode-adapter.d.ts +29 -0
- package/dist/providers/opencode-adapter.d.ts.map +1 -1
- package/dist/providers/opencode-adapter.js +145 -38
- package/dist/providers/opencode-adapter.js.map +1 -1
- package/dist/types.d.ts +83 -1
- package/dist/types.d.ts.map +1 -1
- package/package.json +1 -1
|
@@ -0,0 +1,457 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* OpenClaw Bridge — Persistent gateway connection for channel operations
|
|
3
|
+
*
|
|
4
|
+
* Unlike the per-task OpenClawAdapter (which creates a new connection per task),
|
|
5
|
+
* the bridge maintains a single long-lived WebSocket to the OpenClaw gateway
|
|
6
|
+
* for notification delivery, approval routing, and inbound message forwarding.
|
|
7
|
+
*
|
|
8
|
+
* This enables the relay-routed architecture:
|
|
9
|
+
* Server → Relay → Agent Runner (bridge) → OpenClaw Gateway → User channels
|
|
10
|
+
*/
|
|
11
|
+
import { EventEmitter } from 'node:events';
|
|
12
|
+
import { readFileSync, existsSync } from 'node:fs';
|
|
13
|
+
import { join } from 'node:path';
|
|
14
|
+
import { homedir } from 'node:os';
|
|
15
|
+
import WebSocket from 'ws';
|
|
16
|
+
import { randomUUID } from 'node:crypto';
|
|
17
|
+
// ---------------------------------------------------------------------------
|
|
18
|
+
// Constants
|
|
19
|
+
// ---------------------------------------------------------------------------
|
|
20
|
+
const PROTOCOL_VERSION = 3;
|
|
21
|
+
const CONNECT_TIMEOUT_MS = 10_000;
|
|
22
|
+
const REQUEST_TIMEOUT_MS = 15_000;
|
|
23
|
+
const APPROVAL_TIMEOUT_MS = 300_000; // 5 minutes
|
|
24
|
+
const RECONNECT_DELAY_MS = 5_000;
|
|
25
|
+
// ---------------------------------------------------------------------------
|
|
26
|
+
// Bridge
|
|
27
|
+
// ---------------------------------------------------------------------------
|
|
28
|
+
export class OpenClawBridge extends EventEmitter {
|
|
29
|
+
ws = null;
|
|
30
|
+
gatewayConfig = null;
|
|
31
|
+
pendingRequests = new Map();
|
|
32
|
+
pendingApprovals = new Map();
|
|
33
|
+
_connected = false;
|
|
34
|
+
_started = false;
|
|
35
|
+
_connecting = false;
|
|
36
|
+
reconnectTimer = null;
|
|
37
|
+
/** Default recipient for send (e.g., Telegram username, phone). Read from openclaw.json */
|
|
38
|
+
defaultRecipient = null;
|
|
39
|
+
/** Telegram bot token, cached from config at start() */
|
|
40
|
+
telegramBotToken = null;
|
|
41
|
+
get isConnected() {
|
|
42
|
+
return this._connected && this.ws !== null && this.ws.readyState === WebSocket.OPEN;
|
|
43
|
+
}
|
|
44
|
+
// ─── Lifecycle ──────────────────────────────────────────────────
|
|
45
|
+
async start() {
|
|
46
|
+
if (this._started)
|
|
47
|
+
return this._connected;
|
|
48
|
+
const config = this.readGatewayConfig();
|
|
49
|
+
if (!config)
|
|
50
|
+
return false;
|
|
51
|
+
this.gatewayConfig = config;
|
|
52
|
+
this.defaultRecipient = config.defaultRecipient || null;
|
|
53
|
+
this.telegramBotToken = this.readTelegramBotToken();
|
|
54
|
+
this._started = true;
|
|
55
|
+
try {
|
|
56
|
+
await this.connect();
|
|
57
|
+
}
|
|
58
|
+
catch {
|
|
59
|
+
// Reset so future start() calls can retry
|
|
60
|
+
this._started = false;
|
|
61
|
+
}
|
|
62
|
+
if (!this._connected) {
|
|
63
|
+
this._started = false;
|
|
64
|
+
}
|
|
65
|
+
return this._connected;
|
|
66
|
+
}
|
|
67
|
+
stop() {
|
|
68
|
+
this._started = false;
|
|
69
|
+
this._connected = false;
|
|
70
|
+
if (this.reconnectTimer) {
|
|
71
|
+
clearTimeout(this.reconnectTimer);
|
|
72
|
+
this.reconnectTimer = null;
|
|
73
|
+
}
|
|
74
|
+
for (const [id, pending] of this.pendingRequests) {
|
|
75
|
+
clearTimeout(pending.timeoutId);
|
|
76
|
+
pending.reject(new Error('Bridge stopped'));
|
|
77
|
+
this.pendingRequests.delete(id);
|
|
78
|
+
}
|
|
79
|
+
for (const [id, pending] of this.pendingApprovals) {
|
|
80
|
+
clearTimeout(pending.timeoutId);
|
|
81
|
+
pending.reject(new Error('Bridge stopped'));
|
|
82
|
+
this.pendingApprovals.delete(id);
|
|
83
|
+
}
|
|
84
|
+
if (this.ws) {
|
|
85
|
+
this.ws.removeAllListeners();
|
|
86
|
+
this.ws.close();
|
|
87
|
+
this.ws = null;
|
|
88
|
+
}
|
|
89
|
+
// Remove external EventEmitter listeners (e.g., 'inbound' from websocket-client)
|
|
90
|
+
// to prevent leaks if the bridge is restarted after stop()
|
|
91
|
+
this.removeAllListeners();
|
|
92
|
+
}
|
|
93
|
+
// ─── Gateway Config ─────────────────────────────────────────────
|
|
94
|
+
readGatewayConfig() {
|
|
95
|
+
try {
|
|
96
|
+
const configPath = join(homedir(), '.openclaw', 'openclaw.json');
|
|
97
|
+
if (!existsSync(configPath))
|
|
98
|
+
return null;
|
|
99
|
+
const raw = JSON.parse(readFileSync(configPath, 'utf-8'));
|
|
100
|
+
const port = raw?.gateway?.port;
|
|
101
|
+
if (!port)
|
|
102
|
+
return null;
|
|
103
|
+
const token = raw?.gateway?.auth?.token || '';
|
|
104
|
+
const bind = raw?.gateway?.bind || '127.0.0.1';
|
|
105
|
+
const host = bind === 'loopback' || bind === '127.0.0.1' ? '127.0.0.1' : bind;
|
|
106
|
+
// Read default notification recipient from astro-specific config
|
|
107
|
+
const defaultRecipient = raw?.astro?.notifyTo || undefined;
|
|
108
|
+
return { port, token, url: `ws://${host}:${port}`, defaultRecipient };
|
|
109
|
+
}
|
|
110
|
+
catch {
|
|
111
|
+
return null;
|
|
112
|
+
}
|
|
113
|
+
}
|
|
114
|
+
// ─── Gateway Connection ─────────────────────────────────────────
|
|
115
|
+
connect() {
|
|
116
|
+
if (!this.gatewayConfig)
|
|
117
|
+
return Promise.resolve();
|
|
118
|
+
if (this._connecting)
|
|
119
|
+
return Promise.resolve();
|
|
120
|
+
this._connecting = true;
|
|
121
|
+
return new Promise((resolve) => {
|
|
122
|
+
// Clean up old WebSocket handlers to prevent leaks on reconnection
|
|
123
|
+
if (this.ws) {
|
|
124
|
+
this.ws.removeAllListeners();
|
|
125
|
+
this.ws = null;
|
|
126
|
+
}
|
|
127
|
+
const done = () => { this._connecting = false; resolve(); };
|
|
128
|
+
const timeout = setTimeout(() => {
|
|
129
|
+
console.warn('[openclaw-bridge] Connection timeout');
|
|
130
|
+
if (this.ws) {
|
|
131
|
+
this.ws.removeAllListeners();
|
|
132
|
+
this.ws.close();
|
|
133
|
+
this.ws = null;
|
|
134
|
+
}
|
|
135
|
+
done();
|
|
136
|
+
}, CONNECT_TIMEOUT_MS);
|
|
137
|
+
const ws = new WebSocket(this.gatewayConfig.url);
|
|
138
|
+
this.ws = ws;
|
|
139
|
+
ws.on('message', (data) => {
|
|
140
|
+
let frame;
|
|
141
|
+
try {
|
|
142
|
+
frame = JSON.parse(String(data));
|
|
143
|
+
}
|
|
144
|
+
catch {
|
|
145
|
+
return;
|
|
146
|
+
}
|
|
147
|
+
// Challenge → send connect
|
|
148
|
+
if (frame.type === 'event' && frame.event === 'connect.challenge') {
|
|
149
|
+
ws.send(JSON.stringify({
|
|
150
|
+
type: 'req',
|
|
151
|
+
id: 'connect-1',
|
|
152
|
+
method: 'connect',
|
|
153
|
+
params: {
|
|
154
|
+
minProtocol: PROTOCOL_VERSION,
|
|
155
|
+
maxProtocol: PROTOCOL_VERSION,
|
|
156
|
+
client: {
|
|
157
|
+
id: 'gateway-client',
|
|
158
|
+
version: 'dev',
|
|
159
|
+
platform: process.platform,
|
|
160
|
+
mode: 'backend',
|
|
161
|
+
},
|
|
162
|
+
caps: [],
|
|
163
|
+
auth: { token: this.gatewayConfig.token },
|
|
164
|
+
role: 'operator',
|
|
165
|
+
scopes: ['operator.read', 'operator.write', 'operator.admin'],
|
|
166
|
+
},
|
|
167
|
+
}));
|
|
168
|
+
return;
|
|
169
|
+
}
|
|
170
|
+
// Connect response
|
|
171
|
+
if (frame.type === 'res' && frame.id === 'connect-1') {
|
|
172
|
+
clearTimeout(timeout);
|
|
173
|
+
if (frame.ok) {
|
|
174
|
+
this._connected = true;
|
|
175
|
+
console.log('[openclaw-bridge] Connected to gateway');
|
|
176
|
+
this.emit('connected');
|
|
177
|
+
done();
|
|
178
|
+
}
|
|
179
|
+
else {
|
|
180
|
+
console.error('[openclaw-bridge] Handshake failed:', frame.error?.message);
|
|
181
|
+
ws.close();
|
|
182
|
+
done();
|
|
183
|
+
}
|
|
184
|
+
return;
|
|
185
|
+
}
|
|
186
|
+
// After connected — handle responses and events
|
|
187
|
+
if (this._connected) {
|
|
188
|
+
if (frame.type === 'res') {
|
|
189
|
+
this.handleResponse(frame);
|
|
190
|
+
}
|
|
191
|
+
else if (frame.type === 'event') {
|
|
192
|
+
this.handleEvent(frame);
|
|
193
|
+
}
|
|
194
|
+
}
|
|
195
|
+
});
|
|
196
|
+
ws.on('close', () => {
|
|
197
|
+
this._connected = false;
|
|
198
|
+
this.ws = null;
|
|
199
|
+
this.emit('disconnected');
|
|
200
|
+
if (this._started) {
|
|
201
|
+
this.scheduleReconnect();
|
|
202
|
+
}
|
|
203
|
+
});
|
|
204
|
+
ws.on('error', (err) => {
|
|
205
|
+
console.error('[openclaw-bridge] WebSocket error:', err.message);
|
|
206
|
+
clearTimeout(timeout);
|
|
207
|
+
ws.removeAllListeners();
|
|
208
|
+
ws.close();
|
|
209
|
+
this.ws = null;
|
|
210
|
+
done();
|
|
211
|
+
});
|
|
212
|
+
});
|
|
213
|
+
}
|
|
214
|
+
scheduleReconnect() {
|
|
215
|
+
if (this.reconnectTimer)
|
|
216
|
+
return;
|
|
217
|
+
this.reconnectTimer = setTimeout(() => {
|
|
218
|
+
this.reconnectTimer = null;
|
|
219
|
+
if (this._started) {
|
|
220
|
+
this.connect().catch(() => { });
|
|
221
|
+
}
|
|
222
|
+
}, RECONNECT_DELAY_MS);
|
|
223
|
+
}
|
|
224
|
+
// ─── Request/Response ───────────────────────────────────────────
|
|
225
|
+
sendRequest(method, params) {
|
|
226
|
+
return new Promise((resolve, reject) => {
|
|
227
|
+
if (!this.isConnected) {
|
|
228
|
+
reject(new Error('OpenClaw gateway not connected'));
|
|
229
|
+
return;
|
|
230
|
+
}
|
|
231
|
+
const id = randomUUID();
|
|
232
|
+
const timeoutId = setTimeout(() => {
|
|
233
|
+
this.pendingRequests.delete(id);
|
|
234
|
+
reject(new Error(`Request ${method} timed out`));
|
|
235
|
+
}, REQUEST_TIMEOUT_MS);
|
|
236
|
+
this.pendingRequests.set(id, { resolve, reject, timeoutId });
|
|
237
|
+
try {
|
|
238
|
+
this.ws.send(JSON.stringify({
|
|
239
|
+
type: 'req',
|
|
240
|
+
id,
|
|
241
|
+
method,
|
|
242
|
+
params,
|
|
243
|
+
}));
|
|
244
|
+
}
|
|
245
|
+
catch (err) {
|
|
246
|
+
clearTimeout(timeoutId);
|
|
247
|
+
this.pendingRequests.delete(id);
|
|
248
|
+
reject(err instanceof Error ? err : new Error(String(err)));
|
|
249
|
+
}
|
|
250
|
+
});
|
|
251
|
+
}
|
|
252
|
+
handleResponse(frame) {
|
|
253
|
+
if (!frame.id)
|
|
254
|
+
return;
|
|
255
|
+
const pending = this.pendingRequests.get(frame.id);
|
|
256
|
+
if (!pending)
|
|
257
|
+
return;
|
|
258
|
+
clearTimeout(pending.timeoutId);
|
|
259
|
+
this.pendingRequests.delete(frame.id);
|
|
260
|
+
if (frame.ok) {
|
|
261
|
+
pending.resolve(frame.payload);
|
|
262
|
+
}
|
|
263
|
+
else {
|
|
264
|
+
pending.reject(new Error(frame.error?.message || 'Request failed'));
|
|
265
|
+
}
|
|
266
|
+
}
|
|
267
|
+
handleEvent(frame) {
|
|
268
|
+
if (frame.event === 'approval.response') {
|
|
269
|
+
// Direct approval response (if gateway supports it in the future)
|
|
270
|
+
const approvalId = frame.payload?.approvalId;
|
|
271
|
+
const response = frame.payload?.response;
|
|
272
|
+
if (approvalId && response) {
|
|
273
|
+
this.resolveApproval(approvalId, response);
|
|
274
|
+
}
|
|
275
|
+
}
|
|
276
|
+
else if (frame.event === 'message.inbound') {
|
|
277
|
+
const text = frame.payload?.text || '';
|
|
278
|
+
// If there are pending approvals, treat inbound message as an approval response.
|
|
279
|
+
// NOTE: This FIFO approach assumes serialized approvals. Concurrent approvals
|
|
280
|
+
// using the fallback path (no bot token) may match responses to the wrong request.
|
|
281
|
+
// The Telegram polling path (requestApprovalViaTelegram) avoids this issue.
|
|
282
|
+
if (this.pendingApprovals.size > 0 && text.trim()) {
|
|
283
|
+
if (this.pendingApprovals.size > 1) {
|
|
284
|
+
console.warn(`[openclaw-bridge] ${this.pendingApprovals.size} concurrent approvals pending — FIFO matching may route response to wrong request`);
|
|
285
|
+
}
|
|
286
|
+
const [approvalId] = this.pendingApprovals.keys();
|
|
287
|
+
this.resolveApproval(approvalId, text.trim());
|
|
288
|
+
return;
|
|
289
|
+
}
|
|
290
|
+
// Otherwise forward as a regular inbound message
|
|
291
|
+
this.emit('inbound', frame.payload);
|
|
292
|
+
}
|
|
293
|
+
}
|
|
294
|
+
resolveApproval(approvalId, response) {
|
|
295
|
+
const pending = this.pendingApprovals.get(approvalId);
|
|
296
|
+
if (pending) {
|
|
297
|
+
clearTimeout(pending.timeoutId);
|
|
298
|
+
this.pendingApprovals.delete(approvalId);
|
|
299
|
+
pending.resolve(response);
|
|
300
|
+
}
|
|
301
|
+
this.emit('approval-response', { approvalId, response });
|
|
302
|
+
}
|
|
303
|
+
// ─── Public API ─────────────────────────────────────────────────
|
|
304
|
+
async sendNotification(notification) {
|
|
305
|
+
const prefix = this.getNotificationPrefix(notification.type);
|
|
306
|
+
const msg = `${prefix} ${notification.summary}${notification.astroUrl ? `\n\n${notification.astroUrl}` : ''}`;
|
|
307
|
+
const to = notification.to || this.defaultRecipient;
|
|
308
|
+
if (!to) {
|
|
309
|
+
throw new Error('No recipient configured for OpenClaw notifications (set "to" or defaultRecipient)');
|
|
310
|
+
}
|
|
311
|
+
await this.sendRequest('send', {
|
|
312
|
+
to,
|
|
313
|
+
message: msg,
|
|
314
|
+
idempotencyKey: randomUUID(),
|
|
315
|
+
});
|
|
316
|
+
}
|
|
317
|
+
async sendResponse(response) {
|
|
318
|
+
const to = response.to || response.channelId || this.defaultRecipient;
|
|
319
|
+
if (!to) {
|
|
320
|
+
throw new Error('No recipient for OpenClaw response');
|
|
321
|
+
}
|
|
322
|
+
await this.sendRequest('send', {
|
|
323
|
+
to,
|
|
324
|
+
message: response.text,
|
|
325
|
+
idempotencyKey: randomUUID(),
|
|
326
|
+
...(response.threadId ? { threadId: response.threadId } : {}),
|
|
327
|
+
});
|
|
328
|
+
}
|
|
329
|
+
async requestApproval(opts) {
|
|
330
|
+
const to = opts.to || this.defaultRecipient;
|
|
331
|
+
if (!to) {
|
|
332
|
+
throw new Error('No recipient configured for OpenClaw approval request');
|
|
333
|
+
}
|
|
334
|
+
const options = opts.options ?? ['Yes', 'No'];
|
|
335
|
+
const botToken = this.telegramBotToken;
|
|
336
|
+
if (botToken) {
|
|
337
|
+
return this.requestApprovalViaTelegram(botToken, to, opts.question, options);
|
|
338
|
+
}
|
|
339
|
+
// Fallback: send via gateway send method (no reply detection)
|
|
340
|
+
const optionLines = options.map((o, i) => ` ${i + 1}. ${o}`).join('\n');
|
|
341
|
+
const message = `[Approval Needed]\n\n${opts.question}\n\n${optionLines}\n\nReply with a number (1-${options.length}) or type your answer.`;
|
|
342
|
+
await this.sendRequest('send', {
|
|
343
|
+
to,
|
|
344
|
+
message,
|
|
345
|
+
idempotencyKey: opts.approvalId,
|
|
346
|
+
});
|
|
347
|
+
// Wait for the user's reply via inbound message
|
|
348
|
+
return new Promise((resolve, reject) => {
|
|
349
|
+
const timeoutId = setTimeout(() => {
|
|
350
|
+
this.pendingApprovals.delete(opts.approvalId);
|
|
351
|
+
reject(new Error(`Approval ${opts.approvalId} timed out after ${APPROVAL_TIMEOUT_MS / 1000}s`));
|
|
352
|
+
}, APPROVAL_TIMEOUT_MS);
|
|
353
|
+
this.pendingApprovals.set(opts.approvalId, {
|
|
354
|
+
resolve: resolve,
|
|
355
|
+
reject,
|
|
356
|
+
timeoutId,
|
|
357
|
+
});
|
|
358
|
+
});
|
|
359
|
+
}
|
|
360
|
+
readTelegramBotToken() {
|
|
361
|
+
try {
|
|
362
|
+
const configPath = join(homedir(), '.openclaw', 'openclaw.json');
|
|
363
|
+
if (!existsSync(configPath))
|
|
364
|
+
return null;
|
|
365
|
+
const raw = JSON.parse(readFileSync(configPath, 'utf-8'));
|
|
366
|
+
return raw?.channels?.telegram?.botToken || null;
|
|
367
|
+
}
|
|
368
|
+
catch {
|
|
369
|
+
return null;
|
|
370
|
+
}
|
|
371
|
+
}
|
|
372
|
+
/**
|
|
373
|
+
* Send approval via Telegram as a single poll.
|
|
374
|
+
*
|
|
375
|
+
* Sends one poll (no auto-close). Periodically calls stopPoll to check
|
|
376
|
+
* for votes. If no votes on first check, re-sends the poll once.
|
|
377
|
+
*
|
|
378
|
+
* Text replies are NOT supported via this path because they conflict
|
|
379
|
+
* with the OpenClaw agent session (the agent would also process the reply).
|
|
380
|
+
*/
|
|
381
|
+
async requestApprovalViaTelegram(botToken, chatId, question, options) {
|
|
382
|
+
let pollMessageId = await this.telegramSendPoll(botToken, chatId, question, options);
|
|
383
|
+
if (!pollMessageId)
|
|
384
|
+
throw new Error('Failed to send Telegram poll');
|
|
385
|
+
const CHECK_INTERVAL_MS = 10_000;
|
|
386
|
+
let resent = false;
|
|
387
|
+
return new Promise((resolve, reject) => {
|
|
388
|
+
const overallTimeout = setTimeout(() => {
|
|
389
|
+
clearInterval(timer);
|
|
390
|
+
if (pollMessageId) {
|
|
391
|
+
this.telegramStopPoll(botToken, chatId, pollMessageId).catch(() => { });
|
|
392
|
+
}
|
|
393
|
+
reject(new Error('Approval poll timed out'));
|
|
394
|
+
}, APPROVAL_TIMEOUT_MS);
|
|
395
|
+
const timer = setInterval(async () => {
|
|
396
|
+
if (!pollMessageId)
|
|
397
|
+
return;
|
|
398
|
+
try {
|
|
399
|
+
const result = await this.telegramStopPoll(botToken, chatId, pollMessageId);
|
|
400
|
+
if (result && result.total_voter_count > 0) {
|
|
401
|
+
clearInterval(timer);
|
|
402
|
+
clearTimeout(overallTimeout);
|
|
403
|
+
const winner = result.options.reduce((a, b) => b.voter_count > a.voter_count ? b : a);
|
|
404
|
+
resolve(winner.text);
|
|
405
|
+
return;
|
|
406
|
+
}
|
|
407
|
+
// No votes — poll is now closed. Re-send once.
|
|
408
|
+
if (!resent) {
|
|
409
|
+
resent = true;
|
|
410
|
+
pollMessageId = await this.telegramSendPoll(botToken, chatId, question, options);
|
|
411
|
+
}
|
|
412
|
+
else {
|
|
413
|
+
// Already resent — stop checking, wait for timeout
|
|
414
|
+
clearInterval(timer);
|
|
415
|
+
}
|
|
416
|
+
}
|
|
417
|
+
catch {
|
|
418
|
+
// stopPoll failed — ignore
|
|
419
|
+
}
|
|
420
|
+
}, CHECK_INTERVAL_MS);
|
|
421
|
+
});
|
|
422
|
+
}
|
|
423
|
+
async telegramSendPoll(botToken, chatId, question, options) {
|
|
424
|
+
const resp = await fetch(`https://api.telegram.org/bot${botToken}/sendPoll`, {
|
|
425
|
+
method: 'POST',
|
|
426
|
+
headers: { 'Content-Type': 'application/json' },
|
|
427
|
+
body: JSON.stringify({
|
|
428
|
+
chat_id: chatId,
|
|
429
|
+
question: `[Astro] ${question}`,
|
|
430
|
+
options: JSON.stringify(options),
|
|
431
|
+
is_anonymous: false,
|
|
432
|
+
}),
|
|
433
|
+
});
|
|
434
|
+
const data = await resp.json();
|
|
435
|
+
return data.ok ? data.result?.message_id ?? null : null;
|
|
436
|
+
}
|
|
437
|
+
// ─── Telegram Bot API Helpers ──────────────────────────────────────
|
|
438
|
+
async telegramStopPoll(botToken, chatId, messageId) {
|
|
439
|
+
const resp = await fetch(`https://api.telegram.org/bot${botToken}/stopPoll`, {
|
|
440
|
+
method: 'POST',
|
|
441
|
+
headers: { 'Content-Type': 'application/json' },
|
|
442
|
+
body: JSON.stringify({ chat_id: chatId, message_id: messageId }),
|
|
443
|
+
});
|
|
444
|
+
const data = await resp.json();
|
|
445
|
+
return data.ok ? data.result ?? null : null;
|
|
446
|
+
}
|
|
447
|
+
getNotificationPrefix(type) {
|
|
448
|
+
switch (type) {
|
|
449
|
+
case 'task.completed': return '[Completed]';
|
|
450
|
+
case 'task.failed': return '[Failed]';
|
|
451
|
+
case 'approval.requested': return '[Approval Needed]';
|
|
452
|
+
case 'branch.pruned': return '[Pruned]';
|
|
453
|
+
default: return '[Astro]';
|
|
454
|
+
}
|
|
455
|
+
}
|
|
456
|
+
}
|
|
457
|
+
//# sourceMappingURL=openclaw-bridge.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"openclaw-bridge.js","sourceRoot":"","sources":["../../src/lib/openclaw-bridge.ts"],"names":[],"mappings":"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"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"providers.d.ts","sourceRoot":"","sources":["../../src/lib/providers.ts"],"names":[],"mappings":"AAAA;;GAEG;
|
|
1
|
+
{"version":3,"file":"providers.d.ts","sourceRoot":"","sources":["../../src/lib/providers.ts"],"names":[],"mappings":"AAAA;;GAEG;AAQH,OAAO,KAAK,EAAE,YAAY,EAAE,YAAY,EAAuC,MAAM,aAAa,CAAC;AAugBnG;;;;GAIG;AACH,wBAAsB,eAAe,IAAI,OAAO,CAAC,YAAY,EAAE,CAAC,CA4C/D;AAED;;GAEG;AACH,wBAAsB,WAAW,CAAC,IAAI,EAAE,YAAY,GAAG,OAAO,CAAC,YAAY,GAAG,IAAI,CAAC,CAGlF;AAED;;GAEG;AACH,wBAAsB,mBAAmB,CAAC,IAAI,EAAE,YAAY,GAAG,OAAO,CAAC,OAAO,CAAC,CAG9E;AAED;;GAEG;AACH,wBAAgB,kBAAkB,CAAC,QAAQ,EAAE,YAAY,GAAG,MAAM,CAIjE;AAED;;GAEG;AACH,wBAAgB,sBAAsB,CAAC,SAAS,EAAE,YAAY,EAAE,GAAG,MAAM,CAaxE"}
|
package/dist/lib/providers.js
CHANGED
|
@@ -6,6 +6,7 @@ import { promisify } from 'node:util';
|
|
|
6
6
|
import { access, constants, readFile } from 'node:fs/promises';
|
|
7
7
|
import { join } from 'node:path';
|
|
8
8
|
import { homedir } from 'node:os';
|
|
9
|
+
import WebSocket from 'ws';
|
|
9
10
|
import { detectSlurm } from './slurm-detect.js';
|
|
10
11
|
const execAsync = promisify(exec);
|
|
11
12
|
/**
|
|
@@ -261,76 +262,68 @@ async function detectCodex() {
|
|
|
261
262
|
return null;
|
|
262
263
|
}
|
|
263
264
|
/**
|
|
264
|
-
*
|
|
265
|
+
* Quick probe: connect to a WebSocket URL and check for connect.challenge.
|
|
266
|
+
* Does NOT perform a full handshake — just confirms the gateway is reachable.
|
|
265
267
|
*/
|
|
266
|
-
function
|
|
267
|
-
|
|
268
|
-
|
|
269
|
-
|
|
270
|
-
|
|
271
|
-
|
|
272
|
-
|
|
273
|
-
|
|
274
|
-
|
|
275
|
-
|
|
276
|
-
|
|
277
|
-
|
|
278
|
-
|
|
279
|
-
|
|
280
|
-
|
|
281
|
-
|
|
282
|
-
|
|
283
|
-
|
|
284
|
-
|
|
285
|
-
|
|
286
|
-
paths.push('/usr/local/bin/openclaw');
|
|
287
|
-
paths.push('/usr/bin/openclaw');
|
|
288
|
-
}
|
|
289
|
-
return paths;
|
|
268
|
+
function probeGatewayReachable(url) {
|
|
269
|
+
return new Promise((resolve) => {
|
|
270
|
+
let ws;
|
|
271
|
+
const timeout = setTimeout(() => { ws?.removeAllListeners(); ws?.close(); resolve(false); }, 5000);
|
|
272
|
+
ws = new WebSocket(url);
|
|
273
|
+
ws.on('message', (data) => {
|
|
274
|
+
try {
|
|
275
|
+
const frame = JSON.parse(String(data));
|
|
276
|
+
if (frame.type === 'event' && frame.event === 'connect.challenge') {
|
|
277
|
+
clearTimeout(timeout);
|
|
278
|
+
ws.removeAllListeners();
|
|
279
|
+
ws.close();
|
|
280
|
+
resolve(true);
|
|
281
|
+
}
|
|
282
|
+
}
|
|
283
|
+
catch { /* ignore */ }
|
|
284
|
+
});
|
|
285
|
+
ws.on('error', () => { clearTimeout(timeout); ws?.removeAllListeners(); resolve(false); });
|
|
286
|
+
ws.on('close', () => { clearTimeout(timeout); resolve(false); });
|
|
287
|
+
});
|
|
290
288
|
}
|
|
291
289
|
/**
|
|
292
|
-
* Detect OpenClaw
|
|
290
|
+
* Detect OpenClaw gateway availability.
|
|
291
|
+
*
|
|
292
|
+
* Reads ~/.openclaw/openclaw.json for gateway port + auth token,
|
|
293
|
+
* then probes ws://127.0.0.1:{port} for a connect.challenge event.
|
|
294
|
+
* The adapter itself handles the full handshake at execution time.
|
|
293
295
|
*/
|
|
294
296
|
async function detectOpenClaw() {
|
|
295
|
-
|
|
296
|
-
|
|
297
|
-
const
|
|
298
|
-
const
|
|
297
|
+
try {
|
|
298
|
+
const configPath = join(homedir(), '.openclaw', 'openclaw.json');
|
|
299
|
+
const raw = JSON.parse(await readFile(configPath, 'utf-8'));
|
|
300
|
+
const port = raw?.gateway?.port;
|
|
301
|
+
if (!port)
|
|
302
|
+
return null;
|
|
303
|
+
const bind = raw?.gateway?.bind || '127.0.0.1';
|
|
304
|
+
const host = bind === 'loopback' || bind === '127.0.0.1' ? '127.0.0.1' : bind;
|
|
305
|
+
const url = `ws://${host}:${port}`;
|
|
306
|
+
// Quick probe — just check for connect.challenge (no full handshake)
|
|
307
|
+
const reachable = await probeGatewayReachable(url);
|
|
308
|
+
if (!reachable)
|
|
309
|
+
return null;
|
|
299
310
|
return {
|
|
300
311
|
type: 'openclaw',
|
|
301
312
|
name: 'OpenClaw',
|
|
302
|
-
version,
|
|
303
|
-
path:
|
|
313
|
+
version: null,
|
|
314
|
+
path: url,
|
|
304
315
|
available: true,
|
|
305
316
|
capabilities: {
|
|
306
317
|
streaming: true,
|
|
307
318
|
tools: true,
|
|
308
319
|
multiTurn: true,
|
|
309
|
-
maxConcurrentTasks:
|
|
320
|
+
maxConcurrentTasks: 10,
|
|
310
321
|
},
|
|
311
322
|
};
|
|
312
323
|
}
|
|
313
|
-
|
|
314
|
-
|
|
315
|
-
const isExecutable = await fileExecutable(clawPath);
|
|
316
|
-
if (isExecutable) {
|
|
317
|
-
const version = await getCommandVersion(clawPath, '--version');
|
|
318
|
-
return {
|
|
319
|
-
type: 'openclaw',
|
|
320
|
-
name: 'OpenClaw',
|
|
321
|
-
version,
|
|
322
|
-
path: clawPath,
|
|
323
|
-
available: true,
|
|
324
|
-
capabilities: {
|
|
325
|
-
streaming: true,
|
|
326
|
-
tools: true,
|
|
327
|
-
multiTurn: true,
|
|
328
|
-
maxConcurrentTasks: 1,
|
|
329
|
-
},
|
|
330
|
-
};
|
|
331
|
-
}
|
|
324
|
+
catch {
|
|
325
|
+
return null;
|
|
332
326
|
}
|
|
333
|
-
return null;
|
|
334
327
|
}
|
|
335
328
|
/**
|
|
336
329
|
* Common installation paths for OpenCode
|