@dmsdc-ai/aigentry-telepty 0.1.89 → 0.1.91

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.
Files changed (2) hide show
  1. package/cli.js +65 -19
  2. package/package.json +1 -1
package/cli.js CHANGED
@@ -357,6 +357,61 @@ function startDetachedDaemon() {
357
357
  cp.unref();
358
358
  }
359
359
 
360
+ async function waitForDaemonHealth(maxMs = 5000) {
361
+ const deadline = Date.now() + maxMs;
362
+ while (Date.now() < deadline) {
363
+ try {
364
+ const meta = await getDaemonMeta('127.0.0.1');
365
+ if (meta && meta.version) return meta;
366
+ } catch {}
367
+ await new Promise(r => setTimeout(r, 300));
368
+ }
369
+ return null;
370
+ }
371
+
372
+ async function restartDaemonGraceful(options = {}) {
373
+ const maxAttempts = options.maxAttempts || 3;
374
+ const requiredCapabilities = options.requiredCapabilities || [];
375
+
376
+ for (let attempt = 1; attempt <= maxAttempts; attempt++) {
377
+ // (a) Kill existing daemon processes
378
+ const results = cleanupDaemonProcesses();
379
+
380
+ // (b) Wait up to 3s for old processes to fully exit
381
+ if (results.stopped.length > 0) {
382
+ const { isProcessRunning } = require('./daemon-control');
383
+ const killDeadline = Date.now() + 3000;
384
+ for (const item of results.stopped) {
385
+ while (Date.now() < killDeadline && isProcessRunning(item.pid)) {
386
+ await new Promise(r => setTimeout(r, 100));
387
+ }
388
+ }
389
+ }
390
+
391
+ // (c) Start new daemon
392
+ startDetachedDaemon();
393
+
394
+ // (d) Wait for new daemon to respond with correct version
395
+ const meta = await waitForDaemonHealth(5000);
396
+ if (meta && meta.version === pkg.version) {
397
+ const hasCapabilities = requiredCapabilities.every(c => (meta.capabilities || []).includes(c));
398
+ if (hasCapabilities || requiredCapabilities.length === 0) {
399
+ return { success: true, meta, attempt };
400
+ }
401
+ }
402
+
403
+ // Retry with backoff
404
+ if (attempt < maxAttempts) {
405
+ const backoff = 1000 * attempt;
406
+ process.stdout.write(`\x1b[33m⚠️ Daemon restart attempt ${attempt}/${maxAttempts} failed. Retrying in ${backoff / 1000}s...\x1b[0m\n`);
407
+ await new Promise(r => setTimeout(r, backoff));
408
+ }
409
+ }
410
+
411
+ console.error(`\x1b[31m❌ Daemon restart failed after ${maxAttempts} attempts. Run "telepty daemon" manually to start.\x1b[0m`);
412
+ return { success: false, meta: null, attempt: maxAttempts };
413
+ }
414
+
360
415
  function renderInteractiveHeader() {
361
416
  const runtimeInfo = getRuntimeInfo(__dirname);
362
417
  console.clear();
@@ -403,14 +458,13 @@ async function repairLocalDaemon(options = {}) {
403
458
  return { stopped: results.stopped.length, failed: results.failed.length, meta: null };
404
459
  }
405
460
 
406
- startDetachedDaemon();
407
- await new Promise((resolve) => setTimeout(resolve, 1000));
408
- const meta = await getDaemonMeta('127.0.0.1');
409
- const versionMatch = meta && meta.version === pkg.version;
410
- if (meta && !versionMatch) {
411
- process.stdout.write(`\x1b[33m⚠️ Daemon restarted but version mismatch (running v${meta.version}, expected v${pkg.version})\x1b[0m\n`);
412
- }
413
- return { stopped: results.stopped.length, failed: results.failed.length, meta, versionMatch };
461
+ const restartResult = await restartDaemonGraceful();
462
+ return {
463
+ stopped: results.stopped.length,
464
+ failed: results.failed.length,
465
+ meta: restartResult.meta,
466
+ versionMatch: restartResult.success
467
+ };
414
468
  }
415
469
 
416
470
  function getDiscoveryHosts() {
@@ -477,30 +531,22 @@ async function ensureDaemonRunning(options = {}) {
477
531
  // Version mismatch: running daemon is older than installed CLI
478
532
  if (meta && meta.version !== pkg.version) {
479
533
  process.stdout.write(`\x1b[33m⚙️ Daemon version mismatch (running v${meta.version}, installed v${pkg.version}). Restarting...\x1b[0m\n`);
480
- cleanupDaemonProcesses();
534
+ await restartDaemonGraceful({ requiredCapabilities });
535
+ return;
481
536
  } else {
482
537
  return;
483
538
  }
484
539
  } else if (sessionsRes.ok && !meta) {
485
540
  process.stdout.write('\x1b[33m⚙️ Found an older local telepty daemon. Restarting it...\x1b[0m\n');
486
- cleanupDaemonProcesses();
487
541
  } else if (sessionsRes.ok && meta) {
488
542
  process.stdout.write('\x1b[33m⚙️ Found a local telepty daemon without the required features. Restarting it...\x1b[0m\n');
489
- cleanupDaemonProcesses();
490
543
  }
491
544
  } catch (e) {
492
545
  // Continue to auto-start below.
493
546
  }
494
547
 
495
548
  process.stdout.write('\x1b[33m⚙️ Auto-starting local telepty daemon...\x1b[0m\n');
496
- cleanupDaemonProcesses();
497
- startDetachedDaemon();
498
- await new Promise(r => setTimeout(r, 1000));
499
-
500
- const meta = await getDaemonMeta('127.0.0.1');
501
- if (!meta || !requiredCapabilities.every((item) => meta.capabilities.includes(item))) {
502
- console.error('❌ Failed to start a compatible local telepty daemon. Open telepty and choose "Repair local daemon", or rerun the installer.');
503
- }
549
+ await restartDaemonGraceful({ requiredCapabilities });
504
550
  }
505
551
 
506
552
  async function manageInteractiveAttach(sessionId, targetHost) {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@dmsdc-ai/aigentry-telepty",
3
- "version": "0.1.89",
3
+ "version": "0.1.91",
4
4
  "main": "daemon.js",
5
5
  "bin": {
6
6
  "aigentry-telepty": "install.js",