echoclaw-relay-agent 0.22.6 → 0.22.7
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.
|
@@ -44,10 +44,6 @@ export declare class InstallHandler {
|
|
|
44
44
|
private _runToRequest;
|
|
45
45
|
/** Whether workspace docs have been synced to OpenClaw. */
|
|
46
46
|
private _workspaceSynced;
|
|
47
|
-
/** ICP workspace orchestrator for engine-based flows. */
|
|
48
|
-
private readonly _icpOrchestrator;
|
|
49
|
-
/** Actions that should be routed through ICP workspace flow. */
|
|
50
|
-
private static readonly ICP_ACTIONS;
|
|
51
47
|
constructor(wsClient: OpenClawWsClient, chatHandler: ChatHandler, config?: InstallHandlerConfig);
|
|
52
48
|
/** Set the callback for sending messages back to Desktop. */
|
|
53
49
|
setSendBack(fn: (msg: Record<string, unknown>) => Promise<void>): void;
|
|
@@ -66,25 +62,6 @@ export declare class InstallHandler {
|
|
|
66
62
|
handleAbort(requestId: string): Promise<void>;
|
|
67
63
|
/** Disconnect and clean up all active installs. */
|
|
68
64
|
cleanup(): void;
|
|
69
|
-
/**
|
|
70
|
-
* Handle an install request through the ICP workspace orchestrator.
|
|
71
|
-
* On timeout, falls back to the chat-based flow.
|
|
72
|
-
*/
|
|
73
|
-
private _handleViaIcp;
|
|
74
|
-
/**
|
|
75
|
-
* Build an IcpRequest from an InstallRequest payload.
|
|
76
|
-
* Returns null if the payload can't be mapped to an ICP request.
|
|
77
|
-
*/
|
|
78
|
-
private _buildIcpRequest;
|
|
79
|
-
/**
|
|
80
|
-
* Fall back to the existing chat-based flow.
|
|
81
|
-
* Called when ICP times out or can't handle the request.
|
|
82
|
-
*/
|
|
83
|
-
private _handleViaChatFallback;
|
|
84
|
-
/**
|
|
85
|
-
* Generate human-readable message for ICP progress phases.
|
|
86
|
-
*/
|
|
87
|
-
private _icpPhaseMessage;
|
|
88
65
|
/**
|
|
89
66
|
* Handle a streaming chat event for an install run.
|
|
90
67
|
* Called when a chat event arrives with a runId we're tracking.
|
|
@@ -23,8 +23,6 @@ import crypto from 'node:crypto';
|
|
|
23
23
|
import { buildAppRequestPrompt } from '../gateway/AppRequestPrompt.js';
|
|
24
24
|
import { StreamingMarkerParser } from './MarkerParser.js';
|
|
25
25
|
import { INSTALL_ERROR_CODES, } from './types.js';
|
|
26
|
-
import { IcpOrchestrator, } from '@echoclaw/icp-orchestrator';
|
|
27
|
-
import { resolveInstallAction, } from '@echoclaw/claw-engine';
|
|
28
26
|
// ── Constants ────────────────────────────────────────────────────
|
|
29
27
|
const DEFAULT_TIMEOUT_MS = 120000;
|
|
30
28
|
const DEFAULT_RPC_TIMEOUT_MS = 30000;
|
|
@@ -33,6 +31,11 @@ const DEFAULT_SESSION_KEY = 'main';
|
|
|
33
31
|
const STATUS_THROTTLE_MS = 3000;
|
|
34
32
|
// ── InstallHandler ───────────────────────────────────────────────
|
|
35
33
|
export class InstallHandler {
|
|
34
|
+
// ── ICP (disabled until packages are on npm) ──
|
|
35
|
+
// private readonly _icpOrchestrator: IcpOrchestrator;
|
|
36
|
+
// private static readonly ICP_ACTIONS = new Set([
|
|
37
|
+
// 'install_with_config', 'complete_template', 'generate_fresh', 'adapt',
|
|
38
|
+
// ]);
|
|
36
39
|
constructor(wsClient, chatHandler, config) {
|
|
37
40
|
Object.defineProperty(this, "_wsClient", {
|
|
38
41
|
enumerable: true,
|
|
@@ -92,23 +95,16 @@ export class InstallHandler {
|
|
|
92
95
|
writable: true,
|
|
93
96
|
value: false
|
|
94
97
|
});
|
|
95
|
-
/** ICP workspace orchestrator for engine-based flows. */
|
|
96
|
-
Object.defineProperty(this, "_icpOrchestrator", {
|
|
97
|
-
enumerable: true,
|
|
98
|
-
configurable: true,
|
|
99
|
-
writable: true,
|
|
100
|
-
value: void 0
|
|
101
|
-
});
|
|
102
98
|
this._wsClient = wsClient;
|
|
103
99
|
this._chatHandler = chatHandler;
|
|
104
100
|
this._timeoutMs = config?.timeoutMs ?? DEFAULT_TIMEOUT_MS;
|
|
105
101
|
this._sessionKey = config?.sessionKey ?? DEFAULT_SESSION_KEY;
|
|
106
102
|
this._rpcTimeoutMs = config?.rpcTimeoutMs ?? DEFAULT_RPC_TIMEOUT_MS;
|
|
107
|
-
//
|
|
108
|
-
this._icpOrchestrator = new IcpOrchestrator({
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
});
|
|
103
|
+
// ICP orchestrator init disabled until packages are on npm
|
|
104
|
+
// this._icpOrchestrator = new IcpOrchestrator({
|
|
105
|
+
// outputTimeoutMs: this._timeoutMs,
|
|
106
|
+
// reviewTimeoutMs: this._timeoutMs,
|
|
107
|
+
// });
|
|
112
108
|
// Listen for chat events — only process runs we own
|
|
113
109
|
this._wsClient.on('chat', (payload) => {
|
|
114
110
|
const runId = payload?.runId;
|
|
@@ -163,41 +159,8 @@ export class InstallHandler {
|
|
|
163
159
|
requestId,
|
|
164
160
|
status: 'accepted',
|
|
165
161
|
});
|
|
166
|
-
// ── ICP workspace routing
|
|
167
|
-
//
|
|
168
|
-
// Falls back to chat-based on timeout/failure.
|
|
169
|
-
if (InstallHandler.ICP_ACTIONS.has(action) && this._workspaceSynced) {
|
|
170
|
-
// Track in _activeInstalls to prevent duplicates and support abort
|
|
171
|
-
const icpAbort = new AbortController();
|
|
172
|
-
const icpInstall = {
|
|
173
|
-
requestId,
|
|
174
|
-
action,
|
|
175
|
-
runId: null,
|
|
176
|
-
parser: new StreamingMarkerParser(),
|
|
177
|
-
startedAt: Date.now(),
|
|
178
|
-
timeoutTimer: null,
|
|
179
|
-
lastKnownLength: 0,
|
|
180
|
-
legacy,
|
|
181
|
-
lastStatusAt: 0,
|
|
182
|
-
streamMarkers: [],
|
|
183
|
-
hasConfirmedPlan: false,
|
|
184
|
-
icpAbort,
|
|
185
|
-
};
|
|
186
|
-
this._activeInstalls.set(requestId, icpInstall);
|
|
187
|
-
this._handleViaIcp(requestId, action, payload, icpAbort.signal).catch((err) => {
|
|
188
|
-
// ICP flow threw unexpectedly — send failure to Desktop
|
|
189
|
-
this._send({
|
|
190
|
-
type: 'install_result',
|
|
191
|
-
requestId,
|
|
192
|
-
status: 'failed',
|
|
193
|
-
error: err?.message || 'ICP orchestration failed unexpectedly',
|
|
194
|
-
code: INSTALL_ERROR_CODES.ICP_FAILED,
|
|
195
|
-
}).catch(() => { });
|
|
196
|
-
this._activeInstalls.delete(requestId);
|
|
197
|
-
});
|
|
198
|
-
return;
|
|
199
|
-
}
|
|
200
|
-
// ── Chat-based flow (legacy / preview / execute-with-plan) ──
|
|
162
|
+
// ── ICP workspace routing (disabled until packages are on npm) ──
|
|
163
|
+
// if (InstallHandler.ICP_ACTIONS.has(action) && this._workspaceSynced) { ... }
|
|
201
164
|
// Create active install tracker
|
|
202
165
|
const install = {
|
|
203
166
|
requestId,
|
|
@@ -211,7 +174,6 @@ export class InstallHandler {
|
|
|
211
174
|
lastStatusAt: 0,
|
|
212
175
|
streamMarkers: [],
|
|
213
176
|
hasConfirmedPlan: !!(action === 'install' && payload.confirmedPlan),
|
|
214
|
-
icpAbort: null,
|
|
215
177
|
};
|
|
216
178
|
this._activeInstalls.set(requestId, install);
|
|
217
179
|
// Build prompt from the install/adapt/preview payload
|
|
@@ -274,19 +236,7 @@ export class InstallHandler {
|
|
|
274
236
|
const install = this._activeInstalls.get(requestId);
|
|
275
237
|
if (!install)
|
|
276
238
|
return;
|
|
277
|
-
//
|
|
278
|
-
if (install.icpAbort) {
|
|
279
|
-
install.icpAbort.abort();
|
|
280
|
-
this._send({
|
|
281
|
-
type: 'install_result',
|
|
282
|
-
requestId,
|
|
283
|
-
status: 'cancelled',
|
|
284
|
-
code: INSTALL_ERROR_CODES.CANCELLED,
|
|
285
|
-
}).catch(() => { });
|
|
286
|
-
this._activeInstalls.delete(requestId);
|
|
287
|
-
return;
|
|
288
|
-
}
|
|
289
|
-
// Chat-based flow: try to abort the AI generation
|
|
239
|
+
// Try to abort the AI generation
|
|
290
240
|
try {
|
|
291
241
|
await this._wsClient.request('chat.abort', {
|
|
292
242
|
sessionKey: this._sessionKey,
|
|
@@ -302,246 +252,14 @@ export class InstallHandler {
|
|
|
302
252
|
}
|
|
303
253
|
/** Disconnect and clean up all active installs. */
|
|
304
254
|
cleanup() {
|
|
305
|
-
for (const [requestId
|
|
306
|
-
// Abort any active ICP workspace flows
|
|
307
|
-
if (install.icpAbort) {
|
|
308
|
-
install.icpAbort.abort();
|
|
309
|
-
}
|
|
255
|
+
for (const [requestId] of this._activeInstalls) {
|
|
310
256
|
this._cleanupInstall(requestId);
|
|
311
257
|
}
|
|
312
258
|
this._activeInstalls.clear();
|
|
313
259
|
this._runToRequest.clear();
|
|
314
260
|
}
|
|
315
|
-
// ──
|
|
316
|
-
|
|
317
|
-
* Handle an install request through the ICP workspace orchestrator.
|
|
318
|
-
* On timeout, falls back to the chat-based flow.
|
|
319
|
-
*/
|
|
320
|
-
async _handleViaIcp(requestId, action, payload, signal) {
|
|
321
|
-
// Build ICP request from install payload
|
|
322
|
-
const icpRequest = this._buildIcpRequest(action, payload);
|
|
323
|
-
if (!icpRequest) {
|
|
324
|
-
// Can't build ICP request — fall back to chat
|
|
325
|
-
await this._handleViaChatFallback(requestId, payload);
|
|
326
|
-
return;
|
|
327
|
-
}
|
|
328
|
-
// Map ICP progress to InstallStatus
|
|
329
|
-
const onProgress = (progress) => {
|
|
330
|
-
const phaseMap = {
|
|
331
|
-
writing_task: 'icp_writing_task',
|
|
332
|
-
waiting_output: 'icp_waiting_output',
|
|
333
|
-
validating: 'icp_validating',
|
|
334
|
-
writing_review: 'icp_reviewing',
|
|
335
|
-
waiting_revision: 'icp_reviewing',
|
|
336
|
-
fallback: 'icp_fallback',
|
|
337
|
-
delivering: 'icp_delivering',
|
|
338
|
-
};
|
|
339
|
-
const installPhase = phaseMap[progress.phase] ?? 'ai_processing';
|
|
340
|
-
const message = progress.message ?? this._icpPhaseMessage(progress);
|
|
341
|
-
this._sendStatus(requestId, installPhase, message).catch(() => { });
|
|
342
|
-
};
|
|
343
|
-
// Notify OpenClaw about new tasks/reviews via chat
|
|
344
|
-
const notifyAI = async (taskId, content, isReview) => {
|
|
345
|
-
try {
|
|
346
|
-
const message = isReview
|
|
347
|
-
? `Review feedback written for task ${taskId}. Read the review file and fix the issues, then rewrite output/package.claw.json.`
|
|
348
|
-
: `New task available: ${taskId}. Read the task file at claw-apps/${taskId}/task.md and follow the instructions.`;
|
|
349
|
-
const response = await this._wsClient.request('chat.send', {
|
|
350
|
-
sessionKey: this._sessionKey,
|
|
351
|
-
message,
|
|
352
|
-
idempotencyKey: crypto.randomUUID(),
|
|
353
|
-
}, this._rpcTimeoutMs);
|
|
354
|
-
// Register the runId so ChatHandler ignores events for this notification run
|
|
355
|
-
const notifyRunId = response.payload?.runId;
|
|
356
|
-
if (notifyRunId) {
|
|
357
|
-
this._chatHandler.registerExternalRun(notifyRunId);
|
|
358
|
-
// Auto-unregister after timeout — these are fire-and-forget notifications
|
|
359
|
-
setTimeout(() => {
|
|
360
|
-
this._chatHandler.unregisterExternalRun(notifyRunId);
|
|
361
|
-
}, this._timeoutMs).unref?.();
|
|
362
|
-
}
|
|
363
|
-
}
|
|
364
|
-
catch {
|
|
365
|
-
// Notification failure is non-fatal — OpenClaw may still pick it up
|
|
366
|
-
}
|
|
367
|
-
};
|
|
368
|
-
// Execute ICP flow
|
|
369
|
-
const result = await this._icpOrchestrator.execute(icpRequest, {
|
|
370
|
-
onProgress,
|
|
371
|
-
notifyAI,
|
|
372
|
-
signal,
|
|
373
|
-
});
|
|
374
|
-
// Guard: if aborted while awaiting ICP, don't send duplicate result
|
|
375
|
-
if (!this._activeInstalls.has(requestId))
|
|
376
|
-
return;
|
|
377
|
-
// Handle result
|
|
378
|
-
switch (result.status) {
|
|
379
|
-
case 'success': {
|
|
380
|
-
const pkg = result.output.package;
|
|
381
|
-
this._send({
|
|
382
|
-
type: 'install_result',
|
|
383
|
-
requestId,
|
|
384
|
-
status: 'success',
|
|
385
|
-
app: {
|
|
386
|
-
manifest: pkg.manifest,
|
|
387
|
-
html: pkg.html ?? '',
|
|
388
|
-
},
|
|
389
|
-
}).catch(() => { });
|
|
390
|
-
this._activeInstalls.delete(requestId);
|
|
391
|
-
break;
|
|
392
|
-
}
|
|
393
|
-
case 'timeout': {
|
|
394
|
-
// ICP timed out — remove ICP tracking, fall back to chat-based
|
|
395
|
-
this._activeInstalls.delete(requestId);
|
|
396
|
-
console.warn(`[InstallHandler] ICP timeout for ${requestId}, falling back to chat`);
|
|
397
|
-
await this._handleViaChatFallback(requestId, payload);
|
|
398
|
-
break;
|
|
399
|
-
}
|
|
400
|
-
case 'failed': {
|
|
401
|
-
this._send({
|
|
402
|
-
type: 'install_result',
|
|
403
|
-
requestId,
|
|
404
|
-
status: 'failed',
|
|
405
|
-
error: result.error,
|
|
406
|
-
code: INSTALL_ERROR_CODES.ICP_FAILED,
|
|
407
|
-
}).catch(() => { });
|
|
408
|
-
this._activeInstalls.delete(requestId);
|
|
409
|
-
break;
|
|
410
|
-
}
|
|
411
|
-
default: {
|
|
412
|
-
// Unknown status — send failure
|
|
413
|
-
this._send({
|
|
414
|
-
type: 'install_result',
|
|
415
|
-
requestId,
|
|
416
|
-
status: 'failed',
|
|
417
|
-
error: `Unexpected ICP result status: ${result.status}`,
|
|
418
|
-
code: INSTALL_ERROR_CODES.ICP_FAILED,
|
|
419
|
-
}).catch(() => { });
|
|
420
|
-
this._activeInstalls.delete(requestId);
|
|
421
|
-
break;
|
|
422
|
-
}
|
|
423
|
-
}
|
|
424
|
-
}
|
|
425
|
-
/**
|
|
426
|
-
* Build an IcpRequest from an InstallRequest payload.
|
|
427
|
-
* Returns null if the payload can't be mapped to an ICP request.
|
|
428
|
-
*/
|
|
429
|
-
_buildIcpRequest(action, payload) {
|
|
430
|
-
if ((action === 'install_with_config' || action === 'complete_template') && payload.package) {
|
|
431
|
-
const pkg = payload.package;
|
|
432
|
-
const installAction = resolveInstallAction(pkg);
|
|
433
|
-
if (!installAction.valid)
|
|
434
|
-
return null;
|
|
435
|
-
return { type: 'adapt', pkg, installAction };
|
|
436
|
-
}
|
|
437
|
-
if (action === 'generate_fresh' && payload.package) {
|
|
438
|
-
const pkg = payload.package;
|
|
439
|
-
// Prefer Desktop-provided userRequest; fall back to app name
|
|
440
|
-
const userRequest = payload.userRequest
|
|
441
|
-
?? (typeof pkg.manifest?.name === 'string'
|
|
442
|
-
? `Create app: ${pkg.manifest.name}`
|
|
443
|
-
: `Create app: ${pkg.manifest?.name?.en ?? 'New App'}`);
|
|
444
|
-
return {
|
|
445
|
-
type: 'create',
|
|
446
|
-
userRequest,
|
|
447
|
-
manifest: pkg.manifest,
|
|
448
|
-
};
|
|
449
|
-
}
|
|
450
|
-
if (action === 'adapt' && payload.html && payload.manifest) {
|
|
451
|
-
const manifest = payload.manifest;
|
|
452
|
-
const pkg = {
|
|
453
|
-
manifest,
|
|
454
|
-
html: payload.html,
|
|
455
|
-
prompt: { seed: { goal: `Adapt ${manifest.id ?? 'app'}` } },
|
|
456
|
-
};
|
|
457
|
-
const installAction = resolveInstallAction(pkg);
|
|
458
|
-
if (!installAction.valid)
|
|
459
|
-
return null;
|
|
460
|
-
return { type: 'adapt', pkg, installAction };
|
|
461
|
-
}
|
|
462
|
-
return null;
|
|
463
|
-
}
|
|
464
|
-
/**
|
|
465
|
-
* Fall back to the existing chat-based flow.
|
|
466
|
-
* Called when ICP times out or can't handle the request.
|
|
467
|
-
*/
|
|
468
|
-
async _handleViaChatFallback(requestId, payload) {
|
|
469
|
-
const action = payload.action ?? 'install';
|
|
470
|
-
// Create active install tracker (same as the normal chat flow)
|
|
471
|
-
const install = {
|
|
472
|
-
requestId,
|
|
473
|
-
action,
|
|
474
|
-
runId: null,
|
|
475
|
-
parser: new StreamingMarkerParser(),
|
|
476
|
-
startedAt: Date.now(),
|
|
477
|
-
timeoutTimer: null,
|
|
478
|
-
lastKnownLength: 0,
|
|
479
|
-
legacy: false,
|
|
480
|
-
lastStatusAt: 0,
|
|
481
|
-
streamMarkers: [],
|
|
482
|
-
hasConfirmedPlan: false,
|
|
483
|
-
icpAbort: null,
|
|
484
|
-
};
|
|
485
|
-
this._activeInstalls.set(requestId, install);
|
|
486
|
-
const promptPayload = this._buildPromptPayload(payload);
|
|
487
|
-
const prompt = buildAppRequestPrompt(promptPayload, this._workspaceSynced);
|
|
488
|
-
await this._sendStatus(requestId, 'sending', 'Falling back to chat-based flow...');
|
|
489
|
-
try {
|
|
490
|
-
const response = await this._wsClient.request('chat.send', {
|
|
491
|
-
sessionKey: this._sessionKey,
|
|
492
|
-
message: prompt,
|
|
493
|
-
idempotencyKey: crypto.randomUUID(),
|
|
494
|
-
}, this._rpcTimeoutMs);
|
|
495
|
-
if (!response.ok) {
|
|
496
|
-
this._completeInstall(requestId, {
|
|
497
|
-
status: 'failed',
|
|
498
|
-
error: response.error?.message || 'chat.send failed',
|
|
499
|
-
code: INSTALL_ERROR_CODES.SEND_FAILED,
|
|
500
|
-
});
|
|
501
|
-
return;
|
|
502
|
-
}
|
|
503
|
-
const runId = response.payload?.runId;
|
|
504
|
-
if (!runId) {
|
|
505
|
-
this._completeInstall(requestId, {
|
|
506
|
-
status: 'failed',
|
|
507
|
-
error: 'No runId returned from chat.send',
|
|
508
|
-
code: INSTALL_ERROR_CODES.SEND_FAILED,
|
|
509
|
-
});
|
|
510
|
-
return;
|
|
511
|
-
}
|
|
512
|
-
install.runId = runId;
|
|
513
|
-
this._runToRequest.set(runId, requestId);
|
|
514
|
-
this._chatHandler.registerExternalRun(runId);
|
|
515
|
-
install.timeoutTimer = setTimeout(() => {
|
|
516
|
-
this._handleTimeout(requestId);
|
|
517
|
-
}, this._timeoutMs);
|
|
518
|
-
if (install.timeoutTimer.unref)
|
|
519
|
-
install.timeoutTimer.unref();
|
|
520
|
-
await this._sendStatus(requestId, 'ai_processing', 'Waiting for AI response...');
|
|
521
|
-
}
|
|
522
|
-
catch (err) {
|
|
523
|
-
this._completeInstall(requestId, {
|
|
524
|
-
status: 'failed',
|
|
525
|
-
error: err.message || 'Unknown error',
|
|
526
|
-
code: INSTALL_ERROR_CODES.SEND_FAILED,
|
|
527
|
-
});
|
|
528
|
-
}
|
|
529
|
-
}
|
|
530
|
-
/**
|
|
531
|
-
* Generate human-readable message for ICP progress phases.
|
|
532
|
-
*/
|
|
533
|
-
_icpPhaseMessage(progress) {
|
|
534
|
-
switch (progress.phase) {
|
|
535
|
-
case 'writing_task': return 'Preparing task for AI...';
|
|
536
|
-
case 'waiting_output': return 'Waiting for AI to complete task...';
|
|
537
|
-
case 'validating': return `Validating output (round ${progress.round ?? 1})...`;
|
|
538
|
-
case 'writing_review': return `Quality check failed, requesting revision (round ${progress.round}/${progress.maxRounds})...`;
|
|
539
|
-
case 'waiting_revision': return `Waiting for AI revision (round ${progress.round}/${progress.maxRounds})...`;
|
|
540
|
-
case 'fallback': return 'Applying auto-fix (degraded delivery)...';
|
|
541
|
-
case 'delivering': return 'Quality check passed, delivering...';
|
|
542
|
-
default: return 'Processing...';
|
|
543
|
-
}
|
|
544
|
-
}
|
|
261
|
+
// ── ICP Workspace Flow (disabled until @echoclaw/claw-engine & icp-orchestrator are on npm) ──
|
|
262
|
+
// See git history for full ICP integration code.
|
|
545
263
|
// ── Private: Event Handling ────────────────────────────────────
|
|
546
264
|
/**
|
|
547
265
|
* Handle a streaming chat event for an install run.
|
|
@@ -927,15 +645,3 @@ export class InstallHandler {
|
|
|
927
645
|
}
|
|
928
646
|
}
|
|
929
647
|
}
|
|
930
|
-
/** Actions that should be routed through ICP workspace flow. */
|
|
931
|
-
Object.defineProperty(InstallHandler, "ICP_ACTIONS", {
|
|
932
|
-
enumerable: true,
|
|
933
|
-
configurable: true,
|
|
934
|
-
writable: true,
|
|
935
|
-
value: new Set([
|
|
936
|
-
'install_with_config',
|
|
937
|
-
'complete_template',
|
|
938
|
-
'generate_fresh',
|
|
939
|
-
'adapt',
|
|
940
|
-
])
|
|
941
|
-
});
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "echoclaw-relay-agent",
|
|
3
|
-
"version": "0.22.
|
|
3
|
+
"version": "0.22.7",
|
|
4
4
|
"description": "EchoClaw Relay Connection — E2E encrypted relay transport, pairing, and session management",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "./dist/index.js",
|
|
@@ -22,8 +22,6 @@
|
|
|
22
22
|
"dev": "tsx src/cli.ts"
|
|
23
23
|
},
|
|
24
24
|
"dependencies": {
|
|
25
|
-
"@echoclaw/claw-engine": "workspace:*",
|
|
26
|
-
"@echoclaw/icp-orchestrator": "workspace:*",
|
|
27
25
|
"echoclaw-crypto": "0.3.1",
|
|
28
26
|
"ws": "^8.18.0"
|
|
29
27
|
},
|