@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.
- package/cli.js +33 -0
- package/daemon.js +41 -9
- 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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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, {
|