echoclaw-relay-agent 0.17.2 → 0.19.0
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 +57 -17
- package/package.json +1 -1
package/dist/cli.js
CHANGED
|
@@ -255,6 +255,30 @@ async function runSetup(code, relay, bridgePort) {
|
|
|
255
255
|
}
|
|
256
256
|
}
|
|
257
257
|
catch { /* no service manager on this platform — fine */ }
|
|
258
|
+
// Kill any remaining relay-agent processes not managed by service manager.
|
|
259
|
+
// Use narrow match: only our own binary name, exclude our own PID.
|
|
260
|
+
try {
|
|
261
|
+
const { execSync } = await import('child_process');
|
|
262
|
+
const myPid = process.pid.toString();
|
|
263
|
+
try {
|
|
264
|
+
execSync(`pgrep -f "echoclaw-relay-agent.*--gateway" | grep -v "^${myPid}$" | xargs kill 2>/dev/null`, { stdio: 'ignore' });
|
|
265
|
+
}
|
|
266
|
+
catch { /* no matching processes — fine */ }
|
|
267
|
+
// Poll until processes are gone (max 5s)
|
|
268
|
+
const deadline = Date.now() + 5000;
|
|
269
|
+
while (Date.now() < deadline) {
|
|
270
|
+
try {
|
|
271
|
+
const out = execSync(`pgrep -f "echoclaw-relay-agent.*--gateway" | grep -v "^${myPid}$"`, { stdio: 'pipe' }).toString().trim();
|
|
272
|
+
if (!out)
|
|
273
|
+
break;
|
|
274
|
+
}
|
|
275
|
+
catch {
|
|
276
|
+
break; /* pgrep returns non-zero = no matches */
|
|
277
|
+
}
|
|
278
|
+
await new Promise(r => setTimeout(r, 300));
|
|
279
|
+
}
|
|
280
|
+
}
|
|
281
|
+
catch { /* pgrep not available — fine */ }
|
|
258
282
|
const sid = existingSession?.relaySessionId?.slice?.(0, 8) ?? 'unknown';
|
|
259
283
|
console.log(` ${DIM}Clearing previous session (${sid}...)${RESET}`);
|
|
260
284
|
try {
|
|
@@ -645,32 +669,36 @@ async function runDaemon(relay, code, gateway, bridgePort) {
|
|
|
645
669
|
agent.on('connected', () => {
|
|
646
670
|
updater.startPeriodicCheck();
|
|
647
671
|
});
|
|
648
|
-
//
|
|
649
|
-
|
|
650
|
-
const
|
|
651
|
-
|
|
652
|
-
|
|
672
|
+
// V2: Never-give-up retry logic — daemon must stay alive forever.
|
|
673
|
+
// Only exits on: explicit UNPAIR, SIGINT/SIGTERM, or no saved session + no code.
|
|
674
|
+
const BASE_DELAY = 3000;
|
|
675
|
+
const MAX_DELAY = 60000;
|
|
676
|
+
let attempt = 0;
|
|
677
|
+
while (!stopping) {
|
|
653
678
|
try {
|
|
679
|
+
attempt++;
|
|
654
680
|
await agent.start(code);
|
|
655
|
-
|
|
681
|
+
// Connected — reset attempt counter and clear code
|
|
682
|
+
// Session is saved after first success; future reconnects use session resume
|
|
683
|
+
attempt = 0;
|
|
684
|
+
code = undefined;
|
|
656
685
|
}
|
|
657
686
|
catch (err) {
|
|
658
|
-
lastErr = err;
|
|
659
687
|
const msg = err instanceof Error ? err.message : String(err);
|
|
660
|
-
console.error(` [start-failed] attempt=${attempt}
|
|
661
|
-
//
|
|
662
|
-
if (msg.includes('No saved session found')
|
|
663
|
-
|
|
664
|
-
msg.includes('SESSION_NOT_FOUND')) {
|
|
688
|
+
console.error(` [start-failed] attempt=${attempt} error=${msg}`);
|
|
689
|
+
// Truly permanent: no session AND no code to pair with
|
|
690
|
+
if (msg.includes('No saved session found') && !code) {
|
|
691
|
+
console.error(` [fatal] No session and no pairing code. Run: echoclaw-relay setup <CODE>`);
|
|
665
692
|
break;
|
|
666
693
|
}
|
|
667
|
-
|
|
668
|
-
|
|
669
|
-
|
|
670
|
-
|
|
694
|
+
// SESSION_NOT_FOUND is NOT permanent in V2 — identity reconnect will handle it
|
|
695
|
+
// Just retry with backoff
|
|
696
|
+
// Exponential backoff: 3s, 6s, 12s, 24s, 48s, 60s (capped)
|
|
697
|
+
const delay = Math.min(BASE_DELAY * Math.pow(2, attempt - 1), MAX_DELAY);
|
|
698
|
+
console.log(` [retry] waiting ${(delay / 1000).toFixed(0)}s...`);
|
|
699
|
+
await new Promise(r => setTimeout(r, delay));
|
|
671
700
|
}
|
|
672
701
|
}
|
|
673
|
-
throw lastErr;
|
|
674
702
|
}
|
|
675
703
|
// ── Main ─────────────────────────────────────────────────────
|
|
676
704
|
async function main() {
|
|
@@ -710,4 +738,16 @@ async function main() {
|
|
|
710
738
|
process.exit(1);
|
|
711
739
|
}
|
|
712
740
|
}
|
|
741
|
+
// V2: Global error handlers — log and exit, let supervisor (launchd/systemd) restart.
|
|
742
|
+
// Staying alive after uncaughtException risks corrupted state (half-open sockets,
|
|
743
|
+
// partial writes). Clean crash + restart is safer than zombie process.
|
|
744
|
+
process.on('uncaughtException', (err) => {
|
|
745
|
+
console.error(` [FATAL] uncaughtException: ${err.message}`);
|
|
746
|
+
console.error(err.stack || '');
|
|
747
|
+
process.exit(1);
|
|
748
|
+
});
|
|
749
|
+
process.on('unhandledRejection', (reason) => {
|
|
750
|
+
console.error(` [FATAL] unhandledRejection: ${reason}`);
|
|
751
|
+
process.exit(1);
|
|
752
|
+
});
|
|
713
753
|
main();
|
package/package.json
CHANGED