@dmsdc-ai/aigentry-telepty 0.1.81 → 0.1.83

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 (3) hide show
  1. package/cli.js +33 -0
  2. package/daemon.js +41 -9
  3. package/package.json +1 -1
package/cli.js CHANGED
@@ -1819,6 +1819,39 @@ async function main() {
1819
1819
  return;
1820
1820
  }
1821
1821
 
1822
+ if (cmd === 'delete') {
1823
+ const sessionRef = args[1];
1824
+ if (!sessionRef) { console.error('❌ Usage: telepty delete <session-id>'); process.exit(1); }
1825
+ try {
1826
+ const target = await resolveSessionTarget(sessionRef);
1827
+ if (!target) { console.error(`❌ Session '${sessionRef}' not found.`); process.exit(1); }
1828
+ const res = await fetchWithAuth(`http://${target.host}:${PORT}/api/sessions/${encodeURIComponent(target.id)}`, { method: 'DELETE' });
1829
+ const data = await res.json();
1830
+ if (!res.ok) { console.error(`❌ Error: ${data.error}`); return; }
1831
+ console.log(`✅ Session '\x1b[36m${target.id}\x1b[0m' deleted.`);
1832
+ } catch (e) { console.error(`❌ ${e.message || 'Failed to delete session.'}`); }
1833
+ return;
1834
+ }
1835
+
1836
+ if (cmd === 'clean') {
1837
+ try {
1838
+ const sessions = await discoverSessions({ silent: true });
1839
+ if (sessions.length === 0) { console.log('No sessions found.'); return; }
1840
+ let cleaned = 0;
1841
+ for (const s of sessions) {
1842
+ if (s.healthStatus === 'STALE' || s.healthStatus === 'DISCONNECTED') {
1843
+ try {
1844
+ const host = s.host || '127.0.0.1';
1845
+ const res = await fetchWithAuth(`http://${host}:${PORT}/api/sessions/${encodeURIComponent(s.id)}`, { method: 'DELETE' });
1846
+ if (res.ok) { console.log(` 🗑 Removed ghost: \x1b[36m${s.id}\x1b[0m (${s.healthStatus})`); cleaned++; }
1847
+ } catch (_) {}
1848
+ }
1849
+ }
1850
+ console.log(cleaned > 0 ? `✅ Cleaned ${cleaned} ghost session(s).` : '✅ No ghost sessions found.');
1851
+ } catch (e) { console.error(`❌ ${e.message || 'Failed to clean sessions.'}`); }
1852
+ return;
1853
+ }
1854
+
1822
1855
  if (cmd === 'rename') {
1823
1856
  const oldId = args[1]; const newId = args[2];
1824
1857
  if (!oldId || !newId) { console.error('❌ Usage: telepty rename <old_id> <new_id>'); process.exit(1); }
package/daemon.js CHANGED
@@ -222,7 +222,20 @@ function getSessionHealthStatus(session, options = {}) {
222
222
  }
223
223
 
224
224
  if (session.type === 'aterm') {
225
- if (session.deliveryEndpoint || (session.delivery && session.delivery.address)) {
225
+ const endpoint = session.deliveryEndpoint || (session.delivery && session.delivery.address);
226
+ if (endpoint) {
227
+ const isSocketPath = endpoint.startsWith('/');
228
+ if (isSocketPath) {
229
+ try {
230
+ fs.accessSync(endpoint, fs.constants.F_OK);
231
+ return 'CONNECTED';
232
+ } catch {
233
+ session.deliveryEndpoint = null;
234
+ if (session.delivery) session.delivery.address = null;
235
+ session.lastDisconnectedAt = session.lastDisconnectedAt || new Date().toISOString();
236
+ return 'DISCONNECTED';
237
+ }
238
+ }
226
239
  return 'CONNECTED';
227
240
  }
228
241
  if (disconnectedMs !== null && disconnectedMs >= staleMs) {
@@ -1478,18 +1491,20 @@ app.delete('/api/sessions/:id', (req, res) => {
1478
1491
  try {
1479
1492
  session.isClosing = true;
1480
1493
  if (session.type === 'wrapped') {
1481
- session.clients.forEach(ws => ws.close(1000, 'Session destroyed'));
1482
- delete sessions[id];
1483
- console.log(`[KILL] Wrapped session ${id} removed`);
1484
- persistSessions();
1485
- } else {
1494
+ if (session.clients) session.clients.forEach(ws => ws.close(1000, 'Session destroyed'));
1495
+ } else if (session.ptyProcess) {
1486
1496
  session.ptyProcess.kill();
1487
- console.log(`[KILL] Session ${id} forcefully closed`);
1488
- persistSessions();
1489
1497
  }
1498
+ delete sessions[id];
1499
+ console.log(`[KILL] Session ${id} removed`);
1500
+ persistSessions();
1490
1501
  res.json({ success: true, status: 'closing' });
1491
1502
  } catch (err) {
1492
- res.status(500).json({ error: err.message });
1503
+ // Even if kill fails, remove from registry
1504
+ delete sessions[id];
1505
+ persistSessions();
1506
+ console.log(`[KILL] Session ${id} force-removed (process cleanup error: ${err.message})`);
1507
+ res.json({ success: true, status: 'force-removed' });
1493
1508
  }
1494
1509
  });
1495
1510
 
@@ -1881,6 +1896,23 @@ setInterval(() => {
1881
1896
  session._idleEmitted = false;
1882
1897
  }
1883
1898
 
1899
+ // Periodically verify aterm socket existence — triggers health transition
1900
+ if (session.type === 'aterm') {
1901
+ const atermEndpoint = session.deliveryEndpoint || (session.delivery && session.delivery.address);
1902
+ if (atermEndpoint && atermEndpoint.startsWith('/')) {
1903
+ try {
1904
+ fs.accessSync(atermEndpoint, fs.constants.F_OK);
1905
+ } catch {
1906
+ session.deliveryEndpoint = null;
1907
+ if (session.delivery) session.delivery.address = null;
1908
+ if (!session.lastDisconnectedAt) {
1909
+ session.lastDisconnectedAt = new Date().toISOString();
1910
+ }
1911
+ console.log(`[SWEEP] aterm socket gone for ${id}: ${atermEndpoint}`);
1912
+ }
1913
+ }
1914
+ }
1915
+
1884
1916
  if (healthStatus === 'STALE' && !session._staleEmitted) {
1885
1917
  session._staleEmitted = true;
1886
1918
  emitSessionLifecycleEvent('session_stale', id, session, {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@dmsdc-ai/aigentry-telepty",
3
- "version": "0.1.81",
3
+ "version": "0.1.83",
4
4
  "main": "daemon.js",
5
5
  "bin": {
6
6
  "aigentry-telepty": "install.js",