echoclaw-relay-agent 0.8.0 → 0.8.1
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/RelayAgent.js +11 -2
- package/dist/cli.js +33 -1
- package/package.json +1 -1
package/dist/RelayAgent.js
CHANGED
|
@@ -245,12 +245,21 @@ export class RelayAgent extends EventEmitter {
|
|
|
245
245
|
await this.onPaired(result);
|
|
246
246
|
}
|
|
247
247
|
catch (err) {
|
|
248
|
-
// Resume failed — clear
|
|
248
|
+
// Resume failed — only clear session for permanent errors
|
|
249
249
|
this.transport?.disconnect();
|
|
250
250
|
this.transport = null;
|
|
251
251
|
this.frameCrypto = null;
|
|
252
252
|
this.setStatus('disconnected');
|
|
253
|
-
|
|
253
|
+
const errMsg = err instanceof Error ? err.message : String(err);
|
|
254
|
+
const isPermanent = errMsg.includes('DEVICE_TOKEN_MISMATCH') ||
|
|
255
|
+
errMsg.includes('SESSION_NOT_FOUND') ||
|
|
256
|
+
errMsg.includes('SESSION_EXPIRED') ||
|
|
257
|
+
errMsg.includes('INVALID_SESSION');
|
|
258
|
+
if (isPermanent) {
|
|
259
|
+
// Permanent rejection — session is truly dead, clear it
|
|
260
|
+
await this.sessionStore.clear();
|
|
261
|
+
}
|
|
262
|
+
// Transient errors (network, timeout) — keep session.json for retry
|
|
254
263
|
throw err;
|
|
255
264
|
}
|
|
256
265
|
}
|
package/dist/cli.js
CHANGED
|
@@ -234,6 +234,13 @@ async function runSetup(code, relay, bridgePort) {
|
|
|
234
234
|
console.log();
|
|
235
235
|
// Step 2: Stop the foreground agent (service will take over)
|
|
236
236
|
await agent.stop();
|
|
237
|
+
// Verify session.json exists before installing service
|
|
238
|
+
const { SessionStore } = await import('./relay/SessionStore.js');
|
|
239
|
+
const store = new SessionStore();
|
|
240
|
+
const savedSession = await store.load();
|
|
241
|
+
if (!savedSession) {
|
|
242
|
+
throw new Error('Session file not found after pairing — cannot install service. Try setup again.');
|
|
243
|
+
}
|
|
237
244
|
// Step 3: Install as system service (WITHOUT pairing code — it resumes from session)
|
|
238
245
|
printStep('2/3', 'Installing system service...');
|
|
239
246
|
const svc = await getServiceManager();
|
|
@@ -354,7 +361,32 @@ async function runDaemon(relay, code, gateway, bridgePort) {
|
|
|
354
361
|
process.once('SIGINT', shutdown);
|
|
355
362
|
process.once('SIGTERM', shutdown);
|
|
356
363
|
console.log(` [start] relay=${relay} gateway=${!!gateway}`);
|
|
357
|
-
|
|
364
|
+
// Retry logic — transient failures (network, server restart) shouldn't kill the service
|
|
365
|
+
const MAX_RETRIES = 5;
|
|
366
|
+
const RETRY_DELAY = 3000;
|
|
367
|
+
let lastErr;
|
|
368
|
+
for (let attempt = 1; attempt <= MAX_RETRIES; attempt++) {
|
|
369
|
+
try {
|
|
370
|
+
await agent.start(code);
|
|
371
|
+
return; // success — stay alive
|
|
372
|
+
}
|
|
373
|
+
catch (err) {
|
|
374
|
+
lastErr = err;
|
|
375
|
+
const msg = err instanceof Error ? err.message : String(err);
|
|
376
|
+
console.error(` [start-failed] attempt=${attempt}/${MAX_RETRIES} error=${msg}`);
|
|
377
|
+
// Permanent errors — don't retry
|
|
378
|
+
if (msg.includes('No saved session found') ||
|
|
379
|
+
msg.includes('DEVICE_TOKEN_MISMATCH') ||
|
|
380
|
+
msg.includes('SESSION_NOT_FOUND')) {
|
|
381
|
+
break;
|
|
382
|
+
}
|
|
383
|
+
if (attempt < MAX_RETRIES) {
|
|
384
|
+
console.log(` [retry] waiting ${RETRY_DELAY / 1000}s...`);
|
|
385
|
+
await new Promise(r => setTimeout(r, RETRY_DELAY));
|
|
386
|
+
}
|
|
387
|
+
}
|
|
388
|
+
}
|
|
389
|
+
throw lastErr;
|
|
358
390
|
}
|
|
359
391
|
// ── Main ─────────────────────────────────────────────────────
|
|
360
392
|
async function main() {
|
package/package.json
CHANGED